diff --git a/build.gradle b/build.gradle index 7a1952036..d4bdbba01 100644 --- a/build.gradle +++ b/build.gradle @@ -218,6 +218,13 @@ dependencies { implementation "mekanism:Mekanism:1.21.1-10.7.4.60:api" implementation "curse.maven:spark-361579:5759671" // spark-1.10.109-neoforge.jar + + implementation "curse.maven:cloth-config-348521:5729127" // cloth-config-15.0.140-neoforge.jar + implementation "curse.maven:powah-rearchitected-633483:5735677" // Powah-6.1.2.jar + + implementation "curse.maven:sophisticated-core-618298:5810072" // sophisticatedcore-1.21-0.6.45.722.jar + implementation "curse.maven:sophisticated-backpacks-422301:5787622" // sophisticatedbackpacks-1.21-3.20.17.1113.jar + implementation "curse.maven:sophisticated-storage-619320:5801696" // sophisticatedstorage-1.21-0.10.45.910.jar } // This block of code expands all declared replace properties in the specified resource targets. diff --git a/src/main/java/ca/teamdman/sfm/client/gui/screen/ProxyScreen.java b/src/main/java/ca/teamdman/sfm/client/gui/screen/ProxyScreen.java new file mode 100644 index 000000000..4bc237554 --- /dev/null +++ b/src/main/java/ca/teamdman/sfm/client/gui/screen/ProxyScreen.java @@ -0,0 +1,44 @@ +package ca.teamdman.sfm.client.gui.screen; + +import ca.teamdman.sfm.SFM; +import ca.teamdman.sfm.common.containermenu.ProxyContainerMenu; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; + +public class ProxyScreen extends AbstractContainerScreen { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath( + SFM.MOD_ID, + "textures/gui/container/proxy.png" + ); + + public ProxyScreen( + ProxyContainerMenu menu, + Inventory inv, + Component title + ) { + super(menu, inv, title); + } + + @Override + protected void init() { + super.init(); + this.imageWidth = 176; + this.imageHeight = 209; + this.topPos /= 2; + this.inventoryLabelY = 80; + } + + @Override + protected void renderBg(GuiGraphics pGuiGraphics, float pPartialTick, int pMouseX, int pMouseY) { + pGuiGraphics.blit(TEXTURE, this.leftPos, this.topPos, 0, 0, this.imageWidth, this.imageHeight); + } + + @Override + public void render(GuiGraphics graphics, int mx, int my, float partialTicks) { + super.render(graphics, mx, my, partialTicks); + this.renderTooltip(graphics, mx, my); + } +} diff --git a/src/main/java/ca/teamdman/sfm/client/registry/SFMMenuScreens.java b/src/main/java/ca/teamdman/sfm/client/registry/SFMMenuScreens.java index 3fa2d9436..ce2f69c1a 100644 --- a/src/main/java/ca/teamdman/sfm/client/registry/SFMMenuScreens.java +++ b/src/main/java/ca/teamdman/sfm/client/registry/SFMMenuScreens.java @@ -2,6 +2,7 @@ import ca.teamdman.sfm.SFM; import ca.teamdman.sfm.client.gui.screen.ManagerScreen; +import ca.teamdman.sfm.client.gui.screen.ProxyScreen; import ca.teamdman.sfm.common.registry.SFMMenus; import net.minecraft.client.gui.screens.MenuScreens; import net.neoforged.bus.api.SubscribeEvent; @@ -13,5 +14,6 @@ public class SFMMenuScreens { @SubscribeEvent public static void register(RegisterMenuScreensEvent event) { event.register(SFMMenus.MANAGER_MENU.get(), ManagerScreen::new); + event.register(SFMMenus.PROXY_MENU.get(), ProxyScreen::new); } } diff --git a/src/main/java/ca/teamdman/sfm/common/block/ProxyBlock.java b/src/main/java/ca/teamdman/sfm/common/block/ProxyBlock.java new file mode 100644 index 000000000..f1065aa40 --- /dev/null +++ b/src/main/java/ca/teamdman/sfm/common/block/ProxyBlock.java @@ -0,0 +1,72 @@ +package ca.teamdman.sfm.common.block; + +import ca.teamdman.sfm.common.blockentity.ProxyBlockEntity; +import ca.teamdman.sfm.common.containermenu.ProxyContainerMenu; +import ca.teamdman.sfm.common.registry.SFMBlockEntities; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.Containers; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.apache.commons.lang3.NotImplementedException; +import org.jetbrains.annotations.Nullable; + +public class ProxyBlock extends BaseEntityBlock implements EntityBlock { + public ProxyBlock() { + super(Properties.of() + .destroyTime(2) + .sound(SoundType.METAL)); + } + + @Override + protected MapCodec codec() { + throw new NotImplementedException("This isn't used until 1.20.5 apparently"); + } + + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) { + return SFMBlockEntities.PROXY_BLOCK_ENTITY.get() + .create(pPos, pState); + } + + @Override + protected InteractionResult useWithoutItem( + BlockState pState, + Level level, + BlockPos pos, + Player player, + BlockHitResult pHitResult + ) { + if (level.getBlockEntity(pos) instanceof ProxyBlockEntity pbe && player instanceof ServerPlayer sp) { + sp.openMenu(pbe, buf -> ProxyContainerMenu.encode(pbe, buf)); + return InteractionResult.CONSUME; + } + return InteractionResult.SUCCESS; + } + + @Override + @SuppressWarnings("deprecation") + public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { + if (!state.is(newState.getBlock())) { + if (level.getBlockEntity(pos) instanceof Container container) { + Containers.dropContents(level, pos, container); + level.updateNeighbourForOutputSignal(pos, this); + } + super.onRemove(state, level, pos, newState, isMoving); + } + } +} diff --git a/src/main/java/ca/teamdman/sfm/common/blockentity/ProxyBlockEntity.java b/src/main/java/ca/teamdman/sfm/common/blockentity/ProxyBlockEntity.java new file mode 100644 index 000000000..7abeb92a0 --- /dev/null +++ b/src/main/java/ca/teamdman/sfm/common/blockentity/ProxyBlockEntity.java @@ -0,0 +1,166 @@ +package ca.teamdman.sfm.common.blockentity; + +import ca.teamdman.sfm.common.containermenu.ProxyContainerMenu; +import ca.teamdman.sfm.common.registry.SFMBlockEntities; +import ca.teamdman.sfm.common.util.SFMContainerUtil; +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.chat.Component; +import net.minecraft.world.ContainerHelper; +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.block.entity.BaseContainerBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.capabilities.BlockCapability; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.capabilities.ItemCapability; +import net.neoforged.neoforge.items.wrapper.InvWrapper; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/* + * https://github.com/CyclopsMC/CapabilityProxy/blob/master-1.21/loader-neoforge/src/main/java/org/cyclops/capabilityproxy/blockentity/BlockEntityItemCapabilityProxyNeoForge.java + */ +public class ProxyBlockEntity extends BaseContainerBlockEntity { + private static final Component TITLE = Component.literal("Item Capability Proxy"); + + public static Map, ItemCapability> BLOCK_TO_ITEM_CAPABILITIES = Map.of(); + + private NonNullList inventory = NonNullList.withSize(4, ItemStack.EMPTY); + + public ProxyBlockEntity(BlockPos pPos, BlockState pBlockState) { + super(SFMBlockEntities.PROXY_BLOCK_ENTITY.get(), pPos, pBlockState); + } + + @Nullable + public static ItemCapability blockCapabilityToItemCapability(BlockCapability capability) { + return (ItemCapability) BLOCK_TO_ITEM_CAPABILITIES.get(capability); + } + + @Override + public void setChanged() { + super.setChanged(); + invalidateCapabilities(); + } + + @Override + protected AbstractContainerMenu createMenu(int windowId, Inventory inventory) { + return new ProxyContainerMenu(windowId, inventory, this); + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Override + protected Component getDefaultName() { + return TITLE; + } + + @Override + protected NonNullList getItems() { + return inventory; + } + + @Override + protected void setItems(NonNullList nonNullList) { + inventory = nonNullList; + } + + @Override + public int getContainerSize() { + return inventory.size(); + } + + @Override + public boolean isEmpty() { + return inventory.isEmpty(); + } + + @Override + public ItemStack getItem(int slotId) { + if (slotId < 0 || slotId >= getContainerSize()) return ItemStack.EMPTY; + return inventory.get(slotId); + } + + @Override + public ItemStack removeItem(int slotId, int amount) { + ItemStack result = ContainerHelper.removeItem(inventory, slotId, amount); + setChanged(); + return result; + } + + @Override + public ItemStack removeItemNoUpdate(int slotId) { + ItemStack result = ContainerHelper.takeItem(inventory, slotId); + setChanged(); + return result; + } + + @Override + public void setItem(int slotId, ItemStack itemStack) { + if (slotId < 0 || slotId >= getContainerSize()) return; + inventory.set(slotId, itemStack); + setChanged(); + } + + @Override + public boolean stillValid(Player player) { + return SFMContainerUtil.stillValid(this, player); + } + + @Override + public void clearContent() { + inventory.clear(); + } + + @Override + protected void saveAdditional(CompoundTag pTag, HolderLookup.Provider pRegistries) { + super.saveAdditional(pTag, pRegistries); + ContainerHelper.saveAllItems(pTag, inventory, pRegistries); + } + + @Override + protected void loadAdditional(CompoundTag pTag, HolderLookup.Provider pRegistries) { + super.loadAdditional(pTag, pRegistries); + ContainerHelper.loadAllItems(pTag, inventory, pRegistries); + } + + @Nullable + public T getCapability(BlockCapability blockCapability, @Nullable C1 context) { + if (!(context instanceof Direction ctx)) { + return null; + } + + if (ctx == Direction.UP | ctx == Direction.DOWN) { + if (blockCapability == Capabilities.ItemHandler.BLOCK) { + return (T) new InvWrapper(this); + } + return null; + } + + int slot = switch (ctx) { + case DOWN, UP -> throw new IllegalStateException("Trying to read UP or DOWN direction of capabilities"); + case NORTH -> 0; + case EAST -> 1; + case SOUTH -> 2; + case WEST -> 3; + }; + + ItemStack itemStack = getItem(slot); + ItemCapability itemCapability = blockCapabilityToItemCapability(blockCapability); + if (itemCapability == null) { + return null; + } + T cap = itemStack.getCapability(itemCapability, null); + + return cap; + } +} \ No newline at end of file diff --git a/src/main/java/ca/teamdman/sfm/common/compat/SFMCompat.java b/src/main/java/ca/teamdman/sfm/common/compat/SFMCompat.java index 34c695799..dd0bb1230 100644 --- a/src/main/java/ca/teamdman/sfm/common/compat/SFMCompat.java +++ b/src/main/java/ca/teamdman/sfm/common/compat/SFMCompat.java @@ -1,12 +1,17 @@ package ca.teamdman.sfm.common.compat; +import ca.teamdman.sfm.common.resourcetype.ChemicalResourceType; +import com.google.common.collect.Maps; import net.minecraft.core.Direction; import net.neoforged.fml.ModList; import net.neoforged.neoforge.capabilities.BlockCapability; import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.capabilities.ItemCapability; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; +import java.util.Map; public class SFMCompat { public static boolean isMekanismLoaded() { @@ -14,10 +19,30 @@ public static boolean isMekanismLoaded() { } public static List> getCapabilities() { - return List.of( + ArrayList> capabilities = new ArrayList<>(List.of( Capabilities.ItemHandler.BLOCK, Capabilities.FluidHandler.BLOCK, Capabilities.EnergyStorage.BLOCK - ); + )); + + if (isMekanismLoaded()) { + capabilities.add(ChemicalResourceType.CAP); + } + + return capabilities; } + + public static Map, ItemCapability> getCapabilityMap() { + Map, ItemCapability> capabilityMap = Maps.newIdentityHashMap(); + capabilityMap.put(Capabilities.ItemHandler.BLOCK, Capabilities.ItemHandler.ITEM); + capabilityMap.put(Capabilities.FluidHandler.BLOCK, Capabilities.FluidHandler.ITEM); + capabilityMap.put(Capabilities.EnergyStorage.BLOCK, Capabilities.EnergyStorage.ITEM); + + if (isMekanismLoaded()) { + capabilityMap.put(ChemicalResourceType.CAP, mekanism.common.capabilities.Capabilities.CHEMICAL.item()); + } + + return capabilityMap; + } + } diff --git a/src/main/java/ca/teamdman/sfm/common/containermenu/ProxyContainerMenu.java b/src/main/java/ca/teamdman/sfm/common/containermenu/ProxyContainerMenu.java new file mode 100644 index 000000000..1311b9bf9 --- /dev/null +++ b/src/main/java/ca/teamdman/sfm/common/containermenu/ProxyContainerMenu.java @@ -0,0 +1,102 @@ +package ca.teamdman.sfm.common.containermenu; + +import ca.teamdman.sfm.common.blockentity.ProxyBlockEntity; +import ca.teamdman.sfm.common.registry.SFMMenus; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.Tuple; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class ProxyContainerMenu extends AbstractContainerMenu { + public static final List> CONTAINER_SLOT_POSITIONS = List.of( + new Tuple<>(80, 17), + new Tuple<>(100, 37), + new Tuple<>(80, 57), + new Tuple<>(60, 37) + ); + + public static Tuple PLAYER_INV_START_POS = new Tuple<>(8, 90); + + private final ProxyBlockEntity PROXY_BLOCK_ENTITY; + + public ProxyContainerMenu(int windowId, Inventory inventory, FriendlyByteBuf buf) { + this(windowId, inventory, (ProxyBlockEntity) inventory.player.level().getBlockEntity(buf.readBlockPos())); + } + + public ProxyContainerMenu(int windowId, Inventory inventory, ProxyBlockEntity proxyBlockEntity) { + super(SFMMenus.PROXY_MENU.get(), windowId); + + PROXY_BLOCK_ENTITY = proxyBlockEntity; + + createContainerSlot(PROXY_BLOCK_ENTITY); + createPlayerInventory(inventory); + } + + public static void encode(ProxyBlockEntity pbe, FriendlyByteBuf buf) { + buf.writeBlockPos(pbe.getBlockPos()); + } + + @Override + public ItemStack quickMoveStack(Player pPlayer, int pIndex) { + var slot = this.slots.get(pIndex); + if (!slot.hasItem()) return ItemStack.EMPTY; + + var containerEnd = PROXY_BLOCK_ENTITY.getContainerSize(); + var inventoryEnd = this.slots.size(); + + var contents = slot.getItem(); + var result = contents.copy(); + + if (pIndex < containerEnd) { + // clicked slot in container + if (!this.moveItemStackTo(contents, containerEnd, inventoryEnd, true)) return ItemStack.EMPTY; + } else { + // clicked slot in inventory + if (!this.moveItemStackTo(contents, 0, containerEnd, false)) return ItemStack.EMPTY; + } + + if (contents.isEmpty()) { + slot.set(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + return result; + } + + @Override + public boolean stillValid(Player pPlayer) { + return PROXY_BLOCK_ENTITY.stillValid(pPlayer); + } + + private void createContainerSlot(Container container) { + for (int slot = 0; slot < CONTAINER_SLOT_POSITIONS.size(); slot++) { + Tuple pos = CONTAINER_SLOT_POSITIONS.get(slot); + addSlot( + new Slot(container, slot, pos.getA(), pos.getB()) + ); + } + } + + private void createPlayerInventory(Inventory playerInv) { + int xPos = PLAYER_INV_START_POS.getA(); + int yPos = PLAYER_INV_START_POS.getB(); + for (int row = 0; row < 3; row++) { + for (int column = 0; column < 9; column++) { + addSlot(new Slot(playerInv, + 9 + column + (row * 9), + xPos + (column * 18), + yPos + (row * 18))); + } + } + + for (int column = 0; column < 9; column++) { + this.addSlot(new Slot(playerInv, column, xPos + column * 18, yPos + (18 * 3) + 4)); + } + } +} diff --git a/src/main/java/ca/teamdman/sfm/common/program/CapabilityConsumer.java b/src/main/java/ca/teamdman/sfm/common/program/CapabilityConsumer.java index d34272c3c..40c3ee84c 100644 --- a/src/main/java/ca/teamdman/sfm/common/program/CapabilityConsumer.java +++ b/src/main/java/ca/teamdman/sfm/common/program/CapabilityConsumer.java @@ -10,6 +10,7 @@ void accept( Label label, BlockPos pos, Direction direction, - T cap + T cap, + int count ); } diff --git a/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockCapabilities.java b/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockCapabilities.java index ad2f219d6..7c3a16732 100644 --- a/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockCapabilities.java +++ b/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockCapabilities.java @@ -2,6 +2,9 @@ import ca.teamdman.sfm.SFM; import ca.teamdman.sfm.common.blockcapabilityprovider.CauldronBlockCapabilityProvider; +import ca.teamdman.sfm.common.blockentity.ProxyBlockEntity; +import ca.teamdman.sfm.common.compat.SFMCompat; +import com.google.common.collect.Maps; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; @@ -11,13 +14,13 @@ import net.minecraft.world.level.block.state.BlockState; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.capabilities.Capabilities; -import net.neoforged.neoforge.capabilities.IBlockCapabilityProvider; -import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; +import net.neoforged.neoforge.capabilities.*; import net.neoforged.neoforge.items.IItemHandler; import net.neoforged.neoforge.items.wrapper.InvWrapper; import org.jetbrains.annotations.Nullable; +import java.util.Map; + @EventBusSubscriber(modid = SFM.MOD_ID, bus = EventBusSubscriber.Bus.MOD) public class SFMBlockCapabilities { @@ -64,5 +67,22 @@ private static void registerCapabilities(RegisterCapabilitiesEvent event) { Blocks.LAVA_CAULDRON, Blocks.WATER_CAULDRON ); + + handleCapabilityProxyRegistration(event); + } + + /* + * https://github.com/CyclopsMC/CapabilityProxy/blob/master-1.21/loader-neoforge/src/main/java/org/cyclops/capabilityproxy/blockentity/BlockEntityItemCapabilityProxyNeoForgeConfig.java + */ + private static void handleCapabilityProxyRegistration(RegisterCapabilitiesEvent event) { + ProxyBlockEntity.BLOCK_TO_ITEM_CAPABILITIES = SFMCompat.getCapabilityMap(); + + for (BlockCapability blockCapability : SFMCompat.getCapabilities()) { + event.registerBlockEntity( + (BlockCapability) blockCapability, + SFMBlockEntities.PROXY_BLOCK_ENTITY.get(), + (object, context) -> object.getCapability((BlockCapability) blockCapability, context) + ); + } } } diff --git a/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockEntities.java b/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockEntities.java index 7f2876a4d..d87c023bd 100644 --- a/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockEntities.java +++ b/src/main/java/ca/teamdman/sfm/common/registry/SFMBlockEntities.java @@ -64,5 +64,10 @@ public static void register(IEventBus bus) { .build(null) ); - + public static final Supplier> PROXY_BLOCK_ENTITY = BLOCK_ENTITY_TYPES.register( + "proxy", + () -> BlockEntityType.Builder + .of(ProxyBlockEntity::new, SFMBlocks.PROXY_BLOCK.get()) + .build(null) + ); } diff --git a/src/main/java/ca/teamdman/sfm/common/registry/SFMBlocks.java b/src/main/java/ca/teamdman/sfm/common/registry/SFMBlocks.java index 44a0c8c29..1fd8f6a57 100644 --- a/src/main/java/ca/teamdman/sfm/common/registry/SFMBlocks.java +++ b/src/main/java/ca/teamdman/sfm/common/registry/SFMBlocks.java @@ -21,6 +21,7 @@ public class SFMBlocks { public static final Supplier CABLE_BLOCK = BLOCKS.register("cable", CableBlock::new); public static final Supplier BATTERY_BLOCK = BLOCKS.register("battery", BatteryBlock::new); public static final Supplier TEST_BARREL_BLOCK = BLOCKS.register("test_barrel", TestBarrelBlock::new); + public static final Supplier PROXY_BLOCK = BLOCKS.register("proxy", ProxyBlock::new); public static void register(IEventBus bus) { BLOCKS.register(bus); diff --git a/src/main/java/ca/teamdman/sfm/common/registry/SFMItems.java b/src/main/java/ca/teamdman/sfm/common/registry/SFMItems.java index fc5587f15..8c1e3fa41 100644 --- a/src/main/java/ca/teamdman/sfm/common/registry/SFMItems.java +++ b/src/main/java/ca/teamdman/sfm/common/registry/SFMItems.java @@ -20,6 +20,7 @@ public class SFMItems { public static final Supplier CABLE_ITEM = register("cable", SFMBlocks.CABLE_BLOCK); // public static final Supplier BATTERY_ITEM = register("battery", SFMBlocks.BATTERY_BLOCK); public static final Supplier WATER_TANK_ITEM = register("water_tank", SFMBlocks.WATER_TANK_BLOCK); + public static final Supplier PROXY_ITEM = register("proxy", SFMBlocks.PROXY_BLOCK); public static final Supplier DISK_ITEM = ITEMS.register("disk", DiskItem::new); public static final Supplier LABEL_GUN_ITEM = ITEMS.register( "labelgun", @@ -36,6 +37,8 @@ public class SFMItems { public static final Supplier EXPERIENCE_SHARD_ITEM = ITEMS.register("xp_shard", ExperienceShard::new); public static final Supplier EXPERIENCE_GOOP_ITEM = ITEMS.register("xp_goop", ExperienceGoop::new); + + public static void register(IEventBus bus) { ITEMS.register(bus); } diff --git a/src/main/java/ca/teamdman/sfm/common/registry/SFMMenus.java b/src/main/java/ca/teamdman/sfm/common/registry/SFMMenus.java index e0ea6b2dc..693087588 100644 --- a/src/main/java/ca/teamdman/sfm/common/registry/SFMMenus.java +++ b/src/main/java/ca/teamdman/sfm/common/registry/SFMMenus.java @@ -4,9 +4,10 @@ import ca.teamdman.sfm.SFM; import ca.teamdman.sfm.client.ClientStuff; import ca.teamdman.sfm.common.blockentity.ManagerBlockEntity; +import ca.teamdman.sfm.common.blockentity.ProxyBlockEntity; import ca.teamdman.sfm.common.containermenu.ManagerContainerMenu; +import ca.teamdman.sfm.common.containermenu.ProxyContainerMenu; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.MenuType; @@ -24,11 +25,6 @@ public class SFMMenus { BuiltInRegistries.MENU, SFM.MOD_ID ); - - public static void register(IEventBus bus) { - MENU_TYPES.register(bus); - } - public static final Supplier> MANAGER_MENU = MENU_TYPES.register( "manager", () -> IMenuTypeExtension.create( @@ -66,6 +62,46 @@ public ManagerContainerMenu create( } }) ); + public static final Supplier> PROXY_MENU = MENU_TYPES.register( + "proxy", + () -> IMenuTypeExtension.create( + new IContainerFactory<>() { + @Override + public ProxyContainerMenu create( + int windowId, + Inventory inv, + RegistryFriendlyByteBuf data + ) { + return new ProxyContainerMenu( + windowId, + inv, + data + ); + } + + @Override + public ProxyContainerMenu create( + int windowId, + Inventory inv + ) { + if (FMLEnvironment.dist.isClient()) { + BlockEntity be = ClientStuff.getLookBlockEntity(); + if (!(be instanceof ProxyBlockEntity pbe)) { + return IContainerFactory.super.create(windowId, inv); + } + return new ProxyContainerMenu(windowId, inv, pbe); + } else { + return IContainerFactory.super.create( + windowId, + inv + ); + } + } + }) + ); + public static void register(IEventBus bus) { + MENU_TYPES.register(bus); + } } diff --git a/src/main/java/ca/teamdman/sfm/common/resourcetype/ResourceType.java b/src/main/java/ca/teamdman/sfm/common/resourcetype/ResourceType.java index ba3e52bcb..30f6c0c23 100644 --- a/src/main/java/ca/teamdman/sfm/common/resourcetype/ResourceType.java +++ b/src/main/java/ca/teamdman/sfm/common/resourcetype/ResourceType.java @@ -16,7 +16,7 @@ import net.neoforged.neoforge.capabilities.BlockCapability; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.stream.Stream; @@ -120,12 +120,12 @@ public void forEachCapability( CableNetwork network = programContext.getNetwork(); RoundRobin roundRobin = labelAccess.roundRobin(); LabelPositionHolder labelPositionHolder = programContext.getLabelPositionHolder(); - ArrayList> positions = roundRobin.getPositionsForLabels( + HashMap, Integer> positions = roundRobin.getPositionsForLabels( labelAccess, labelPositionHolder ); - for (var pair : positions) { + for (var pair : positions.keySet()) { Label label = pair.getFirst(); BlockPos pos = pair.getSecond(); // Expand pos to (pos, direction) pairs @@ -143,7 +143,7 @@ public void forEachCapability( pos, dir ))); - consumer.accept(label, pos, dir, cap); + consumer.accept(label, pos, dir, cap, positions.get(pair)); continue; } } diff --git a/src/main/java/ca/teamdman/sfml/ast/InputStatement.java b/src/main/java/ca/teamdman/sfml/ast/InputStatement.java index 1c2f742f7..aedaff04d 100644 --- a/src/main/java/ca/teamdman/sfml/ast/InputStatement.java +++ b/src/main/java/ca/teamdman/sfml/ast/InputStatement.java @@ -96,10 +96,10 @@ public void gatherSlots( // gather slots for each capability found for positions tagged by a provided label Consumer> finalSlotConsumer = slotConsumer; // TODO: fix #166 forEachCapability advances the round robin when it should be shared between resource types - resourceType.forEachCapability(context, labelAccess, (label, pos, direction, cap) -> gatherSlotsForCap( + resourceType.forEachCapability(context, labelAccess, (label, pos, direction, cap, count) -> gatherSlotsForCap( context, (ResourceType) resourceType, - label, pos, direction, cap, + label, pos, direction, cap, count, inputTrackers, finalSlotConsumer )); @@ -119,12 +119,12 @@ public void gatherSlots( // gather slots for each capability found for positions tagged by a provided label Consumer> finalSlotConsumer = slotConsumer; - resourceType.forEachCapability(context, labelAccess, (label, pos, direction, cap) -> { + resourceType.forEachCapability(context, labelAccess, (label, pos, direction, cap, count) -> { List inputTrackers = resourceLimits.createInputTrackers(); gatherSlotsForCap( context, (ResourceType) resourceType, - label, pos, direction, cap, + label, pos, direction, cap, count, inputTrackers, finalSlotConsumer ); @@ -237,6 +237,7 @@ private void gatherSlotsForCap( BlockPos pos, Direction direction, CAP capability, + int count, List trackers, Consumer> acceptor ) { @@ -258,12 +259,14 @@ private void gatherSlotsForCap( stack, tracker.toString() ))); - acceptor.accept(LimitedInputSlotObjectPool.acquire( - label, pos, direction, slot, capability, - tracker, - stack, - type - )); + for (int i = 0; i < count; i++) { + acceptor.accept(LimitedInputSlotObjectPool.acquire( + label, pos, direction, slot, capability, + tracker, + stack, + type + )); + } } } } else { diff --git a/src/main/java/ca/teamdman/sfml/ast/OutputStatement.java b/src/main/java/ca/teamdman/sfml/ast/OutputStatement.java index 63607ba35..ff290e638 100644 --- a/src/main/java/ca/teamdman/sfml/ast/OutputStatement.java +++ b/src/main/java/ca/teamdman/sfml/ast/OutputStatement.java @@ -5,11 +5,8 @@ import ca.teamdman.sfm.common.program.*; import ca.teamdman.sfm.common.registry.SFMResourceTypes; import ca.teamdman.sfm.common.resourcetype.ResourceType; -import com.mojang.math.Constants; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.component.DataComponents; -import net.minecraft.world.item.ItemStack; import java.util.ArrayDeque; import java.util.List; @@ -357,13 +354,14 @@ public void gatherSlots( resourceType.displayAsCapabilityClass() ))); resourceType.forEachCapability(context, labelAccess, ( - (label, pos, direction, cap) -> gatherSlotsForCap( + (label, pos, direction, cap, count) -> gatherSlotsForCap( context, (ResourceType) resourceType, label, pos, direction, cap, + count, outputTracker, slotConsumer ) @@ -378,7 +376,7 @@ public void gatherSlots( resourceType.displayAsCapabilityClass(), resourceType.displayAsCapabilityClass() ))); - resourceType.forEachCapability(context, labelAccess, (label, pos, direction, cap) -> { + resourceType.forEachCapability(context, labelAccess, (label, pos, direction, cap, count) -> { // create a new list of trackers for each limited slot List outputTracker = resourceLimits.createOutputTrackers(); gatherSlotsForCap( @@ -388,6 +386,7 @@ public void gatherSlots( pos, direction, cap, + count, outputTracker, slotConsumer ); @@ -461,6 +460,7 @@ private void gatherSlotsForCap( BlockPos pos, Direction direction, CAP capability, + int count, List trackers, Consumer> acceptor ) { @@ -485,26 +485,28 @@ private void gatherSlotsForCap( stack, tracker.toString() ))); - acceptor.accept(LimitedOutputSlotObjectPool.acquire( - label, - pos, - direction, - slot, - capability, - tracker, - stack, - type - )); + for (int i = 0; i < count; i++) { + acceptor.accept(LimitedOutputSlotObjectPool.acquire( + label, + pos, + direction, + slot, + capability, + tracker, + stack, + type + )); + } } else { context .getLogger() .debug(x -> x.accept(LocalizationKeys.LOG_PROGRAM_TICK_IO_STATEMENT_GATHER_SLOTS_SLOT_SHOULD_NOT_CREATE.get( finalSlot, type.getAmount(stack) - + " of " - + Math.min(type.getMaxStackSize(stack), type.getMaxStackSizeForSlot(capability, finalSlot)) - + " " - + type.getItem(stack) + + " of " + + Math.min(type.getMaxStackSize(stack), type.getMaxStackSizeForSlot(capability, finalSlot)) + + " " + + type.getItem(stack) ))); } } diff --git a/src/main/java/ca/teamdman/sfml/ast/ResourceComparer.java b/src/main/java/ca/teamdman/sfml/ast/ResourceComparer.java index 69c20b520..a94c3b02a 100644 --- a/src/main/java/ca/teamdman/sfml/ast/ResourceComparer.java +++ b/src/main/java/ca/teamdman/sfml/ast/ResourceComparer.java @@ -21,7 +21,7 @@ public BoolExpr toBooleanExpression(SetOperator setOp, LabelAccess labelAccess, AtomicLong overallCount = new AtomicLong(0); // track how many inventories satisfied the condition List satisfiedSet = new ArrayList<>(); - type.forEachCapability(context, labelAccess, (label, pos, direction, cap) -> { + type.forEachCapability(context, labelAccess, (label, pos, direction, cap, count) -> { long inThisInv = 0; for (var stack : (Iterable) type.getStacksInSlots(cap, labelAccess.slots())::iterator) { if (this.res.matchesStack(stack)) { diff --git a/src/main/java/ca/teamdman/sfml/ast/RoundRobin.java b/src/main/java/ca/teamdman/sfml/ast/RoundRobin.java index cdd1083ae..73e2b4726 100644 --- a/src/main/java/ca/teamdman/sfml/ast/RoundRobin.java +++ b/src/main/java/ca/teamdman/sfml/ast/RoundRobin.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public class RoundRobin implements ASTNode { @@ -43,17 +44,19 @@ public boolean isEnabled() { return behaviour != Behaviour.UNMODIFIED; } - public @NotNull ArrayList> getPositionsForLabels( + public @NotNull HashMap, Integer> getPositionsForLabels( LabelAccess labelAccess, LabelPositionHolder labelPositionHolder ) { - ArrayList> positions = new ArrayList<>(); + HashMap, Integer> positions = new HashMap<>(); + switch (getBehaviour()) { case BY_LABEL -> { int index = next(labelAccess.labels().size()); Label label = labelAccess.labels().get(index); for (BlockPos pos : labelPositionHolder.getPositions(label.name())) { - positions.add(Pair.of(label, pos)); + Pair pair = Pair.of(label, pos); + positions.put(pair, positions.getOrDefault(pair, 0) + 1); } } case BY_BLOCK -> { @@ -66,13 +69,15 @@ public boolean isEnabled() { } } if (!candidates.isEmpty()) { - positions.add(candidates.get(next(candidates.size()))); + Pair pair = candidates.get(next(candidates.size())); + positions.put(pair, positions.getOrDefault(pair, 0) + 1); } } case UNMODIFIED -> { for (Label label : labelAccess.labels()) { for (BlockPos pos : labelPositionHolder.getPositions(label.name())) { - positions.add(Pair.of(label, pos)); + Pair pair = Pair.of(label, pos); + positions.put(pair, positions.getOrDefault(pair, 0) + 1); } } } diff --git a/src/main/resources/assets/sfm/textures/gui/container/proxy.png b/src/main/resources/assets/sfm/textures/gui/container/proxy.png new file mode 100644 index 000000000..21ac6c684 Binary files /dev/null and b/src/main/resources/assets/sfm/textures/gui/container/proxy.png differ