diff --git a/src/main/java/com/trunksbomb/bagtabs/BagTabs.java b/src/main/java/com/trunksbomb/bagtabs/BagTabs.java index c9697ae..ba0da40 100644 --- a/src/main/java/com/trunksbomb/bagtabs/BagTabs.java +++ b/src/main/java/com/trunksbomb/bagtabs/BagTabs.java @@ -1,7 +1,9 @@ package com.trunksbomb.bagtabs; import com.mojang.logging.LogUtils; +import com.trunksbomb.bagtabs.item.BagNamerItem; import com.trunksbomb.bagtabs.item.BagItem; +import com.trunksbomb.bagtabs.menu.BagNamerMenu; import com.trunksbomb.bagtabs.menu.BagMenu; import com.trunksbomb.bagtabs.network.BagTabsNetwork; import net.minecraft.core.registries.Registries; @@ -38,13 +40,17 @@ public class BagTabs { .component(DataComponents.CONTAINER, ItemContainerContents.EMPTY) .component(DataComponents.DYED_COLOR, new DyedItemColor(BagItem.DEFAULT_COLOR, true)) )); + public static final DeferredItem BAG_NAMER = ITEMS.register("bag_namer", () -> new BagNamerItem(new Item.Properties().stacksTo(1))); public static final DeferredHolder BAG_TAB = CREATIVE_MODE_TABS.register( "main", () -> CreativeModeTab.builder() .title(Component.translatable("itemGroup." + MODID)) .withTabsBefore(CreativeModeTabs.TOOLS_AND_UTILITIES) .icon(() -> BAG.get().getDefaultInstance()) - .displayItems((parameters, output) -> BagItem.createCreativeStacks().forEach(output::accept)) + .displayItems((parameters, output) -> { + BagItem.createCreativeStacks().forEach(output::accept); + output.accept(BAG_NAMER.get()); + }) .build() ); @@ -52,6 +58,10 @@ public class BagTabs { "bag", () -> IMenuTypeExtension.create(BagMenu::fromNetwork) ); + public static final DeferredHolder, MenuType> BAG_NAMER_MENU = MENUS.register( + "bag_namer", + () -> IMenuTypeExtension.create(BagNamerMenu::fromNetwork) + ); public BagTabs(IEventBus modEventBus) { ITEMS.register(modEventBus); diff --git a/src/main/java/com/trunksbomb/bagtabs/BagTabsClient.java b/src/main/java/com/trunksbomb/bagtabs/BagTabsClient.java index 6e9cfad..09f5759 100644 --- a/src/main/java/com/trunksbomb/bagtabs/BagTabsClient.java +++ b/src/main/java/com/trunksbomb/bagtabs/BagTabsClient.java @@ -1,6 +1,7 @@ package com.trunksbomb.bagtabs; import com.trunksbomb.bagtabs.client.BagScreen; +import com.trunksbomb.bagtabs.client.BagNamerScreen; import com.trunksbomb.bagtabs.client.BagTabOverlay; import net.neoforged.bus.api.IEventBus; import net.minecraft.client.color.item.ItemColor; @@ -25,6 +26,7 @@ public class BagTabsClient { private static void registerScreens(RegisterMenuScreensEvent event) { event.register(BagTabs.BAG_MENU.get(), BagScreen::new); + event.register(BagTabs.BAG_NAMER_MENU.get(), BagNamerScreen::new); } private static void registerItemColors(RegisterColorHandlersEvent.Item event) { diff --git a/src/main/java/com/trunksbomb/bagtabs/bag/BagAccess.java b/src/main/java/com/trunksbomb/bagtabs/bag/BagAccess.java index ed1ba46..3e0ef9c 100644 --- a/src/main/java/com/trunksbomb/bagtabs/bag/BagAccess.java +++ b/src/main/java/com/trunksbomb/bagtabs/bag/BagAccess.java @@ -1,5 +1,6 @@ package com.trunksbomb.bagtabs.bag; +import com.trunksbomb.bagtabs.item.BagItem; import java.util.ArrayList; import java.util.List; import net.minecraft.world.entity.player.Inventory; @@ -16,6 +17,9 @@ public final class BagAccess { for (int slot = 0; slot < inventory.getContainerSize(); slot++) { ItemStack stack = inventory.getItem(slot); + if (stack.getItem() instanceof BagItem) { + BagIdentityData.ensureBagId(stack); + } BagCompat.BagHandler handler = BagCompat.findHandler(stack); if (handler != null) { bags.add(new BagEntry(slot, stack.copy(), handler)); diff --git a/src/main/java/com/trunksbomb/bagtabs/bag/BagCompat.java b/src/main/java/com/trunksbomb/bagtabs/bag/BagCompat.java index 47ff238..17ab62d 100644 --- a/src/main/java/com/trunksbomb/bagtabs/bag/BagCompat.java +++ b/src/main/java/com/trunksbomb/bagtabs/bag/BagCompat.java @@ -5,12 +5,15 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; +import java.util.Locale; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; public final class BagCompat { private static final List HANDLERS = List.of( @@ -41,6 +44,30 @@ public final class BagCompat { return getActiveBagSlot(menu) >= 0; } + public static boolean canName(ItemStack stack) { + return !stack.isEmpty() && (findHandler(stack) != null || looksLikeInventoryItem(stack)); + } + + public static BagIdentity getIdentity(ItemStack stack) { + if (!canName(stack)) { + return null; + } + + if (stack.getItem() instanceof InventoryBag) { + return new BagIdentity("bagtabs:uuid:" + BagIdentityData.ensureBagId(stack), "uuid", true); + } + + Integer dankFrequency = getDankFrequency(stack); + if (dankFrequency != null && dankFrequency >= 0) { + return new BagIdentity("dankstorage:frequency:" + dankFrequency, "frequency", true); + } + + String namespace = BuiltInRegistries.ITEM.getKey(stack.getItem()).getNamespace(); + String displayName = stack.getHoverName().getString().trim().toLowerCase(Locale.ROOT); + String normalizedName = displayName.replaceAll("\\s+", " "); + return new BagIdentity(namespace + ":" + normalizedName, "name_mod", false); + } + public static int getActiveBagSlot(AbstractContainerMenu menu) { if (menu instanceof BagMenu bagMenu) { return bagMenu.getBagSlot(); @@ -114,6 +141,19 @@ public final class BagCompat { } } + private static Integer getDankFrequency(ItemStack stack) { + if (!isInstance(DankStorageHandler.ITEM_CLASS, stack.getItem())) { + return null; + } + + try { + Object frequency = stack.getItem().getClass().getMethod("getFrequency", ItemStack.class).invoke(null, stack); + return frequency instanceof Integer integer ? integer : null; + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) { + return null; + } + } + private static final class TravelersBackpackHandler implements BagHandler { private static final String ITEM_CLASS = "com.tiviacz.travelersbackpack.items.TravelersBackpackItem"; private static final String MENU_CLASS = "com.tiviacz.travelersbackpack.inventory.menu.AbstractBackpackMenu"; @@ -442,6 +482,30 @@ public final class BagCompat { } } + private static boolean looksLikeInventoryItem(ItemStack stack) { + if (stack.has(DataComponents.CONTAINER)) { + return true; + } + + String itemPath = BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath(); + String className = stack.getItem().getClass().getName().toLowerCase(Locale.ROOT); + String lowerPath = itemPath.toLowerCase(Locale.ROOT); + boolean nameHint = lowerPath.contains("bag") + || lowerPath.contains("backpack") + || lowerPath.contains("pouch") + || lowerPath.contains("satchel") + || lowerPath.contains("dank") + || lowerPath.contains("shulker") + || className.contains("bag") + || className.contains("backpack") + || className.contains("pouch") + || className.contains("satchel") + || className.contains("dank") + || className.contains("shulker"); + + return nameHint && stack.getMaxStackSize() == 1; + } + private static Object invoke(Object target, String methodName) { try { Method method = target.getClass().getMethod(methodName); diff --git a/src/main/java/com/trunksbomb/bagtabs/bag/BagIdentity.java b/src/main/java/com/trunksbomb/bagtabs/bag/BagIdentity.java new file mode 100644 index 0000000..672bb70 --- /dev/null +++ b/src/main/java/com/trunksbomb/bagtabs/bag/BagIdentity.java @@ -0,0 +1,4 @@ +package com.trunksbomb.bagtabs.bag; + +public record BagIdentity(String key, String strategy, boolean stable) { +} diff --git a/src/main/java/com/trunksbomb/bagtabs/bag/BagIdentityData.java b/src/main/java/com/trunksbomb/bagtabs/bag/BagIdentityData.java new file mode 100644 index 0000000..e0dbfdf --- /dev/null +++ b/src/main/java/com/trunksbomb/bagtabs/bag/BagIdentityData.java @@ -0,0 +1,40 @@ +package com.trunksbomb.bagtabs.bag; + +import java.util.UUID; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; + +public final class BagIdentityData { + private static final String ROOT_KEY = "bagtabs"; + private static final String BAG_ID_KEY = "bag_id"; + + private BagIdentityData() { + } + + public static UUID getBagId(ItemStack stack) { + CustomData customData = stack.get(DataComponents.CUSTOM_DATA); + if (customData == null || !customData.contains(ROOT_KEY)) { + return null; + } + + CompoundTag root = customData.copyTag().getCompound(ROOT_KEY); + return root.hasUUID(BAG_ID_KEY) ? root.getUUID(BAG_ID_KEY) : null; + } + + public static UUID ensureBagId(ItemStack stack) { + UUID existing = getBagId(stack); + if (existing != null) { + return existing; + } + + UUID created = UUID.randomUUID(); + CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> { + CompoundTag root = tag.contains(ROOT_KEY, 10) ? tag.getCompound(ROOT_KEY) : new CompoundTag(); + root.putUUID(BAG_ID_KEY, created); + tag.put(ROOT_KEY, root); + }); + return created; + } +} diff --git a/src/main/java/com/trunksbomb/bagtabs/client/BagNamerScreen.java b/src/main/java/com/trunksbomb/bagtabs/client/BagNamerScreen.java new file mode 100644 index 0000000..d3e618c --- /dev/null +++ b/src/main/java/com/trunksbomb/bagtabs/client/BagNamerScreen.java @@ -0,0 +1,100 @@ +package com.trunksbomb.bagtabs.client; + +import com.trunksbomb.bagtabs.BagTabs; +import com.trunksbomb.bagtabs.menu.BagNamerMenu; +import com.trunksbomb.bagtabs.network.RenameBagPayload; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.neoforged.neoforge.network.PacketDistributor; + +public class BagNamerScreen extends AbstractContainerScreen { + private static final ResourceLocation CONTAINER_BACKGROUND = BagTabs.id("textures/gui/bag_namer.png"); + private static final int TEXTURE_WIDTH = 176; + private static final int TEXTURE_HEIGHT = 165; + private EditBox nameBox; + private Button renameButton; + + public BagNamerScreen(BagNamerMenu menu, Inventory playerInventory, Component title) { + super(menu, playerInventory, title); + this.imageHeight = 165; + this.inventoryLabelY = this.imageHeight - 94; + } + + @Override + protected void init() { + super.init(); + + this.nameBox = new EditBox(this.font, this.leftPos + 21, this.topPos + 15, 134, 16, BagTabs.translation("gui.bag_namer.name")); + this.nameBox.setMaxLength(48); + this.nameBox.setCanLoseFocus(true); + this.nameBox.setHint(BagTabs.translation("gui.bag_namer.placeholder")); + this.addRenderableWidget(this.nameBox); + + this.renameButton = this.addRenderableWidget(Button.builder(BagTabs.translation("gui.bag_namer.rename"), button -> rename()) + .bounds(this.leftPos + 64, this.topPos + 44, 48, 20) + .build()); + } + + @Override + public void containerTick() { + super.containerTick(); + this.renameButton.active = this.menu.getSlot(0).hasItem() && !this.menu.getSlot(1).hasItem(); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (this.nameBox.keyPressed(keyCode, scanCode, modifiers) || this.nameBox.canConsumeInput()) { + return true; + } + + if (keyCode == 257 || keyCode == 335) { + rename(); + return true; + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean charTyped(char codePoint, int modifiers) { + return this.nameBox.charTyped(codePoint, modifiers) || super.charTyped(codePoint, modifiers); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.nameBox.mouseClicked(mouseX, mouseY, button)) { + this.setFocused(this.nameBox); + return true; + } + + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + super.render(guiGraphics, mouseX, mouseY, partialTick); + this.renderTooltip(guiGraphics, mouseX, mouseY); + } + + @Override + protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { + guiGraphics.drawString(this.font, this.playerInventoryTitle, this.inventoryLabelX, this.inventoryLabelY, 0x404040, false); + guiGraphics.drawString(this.font, BagTabs.translation("gui.bag_namer.name"), 21, 5, 0x404040, false); + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, float partialTick, int mouseX, int mouseY) { + int left = this.leftPos; + int top = this.topPos; + guiGraphics.blit(CONTAINER_BACKGROUND, left, top, 0, 0, this.imageWidth, this.imageHeight, TEXTURE_WIDTH, TEXTURE_HEIGHT); + } + + private void rename() { + PacketDistributor.sendToServer(new RenameBagPayload(this.nameBox.getValue())); + } +} diff --git a/src/main/java/com/trunksbomb/bagtabs/item/BagItem.java b/src/main/java/com/trunksbomb/bagtabs/item/BagItem.java index f9b280e..dd5d0a9 100644 --- a/src/main/java/com/trunksbomb/bagtabs/item/BagItem.java +++ b/src/main/java/com/trunksbomb/bagtabs/item/BagItem.java @@ -2,6 +2,7 @@ package com.trunksbomb.bagtabs.item; import com.trunksbomb.bagtabs.BagTabs; import com.trunksbomb.bagtabs.bag.BagContainer; +import com.trunksbomb.bagtabs.bag.BagIdentityData; import com.trunksbomb.bagtabs.bag.InventoryBag; import com.trunksbomb.bagtabs.menu.BagMenu; import java.util.ArrayList; @@ -43,12 +44,14 @@ public class BagItem extends Item implements InventoryBag { public static ItemStack createColoredStack(int color) { ItemStack stack = BagTabs.BAG.get().getDefaultInstance(); stack.set(DataComponents.DYED_COLOR, new DyedItemColor(color, true)); + BagIdentityData.ensureBagId(stack); return stack; } @Override public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { ItemStack stack = player.getItemInHand(usedHand); + BagIdentityData.ensureBagId(stack); if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) { this.openFromInventory(serverPlayer, usedHand == InteractionHand.MAIN_HAND ? serverPlayer.getInventory().selected : Inventory.SLOT_OFFHAND); } @@ -63,6 +66,8 @@ public class BagItem extends Item implements InventoryBag { return; } + BagIdentityData.ensureBagId(stack); + Component title = stack.getHoverName(); OptionalInt windowId = player.openMenu( new SimpleMenuProvider((containerId, playerInventory, ignoredPlayer) -> new BagMenu( diff --git a/src/main/java/com/trunksbomb/bagtabs/item/BagNamerItem.java b/src/main/java/com/trunksbomb/bagtabs/item/BagNamerItem.java new file mode 100644 index 0000000..6554b0e --- /dev/null +++ b/src/main/java/com/trunksbomb/bagtabs/item/BagNamerItem.java @@ -0,0 +1,33 @@ +package com.trunksbomb.bagtabs.item; + +import com.trunksbomb.bagtabs.BagTabs; +import com.trunksbomb.bagtabs.menu.BagNamerMenu; +import java.util.OptionalInt; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class BagNamerItem extends Item { + public BagNamerItem(Properties properties) { + super(properties); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + ItemStack stack = player.getItemInHand(usedHand); + if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) { + OptionalInt ignored = serverPlayer.openMenu(new SimpleMenuProvider( + (containerId, inventory, ignoredPlayer) -> new BagNamerMenu(containerId, inventory), + Component.translatable("container." + BagTabs.MODID + ".bag_namer") + )); + } + + return InteractionResultHolder.sidedSuccess(stack, level.isClientSide); + } +} diff --git a/src/main/java/com/trunksbomb/bagtabs/menu/BagNamerMenu.java b/src/main/java/com/trunksbomb/bagtabs/menu/BagNamerMenu.java new file mode 100644 index 0000000..0efdf2f --- /dev/null +++ b/src/main/java/com/trunksbomb/bagtabs/menu/BagNamerMenu.java @@ -0,0 +1,136 @@ +package com.trunksbomb.bagtabs.menu; + +import com.trunksbomb.bagtabs.BagTabs; +import com.trunksbomb.bagtabs.bag.BagCompat; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; + +public class BagNamerMenu extends AbstractContainerMenu { + private static final int INPUT_SLOT = 0; + private static final int OUTPUT_SLOT = 1; + private static final int PLAYER_INV_START = 2; + private static final int PLAYER_INV_END = 29; + private static final int HOTBAR_START = 29; + private static final int HOTBAR_END = 38; + + private final SimpleContainer renameContainer; + + public static BagNamerMenu fromNetwork(int containerId, Inventory playerInventory, RegistryFriendlyByteBuf extraData) { + return new BagNamerMenu(containerId, playerInventory); + } + + public BagNamerMenu(int containerId, Inventory playerInventory) { + this(containerId, playerInventory, new SimpleContainer(2)); + } + + private BagNamerMenu(int containerId, Inventory playerInventory, SimpleContainer renameContainer) { + super(BagTabs.BAG_NAMER_MENU.get(), containerId); + checkContainerSize(renameContainer, 2); + this.renameContainer = renameContainer; + renameContainer.startOpen(playerInventory.player); + + this.addSlot(new Slot(renameContainer, INPUT_SLOT, 44, 46) { + @Override + public boolean mayPlace(ItemStack stack) { + return BagCompat.canName(stack); + } + }); + this.addSlot(new Slot(renameContainer, OUTPUT_SLOT, 116, 46) { + @Override + public boolean mayPlace(ItemStack stack) { + return false; + } + }); + + for (int row = 0; row < 3; row++) { + for (int column = 0; column < 9; column++) { + int slotIndex = column + row * 9 + 9; + this.addSlot(new Slot(playerInventory, slotIndex, 8 + column * 18, 83 + row * 18)); + } + } + + for (int column = 0; column < 9; column++) { + this.addSlot(new Slot(playerInventory, column, 8 + column * 18, 141)); + } + } + + public boolean renameInput(String requestedName) { + ItemStack input = this.renameContainer.getItem(INPUT_SLOT); + ItemStack output = this.renameContainer.getItem(OUTPUT_SLOT); + if (input.isEmpty() || !output.isEmpty() || !BagCompat.canName(input)) { + return false; + } + + ItemStack renamed = input.copy(); + String name = requestedName.trim(); + if (name.isEmpty()) { + renamed.remove(DataComponents.CUSTOM_NAME); + } else { + renamed.set(DataComponents.CUSTOM_NAME, Component.literal(name)); + } + + this.renameContainer.setItem(OUTPUT_SLOT, renamed); + this.renameContainer.setItem(INPUT_SLOT, ItemStack.EMPTY); + this.broadcastChanges(); + return true; + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public ItemStack quickMoveStack(Player player, int index) { + Slot slot = this.slots.get(index); + if (slot == null || !slot.hasItem()) { + return ItemStack.EMPTY; + } + + ItemStack stack = slot.getItem(); + ItemStack copied = stack.copy(); + + if (index == OUTPUT_SLOT) { + if (!this.moveItemStackTo(stack, PLAYER_INV_START, this.slots.size(), true)) { + return ItemStack.EMPTY; + } + slot.onQuickCraft(stack, copied); + } else if (index == INPUT_SLOT) { + if (!this.moveItemStackTo(stack, PLAYER_INV_START, this.slots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (BagCompat.canName(stack)) { + if (!this.moveItemStackTo(stack, INPUT_SLOT, INPUT_SLOT + 1, false)) { + return ItemStack.EMPTY; + } + } else if (index < HOTBAR_START) { + if (!this.moveItemStackTo(stack, HOTBAR_START, HOTBAR_END, false)) { + return ItemStack.EMPTY; + } + } else if (!this.moveItemStackTo(stack, PLAYER_INV_START, HOTBAR_START, false)) { + return ItemStack.EMPTY; + } + + if (stack.isEmpty()) { + slot.setByPlayer(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + + return copied; + } + + @Override + public void removed(Player player) { + super.removed(player); + this.clearContainer(player, this.renameContainer); + this.renameContainer.stopOpen(player); + } +} diff --git a/src/main/java/com/trunksbomb/bagtabs/network/BagTabsNetwork.java b/src/main/java/com/trunksbomb/bagtabs/network/BagTabsNetwork.java index c7a08fe..7a8343d 100644 --- a/src/main/java/com/trunksbomb/bagtabs/network/BagTabsNetwork.java +++ b/src/main/java/com/trunksbomb/bagtabs/network/BagTabsNetwork.java @@ -10,6 +10,7 @@ public final class BagTabsNetwork { registrar.playToServer(OpenBagPayload.TYPE, OpenBagPayload.STREAM_CODEC, OpenBagPayload::handle); registrar.playToServer(InsertIntoBagPayload.TYPE, InsertIntoBagPayload.STREAM_CODEC, InsertIntoBagPayload::handle); registrar.playToServer(QueryInsertTargetsPayload.TYPE, QueryInsertTargetsPayload.STREAM_CODEC, QueryInsertTargetsPayload::handle); + registrar.playToServer(RenameBagPayload.TYPE, RenameBagPayload.STREAM_CODEC, RenameBagPayload::handle); registrar.playToClient(InsertTargetsPayload.TYPE, InsertTargetsPayload.STREAM_CODEC, InsertTargetsPayload::handle); } } diff --git a/src/main/java/com/trunksbomb/bagtabs/network/RenameBagPayload.java b/src/main/java/com/trunksbomb/bagtabs/network/RenameBagPayload.java new file mode 100644 index 0000000..3562142 --- /dev/null +++ b/src/main/java/com/trunksbomb/bagtabs/network/RenameBagPayload.java @@ -0,0 +1,34 @@ +package com.trunksbomb.bagtabs.network; + +import com.trunksbomb.bagtabs.BagTabs; +import com.trunksbomb.bagtabs.menu.BagNamerMenu; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +public record RenameBagPayload(String name) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(BagTabs.id("rename_bag")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.stringUtf8(48), + RenameBagPayload::name, + RenameBagPayload::new + ); + + @Override + public Type type() { + return TYPE; + } + + public static void handle(RenameBagPayload payload, IPayloadContext context) { + if (!(context.player() instanceof ServerPlayer serverPlayer)) { + return; + } + + if (serverPlayer.containerMenu instanceof BagNamerMenu bagNamerMenu) { + bagNamerMenu.renameInput(payload.name()); + } + } +} diff --git a/src/main/resources/assets/bagtabs/lang/en_us.json b/src/main/resources/assets/bagtabs/lang/en_us.json index 648c34b..52e17fc 100644 --- a/src/main/resources/assets/bagtabs/lang/en_us.json +++ b/src/main/resources/assets/bagtabs/lang/en_us.json @@ -1,6 +1,11 @@ { "item.bagtabs.bag": "Traveler's Bag", + "item.bagtabs.bag_namer": "Bag Namer", "itemGroup.bagtabs": "Bag Tabs", "container.bagtabs.bag": "Bag", - "bagtabs.tooltip.click_to_open": "Open from your inventory tabs" + "container.bagtabs.bag_namer": "Bag Namer", + "bagtabs.tooltip.click_to_open": "Open from your inventory tabs", + "bagtabs.gui.bag_namer.name": "New Name", + "bagtabs.gui.bag_namer.placeholder": "Leave blank to clear", + "bagtabs.gui.bag_namer.rename": "Rename" } diff --git a/src/main/resources/assets/bagtabs/models/item/bag_namer.json b/src/main/resources/assets/bagtabs/models/item/bag_namer.json new file mode 100644 index 0000000..2ff422a --- /dev/null +++ b/src/main/resources/assets/bagtabs/models/item/bag_namer.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "bagtabs:item/bag_namer" + } +} diff --git a/src/main/resources/assets/bagtabs/textures/gui/bag_namer.png b/src/main/resources/assets/bagtabs/textures/gui/bag_namer.png new file mode 100644 index 0000000..171e76e Binary files /dev/null and b/src/main/resources/assets/bagtabs/textures/gui/bag_namer.png differ diff --git a/src/main/resources/assets/bagtabs/textures/item/bag_namer.png b/src/main/resources/assets/bagtabs/textures/item/bag_namer.png new file mode 100644 index 0000000..286f870 Binary files /dev/null and b/src/main/resources/assets/bagtabs/textures/item/bag_namer.png differ diff --git a/src/main/resources/data/bagtabs/recipes/bag_namer.json b/src/main/resources/data/bagtabs/recipes/bag_namer.json new file mode 100644 index 0000000..0260627 --- /dev/null +++ b/src/main/resources/data/bagtabs/recipes/bag_namer.json @@ -0,0 +1,28 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " PI", + " NB", + " G" + ], + "key": { + "P": { + "item": "minecraft:paper" + }, + "I": { + "item": "minecraft:ink_sac" + }, + "N": { + "item": "minecraft:name_tag" + }, + "B": { + "item": "bagtabs:bag" + }, + "G": { + "item": "minecraft:gold_nugget" + } + }, + "result": { + "id": "bagtabs:bag_namer" + } +}