diff --git a/src/main/generated/assets/acesbs/items/bag_of_holding.json b/src/main/generated/assets/acesbs/items/bag_of_holding.json new file mode 100644 index 0000000..958d36e --- /dev/null +++ b/src/main/generated/assets/acesbs/items/bag_of_holding.json @@ -0,0 +1,15 @@ +{ + "model": { + "type": "minecraft:condition", + "component": "acesbs:bag_open", + "on_false": { + "type": "minecraft:model", + "model": "acesbs:item/bag_of_holding" + }, + "on_true": { + "type": "minecraft:model", + "model": "acesbs:item/bag_of_holding_open" + }, + "property": "minecraft:has_component" + } +} \ No newline at end of file diff --git a/src/main/generated/assets/acesbs/models/item/bag_of_holding.json b/src/main/generated/assets/acesbs/models/item/bag_of_holding.json new file mode 100644 index 0000000..b9a3ab2 --- /dev/null +++ b/src/main/generated/assets/acesbs/models/item/bag_of_holding.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "acesbs:item/bag_of_holding" + } +} \ No newline at end of file diff --git a/src/main/generated/assets/acesbs/models/item/bag_of_holding_open.json b/src/main/generated/assets/acesbs/models/item/bag_of_holding_open.json new file mode 100644 index 0000000..96ca55e --- /dev/null +++ b/src/main/generated/assets/acesbs/models/item/bag_of_holding_open.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "acesbs:item/bag_of_holding_open" + } +} \ No newline at end of file diff --git a/src/main/generated/data/acesbs/advancement/recipes/tools/bag_of_holding.json b/src/main/generated/data/acesbs/advancement/recipes/tools/bag_of_holding.json new file mode 100644 index 0000000..0f8a15d --- /dev/null +++ b/src/main/generated/data/acesbs/advancement/recipes/tools/bag_of_holding.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_fractal_diamond": { + "conditions": { + "items": [ + { + "items": "acesbs:fractal_diamond" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "acesbs:bag_of_holding" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_fractal_diamond" + ] + ], + "rewards": { + "recipes": [ + "acesbs:bag_of_holding" + ] + } +} \ No newline at end of file diff --git a/src/main/generated/data/acesbs/recipe/bag_of_holding.json b/src/main/generated/data/acesbs/recipe/bag_of_holding.json new file mode 100644 index 0000000..39dfbc7 --- /dev/null +++ b/src/main/generated/data/acesbs/recipe/bag_of_holding.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "C": "minecraft:chest", + "F": "acesbs:fractal_diamond_block", + "L": "minecraft:leather", + "S": "minecraft:string" + }, + "pattern": [ + "LSL", + "CFC", + "LLL" + ], + "result": { + "count": 1, + "id": "acesbs:bag_of_holding" + } +} \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java b/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java index 339a112..3780e40 100644 --- a/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java +++ b/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java @@ -12,6 +12,7 @@ import com.acethewildfire.acesbs.particle.GreenFlame; import com.acethewildfire.acesbs.particle.ModParticles; import com.acethewildfire.acesbs.particle.PurpleFlame; import com.acethewildfire.acesbs.screen.ModScreenHandlers; +import com.acethewildfire.acesbs.screen.custom.BagOfHoldingScreen; import com.acethewildfire.acesbs.screen.custom.EntropicEntanglerScreen; import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreen; import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreen; @@ -47,6 +48,7 @@ public class AcesBSClient implements ClientModInitializer { HandledScreens.register(ModScreenHandlers.ENTROPIC_STABILIZER_SCREEN_HANDLER, EntropicStabilizerScreen::new); HandledScreens.register(ModScreenHandlers.ENTROPIC_EVISCERATOR_SCREEN_HANDLER, EntropicEvisceratorScreen::new); HandledScreens.register(ModScreenHandlers.ENTROPIC_ENTANGLER_SCREEN_HANDLER, EntropicEntanglerScreen::new); + HandledScreens.register(ModScreenHandlers.BAG_OF_HOLDING_SCREEN_HANDLER, BagOfHoldingScreen::new); ParticleFactoryRegistry.getInstance().register(ModParticles.PURPLE_FLAME, PurpleFlame.Factory::new); ParticleFactoryRegistry.getInstance().register(ModParticles.GREEN_FLAME, GreenFlame.Factory::new); diff --git a/src/main/java/com/acethewildfire/acesbs/PATCH_NOTES.md b/src/main/java/com/acethewildfire/acesbs/PATCH_NOTES.md index 6cbe017..deed1de 100644 --- a/src/main/java/com/acethewildfire/acesbs/PATCH_NOTES.md +++ b/src/main/java/com/acethewildfire/acesbs/PATCH_NOTES.md @@ -6,6 +6,7 @@ - Fire Oak Trees and associated wood blocks. Obtainable by placing an oak sapling and infernal ashes in an Entropic Entangler - Fractal Diamonds can now be obtained by placing a diamond and stable entropy into an entropic entangler. They can be used to craft tools and armor. They have the same effect as Prisma Steel and drop additional ores when mining. - Hellfire Diamonds can now be obtained by placing a diamond and infernal ashes into an entropic entangler. They can be used to craft tools and armor. They automatically smelt items that are smeltable. (Ex: Ores->ingots, logs->charcoal, sand->glass). +- Bag of Holding which acts as a portable double chest. - More Advancements! ## Fixes - Blocks of Ashen Steel now have a recipe and drop when mined. Not sure how I missed that one. @@ -24,4 +25,5 @@ # Known Issues - The Command Core Item does not display the correct texture when activated. - The Command Core Item does not offer any functionality -- The Combustible Lemon does not render when thrown. \ No newline at end of file +- The Combustible Lemon does not render when thrown. +- Do not drop the bundle while it is open. It will not save your changes, and you will delete your items. \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/component/BagContentsComponent.java b/src/main/java/com/acethewildfire/acesbs/component/BagContentsComponent.java new file mode 100644 index 0000000..38bd539 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/component/BagContentsComponent.java @@ -0,0 +1,116 @@ +package com.acethewildfire.acesbs.component; + +import com.acethewildfire.acesbs.item.custom.BagOfHolding; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.item.ItemStack; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.util.collection.DefaultedList; + +import java.util.ArrayList; +import java.util.List; + +public class BagContentsComponent { + public record SlotEntry(int slot, ItemStack stack) {} + + public static final int SIZE = 54; + + private final DefaultedList items; + + public BagContentsComponent(DefaultedList items) { + this.items = items; + } + + public DefaultedList getItems() { + return items; + } + + public static boolean isInvalidStack(ItemStack stack) { + return stack.getItem() instanceof BagOfHolding; + } + + public static BagContentsComponent empty() { + return new BagContentsComponent(DefaultedList.ofSize(SIZE, ItemStack.EMPTY)); + } + + public static final Codec SLOT_ENTRY_CODEC = + Codec.pair( + Codec.INT.fieldOf("slot").codec(), + ItemStack.CODEC + ).xmap( + pair -> new SlotEntry(pair.getFirst(), pair.getSecond()), + entry -> com.mojang.datafixers.util.Pair.of(entry.slot(), entry.stack()) + ); + + public static final Codec CODEC = + SLOT_ENTRY_CODEC.listOf().xmap( + list -> { + DefaultedList items = + DefaultedList.ofSize(BagContentsComponent.SIZE, ItemStack.EMPTY); + + for (SlotEntry entry : list) { + if (entry.slot() >= 0 && entry.slot() < items.size()) { + items.set(entry.slot(), entry.stack()); + } + } + + return new BagContentsComponent(items); + }, + component -> { + List result = new ArrayList<>(); + + for (int i = 0; i < component.getItems().size(); i++) { + ItemStack stack = component.getItems().get(i); + if (!stack.isEmpty()) { + result.add(new SlotEntry(i, stack)); + } + } + + return result; + } + ); + + public static final PacketCodec SLOT_ENTRY_PACKET_CODEC = + PacketCodec.of( + (entry, buf) -> { + buf.writeVarInt(entry.slot()); + ItemStack.PACKET_CODEC.encode(buf, entry.stack()); + }, + buf -> { + int slot = buf.readVarInt(); + ItemStack stack = ItemStack.PACKET_CODEC.decode(buf); + return new SlotEntry(slot, stack); + } + ); + + public static final PacketCodec PACKET_CODEC = + SLOT_ENTRY_PACKET_CODEC.collect(PacketCodecs.toList()) + .xmap( + list -> { + DefaultedList items = + DefaultedList.ofSize(BagContentsComponent.SIZE, ItemStack.EMPTY); + + for (SlotEntry entry : list) { + if (entry.slot() >= 0 && entry.slot() < items.size()) { + items.set(entry.slot(), entry.stack()); + } + } + + return new BagContentsComponent(items); + }, + component -> { + List list = new ArrayList<>(); + + for (int i = 0; i < component.getItems().size(); i++) { + ItemStack stack = component.getItems().get(i); + if (!stack.isEmpty()) { + list.add(new SlotEntry(i, stack)); + } + } + + return list; + } + ); +} diff --git a/src/main/java/com/acethewildfire/acesbs/component/ModDataComponentTypes.java b/src/main/java/com/acethewildfire/acesbs/component/ModDataComponentTypes.java index 400f19b..b83b9a3 100644 --- a/src/main/java/com/acethewildfire/acesbs/component/ModDataComponentTypes.java +++ b/src/main/java/com/acethewildfire/acesbs/component/ModDataComponentTypes.java @@ -3,10 +3,13 @@ package com.acethewildfire.acesbs.component; import com.acethewildfire.acesbs.AcesBS; import com.mojang.serialization.Codec; import net.minecraft.component.ComponentType; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; import net.minecraft.network.codec.PacketCodecs; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; +import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.math.BlockPos; import java.util.function.UnaryOperator; @@ -28,6 +31,11 @@ public class ModDataComponentTypes { public static final ComponentType COMMAND_ACTIVE = register("command_active", booleanBuilder -> booleanBuilder.codec(Codec.BOOL).packetCodec(PacketCodecs.BOOLEAN)); + public static final ComponentType BAG_CONTENTS = + register("bag_contents", inventoryBuilder -> inventoryBuilder.codec(BagContentsComponent.CODEC).packetCodec(BagContentsComponent.PACKET_CODEC)); + + public static final ComponentType BAG_OPEN = + register("bag_open", booleanBuilder -> booleanBuilder.codec(Codec.BOOL).packetCodec(PacketCodecs.BOOLEAN)); private static ComponentType register(String name, UnaryOperator> builderOperator){ return Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(AcesBS.MOD_ID, name), diff --git a/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java b/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java index a4f9844..40c1177 100644 --- a/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java +++ b/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java @@ -195,6 +195,13 @@ public class ModModelProvider extends FabricModelProvider { unbakedUsedWand, unbakedWand), new ItemAsset.Properties(false, false)).model()); + ItemModel.Unbaked unbakedBagOfHolding = ItemModels.basic(itemModelGenerator.upload(ModItems.BAG_OF_HOLDING, Models.GENERATED)); + ItemModel.Unbaked unbakedUsedBagOfHolding = ItemModels.basic(itemModelGenerator.registerSubModel(ModItems.BAG_OF_HOLDING, "_open", Models.GENERATED)); + itemModelGenerator.output.accept(ModItems.BAG_OF_HOLDING, + new ItemAsset(new ConditionItemModel.Unbaked(new HasComponentProperty(ModDataComponentTypes.BAG_OPEN, false), + unbakedUsedBagOfHolding, unbakedBagOfHolding), + new ItemAsset.Properties(false, false)).model()); + // ItemModel.Unbaked unbakedCigarette = ItemModels.basic(itemModelGenerator.upload(ModItems.CIGARETTE, Models.GENERATED)); // ItemModel.Unbaked unbakedUsedCigarette = ItemModels.basic(itemModelGenerator.registerSubModel(ModItems.CIGARETTE, "_smoking", Models.GENERATED)); // itemModelGenerator.output.accept(ModItems.CIGARETTE, diff --git a/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java b/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java index f07f487..f3a3437 100644 --- a/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java +++ b/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java @@ -56,6 +56,17 @@ public class ModRecipeProvider extends FabricRecipeProvider { offerAllFoodCookingRecipes(200, ModItems.LEMON, ModItems.COOKED_LEMON, 0.35F); + createShaped(RecipeCategory.TOOLS, ModItems.BAG_OF_HOLDING, 1) + .pattern("LSL") + .pattern("CFC") + .pattern("LLL") + .input('S', Items.STRING) + .input('F', ModBlocks.FRACTAL_DIAMOND_BLOCK) + .input('C', Blocks.CHEST) + .input('L', Items.LEATHER) + .criterion(hasItem(FractalDiamondItems.FRACTAL_DIAMOND), conditionsFromItem(FractalDiamondItems.FRACTAL_DIAMOND)) + .offerTo(recipeExporter); + createShaped(RecipeCategory.COMBAT, ModItems.ORACLE_LEMON, 4) .pattern("###") .pattern("#L#") diff --git a/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java b/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java index 530ebf4..95bb7b2 100644 --- a/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java +++ b/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java @@ -49,6 +49,7 @@ public class ModItemGroups { entries.add(ModItems.FREN_SPAWN_EGG); entries.add(ModItems.VULGAR_BONES_SPAWN_EGG); + entries.add(ModItems.BAG_OF_HOLDING); }) .build(); diff --git a/src/main/java/com/acethewildfire/acesbs/item/ModItems.java b/src/main/java/com/acethewildfire/acesbs/item/ModItems.java index 799c1c0..a4a3949 100644 --- a/src/main/java/com/acethewildfire/acesbs/item/ModItems.java +++ b/src/main/java/com/acethewildfire/acesbs/item/ModItems.java @@ -38,6 +38,7 @@ import java.util.function.Function; public class ModItems { public static final Item ORACLE_LEMON = registerItem("oracle_lemon", setting -> new OracleLemon(setting.component(DataComponentTypes.POTION_CONTENTS, new PotionContentsComponent(ModPotions.LEMON)))); public static final Item WAND = registerItem("wand", setting -> new Wand(setting.maxDamage(32))); + public static final Item BAG_OF_HOLDING = registerItem("bag_of_holding", BagOfHolding::new); public static final Item RAW_ENTROPY = registerItem("raw_entropy", Item::new); public static final Item STABLE_ENTROPY = registerItem("stable_entropy", Item::new); public static final Item RAW_ENDTROPY = registerItem("raw_endtropy", Item::new); diff --git a/src/main/java/com/acethewildfire/acesbs/item/custom/BagOfHolding.java b/src/main/java/com/acethewildfire/acesbs/item/custom/BagOfHolding.java new file mode 100644 index 0000000..55769af --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/item/custom/BagOfHolding.java @@ -0,0 +1,63 @@ +package com.acethewildfire.acesbs.item.custom; + +import com.acethewildfire.acesbs.component.BagContentsComponent; +import com.acethewildfire.acesbs.component.ModDataComponentTypes; +import com.acethewildfire.acesbs.screen.custom.BagOfHoldingScreenHandler; +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +public class BagOfHolding extends Item implements ExtendedScreenHandlerFactory { + + + public BagOfHolding(Settings settings) { + super(settings.maxCount(1)); + } + + @Override + public ItemStack getScreenOpeningData(ServerPlayerEntity serverPlayerEntity) { + return serverPlayerEntity.getMainHandStack(); + } + + @Override + public Text getDisplayName() { + return Text.literal("Bag of Holding"); + } + + @Override + public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { + return new BagOfHoldingScreenHandler(syncId, playerInventory, player.getMainHandStack()); + } + + @Override + public ActionResult use(World world, PlayerEntity user, Hand hand) { + BagContentsComponent bagContentsComponent = + user.getMainHandStack().get(ModDataComponentTypes.BAG_CONTENTS); + + user.getMainHandStack().set(ModDataComponentTypes.BAG_OPEN, true); + + if (bagContentsComponent == null) { + user.getMainHandStack().set( + ModDataComponentTypes.BAG_CONTENTS, + BagContentsComponent.empty() + ); + } + if (!world.isClient()) { + NamedScreenHandlerFactory screenHandlerFactory = (BagOfHolding) user.getMainHandStack().getItem(); + if (screenHandlerFactory != null) { + user.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/item/custom/BagOfHoldingInventory.java b/src/main/java/com/acethewildfire/acesbs/item/custom/BagOfHoldingInventory.java new file mode 100644 index 0000000..5cd9a9b --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/item/custom/BagOfHoldingInventory.java @@ -0,0 +1,87 @@ +package com.acethewildfire.acesbs.item.custom; + +import com.acethewildfire.acesbs.component.BagContentsComponent; +import com.acethewildfire.acesbs.component.ModDataComponentTypes; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; + +import java.util.List; + +public class BagOfHoldingInventory implements Inventory { + private final DefaultedList items; + private final ItemStack stack; + + public BagOfHoldingInventory(ItemStack stack, BagContentsComponent component) { + this.stack = stack; + this.items = DefaultedList.ofSize(BagContentsComponent.SIZE, ItemStack.EMPTY); + + // Copy saved items into inventory + DefaultedList saved = component.getItems(); + for (int i = 0; i < Math.min(saved.size(), items.size()); i++) { + items.set(i, saved.get(i)); + } + } + + public DefaultedList getItems() { + return items; + } + + @Override + public int size() { + return items.size(); + } + + @Override + public boolean isEmpty() { + return items.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public ItemStack getStack(int slot) { + return items.get(slot); + } + + @Override + public ItemStack removeStack(int slot, int amount) { + ItemStack result = Inventories.splitStack(items, slot, amount); + markDirty(); + return result; + } + + @Override + public ItemStack removeStack(int slot) { + ItemStack result = Inventories.removeStack(items, slot); + markDirty(); + return result; + } + + @Override + public void setStack(int slot, ItemStack stack) { + items.set(slot, stack); + markDirty(); + } + + @Override + public void markDirty() { + // Save back into the item + stack.set(ModDataComponentTypes.BAG_CONTENTS, + new BagContentsComponent(DefaultedList.copyOf(ItemStack.EMPTY, items.toArray(new ItemStack[0]))) + ); + } + + @Override + public boolean canPlayerUse(PlayerEntity player) { + return true; + } + + @Override + public void clear() { + for (int i = 0; i < items.size(); i++) { + items.set(i, ItemStack.EMPTY); + } + markDirty(); + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java b/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java index c1412a4..320936a 100644 --- a/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java +++ b/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java @@ -1,13 +1,18 @@ package com.acethewildfire.acesbs.screen; import com.acethewildfire.acesbs.AcesBS; +import com.acethewildfire.acesbs.item.custom.BagOfHolding; +import com.acethewildfire.acesbs.screen.custom.BagOfHoldingScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicEntanglerScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreenHandler; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; @@ -25,6 +30,10 @@ public class ModScreenHandlers { Registry.register(Registries.SCREEN_HANDLER, Identifier.of(AcesBS.MOD_ID, "entropic_entangler_screen_handler"), new ExtendedScreenHandlerType<>(EntropicEntanglerScreenHandler::new, BlockPos.PACKET_CODEC)); + public static final ScreenHandlerType BAG_OF_HOLDING_SCREEN_HANDLER = + Registry.register(Registries.SCREEN_HANDLER, Identifier.of(AcesBS.MOD_ID, "bag_of_holding_screen_handler"), + new ExtendedScreenHandlerType<>(BagOfHoldingScreenHandler::new, ItemStack.PACKET_CODEC)); + public static void registerScreenHandlers() { AcesBS.LOGGER.info("Registering Screen Handlers for " + AcesBS.MOD_ID); diff --git a/src/main/java/com/acethewildfire/acesbs/screen/custom/BagOfHoldingScreen.java b/src/main/java/com/acethewildfire/acesbs/screen/custom/BagOfHoldingScreen.java new file mode 100644 index 0000000..8a596ab --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/screen/custom/BagOfHoldingScreen.java @@ -0,0 +1,44 @@ +package com.acethewildfire.acesbs.screen.custom; + +import com.acethewildfire.acesbs.AcesBS; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class BagOfHoldingScreen extends HandledScreen { + + public static final Identifier GUI_TEXTURE = + Identifier.of(AcesBS.MOD_ID, "textures/gui/bag_of_holding/bag_of_holding_gui.png"); + + public BagOfHoldingScreen(BagOfHoldingScreenHandler handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + this.backgroundHeight = 221; + + } + + @Override + protected void drawBackground(DrawContext context, float deltaTicks, int mouseX, int mouseY) { + int x = (width - backgroundWidth) / 2; + int y = (height - backgroundHeight) / 2; + + context.drawTexture(RenderPipelines.GUI_TEXTURED, GUI_TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight, 256, 256); + + } + + @Override + protected void drawForeground(DrawContext context, int mouseX, int mouseY) { +// super.drawForeground(context, mouseX, mouseY); + + context.drawText(this.textRenderer, this.title, this.titleX, this.titleY, -12566464, false); + context.drawText(this.textRenderer, this.playerInventoryTitle, this.playerInventoryTitleX, this.backgroundHeight - 96 + 3, -12566464, false); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + drawMouseoverTooltip(context, mouseX, mouseY); + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/screen/custom/BagOfHoldingScreenHandler.java b/src/main/java/com/acethewildfire/acesbs/screen/custom/BagOfHoldingScreenHandler.java new file mode 100644 index 0000000..dc9a72d --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/screen/custom/BagOfHoldingScreenHandler.java @@ -0,0 +1,133 @@ +package com.acethewildfire.acesbs.screen.custom; + +import com.acethewildfire.acesbs.AcesBS; +import com.acethewildfire.acesbs.component.BagContentsComponent; +import com.acethewildfire.acesbs.component.ModDataComponentTypes; +import com.acethewildfire.acesbs.item.custom.BagOfHolding; +import com.acethewildfire.acesbs.item.custom.BagOfHoldingInventory; +import com.acethewildfire.acesbs.screen.ModScreenHandlers; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.util.collection.DefaultedList; + +public class BagOfHoldingScreenHandler extends ScreenHandler { + private final BagOfHoldingInventory inventory; + + public class BagSlot extends Slot { + public BagSlot(Inventory inventory, int index, int x, int y) { + super(inventory, index, x, y); + } + + @Override + public boolean canInsert(ItemStack stack) { + return !BagContentsComponent.isInvalidStack(stack); + } + } + + public BagOfHoldingScreenHandler(int syncId, PlayerInventory playerInventory, ItemStack stack) { + super(ModScreenHandlers.BAG_OF_HOLDING_SCREEN_HANDLER, syncId); + + BagContentsComponent comp = stack.getOrDefault( + ModDataComponentTypes.BAG_CONTENTS, + BagContentsComponent.empty() + ); + + this.inventory = new BagOfHoldingInventory(stack, comp); + + addBagInventory(); + addPlayerInventory(playerInventory); + addPlayerHotbar(playerInventory); + } + + @Override + public boolean insertItem(ItemStack stack, int startIndex, int endIndex, boolean fromLast) { + if (BagContentsComponent.isInvalidStack(stack)) { + return false; + } + + return super.insertItem(stack, startIndex, endIndex, fromLast); + } + + @Override + public ItemStack quickMove(PlayerEntity player, int index) { + ItemStack newStack = ItemStack.EMPTY; + Slot slot = this.slots.get(index); + + if (slot != null && slot.hasStack()) { + ItemStack originalStack = slot.getStack(); + newStack = originalStack.copy(); + + int containerSize = 54; + + if (index < containerSize) { + // Move from bag → player + if (!this.insertItem(originalStack, containerSize, this.slots.size(), true)) { + return ItemStack.EMPTY; + } + } else { + // Move from player → bag + if (!this.insertItem(originalStack, 0, containerSize, false)) { + return ItemStack.EMPTY; + } + } + + if (originalStack.isEmpty()) { + slot.setStack(ItemStack.EMPTY); + } else { + slot.markDirty(); + } + } + + return newStack; + } + + @Override + public boolean canUse(PlayerEntity player) { + return true; + } + + private void addPlayerInventory(PlayerInventory playerInventory) { + for (int i = 0; i < 3; ++i) { + for (int l = 0; l < 9; ++l) { + this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, 140 + i * 18)); + } + } + } + + private void addBagInventory() { + for (int row = 0; row < 6; row++) { + for (int col = 0; col < 9; col++) { + int index = col + row * 9; + this.addSlot(new BagSlot(inventory, index, 8 + col * 18, 18 + row * 18)); + } + } + } + + private void addPlayerHotbar(PlayerInventory playerInventory) { + for (int i = 0; i < 9; ++i) { + this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 198)); + } + } + + @Override + public void onClosed(PlayerEntity player) { + super.onClosed(player); + + if (player.getMainHandStack().getItem() instanceof BagOfHolding) { + BagContentsComponent updated = new BagContentsComponent( + this.inventory.getItems() + ); + + player.getMainHandStack().set( + ModDataComponentTypes.BAG_CONTENTS, + updated + ); + + player.getMainHandStack().remove(ModDataComponentTypes.BAG_OPEN); + } + } +} diff --git a/src/main/resources/assets/acesbs/lang/en_us.json b/src/main/resources/assets/acesbs/lang/en_us.json index 06eba25..c18cb2f 100644 --- a/src/main/resources/assets/acesbs/lang/en_us.json +++ b/src/main/resources/assets/acesbs/lang/en_us.json @@ -1,4 +1,5 @@ { + "item.acesbs.bag_of_holding": "Bag of Holding", "item.acesbs.oracle_lemon.effect.lemon": "Oracle of Lemon", "item.acesbs.combustible_lemon": "Combustible Lemon", "item.acesbs.raw_entropy": "Raw Entropy", diff --git a/src/main/resources/assets/acesbs/textures/gui/bag_of_holding/bag_of_holding_gui.png b/src/main/resources/assets/acesbs/textures/gui/bag_of_holding/bag_of_holding_gui.png new file mode 100644 index 0000000..744ea03 Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/gui/bag_of_holding/bag_of_holding_gui.png differ diff --git a/src/main/resources/assets/acesbs/textures/item/bag_of_holding.png b/src/main/resources/assets/acesbs/textures/item/bag_of_holding.png new file mode 100644 index 0000000..d582a1d Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/item/bag_of_holding.png differ diff --git a/src/main/resources/assets/acesbs/textures/item/bag_of_holding_open.png b/src/main/resources/assets/acesbs/textures/item/bag_of_holding_open.png new file mode 100644 index 0000000..b5fed33 Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/item/bag_of_holding_open.png differ