From de37cfa88f0861567fe0d93812293bac396c3599 Mon Sep 17 00:00:00 2001 From: Rasmus Praestholm Date: Tue, 3 May 2022 16:04:03 -0500 Subject: [PATCH 1/3] fix: path quirk on an M1 Mac using Azul JDK 11 (#5006) Co-authored-by: Kevin Turner <83819+keturn@users.noreply.github.com> --- .../terasology/gradology/file_operations.kt | 28 +++++++++++++++++++ build.gradle | 22 +++++---------- 2 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 build-logic/src/main/kotlin/org/terasology/gradology/file_operations.kt diff --git a/build-logic/src/main/kotlin/org/terasology/gradology/file_operations.kt b/build-logic/src/main/kotlin/org/terasology/gradology/file_operations.kt new file mode 100644 index 00000000000..dad2e84a1f8 --- /dev/null +++ b/build-logic/src/main/kotlin/org/terasology/gradology/file_operations.kt @@ -0,0 +1,28 @@ +// Copyright 2022 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.gradology + +import org.gradle.api.internal.file.copy.CopySpecInternal +import org.gradle.api.tasks.Copy + + +/** + * Copy, but never overwrite any existing file. + * + * Preserves existing files regardless of how up-to-date they are. + * + * Useful for providing boilerplate or defaults. + */ +abstract class CopyButNeverOverwrite : Copy() { + + override fun createRootSpec(): CopySpecInternal { + val copySpec = super.createRootSpec() + copySpec.eachFile { + if (this.relativePath.getFile(destinationDir).exists()) { + this.exclude() + } + } + return copySpec; + } +} diff --git a/build.gradle b/build.gradle index b5d6dce5af8..c1e5ed907ed 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,7 @@ plugins { import org.gradle.internal.logging.text.StyledTextOutputFactory import org.jetbrains.gradle.ext.ActionDelegationConfig +import org.terasology.gradology.CopyButNeverOverwrite import static org.gradle.internal.logging.text.StyledTextOutput.Style @@ -80,7 +81,7 @@ located at ${System.getProperty("java.home")} ext { dirNatives = 'natives' dirConfigMetrics = 'config/metrics' - templatesDir = 'templates' + templatesDir = file('templates') // Lib dir for use in manifest entries etc (like in :engine). A separate "libsDir" exists, auto-created by Gradle subDirLibs = 'libs' @@ -230,19 +231,14 @@ tasks.named('wrapper') { // General IDE customization // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -task copyInMissingTemplates { +tasks.register("copyInMissingTemplates", CopyButNeverOverwrite) { description = "Copies in placeholders from the /templates dir to project root if not present yet" - File gradlePropsFile = new File(rootDir, 'gradle.properties') - File OverrideCfgFile = new File(rootDir, 'override.cfg') - if (!gradlePropsFile.exists()) { - new File(rootDir, 'gradle.properties') << new File(templatesDir, 'gradle.properties').text - } - if (!OverrideCfgFile.exists()) { - new File(rootDir, 'override.cfg') << new File(templatesDir, 'override.cfg').text - } + from(templatesDir) + into(rootDir) + include('gradle.properties', 'override.cfg') } -tasks.register("jmxPassword", Copy) { +tasks.register("jmxPassword", CopyButNeverOverwrite) { description = "Create config/jmxremote.password from a template." setFileMode(0600) // passwords must be accessible only by owner @@ -253,10 +249,6 @@ tasks.register("jmxPassword", Copy) { rename("(.*).template", '$1') into("config") - onlyIf { - // Do not overwrite an existing password file. - !it.destinationDir.toPath().resolve("jmxremote.password").toFile().exists() - } doLast { logger.warn("${it.outputs.files.singleFile}/jmxremote.password:100: Edit this to set your password.") } From b7da78758ac7672d6d7c3e8bb3f8c6fda52e8a71 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 5 May 2022 03:28:03 -0700 Subject: [PATCH 2/3] build(idea): update dictionary and gitignores (#5007) --- .idea/.gitignore | 9 +++++++-- .idea/dictionaries/kevint.xml | 4 ++++ .idea/misc.xml | 7 ++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.idea/.gitignore b/.idea/.gitignore index dc25394c5c3..cc27680a940 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -48,5 +48,10 @@ workspace.xml # Automatically created when the checkout directy name is different from git origin? /.name -# Discord files. It's user-specific and not-for-sharing -discord.xml +# Git Toolbox https://plugins.jetbrains.com/plugin/7499-gittoolbox +# Settings appear to be user-specific. +/git_toolbox_prj.xml + +# Grep Console https://plugins.jetbrains.com/plugin/7125-grep-console +# Settings appear to be workspace-specific. +/GrepConsole.xml diff --git a/.idea/dictionaries/kevint.xml b/.idea/dictionaries/kevint.xml index ec1a15440b6..2251213e7af 100644 --- a/.idea/dictionaries/kevint.xml +++ b/.idea/dictionaries/kevint.xml @@ -3,10 +3,14 @@ SPDX-License-Identifier artifactory + biome classpaths + coord deserialized deserializing gameplay + lootable + lootables minecraft reddit renderable diff --git a/.idea/misc.xml b/.idea/misc.xml index 53ca35395f0..12fcfb1f537 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,10 @@ - + - + + @@ -14,5 +15,5 @@ - + \ No newline at end of file From 685a895a3e67cc72309ca7d57cf0a90c018ef212 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 8 May 2022 10:04:07 -0700 Subject: [PATCH 3/3] fix(SelectionScreen): be more robust in the face of save files with incomplete manifests (#5008) --- .../modes/loadProcesses/InitialiseWorld.java | 6 ++-- .../terasology/engine/game/GameManifest.java | 34 ++++++++++++++++++- .../nui/layers/mainMenu/SelectionScreen.java | 27 ++++----------- .../gameDetailsScreen/GameDetailsScreen.java | 22 +++++------- .../layers/mainMenu/savedGames/GameInfo.java | 8 +++-- 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java index f77b57ad2e2..ca3928ca025 100644 --- a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java +++ b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/InitialiseWorld.java @@ -1,4 +1,4 @@ -// Copyright 2021 The Terasology Foundation +// Copyright 2022 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.core.modes.loadProcesses; @@ -58,6 +58,7 @@ import java.nio.file.Path; import static com.google.common.base.Verify.verify; +import static com.google.common.base.Verify.verifyNotNull; public class InitialiseWorld extends SingleStepLoadProcess { @@ -84,7 +85,8 @@ public boolean step() { ModuleEnvironment environment = context.get(ModuleManager.class).getEnvironment(); context.put(WorldGeneratorPluginLibrary.class, new DefaultWorldGeneratorPluginLibrary(environment, context)); - WorldInfo worldInfo = gameManifest.getWorldInfo(TerasologyConstants.MAIN_WORLD); + WorldInfo worldInfo = verifyNotNull(gameManifest.getWorldInfo(TerasologyConstants.MAIN_WORLD), + "Game manifest does not contain a MAIN_WORLD"); verify(worldInfo.getWorldGenerator().isValid(), "Game manifest did not specify world type."); if (worldInfo.getSeed() == null || worldInfo.getSeed().isEmpty()) { FastRandom random = new FastRandom(); diff --git a/engine/src/main/java/org/terasology/engine/game/GameManifest.java b/engine/src/main/java/org/terasology/engine/game/GameManifest.java index 002295b6d08..c0681e58f54 100644 --- a/engine/src/main/java/org/terasology/engine/game/GameManifest.java +++ b/engine/src/main/java/org/terasology/engine/game/GameManifest.java @@ -1,17 +1,21 @@ -// Copyright 2021 The Terasology Foundation +// Copyright 2022 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.game; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.terasology.engine.core.SimpleUri; import org.terasology.engine.core.TerasologyConstants; import org.terasology.engine.utilities.gson.CaseInsensitiveEnumTypeAdapterFactory; import org.terasology.engine.utilities.gson.UriTypeAdapterFactory; +import org.terasology.engine.world.generator.internal.WorldGeneratorManager; import org.terasology.engine.world.internal.WorldInfo; import org.terasology.gestalt.entitysystem.component.Component; import org.terasology.gestalt.naming.Name; @@ -31,6 +35,8 @@ public class GameManifest { public static final String DEFAULT_FILE_NAME = "manifest.json"; + private static final Logger logger = LoggerFactory.getLogger(GameManifest.class); + private String title = ""; private String seed = ""; private long time; @@ -174,4 +180,30 @@ public void addModule(Name id, Version version) { modules.add(new NameVersion(id, version)); } + /** + * The name of the generator used for the main world. + *

+ * Always returns a String, but may be an "ERROR:" string. + */ + public String mainWorldDisplayName(WorldGeneratorManager manager) { + var world = getWorldInfo(TerasologyConstants.MAIN_WORLD); + if (world == null) { + logger.warn("{} has no MAIN_WORLD", this); + return "ERROR: No main world"; + } + SimpleUri generatorUri = world.getWorldGenerator(); + var generator = manager.getWorldGeneratorInfo(generatorUri); + if (generator == null) { + logger.warn("{}: {} has no generator for {}", this, manager, generatorUri); + return "ERROR: No generator found for " + generatorUri; + } + return generator.getDisplayName(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("title", title) + .toString(); + } } diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/SelectionScreen.java b/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/SelectionScreen.java index 57cdc8f9ac4..e7b92627a07 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/SelectionScreen.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/SelectionScreen.java @@ -1,13 +1,12 @@ -// Copyright 2021 The Terasology Foundation +// Copyright 2022 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.rendering.nui.layers.mainMenu; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.engine.config.Config; import org.terasology.engine.config.PlayerConfig; -import org.terasology.engine.core.TerasologyConstants; +import org.terasology.engine.game.GameManifest; import org.terasology.engine.i18n.TranslationSystem; import org.terasology.engine.persistence.internal.GamePreviewImageProvider; import org.terasology.engine.registry.In; @@ -18,8 +17,8 @@ import org.terasology.engine.rendering.nui.layers.mainMenu.savedGames.GameInfo; import org.terasology.engine.utilities.Assets; import org.terasology.engine.utilities.FilesUtil; -import org.terasology.engine.world.generator.internal.WorldGeneratorInfo; import org.terasology.engine.world.generator.internal.WorldGeneratorManager; +import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.naming.Name; import org.terasology.gestalt.naming.NameVersion; import org.terasology.nui.widgets.UIImage; @@ -78,22 +77,10 @@ void updateDescription(final GameInfo gameInfo) { return; } - final WorldGeneratorInfo wgi = worldGeneratorManager.getWorldGeneratorInfo( - gameInfo.getManifest() - .getWorldInfo(TerasologyConstants.MAIN_WORLD) - .getWorldGenerator()); - - String mainWorldGenerator = "ERROR: world generator "; - if (wgi != null) { - mainWorldGenerator = wgi.getDisplayName(); - } else { - mainWorldGenerator = mainWorldGenerator + gameInfo.getManifest() - .getWorldInfo(TerasologyConstants.MAIN_WORLD) - .getWorldGenerator() - .toString() + " not found"; - } + GameManifest manifest = gameInfo.getManifest(); + String mainWorldGenerator = manifest.mainWorldDisplayName(worldGeneratorManager); - final String commaSeparatedModules = gameInfo.getManifest() + final String commaSeparatedModules = manifest .getModules() .stream() .map(NameVersion::getName) @@ -120,7 +107,7 @@ private void loadPreviewImages(final GameInfo gameInfo) { try { textureData = AWTTextureFormat.convertToTextureData(buffImage, Texture.FilterMode.LINEAR); } catch (IOException e) { - logger.error("Converting preview image to texture data {} failed", e); + logger.error("Converting preview image to texture data failed", e); return null; } return Assets.generateAsset(new ResourceUrn(PREVIEW_IMAGE_URI_PATTERN + bufferedImages.indexOf(buffImage)), diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/gameDetailsScreen/GameDetailsScreen.java b/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/gameDetailsScreen/GameDetailsScreen.java index eaa2596fa37..af6690c865d 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/gameDetailsScreen/GameDetailsScreen.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/gameDetailsScreen/GameDetailsScreen.java @@ -1,4 +1,4 @@ -// Copyright 2021 The Terasology Foundation +// Copyright 2022 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.rendering.nui.layers.mainMenu.gameDetailsScreen; @@ -9,9 +9,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.context.Context; -import org.terasology.engine.core.SimpleUri; -import org.terasology.engine.core.TerasologyConstants; import org.terasology.engine.core.module.ModuleManager; +import org.terasology.engine.game.GameManifest; import org.terasology.engine.i18n.TranslationSystem; import org.terasology.engine.registry.In; import org.terasology.engine.rendering.nui.CoreScreenLayer; @@ -21,7 +20,6 @@ import org.terasology.engine.rendering.nui.layers.mainMenu.moduleDetailsScreen.ModuleDetailsScreen; import org.terasology.engine.rendering.nui.layers.mainMenu.savedGames.GameInfo; import org.terasology.engine.utilities.time.DateTimeHelper; -import org.terasology.engine.world.generator.internal.WorldGeneratorInfo; import org.terasology.engine.world.generator.internal.WorldGeneratorManager; import org.terasology.engine.world.internal.WorldInfo; import org.terasology.gestalt.assets.ResourceUrn; @@ -392,22 +390,18 @@ private void loadGeneralInfo() { } private String getGeneralInfo(final GameInfo theGameInfo) { - SimpleUri name = theGameInfo.getManifest().getWorldInfo(TerasologyConstants.MAIN_WORLD).getWorldGenerator(); - WorldGeneratorInfo wgi = worldGeneratorManager.getWorldGeneratorInfo(name); - String display = "ERROR: generator " + name + " not found."; - if (wgi != null) { - display = wgi.getDisplayName(); - } + GameManifest manifest = theGameInfo.getManifest(); + return translationSystem.translate("${engine:menu#game-details-game-title} ") - + theGameInfo.getManifest().getTitle() + '\n' + '\n' + + + manifest.getTitle() + '\n' + '\n' + translationSystem.translate("${engine:menu#game-details-last-play}: ") + DATE_FORMAT.format(theGameInfo.getTimestamp()) + '\n' + '\n' + translationSystem.translate("${engine:menu#game-details-game-duration} ") - + DateTimeHelper.getDeltaBetweenTimestamps(new Date(0).getTime(), theGameInfo.getManifest().getTime()) + '\n' + '\n' + + + DateTimeHelper.getDeltaBetweenTimestamps(new Date(0).getTime(), manifest.getTime()) + '\n' + '\n' + translationSystem.translate("${engine:menu#game-details-game-seed} ") - + theGameInfo.getManifest().getSeed() + '\n' + '\n' + + + manifest.getSeed() + '\n' + '\n' + translationSystem.translate("${engine:menu#game-details-world-generator}: ") + '\t' - + display; + + manifest.mainWorldDisplayName(worldGeneratorManager); } private void loadGameWorlds() { diff --git a/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/savedGames/GameInfo.java b/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/savedGames/GameInfo.java index 31185ef29e0..8876ed27528 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/savedGames/GameInfo.java +++ b/engine/src/main/java/org/terasology/engine/rendering/nui/layers/mainMenu/savedGames/GameInfo.java @@ -1,4 +1,4 @@ -// Copyright 2021 The Terasology Foundation +// Copyright 2022 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.rendering.nui.layers.mainMenu.savedGames; @@ -9,6 +9,8 @@ import java.text.SimpleDateFormat; import java.util.Date; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Contains information about saved game. */ @@ -17,11 +19,11 @@ public class GameInfo { private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; private Date timestamp; - private GameManifest manifest; + private final GameManifest manifest; private Path savePath; public GameInfo(GameManifest manifest, Date timestamp, Path savePath) { - this.manifest = manifest; + this.manifest = checkNotNull(manifest, "manifest"); this.timestamp = timestamp; this.savePath = savePath; }