diff --git a/CHANGELOG.md b/CHANGELOG.md index 56069e7eb..ec26ecf70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Stage Reward now grants a team stage if "Team Reward" is true * The text color for not-started chapters in the left-hand chapter panel is now themable * It uses the `quest_not_started_color` value from `ftb_quests_theme.txt` (default is white as before) +* Added a "Copy ID" menu item to the context menu in the Reward Table editor screen + +### Changed +* FTB XMod Compat 21.1.7+ is now required, if that mod is in your instance +* The entity selector screen for the Kill task now shows entity ID's as well as the display name + * It's entirely possible for two mods to use the same display name for two different entities, leading to confusion +* The `/ftbquests generate_chapter_with_all_items_in_game` command has been overhauled and improved: + * `/ftbquests generate_chapter from_entire_creative_list` - replaces the above command. Beware: this command can cause a lot of server lag! + * `/ftbquests generate_chapter from_inventory` - creates a new chapter with an item task & quest for each item in the inventory a player is looking at + * `/ftbquests generate_chapter from_player_inventory` - creates a new chapter with an item task & quest for each item in the player's inventory/hotbar (not armor slots) ### Fixed * Fixed some logic errors related to quest exclusion and flexible mode -* Fixed UI bug causing multiline text boxes to sometimes go blank +* Fixed UI bug causing the multiline text box editor to occasionally go blank ## [2101.1.19] diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/api/ItemFilterAdapter.java b/common/src/main/java/dev/ftb/mods/ftbquests/api/ItemFilterAdapter.java index 7a56969dc..da104dd7f 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/api/ItemFilterAdapter.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/api/ItemFilterAdapter.java @@ -1,5 +1,6 @@ package dev.ftb.mods.ftbquests.api; +import net.minecraft.core.HolderLookup; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -35,7 +36,7 @@ public interface ItemFilterAdapter { * @param toCheck the itemstack to check * @return true if the first item is a filter stack AND the second item is matched by it */ - boolean doesItemMatch(ItemStack filterStack, ItemStack toCheck); + boolean doesItemMatch(ItemStack filterStack, ItemStack toCheck, HolderLookup.Provider registryAccess); /** * Retrieve the actual item matcher from this filter implementation, which is basically a predicate that can @@ -45,7 +46,7 @@ public interface ItemFilterAdapter { * @param filterStack the filter item (note: the filter, not the item to be tested!) * @return a matcher object */ - Matcher getMatcher(ItemStack filterStack); + Matcher getMatcher(ItemStack filterStack, HolderLookup.Provider registryAccess); /** * Does this filter mod provide a way to filter items by item tag? diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/RewardTablesScreen.java b/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/RewardTablesScreen.java index f5b77b87c..1213cce47 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/RewardTablesScreen.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/client/gui/RewardTablesScreen.java @@ -236,7 +236,9 @@ public void onClicked(MouseButton button) { new ContextMenuItem(Component.translatable(pendingDeleteIndexes.contains(idx) ? "ftbquests.gui.restore" : "gui.remove"), Icons.BIN, b -> deleteRewardTable()), new ContextMenuItem(getLootCrateText(), ItemIcon.getItemIcon(ModItems.LOOTCRATE.get()), - b -> toggleLootCrate()) + b -> toggleLootCrate()), + new ContextMenuItem(Component.translatable("ftbquests.gui.copy_id"), Icons.SETTINGS, + b -> QuestScreen.setClipboardString(table.getCodeString())) ); getGui().openContextMenu(menu); } diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/command/FTBQuestsCommands.java b/common/src/main/java/dev/ftb/mods/ftbquests/command/FTBQuestsCommands.java index 86be574ce..7f0444d7f 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/command/FTBQuestsCommands.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/command/FTBQuestsCommands.java @@ -9,7 +9,6 @@ import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import dev.architectury.networking.NetworkManager; import dev.architectury.registry.registries.RegistrarManager; -import dev.ftb.mods.ftblibrary.config.Tristate; import dev.ftb.mods.ftblibrary.util.NetworkHelper; import dev.ftb.mods.ftbquests.FTBQuests; import dev.ftb.mods.ftbquests.integration.PermissionsHelper; @@ -20,30 +19,31 @@ import dev.ftb.mods.ftbquests.quest.reward.ItemReward; import dev.ftb.mods.ftbquests.quest.task.ItemTask; import dev.ftb.mods.ftbquests.quest.translation.TranslationKey; +import dev.ftb.mods.ftbquests.util.InventoryUtil; import dev.ftb.mods.ftbquests.util.ProgressChange; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.EntityArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; import java.util.*; +import static net.minecraft.commands.Commands.argument; +import static net.minecraft.commands.Commands.literal; + public class FTBQuestsCommands { public static final SimpleCommandExceptionType NO_FILE = new SimpleCommandExceptionType( Component.translatable("commands.ftbquests.command.error.no_file")); @@ -55,58 +55,57 @@ public class FTBQuestsCommands { Component.translatable("commands.ftbquests.command.error.no_inventory")); public static void register(CommandDispatcher dispatcher) { - //noinspection ConstantValue - dispatcher.register(Commands.literal("ftbquests") - .then(Commands.literal("editing_mode") + dispatcher.register(literal("ftbquests") + .then(literal("editing_mode") .requires(FTBQuestsCommands::isSSPOrEditor) .executes(c -> editingMode(c.getSource(), c.getSource().getPlayerOrException(), null)) - .then(Commands.argument("enabled", BoolArgumentType.bool()) + .then(argument("enabled", BoolArgumentType.bool()) .executes(c -> editingMode(c.getSource(), c.getSource().getPlayerOrException(), BoolArgumentType.getBool(c, "enabled"))) - .then(Commands.argument("player", EntityArgument.player()) + .then(argument("player", EntityArgument.player()) .executes(c -> editingMode(c.getSource(), EntityArgument.getPlayer(c, "player"), BoolArgumentType.getBool(c, "enabled"))) ) ) ) - .then(Commands.literal("locked") + .then(literal("locked") .requires(FTBQuestsCommands::hasEditorPermission) .executes(c -> locked(c.getSource(), c.getSource().getPlayerOrException(), null)) - .then(Commands.argument("enabled", BoolArgumentType.bool()) + .then(argument("enabled", BoolArgumentType.bool()) .executes(c -> locked(c.getSource(), c.getSource().getPlayerOrException(), BoolArgumentType.getBool(c, "enabled"))) - .then(Commands.argument("player", EntityArgument.player()) + .then(argument("player", EntityArgument.player()) .executes(c -> locked(c.getSource(), EntityArgument.getPlayer(c, "player"), BoolArgumentType.getBool(c, "enabled"))) ) ) ) - .then(Commands.literal("delete_empty_reward_tables") + .then(literal("delete_empty_reward_tables") .requires(FTBQuestsCommands::hasEditorPermission) .executes(context -> deleteEmptyRewardTables(context.getSource())) ) - .then(Commands.literal("change_progress") + .then(literal("change_progress") .requires(FTBQuestsCommands::hasEditorPermission) - .then(Commands.argument("players", EntityArgument.players()) - .then(Commands.literal("reset") - .then(Commands.argument("quest_object", StringArgumentType.string()) + .then(argument("players", EntityArgument.players()) + .then(literal("reset") + .then(argument("quest_object", StringArgumentType.string()) .executes(ctx -> { Collection players = EntityArgument.getPlayers(ctx, "players"); return changeProgress(ctx.getSource(), players, true, StringArgumentType.getString(ctx, "quest_object")); }) ) ) - .then(Commands.literal("reset-all") + .then(literal("reset-all") .executes(ctx -> { Collection players = EntityArgument.getPlayers(ctx, "players"); return changeProgress(ctx.getSource(), players, true, "1"); }) ) - .then(Commands.literal("complete") - .then(Commands.argument("quest_object", StringArgumentType.string()) + .then(literal("complete") + .then(argument("quest_object", StringArgumentType.string()) .executes(ctx -> { Collection players = EntityArgument.getPlayers(ctx, "players"); return changeProgress(ctx.getSource(), players, false, StringArgumentType.getString(ctx, "quest_object")); }) ) ) - .then(Commands.literal("complete-all") + .then(literal("complete-all") .executes(ctx -> { Collection players = EntityArgument.getPlayers(ctx, "players"); return changeProgress(ctx.getSource(), players, false, "1"); @@ -114,13 +113,13 @@ public static void register(CommandDispatcher dispatcher) { ) ) ) - .then(Commands.literal("export_reward_table_to_chest") + .then(literal("export_reward_table_to_chest") .requires(FTBQuestsCommands::hasEditorPermission) - .then(Commands.argument("reward_table", StringArgumentType.string()) + .then(argument("reward_table", StringArgumentType.string()) .executes(ctx -> exportRewards(ctx.getSource(), StringArgumentType.getString(ctx, "reward_table"), null) ) - .then(Commands.argument("pos", BlockPosArgument.blockPos()) + .then(argument("pos", BlockPosArgument.blockPos()) .executes(ctx -> { BlockPos pos = BlockPosArgument.getSpawnablePos(ctx, "pos"); return exportRewards(ctx.getSource(), StringArgumentType.getString(ctx, "reward_table"), pos); @@ -128,14 +127,14 @@ public static void register(CommandDispatcher dispatcher) { ) ) ) - .then(Commands.literal("import_reward_table_from_chest") + .then(literal("import_reward_table_from_chest") .requires(FTBQuestsCommands::hasEditorPermission) - .then(Commands.argument("name", StringArgumentType.string()) + .then(argument("name", StringArgumentType.string()) .executes(ctx -> { String name = StringArgumentType.getString(ctx, "name"); return importRewards(ctx.getSource(), name, null); }) - .then(Commands.argument("pos", BlockPosArgument.blockPos()) + .then(argument("pos", BlockPosArgument.blockPos()) .executes(ctx -> { String name = StringArgumentType.getString(ctx, "name"); BlockPos pos = BlockPosArgument.getSpawnablePos(ctx, "pos"); @@ -144,37 +143,47 @@ public static void register(CommandDispatcher dispatcher) { ) ) ) - .then(Commands.literal("generate_chapter_with_all_items_in_game") + .then(literal("generate_chapter") .requires(FTBQuestsCommands::hasEditorPermission) - .executes(context -> generateAllItemChapter(context.getSource())) + .then(literal("from_entire_creative_list") + .executes(context -> generateAllItemChapter(context.getSource())) + ) + .then(literal("from_player_inventory") + .executes(context -> generateChapterFromPlayerInv(context.getSource())) + ) + .then(literal("from_inventory") + .then(argument("pos", BlockPosArgument.blockPos()) + .executes(context -> generateChapterFromInv(context.getSource(), BlockPosArgument.getSpawnablePos(context, "pos"))) + ) + ) ) - .then(Commands.literal("reload") + .then(literal("reload") .requires(FTBQuestsCommands::hasEditorPermission) .executes(context -> doReload(context.getSource(), true, true)) - .then(Commands.literal("quests") + .then(literal("quests") .executes(context -> doReload(context.getSource(), true, false)) ) - .then(Commands.literal("team_progress") + .then(literal("team_progress") .executes(context -> doReload(context.getSource(), false, true)) ) ) - .then(Commands.literal("block_rewards") + .then(literal("block_rewards") .requires(FTBQuestsCommands::hasEditorPermission) .executes(c -> toggleRewardBlocking(c.getSource(), c.getSource().getPlayerOrException(), null)) - .then(Commands.argument("enabled", BoolArgumentType.bool()) + .then(argument("enabled", BoolArgumentType.bool()) .executes(c -> toggleRewardBlocking(c.getSource(), c.getSource().getPlayerOrException(), BoolArgumentType.getBool(c, "enabled"))) - .then(Commands.argument("player", EntityArgument.player()) + .then(argument("player", EntityArgument.player()) .requires(FTBQuestsCommands::hasEditorPermission) .executes(c -> toggleRewardBlocking(c.getSource(), EntityArgument.getPlayer(c, "player"), BoolArgumentType.getBool(c, "enabled"))) ) ) ) - .then(Commands.literal("open_book") + .then(literal("open_book") .executes(c -> openQuest(c.getSource().getPlayerOrException(), null)) - .then(Commands.argument("quest_object", StringArgumentType.string()) + .then(argument("quest_object", StringArgumentType.string()) .executes(c -> openQuest(c.getSource().getPlayerOrException(), StringArgumentType.getString(c, "quest_object")))) ) - .then(Commands.literal("clear_item_display_cache") + .then(literal("clear_item_display_cache") .requires(FTBQuestsCommands::hasEditorPermission) .executes(c -> clearDisplayCache(c.getSource())) ) @@ -249,23 +258,19 @@ private static int exportRewards(CommandSourceStack source, String idStr, @Nulla } pos = Objects.requireNonNullElse(pos, BlockPos.containing(player.pick(10, 1F, false).getLocation())); - if (!(level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container)) { + if (level.getBlockEntity(pos) == null) { throw NO_INVENTORY.create(); } - container.clearContent(); - - int slot = 0; + List items = new ArrayList<>(); for (WeightedReward wr : table.getWeightedRewards()) { - if (slot >= container.getContainerSize()) { - source.sendFailure(Component.translatable("commands.ftbquests.command.feedback.table_too_many_items", table.getTitle())); - return 0; - } else if (wr.getReward() instanceof ItemReward itemReward) { - container.setItem(slot++, itemReward.getItem()); + if (wr.getReward() instanceof ItemReward itemReward) { + items.add(itemReward.getItem()); } } + InventoryUtil.putItemsInInventory(items, level, pos, Direction.UP, true); - source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.feedback.table_exported", table.getTitle(), table.getWeightedRewards().size()), false); + source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.feedback.table_exported", table.getTitle(), items.size()), false); return Command.SINGLE_SUCCESS; } @@ -279,8 +284,7 @@ private static int importRewards(CommandSourceStack source, String name, BlockPo pos = BlockPos.containing(player.pick(10, 1F, false).getLocation()); } - BlockEntity be = level.getBlockEntity(pos); - if (!(be instanceof BaseContainerBlockEntity container)) { + if (level.getBlockEntity(pos) == null) { throw NO_INVENTORY.create(); } @@ -288,8 +292,7 @@ private static int importRewards(CommandSourceStack source, String name, BlockPo table.setRawTitle(name); table.setRawIcon(Items.CHEST.getDefaultInstance()); - for (int i = 0; i < container.getContainerSize(); i++) { - ItemStack stack = container.getItem(i); + for (ItemStack stack : InventoryUtil.getItemsInInventory(level, pos, Direction.UP)) { if (!stack.isEmpty()) { table.addReward(table.makeWeightedItemReward(stack, 1f)); } @@ -367,37 +370,67 @@ private static int deleteEmptyRewardTables(CommandSourceStack source) { private static int generateAllItemChapter(CommandSourceStack source) { if (!CreativeModeTabs.searchTab().hasAnyItems()) { - CreativeModeTabs.tryRebuildTabContents(FeatureFlags.DEFAULT_FLAGS, true, source.getLevel().registryAccess()); + CreativeModeTabs.tryRebuildTabContents(source.enabledFeatures(), true, source.getLevel().registryAccess()); } - Collection allItems = CreativeModeTabs.searchTab().getSearchTabDisplayItems(); - long newId = ServerQuestFile.INSTANCE.newID(); - Chapter chapter = new Chapter(newId, ServerQuestFile.INSTANCE, ServerQuestFile.INSTANCE.getDefaultChapterGroup()); - chapter.onCreated(); + return generateMultiItemChapter(source, CreativeModeTabs.searchTab().getSearchTabDisplayItems()); + } - chapter.setRawTitle("Generated chapter of all items in search creative tab [" + allItems.size() + "]"); - chapter.setRawIcon(new ItemStack(Items.COMPASS)); - chapter.setDefaultQuestShape("rsquare"); + private static int generateChapterFromInv(CommandSourceStack source, BlockPos pos) { + return generateMultiItemChapter(source, InventoryUtil.getItemsInInventory(source.getLevel(), pos, Direction.UP)); + } - NetworkHelper.sendToAll(source.getServer(), CreateObjectResponseMessage.create(chapter, null)); + private static int generateChapterFromPlayerInv(CommandSourceStack source) throws CommandSyntaxException { + return generateMultiItemChapter(source, source.getPlayerOrException().getInventory().items); + } + private static int generateMultiItemChapter(CommandSourceStack source, Collection allItems) { //noinspection DataFlowIssue List list = allItems.stream() .filter(stack -> !stack.isEmpty() && RegistrarManager.getId(stack.getItem(), Registries.ITEM) != null) .sorted(Comparator.comparing(a -> RegistrarManager.getId(a.getItem(), Registries.ITEM))) .toList(); - FTBQuests.LOGGER.info("Found {} items in total, chapter ID: {}", allItems.size(), chapter); if (list.isEmpty()) { + FTBQuests.LOGGER.warn("No suitable items found for chapter auto-creation"); return 0; } + ServerQuestFile file = ServerQuestFile.INSTANCE; + + long newId = file.newID(); + Chapter chapter = new Chapter(newId, file, file.getDefaultChapterGroup()); + chapter.onCreated(); + + FTBQuests.LOGGER.info("Adding {} items to new chapter ID: {}", list.size(), newId); + + chapter.setRawTitle("Auto-generated chapter [" + list.size() + " items]"); + chapter.setRawIcon(new ItemStack(Items.COMPASS)); + chapter.setDefaultQuestShape("rsquare"); + + NetworkHelper.sendToAll(source.getServer(), CreateObjectResponseMessage.create(chapter, null)); + NetworkHelper.sendToAll(source.getServer(), SyncTranslationMessageToClient.create(chapter, file.getLocale(), TranslationKey.TITLE, chapter.getRawTitle())); + + addItemsToChapter(source, list, chapter); + + file.markDirty(); + file.saveNow(); + + source.sendSuccess(() -> Component.literal("Done!"), false); + + return Command.SINGLE_SUCCESS; + } + + private static void addItemsToChapter(CommandSourceStack source, Collection list, Chapter chapter) { int col = 0; int row = 0; - String modid = RegistrarManager.getId(list.getFirst().getItem(), Registries.ITEM).getNamespace(); + String modid = null; for (ItemStack stack : list) { ResourceLocation id = RegistrarManager.getId(stack.getItem(), Registries.ITEM); + if (modid == null) { + modid = id.getNamespace(); + } if (!modid.equals(id.getNamespace())) { modid = id.getNamespace(); col = 0; @@ -417,17 +450,12 @@ private static int generateAllItemChapter(CommandSourceStack source) { ItemTask task = new ItemTask(chapter.file.newID(), quest); task.onCreated(); - task.setStackAndCount(stack, 1).setConsumeItems(Tristate.TRUE); + task.setStackAndCount(stack, 1);//.setConsumeItems(Tristate.TRUE); - NetworkHelper.sendToAll(source.getServer(), CreateObjectMessage.create(task, task.getType().makeExtraNBT())); + NetworkHelper.sendToAll(source.getServer(), CreateObjectResponseMessage.create(task, task.getType().makeExtraNBT())); col++; } - - ServerQuestFile.INSTANCE.markDirty(); - ServerQuestFile.INSTANCE.saveNow(); - source.sendSuccess(() -> Component.literal("Done!"), false); - return Command.SINGLE_SUCCESS; } private static final Set warnedPlayers = new HashSet<>(); diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/DisplayStacksCache.java b/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/DisplayStacksCache.java index a995adda2..c8c1f6f96 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/DisplayStacksCache.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/DisplayStacksCache.java @@ -6,6 +6,7 @@ import dev.ftb.mods.ftbquests.api.event.CustomFilterDisplayItemsEvent; import dev.ftb.mods.ftbquests.client.FTBQuestsClient; import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; +import net.minecraft.core.HolderLookup; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; @@ -18,12 +19,12 @@ public class DisplayStacksCache { private static List extraCache = null; @NotNull - public static List getCachedDisplayStacks(ItemStack filterStack, ItemFilterAdapter adapter) { + public static List getCachedDisplayStacks(ItemStack filterStack, ItemFilterAdapter adapter, HolderLookup.Provider registryAccess) { int key = ItemStack.hashItemAndComponents(filterStack); List result = cache.getAndMoveToFirst(key); if (result == null) { - result = computeMatchingStacks(adapter.getMatcher(filterStack)); + result = computeMatchingStacks(adapter.getMatcher(filterStack, registryAccess)); cache.put(key, result); if (cache.size() >= MAX_CACHE_SIZE) { cache.removeLast(); diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/ItemMatchingSystem.java b/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/ItemMatchingSystem.java index d4b9c88e3..f3e635a49 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/ItemMatchingSystem.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/integration/item_filtering/ItemMatchingSystem.java @@ -2,6 +2,7 @@ import dev.ftb.mods.ftblibrary.config.NameMap; import dev.ftb.mods.ftbquests.api.ItemFilterAdapter; +import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentMap; import net.minecraft.world.item.ItemStack; @@ -25,18 +26,18 @@ public Optional getFilterAdapter(ItemStack stack) { return adapters.stream().filter(adapter -> adapter.isFilterStack(stack)).findFirst(); } - public boolean doesItemMatch(ItemStack filterStack, ItemStack toCheck, ComponentMatchType matchType) { + public boolean doesItemMatch(ItemStack filterStack, ItemStack toCheck, ComponentMatchType matchType, HolderLookup.Provider registryAccess) { return getFilterAdapter(filterStack) - .map(adapter -> adapter.doesItemMatch(filterStack, toCheck)) + .map(adapter -> adapter.doesItemMatch(filterStack, toCheck, registryAccess)) .orElse(areItemStacksEqual(filterStack, toCheck, matchType)); } - public List getAllMatchingStacks(ItemStack filterStack) { + public List getAllMatchingStacks(ItemStack filterStack, HolderLookup.Provider registryAccess) { List res = new ArrayList<>(); adapters.forEach(adapter -> { if (adapter.isFilterStack(filterStack)) { - res.addAll(DisplayStacksCache.getCachedDisplayStacks(filterStack, adapter)); + res.addAll(DisplayStacksCache.getCachedDisplayStacks(filterStack, adapter, registryAccess)); } }); diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/ItemTask.java b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/ItemTask.java index 34be53857..4757b6d06 100644 --- a/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/ItemTask.java +++ b/common/src/main/java/dev/ftb/mods/ftbquests/quest/task/ItemTask.java @@ -147,7 +147,7 @@ public void readNetData(RegistryFriendlyByteBuf buffer) { } public List getValidDisplayItems() { - return ItemMatchingSystem.INSTANCE.getAllMatchingStacks(itemStack); + return ItemMatchingSystem.INSTANCE.getAllMatchingStacks(itemStack, getQuestFile().holderLookup()); } @Override @@ -188,7 +188,7 @@ public boolean test(ItemStack stack) { return true; } - return ItemMatchingSystem.INSTANCE.doesItemMatch(itemStack, stack, matchComponents); + return ItemMatchingSystem.INSTANCE.doesItemMatch(itemStack, stack, matchComponents, getQuestFile().holderLookup()); } @Override 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 ef6f011a4..6c792dd38 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 @@ -15,6 +15,7 @@ import dev.ftb.mods.ftbquests.quest.TeamData; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.ChatFormatting; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; @@ -226,7 +227,9 @@ private boolean nameMatchOK(LivingEntity e) { return c1.getString().compareTo(c2.getString()); }); return NameMap.of(ZOMBIE, ids) - .nameKey(id -> "entity." + id.toLanguageKey()) + .name(id -> Component.translatable("entity." + id.toLanguageKey()) + .append(Component.empty().withStyle(ChatFormatting.GRAY).append(" [").append(Component.literal(id.toString())).append("]")) + ) .icon(KillTask::getIconForEntityType) .create(); } diff --git a/common/src/main/java/dev/ftb/mods/ftbquests/util/InventoryUtil.java b/common/src/main/java/dev/ftb/mods/ftbquests/util/InventoryUtil.java new file mode 100644 index 000000000..47524326f --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbquests/util/InventoryUtil.java @@ -0,0 +1,22 @@ +package dev.ftb.mods.ftbquests.util; + +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import java.util.List; + +public class InventoryUtil { + @ExpectPlatform + public static NonNullList getItemsInInventory(Level level, BlockPos pos, Direction side) { + throw new AssertionError(); + } + + @ExpectPlatform + public static boolean putItemsInInventory(List items, Level level, BlockPos pos, Direction side, boolean clearFirst) { + throw new AssertionError(); + } +} diff --git a/fabric/src/main/java/dev/ftb/mods/ftbquests/util/fabric/InventoryUtilImpl.java b/fabric/src/main/java/dev/ftb/mods/ftbquests/util/fabric/InventoryUtilImpl.java new file mode 100644 index 000000000..32c7fc4f1 --- /dev/null +++ b/fabric/src/main/java/dev/ftb/mods/ftbquests/util/fabric/InventoryUtilImpl.java @@ -0,0 +1,62 @@ +package dev.ftb.mods.ftbquests.util.fabric; + +import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import java.util.List; + +public class InventoryUtilImpl { + @SuppressWarnings("UnstableApiUsage") + public static NonNullList getItemsInInventory(Level level, BlockPos pos, Direction side) { + NonNullList items = NonNullList.create(); + + Storage storage = ItemStorage.SIDED.find(level, pos, side); + if (storage != null) { + storage.forEach(storageView -> { + if (!storageView.isResourceBlank()) { + items.add(storageView.getResource().toStack((int) storageView.getAmount())); + } + }); + } + + return items; + } + + @SuppressWarnings("UnstableApiUsage") + public static boolean putItemsInInventory(List items, Level level, BlockPos pos, Direction side, boolean clearFirst) { + Storage storage = ItemStorage.SIDED.find(level, pos, side); + if (storage == null || !storage.supportsInsertion()) { + throw new IllegalArgumentException("No item storage found"); + } + + try (Transaction tx = Transaction.openOuter()) { + if (clearFirst && storage.supportsExtraction()) { + for (var view : storage.nonEmptyViews()) { + view.extract(view.getResource(), view.getAmount(), tx); + } + } + int ok = 0; + for (ItemStack stack : items) { + if (storage.insert(ItemVariant.of(stack), Integer.MAX_VALUE, tx) == stack.getCount()) { + ok++; + } else { + break; + } + } + if (ok == items.size()) { + tx.commit(); + return true; + } else { + tx.abort(); + return false; + } + } + } +} diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index dea32aa8a..b18b5a6e8 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -31,5 +31,6 @@ "ftbteams": ">=${ftbteamsversion}" }, "breaks": { + "ftbxmodcompat": "<21.1.7" } } diff --git a/gradle.properties b/gradle.properties index 78306c356..58590240c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ maven_group=dev.ftb.mods mod_author=FTB Team # Build time -mod_version=2101.1.20 +mod_version=2101.1.21 minecraft_version=1.21.1 # Cross env @@ -23,7 +23,7 @@ fabric_api_version=0.102.1+1.21.1 fabric_api_version_range=>=0.102.1+1.21.1 architectury_api_version=13.0.8 -ftb_library_version=2101.1.29 +ftb_library_version=2101.1.30 ftb_teams_version=2101.1.8 # Optional deps diff --git a/neoforge/src/main/java/dev/ftb/mods/ftbquests/util/neoforge/InventoryUtilImpl.java b/neoforge/src/main/java/dev/ftb/mods/ftbquests/util/neoforge/InventoryUtilImpl.java new file mode 100644 index 000000000..18c7656d6 --- /dev/null +++ b/neoforge/src/main/java/dev/ftb/mods/ftbquests/util/neoforge/InventoryUtilImpl.java @@ -0,0 +1,51 @@ +package dev.ftb.mods.ftbquests.util.neoforge; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.ItemHandlerHelper; + +import java.util.List; + +public class InventoryUtilImpl { + public static NonNullList getItemsInInventory(Level level, BlockPos pos, Direction side) { + IItemHandler handler = level.getCapability(Capabilities.ItemHandler.BLOCK, pos, side); + NonNullList items = NonNullList.create(); + + if (handler != null) { + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack stack = handler.getStackInSlot(i); + if (!stack.isEmpty()) { + items.add(stack); + } + } + } + + return items; + } + + public static boolean putItemsInInventory(List items, Level level, BlockPos pos, Direction side, boolean clearFirst) { + IItemHandler handler = level.getCapability(Capabilities.ItemHandler.BLOCK, pos, side); + if (handler == null) { + throw new IllegalArgumentException("No item handler at that blockpos & side"); + } + + if (clearFirst) { + for (int i = 0; i < handler.getSlots(); i++) { + handler.extractItem(i, Integer.MAX_VALUE, false); + } + } + for (ItemStack stack : items) { + ItemStack excess = ItemHandlerHelper.insertItem(handler, stack.copy(), false); + if (!excess.isEmpty()) { + return false; + } + } + + return true; + } +} diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 070655619..10538da5a 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -49,3 +49,9 @@ type = "required" versionRange = "[${ftbteamsversion},)" ordering = "AFTER" side = "BOTH" + +[[dependencies.ftbquests]] +modId = "ftbxmodcompat" +type = "optional" +versionRange = "[21.1.7,)" +side = "BOTH"