From 7877be2bc6f277f79c08077b6810414f87c32161 Mon Sep 17 00:00:00 2001 From: Buuz135 Date: Sun, 19 Dec 2021 16:09:09 +0100 Subject: [PATCH] Added compacting drawer --- src/generated/resources/.cache/cache | 8 + .../blockstates/compacting_drawer.json | 19 ++ .../loot_tables/blocks/compacting_drawer.json | 33 +++ .../functionalstorage/FunctionalStorage.java | 9 +- .../block/CompactingDrawerBlock.java | 152 +++++++++++ .../functionalstorage/block/DrawerBlock.java | 8 +- .../block/tile/CompactingDrawerTile.java | 122 +++++++++ .../block/tile/DrawerTile.java | 2 +- .../client/CompactingDrawerRenderer.java | 83 ++++++ .../client/DrawerRenderer.java | 39 +-- .../inventory/CompactingInventoryHandler.java | 162 ++++++++++++ .../util/CompactingUtil.java | 237 ++++++++++++++++++ 12 files changed, 851 insertions(+), 23 deletions(-) create mode 100644 src/generated/resources/assets/functionalstorage/blockstates/compacting_drawer.json create mode 100644 src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_drawer.json create mode 100644 src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java create mode 100644 src/main/java/com/buuz135/functionalstorage/block/tile/CompactingDrawerTile.java create mode 100644 src/main/java/com/buuz135/functionalstorage/client/CompactingDrawerRenderer.java create mode 100644 src/main/java/com/buuz135/functionalstorage/inventory/CompactingInventoryHandler.java create mode 100644 src/main/java/com/buuz135/functionalstorage/util/CompactingUtil.java diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 6de075e..d4ba5f7 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -4,9 +4,13 @@ ad618fbf42f1c54275c29beaa25710bca73acef2 assets/functionalstorage/blockstates/ac 3b02d94db9f2f0b4d9b7b4a412427929a6f87d2b assets/functionalstorage/blockstates/birch_wood_x_1.json 7bd0dc17af1d849100a423ca36eacb767bb2b1ea assets/functionalstorage/blockstates/birch_wood_x_2.json 7e20830acae23717dd782ebf628e5eef778de0c1 assets/functionalstorage/blockstates/birch_wood_x_4.json +78ab16e1714fbed8ba98acfe243a89c15587feb0 assets/functionalstorage/blockstates/compacting_drawer.json e0fee0fdb3a3e76bd6ca5a8f92f7c6c5e54b5e23 assets/functionalstorage/blockstates/crimson_hyphae_x_1.json 17eec305ac9c19c66a32af11de2e1a528fa00894 assets/functionalstorage/blockstates/crimson_hyphae_x_2.json ffcd4cbf2a5406b7e4f96e87ad643b1feb18caf3 assets/functionalstorage/blockstates/crimson_hyphae_x_4.json +243258d54301c9f1cb03b313a6caf248d9c42943 assets/functionalstorage/blockstates/dark_oak_wood_x_1.json +a3e62a3fe37312b70cfd621784f782d18e063475 assets/functionalstorage/blockstates/dark_oak_wood_x_2.json +586ce6d546f06d679d720166421d049afc7138a2 assets/functionalstorage/blockstates/dark_oak_wood_x_4.json a75ff2ba030156b42ed5e545fbf8e06f9854bf2c assets/functionalstorage/blockstates/jungle_wood_x_1.json 19ae7afc5de0593b427309159c299e8d2ddfc4cd assets/functionalstorage/blockstates/jungle_wood_x_2.json 228dd78c840b995c601704c32eaf17fe007d0346 assets/functionalstorage/blockstates/jungle_wood_x_4.json @@ -25,9 +29,13 @@ a0f7a648fc02bbe7951b1616e8b5024e98b9f4bc data/functionalstorage/loot_tables/bloc 9e61407957cd64d6bf221214d2766fbf0387f810 data/functionalstorage/loot_tables/blocks/birch_wood_x_1.json 6dc0f3e0eb3c0d95946727dc7a94889eba7b3d9d data/functionalstorage/loot_tables/blocks/birch_wood_x_2.json bb380824c89d14571908e3283170112c0425f832 data/functionalstorage/loot_tables/blocks/birch_wood_x_4.json +5ca84bb6e4d35893da638b52bb7884426a409719 data/functionalstorage/loot_tables/blocks/compacting_drawer.json 751843faeb73f732abf09285fa5db1c22d3e9aa7 data/functionalstorage/loot_tables/blocks/crimson_hyphae_x_1.json f5f4160a7223af9205e2df1917b58bd00a65a1bc data/functionalstorage/loot_tables/blocks/crimson_hyphae_x_2.json 598f9907cefdc9a2acd5019ea744979f24c561b2 data/functionalstorage/loot_tables/blocks/crimson_hyphae_x_4.json +ae61cae584aed7ecd672d5223992d9949af4acf0 data/functionalstorage/loot_tables/blocks/dark_oak_wood_x_1.json +8b7272c3fc37b4683678c95502c80d6e3d1618a9 data/functionalstorage/loot_tables/blocks/dark_oak_wood_x_2.json +0e29723f48411634d77aa1f8ccb668761f0f529d data/functionalstorage/loot_tables/blocks/dark_oak_wood_x_4.json a3f6195051ee19033bb167e924645cfff1982c13 data/functionalstorage/loot_tables/blocks/jungle_wood_x_1.json a9054f38503082c4448495eb28477f4aad833b6c data/functionalstorage/loot_tables/blocks/jungle_wood_x_2.json 7d0ec816a992ae76cf1b32cffa386a60ed59a7c8 data/functionalstorage/loot_tables/blocks/jungle_wood_x_4.json diff --git a/src/generated/resources/assets/functionalstorage/blockstates/compacting_drawer.json b/src/generated/resources/assets/functionalstorage/blockstates/compacting_drawer.json new file mode 100644 index 0000000..6f6f102 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/blockstates/compacting_drawer.json @@ -0,0 +1,19 @@ +{ + "variants": { + "subfacing=north": { + "model": "functionalstorage:block/compacting_drawer" + }, + "subfacing=south": { + "model": "functionalstorage:block/compacting_drawer", + "y": 180 + }, + "subfacing=west": { + "model": "functionalstorage:block/compacting_drawer", + "y": 270 + }, + "subfacing=east": { + "model": "functionalstorage:block/compacting_drawer", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_drawer.json b/src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_drawer.json new file mode 100644 index 0000000..c873cda --- /dev/null +++ b/src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_drawer.json @@ -0,0 +1,33 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_nbt", + "source": "block_entity", + "ops": [ + { + "source": "handler", + "target": "BlockEntityTag.handler", + "op": "replace" + } + ] + } + ], + "name": "functionalstorage:compacting_drawer" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java b/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java index 6c76a3d..f4cb594 100644 --- a/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java +++ b/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java @@ -1,6 +1,8 @@ package com.buuz135.functionalstorage; +import com.buuz135.functionalstorage.block.CompactingDrawerBlock; import com.buuz135.functionalstorage.block.DrawerBlock; +import com.buuz135.functionalstorage.client.CompactingDrawerRenderer; import com.buuz135.functionalstorage.client.DrawerRenderer; import com.buuz135.functionalstorage.data.FunctionalStorageBlockstateProvider; import com.hrznstudio.titanium.block.BasicTileBlock; @@ -19,7 +21,6 @@ import net.minecraftforge.client.event.EntityRenderersEvent; import net.minecraftforge.common.util.NonNullLazy; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; @@ -40,6 +41,8 @@ public class FunctionalStorage extends ModuleController { public static List WOOD_TYPES = new ArrayList<>(); public static HashMap>> DRAWER_TYPES = new HashMap<>(); + public static RegistryObject COMPACTING_DRAWER; + public static AdvancedTitaniumTab TAB = new AdvancedTitaniumTab("functionalstorage", true); public FunctionalStorage() { @@ -69,7 +72,7 @@ public class FunctionalStorage extends ModuleController { } DRAWER_TYPES.get(value).forEach(blockRegistryObject -> TAB.addIconStacks(() -> new ItemStack(blockRegistryObject.get()))); } - + COMPACTING_DRAWER = getRegistries().register(Block.class, "compacting_drawer", () -> new CompactingDrawerBlock("compacting_drawer")); } public enum DrawerType{ @@ -101,6 +104,8 @@ public class FunctionalStorage extends ModuleController { registerRenderers.registerBlockEntityRenderer(((BasicTileBlock)blockRegistryObject.get()).getTileEntityType(), p_173571_ -> new DrawerRenderer()); }); } + registerRenderers.registerBlockEntityRenderer(((BasicTileBlock)COMPACTING_DRAWER.get()).getTileEntityType(), p_173571_ -> new CompactingDrawerRenderer()); + }).subscribe(); } diff --git a/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java b/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java new file mode 100644 index 0000000..c6098e3 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java @@ -0,0 +1,152 @@ +package com.buuz135.functionalstorage.block; + +import com.buuz135.functionalstorage.FunctionalStorage; +import com.buuz135.functionalstorage.block.tile.CompactingDrawerTile; +import com.buuz135.functionalstorage.block.tile.DrawerTile; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import com.hrznstudio.titanium.block.RotatableBlock; +import com.hrznstudio.titanium.datagenerator.loot.block.BasicBlockLootTables; +import com.hrznstudio.titanium.module.DeferredRegistryHelper; +import com.hrznstudio.titanium.util.RayTraceUtils; +import com.hrznstudio.titanium.util.TileUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.functions.CopyNbtFunction; +import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class CompactingDrawerBlock extends RotatableBlock { + + public static Multimap CACHED_SHAPES = MultimapBuilder.hashKeys().arrayListValues().build(); + + static { + CACHED_SHAPES.put(Direction.NORTH, Shapes.box(1/16D, 1/16D, 0, 8/16D, 8/16D, 1/16D)); + CACHED_SHAPES.put(Direction.NORTH, Shapes.box(8/16D, 1/16D, 0, 15/16D, 8/16D, 1/16D)); + CACHED_SHAPES.put(Direction.NORTH, Shapes.box(1/16D, 8/16D, 0, 15/16D, 15/16D, 1/16D)); + CACHED_SHAPES.put(Direction.SOUTH, Shapes.box(8/16D, 1/16D, 15/16D, 15/16D, 8/16D, 1)); + CACHED_SHAPES.put(Direction.SOUTH, Shapes.box(1/16D, 1/16D, 15/16D, 8/16D, 8/16D, 1)); + CACHED_SHAPES.put(Direction.SOUTH, Shapes.box(1/16D, 8/16D, 15/16D, 15/16D, 15/16D, 1)); + CACHED_SHAPES.put(Direction.EAST, Shapes.box(15/16D, 1/16D, 1/16D, 1, 8/16D, 7/16D)); + CACHED_SHAPES.put(Direction.EAST, Shapes.box(15/16D, 1/16D, 8/16D, 1, 8/16D, 15/16D)); + CACHED_SHAPES.put(Direction.EAST, Shapes.box(15/16D, 8/16D, 1/16D, 1, 15/16D, 15/16D)); + CACHED_SHAPES.put(Direction.WEST, Shapes.box(0, 1/16D, 8/16D, 1/16D, 8/16D, 15/16D)); + CACHED_SHAPES.put(Direction.WEST, Shapes.box(0, 1/16D, 1/16D, 1/16D, 8/16D, 7/16D)); + CACHED_SHAPES.put(Direction.WEST, Shapes.box(0, 8/16D, 1/16D, 1/16D, 15/16D, 15/16D)); + } + + + public CompactingDrawerBlock(String name) { + super(name, Properties.copy(Blocks.OAK_PLANKS), CompactingDrawerTile.class); + setItemGroup(FunctionalStorage.TAB); + registerDefaultState(defaultBlockState().setValue(RotatableBlock.FACING_HORIZONTAL, Direction.NORTH)); + } + + @Override + public void addAlternatives(DeferredRegistryHelper registry) { + super.addAlternatives(registry); + } + + @NotNull + @Override + public RotationType getRotationType() { + return RotationType.FOUR_WAY; + } + + @Override + public BlockEntityType.BlockEntitySupplier getTileEntityFactory() { + return (blockPos, state) -> new CompactingDrawerTile(this, blockPos, state); + } + + @Override + public List getBoundingBoxes(BlockState state, BlockGetter source, BlockPos pos) { + return getShapes(state, source, pos); + } + + private static List getShapes(BlockState state, BlockGetter source, BlockPos pos){ + List boxes = new ArrayList<>(); + CACHED_SHAPES.get(state.getValue(RotatableBlock.FACING_HORIZONTAL)).forEach(boxes::add); //TODO + VoxelShape total = Shapes.block(); + boxes.add(total); + return boxes; + } + + @Nonnull + @Override + public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) { + return Shapes.box(0, 0, 0, 1,1,1); + } + + @Override + public boolean hasCustomBoxes(BlockState state, BlockGetter source, BlockPos pos) { + return true; + } + + @Override + public boolean hasIndividualRenderVoxelShape() { + return true; + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand hand, BlockHitResult ray) { + return TileUtil.getTileEntity(worldIn, pos, CompactingDrawerTile.class).map(drawerTile -> drawerTile.onSlotActivated(player, hand, ray.getDirection(), ray.getLocation().x, ray.getLocation().y, ray.getLocation().z, getHit(state, worldIn, pos, player))).orElse(InteractionResult.PASS); + } + + @Override + public void attack(BlockState state, Level worldIn, BlockPos pos, Player player) { + TileUtil.getTileEntity(worldIn, pos, CompactingDrawerTile.class).ifPresent(drawerTile -> drawerTile.onClicked(player, getHit(state, worldIn, pos, player))); + } + + public int getHit(BlockState state, Level worldIn, BlockPos pos, Player player) { + HitResult result = RayTraceUtils.rayTraceSimple(worldIn, player, 32, 0); + if (result instanceof BlockHitResult) { + VoxelShape hit = RayTraceUtils.rayTraceVoxelShape((BlockHitResult) result, worldIn, player, 32, 0); + if (hit != null) { + if (hit.equals(Shapes.block())) return -1; + List shapes = new ArrayList<>(CACHED_SHAPES.get(state.getValue(RotatableBlock.FACING_HORIZONTAL))); //TODO + for (int i = 0; i < shapes.size(); i++) { + if (Shapes.joinIsNotEmpty(shapes.get(i), hit, BooleanOp.AND)) { + return i; + } + } + } + } + return -1; + } + + @Override + public LootTable.Builder getLootTable(@Nonnull BasicBlockLootTables blockLootTables) { + CopyNbtFunction.Builder nbtBuilder = CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY); + nbtBuilder.copy("handler", "BlockEntityTag.handler"); + return blockLootTables.droppingSelfWithNbt(this, nbtBuilder); + } + + @Override + public NonNullList getDynamicDrops(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + return NonNullList.create(); + } + +} diff --git a/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java b/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java index d360768..0eb4f34 100644 --- a/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java +++ b/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java @@ -66,15 +66,15 @@ public class DrawerBlock extends RotatableBlock { for (VoxelShape voxelShape : CACHED_SHAPES.get(FunctionalStorage.DrawerType.X_2).get(direction)) { AABB bounding = voxelShape.toAabbs().get(0); if (direction == Direction.NORTH || direction == Direction.SOUTH) { - CACHED_SHAPES.computeIfAbsent(FunctionalStorage.DrawerType.X_4, type1 -> MultimapBuilder.hashKeys().arrayListValues().build()). - put(direction, Shapes.box(bounding.minX, bounding.minY, bounding.minZ , 7/16D, bounding.maxY, bounding.maxZ)); CACHED_SHAPES.computeIfAbsent(FunctionalStorage.DrawerType.X_4, type1 -> MultimapBuilder.hashKeys().arrayListValues().build()). put(direction, Shapes.box(9/16D, bounding.minY, bounding.minZ ,bounding.maxX, bounding.maxY, bounding.maxZ)); + CACHED_SHAPES.computeIfAbsent(FunctionalStorage.DrawerType.X_4, type1 -> MultimapBuilder.hashKeys().arrayListValues().build()). + put(direction, Shapes.box(bounding.minX, bounding.minY, bounding.minZ , 7/16D, bounding.maxY, bounding.maxZ)); } else { CACHED_SHAPES.computeIfAbsent(FunctionalStorage.DrawerType.X_4, type1 -> MultimapBuilder.hashKeys().arrayListValues().build()). - put(direction, Shapes.box(bounding.minX, bounding.minY, 7/16D,bounding.maxX, bounding.maxY, bounding.maxZ)); + put(direction, Shapes.box(bounding.minX, bounding.minY, bounding.minZ , bounding.maxX, bounding.maxY, 7/16D)); CACHED_SHAPES.computeIfAbsent(FunctionalStorage.DrawerType.X_4, type1 -> MultimapBuilder.hashKeys().arrayListValues().build()). - put(direction, Shapes.box(bounding.minX, bounding.minY, bounding.minZ , bounding.maxX, bounding.maxY, 9/16D)); + put(direction, Shapes.box(bounding.minX, bounding.minY, 9/16D,bounding.maxX, bounding.maxY, bounding.maxZ)); } } } diff --git a/src/main/java/com/buuz135/functionalstorage/block/tile/CompactingDrawerTile.java b/src/main/java/com/buuz135/functionalstorage/block/tile/CompactingDrawerTile.java new file mode 100644 index 0000000..5e454bd --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/block/tile/CompactingDrawerTile.java @@ -0,0 +1,122 @@ +package com.buuz135.functionalstorage.block.tile; + +import com.buuz135.functionalstorage.FunctionalStorage; +import com.buuz135.functionalstorage.inventory.BigInventoryHandler; +import com.buuz135.functionalstorage.inventory.CompactingInventoryHandler; +import com.buuz135.functionalstorage.util.CompactingUtil; +import com.hrznstudio.titanium.annotation.Save; +import com.hrznstudio.titanium.block.BasicTileBlock; +import com.hrznstudio.titanium.block.tile.ActiveTile; +import com.hrznstudio.titanium.util.RayTraceUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.datafix.fixes.ItemStackTheFlatteningFix; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.UUID; + +public class CompactingDrawerTile extends ActiveTile { + + private static HashMap INTERACTION_LOGGER = new HashMap<>(); + + @Save + public CompactingInventoryHandler handler; + private final LazyOptional lazyStorage; + + public CompactingDrawerTile(BasicTileBlock base, BlockPos pos, BlockState state) { + super(base, pos, state); + this.handler = new CompactingInventoryHandler() { + @Override + public void onChange() { + CompactingDrawerTile.this.markForUpdate(); + } + }; + lazyStorage = LazyOptional.of(() -> this.handler); + //TODO Check for the recipe on load + } + + public InteractionResult onSlotActivated(Player playerIn, InteractionHand hand, Direction facing, double hitX, double hitY, double hitZ, int slot) { + if (super.onActivated(playerIn, hand, facing, hitX, hitY, hitZ) == InteractionResult.SUCCESS) { + return InteractionResult.SUCCESS; + } + if (slot == -1){ + openGui(playerIn); + } else if (isServer()){ + if (!handler.isSetup()){ + ItemStack stack = playerIn.getItemInHand(hand).copy(); + stack.setCount(1); + CompactingUtil compactingUtil = new CompactingUtil(this.level); + compactingUtil.setup(stack); + handler.setup(compactingUtil); + for (int i = 0; i < handler.getResultList().size(); i++) { + if (ItemStack.isSame(handler.getResultList().get(i).getResult(), stack)){ + slot = i; + break; + } + } + } + ItemStack stack = playerIn.getItemInHand(hand); + if (!stack.isEmpty() && handler.isItemValid(slot, stack)) { + playerIn.setItemInHand(hand, handler.insertItem(slot, stack, false)); + } else if (System.currentTimeMillis() - INTERACTION_LOGGER.getOrDefault(playerIn.getUUID(), System.currentTimeMillis()) < 300) { + for (ItemStack itemStack : playerIn.getInventory().items) { + if (!itemStack.isEmpty() && handler.insertItem(slot, itemStack, true).isEmpty()) { + handler.insertItem(slot, itemStack.copy(), false); + itemStack.setCount(0); + } + } + } + INTERACTION_LOGGER.put(playerIn.getUUID(), System.currentTimeMillis()); + } + return InteractionResult.SUCCESS; + } + + public void onClicked(Player playerIn, int slot) { + if (isServer()){ + HitResult rayTraceResult = RayTraceUtils.rayTraceSimple(this.level, playerIn, 16, 0); + if (rayTraceResult.getType() == HitResult.Type.BLOCK) { + BlockHitResult blockResult = (BlockHitResult) rayTraceResult; + Direction facing = blockResult.getDirection(); + if (facing.equals(this.getFacingDirection())){ + ItemHandlerHelper.giveItemToPlayer(playerIn, handler.extractItem(slot, playerIn.isShiftKeyDown() ? 64 : 1, false)); + } + } + } + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return lazyStorage.cast(); + } + return super.getCapability(cap, side); + } + + @NotNull + @Override + public CompactingDrawerTile getSelf() { + return this; + } + + public CompactingInventoryHandler getHandler() { + return handler; + } + +} diff --git a/src/main/java/com/buuz135/functionalstorage/block/tile/DrawerTile.java b/src/main/java/com/buuz135/functionalstorage/block/tile/DrawerTile.java index c20ad09..20781cf 100644 --- a/src/main/java/com/buuz135/functionalstorage/block/tile/DrawerTile.java +++ b/src/main/java/com/buuz135/functionalstorage/block/tile/DrawerTile.java @@ -75,7 +75,7 @@ public class DrawerTile extends ActiveTile { } public void onClicked(Player playerIn, int slot) { - if (isServer()){ + if (isServer() && slot != -1){ HitResult rayTraceResult = RayTraceUtils.rayTraceSimple(this.level, playerIn, 16, 0); if (rayTraceResult.getType() == HitResult.Type.BLOCK) { BlockHitResult blockResult = (BlockHitResult) rayTraceResult; diff --git a/src/main/java/com/buuz135/functionalstorage/client/CompactingDrawerRenderer.java b/src/main/java/com/buuz135/functionalstorage/client/CompactingDrawerRenderer.java new file mode 100644 index 0000000..6699f2c --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/CompactingDrawerRenderer.java @@ -0,0 +1,83 @@ +package com.buuz135.functionalstorage.client; + +import com.buuz135.functionalstorage.FunctionalStorage; +import com.buuz135.functionalstorage.block.tile.CompactingDrawerTile; +import com.buuz135.functionalstorage.block.tile.DrawerTile; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix3f; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; + +public class CompactingDrawerRenderer implements BlockEntityRenderer { + + private static final Matrix3f FAKE_NORMALS; + + static { + Vector3f NORMAL = new Vector3f(1, 1, 1); + NORMAL.normalize(); + FAKE_NORMALS = new Matrix3f(new Quaternion(NORMAL, 0, true)); + } + + @Override + public void render(CompactingDrawerTile tile, float partialTicks, PoseStack matrixStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + matrixStack.pushPose(); + + Direction facing = tile.getFacingDirection(); + matrixStack.mulPose(Vector3f.YP.rotationDegrees(-180)); + matrixStack.last().normal().load(FAKE_NORMALS); + if (facing == Direction.NORTH) { + //matrixStack.translate(0, 0, 1.016 / 16D); + matrixStack.translate(-1, 0, 0); + } + if (facing == Direction.EAST) { + matrixStack.translate(-1, 0, -1); + matrixStack.mulPose(Vector3f.YP.rotationDegrees(-90)); + } + if (facing == Direction.SOUTH) { + matrixStack.translate(0, 0,-1); + matrixStack.mulPose(Vector3f.YP.rotationDegrees(-180)); + } + if (facing == Direction.WEST) { + matrixStack.mulPose(Vector3f.YP.rotationDegrees(90)); + } + combinedLightIn = LevelRenderer.getLightColor(tile.getLevel(), tile.getBlockPos().relative(facing)); + ItemStack stack = tile.getHandler().getResultList().get(0).getResult(); + if (!stack.isEmpty()){ + matrixStack.pushPose(); + matrixStack.translate(0.725, 0.30f, 0.0005f); + matrixStack.scale(0.5f, 0.5f, 1); + DrawerRenderer.renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, tile.getHandler().getStackInSlot(0).getCount(), 0.02f); + matrixStack.popPose(); + } + stack = tile.getHandler().getResultList().get(1).getResult(); + if (!stack.isEmpty()){ + matrixStack.pushPose(); + matrixStack.translate(0.275, 0.30f, 0.0005f); + matrixStack.scale(0.5f, 0.5f, 1); + DrawerRenderer.renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, tile.getHandler().getStackInSlot(1).getCount(), 0.02f); + matrixStack.popPose(); + } + stack = tile.getHandler().getResultList().get(2).getResult(); + if (!stack.isEmpty()){ + matrixStack.pushPose(); + matrixStack.translate(0.5, 0.75f, 0.0005f); + matrixStack.scale(0.5f, 0.5f, 1); + DrawerRenderer.renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, tile.getHandler().getStackInSlot(2).getCount(), 0.02f); + matrixStack.popPose(); + } + matrixStack.popPose(); + } + +} diff --git a/src/main/java/com/buuz135/functionalstorage/client/DrawerRenderer.java b/src/main/java/com/buuz135/functionalstorage/client/DrawerRenderer.java index b5a533e..4847788 100644 --- a/src/main/java/com/buuz135/functionalstorage/client/DrawerRenderer.java +++ b/src/main/java/com/buuz135/functionalstorage/client/DrawerRenderer.java @@ -14,6 +14,7 @@ import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; @@ -36,7 +37,7 @@ public class DrawerRenderer implements BlockEntityRenderer { Direction facing = tile.getFacingDirection(); matrixStack.mulPose(Vector3f.YP.rotationDegrees(-180)); - matrixStack.last().normal().load(FAKE_NORMALS); + if (facing != Direction.SOUTH) matrixStack.last().normal().load(FAKE_NORMALS); if (facing == Direction.NORTH) { //matrixStack.translate(0, 0, 1.016 / 16D); matrixStack.translate(-1, 0, 0); @@ -52,6 +53,7 @@ public class DrawerRenderer implements BlockEntityRenderer { if (facing == Direction.WEST) { matrixStack.mulPose(Vector3f.YP.rotationDegrees(90)); } + matrixStack.translate(0,0,-0.5/16D); combinedLightIn = LevelRenderer.getLightColor(tile.getLevel(), tile.getBlockPos().relative(facing)); if (tile.getDrawerType() == FunctionalStorage.DrawerType.X_1) render1Slot(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, tile); if (tile.getDrawerType() == FunctionalStorage.DrawerType.X_2) render2Slot(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, tile); @@ -70,7 +72,7 @@ public class DrawerRenderer implements BlockEntityRenderer { private void render2Slot(PoseStack matrixStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, DrawerTile tile){ if (!tile.getHandler().getStackInSlot(0).isEmpty()){ matrixStack.pushPose(); - matrixStack.translate(0.5, 0.30f, 0.0005f); + matrixStack.translate(0.5, 0.27f, 0.0005f); matrixStack.scale(0.5f, 0.5f, 1); ItemStack stack = tile.getHandler().getStackInSlot(0); renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, stack.getCount(), 0.02f); @@ -78,7 +80,7 @@ public class DrawerRenderer implements BlockEntityRenderer { } if (!tile.getHandler().getStackInSlot(1).isEmpty()){ matrixStack.pushPose(); - matrixStack.translate(0.5, 0.75f, 0.0005f); + matrixStack.translate(0.5, 0.77f, 0.0005f); matrixStack.scale(0.5f, 0.5f, 1); ItemStack stack = tile.getHandler().getStackInSlot(1); renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, stack.getCount(), 0.02f); @@ -88,7 +90,7 @@ public class DrawerRenderer implements BlockEntityRenderer { private void render4Slot(PoseStack matrixStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, DrawerTile tile){ if (!tile.getHandler().getStackInSlot(0).isEmpty()){ //BOTTOM RIGHT matrixStack.pushPose(); - matrixStack.translate(0.725, 0.30f, 0.0005f); + matrixStack.translate(0.75, 0.27f, 0.0005f); matrixStack.scale(0.5f, 0.5f, 1); ItemStack stack = tile.getHandler().getStackInSlot(0); renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, stack.getCount(), 0.02f); @@ -96,7 +98,7 @@ public class DrawerRenderer implements BlockEntityRenderer { } if (!tile.getHandler().getStackInSlot(1).isEmpty()){ //BOTTOM LEFT matrixStack.pushPose(); - matrixStack.translate(0.275, 0.30f, 0.0005f); + matrixStack.translate(0.25, 0.27f, 0.0005f); matrixStack.scale(0.5f, 0.5f, 1); ItemStack stack = tile.getHandler().getStackInSlot(1); renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, stack.getCount(), 0.02f); @@ -104,7 +106,7 @@ public class DrawerRenderer implements BlockEntityRenderer { } if (!tile.getHandler().getStackInSlot(2).isEmpty()){ //TOP RIGHT matrixStack.pushPose(); - matrixStack.translate(0.725, 0.75f, 0.0005f); + matrixStack.translate(0.75, 0.77f, 0.0005f); matrixStack.scale(0.5f, 0.5f, 1); ItemStack stack = tile.getHandler().getStackInSlot(2); renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, stack.getCount(), 0.02f); @@ -112,7 +114,7 @@ public class DrawerRenderer implements BlockEntityRenderer { } if (!tile.getHandler().getStackInSlot(3).isEmpty()){ //TOP LEFT matrixStack.pushPose(); - matrixStack.translate(0.275, 0.75f, 0.0005f); + matrixStack.translate(0.25, 0.77f, 0.0005f); matrixStack.scale(0.5f, 0.5f, 1); ItemStack stack = tile.getHandler().getStackInSlot(3); renderStack(matrixStack, bufferIn, combinedLightIn, combinedOverlayIn, stack, stack.getCount(), 0.02f); @@ -121,25 +123,30 @@ public class DrawerRenderer implements BlockEntityRenderer { } - private void renderStack(PoseStack matrixStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, ItemStack stack, int amount, float scale){ - if (stack.getItem() instanceof BlockItem){ - matrixStack.scale(0.5f, 0.5f, 0.0001f); + public static void renderStack(PoseStack matrixStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, ItemStack stack, int amount, float scale){ + BakedModel model = Minecraft.getInstance().getItemRenderer().getModel(stack, Minecraft.getInstance().level, null, 0); + if (model.isGui3d()){ + matrixStack.translate(0,0, -0.23f); + matrixStack.scale(0.5f, 0.5f, 0.5f); } else { - matrixStack.scale(0.4f, 0.4f, 0.0001f); + matrixStack.scale(0.4f, 0.4f, 0.4f); } - Minecraft.getInstance().getItemRenderer().renderStatic(stack, ItemTransforms.TransformType.GUI, combinedLightIn, combinedOverlayIn, matrixStack, bufferIn, 0); - if (!(stack.getItem() instanceof BlockItem)){ + + Minecraft.getInstance().getItemRenderer().renderStatic(stack, ItemTransforms.TransformType.NONE, combinedLightIn, combinedOverlayIn, matrixStack, bufferIn, 0); + if (!model.isGui3d()){ matrixStack.scale(1/0.4f, 1/0.4f, 1/0.0001f); matrixStack.scale(0.5f, 0.5f, 0.0001f); + }else { + matrixStack.translate(0,0, 0.23f*2); } - renderText(matrixStack, bufferIn, combinedOverlayIn, new TextComponent(ChatFormatting.WHITE + "" + stack.getCount()), Direction.NORTH, scale); + renderText(matrixStack, bufferIn, combinedOverlayIn, new TextComponent(ChatFormatting.WHITE + "" + amount), Direction.NORTH, scale); } /* Thanks Mekanism */ - private void renderText(PoseStack matrix, MultiBufferSource renderer, int overlayLight, Component text, Direction side, float maxScale) { + public static void renderText(PoseStack matrix, MultiBufferSource renderer, int overlayLight, Component text, Direction side, float maxScale) { - matrix.translate(0, -0.8, 0); + matrix.translate(0, -0.745, 0); float displayWidth = 1; diff --git a/src/main/java/com/buuz135/functionalstorage/inventory/CompactingInventoryHandler.java b/src/main/java/com/buuz135/functionalstorage/inventory/CompactingInventoryHandler.java new file mode 100644 index 0000000..70b869e --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/inventory/CompactingInventoryHandler.java @@ -0,0 +1,162 @@ +package com.buuz135.functionalstorage.inventory; + +import com.buuz135.functionalstorage.util.CompactingUtil; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public abstract class CompactingInventoryHandler implements IItemHandler, INBTSerializable { + + public static String VOID = "Void"; + public static String BIG_ITEMS = "BigItems"; + public static String STACK = "Stack"; + public static String AMOUNT = "Amount"; + + private final int TOTAL_AMOUNT = 8192 * 9 * 9; + + private int amount; + private boolean voidItems; + private List resultList; + + public CompactingInventoryHandler(){ + this.resultList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + this.resultList.add(i, new CompactingUtil.Result(ItemStack.EMPTY, 1)); + } + this.voidItems = false; + } + + @Override + public int getSlots() { + return 3; + } + + @Nonnull + @Override + public ItemStack getStackInSlot(int slot) { + CompactingUtil.Result bigStack = this.resultList.get(slot); + ItemStack copied = bigStack.getResult().copy(); + copied.setCount(this.amount / bigStack.getNeeded()); + return copied; + } + + @Nonnull + @Override + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { + if (isItemValid(slot, stack)) { + CompactingUtil.Result result = this.resultList.get(slot); + int inserted = Math.min(TOTAL_AMOUNT - amount, stack.getCount() * result.getNeeded()); + inserted = (int) (Math.floor(inserted / result.getNeeded()) * result.getNeeded()); + if (!simulate){ + this.amount = Math.min(this.amount + inserted, TOTAL_AMOUNT); + onChange(); + } + if (inserted == stack.getCount() * result.getNeeded() || voidItems) return ItemStack.EMPTY; + return ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - inserted / result.getNeeded()); + + } + return stack; + } + + + public boolean isSetup(){ + return !this.resultList.get(this.resultList.size() -1).getResult().isEmpty(); + } + + public void setup(CompactingUtil compactingUtil){ + this.resultList = compactingUtil.getResults(); + onChange(); + } + + public void reset(){ + this.resultList.forEach(result -> { + result.setResult(ItemStack.EMPTY); + result.setNeeded(1); + }); + } + + @Nonnull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (amount == 0) return ItemStack.EMPTY; + if (slot < 3){ + CompactingUtil.Result bigStack = this.resultList.get(slot); + if (bigStack.getResult().isEmpty()) return ItemStack.EMPTY; + int stackAmount = bigStack.getNeeded() * amount; + if (stackAmount >= this.amount) { + ItemStack out = bigStack.getResult().copy(); + int newAmount = (int) Math.floor(this.amount / bigStack.getNeeded()); + if (!simulate) { + //TODO Dont change if locked + this.amount -= (newAmount * bigStack.getNeeded()); + if (this.amount == 0) reset(); + onChange(); + } + out.setCount(newAmount); + return out; + } else { + if (!simulate) { + this.amount -= stackAmount; + onChange(); + } + return ItemHandlerHelper.copyStackWithSize(bigStack.getResult(), amount); + } + + + } + return ItemStack.EMPTY; + } + + @Override + public int getSlotLimit(int slot) { + return (int) Math.floor(TOTAL_AMOUNT / this.resultList.get(slot).getNeeded()); + } + + @Override + public boolean isItemValid(int slot, @Nonnull ItemStack stack) { + if (slot < 3){ + CompactingUtil.Result bigStack = this.resultList.get(slot); + ItemStack fl = bigStack.getResult(); + return !fl.isEmpty() && fl.sameItem(stack) && ItemStack.tagMatches(fl, stack); + } + return false; + } + + @Override + public CompoundTag serializeNBT() { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putBoolean(VOID, voidItems); + compoundTag.putInt(AMOUNT, this.amount); + CompoundTag items = new CompoundTag(); + for (int i = 0; i < this.resultList.size(); i++) { + CompoundTag bigStack = new CompoundTag(); + bigStack.put(STACK, this.resultList.get(i).getResult().serializeNBT()); + bigStack.putInt(AMOUNT, this.resultList.get(i).getNeeded()); + items.put(i + "", bigStack); + } + compoundTag.put(BIG_ITEMS, items); + return compoundTag; + } + + @Override + public void deserializeNBT(CompoundTag nbt) { + this.voidItems = nbt.getBoolean(VOID); + this.amount = nbt.getInt(AMOUNT); + for (String allKey : nbt.getCompound(BIG_ITEMS).getAllKeys()) { + this.resultList.get(Integer.parseInt(allKey)).setResult(ItemStack.of(nbt.getCompound(BIG_ITEMS).getCompound(allKey).getCompound(STACK))); + this.resultList.get(Integer.parseInt(allKey)).setNeeded(Math.max(1, nbt.getCompound(BIG_ITEMS).getCompound(allKey).getInt(AMOUNT))); + } + } + + public abstract void onChange(); + + public List getResultList() { + return resultList; + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/util/CompactingUtil.java b/src/main/java/com/buuz135/functionalstorage/util/CompactingUtil.java new file mode 100644 index 0000000..9d45236 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/util/CompactingUtil.java @@ -0,0 +1,237 @@ +package com.buuz135.functionalstorage.util; + +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; + +import java.util.*; + + +/** + * Some code in this class is from the original Storage Drawers + * findSimilar + * findAllMatchingRecipes + * tryMatch + * findLowerTier + */ +public class CompactingUtil { + + private final Level level; + private List results; + + public CompactingUtil(Level level) { + this.level = level; + this.results = new ArrayList<>(); + } + + public void setup(ItemStack stack){ + results.add(new Result(stack, 1)); + Result result = findUpperTier(stack); + if (!result.getResult().isEmpty()){ + results.add(result); + result = findUpperTier(result.getResult()); + if (!result.getResult().isEmpty()){ + result.setNeeded(result.getNeeded() * this.results.get(this.results.size() - 1).getNeeded()); + results.add(result); + } + } + boolean canFind = true; + while (canFind && results.size() < 3){ + result = findLowerTier(results.get(0).getResult()); + if (!result.getResult().isEmpty()){ + for (Result result1 : results) { + result1.setNeeded(result1.getNeeded() * result.getNeeded()); + } + result.setNeeded(1); + results.add(0, result); + }else{ + canFind = false; + } + } + while (results.size() < 3){ + results.add(0, new Result(ItemStack.EMPTY, 1)); + } + } + + public List getResults() { + return results; + } + + private Result findUpperTier(ItemStack stack){ + //Checking 3x3 + int sizeCheck = 9; + CraftingContainer container = createContainerAndFill(3, stack); + List outputs = findAllMatchingRecipes(container); + List realOutputs = new ArrayList<>(); + if (outputs.size() == 0){ + //Checking 2x2 + sizeCheck = 4; + container = createContainerAndFill(2, stack); + outputs = findAllMatchingRecipes(container); + } + if (outputs.size() > 0){ + for (ItemStack output : outputs) { + container = createContainerAndFill(1, output); + List reversed = findAllMatchingRecipes(container); + for (ItemStack reversedStack : reversed) { + if (reversedStack.getCount() != sizeCheck || !ItemStack.isSame(reversedStack, stack)){ + continue; + } + realOutputs.add(output); + } + } + } + + ItemStack similar = findSimilar(stack, realOutputs); + if (!similar.isEmpty()){ + return new Result(similar, sizeCheck); + } + if (realOutputs.size() > 0){ + return new Result(realOutputs.get(0), sizeCheck); + } + return new Result(ItemStack.EMPTY, 0); + } + + private Result findLowerTier(ItemStack stack){ + List candidates = new ArrayList<>(); + Map candidatesRate = new HashMap<>(); + for (CraftingRecipe craftingRecipe : level.getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)) { + ItemStack output = craftingRecipe.getResultItem(); + if (!ItemStack.isSame(stack, output)) continue; + ItemStack match = tryMatch(stack, craftingRecipe.getIngredients()); + if (!match.isEmpty()){ + CraftingContainer container = createContainerAndFill(1, output); + List matchStacks = findAllMatchingRecipes(container); + for (ItemStack matchStack : matchStacks) { + int recipeSize = craftingRecipe.getIngredients().size(); + if (ItemStack.isSame(match, matchStack) && matchStack.getCount() == recipeSize){ + candidates.add(match); + candidatesRate.put(match, recipeSize); + } + } + } + } + ItemStack similar = findSimilar(stack, candidates); + if (!similar.isEmpty()){ + return new Result(similar, candidatesRate.get(similar)); + } + if (candidates.size() > 0){ + return new Result(candidates.get(0), candidatesRate.get(candidates.get(0))); + } + return new Result(ItemStack.EMPTY, 0); + } + + private List findAllMatchingRecipes(CraftingContainer crafting) { + List candidates = new ArrayList<>(); + for (CraftingRecipe recipe : level.getRecipeManager().getRecipesFor(RecipeType.CRAFTING, crafting, level)) { + if (recipe.matches(crafting, level)) { + ItemStack result = recipe.assemble(crafting); + if (!result.isEmpty()) + candidates.add(result); + } + } + return candidates; + } + + private ItemStack findSimilar(ItemStack reference, List candidates) { + ResourceLocation referenceName = reference.getItem().getRegistryName(); + if (referenceName != null) { + for (ItemStack candidate : candidates) { + ResourceLocation matchName = candidate.getItem().getRegistryName(); + if (matchName != null) { + if (referenceName.getNamespace().equals(matchName.getNamespace())) + return candidate; + } + } + } + return ItemStack.EMPTY; + } + + + private ItemStack tryMatch(ItemStack stack, NonNullList ingredients) { + if (ingredients.size() != 9 && ingredients.size() != 4) + return ItemStack.EMPTY; + + Ingredient refIngredient = ingredients.get(0); + ItemStack[] refMatchingStacks = refIngredient.getItems(); + if (refMatchingStacks.length == 0) + return ItemStack.EMPTY; + + for (int i = 1, n = ingredients.size(); i < n; i++) { + Ingredient ingredient = ingredients.get(i); + ItemStack match = ItemStack.EMPTY; + + for (ItemStack ingItemMatch : refMatchingStacks) { + if (ingredient.test(ingItemMatch)) { + match = ingItemMatch; + break; + } + } + + if (match.isEmpty()) + return ItemStack.EMPTY; + } + + ItemStack match = findSimilar(stack, Arrays.asList(refMatchingStacks)); + if (match.isEmpty()) + match = refMatchingStacks[0]; + + return match; + } + + private CraftingContainer createContainerAndFill(int size, ItemStack stack){ + CraftingContainer inventoryCrafting = new CraftingContainer(new AbstractContainerMenu(null, 0) { + @Override + public boolean stillValid(Player playerIn) { + return false; + } + }, size, size); + for (int i = 0; i < size * size; i++) { + inventoryCrafting.setItem(i, stack.copy()); + } + return inventoryCrafting; + } + + public static class Result{ + + private ItemStack result; + private int needed; + + public Result(ItemStack result, int needed) { + this.result = result; + this.needed = needed; + } + + public ItemStack getResult() { + return result; + } + + public void setResult(ItemStack result) { + this.result = result; + } + + public int getNeeded() { + return needed; + } + + public void setNeeded(int needed) { + this.needed = needed; + } + + @Override + public String toString() { + return "Result{" + + "result=" + result + + ", needed=" + needed + + '}'; + } + } + +}