Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSOC 2018: First batch of UI changes for multi-world #3399

Merged
merged 72 commits into from
Jun 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
bef074c
Add 'Advanced' to i18n
TheFlash98 May 21, 2018
4855af6
Add 'Advanced Game Setup' to i18n
TheFlash98 May 21, 2018
5230243
Add a NewGameScreen
TheFlash98 May 21, 2018
0487408
Add a AdvancedGameSetupScreen with seed and modules
TheFlash98 May 21, 2018
ccb9fff
add a dummy test button on select game screen
TheFlash98 May 21, 2018
e7c61d2
Change UniverseSetupScreen title
TheFlash98 May 22, 2018
1d24e2f
More additions to i18n
TheFlash98 May 22, 2018
32fd1ac
Add the UniverseSetupScreen
TheFlash98 May 22, 2018
a4ebe58
Open screen from AdvancedGameSetupScreen
TheFlash98 May 22, 2018
414db02
some more i18n stuff
TheFlash98 May 22, 2018
6d5f2e1
Add the WorldSetupScreen
TheFlash98 May 22, 2018
45b5774
Appropriate linking for tests and some id tweaks
TheFlash98 May 22, 2018
89e997b
triggerBackAnimation on AdvancedGameSetupScreen, forgot earlier
TheFlash98 May 22, 2018
a9290e5
Some more i18n stuff
TheFlash98 May 25, 2018
7332471
World Pre-gen screen UI
TheFlash98 May 25, 2018
87759c1
World Config screen UI
TheFlash98 May 25, 2018
165b5f6
Link it all up for testing
TheFlash98 May 25, 2018
b17eb2a
quick id fix
TheFlash98 May 25, 2018
abf55be
A few UI fixes
TheFlash98 May 25, 2018
08d6610
worldconfiguration -> startplaying
TheFlash98 May 25, 2018
fe2be67
Link a few more buttons
TheFlash98 May 25, 2018
90dcc79
Time progression default value 0
TheFlash98 May 25, 2018
b0dbbab
finish game name + game template
TheFlash98 May 27, 2018
e7f3c25
Finish play from NewGameScreen
TheFlash98 May 28, 2018
7070ddb
Support hosting a game
TheFlash98 May 28, 2018
bd943d9
Move AdvanceGameSetupScreen to relevant folder
TheFlash98 May 30, 2018
9a6c290
Basic advance game setup screen done
TheFlash98 May 30, 2018
caaedfe
A few corrections to new game screen
TheFlash98 May 30, 2018
e6443e8
Loads world generators and world names on universe setup screen
TheFlash98 May 30, 2018
be003ce
Remove useless System.out.println()
TheFlash98 May 30, 2018
0759bf7
Empty worlds list when screen in closed + style tweaks
TheFlash98 May 31, 2018
f2e2e90
Correct Copyright year
TheFlash98 May 31, 2018
60c60a4
More space more visible options
TheFlash98 May 31, 2018
9bbb5b8
A little java doc
TheFlash98 May 31, 2018
80b9532
A few hits at switching Environments
TheFlash98 Jun 1, 2018
6f7fc64
Add check for empty worlds list and popup a message
TheFlash98 Jun 2, 2018
656ca7b
Start of WorldSetup screen and new World class
TheFlash98 Jun 2, 2018
a3747d7
Able to change property values for a world
TheFlash98 Jun 3, 2018
5d74b47
Quick id corrections
TheFlash98 Jun 3, 2018
aa6a4bd
Display world list in worldpregenscreen
TheFlash98 Jun 3, 2018
d86d2d7
Fix Scrollable of WorldSetupScreen
TheFlash98 Jun 4, 2018
8b8bb37
Preview now loads up according to different configurations
TheFlash98 Jun 5, 2018
16ac9d5
Link worldpren -> worldsetup
TheFlash98 Jun 5, 2018
0311a53
Add zoom to preview screen
TheFlash98 Jun 5, 2018
b436ae4
re-roll the world seed
TheFlash98 Jun 5, 2018
130e271
StartPlaying screen done
TheFlash98 Jun 5, 2018
ea8acf3
code clean up
TheFlash98 Jun 5, 2018
d210112
World -> WorldSetupWrapper
TheFlash98 Jun 5, 2018
deedf14
show preview when screen is opened
TheFlash98 Jun 5, 2018
5bf54e1
Some java doc
TheFlash98 Jun 5, 2018
11b1914
Add universe wrapper for game name, seed and mulitplayer
TheFlash98 Jun 7, 2018
03e9098
Give seed when game rum from NewGameScreen
TheFlash98 Jun 7, 2018
ccfe308
Display world name on top of WorldSetup and StartPlaying screens
TheFlash98 Jun 7, 2018
3ca6d32
Change timeoffset to start game at 12 noon
TheFlash98 Jun 7, 2018
f97587a
Change preview everytime zoom changes
TheFlash98 Jun 7, 2018
8830a3d
A few fixes as asked in the review
TheFlash98 Jun 7, 2018
483d300
Address changes requested by vampcat
TheFlash98 Jun 8, 2018
9a859e4
Remove HeightMap support, for now
TheFlash98 Jun 8, 2018
721d204
Set enabled as false for unused elements
TheFlash98 Jun 9, 2018
3b37ed7
Remove message popup on clicking re-roll
TheFlash98 Jun 9, 2018
7a7823d
Modify worldsetup UI
TheFlash98 Jun 9, 2018
5ef32ca
Create game -> new game
TheFlash98 Jun 9, 2018
88b0996
Switch from accept/cancel to a single done button
TheFlash98 Jun 10, 2018
8ebeea3
Don't allow empty game name
TheFlash98 Jun 13, 2018
bf48676
Remove test button
TheFlash98 Jun 13, 2018
cb782c4
Add temp label next to zoom slider
TheFlash98 Jun 13, 2018
99032ea
@nihal111 slider fix + remove temp + clean up
TheFlash98 Jun 14, 2018
6b677f6
Merge pull request #3388 from TheFlash98/new-create-game
nihal111 Jun 15, 2018
b14d99c
Change listener name and new interface file
TheFlash98 Jun 17, 2018
254e6ca
onSliderMouseDown -> onSliderValueChanged
TheFlash98 Jun 17, 2018
b5e0289
Checksytle + doc
TheFlash98 Jun 17, 2018
f23c0f1
Sorry I am sleepy, fixed space
TheFlash98 Jun 17, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ public class CreateGameScreen extends CoreScreenLayer {

private boolean loadingAsServer;

/**
* A UniverseWrapper object used here to determine if the game is single-player or multi-player.
*/
private UniverseWrapper universeWrapper;

@Override
@SuppressWarnings("unchecked")
public void initialise() {
Expand All @@ -102,7 +107,7 @@ public void initialise() {
gameTypeTitle.bindText(new ReadOnlyBinding<String>() {
@Override
public String get() {
if (loadingAsServer) {
if (isLoadingAsServer()) {
return translationSystem.translate("${engine:menu#select-multiplayer-game-sub-title}");
} else {
return translationSystem.translate("${engine:menu#select-singleplayer-game-sub-title}");
Expand Down Expand Up @@ -264,7 +269,7 @@ public void set(Boolean value) {
(long) (WorldTime.DAY_LENGTH * timeOffset), worldGenerator.getSelection().getUri());
gameManifest.addWorld(worldInfo);

gameEngine.changeState(new StateLoading(gameManifest, (loadingAsServer) ? NetworkMode.DEDICATED_SERVER : NetworkMode.NONE));
gameEngine.changeState(new StateLoading(gameManifest, (isLoadingAsServer()) ? NetworkMode.DEDICATED_SERVER : NetworkMode.NONE));
}
});

Expand Down Expand Up @@ -428,11 +433,11 @@ private List<Module> getGameplayModules() {
}

public boolean isLoadingAsServer() {
return loadingAsServer;
return universeWrapper.getLoadingAsServer();
}

public void setLoadingAsServer(boolean loadingAsServer) {
this.loadingAsServer = loadingAsServer;
public void setUniverseWrapper(UniverseWrapper wrapper) {
this.universeWrapper = wrapper;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ public void initialise() {
jvmWarningLabel.setVisible(NonNativeJVMDetector.JVM_ARCH_IS_NONNATIVE);

SelectGameScreen selectScreen = getManager().createScreen(SelectGameScreen.ASSET_URI, SelectGameScreen.class);

UniverseWrapper universeWrapper = new UniverseWrapper();
WidgetUtil.trySubscribe(this, "singleplayer", button -> {
selectScreen.setLoadingAsServer(false);
universeWrapper.setLoadingAsServer(false);
selectScreen.setUniverseWrapper(universeWrapper);
triggerForwardAnimation(selectScreen);
});
WidgetUtil.trySubscribe(this, "multiplayer", button -> {
selectScreen.setLoadingAsServer(true);
universeWrapper.setLoadingAsServer(true);
selectScreen.setUniverseWrapper(universeWrapper);
triggerForwardAnimation(selectScreen);
});
WidgetUtil.trySubscribe(this, "join", button -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
/*
* Copyright 2018 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.rendering.nui.layers.mainMenu;

import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.assets.ResourceUrn;
import org.terasology.config.Config;
import org.terasology.config.ModuleConfig;
import org.terasology.engine.GameEngine;
import org.terasology.engine.SimpleUri;
import org.terasology.engine.TerasologyConstants;
import org.terasology.engine.modes.StateLoading;
import org.terasology.engine.module.ModuleManager;
import org.terasology.engine.module.StandardModuleExtension;
import org.terasology.game.GameManifest;
import org.terasology.i18n.TranslationSystem;
import org.terasology.module.DependencyResolver;
import org.terasology.module.Module;
import org.terasology.module.ResolutionResult;
import org.terasology.naming.Name;
import org.terasology.network.NetworkMode;
import org.terasology.registry.In;
import org.terasology.rendering.nui.Canvas;
import org.terasology.rendering.nui.Color;
import org.terasology.rendering.nui.CoreScreenLayer;
import org.terasology.rendering.nui.WidgetUtil;
import org.terasology.rendering.nui.animation.MenuAnimationSystems;
import org.terasology.rendering.nui.databinding.Binding;
import org.terasology.rendering.nui.databinding.ReadOnlyBinding;
import org.terasology.rendering.nui.itemRendering.StringTextRenderer;
import org.terasology.rendering.nui.layers.mainMenu.savedGames.GameInfo;
import org.terasology.rendering.nui.layers.mainMenu.savedGames.GameProvider;
import org.terasology.rendering.nui.layers.mainMenu.selectModulesScreen.AdvancedGameSetupScreen;
import org.terasology.rendering.nui.widgets.UIDropdown;
import org.terasology.rendering.nui.widgets.UIDropdownScrollable;
import org.terasology.rendering.nui.widgets.UILabel;
import org.terasology.rendering.nui.widgets.UIText;
import org.terasology.utilities.random.FastRandom;
import org.terasology.world.generator.internal.WorldGeneratorInfo;
import org.terasology.world.generator.internal.WorldGeneratorManager;
import org.terasology.world.internal.WorldInfo;
import org.terasology.world.time.WorldTime;

import java.util.Collections;
import java.util.List;

public class NewGameScreen extends CoreScreenLayer {

public static final ResourceUrn ASSET_URI = new ResourceUrn("engine:newGameScreen");
private static final String DEFAULT_GAME_NAME_PREFIX = "Game ";
private static final Logger logger = LoggerFactory.getLogger(CreateGameScreen.class);
private static final String DEFAULT_GAME_TEMPLATE_NAME = "JoshariasSurvival";
private static final String DEFAULT_WORLD_GENERATOR = "Core:FacetedPerlin";
private boolean loadingAsServer;

@In
private ModuleManager moduleManager;

@In
private Config config;

@In
private WorldGeneratorManager worldGeneratorManager;

@In
private GameEngine gameEngine;

@In
private TranslationSystem translationSystem;

private UniverseWrapper universeWrapper;

@Override
public void initialise() {

setAnimationSystem(MenuAnimationSystems.createDefaultSwipeAnimation());

UILabel gameTypeTitle = find("gameTypeTitle", UILabel.class);
if (gameTypeTitle != null) {
gameTypeTitle.bindText(new ReadOnlyBinding<String>() {
@Override
public String get() {
if (isLoadingAsServer()) {
return translationSystem.translate("${engine:menu#select-multiplayer-game-sub-title}");
} else {
return translationSystem.translate("${engine:menu#select-singleplayer-game-sub-title}");
}
}
});
}
final UIText gameName = find("gameName", UIText.class);
setGameName(gameName);

final UIDropdownScrollable<Module> gameplay = find("gameplay", UIDropdownScrollable.class);
gameplay.setOptions(getGameplayModules());
gameplay.setVisibleOptions(5);
gameplay.bindSelection(new Binding<Module>() {
Module selected;

@Override
public Module get() {
return selected;
}

@Override
public void set(Module value) {
setSelectedGameplayModule(value);
selected = value;
}
});
gameplay.setOptionRenderer(new StringTextRenderer<Module>() {
@Override
public String getString(Module value) {
return value.getMetadata().getDisplayName().value();
}

@Override
public void draw(Module value, Canvas canvas) {
canvas.getCurrentStyle().setTextColor(validateModuleDependencies(value.getId()) ? Color.WHITE : Color.RED);
super.draw(value, canvas);
canvas.getCurrentStyle().setTextColor(Color.WHITE);
}
});

UILabel gameplayDescription = find("gameplayDescription", UILabel.class);
gameplayDescription.bindText(new ReadOnlyBinding<String>() {
@Override
public String get() {
Module selectedModule = gameplay.getSelection();
if (selectedModule != null) {
return selectedModule.getMetadata().getDescription().value();
} else {
return "";
}
}
});

AdvancedGameSetupScreen advancedSetupGameScreen = getManager().createScreen(AdvancedGameSetupScreen.ASSET_URI, AdvancedGameSetupScreen.class);
WidgetUtil.trySubscribe(this, "advancedSetup", button -> {
universeWrapper.setGameName(gameName.getText());
advancedSetupGameScreen.setUniverseWrapper(universeWrapper);
triggerForwardAnimation(advancedSetupGameScreen);
});

WidgetUtil.trySubscribe(this, "play", button -> {
if(gameName.getText().isEmpty()) {
getManager().pushScreen(MessagePopup.ASSET_URI, MessagePopup.class).setMessage("Error", "Game name cannot be empty");
} else {
GameManifest gameManifest = new GameManifest();

gameManifest.setTitle(gameName.getText());
String tempSeed = new FastRandom().nextString(32);
gameManifest.setSeed(tempSeed);
DependencyResolver resolver = new DependencyResolver(moduleManager.getRegistry());
ResolutionResult result = resolver.resolve(config.getDefaultModSelection().listModules());
if (!result.isSuccess()) {
MessagePopup errorMessagePopup = getManager().pushScreen(MessagePopup.ASSET_URI, MessagePopup.class);
if (errorMessagePopup != null) {
errorMessagePopup.setMessage("Invalid Module Selection", "Please review your module seleciton and try again");
}
return;
}
for (Module module : result.getModules()) {
gameManifest.addModule(module.getId(), module.getVersion());
}

SimpleUri uri = config.getWorldGeneration().getDefaultGenerator();
// This is multiplied by the number of seconds in a day (86400000) to determine the exact millisecond at which the game will start.
final float timeOffset = 0.50f;
WorldInfo worldInfo = new WorldInfo(TerasologyConstants.MAIN_WORLD, tempSeed,
(long) (WorldTime.DAY_LENGTH * timeOffset), uri);
gameManifest.addWorld(worldInfo);
gameEngine.changeState(new StateLoading(gameManifest, (isLoadingAsServer()) ? NetworkMode.DEDICATED_SERVER : NetworkMode.NONE));
}
});

WidgetUtil.trySubscribe(this, "close", button ->
triggerBackAnimation()
);
}

/**
* Sets the game names based on the game number of the last saved game
* @param gameName The {@link UIText} in which the name will be displayed.
*/
private void setGameName(UIText gameName) {
if (gameName != null) {
int gameNumber = 1;
for (GameInfo info : GameProvider.getSavedGames()) {
if (info.getManifest().getTitle().startsWith(DEFAULT_GAME_NAME_PREFIX)) {
String remainder = info.getManifest().getTitle().substring(DEFAULT_GAME_NAME_PREFIX.length());
try {
gameNumber = Math.max(gameNumber, Integer.parseInt(remainder) + 1);
} catch (NumberFormatException e) {
logger.trace("Could not parse {} as integer (not an error)", remainder, e);
}
}
}

gameName.setText(DEFAULT_GAME_NAME_PREFIX + gameNumber);
}
}

private List<Module> getGameplayModules() {
List<Module> gameplayModules = Lists.newArrayList();
for (Name moduleId : moduleManager.getRegistry().getModuleIds()) {
Module latestVersion = moduleManager.getRegistry().getLatestModuleVersion(moduleId);
if (!latestVersion.isOnClasspath()) {
if (StandardModuleExtension.isGameplayModule(latestVersion)) {
gameplayModules.add(latestVersion);
}
}
}
Collections.sort(gameplayModules, (o1, o2) ->
o1.getMetadata().getDisplayName().value().compareTo(o2.getMetadata().getDisplayName().value()));

return gameplayModules;
}

private boolean validateModuleDependencies(Name moduleName) {
DependencyResolver resolver = new DependencyResolver(moduleManager.getRegistry());
return resolver.resolve(moduleName).isSuccess();
}

private void setSelectedGameplayModule(Module module) {
ModuleConfig moduleConfig = config.getDefaultModSelection();
if (moduleConfig.getDefaultGameplayModuleName().equals(module.getId().toString())) {
// same as before -> we're done
return;
}

moduleConfig.setDefaultGameplayModuleName(module.getId().toString());
moduleConfig.clear();
moduleConfig.addModule(module.getId());

// Set the default generator of the selected gameplay module
setDefaultGeneratorOfGameplayModule(module);

config.save();
}

// Sets the default generator of the passed in gameplay module. Make sure it's already selected.
private void setDefaultGeneratorOfGameplayModule(Module module) {
ModuleConfig moduleConfig = config.getDefaultModSelection();

// Set the default generator of the selected gameplay module
SimpleUri defaultWorldGenerator = StandardModuleExtension.getDefaultWorldGenerator(module);
if (defaultWorldGenerator != null) {
for (WorldGeneratorInfo worldGenInfo : worldGeneratorManager.getWorldGenerators()) {
if (worldGenInfo.getUri().equals(defaultWorldGenerator)) {
config.getWorldGeneration().setDefaultGenerator(worldGenInfo.getUri());
}
}
}

config.save();
}


@Override
public void onOpened() {
final UIText gameName = find("gameName", UIText.class);
setGameName(gameName);

final UIDropdown<Module> gameplay = find("gameplay", UIDropdown.class);

String configDefaultModuleName = config.getDefaultModSelection().getDefaultGameplayModuleName();
String useThisModuleName = "";

// Get the default gameplay module from the config if it exists. This is likely to have a user triggered selection.
// Otherwise, default to DEFAULT_GAME_TEMPLATE_NAME.
if ("".equalsIgnoreCase(configDefaultModuleName) || DEFAULT_GAME_TEMPLATE_NAME.equalsIgnoreCase(configDefaultModuleName)) {
useThisModuleName = DEFAULT_GAME_TEMPLATE_NAME;
} else {
useThisModuleName = configDefaultModuleName;
}

Name defaultGameplayModuleName = new Name(useThisModuleName);
Module defaultGameplayModule = moduleManager.getRegistry().getLatestModuleVersion(defaultGameplayModuleName);

if (defaultGameplayModule != null) {
gameplay.setSelection(defaultGameplayModule);

if (configDefaultModuleName.equalsIgnoreCase(DEFAULT_GAME_TEMPLATE_NAME)) {
setDefaultGeneratorOfGameplayModule(defaultGameplayModule);
}
} else {
// Find the first gameplay module that is available.
for (Module module : moduleManager.getRegistry()) {
// Module is null if it is no longer present.
if (module != null && StandardModuleExtension.isGameplayModule(module)) {
gameplay.setSelection(module);
break;
}
}
}
}

public boolean isLoadingAsServer() {
return universeWrapper.getLoadingAsServer();
}

public void setUniverseWrapper(UniverseWrapper wrapper) {
this.universeWrapper = wrapper;
}

}

Loading