2.1.0 Bag of Holding

This commit is contained in:
Vos
2026-03-26 23:45:26 -05:00
parent 444e54518d
commit 4f28430810
22 changed files with 564 additions and 1 deletions
@@ -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"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "acesbs:item/bag_of_holding"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "acesbs:item/bag_of_holding_open"
}
}
@@ -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"
]
}
}
@@ -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"
}
}
@@ -12,6 +12,7 @@ import com.acethewildfire.acesbs.particle.GreenFlame;
import com.acethewildfire.acesbs.particle.ModParticles; import com.acethewildfire.acesbs.particle.ModParticles;
import com.acethewildfire.acesbs.particle.PurpleFlame; import com.acethewildfire.acesbs.particle.PurpleFlame;
import com.acethewildfire.acesbs.screen.ModScreenHandlers; 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.EntropicEntanglerScreen;
import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreen; import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreen;
import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreen; 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_STABILIZER_SCREEN_HANDLER, EntropicStabilizerScreen::new);
HandledScreens.register(ModScreenHandlers.ENTROPIC_EVISCERATOR_SCREEN_HANDLER, EntropicEvisceratorScreen::new); HandledScreens.register(ModScreenHandlers.ENTROPIC_EVISCERATOR_SCREEN_HANDLER, EntropicEvisceratorScreen::new);
HandledScreens.register(ModScreenHandlers.ENTROPIC_ENTANGLER_SCREEN_HANDLER, EntropicEntanglerScreen::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.PURPLE_FLAME, PurpleFlame.Factory::new);
ParticleFactoryRegistry.getInstance().register(ModParticles.GREEN_FLAME, GreenFlame.Factory::new); ParticleFactoryRegistry.getInstance().register(ModParticles.GREEN_FLAME, GreenFlame.Factory::new);
@@ -6,6 +6,7 @@
- Fire Oak Trees and associated wood blocks. Obtainable by placing an oak sapling and infernal ashes in an Entropic Entangler - 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. - 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). - 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! - More Advancements!
## Fixes ## Fixes
- Blocks of Ashen Steel now have a recipe and drop when mined. Not sure how I missed that one. - 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 # Known Issues
- The Command Core Item does not display the correct texture when activated. - The Command Core Item does not display the correct texture when activated.
- The Command Core Item does not offer any functionality - The Command Core Item does not offer any functionality
- The Combustible Lemon does not render when thrown. - 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.
@@ -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<ItemStack> items;
public BagContentsComponent(DefaultedList<ItemStack> items) {
this.items = items;
}
public DefaultedList<ItemStack> 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<SlotEntry> 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<BagContentsComponent> CODEC =
SLOT_ENTRY_CODEC.listOf().xmap(
list -> {
DefaultedList<ItemStack> 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<SlotEntry> 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<RegistryByteBuf, SlotEntry> 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<RegistryByteBuf, BagContentsComponent> PACKET_CODEC =
SLOT_ENTRY_PACKET_CODEC.collect(PacketCodecs.toList())
.xmap(
list -> {
DefaultedList<ItemStack> 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<SlotEntry> 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;
}
);
}
@@ -3,10 +3,13 @@ package com.acethewildfire.acesbs.component;
import com.acethewildfire.acesbs.AcesBS; import com.acethewildfire.acesbs.AcesBS;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import net.minecraft.component.ComponentType; import net.minecraft.component.ComponentType;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.network.codec.PacketCodecs; import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
@@ -28,6 +31,11 @@ public class ModDataComponentTypes {
public static final ComponentType<Boolean> COMMAND_ACTIVE = public static final ComponentType<Boolean> COMMAND_ACTIVE =
register("command_active", booleanBuilder -> booleanBuilder.codec(Codec.BOOL).packetCodec(PacketCodecs.BOOLEAN)); register("command_active", booleanBuilder -> booleanBuilder.codec(Codec.BOOL).packetCodec(PacketCodecs.BOOLEAN));
public static final ComponentType<BagContentsComponent> BAG_CONTENTS =
register("bag_contents", inventoryBuilder -> inventoryBuilder.codec(BagContentsComponent.CODEC).packetCodec(BagContentsComponent.PACKET_CODEC));
public static final ComponentType<Boolean> BAG_OPEN =
register("bag_open", booleanBuilder -> booleanBuilder.codec(Codec.BOOL).packetCodec(PacketCodecs.BOOLEAN));
private static <T>ComponentType<T> register(String name, UnaryOperator<ComponentType.Builder<T>> builderOperator){ private static <T>ComponentType<T> register(String name, UnaryOperator<ComponentType.Builder<T>> builderOperator){
return Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(AcesBS.MOD_ID, name), return Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(AcesBS.MOD_ID, name),
@@ -195,6 +195,13 @@ public class ModModelProvider extends FabricModelProvider {
unbakedUsedWand, unbakedWand), unbakedUsedWand, unbakedWand),
new ItemAsset.Properties(false, false)).model()); 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 unbakedCigarette = ItemModels.basic(itemModelGenerator.upload(ModItems.CIGARETTE, Models.GENERATED));
// ItemModel.Unbaked unbakedUsedCigarette = ItemModels.basic(itemModelGenerator.registerSubModel(ModItems.CIGARETTE, "_smoking", Models.GENERATED)); // ItemModel.Unbaked unbakedUsedCigarette = ItemModels.basic(itemModelGenerator.registerSubModel(ModItems.CIGARETTE, "_smoking", Models.GENERATED));
// itemModelGenerator.output.accept(ModItems.CIGARETTE, // itemModelGenerator.output.accept(ModItems.CIGARETTE,
@@ -56,6 +56,17 @@ public class ModRecipeProvider extends FabricRecipeProvider {
offerAllFoodCookingRecipes(200, ModItems.LEMON, ModItems.COOKED_LEMON, 0.35F); 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) createShaped(RecipeCategory.COMBAT, ModItems.ORACLE_LEMON, 4)
.pattern("###") .pattern("###")
.pattern("#L#") .pattern("#L#")
@@ -49,6 +49,7 @@ public class ModItemGroups {
entries.add(ModItems.FREN_SPAWN_EGG); entries.add(ModItems.FREN_SPAWN_EGG);
entries.add(ModItems.VULGAR_BONES_SPAWN_EGG); entries.add(ModItems.VULGAR_BONES_SPAWN_EGG);
entries.add(ModItems.BAG_OF_HOLDING);
}) })
.build(); .build();
@@ -38,6 +38,7 @@ import java.util.function.Function;
public class ModItems { 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 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 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 RAW_ENTROPY = registerItem("raw_entropy", Item::new);
public static final Item STABLE_ENTROPY = registerItem("stable_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); public static final Item RAW_ENDTROPY = registerItem("raw_endtropy", Item::new);
@@ -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<ItemStack> {
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;
}
}
@@ -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<ItemStack> 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<ItemStack> saved = component.getItems();
for (int i = 0; i < Math.min(saved.size(), items.size()); i++) {
items.set(i, saved.get(i));
}
}
public DefaultedList<ItemStack> 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();
}
}
@@ -1,13 +1,18 @@
package com.acethewildfire.acesbs.screen; package com.acethewildfire.acesbs.screen;
import com.acethewildfire.acesbs.AcesBS; 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.EntropicEntanglerScreenHandler;
import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreenHandler;
import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreenHandler;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; 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.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos; 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"), Registry.register(Registries.SCREEN_HANDLER, Identifier.of(AcesBS.MOD_ID, "entropic_entangler_screen_handler"),
new ExtendedScreenHandlerType<>(EntropicEntanglerScreenHandler::new, BlockPos.PACKET_CODEC)); new ExtendedScreenHandlerType<>(EntropicEntanglerScreenHandler::new, BlockPos.PACKET_CODEC));
public static final ScreenHandlerType<BagOfHoldingScreenHandler> 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() { public static void registerScreenHandlers() {
AcesBS.LOGGER.info("Registering Screen Handlers for " + AcesBS.MOD_ID); AcesBS.LOGGER.info("Registering Screen Handlers for " + AcesBS.MOD_ID);
@@ -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<BagOfHoldingScreenHandler> {
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);
}
}
@@ -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);
}
}
}
@@ -1,4 +1,5 @@
{ {
"item.acesbs.bag_of_holding": "Bag of Holding",
"item.acesbs.oracle_lemon.effect.lemon": "Oracle of Lemon", "item.acesbs.oracle_lemon.effect.lemon": "Oracle of Lemon",
"item.acesbs.combustible_lemon": "Combustible Lemon", "item.acesbs.combustible_lemon": "Combustible Lemon",
"item.acesbs.raw_entropy": "Raw Entropy", "item.acesbs.raw_entropy": "Raw Entropy",
Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B