From 4bc528f3d5caf3315f3cdcca9b129057744d3d5c Mon Sep 17 00:00:00 2001 From: Halbear Date: Mon, 27 Jul 2026 19:35:41 +0100 Subject: [PATCH] yo what the FUCK did they do to GUIs --- .../java/net/halbear/aotg/AgeoftheGods.java | 23 ++ .../GuiScreens/AlloyFurnaceGUIScreen.java | 66 +++++ .../AlloyFurnaceBlockEntity.java | 58 +++- .../blocks/AlloyFurnace/AlloyFurnaceGUI.java | 266 ++++++++++++++++++ .../AlloyFurnaceMultiBlock.java | 85 ++++-- .../AlloyFurnaceUpdateHandler.java | 50 +++- .../aotg/registries/ModBlockEntities.java | 10 +- .../halbear/aotg/registries/ModBlocks.java | 6 +- .../net/halbear/aotg/registries/ModItems.java | 4 + .../net/halbear/aotg/registries/ModMenus.java | 54 ++++ .../halbear/aotg/registries/ModScreens.java | 21 ++ .../utility/Networking/MenuStateUpdate.java | 75 +++++ .../aotg/utility/ServerModEventHandler.java | 46 +++ .../textures/screens/example_gui.png | Bin 0 -> 1177 bytes 14 files changed, 707 insertions(+), 57 deletions(-) create mode 100644 src/main/java/net/halbear/aotg/custom/GuiScreens/AlloyFurnaceGUIScreen.java rename src/main/java/net/halbear/aotg/custom/blocks/{ => AlloyFurnace}/AlloyFurnaceBlockEntity.java (54%) create mode 100644 src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceGUI.java rename src/main/java/net/halbear/aotg/custom/blocks/{ => AlloyFurnace}/AlloyFurnaceMultiBlock.java (66%) rename src/main/java/net/halbear/aotg/custom/blocks/{ => AlloyFurnace}/AlloyFurnaceUpdateHandler.java (53%) create mode 100644 src/main/java/net/halbear/aotg/registries/ModMenus.java create mode 100644 src/main/java/net/halbear/aotg/registries/ModScreens.java create mode 100644 src/main/java/net/halbear/aotg/utility/Networking/MenuStateUpdate.java create mode 100644 src/main/java/net/halbear/aotg/utility/ServerModEventHandler.java create mode 100644 src/main/resources/assets/ageofthegods/textures/screens/example_gui.png diff --git a/src/main/java/net/halbear/aotg/AgeoftheGods.java b/src/main/java/net/halbear/aotg/AgeoftheGods.java index 5532ff7..facdac8 100644 --- a/src/main/java/net/halbear/aotg/AgeoftheGods.java +++ b/src/main/java/net/halbear/aotg/AgeoftheGods.java @@ -1,12 +1,17 @@ package net.halbear.aotg; import net.halbear.aotg.registries.ModBiomes; +import net.halbear.aotg.registries.ModMenus; import net.halbear.aotg.utility.DataGenerators.AgeOfTheGodsDataGeneration; import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.levelgen.WorldGenSettings; import net.neoforged.bus.api.Event; +import net.neoforged.neoforge.network.handling.IPayloadHandler; import org.slf4j.Logger; import com.mojang.logging.LogUtils; @@ -38,6 +43,9 @@ import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredItem; import net.neoforged.neoforge.registries.DeferredRegister; +import java.util.HashMap; +import java.util.Map; + import static net.halbear.aotg.registries.ModBlockEntities.BLOCK_ENTITY_TYPES; import static net.halbear.aotg.registries.ModBlocks.*; import static net.halbear.aotg.registries.ModFoliagePlacers.FOLIAGE_PLACERS; @@ -78,6 +86,7 @@ public class AgeoftheGods { // Register the Deferred Register to the mod event bus so blocks get registered BLOCKS.register(modEventBus); BLOCK_ENTITY_TYPES.register(modEventBus); + ModMenus.MENUS.register(modEventBus); // Register the Deferred Register to the mod event bus so items get registered ITEMS.register(modEventBus); // Register the Deferred Register to the mod event bus so tabs get registered @@ -122,4 +131,18 @@ public class AgeoftheGods { // Do something when the server starts LOGGER.info("HELLO from server starting"); } + + private static boolean networkingRegistered = false; + private static final Map, NetworkMessage> MESSAGES = new HashMap<>(); + + private record NetworkMessage(StreamCodec reader, IPayloadHandler handler) { + } + + public static void addNetworkMessage(CustomPacketPayload.Type id, StreamCodec reader, IPayloadHandler handler) { + if (networkingRegistered) + throw new IllegalStateException("Cannot register new network messages after networking has been registered"); + MESSAGES.put(id, new NetworkMessage<>(reader, handler)); + } + + } diff --git a/src/main/java/net/halbear/aotg/custom/GuiScreens/AlloyFurnaceGUIScreen.java b/src/main/java/net/halbear/aotg/custom/GuiScreens/AlloyFurnaceGUIScreen.java new file mode 100644 index 0000000..8e24ace --- /dev/null +++ b/src/main/java/net/halbear/aotg/custom/GuiScreens/AlloyFurnaceGUIScreen.java @@ -0,0 +1,66 @@ +package net.halbear.aotg.custom.GuiScreens; + +import com.mojang.blaze3d.platform.InputConstants; +import net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceGUI; +import net.halbear.aotg.registries.ModScreens; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; + +public class AlloyFurnaceGUIScreen extends AbstractContainerScreen implements ModScreens.ScreenAccessor { + private final Level world; + private final int x, y, z; + private final Player entity; + private boolean menuStateUpdateActive = false; + private static final Identifier BACKGROUND = Identifier.parse("ageofthegods:textures/screens/example_gui.png"); + + public AlloyFurnaceGUIScreen(AlloyFurnaceGUI container, Inventory inventory, Component text) { + super(container, inventory, text, 176, 166); + this.world = container.world; + this.x = container.x; + this.y = container.y; + this.z = container.z; + this.entity = container.entity; + } + + @Override + public void updateMenuState(int elementType, String name, Object elementState) { + menuStateUpdateActive = false; + } + + @Override + public void extractRenderState(GuiGraphicsExtractor guiGraphics, int mouseX, int mouseY, float partialTicks) { + super.extractRenderState(guiGraphics, mouseX, mouseY, partialTicks); + } + + @Override + public void extractBackground(GuiGraphicsExtractor guiGraphics, int mouseX, int mouseY, float partialTicks) { + super.extractBackground(guiGraphics, mouseX, mouseY, partialTicks); + guiGraphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, this.leftPos, this.topPos, 0, 0, this.imageWidth, this.imageHeight, this.imageWidth, this.imageHeight); + } + + @Override + public boolean keyPressed(KeyEvent event) { + int key = InputConstants.getKey(event).getValue(); + if (key == 256) { + this.minecraft.player.closeContainer(); + return true; + } + return super.keyPressed(event); + } + + @Override + protected void extractLabels(GuiGraphicsExtractor guiGraphics, int mouseX, int mouseY) { + } + + @Override + public void init() { + super.init(); + } +} diff --git a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceBlockEntity.java b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceBlockEntity.java similarity index 54% rename from src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceBlockEntity.java rename to src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceBlockEntity.java index 7c282eb..4b73c01 100644 --- a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceBlockEntity.java +++ b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceBlockEntity.java @@ -1,30 +1,43 @@ -package net.halbear.aotg.custom.blocks; +package net.halbear.aotg.custom.blocks.AlloyFurnace; import net.halbear.aotg.registries.ModBlocks; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.HolderLookup; +import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; +import net.neoforged.neoforge.transfer.ResourceHandler; +import net.neoforged.neoforge.transfer.StacksResourceHandler; +import net.neoforged.neoforge.transfer.item.ItemResource; +import net.neoforged.neoforge.transfer.item.ItemStacksResourceHandler; +import org.jspecify.annotations.Nullable; -import static net.halbear.aotg.custom.blocks.AlloyFurnaceMultiBlock.MULTI_BLOCK_POSITIONS; -import static net.halbear.aotg.custom.blocks.AlloyFurnaceMultiBlock.FACING; -import static net.halbear.aotg.custom.blocks.AlloyFurnaceUpdateHandler.getInverseRotationForDirection; +import static net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceMultiBlock.*; +import static net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceUpdateHandler.getInverseRotationForDirection; import static net.halbear.aotg.registries.ModBlockEntities.ALLOY_FURNACE_BLOCK_ENTITY; -public class AlloyFurnaceBlockEntity extends BlockEntity { +public class AlloyFurnaceBlockEntity extends BlockEntity implements MenuProvider { + private boolean isFormed = false; private float Fuel = 0.0f; private int progress = 0; + private final NonNullList items = NonNullList.withSize(2, ItemStack.EMPTY); public AlloyFurnaceBlockEntity(BlockPos worldPosition, BlockState blockState) { super(ALLOY_FURNACE_BLOCK_ENTITY.get(), worldPosition, blockState); @@ -45,6 +58,19 @@ public class AlloyFurnaceBlockEntity extends BlockEntity { Complete = false; } } + if(Complete){ + for (BlockPos offset : MULTI_BLOCK_POSITIONS) { + int Part = AlloyFurnaceUpdateHandler.GetModelPart(offset); + BlockPos Rotated = offset.rotate(rotation); + BlockPos targetPos = masterPos.offset(Rotated); + BlockState state = level.getBlockState(targetPos); + if(state.getValue(PARENT_BLOCK) && !(offset.getX() == 0 && offset.getY() == 0 && offset.getZ() == 0)) state = state.setValue(AlloyFurnaceMultiBlock.PARENT_BLOCK,false); + if(state.getValue(MODEL_PART) != Part) state = state.setValue(AlloyFurnaceMultiBlock.MODEL_PART,Part); + if(state.getValue(FACING) != direction) state = state.setValue(FACING,direction); + level.setBlockAndUpdate(targetPos,state); + } + + } return Complete; } @@ -94,4 +120,26 @@ public class AlloyFurnaceBlockEntity extends BlockEntity { public void onDataPacket(Connection connection, ValueInput input) { super.onDataPacket(connection, input); } + + @Override + public Component getDisplayName() { + return Component.translatable("container.ageofthegods.alloy_furnace"); + } + + @Override + public @Nullable AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) { + return null; + } + + private final StacksResourceHandler resourceHandler = new ItemStacksResourceHandler(this.items) { + @Override + protected void onContentsChanged(int index, ItemStack stack) { + super.onContentsChanged(index, stack); + setChanged(); + } + }; + + public StacksResourceHandler getResourceHandler() { + return this.resourceHandler; + } } diff --git a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceGUI.java b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceGUI.java new file mode 100644 index 0000000..6d265cf --- /dev/null +++ b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceGUI.java @@ -0,0 +1,266 @@ +package net.halbear.aotg.custom.blocks.AlloyFurnace; + +import net.halbear.aotg.registries.ModBlocks; +import net.halbear.aotg.registries.ModMenus; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.entity.Entity; +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.ContainerLevelAccess; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.transfer.IndexModifier; +import net.neoforged.neoforge.transfer.ResourceHandler; +import net.neoforged.neoforge.transfer.StacksResourceHandler; +import net.neoforged.neoforge.transfer.access.ItemAccess; +import net.neoforged.neoforge.transfer.item.*; +import net.neoforged.neoforge.transfer.transaction.Transaction; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class AlloyFurnaceGUI extends AbstractContainerMenu implements ModMenus.MenuAccessor { + public final Map menuState = new HashMap<>() { + @Override + public Object put(String key, Object value) { + if (!this.containsKey(key) && this.size() >= 4) + return null; + return super.put(key, value); + } + }; + public final Level world; + public final Player entity; + public int x, y, z; + private ContainerLevelAccess access = ContainerLevelAccess.NULL; + private ResourceHandler internal; + private final Map customSlots = new HashMap<>(); + private boolean bound = false; + private Supplier boundItemMatcher = null; + private Entity boundEntity = null; + private BlockEntity boundBlockEntity = null; + + + public AlloyFurnaceGUI(int containerId, Inventory playerInv, FriendlyByteBuf buffer) { + super(ModMenus.ALLOY_FURNACE_GUI.get(), containerId); + this.entity = playerInv.player; + this.world = playerInv.player.level(); + this.internal = new ItemStacksResourceHandler(4); + + BlockPos pos = null; + if (buffer != null) { + pos = buffer.readBlockPos(); + this.x = pos.getX(); + this.y = pos.getY(); + this.z = pos.getZ(); + access = ContainerLevelAccess.create(world, pos); + } + + if (pos != null) { + boundBlockEntity = this.world.getBlockEntity(pos); + if (boundBlockEntity instanceof BaseContainerBlockEntity baseContainerBlockEntity) { + this.internal = VanillaContainerWrapper.of(baseContainerBlockEntity); + this.bound = true; + } + } + this.customSlots.put(0, this.addSlot(new ResourceHandlerSlot(internal, this::setItemInSlot, 0, 42, 41) { + private final int slot = 0; + private int x = this.x; + private int y = this.y; + })); + this.customSlots.put(1, this.addSlot(new ResourceHandlerSlot(internal, this::setItemInSlot, 1, 21, 40) { + private final int slot = 1; + private int x = this.x; + private int y = this.y; + })); + this.customSlots.put(2, this.addSlot(new ResourceHandlerSlot(internal, this::setItemInSlot, 2, 63, 41) { + private final int slot = 2; + private int x = this.x; + private int y = this.y; + })); + this.customSlots.put(3, this.addSlot(new ResourceHandlerSlot(internal, this::setItemInSlot, 3, 129, 41) { + private final int slot = 3; + private int x = this.x; + private int y = this.y; + + @Override + public boolean mayPlace(ItemStack stack) { + return false; + } + })); + + + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 9; ++col) { + this.addSlot(new Slot(playerInv, col + row * 9 + 9, 8 + col * 18, 84 + row * 18)); + } + } + + for (int col = 0; col < 9; ++col) { + this.addSlot(new Slot(playerInv, col, 8 + col * 18, 142)); + } + } + + private void setItemInSlot(int index, ItemResource resource, int amount) { + if (internal instanceof ItemStacksResourceHandler handler) { + handler.set(index, resource, amount); + } else if (boundBlockEntity instanceof Container container) { + container.setItem(index, resource.toStack(Math.max(0, amount))); + } else { + try (var tx = Transaction.openRoot()) { + if (!internal.getResource(index).isEmpty()) + internal.extract(index, internal.getResource(index), internal.getAmountAsInt(index), tx); + if (!resource.isEmpty() && amount > 0) + internal.insert(index, resource, amount, tx); + tx.commit(); + } + } + } + + + + + @Override + public boolean stillValid(Player player) { + if (this.bound) { + if (this.boundItemMatcher != null) + return this.boundItemMatcher.get(); + else if (this.boundBlockEntity != null) + return AbstractContainerMenu.stillValid(this.access, player, this.boundBlockEntity.getBlockState().getBlock()); + else if (this.boundEntity != null) + return this.boundEntity.isAlive(); + } + return true; + } + + @Override + public ItemStack quickMoveStack(Player playerIn, int index) { + ItemStack itemstack = ItemStack.EMPTY; + Slot slot = this.slots.get(index); + if (slot != null && slot.hasItem()) { + ItemStack itemstack1 = slot.getItem(); + itemstack = itemstack1.copy(); + if (index < 4) { + if (!this.moveItemStackTo(itemstack1, 4, this.slots.size(), true)) + return ItemStack.EMPTY; + slot.onQuickCraft(itemstack1, itemstack); + } else if (!this.moveItemStackTo(itemstack1, 0, 4, false)) { + if (index < 4 + 27) { + if (!this.moveItemStackTo(itemstack1, 4 + 27, this.slots.size(), true)) + return ItemStack.EMPTY; + } else { + if (!this.moveItemStackTo(itemstack1, 4, 4 + 27, false)) + return ItemStack.EMPTY; + } + return ItemStack.EMPTY; + } + if (itemstack1.isEmpty()) { + slot.setByPlayer(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + if (itemstack1.getCount() == itemstack.getCount()) { + return ItemStack.EMPTY; + } + slot.onTake(playerIn, itemstack1); + } + return itemstack; + } + + @Override + protected boolean moveItemStackTo(ItemStack itemStack, int startSlot, int endSlot, boolean backwards) { + boolean anythingChanged = false; + int destSlot = startSlot; + if (backwards) { + destSlot = endSlot - 1; + } + if (itemStack.isStackable()) { + while (!itemStack.isEmpty() && (backwards ? destSlot >= startSlot : destSlot < endSlot)) { + Slot slot = this.slots.get(destSlot); + ItemStack target = slot.getItem(); + if (slot.mayPlace(target) && !target.isEmpty() && ItemStack.isSameItemSameComponents(itemStack, target)) { + int totalStack = target.getCount() + itemStack.getCount(); + int maxStackSize = slot.getMaxStackSize(target); + if (totalStack <= maxStackSize) { + itemStack.setCount(0); + target.setCount(totalStack); + slot.set(target); + anythingChanged = true; + } else if (target.getCount() < maxStackSize) { + itemStack.shrink(maxStackSize - target.getCount()); + target.setCount(maxStackSize); + slot.set(target); + anythingChanged = true; + } + } + if (backwards) { + destSlot--; + } else { + destSlot++; + } + } + } + if (!itemStack.isEmpty()) { + if (backwards) { + destSlot = endSlot - 1; + } else { + destSlot = startSlot; + } + while (backwards ? destSlot >= startSlot : destSlot < endSlot) { + Slot slotx = this.slots.get(destSlot); + ItemStack targetx = slotx.getItem(); + if (targetx.isEmpty() && slotx.mayPlace(itemStack)) { + int maxStackSize = slotx.getMaxStackSize(itemStack); + slotx.setByPlayer(itemStack.split(Math.min(itemStack.getCount(), maxStackSize))); + slotx.setChanged(); + anythingChanged = true; + break; + } + if (backwards) { + destSlot--; + } else { + destSlot++; + } + } + } + return anythingChanged; + } + + @Override + public void removed(Player playerIn) { + super.removed(playerIn); + if (!bound && playerIn instanceof ServerPlayer serverPlayer) { + if (!serverPlayer.isAlive() || serverPlayer.hasDisconnected()) { + for (int j = 0; j < internal.size(); ++j) { + playerIn.drop(ItemUtil.getStack(internal, j), false); + setItemInSlot(j, ItemResource.EMPTY, 0); + } + } else { + for (int i = 0; i < internal.size(); ++i) { + playerIn.getInventory().placeItemBackInInventory(ItemUtil.getStack(internal, i)); + setItemInSlot(i, ItemResource.EMPTY, 0); + } + } + } + } + + @Override + public Map getSlots() { + return Collections.unmodifiableMap(customSlots); + } + + @Override + public Map getMenuState() { + return menuState; + } + +} diff --git a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceMultiBlock.java b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceMultiBlock.java similarity index 66% rename from src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceMultiBlock.java rename to src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceMultiBlock.java index 4c3d2d2..57208d5 100644 --- a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceMultiBlock.java +++ b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceMultiBlock.java @@ -1,17 +1,23 @@ -package net.halbear.aotg.custom.blocks; +package net.halbear.aotg.custom.blocks.AlloyFurnace; -import com.mojang.serialization.MapCodec; +import io.netty.buffer.Unpooled; import net.halbear.aotg.AgeoftheGods; import net.halbear.aotg.registries.ModBlocks; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.TriState; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Containers; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.Rotation; @@ -24,9 +30,10 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.phys.BlockHitResult; import org.jspecify.annotations.Nullable; -import static net.halbear.aotg.custom.blocks.AlloyFurnaceUpdateHandler.getInverseRotationForDirection; +import static net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceUpdateHandler.getInverseRotationForDirection; import static net.halbear.aotg.registries.ModBlockEntities.ALLOY_FURNACE_BLOCK_ENTITY; public class AlloyFurnaceMultiBlock extends Block implements EntityBlock { @@ -74,24 +81,46 @@ public class AlloyFurnaceMultiBlock extends Block implements EntityBlock { for(int x = -1; x < 2; x++){ for(int z = -1; z < 2; z++){ for(int y = -1; y < 2; y++){ + if(x == 0 && y == 0 && z == 0) continue; //skip if it is the block we're checking to place + /*check 3x3x3 area + and assign a BlockPos, and BlockState to the block at each offset*/ BlockPos parentPos = position.offset(x,y,z); BlockState state = level.getBlockState(parentPos); if(state.is(ModBlocks.ALLOY_FURNACE.get()) && state.getValue(PARENT_BLOCK)) { - AgeoftheGods.LOGGER.debug("LOCATED PARENT BLOCK AT: " + parentPos); + //make sure the block matches, and that it has the "PARENT_BLOCK" boolean set to true, this means it is the parent block Direction direction = state.getValue(FACING); + //get direction of parent block and then flip it to get the rotation Rotation rotation = getInverseRotationForDirection(direction); - AgeoftheGods.LOGGER.debug("Placed Next to PARENT_BLOCK"); for (BlockPos offset : MULTI_BLOCK_POSITIONS) { + //iterate through the child block positions BlockPos Rotated = offset.rotate(rotation); + //rotate the child block position to face the direction of the parent block BlockPos targetPos = parentPos.offset(Rotated); - AgeoftheGods.LOGGER.debug("TARGET_POS: " + targetPos + " | CURRENT_POS: " + position + " | ROTATION: " + Rotated); + //get the World Position of the child block and check if it matches the block we want to place if (targetPos.getX() == position.getX() && targetPos.getY() == position.getY() && targetPos.getZ() == position.getZ()) { + //if it matches, the block we're placing is a child block, so set its parent value to false and its direction to the parent blockState = blockState.setValue(PARENT_BLOCK, false); blockState = blockState.setValue(FACING, direction); - String PosString = Math.abs(offset.getX()) + "_" + Math.abs(offset.getY()) + "_" + Math.abs(offset.getZ()); - AgeoftheGods.LOGGER.debug("POS_STRING: " + PosString); - switch (PosString) { + //get an absolute value of the original child offset before rotating it + BlockPos purePos = new BlockPos(Math.abs(offset.getX()) , Math.abs(offset.getY()),Math.abs(offset.getZ())); + //set the model part to whatever value gets cross-matched when looking up offset positions in a Map containing the position and the respective model value + blockState = blockState.setValue(MODEL_PART, Math.max(AlloyFurnaceUpdateHandler.GetModelPart(purePos), 0)); + return blockState; + } + } + } + } + } + } + + if (blockState.getValue(PARENT_BLOCK)) AgeoftheGods.LOGGER.debug("becoming PARENT_BLOCK"); + return blockState; + } + //old case switch hard code + /*// AgeoftheGods.LOGGER.debug("POS_STRING: " + PosString); + String PosString = Math.abs(offset.getX()) + "_" + Math.abs(offset.getY()) + "_" + Math.abs(offset.getZ()); + switch (PosString) { case "0_0_0": blockState = blockState.setValue(PARENT_BLOCK, true); blockState = blockState.setValue(MODEL_PART, 0); @@ -117,17 +146,7 @@ public class AlloyFurnaceMultiBlock extends Block implements EntityBlock { case "0_1_1": blockState = blockState.setValue(MODEL_PART, 7); break; - } - } - } - } - } - } - } - - if (blockState.getValue(PARENT_BLOCK)) AgeoftheGods.LOGGER.debug("becoming PARENT_BLOCK"); - return blockState; - } + }*/ @Override protected void createBlockStateDefinition(StateDefinition.Builder builder){ @@ -136,6 +155,26 @@ public class AlloyFurnaceMultiBlock extends Block implements EntityBlock { builder.add(PARENT_BLOCK); } + @Override + public InteractionResult useWithoutItem(BlockState blockstate, Level world, BlockPos pos, Player entity, BlockHitResult hit) { + super.useWithoutItem(blockstate, world, pos, entity, hit); + if (entity instanceof ServerPlayer player) { + player.openMenu(new MenuProvider() { + @Override + public Component getDisplayName() { + return Component.literal("Sigma"); + } + + @Override + public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) { + return new AlloyFurnaceGUI(id, inventory, new FriendlyByteBuf(Unpooled.buffer()).writeBlockPos(pos)); + } + }, pos); + } + return InteractionResult.SUCCESS; + } + + @Override public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { return new AlloyFurnaceBlockEntity(blockPos,blockState); diff --git a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceUpdateHandler.java b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceUpdateHandler.java similarity index 53% rename from src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceUpdateHandler.java rename to src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceUpdateHandler.java index 107861d..191b023 100644 --- a/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnaceUpdateHandler.java +++ b/src/main/java/net/halbear/aotg/custom/blocks/AlloyFurnace/AlloyFurnaceUpdateHandler.java @@ -1,18 +1,22 @@ -package net.halbear.aotg.custom.blocks; +package net.halbear.aotg.custom.blocks.AlloyFurnace; import net.halbear.aotg.AgeoftheGods; -import net.halbear.aotg.registries.ModBlocks; +import net.halbear.aotg.registries.ModItems; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.ItemContainerContents; +import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.TestBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.level.BlockEvent; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @EventBusSubscriber(modid = AgeoftheGods.MODID) public class AlloyFurnaceUpdateHandler { @@ -20,6 +24,31 @@ public class AlloyFurnaceUpdateHandler { public static final BlockPos[] parts = new BlockPos[]{new BlockPos(0,0,0),new BlockPos(-1,0,0),new BlockPos(-1,0,1),new BlockPos(0,0,1), new BlockPos(0,1,0),new BlockPos(-1,1,0),new BlockPos(-1,1,1),new BlockPos(0,1,1)}; + public static final Map ModelPartLookup = new HashMap<>(); + + static{ + for(int i = 0; i < 8; i++) { + String PosString = Math.abs(parts[i].getX()) + "_" + Math.abs(parts[i].getY()) + "_" + Math.abs(parts[i].getZ()); + ModelPartLookup.put(PosString, i); + } + } + + public static int GetModelPart(BlockPos MultipartLocation){ + String PosString = Math.abs(MultipartLocation.getX()) + "_" + Math.abs(MultipartLocation.getY()) + "_" + Math.abs(MultipartLocation.getZ()); + return ModelPartLookup.get(PosString); + } + + + protected ItemStack CreateFilledPot(Item ItemToFillWith, int StackSize){ + ItemStack potStack = new ItemStack(Items.DECORATED_POT); + ItemStack newContents = new ItemStack(ItemToFillWith,StackSize); + ItemStack liquidMarker = new ItemStack(ModItems.FLUID_INDICATOR_ITEM.asItem(),1); + ItemContainerContents contents = ItemContainerContents.fromItems(List.of(liquidMarker, newContents)); + potStack.set(DataComponents.CONTAINER, contents); + return potStack; + } + + //@SubscribeEvent public static void onNeighborNotify(BlockEvent.NeighborNotifyEvent event) { var level = event.getLevel(); @@ -36,15 +65,6 @@ public class AlloyFurnaceUpdateHandler { var state = event.getPlacedBlock(); } - public static int GetModelPart(BlockPos MultipartLocation){ - for(int i = 0; i < 8; i++){ - if(MultipartLocation.getX() == parts[i].getX() && MultipartLocation.getZ() == parts[i].getZ() && MultipartLocation.getY() == parts[i].getY()){ - return i; - } - } - return -1; - } - public static BlockPos GetMultipartLocation(int ModelPart){ return parts[Math.clamp(ModelPart,0,7)]; } diff --git a/src/main/java/net/halbear/aotg/registries/ModBlockEntities.java b/src/main/java/net/halbear/aotg/registries/ModBlockEntities.java index 7a4e653..709129e 100644 --- a/src/main/java/net/halbear/aotg/registries/ModBlockEntities.java +++ b/src/main/java/net/halbear/aotg/registries/ModBlockEntities.java @@ -1,19 +1,11 @@ package net.halbear.aotg.registries; import net.halbear.aotg.AgeoftheGods; -import net.halbear.aotg.custom.blocks.AlloyFurnaceBlockEntity; -import net.minecraft.core.registries.BuiltInRegistries; +import net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceBlockEntity; import net.minecraft.core.registries.Registries; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.neoforged.neoforge.registries.DeferredBlock; -import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; -import org.intellij.lang.annotations.Identifier; -import java.util.function.Function; import java.util.function.Supplier; public class ModBlockEntities { diff --git a/src/main/java/net/halbear/aotg/registries/ModBlocks.java b/src/main/java/net/halbear/aotg/registries/ModBlocks.java index 61a39f1..1998b8c 100644 --- a/src/main/java/net/halbear/aotg/registries/ModBlocks.java +++ b/src/main/java/net/halbear/aotg/registries/ModBlocks.java @@ -1,14 +1,10 @@ package net.halbear.aotg.registries; import net.halbear.aotg.AgeoftheGods; -import net.halbear.aotg.custom.blocks.AlloyFurnaceMultiBlock; +import net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceMultiBlock; import net.halbear.aotg.custom.blocks.RockCoveredGrassBlock; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.RotatedPillarBlock; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockBehaviour; diff --git a/src/main/java/net/halbear/aotg/registries/ModItems.java b/src/main/java/net/halbear/aotg/registries/ModItems.java index 8908794..3da5978 100644 --- a/src/main/java/net/halbear/aotg/registries/ModItems.java +++ b/src/main/java/net/halbear/aotg/registries/ModItems.java @@ -24,6 +24,10 @@ public class ModItems { public static final DeferredItem OLIVE_LOG_ITEM = ITEMS.registerSimpleBlockItem("olive_log", OLIVE_LOG); public static final DeferredItem ALLOY_FURNACE_ITEM = ITEMS.registerSimpleBlockItem("alloy_furnace", ALLOY_FURNACE); + public static final DeferredItem FLUID_INDICATOR_ITEM = RegisterItem("fluid_indicator_debug_item", properties -> new Item(properties + .fireResistant() + )); + public static final DeferredItem XIPHOS_SWORD = RegisterItem("xiphos", properties -> new Item(properties .tool(ModTiers.SWORD_TIER, diff --git a/src/main/java/net/halbear/aotg/registries/ModMenus.java b/src/main/java/net/halbear/aotg/registries/ModMenus.java new file mode 100644 index 0000000..30e45af --- /dev/null +++ b/src/main/java/net/halbear/aotg/registries/ModMenus.java @@ -0,0 +1,54 @@ +package net.halbear.aotg.registries; + +import net.halbear.aotg.AgeoftheGods; +import net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceGUI; +import net.halbear.aotg.utility.Networking.MenuStateUpdate; +import net.minecraft.client.Minecraft; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.neoforged.neoforge.client.network.ClientPacketDistributor; +import net.neoforged.neoforge.common.extensions.IMenuTypeExtension; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +import java.util.Map; + +public class ModMenus { + public static DeferredRegister> MENUS = + DeferredRegister.create(BuiltInRegistries.MENU, AgeoftheGods.MODID); + + public static final DeferredHolder, MenuType> ALLOY_FURNACE_GUI = + MENUS.register("alloy_furnace_gui", () -> IMenuTypeExtension.create(AlloyFurnaceGUI::new)); + + + public interface MenuAccessor { + Map getMenuState(); + + Map getSlots(); + + default void sendMenuStateUpdate(Player player, int elementType, String name, Object elementState, boolean needClientUpdate) { + getMenuState().put(elementType + ":" + name, elementState); + if (player instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new MenuStateUpdate(elementType, name, elementState)); + } else if (player.level().isClientSide()) { + if (Minecraft.getInstance().screen instanceof ModScreens.ScreenAccessor accessor && needClientUpdate) + accessor.updateMenuState(elementType, name, elementState); + ClientPacketDistributor.sendToServer(new MenuStateUpdate(elementType, name, elementState)); + } + } + + default T getMenuState(int elementType, String name, T defaultValue) { + try { + return (T) getMenuState().getOrDefault(elementType + ":" + name, defaultValue); + } catch (ClassCastException e) { + return defaultValue; + } + } + } + + +} diff --git a/src/main/java/net/halbear/aotg/registries/ModScreens.java b/src/main/java/net/halbear/aotg/registries/ModScreens.java new file mode 100644 index 0000000..4a3a173 --- /dev/null +++ b/src/main/java/net/halbear/aotg/registries/ModScreens.java @@ -0,0 +1,21 @@ +package net.halbear.aotg.registries; + +import net.halbear.aotg.custom.GuiScreens.AlloyFurnaceGUIScreen; +import net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceGUI; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent; + +@EventBusSubscriber(Dist.CLIENT) +public class ModScreens { + @SubscribeEvent + public static void clientLoad(RegisterMenuScreensEvent event) { + event.register(ModMenus.ALLOY_FURNACE_GUI.get(), AlloyFurnaceGUIScreen::new); + } + + public interface ScreenAccessor { + void updateMenuState(int elementType, String name, Object elementState); + } + +} diff --git a/src/main/java/net/halbear/aotg/utility/Networking/MenuStateUpdate.java b/src/main/java/net/halbear/aotg/utility/Networking/MenuStateUpdate.java new file mode 100644 index 0000000..ce7fb6c --- /dev/null +++ b/src/main/java/net/halbear/aotg/utility/Networking/MenuStateUpdate.java @@ -0,0 +1,75 @@ +package net.halbear.aotg.utility.Networking; + +import net.halbear.aotg.AgeoftheGods; +import net.halbear.aotg.registries.ModMenus; +import net.halbear.aotg.registries.ModScreens; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.Identifier; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +@EventBusSubscriber +public record MenuStateUpdate(int elementType, String name, Object elementState) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "menustate_update")); + public static final StreamCodec STREAM_CODEC = StreamCodec.of(MenuStateUpdate::write, MenuStateUpdate::read); + + public static void write(FriendlyByteBuf buffer, MenuStateUpdate message) { + buffer.writeInt(message.elementType); + buffer.writeUtf(message.name); + if (message.elementType == 0) { + buffer.writeUtf((String) message.elementState); + } else if (message.elementType == 1) { + buffer.writeBoolean((boolean) message.elementState); + } else if (message.elementType == 2 && message.elementState instanceof Number n) { + buffer.writeDouble(n.doubleValue()); + } + } + + public static MenuStateUpdate read(FriendlyByteBuf buffer) { + int elementType = buffer.readInt(); + String name = buffer.readUtf(); + Object elementState = null; + if (elementType == 0) { + elementState = buffer.readUtf(); + } else if (elementType == 1) { + elementState = buffer.readBoolean(); + } else if (elementType == 2) { + elementState = buffer.readDouble(); + } + return new MenuStateUpdate(elementType, name, elementState); + } + + @Override + public Type type() { + return TYPE; + } + + public static void handleMenuState(final MenuStateUpdate message, final IPayloadContext context) { + if (message.name.length() > 256 || message.elementState instanceof String string && string.length() > 8192) + return; + context.enqueueWork(() -> { + if (context.player().containerMenu instanceof ModMenus.MenuAccessor menu) { + menu.getMenuState().put(message.elementType + ":" + message.name, message.elementState); + if (context.flow() == PacketFlow.CLIENTBOUND && Minecraft.getInstance().screen instanceof ModScreens.ScreenAccessor accessor) { + accessor.updateMenuState(message.elementType, message.name, message.elementState); + } + } + }).exceptionally(e -> { + context.connection().disconnect(Component.literal(e.getMessage())); + return null; + }); + } + + @SubscribeEvent + public static void registerMessage(FMLCommonSetupEvent event) { + AgeoftheGods.addNetworkMessage(MenuStateUpdate.TYPE, MenuStateUpdate.STREAM_CODEC, MenuStateUpdate::handleMenuState); + } +} \ No newline at end of file diff --git a/src/main/java/net/halbear/aotg/utility/ServerModEventHandler.java b/src/main/java/net/halbear/aotg/utility/ServerModEventHandler.java new file mode 100644 index 0000000..bc2ad47 --- /dev/null +++ b/src/main/java/net/halbear/aotg/utility/ServerModEventHandler.java @@ -0,0 +1,46 @@ +package net.halbear.aotg.utility; + +import net.halbear.aotg.AgeoftheGods; +import net.halbear.aotg.registries.ModItems; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.ItemContainerContents; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.DecoratedPotBlockEntity; +import net.minecraft.world.level.material.Fluids; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.level.BlockEvent; + +@EventBusSubscriber(modid = AgeoftheGods.MODID) +public class ServerModEventHandler { + @SubscribeEvent + public static void OnAlloyPotDestroy(BlockEvent.BreakEvent event){ + if (!(event.getLevel() instanceof Level level)) return; + if (level.isClientSide()) return; + + BlockPos pos = event.getPos(); + BlockEntity blockEntity = level.getBlockEntity(pos); + + if (blockEntity instanceof DecoratedPotBlockEntity potEntity) { + ItemContainerContents contents = potEntity.getContainerBlockEntity().components().get(DataComponents.CONTAINER); + + if (contents != null) { + boolean hasMarker = contents.getStackInSlot(0).is(ModItems.FLUID_INDICATOR_ITEM.asItem()); + + if (hasMarker) { + potEntity.getContainerBlockEntity().setRemoved(); + potEntity.setChanged(); + level.setBlock(pos, Fluids.WATER.defaultFluidState().createLegacyBlock(), 3); + + event.setCanceled(true); + } + } + } + } +} diff --git a/src/main/resources/assets/ageofthegods/textures/screens/example_gui.png b/src/main/resources/assets/ageofthegods/textures/screens/example_gui.png new file mode 100644 index 0000000000000000000000000000000000000000..a871597bcf83c280fb1b0bfa4884818523e734e3 GIT binary patch literal 1177 zcmeAS@N?(olHy`uVBq!ia0vp^8-REj2OE&AvS7Wzz`&B=>Eakt5%>0PVwQBINXx}H zr?fw=dQ+MjEqN>9SnxBmNo)AFw|#!_XQGdwy`7{`%G2xX>(9$;e0=+-aL%;iFIsWS zzy105_qV-ZeYKETb#3k650V=zRw^Z|;+&Div}{(xN;T>;r?dU}^yyRb`}gnfmp#1v zlyU#wy?;IaMH+o@f6}cqzuqO!?9}_0g7v@Uw3yGW-+BH1jhrhL{7m~YHU~bo<@mAa ztXuDQg$Lbc(x&&C8}x5cQ?elQ!0~G5`Gx!P;tEfO=a^;fY4>K{cSuyfOB-aJbL@c+ zQz;ITTW1;N<*mO2A6MW1B)NY>@w@+fCdb|rEvVzWwzn@iJ?;6O!cE?cw6KNz6m-|<|bWEb;(c98s>k!KjD_8ec3txvdZEE$F*N9pZD|JpPDy< zW#>T7c+X`~zvTXFi?Xz`bF#E{4w^6X`F=#cU$MQo?#-O}Z-7qi55M4V`+4rqpEs1> z%(=Y-9CZIY_Fpf2bLPz)Yrith1nb4U);E_nyzMc2molAcoAE86BCZ?fG9FW3@}A6x z&G!QHpZ~dGX@B$SS;oU|uuOAT=EKMBC+1f@%U}Ks6w7%)+bhEl{5&u9-KuZy%(=zK z=@h%r;5x$av2R750imzopr09Bkvy#N3J literal 0 HcmV?d00001