Skip to content

Commit 190ef7d

Browse files
committed
feat(save): add module select UI for new games
1 parent 1501eb5 commit 190ef7d

File tree

13 files changed

+360
-15
lines changed

13 files changed

+360
-15
lines changed

engine/src/main/java/org/destinationsol/SolApplication.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ private void draw() {
333333

334334
public void play(boolean tut, String shipName, boolean isNewGame, WorldConfig worldConfig) {
335335
ModuleManager moduleManager = appContext.getBean(ModuleManager.class);
336+
moduleManager.loadEnvironment(worldConfig.getModules());
337+
appContext.getBean(AssetHelper.class).switchEnvironment(moduleManager.getEnvironment());
338+
336339
gameContext = appContext.getNestedContainer(
337340
new GameConfigurationServiceRegistry(worldConfig),
338341
new EventReceiverServiceRegistry(moduleManager.getEnvironment()),

engine/src/main/java/org/destinationsol/assets/AssetHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ public Set<ResourceUrn> listAssets(Class<? extends Asset<?>> type, String asset,
131131
return list;
132132
}
133133

134+
public void switchEnvironment(ModuleEnvironment environment) {
135+
assetTypeManager.switchEnvironment(environment);
136+
}
137+
134138
public void dispose() {
135139
try {
136140
assetTypeManager.unloadEnvironment();

engine/src/main/java/org/destinationsol/assets/music/OggMusicManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public void unregisterModuleMusic() {
238238
}
239239

240240
public void resetMusic() {
241-
musicMap.put(GAME_MUSIC_SET, new ArrayList<>());
241+
musicMap.clear();
242242
}
243243

244244
public String getCurrentMusicSet() {

engine/src/main/java/org/destinationsol/game/SaveManager.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@
3636
import org.destinationsol.game.item.SolItem;
3737
import org.destinationsol.game.ship.SolShip;
3838
import org.destinationsol.game.ship.hulls.HullConfig;
39+
import org.destinationsol.modules.ModuleManager;
3940
import org.destinationsol.ui.Waypoint;
4041
import org.slf4j.Logger;
4142
import org.slf4j.LoggerFactory;
4243
import org.terasology.context.annotation.API;
44+
import org.terasology.gestalt.module.Module;
45+
import org.terasology.gestalt.naming.Name;
4346

4447
import java.io.File;
4548
import java.io.FileNotFoundException;
@@ -50,8 +53,10 @@
5053
import java.security.AccessController;
5154
import java.security.PrivilegedAction;
5255
import java.util.ArrayList;
56+
import java.util.HashSet;
5357
import java.util.List;
5458
import java.util.Optional;
59+
import java.util.Set;
5560

5661
@API
5762
public class SaveManager {
@@ -263,6 +268,15 @@ public static void saveWorld(WorldConfig worldConfig) {
263268
}
264269
world.add("featureGenerators", featureGenerators);
265270

271+
JsonArray modulesArray = new JsonArray();
272+
for (Name module : ModuleManager.getEnvironmentStatic().getModuleIdsOrderedByDependencies()) {
273+
// Exclude built-in modules
274+
if (module.compareTo("engine") != 0 && module.compareTo("nui") != 0) {
275+
modulesArray.add(module.toString());
276+
}
277+
}
278+
world.add("modules", modulesArray);
279+
266280
Gson gson = new GsonBuilder().setPrettyPrinting().create();
267281
String stringToWrite = gson.toJson(world);
268282

@@ -316,6 +330,24 @@ public static Optional<WorldConfig> loadWorld() {
316330
config.setFeatureGenerators(featureGenerators);
317331
}
318332

333+
if (world.has("modules")) {
334+
Set<Module> modules = new HashSet<>();
335+
for (JsonElement value : world.getAsJsonArray("modules")) {
336+
if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) {
337+
Module module = ModuleManager.getEnvironmentStatic().get(new Name(value.getAsString()));
338+
if (module != null) {
339+
modules.add(module);
340+
} else {
341+
logger.warn("The module \"" + value.getAsString() + "\" is missing!");
342+
}
343+
}
344+
}
345+
config.setModules(modules);
346+
} else {
347+
// This is for compatibility with older saves, which always used all modules unconditionally.
348+
config.setModules(new HashSet<>(ModuleManager.getEnvironmentStatic().getModulesOrderedByDependencies()));
349+
}
350+
319351
logger.debug("Successfully loaded the world file");
320352
return Optional.of(config);
321353
} catch (FileNotFoundException e) {

engine/src/main/java/org/destinationsol/game/WorldConfig.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,37 @@
1616
package org.destinationsol.game;
1717

1818
import org.destinationsol.game.planet.SystemsBuilder;
19+
import org.terasology.gestalt.module.Module;
1920

2021
import java.util.ArrayList;
22+
import java.util.HashSet;
2123
import java.util.List;
24+
import java.util.Set;
2225

2326
public class WorldConfig {
2427
protected long seed;
2528
protected int numberOfSystems;
2629
private List<String> solarSystemGenerators;
2730
private List<String> featureGenerators;
31+
private Set<Module> modules;
2832

2933
public WorldConfig() {
3034
seed = System.currentTimeMillis();
3135
numberOfSystems = SystemsBuilder.DEFAULT_SYSTEM_COUNT;
3236
solarSystemGenerators = new ArrayList<>();
3337
featureGenerators = new ArrayList<>();
38+
modules = new HashSet<>();
3439
}
3540

3641
public WorldConfig(long seed, int numberOfSystems,
3742
List<String> solarSystemGenerators,
38-
List<String> featureGenerators) {
43+
List<String> featureGenerators,
44+
Set<Module> modules) {
3945
this.seed = seed;
4046
this.numberOfSystems = numberOfSystems;
4147
this.solarSystemGenerators = solarSystemGenerators;
4248
this.featureGenerators = featureGenerators;
49+
this.modules = modules;
4350
}
4451

4552
public long getSeed() {
@@ -73,4 +80,12 @@ public List<String> getFeatureGenerators() {
7380
public void setSolarSystemGenerators(List<String> solarSystemGenerators) {
7481
this.solarSystemGenerators = solarSystemGenerators;
7582
}
83+
84+
public Set<Module> getModules() {
85+
return modules;
86+
}
87+
88+
public void setModules(Set<Module> modules) {
89+
this.modules = modules;
90+
}
7691
}

engine/src/main/java/org/destinationsol/menu/MenuScreens.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.destinationsol.ui.nui.screens.mainMenu.InputMapScreen;
2323
import org.destinationsol.ui.nui.screens.mainMenu.LoadingScreen;
2424
import org.destinationsol.ui.nui.screens.mainMenu.MainMenuScreen;
25+
import org.destinationsol.ui.nui.screens.mainMenu.ModulesScreen;
2526
import org.destinationsol.ui.nui.screens.mainMenu.NewGameScreen;
2627
import org.destinationsol.ui.nui.screens.mainMenu.NewShipScreen;
2728
import org.destinationsol.ui.nui.screens.mainMenu.OptionsScreen;
@@ -36,6 +37,7 @@ public class MenuScreens {
3637
public final LoadingScreen loading;
3738
public final NewGameScreen newGame;
3839
public final NewShipScreen newShip;
40+
public final ModulesScreen modules;
3941

4042
public MenuScreens(SolLayouts layouts, boolean mobile, GameOptions gameOptions, NUIManager nuiManager) {
4143
MenuLayout menuLayout = layouts.menuLayout;
@@ -47,5 +49,6 @@ public MenuScreens(SolLayouts layouts, boolean mobile, GameOptions gameOptions,
4749
loading = (LoadingScreen) nuiManager.createScreen("engine:loadingScreen");
4850
newGame = (NewGameScreen) nuiManager.createScreen("engine:newGameScreen");
4951
newShip = (NewShipScreen) nuiManager.createScreen("engine:newShipScreen");
52+
modules = (ModulesScreen) nuiManager.createScreen("engine:modulesScreen");
5053
}
5154
}

engine/src/main/java/org/destinationsol/modules/ModuleManager.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ public class ModuleManager implements AutoCloseable {
220220
private final FacadeModuleConfig moduleConfig;
221221
protected ModuleRegistry registry;
222222
protected Module engineModule;
223+
private Set<Module> builtInModules;
223224

224225
@Inject
225226
public ModuleManager(BeanContext beanContext, ModuleFactory moduleFactory, ModuleRegistry moduleRegistry,
@@ -240,9 +241,12 @@ public void init() throws Exception {
240241
File modulesRoot = moduleConfig.getModulesPath();
241242
scanner.scan(registry, modulesRoot);
242243

244+
builtInModules = Sets.newHashSet();
245+
builtInModules.add(engineModule);
246+
builtInModules.add(nuiModule);
247+
registry.addAll(builtInModules);
248+
243249
Set<Module> requiredModules = Sets.newHashSet();
244-
registry.add(engineModule);
245-
registry.add(nuiModule);
246250
requiredModules.addAll(registry);
247251

248252
loadEnvironment(requiredModules);
@@ -253,6 +257,8 @@ public void init() throws Exception {
253257
}
254258

255259
public void loadEnvironment(Set<Module> modules) {
260+
modules.addAll(builtInModules);
261+
256262
StandardPermissionProviderFactory permissionFactory = new StandardPermissionProviderFactory();
257263
for (String api : API_WHITELIST) {
258264
permissionFactory.getBasePermissionSet().addAPIPackage(api);
@@ -288,6 +294,10 @@ public ModuleEnvironment getEnvironment() {
288294
return environment;
289295
}
290296

297+
public Set<Module> getBuiltInModules() {
298+
return builtInModules;
299+
}
300+
291301
//TODO: REMOVE THIS
292302
public static ModuleEnvironment getEnvironmentStatic() {
293303
return environment;
@@ -299,6 +309,10 @@ public void printAvailableModules() {
299309
}
300310
}
301311

312+
public ModuleRegistry getRegistry() {
313+
return registry;
314+
}
315+
302316
public void dispose() {
303317
environment.close();
304318
}

engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,37 @@
2020
import org.destinationsol.SolApplication;
2121
import org.destinationsol.assets.music.OggMusicManager;
2222
import org.destinationsol.game.WorldConfig;
23+
import org.destinationsol.modules.ModuleManager;
2324
import org.destinationsol.ui.nui.NUIManager;
2425
import org.destinationsol.ui.nui.NUIScreenLayer;
2526
import org.terasology.nui.Canvas;
2627
import org.terasology.nui.widgets.UIButton;
2728

2829
import javax.inject.Inject;
30+
import java.util.HashSet;
2931

3032
/**
3133
* The main menu screen. This is the first screen shown when you open the game.
3234
*/
3335
public class MainMenuScreen extends NUIScreenLayer {
3436

3537
private final SolApplication solApplication;
38+
private final ModuleManager moduleManager;
3639
private UIButton tutorialButton;
3740

3841
@Inject
39-
public MainMenuScreen(SolApplication solApplication) {
42+
public MainMenuScreen(SolApplication solApplication, ModuleManager moduleManager) {
4043
this.solApplication = solApplication;
44+
this.moduleManager = moduleManager;
4145
}
4246

4347
@Override
4448
public void initialise() {
4549
tutorialButton = find("tutorialButton", UIButton.class);
4650
tutorialButton.subscribe(button -> {
47-
solApplication.getMenuScreens().loading.setMode(true, "Imperial Small", true, new WorldConfig());
51+
WorldConfig worldConfig = new WorldConfig();
52+
worldConfig.setModules(new HashSet<>(moduleManager.getEnvironment().getModulesOrderedByDependencies()));
53+
solApplication.getMenuScreens().loading.setMode(true, "Imperial Small", true, worldConfig);
4854
nuiManager.setScreen(solApplication.getMenuScreens().loading);
4955
});
5056

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2022 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.destinationsol.ui.nui.screens.mainMenu;
18+
19+
import org.destinationsol.SolApplication;
20+
import org.destinationsol.modules.ModuleManager;
21+
import org.destinationsol.ui.nui.NUIScreenLayer;
22+
import org.terasology.gestalt.module.Module;
23+
import org.terasology.nui.databinding.ReadOnlyBinding;
24+
import org.terasology.nui.itemRendering.StringTextRenderer;
25+
import org.terasology.nui.widgets.UIButton;
26+
import org.terasology.nui.widgets.UIList;
27+
28+
import javax.inject.Inject;
29+
import java.util.ArrayList;
30+
import java.util.HashSet;
31+
import java.util.List;
32+
import java.util.Set;
33+
34+
/**
35+
* This screen is used to select the modules that should be active when playing a particular save.
36+
* You can activate and de-activate modules only when initially creating a game.
37+
* This is to prevent side-effects from new modules being introduced unexpectedly.
38+
*/
39+
public class ModulesScreen extends NUIScreenLayer {
40+
private final SolApplication solApplication;
41+
private final ModuleManager moduleManager;
42+
private Set<Module> selectedModules;
43+
44+
@Inject
45+
public ModulesScreen(SolApplication solApplication, ModuleManager moduleManager) {
46+
this.solApplication = solApplication;
47+
this.moduleManager = moduleManager;
48+
}
49+
50+
@Override
51+
public void initialise() {
52+
selectedModules = new HashSet<>();
53+
54+
UIList<Module> moduleList = find("modulesList", UIList.class);
55+
List<Module> modules = new ArrayList<>(moduleManager.getEnvironment().getModulesOrderedByDependencies());
56+
modules.removeAll(moduleManager.getBuiltInModules());
57+
moduleList.setList(modules);
58+
moduleList.setItemRenderer(new StringTextRenderer<Module>() {
59+
@Override
60+
public String getString(Module value) {
61+
if (!selectedModules.contains(value)) {
62+
return value.getId().toString();
63+
} else {
64+
return value.getId().toString() + " (Active)";
65+
}
66+
}
67+
});
68+
moduleList.subscribe((list, module) -> {
69+
if (selectedModules.contains(module)) {
70+
selectedModules.remove(module);
71+
} else {
72+
selectedModules.add(module);
73+
}
74+
});
75+
76+
UIButton activateButton = find("activateButton", UIButton.class);
77+
activateButton.bindEnabled(new ReadOnlyBinding<Boolean>() {
78+
@Override
79+
public Boolean get() {
80+
Module selectedModule = moduleList.getSelection();
81+
return selectedModule != null && !selectedModules.contains(selectedModule);
82+
}
83+
});
84+
activateButton.subscribe(button -> selectedModules.add(moduleList.getSelection()));
85+
86+
UIButton deactivateButton = find("deactivateButton", UIButton.class);
87+
deactivateButton.bindEnabled(new ReadOnlyBinding<Boolean>() {
88+
@Override
89+
public Boolean get() {
90+
Module selectedModule = moduleList.getSelection();
91+
return selectedModule != null && selectedModules.contains(selectedModule);
92+
}
93+
});
94+
deactivateButton.subscribe(button -> selectedModules.remove(moduleList.getSelection()));
95+
96+
UIButton confirmButton = find("confirmButton", UIButton.class);
97+
confirmButton.subscribe(button -> {
98+
nuiManager.setScreen(solApplication.getMenuScreens().newShip);
99+
});
100+
}
101+
102+
public Set<Module> getSelectedModules() {
103+
return selectedModules;
104+
}
105+
106+
public void setSelectedModules(Set<Module> selectedModules) {
107+
this.selectedModules = selectedModules;
108+
}
109+
}

0 commit comments

Comments
 (0)