From 555e27543a789c6cf7d1957ca55f1c8a3dca126c Mon Sep 17 00:00:00 2001 From: KptKosmit91 Date: Wed, 4 Jun 2025 19:16:38 +0200 Subject: [PATCH 1/3] 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 { From 444a5a8abe2856dbe0bed92a0bd6b975be8fec53 Mon Sep 17 00:00:00 2001 From: KptKosmit91 Date: Wed, 4 Jun 2025 19:24:59 +0200 Subject: [PATCH 2/3] Update forceSearchInputsTicks and update comment --- .../create/content/kinetics/mechanicalArm/ArmBlockEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 00f176e5a5..2db87e6287 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 @@ -404,7 +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 + forceSearchInputsTicks = 5; // might need it's own static variable. this should be atleast one tick if you want the arm to jump to another action quickly (for example when refilling blaze burners) if (armInteractionPoint instanceof JukeboxPoint && remainder.isEmpty()) award(AllAdvancements.MUSICAL_ARM); From 88a37b4093a0ba8a689bc1377c2a65cc9d81beb6 Mon Sep 17 00:00:00 2001 From: KptKosmit91 Date: Thu, 5 Jun 2025 00:39:43 +0200 Subject: [PATCH 3/3] Remove leftover log print --- .../create/content/kinetics/mechanicalArm/ArmBlockEntity.java | 2 -- 1 file changed, 2 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 2db87e6287..98b96a38a7 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 @@ -283,8 +283,6 @@ private ArmInteractionPoint getTargetedInteractionPoint() { } protected void searchForItem() { - Create.LOGGER.info("searchForItem"); - if (redstoneLocked) return;