From c0b88453b1529c864ac7e35629fd820daf59cc7c Mon Sep 17 00:00:00 2001 From: Eclipse Date: Fri, 4 Jul 2025 08:14:44 +0000 Subject: [PATCH] Refactor item suggestion mapper into custom item provider, only map items if their model hasn't been mapped before, don't export textures more than once --- .../GeyserMappingsGenerator.java | 8 +- .../geysermc/packgenerator/PackManager.java | 35 ++++----- .../command/PackGeneratorCommand.java | 76 ++++++++++--------- .../mapper/CustomItemProvider.java | 14 ++++ .../packgenerator/mapper/InventoryMapper.java | 22 ++++-- .../mapper/ItemSuggestionMapper.java | 73 ------------------ .../mapper/ItemSuggestionProvider.java | 52 +++++++++++++ .../packgenerator/mapper/PackMapper.java | 38 ++++++++++ .../packgenerator/mapper/PackMappers.java | 26 ------- .../packgenerator/pack/BedrockPack.java | 9 ++- 10 files changed, 190 insertions(+), 163 deletions(-) create mode 100644 src/main/java/org/geysermc/packgenerator/mapper/CustomItemProvider.java delete mode 100644 src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionMapper.java create mode 100644 src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionProvider.java create mode 100644 src/main/java/org/geysermc/packgenerator/mapper/PackMapper.java delete mode 100644 src/main/java/org/geysermc/packgenerator/mapper/PackMappers.java diff --git a/src/main/java/org/geysermc/packgenerator/GeyserMappingsGenerator.java b/src/main/java/org/geysermc/packgenerator/GeyserMappingsGenerator.java index f7d3277..d0642b4 100644 --- a/src/main/java/org/geysermc/packgenerator/GeyserMappingsGenerator.java +++ b/src/main/java/org/geysermc/packgenerator/GeyserMappingsGenerator.java @@ -9,7 +9,7 @@ import net.minecraft.commands.synchronization.SingletonArgumentInfo; import net.minecraft.resources.ResourceLocation; import org.geysermc.packgenerator.command.CommandSuggestionsArgumentType; import org.geysermc.packgenerator.command.PackGeneratorCommand; -import org.geysermc.packgenerator.mapper.PackMappers; +import org.geysermc.packgenerator.mapper.PackMapper; import org.slf4j.Logger; public class GeyserMappingsGenerator implements ClientModInitializer { @@ -19,12 +19,12 @@ public class GeyserMappingsGenerator implements ClientModInitializer { public static final Logger LOGGER = LogUtils.getLogger(); private final PackManager packManager = new PackManager(); - private final PackMappers packMappers = new PackMappers(packManager); + private final PackMapper packMapper = new PackMapper(); @Override public void onInitializeClient() { - ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext) -> PackGeneratorCommand.register(dispatcher, packManager, packMappers)); - ClientTickEvents.START_CLIENT_TICK.register(packMappers::tick); + ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext) -> PackGeneratorCommand.register(dispatcher, packManager, packMapper)); + ClientTickEvents.START_CLIENT_TICK.register(minecraft -> packMapper.tick(packManager, minecraft)); ArgumentTypeRegistry.registerArgumentType(getModdedLocation("command_suggestions"), CommandSuggestionsArgumentType.class, SingletonArgumentInfo.contextFree(CommandSuggestionsArgumentType::new)); diff --git a/src/main/java/org/geysermc/packgenerator/PackManager.java b/src/main/java/org/geysermc/packgenerator/PackManager.java index 8fd8ee2..e0a8a0b 100644 --- a/src/main/java/org/geysermc/packgenerator/PackManager.java +++ b/src/main/java/org/geysermc/packgenerator/PackManager.java @@ -1,39 +1,36 @@ package org.geysermc.packgenerator; -import net.minecraft.world.item.ItemStack; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import org.geysermc.packgenerator.pack.BedrockPack; import java.io.IOException; import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; public final class PackManager { - private BedrockPack currentPack; + private Optional currentPack = Optional.empty(); public void startPack(String name) throws IOException { - if (currentPack != null) { - throw new IllegalStateException("Already started a pack (" + currentPack.name() + ")"); + if (currentPack.isPresent()) { + throw new IllegalStateException("Already started a pack (" + currentPack.get().name() + ")"); } - currentPack = new BedrockPack(name); + currentPack = Optional.of(new BedrockPack(name)); } - public Optional map(ItemStack stack) { - ensurePackIsCreated(); - - return currentPack.map(stack); + public void run(Consumer consumer) { + currentPack.ifPresent(consumer); } - public boolean finish() { - ensurePackIsCreated(); - boolean success = currentPack.save(); - currentPack = null; + public Optional run(Function function) { + return currentPack.map(function); + } + + public Optional finish() { + Optional success = currentPack.map(BedrockPack::save); + currentPack = Optional.empty(); return success; } - - public void ensurePackIsCreated() { - if (currentPack == null) { - throw new IllegalStateException("Create a new pack first!"); - } - } } diff --git a/src/main/java/org/geysermc/packgenerator/command/PackGeneratorCommand.java b/src/main/java/org/geysermc/packgenerator/command/PackGeneratorCommand.java index 92fcde3..ffc511b 100644 --- a/src/main/java/org/geysermc/packgenerator/command/PackGeneratorCommand.java +++ b/src/main/java/org/geysermc/packgenerator/command/PackGeneratorCommand.java @@ -10,9 +10,9 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -import org.geysermc.packgenerator.GeyserMappingsGenerator; import org.geysermc.packgenerator.PackManager; -import org.geysermc.packgenerator.mapper.PackMappers; +import org.geysermc.packgenerator.mapper.ItemSuggestionProvider; +import org.geysermc.packgenerator.mapper.PackMapper; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -20,7 +20,7 @@ import java.util.function.Consumer; public class PackGeneratorCommand { - public static void register(CommandDispatcher dispatcher, PackManager packManager, PackMappers mappers) { + public static void register(CommandDispatcher dispatcher, PackManager packManager, PackMapper packMapper) { dispatcher.register(ClientCommandManager.literal("packgenerator") .then(ClientCommandManager.literal("create") .then(ClientCommandManager.argument("name", StringArgumentType.word()) @@ -39,14 +39,16 @@ public class PackGeneratorCommand { ) .then(ClientCommandManager.literal("map") .executes(context -> { - ItemStack heldItem = context.getSource().getPlayer().getMainHandItem(); - Optional problems = packManager.map(heldItem); - if (problems.isEmpty()) { - context.getSource().sendError(Component.literal("No item found to map!")); - } else if (problems.get()) { - context.getSource().sendError(Component.literal("Problems occurred whilst mapping the item!")); - } - context.getSource().sendFeedback(Component.literal("Added held item to Geyser mappings")); + packManager.run(pack -> { + ItemStack heldItem = context.getSource().getPlayer().getMainHandItem(); + Optional problems = pack.map(heldItem); + if (problems.isEmpty()) { + context.getSource().sendError(Component.literal("No item found to map!")); + } else if (problems.get()) { + context.getSource().sendError(Component.literal("Problems occurred whilst mapping the item!")); + } + context.getSource().sendFeedback(Component.literal("Added held item to Geyser mappings")); + }); return 0; }) ) @@ -55,24 +57,27 @@ public class PackGeneratorCommand { ) .then(ClientCommandManager.literal("finish") .executes(context -> { - if (!packManager.finish()) { - context.getSource().sendError(Component.literal("Errors occurred whilst trying to write the pack to disk!")); - } - context.getSource().sendFeedback(Component.literal("Wrote pack to disk")); + packManager.finish().ifPresent(success -> { + if (!success) { + context.getSource().sendError(Component.literal("Errors occurred whilst trying to write the pack to disk!")); + } else { + context.getSource().sendFeedback(Component.literal("Wrote pack to disk")); + } + }); return 0; }) ) .then(ClientCommandManager.literal("auto") .then(ClientCommandManager.argument("suggestions", CommandSuggestionsArgumentType.TYPE) .executes(context -> { - packManager.ensurePackIsCreated(); Pair> suggestions = CommandSuggestionsArgumentType.getSuggestions(context, "suggestions"); String baseCommand = suggestions.getFirst(); suggestions.getSecond().thenAccept(completed -> { - mappers.getSuggestionMapper().start(completed.getList().stream() + ItemSuggestionProvider provider = new ItemSuggestionProvider(completed.getList().stream() .map(suggestion -> baseCommand.substring(0, suggestion.getRange().getStart()) + suggestion.getText()) .toList()); - context.getSource().sendFeedback(Component.literal("Running " + mappers.getSuggestionMapper().queueSize() + " commands to obtain custom items to map")); + packMapper.setItemProvider(provider); + context.getSource().sendFeedback(Component.literal("Running " + provider.queueSize() + " commands to obtain custom items to map")); }); return 0; }) @@ -82,23 +87,26 @@ public class PackGeneratorCommand { } public static int mapInventory(PackManager manager, Inventory inventory, Consumer feedback, boolean feedbackOnEmpty) { - int mapped = 0; - boolean errors = false; - for (ItemStack stack : inventory) { - Optional problems = manager.map(stack); - if (problems.isPresent()) { - mapped++; - errors |= problems.get(); + return manager.run(pack -> { + int mapped = 0; + boolean errors = false; + for (ItemStack stack : inventory) { + Optional problems = pack.map(stack); + if (problems.isPresent()) { + mapped++; + errors |= problems.get(); + } } - } - if (mapped > 0) { - if (errors) { - feedback.accept(Component.literal("Problems occurred whilst mapping items!").withStyle(ChatFormatting.RED)); + if (mapped > 0) { + if (errors) { + feedback.accept(Component.literal("Problems occurred whilst mapping items!").withStyle(ChatFormatting.RED)); + } + feedback.accept(Component.literal("Mapped " + mapped + " items from your inventory")); + } else if (feedbackOnEmpty) { + feedback.accept(Component.literal("No items were mapped")); } - feedback.accept(Component.literal("Mapped " + mapped + " items from your inventory")); - } else if (feedbackOnEmpty) { - feedback.accept(Component.literal("No items were mapped")); - } - return mapped; + + return mapped; + }).orElse(0); } } diff --git a/src/main/java/org/geysermc/packgenerator/mapper/CustomItemProvider.java b/src/main/java/org/geysermc/packgenerator/mapper/CustomItemProvider.java new file mode 100644 index 0000000..4262803 --- /dev/null +++ b/src/main/java/org/geysermc/packgenerator/mapper/CustomItemProvider.java @@ -0,0 +1,14 @@ +package org.geysermc.packgenerator.mapper; + +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.item.ItemStack; + +import java.util.stream.Stream; + +public interface CustomItemProvider { + + Stream nextItems(LocalPlayer player, ClientPacketListener connection); + + boolean isDone(); +} diff --git a/src/main/java/org/geysermc/packgenerator/mapper/InventoryMapper.java b/src/main/java/org/geysermc/packgenerator/mapper/InventoryMapper.java index 5148470..63ceae9 100644 --- a/src/main/java/org/geysermc/packgenerator/mapper/InventoryMapper.java +++ b/src/main/java/org/geysermc/packgenerator/mapper/InventoryMapper.java @@ -1,11 +1,23 @@ package org.geysermc.packgenerator.mapper; -import org.geysermc.packgenerator.PackManager; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.item.ItemStack; -public class InventoryMapper { - private final PackManager packManager; +import java.util.stream.Stream; - public InventoryMapper(PackManager packManager) { - this.packManager = packManager; +public class InventoryMapper implements CustomItemProvider { + + public InventoryMapper() { + } + + @Override + public Stream nextItems(LocalPlayer player, ClientPacketListener connection) { + return Stream.empty(); + } + + @Override + public boolean isDone() { + return false; } } diff --git a/src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionMapper.java b/src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionMapper.java deleted file mode 100644 index 8751cb8..0000000 --- a/src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionMapper.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.geysermc.packgenerator.mapper; - -import net.minecraft.client.Minecraft; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundChatCommandPacket; -import org.geysermc.packgenerator.PackManager; -import org.geysermc.packgenerator.command.PackGeneratorCommand; - -import java.util.ArrayList; -import java.util.List; - -// TODO safety -public final class ItemSuggestionMapper { - private final PackManager packManager; - private final List remainingCommands = new ArrayList<>(); - private boolean waitingOnItem = false; - private boolean waitingOnClear = false; - private int mapped = 0; - - public ItemSuggestionMapper(PackManager packManager) { - this.packManager = packManager; - } - - // TODO - public boolean start(List commands) { - if (remainingCommands.isEmpty()) { - remainingCommands.addAll(commands); - return true; - } - return false; - } - - public void tick(Minecraft minecraft) { - if (minecraft.player == null || minecraft.getConnection() == null) { - stop(); - return; - } - - if (!remainingCommands.isEmpty() || waitingOnItem) { - if (waitingOnClear && minecraft.player.getInventory().isEmpty()) { - waitingOnClear = false; - } else if (!waitingOnItem) { - minecraft.getConnection().send(new ServerboundChatCommandPacket(remainingCommands.removeFirst())); - waitingOnItem = true; - } else { - if (!minecraft.player.getInventory().isEmpty()) { - mapped += PackGeneratorCommand.mapInventory(packManager, minecraft.player.getInventory(), - component -> minecraft.player.displayClientMessage(component, false), false); - - minecraft.getConnection().send(new ServerboundChatCommandPacket("clear")); - - waitingOnItem = false; - if (remainingCommands.isEmpty()) { - minecraft.player.displayClientMessage(Component.literal("Done, " + mapped + " items have been mapped"), false); - } else { - waitingOnClear = true; - } - } - } - } - } - - public int queueSize() { - return remainingCommands.size(); - } - - public void stop() { - remainingCommands.clear(); - waitingOnItem = false; - waitingOnClear = false; - mapped = 0; - } -} diff --git a/src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionProvider.java b/src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionProvider.java new file mode 100644 index 0000000..b34cc61 --- /dev/null +++ b/src/main/java/org/geysermc/packgenerator/mapper/ItemSuggestionProvider.java @@ -0,0 +1,52 @@ +package org.geysermc.packgenerator.mapper; + +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.protocol.game.ServerboundChatCommandPacket; +import net.minecraft.world.item.ItemStack; + +import java.util.List; +import java.util.stream.Stream; + +// TODO safety +public class ItemSuggestionProvider implements CustomItemProvider { + private final List remainingCommands; + private boolean waitingOnItem = false; + private boolean waitingOnClear = false; + + public ItemSuggestionProvider(List commands) { + remainingCommands = commands; + } + + public Stream nextItems(LocalPlayer player, ClientPacketListener connection) { + if (!remainingCommands.isEmpty() || waitingOnItem) { + if (waitingOnClear && player.getInventory().isEmpty()) { + waitingOnClear = false; + } else if (!waitingOnItem) { + connection.send(new ServerboundChatCommandPacket(remainingCommands.removeFirst())); + waitingOnItem = true; + } else { + if (!player.getInventory().isEmpty()) { + Stream items = player.getInventory().getNonEquipmentItems().stream(); + connection.send(new ServerboundChatCommandPacket("clear")); + + waitingOnItem = false; + if (!remainingCommands.isEmpty()) { + waitingOnClear = true; + } + return items; + } + } + } + return Stream.empty(); + } + + public int queueSize() { + return remainingCommands.size(); + } + + @Override + public boolean isDone() { + return remainingCommands.isEmpty(); + } +} diff --git a/src/main/java/org/geysermc/packgenerator/mapper/PackMapper.java b/src/main/java/org/geysermc/packgenerator/mapper/PackMapper.java new file mode 100644 index 0000000..61b8fd9 --- /dev/null +++ b/src/main/java/org/geysermc/packgenerator/mapper/PackMapper.java @@ -0,0 +1,38 @@ +package org.geysermc.packgenerator.mapper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import org.geysermc.packgenerator.PackManager; + +import java.util.Objects; +import java.util.Optional; + +public class PackMapper { + private CustomItemProvider itemProvider; + + public void setItemProvider(CustomItemProvider itemProvider) { + this.itemProvider = itemProvider; + } + + public void tick(PackManager packManager, Minecraft minecraft) { + if (itemProvider != null) { + LocalPlayer player = Objects.requireNonNull(minecraft.player); + ClientPacketListener connection = Objects.requireNonNull(minecraft.getConnection()); + + packManager.run(pack -> { + // TODO maybe report problems here... probably better to do so in pack class though + long mapped = itemProvider.nextItems(player, connection) + .map(pack::map) + .filter(Optional::isPresent) + .count(); + player.displayClientMessage(Component.literal("Mapped " + mapped + " items"), false); + if (itemProvider.isDone()) { + player.displayClientMessage(Component.literal("Finished mapping items from provider"), false); + itemProvider = null; + } + }); + } + } +} diff --git a/src/main/java/org/geysermc/packgenerator/mapper/PackMappers.java b/src/main/java/org/geysermc/packgenerator/mapper/PackMappers.java deleted file mode 100644 index e8af58d..0000000 --- a/src/main/java/org/geysermc/packgenerator/mapper/PackMappers.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.geysermc.packgenerator.mapper; - -import net.minecraft.client.Minecraft; -import org.geysermc.packgenerator.PackManager; - -public class PackMappers { - private final ItemSuggestionMapper suggestionMapper; - private final InventoryMapper inventoryMapper; - - public PackMappers(PackManager packManager) { - this.suggestionMapper = new ItemSuggestionMapper(packManager); - this.inventoryMapper = new InventoryMapper(packManager); - } - - public ItemSuggestionMapper getSuggestionMapper() { - return suggestionMapper; - } - - public InventoryMapper getInventoryMapper() { - return inventoryMapper; - } - - public void tick(Minecraft minecraft) { - suggestionMapper.tick(minecraft); - } -} diff --git a/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java b/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java index 7c4ffa1..bf98372 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java +++ b/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java @@ -3,6 +3,7 @@ package org.geysermc.packgenerator.pack; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.SplashRenderer; +import net.minecraft.core.component.DataComponents; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ProblemReporter; import net.minecraft.world.item.ItemStack; @@ -22,8 +23,10 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -45,7 +48,9 @@ public class BedrockPack { private final GeyserMappings mappings; private final BedrockTextures.Builder itemTextures; private final List attachables = new ArrayList<>(); - private final List texturesToExport = new ArrayList<>(); + private final Set texturesToExport = new HashSet<>(); + + private final Set modelsMapped = new HashSet<>(); private final ProblemReporter.Collector reporter; @@ -67,7 +72,7 @@ public class BedrockPack { } public Optional map(ItemStack stack) { - if (stack.isEmpty()) { + if (stack.isEmpty() || !modelsMapped.add(stack.get(DataComponents.ITEM_MODEL))) { return Optional.empty(); } AtomicBoolean problems = new AtomicBoolean();