From ead43da3e35171326602fd1e6678b48409f3e0c7 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Fri, 21 Jun 2024 15:24:51 +0100 Subject: [PATCH 01/11] fix: parent chapter/group creation popup panels to the quest screen Otherwise they are drawn relative to the chapter panel, which can pop in and out... --- .../ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java b/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java index e34d6434..df025f60 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java @@ -196,7 +196,7 @@ public void onClicked(MouseButton button) { List contextMenu = new ArrayList<>(); contextMenu.add(new ContextMenuItem(Component.translatable("ftbquests.chapter"), ThemeProperties.ADD_ICON.get(), b -> { StringConfig c = new StringConfig(NON_EMPTY_PAT); - EditStringConfigOverlay overlay = new EditStringConfigOverlay<>(parent, c, accepted -> { + EditStringConfigOverlay overlay = new EditStringConfigOverlay<>(parent.getParent(), c, accepted -> { chapterPanel.questScreen.openGui(); if (accepted && !c.getValue().isEmpty()) { @@ -215,7 +215,7 @@ public void onClicked(MouseButton button) { contextMenu.add(new ContextMenuItem(Component.translatable("ftbquests.chapter_group"), ThemeProperties.ADD_ICON.get(), b -> { StringConfig c = new StringConfig(NON_EMPTY_PAT); - EditStringConfigOverlay overlay = new EditStringConfigOverlay<>(parent, c, accepted -> { + EditStringConfigOverlay overlay = new EditStringConfigOverlay<>(parent.getParent(), c, accepted -> { chapterPanel.questScreen.openGui(); if (accepted) { @@ -298,7 +298,7 @@ public void onClicked(MouseButton button) { playClickSound(); StringConfig c = new StringConfig(NON_EMPTY_PAT); - EditStringConfigOverlay overlay = new EditStringConfigOverlay<>(parent, c, accepted -> { + EditStringConfigOverlay overlay = new EditStringConfigOverlay<>(parent.getParent(), c, accepted -> { chapterPanel.questScreen.openGui(); if (accepted && !c.getValue().isEmpty()) { From 6ed1dbd6b7a39bdc41297b693ec30c92e06b9b51 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Fri, 21 Jun 2024 15:25:45 +0100 Subject: [PATCH 02/11] build: version -> 2006.1.1, changelog updated --- CHANGELOG.md | 5 +++++ gradle.properties | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b88623d..f63e930d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +# [2006.1.1] + +### Fixed +* Fixed chapter and chapter group creation popups moving in and out with the chapter panel when it's not pinned. + # [2006.1.0] ### Changed diff --git a/gradle.properties b/gradle.properties index 3e092d76..8c707c2b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ maven_group=dev.ftb.mods mod_author=FTB Team # Build time -mod_version=2100.1.0 +mod_version=2100.1.1 minecraft_version=1.21 From d7af03527fef0cee1c7b20363421f972560e02ea Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Fri, 21 Jun 2024 17:57:09 +0100 Subject: [PATCH 03/11] fix: remove misleading tooltip from Task --- .../src/main/java/dev/ftb/mods/ftbquests/quest/task/Task.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/Task.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/Task.java index 69406a90..ec1c919a 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/Task.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/Task.java @@ -233,10 +233,6 @@ public void addMouseOverHeader(TooltipList list, TeamData teamData, boolean adva */ @Environment(EnvType.CLIENT) public void addMouseOverText(TooltipList list, TeamData teamData) { - if (consumesResources()) { - list.blankLine(); - list.add(Component.translatable("ftbquests.task.click_to_submit").withStyle(ChatFormatting.YELLOW, ChatFormatting.UNDERLINE)); - } } @Environment(EnvType.CLIENT) From 3efe4b5d6a449bb13345c4f8db03953a06371da5 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Fri, 21 Jun 2024 17:58:10 +0100 Subject: [PATCH 04/11] build: bump ftb library & neoforge dep versions --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 8c707c2b..15d996bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,14 +16,14 @@ minecraft_version=1.21 # Cross env #forge_version=50.0.9 #forge_loader_version=49 -neoforge_version=21.0.10-beta +neoforge_version=21.0.21-beta # https://maven.neoforged.net/#/releases/net/neoforged/fancymodloader/loader neoforge_loader_version=4 fabric_loader_version=0.15.11 fabric_api_version=0.100.1+1.21 architectury_api_version=13.0.1 -ftb_library_version=2100.1.0 +ftb_library_version=2100.1.1 ftb_teams_version=2100.1.0 # Optional deps From 10a0bab85c9a0f3d5a3f6ae2adb42f1a2940f472 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 07:45:16 +0100 Subject: [PATCH 05/11] fix: crash in advancement task init https://github.com/FTBTeam/FTB-Mods-Issues/issues/1233 --- .../java/dev/ftb/mods/ftbquests/quest/task/AdvancementTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/AdvancementTask.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/AdvancementTask.java index 9da1c861..f69f15c8 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/AdvancementTask.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/AdvancementTask.java @@ -22,7 +22,7 @@ import net.minecraft.server.level.ServerPlayer; public class AdvancementTask extends AbstractBooleanTask { - private ResourceLocation advancement = ResourceLocation.withDefaultNamespace("minecraft:story/root"); + private ResourceLocation advancement = ResourceLocation.parse("minecraft:story/root"); private String criterion = ""; public AdvancementTask(long id, Quest quest) { From c883c52234a23ea6f700145e0fc86d09fd67af15 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 09:44:20 +0100 Subject: [PATCH 06/11] fix: crash in kill tank init https://github.com/FTBTeam/FTB-Mods-Issues/issues/1232 --- .../main/java/dev/ftb/mods/ftbquests/quest/task/KillTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/KillTask.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/KillTask.java index 488c69a9..a4fb840b 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/KillTask.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/KillTask.java @@ -26,7 +26,7 @@ import java.util.List; public class KillTask extends Task { - private static final ResourceLocation ZOMBIE = ResourceLocation.withDefaultNamespace("minecraft:zombie"); + private static final ResourceLocation ZOMBIE = ResourceLocation.parse("minecraft:zombie"); private ResourceLocation entity = ZOMBIE; private long value = 100L; From 70e48bedecbef9b5acd63ec4507511b97ac031f2 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 09:54:34 +0100 Subject: [PATCH 07/11] fix: support reading fluidstacks from legacy quest book data Format is different in 1.21 (fluidstack stored as compound tag, not separate string id and amount). --- .../ftb/mods/ftbquests/quest/task/FluidTask.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/FluidTask.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/FluidTask.java index 5cd47e70..79a35237 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/FluidTask.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/FluidTask.java @@ -14,12 +14,15 @@ import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import org.jetbrains.annotations.Nullable; @@ -88,7 +91,17 @@ public void writeData(CompoundTag nbt, HolderLookup.Provider provider) { public void readData(CompoundTag nbt, HolderLookup.Provider provider) { super.readData(nbt, provider); - fluidStack = FluidStack.read(provider, nbt.getCompound("fluid")).orElse(FluidStack.empty()); + if (nbt.contains("fluid", Tag.TAG_STRING)) { + // legacy - fluid stored as string ID + ResourceLocation id = ResourceLocation.tryParse(nbt.getString("fluid")); + if (id == null) { + fluidStack = FluidStack.create(Fluids.WATER, 1000L); + } else { + fluidStack = FluidStack.create(BuiltInRegistries.FLUID.get(id), nbt.getLong("amount")); + } + } else { + fluidStack = FluidStack.read(provider, nbt.getCompound("fluid")).orElse(FluidStack.empty()); + } } @Override From 62204385a4d39e955a26b9a3ff0bc25e9d763ec7 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 10:27:18 +0100 Subject: [PATCH 08/11] chore: added support for reading legacy quest data translations Any title/subtitle/desc text in the quest book data is now moved into the translation manager on questbook load, and then saved into lang/en_us.snbt. --- .../mods/ftbquests/quest/BaseQuestFile.java | 62 +++++++++++++++++++ .../ftb/mods/ftbquests/util/TextUtils.java | 15 +++++ 2 files changed, 77 insertions(+) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/BaseQuestFile.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/BaseQuestFile.java index f43e96ba..f18521bc 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/BaseQuestFile.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/BaseQuestFile.java @@ -20,8 +20,10 @@ import dev.ftb.mods.ftbquests.quest.reward.*; import dev.ftb.mods.ftbquests.quest.task.*; import dev.ftb.mods.ftbquests.quest.theme.property.ThemeProperties; +import dev.ftb.mods.ftbquests.quest.translation.TranslationKey; import dev.ftb.mods.ftbquests.quest.translation.TranslationManager; import dev.ftb.mods.ftbquests.util.FileUtils; +import dev.ftb.mods.ftbquests.util.TextUtils; import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; import dev.ftb.mods.ftbteams.api.Team; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -561,6 +563,7 @@ public final void readDataFull(Path folder, HolderLookup.Provider provider) { fileVersion = fileNBT.getInt("version"); questObjectMap.put(1, this); readData(fileNBT, provider); + handleLegacyFileNBT(fileNBT); } translationManager.loadFromNBT(folder.resolve("lang")); @@ -575,6 +578,9 @@ public final void readDataFull(Path folder, HolderLookup.Provider provider) { for (int i = 0; i < groupListTag.size(); i++) { CompoundTag groupNBT = groupListTag.getCompound(i); ChapterGroup chapterGroup = new ChapterGroup(readID(groupNBT.get("id")), this); + + handleLegacyChapterGroupNBT(groupNBT, chapterGroup); + questObjectMap.put(chapterGroup.id, chapterGroup); dataCache.put(chapterGroup.id, groupNBT); chapterGroups.add(chapterGroup); @@ -597,6 +603,9 @@ public final void readDataFull(Path folder, HolderLookup.Provider provider) { getChapterGroup(getID(chapterNBT.get("group"))), path.getFileName().toString().replace(".snbt", "") ); + + handleLegacyChapterNBT(chapterNBT, chapter); + objectOrderMap.put(chapter.id, chapterNBT.getInt("order_index")); questObjectMap.put(chapter.id, chapter); dataCache.put(chapter.id, chapterNBT); @@ -607,6 +616,9 @@ public final void readDataFull(Path folder, HolderLookup.Provider provider) { for (int i = 0; i < questList.size(); i++) { CompoundTag questNBT = questList.getCompound(i); Quest quest = new Quest(readID(questNBT.get("id")), chapter); + + handleLegacyQuestNBT(quest, questNBT); + questObjectMap.put(quest.id, quest); dataCache.put(quest.id, questNBT); chapter.addQuest(quest); @@ -617,6 +629,9 @@ public final void readDataFull(Path folder, HolderLookup.Provider provider) { CompoundTag taskNBT = taskList.getCompound(j); long taskId = readID(taskNBT.get("id")); Task task = TaskType.createTask(taskId, quest, taskNBT.getString("type")); + + handleLegacyTaskNBT(task, taskNBT); + if (task == null) { task = new CustomTask(taskId, quest); task.setRawTitle("Unknown type: " + taskNBT.getString("type")); @@ -728,6 +743,53 @@ public final void readDataFull(Path folder, HolderLookup.Provider provider) { FTBQuests.LOGGER.info("Loaded {} chapter groups, {} chapters, {} quests, {} reward tables", chapterGroups.size(), chapterCounter, questCounter, rewardTables.size()); } + private void handleLegacyFileNBT(CompoundTag fileNBT) { + if (fileNBT.contains("title", Tag.TAG_STRING)) { + translationManager.addTranslation(this, "en_us", TranslationKey.TITLE, fileNBT.getString("title")); + markDirty(); + } + } + + private void handleLegacyChapterGroupNBT(CompoundTag groupNBT, ChapterGroup chapterGroup) { + if (groupNBT.contains("title", Tag.TAG_STRING)) { + translationManager.addTranslation(chapterGroup, "en_us", TranslationKey.TITLE, groupNBT.getString("title")); + markDirty(); + } + } + + private void handleLegacyChapterNBT(CompoundTag chapterNBT, Chapter chapter) { + if (chapterNBT.contains("title", Tag.TAG_STRING)) { + translationManager.addTranslation(chapter, "en_us", TranslationKey.TITLE, chapterNBT.getString("title")); + markDirty(); + } + if (chapterNBT.contains("subtitle", Tag.TAG_LIST)) { + translationManager.addTranslation(chapter, "en_us", TranslationKey.CHAPTER_SUBTITLE, TextUtils.fromListTag(chapterNBT.getList("subtitle", Tag.TAG_STRING))); + markDirty(); + } + } + + private void handleLegacyQuestNBT(Quest quest, CompoundTag questNBT) { + if (questNBT.contains("title", Tag.TAG_STRING)) { + translationManager.addTranslation(quest, "en_us", TranslationKey.TITLE, questNBT.getString("title")); + markDirty(); + } + if (questNBT.contains("subtitle", Tag.TAG_STRING)) { + translationManager.addTranslation(quest, "en_us", TranslationKey.QUEST_SUBTITLE, questNBT.getString("subtitle")); + markDirty(); + } + if (questNBT.contains("description", Tag.TAG_LIST)) { + translationManager.addTranslation(quest, "en_us", TranslationKey.QUEST_DESC, TextUtils.fromListTag(questNBT.getList("description", Tag.TAG_STRING))); + markDirty(); + } + } + + private void handleLegacyTaskNBT(Task task, CompoundTag taskNBT) { + if (taskNBT.contains("title", Tag.TAG_STRING)) { + translationManager.addTranslation(task, "en_us", TranslationKey.TITLE, taskNBT.getString("title")); + markDirty(); + } + } + public void updateLootCrates() { Set prevCrateNames = new HashSet<>(LootCrate.LOOT_CRATES.keySet()); Collection oldStacks = LootCrate.allCrateStacks(); diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/util/TextUtils.java b/common/src/main/java/dev/ftb/mods/ftbquests/util/TextUtils.java index 9ba268f3..7c79585c 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/util/TextUtils.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/util/TextUtils.java @@ -4,8 +4,13 @@ import dev.ftb.mods.ftblibrary.util.client.ClientTextComponentUtils; import net.minecraft.ChatFormatting; import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.TagType; import net.minecraft.network.chat.Component; +import java.util.ArrayList; +import java.util.List; import java.util.regex.Pattern; public class TextUtils { @@ -31,4 +36,14 @@ private static Component deserializeRawJsonText(String raw, HolderLookup.Provide return Component.literal("ERROR: " + e.getMessage()).withStyle(ChatFormatting.RED); } } + + public static List fromListTag(ListTag tag) { + List res = new ArrayList<>(); + tag.forEach(el -> { + if (el.getId() == Tag.TAG_STRING) { + res.add(el.getAsString()); + } + }); + return res; + } } From 6d99af361f083473845d68dd233d549b3443a6a0 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 12:07:11 +0100 Subject: [PATCH 09/11] chore: changelog updated [ciskip] --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f63e930d..74b4644e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed * Fixed chapter and chapter group creation popups moving in and out with the chapter panel when it's not pinned. +* Fixed crash when creating Kill and Advancement tasks +* Fixed Fluid Tasks not loading correctly from older quest book data +* Any translatable text loaded from older quest book data is now automatically migrated into the new translation system + * A `lang/en_us.snbt` file will be auto-created under your `config/ftbquests/quests` folder when an older quest book is loaded +* Removed a misleading "Click to Submit" tooltip from fluid tasks in the quest view panel + * Fluid tasks can only be submitted via a Task Screen # [2006.1.0] From 08e3a47e025ff2988ae5c70d45eb89e6242f4c4c Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 12:08:23 +0100 Subject: [PATCH 10/11] fix: versions in the changelog [ciskip] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74b4644e..54993d3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -# [2006.1.1] +# [2100.1.1] ### Fixed * Fixed chapter and chapter group creation popups moving in and out with the chapter panel when it's not pinned. @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Removed a misleading "Click to Submit" tooltip from fluid tasks in the quest view panel * Fluid tasks can only be submitted via a Task Screen -# [2006.1.0] +# [2100.1.0] ### Changed * Ported to Minecraft 1.21. Support for Fabric and NeoForge. From a1e383776de183695eba8fdee558e7ecc37b6ff5 Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Mon, 24 Jun 2024 15:21:22 +0100 Subject: [PATCH 11/11] chore: keep meaningful names for chapter SNBT files As in previous versions, chapter files are named after the chapter title, which is easier than storing it under its hex ID. --- .../client/gui/quests/ChapterPanel.java | 2 +- .../dev/ftb/mods/ftbquests/quest/Chapter.java | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java b/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java index df025f60..1fc0f285 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/quests/ChapterPanel.java @@ -302,7 +302,7 @@ public void onClicked(MouseButton button) { chapterPanel.questScreen.openGui(); if (accepted && !c.getValue().isEmpty()) { - Chapter chapter = new Chapter(0L, file, file.getDefaultChapterGroup()); + Chapter chapter = new Chapter(0L, file, file.getDefaultChapterGroup(), Chapter.titleToID( c.getValue()).orElse("")); CompoundTag extra = Util.make(new CompoundTag(), t -> t.putLong("group", group.id)); file.getTranslationManager().addInitialTranslation(extra, file.getLocale(), TranslationKey.TITLE, c.getValue()); NetworkManager.sendToServer(CreateObjectMessage.create(chapter, extra)); diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/Chapter.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/Chapter.java index da1fd729..8d014a58 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/Chapter.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/Chapter.java @@ -364,16 +364,17 @@ public void deleteChildren() { @Override public void onCreated() { + // filename should have been suggested by the client and available here + // but in case not, fall back to the chapter's hex object id if (filename.isEmpty()) { - String basename = titleToID(getRawTitle()).orElse(toString()); - filename = basename; - - Set existingNames = new HashSet<>(); - getQuestFile().forAllChapters(ch -> existingNames.add(ch.filename)); + filename = getCodeString(); + } - for (int i = 2; existingNames.contains(filename); i++) { - filename = basename + "_" + i; - } + // ensure the filename is actually unique (same chapter name could appear in multiple groups...) + Set existingNames = new HashSet<>(); + getQuestFile().forAllChapters(ch -> existingNames.add(ch.filename)); + if (existingNames.contains(filename)) { + filename = filename + "_" + getCodeString(); } group.addChapter(this);