From 7784e5b58d0b20f32f42c40ae7cb39fcd678bece Mon Sep 17 00:00:00 2001 From: grimmauld Date: Thu, 10 Sep 2020 13:23:05 +0200 Subject: [PATCH] Added potion moved dispense behaviour, fixed dispense behaviour output stack not being used resulting in potential dupes --- .../dispenser/DispenseItemLocation.java | 25 +++++++ .../dispenser/DispenserMovementBehaviour.java | 15 +++-- .../dispenser/DropperMovementBehaviour.java | 65 +++++++++++++------ .../IMovedDispenseItemBehaviour.java | 36 +++++----- .../MovedDefaultDispenseItemBehaviour.java | 10 +++ .../create/foundation/item/ItemHelper.java | 16 +++-- 6 files changed, 120 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java new file mode 100644 index 000000000..2b0b23916 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.contraptions.components.actors.dispenser; + +public class DispenseItemLocation { + private final boolean internal; + private final int slot; + + public static final DispenseItemLocation NONE = new DispenseItemLocation(false, -1); + + public DispenseItemLocation(boolean internal, int slot) { + this.internal = internal; + this.slot = slot; + } + + public boolean isInternal() { + return internal; + } + + public int getSlot() { + return slot; + } + + public boolean isEmpty() { + return slot < 0; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java index f49e1df97..d7453ae60 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java @@ -31,13 +31,14 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour { @Override protected void activate(MovementContext context, BlockPos pos) { - ItemStack itemstack = getDispenseStack(context); - if (itemstack.isEmpty()) { + DispenseItemLocation location = getDispenseStack(context); + if (location.isEmpty()) { context.world.playEvent(1001, pos, 0); } else { + ItemStack itemstack = getItemStackAt(location, context); // Special dispense item behaviour for moving contraptions if (MOVED_DISPENSE_ITEM_BEHAVIOURS.containsKey(itemstack.getItem())) { - MOVED_DISPENSE_ITEM_BEHAVIOURS.get(itemstack.getItem()).dispense(itemstack, context, pos); + setItemStackAt(location, MOVED_DISPENSE_ITEM_BEHAVIOURS.get(itemstack.getItem()).dispense(itemstack, context, pos), context); return; } @@ -51,14 +52,14 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour { ContraptionBlockSource blockSource = new ContraptionBlockSource(context, pos, clostestFacing); IDispenseItemBehavior idispenseitembehavior = BEHAVIOUR_LOOKUP.getBehavior(itemstack); if (idispenseitembehavior.getClass() != DefaultDispenseItemBehavior.class) { // There is a dispense item behaviour registered for the vanilla dispenser - idispenseitembehavior.dispense(blockSource, itemstack); + setItemStackAt(location, idispenseitembehavior.dispense(blockSource, itemstack), context); return; } - } catch (NullPointerException e) { - itemstack = backup; // Something went wrong with the TE being null in ContraptionBlockSource, reset the stack + } catch (NullPointerException ignored) { + itemstack = backup; } - defaultBehaviour.dispense(itemstack, context, pos); // the default: launch the item + setItemStackAt(location, defaultBehaviour.dispense(itemstack, context, pos), context); // the default: launch the item } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java index 7a45b5d4f..f733c35f8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java @@ -19,11 +19,11 @@ public class DropperMovementBehaviour extends MovementBehaviour { private static final Random RNG = new Random(); protected void activate(MovementContext context, BlockPos pos) { - ItemStack itemstack = getDispenseStack(context); - if (itemstack.isEmpty()) { + DispenseItemLocation location = getDispenseStack(context); + if (location.isEmpty()) { context.world.playEvent(1001, pos, 0); } else { - defaultBehaviour.dispense(itemstack, context, pos); + setItemStackAt(location, defaultBehaviour.dispense(getItemStackAt(location, context), context, pos), context); } } @@ -40,27 +40,34 @@ public class DropperMovementBehaviour extends MovementBehaviour { ItemHelper.extract(context.contraption.inventory, itemStack::isItemEqual, ItemHelper.ExtractionCountMode.UPTO, itemStack.getMaxStackSize() - itemStack.getCount(), false).getCount())); } - @SuppressWarnings("unchecked") - private NonNullList getStacks(MovementContext context) { + private void updateTemporaryData(MovementContext context) { if (!(context.temporaryData instanceof NonNullList) && context.world instanceof ServerWorld) { - NonNullList stacks = NonNullList.withSize(9, ItemStack.EMPTY); + NonNullList stacks = NonNullList.withSize(getInvSize(), ItemStack.EMPTY); ItemStackHelper.loadAllItems(context.tileData, stacks); context.temporaryData = stacks; } + } + + @SuppressWarnings("unchecked") + private NonNullList getStacks(MovementContext context) { + updateTemporaryData(context); return (NonNullList) context.temporaryData; } - private ArrayList getUseableStacks(MovementContext context) { - ArrayList useable = new ArrayList<>(); - for (ItemStack testStack : getStacks(context)) { + private ArrayList getUseableLocations(MovementContext context) { + ArrayList useable = new ArrayList<>(); + NonNullList internalStacks = getStacks(context); + for (int slot = 0; slot < getInvSize(); slot++) { + DispenseItemLocation location = new DispenseItemLocation(true, slot); + ItemStack testStack = getItemStackAt(location, context); if (testStack == null || testStack.isEmpty()) continue; if (testStack.getMaxStackSize() == 1) { - ItemStack stack = ItemHelper.findFirstMatch(context.contraption.inventory, testStack::isItemEqual); - if (!stack.isEmpty()) - useable.add(stack); - } else if (testStack.getCount() >= 2) - useable.add(testStack); + location = new DispenseItemLocation(false, ItemHelper.findFirstMatchingSlotIndex(context.contraption.inventory, testStack::isItemEqual)); + if (!getItemStackAt(location, context).isEmpty()) + useable.add(location); + } else if (internalStacks.get(slot).getCount() >= 2) + useable.add(location); } return useable; } @@ -79,18 +86,38 @@ public class DropperMovementBehaviour extends MovementBehaviour { writeExtraData(context); } - protected ItemStack getDispenseStack(MovementContext context) { + protected DispenseItemLocation getDispenseStack(MovementContext context) { int i = -1; int j = 1; - List stacks = getUseableStacks(context); - for (int k = 0; k < stacks.size(); ++k) { + List useableLocations = getUseableLocations(context); + for (int k = 0; k < useableLocations.size(); ++k) { if (RNG.nextInt(j++) == 0) { i = k; } } if (i < 0) - return ItemStack.EMPTY; + return DispenseItemLocation.NONE; else - return stacks.get(i); + return useableLocations.get(i); + } + + protected ItemStack getItemStackAt(DispenseItemLocation location, MovementContext context) { + if (location.isInternal()) { + return getStacks(context).get(location.getSlot()); + } else { + return context.contraption.inventory.getStackInSlot(location.getSlot()); + } + } + + protected void setItemStackAt(DispenseItemLocation location, ItemStack stack, MovementContext context) { + if (location.isInternal()) { + getStacks(context).set(location.getSlot(), stack); + } else { + context.contraption.inventory.setStackInSlot(location.getSlot(), stack); + } + } + + private static int getInvSize() { + return 9; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java index 6636c0292..7ef9d1748 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java @@ -15,6 +15,7 @@ import net.minecraft.entity.item.TNTEntity; import net.minecraft.entity.projectile.*; import net.minecraft.fluid.FlowingFluid; import net.minecraft.fluid.Fluid; +import net.minecraft.item.BucketItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.SpawnEggItem; @@ -30,7 +31,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.IWorld; import net.minecraft.world.World; -import net.minecraftforge.items.ItemHandlerHelper; import java.util.Random; @@ -100,6 +100,24 @@ public interface IMovedDispenseItemBehaviour { }); + MovedProjectileDispenserBehaviour movedPotionDispenseItemBehaviour = new MovedProjectileDispenserBehaviour() { + @Override + protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) { + return Util.make(new PotionEntity(world, x, y, z), (p_218411_1_) -> p_218411_1_.setItem(itemStack)); + } + + protected float getProjectileInaccuracy() { + return super.getProjectileInaccuracy() * 0.5F; + } + + protected float getProjectileVelocity() { + return super.getProjectileVelocity() * .5F; + } + }; + DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.SPLASH_POTION, movedPotionDispenseItemBehaviour); + DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.LINGERING_POTION, movedPotionDispenseItemBehaviour); + + DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.TNT, new MovedDefaultDispenseItemBehaviour() { @Override protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) { @@ -175,14 +193,6 @@ public interface IMovedDispenseItemBehaviour { return super.dispenseStack(itemStack, context, pos, facing); } } - - private ItemStack placeItemInInventory(ItemStack bottles, ItemStack output, MovementContext context, BlockPos pos, Vec3d facing) { - bottles.shrink(1); - ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, output.copy(), false); - if (!remainder.isEmpty()) - super.dispenseStack(output, context, pos, facing); - return bottles; - } }); DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.BUCKET, new MovedDefaultDispenseItemBehaviour() { @@ -198,14 +208,6 @@ public interface IMovedDispenseItemBehaviour { } return super.dispenseStack(itemStack, context, pos, facing); } - - private ItemStack placeItemInInventory(ItemStack buckets, ItemStack output, MovementContext context, BlockPos pos, Vec3d facing) { - buckets.shrink(1); - ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, output.copy(), false); - if (!remainder.isEmpty()) - super.dispenseStack(output, context, pos, facing); - return buckets; - } }); final IMovedDispenseItemBehaviour spawnEggDispenseBehaviour = new MovedDefaultDispenseItemBehaviour() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java index 6692f44cf..6318da0f4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java @@ -12,8 +12,10 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.IWorld; import net.minecraft.world.World; +import net.minecraftforge.items.ItemHandlerHelper; public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBehaviour { + private static final MovedDefaultDispenseItemBehaviour defaultInstance = new MovedDefaultDispenseItemBehaviour(); public static void doDispense(World p_82486_0_, ItemStack p_82486_1_, int p_82486_2_, Vec3d facing, BlockPos p_82486_4_, MovementContext context) { double d0 = p_82486_4_.getX() + facing.x + .5; @@ -80,4 +82,12 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha protected Direction getClosestFacingDirection(Vec3d exactFacing) { return Direction.getFacingFromVector(exactFacing.x, exactFacing.y, exactFacing.z); } + + protected ItemStack placeItemInInventory(ItemStack consumedFrom, ItemStack output, MovementContext context, BlockPos pos, Vec3d facing) { + consumedFrom.shrink(1); + ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, output.copy(), false); + if (!remainder.isEmpty()) + defaultInstance.dispenseStack(output, context, pos, facing); + return consumedFrom; + } } diff --git a/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java b/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java index 9a57db79a..c6f9e4816 100644 --- a/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java +++ b/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java @@ -242,11 +242,19 @@ public class ItemHelper { } public static ItemStack findFirstMatch(IItemHandler inv, Predicate test) { - for (int i = 0; i < inv.getSlots(); i++) { - ItemStack toTest = inv.getStackInSlot(i); + int slot = findFirstMatchingSlotIndex(inv, test); + if (slot == -1) + return ItemStack.EMPTY; + else + return inv.getStackInSlot(slot); + } + + public static int findFirstMatchingSlotIndex(IItemHandler inv, Predicate test) { + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack toTest = inv.getStackInSlot(slot); if (test.test(toTest)) - return toTest; + return slot; } - return ItemStack.EMPTY; + return -1; } }