From 952132bcfeda4910b8d4830037646df7bfc61786 Mon Sep 17 00:00:00 2001 From: KptKosmit91 Date: Mon, 2 Jun 2025 18:25:27 +0200 Subject: [PATCH 1/2] Client-side remove package from hand when put on chain Forces mainhand package to be instantly removed from the mainhand when placing it on a chain conveyor This is more of a failsafe to prevent the player from putting the package on the chain multiple times --- .../chainConveyor/ChainConveyorInteractionHandler.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorInteractionHandler.java b/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorInteractionHandler.java index cca47498dc..4c1cc07e96 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorInteractionHandler.java @@ -22,6 +22,7 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.HitResult; @@ -149,6 +150,12 @@ public static boolean onUse() { AllPackets.getChannel() .sendToServer(new ChainPackageInteractionPacket(selectedLift, selectedConnection, selectedChainPosition, mainHandItem)); + + // force hand to be set as empty while in survival. this will run on the client only + // in case the server doesn't reply correctly the package will re-appear in the player's hand + if (!mc.player.isCreative()) { + mc.player.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); + } return true; } From 7bb523c7924e255814059e19e83846fda3d9df1d Mon Sep 17 00:00:00 2001 From: KptKosmit91 Date: Wed, 4 Jun 2025 19:16:38 +0200 Subject: [PATCH 2/2] Mech arm optimizations -Lazy updating during SEARCH_INPUTS phase so as to not make the arm search for targets on every tick. This should help with performance with many arms or arms that have lots of targets -Replaced if-else-if blocks that checked the arm's Phase with Switch statements -Cached getSlotCount result for arm interaction point slot iterations, should help when iterating high slot counts --- .../mechanicalArm/ArmBlockEntity.java | 83 +++++++++++++++---- 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java index 7ea5a89d84..00f176e5a5 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java @@ -54,10 +54,16 @@ public class ArmBlockEntity extends KineticBlockEntity implements TransformableBlockEntity { + // Server Statics + private static final int SearchInputsRate = 20; // the rate at which the arm will search for targets while in SEARCH_INPUTS phase + private static int LastRandomSearchTickOffset = 0; + // Server List inputs; List outputs; ListTag interactionPointTag; + int randomSearchTickOffset; + int forceSearchInputsTicks = 1; // ticks for how long the arm will search on every tick instead of every SearchInputsRate ticks (while in SEARCH_INPUTS phase) // Both float chasedPointProgress; @@ -142,12 +148,24 @@ public void tick() { if (level.isClientSide) return; - if (phase == Phase.MOVE_TO_INPUT) - collectItem(); - else if (phase == Phase.MOVE_TO_OUTPUT) - depositItem(); - else if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) - searchForItem(); + switch (phase) { + case MOVE_TO_INPUT: + collectItem(); + break; + case MOVE_TO_OUTPUT: + depositItem(); + break; + case SEARCH_INPUTS: + case DANCING: + boolean forcedSearch = forceSearchInputsTicks > 0; + if (forcedSearch || (level.getGameTime() + randomSearchTickOffset) % SearchInputsRate == 0) { + if(forcedSearch) { + forceSearchInputsTicks--; + } + searchForItem(); + } + break; + } if (targetReached) lazyTick(); @@ -161,10 +179,16 @@ public void lazyTick() { return; if (chasedPointProgress < .5f) return; - if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) - checkForMusic(); - if (phase == Phase.SEARCH_OUTPUTS) - searchForDestination(); + + switch (phase){ + case SEARCH_INPUTS: + case DANCING: + checkForMusic(); + break; + case SEARCH_OUTPUTS: + searchForDestination(); + break; + } } private void checkForMusic() { @@ -240,14 +264,27 @@ public void destroy() { private ArmInteractionPoint getTargetedInteractionPoint() { if (chasedPointIndex == -1) return null; - if (phase == Phase.MOVE_TO_INPUT && chasedPointIndex < inputs.size()) - return inputs.get(chasedPointIndex); - if (phase == Phase.MOVE_TO_OUTPUT && chasedPointIndex < outputs.size()) - return outputs.get(chasedPointIndex); + + switch (phase){ + case MOVE_TO_INPUT: + if(chasedPointIndex < inputs.size()) + { + return inputs.get(chasedPointIndex); + } + break; + case MOVE_TO_OUTPUT: + if(chasedPointIndex < outputs.size()) + { + return outputs.get(chasedPointIndex); + } + break; + } return null; } protected void searchForItem() { + Create.LOGGER.info("searchForItem"); + if (redstoneLocked) return; @@ -267,7 +304,9 @@ protected void searchForItem() { ArmInteractionPoint armInteractionPoint = inputs.get(i); if (!armInteractionPoint.isValid()) continue; - for (int j = 0; j < armInteractionPoint.getSlotCount(); j++) { + + int slotCount = armInteractionPoint.getSlotCount(); + for (int j = 0; j < slotCount; j++) { if (getDistributableAmount(armInteractionPoint, j) == 0) continue; @@ -365,6 +404,7 @@ protected void depositItem() { ItemStack toInsert = heldItem.copy(); ItemStack remainder = armInteractionPoint.insert(toInsert, false); heldItem = remainder; + forceSearchInputsTicks = 30; // might need it's own static variable. this should be atleast one frame if you want the arm to jump to another action quickly if (armInteractionPoint instanceof JukeboxPoint && remainder.isEmpty()) award(AllAdvancements.MUSICAL_ARM); @@ -382,8 +422,10 @@ protected void depositItem() { protected void collectItem() { ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); - if (armInteractionPoint != null && armInteractionPoint.isValid()) - for (int i = 0; i < armInteractionPoint.getSlotCount(); i++) { + if (armInteractionPoint != null && armInteractionPoint.isValid()) { + + int slotCount = armInteractionPoint.getSlotCount(); + for (int i = 0; i < slotCount; i++) { int amountExtracted = getDistributableAmount(armInteractionPoint, i); if (amountExtracted == 0) continue; @@ -401,6 +443,7 @@ protected void collectItem() { .5f + Create.RANDOM.nextFloat() * .25f); return; } + } phase = Phase.SEARCH_INPUTS; chasedPointProgress = 0; @@ -608,6 +651,12 @@ public void setLevel(Level level) { for (ArmInteractionPoint output : outputs) { output.setLevel(level); } + + // ensures that not all mechanical arms search for targets on the same tick while in SEARCH_INPUTS phase + // this only needs to be done on the server side + if (!level.isClientSide) { + randomSearchTickOffset = LastRandomSearchTickOffset++; + } } private class SelectionModeValueBox extends CenteredSideValueBoxTransform {