From f45e22496e6de8982532059ebb281adffcd1c575 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:45:13 +0200 Subject: [PATCH] Secret Spinformation - Fixed Bearings, Pistons, Pulleys and Gantries powered by a Sequenced Gearshift not moving precisely to its instructions at high speeds - Minecart contraptions no longer visually jump to a location when stalled - Mechanical bearings now snap to a rounded angle when stopped --- .../contraptions/RotationPropagator.java | 13 +++-- .../contraptions/base/KineticBlockEntity.java | 19 ++++++- .../bearing/MechanicalBearingBlockEntity.java | 36 ++++++++++++-- .../gantry/GantryCarriageBlockEntity.java | 11 +++-- .../gantry/GantryContraptionEntity.java | 49 +++++++++++++++---- .../gantry/GantryContraptionUpdatePacket.java | 6 ++- .../piston/LinearActuatorBlockEntity.java | 33 +++++++++++++ .../piston/MechanicalPistonBlockEntity.java | 2 + .../train/capability/MinecartController.java | 2 +- .../advanced/GantryShaftBlockEntity.java | 5 ++ .../advanced/sequencer/Instruction.java | 15 ++---- .../SequencedGearshiftBlockEntity.java | 37 ++++++++++++++ .../sequencer/SequencerInstructions.java | 4 ++ 13 files changed, 197 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java b/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java index 51c28737e..0cbe0c8ed 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java +++ b/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java @@ -426,14 +426,17 @@ public class RotationPropagator { private static List getPotentialNeighbourLocations(KineticBlockEntity be) { List neighbours = new LinkedList<>(); + BlockPos blockPos = be.getBlockPos(); + Level level = be.getLevel(); - if (!be.getLevel() - .isAreaLoaded(be.getBlockPos(), 1)) + if (!level.isLoaded(blockPos)) return neighbours; - for (Direction facing : Iterate.directions) - neighbours.add(be.getBlockPos() - .relative(facing)); + for (Direction facing : Iterate.directions) { + BlockPos relative = blockPos.relative(facing); + if (level.isLoaded(relative)) + neighbours.add(relative); + } BlockState blockState = be.getBlockState(); if (!(blockState.getBlock() instanceof IRotate)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlockEntity.java index 159011d15..c637f7867 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlockEntity.java @@ -15,6 +15,7 @@ import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftBlockEntity.SequenceContext; import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxBlock; import com.simibubi.create.foundation.block.BlockStressValues; @@ -67,6 +68,8 @@ public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleI private int validationCountdown; protected float lastStressApplied; protected float lastCapacityProvided; + + public SequenceContext sequenceContext; public KineticBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { super(typeIn, pos, state); @@ -197,6 +200,8 @@ public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleI @Override protected void write(CompoundTag compound, boolean clientPacket) { compound.putFloat("Speed", speed); + if (sequenceContext != null && (!clientPacket || syncSequenceContext())) + compound.put("Sequence", sequenceContext.serializeNBT()); if (needsSpeedUpdate()) compound.putBoolean("NeedsSpeedUpdate", true); @@ -238,6 +243,7 @@ public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleI } speed = compound.getFloat("Speed"); + sequenceContext = SequenceContext.fromNBT(compound.getCompound("Sequence")); if (compound.contains("Source")) source = NbtUtils.readBlockPos(compound.getCompound("Source")); @@ -294,13 +300,17 @@ public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleI return; BlockEntity blockEntity = level.getBlockEntity(source); - if (!(blockEntity instanceof KineticBlockEntity)) { + if (!(blockEntity instanceof KineticBlockEntity sourceBE)) { removeSource(); return; } - KineticBlockEntity sourceBE = (KineticBlockEntity) blockEntity; setNetwork(sourceBE.network); + copySequenceContextFrom(sourceBE); + } + + protected void copySequenceContextFrom(KineticBlockEntity sourceBE) { + sequenceContext = sourceBE.sequenceContext; } public void removeSource() { @@ -309,6 +319,7 @@ public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleI speed = 0; source = null; setNetwork(null); + sequenceContext = null; onSpeedChanged(prevSpeed); } @@ -592,5 +603,9 @@ public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleI public int getRotationAngleOffset(Axis axis) { return 0; } + + protected boolean syncSequenceContext() { + return false; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlockEntity.java index 8a92027e3..76f975ce9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlockEntity.java @@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Abs import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencerInstructions; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollOptionBehaviour; @@ -35,12 +36,14 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity protected boolean assembleNextTick; protected float clientAngleDiff; protected AssemblyException lastException; + protected double sequencedAngleLimit; private float prevAngle; public MechanicalBearingBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); setLazyTickRate(3); + sequencedAngleLimit = -1; } @Override @@ -48,11 +51,16 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity return false; } + @Override + protected boolean syncSequenceContext() { + return true; + } + @Override public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); - movementMode = new ScrollOptionBehaviour<>(RotationMode.class, Lang.translateDirect("contraptions.movement_mode"), - this, getMovementModeSlot()); + movementMode = new ScrollOptionBehaviour<>(RotationMode.class, + Lang.translateDirect("contraptions.movement_mode"), this, getMovementModeSlot()); movementMode.requiresWrench(); behaviours.add(movementMode); registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); @@ -69,6 +77,8 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity public void write(CompoundTag compound, boolean clientPacket) { compound.putBoolean("Running", running); compound.putFloat("Angle", angle); + if (sequencedAngleLimit >= 0) + compound.putDouble("SequencedAngleLimit", sequencedAngleLimit); AssemblyException.write(compound, lastException); super.write(compound, clientPacket); } @@ -83,6 +93,7 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity float angleBefore = angle; running = compound.getBoolean("Running"); angle = compound.getFloat("Angle"); + sequencedAngleLimit = compound.contains("SequencedAngleLimit") ? compound.getDouble("SequencedAngleLimit") : -1; lastException = AssemblyException.read(compound); super.read(compound, clientPacket); if (!clientPacket) @@ -102,18 +113,30 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity return Mth.lerp(partialTicks + .5f, prevAngle, angle); if (movedContraption == null || movedContraption.isStalled() || !running) partialTicks = 0; - return Mth.lerp(partialTicks, angle, angle + getAngularSpeed()); + float angularSpeed = getAngularSpeed(); + if (sequencedAngleLimit >= 0) + angularSpeed = (float) Mth.clamp(angularSpeed, -sequencedAngleLimit, sequencedAngleLimit); + return Mth.lerp(partialTicks, angle, angle + angularSpeed); } @Override public void onSpeedChanged(float prevSpeed) { super.onSpeedChanged(prevSpeed); assembleNextTick = true; + sequencedAngleLimit = -1; if (movedContraption != null && Math.signum(prevSpeed) != Math.signum(getSpeed()) && prevSpeed != 0) { + if (!movedContraption.isStalled()) { + angle = Math.round(angle); + applyRotation(); + } movedContraption.getContraption() .stop(level); } + + if (!isWindmill() && sequenceContext != null + && sequenceContext.instruction() == SequencerInstructions.TURN_ANGLE) + sequencedAngleLimit = sequenceContext.getEffectiveValue(getTheoreticalSpeed()); } public float getAngularSpeed() { @@ -172,7 +195,7 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity level.addFreshEntity(movedContraption); AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); - + if (contraption.containsBlockBreakers()) award(AllAdvancements.CONTRAPTION_ACTORS); @@ -186,6 +209,7 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity if (!running && movedContraption == null) return; angle = 0; + sequencedAngleLimit = -1; if (isWindmill()) applyRotation(); if (movedContraption != null) { @@ -234,6 +258,10 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity if (!(movedContraption != null && movedContraption.isStalled())) { float angularSpeed = getAngularSpeed(); + if (sequencedAngleLimit >= 0) { + angularSpeed = (float) Mth.clamp(angularSpeed, -sequencedAngleLimit, sequencedAngleLimit); + sequencedAngleLimit = Math.max(0, sequencedAngleLimit - Math.abs(angularSpeed)); + } float newAngle = angle + angularSpeed; angle = (float) (newAngle % 360); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlockEntity.java index b625c6134..e021dbafe 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlockEntity.java @@ -10,6 +10,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlockEntity; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencerInstructions; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; @@ -83,14 +84,14 @@ public class GantryCarriageBlockEntity extends KineticBlockEntity implements IDi Direction direction = blockState.getValue(GantryCarriageBlock.FACING); GantryContraption contraption = new GantryContraption(direction); - BlockEntity shaftBE = level.getBlockEntity(worldPosition.relative(direction.getOpposite())); - if (!(shaftBE instanceof GantryShaftBlockEntity)) + BlockEntity blockEntity = level.getBlockEntity(worldPosition.relative(direction.getOpposite())); + if (!(blockEntity instanceof GantryShaftBlockEntity shaftBE)) return; BlockState shaftState = shaftBE.getBlockState(); if (!AllBlocks.GANTRY_SHAFT.has(shaftState)) return; - float pinionMovementSpeed = ((GantryShaftBlockEntity) shaftBE).getPinionMovementSpeed(); + float pinionMovementSpeed = shaftBE.getPinionMovementSpeed(); Direction shaftOrientation = shaftState.getValue(GantryShaftBlock.FACING); Direction movementDirection = shaftOrientation; if (pinionMovementSpeed < 0) @@ -121,6 +122,10 @@ public class GantryCarriageBlockEntity extends KineticBlockEntity implements IDi movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); level.addFreshEntity(movedContraption); + + if (shaftBE.sequenceContext != null + && shaftBE.sequenceContext.instruction() == SequencerInstructions.TURN_DISTANCE) + movedContraption.limitMovement(shaftBE.sequenceContext.getEffectiveValue(shaftBE.getTheoreticalSpeed())); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java index ab632ccb4..c7bef330b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java @@ -12,6 +12,7 @@ import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.ServerSpeedProvider; +import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; @@ -34,8 +35,11 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { double clientOffsetDiff; double axisMotion; + public double sequencedOffsetLimit; + public GantryContraptionEntity(EntityType entityTypeIn, Level worldIn) { super(entityTypeIn, worldIn); + sequencedOffsetLimit = -1; } public static GantryContraptionEntity create(Level world, Contraption contraption, Direction movementAxis) { @@ -45,6 +49,10 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { return entity; } + public void limitMovement(double maxOffset) { + sequencedOffsetLimit = maxOffset; + } + @Override protected void tickContraption() { if (!(contraption instanceof GantryContraption)) @@ -66,8 +74,13 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { return; } - if (!isStalled() && tickCount > 2) + if (!isStalled() && tickCount > 2) { + if (sequencedOffsetLimit >= 0) + movementVec = VecHelper.clampComponentWise(movementVec, (float) sequencedOffsetLimit); move(movementVec.x, movementVec.y, movementVec.z); + if (sequencedOffsetLimit > 0) + sequencedOffsetLimit = Math.max(0, sequencedOffsetLimit - movementVec.length()); + } if (Math.signum(prevAxisMotion) != Math.signum(axisMotion) && prevAxisMotion != 0) contraption.stop(level); @@ -75,6 +88,12 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { sendPacket(); } + @Override + public void disassemble() { + sequencedOffsetLimit = -1; + super.disassemble(); + } + protected void checkPinionShaft() { Vec3 movementVec; Direction facing = ((GantryContraption) contraption).getFacing(); @@ -95,8 +114,6 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { GantryShaftBlockEntity gantryShaftBlockEntity = (GantryShaftBlockEntity) be; float pinionMovementSpeed = gantryShaftBlockEntity.getPinionMovementSpeed(); - movementVec = Vec3.atLowerCornerOf(direction.getNormal()).scale(pinionMovementSpeed); - if (blockState.getValue(GantryShaftBlock.POWERED) || pinionMovementSpeed == 0) { setContraptionMotion(Vec3.ZERO); if (!level.isClientSide) @@ -104,6 +121,11 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { return; } + if (sequencedOffsetLimit >= 0) + pinionMovementSpeed = (float) Mth.clamp(pinionMovementSpeed, -sequencedOffsetLimit, sequencedOffsetLimit); + movementVec = Vec3.atLowerCornerOf(direction.getNormal()) + .scale(pinionMovementSpeed); + Vec3 nextPosition = currentPosition.add(movementVec); double currentCoord = direction.getAxis() .choose(currentPosition.x, currentPosition.y, currentPosition.z); @@ -121,7 +143,7 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { if (level.isClientSide) return; - + axisMotion = pinionMovementSpeed; setContraptionMotion(movementVec); } @@ -129,11 +151,15 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { @Override protected void writeAdditional(CompoundTag compound, boolean spawnPacket) { NBTHelper.writeEnum(compound, "GantryAxis", movementAxis); + if (sequencedOffsetLimit >= 0) + compound.putDouble("SequencedOffsetLimit", sequencedOffsetLimit); super.writeAdditional(compound, spawnPacket); } protected void readAdditional(CompoundTag compound, boolean spawnData) { movementAxis = NBTHelper.readEnum(compound, "GantryAxis", Direction.class); + sequencedOffsetLimit = + compound.contains("SequencedOffsetLimit") ? compound.getDouble("SequencedOffsetLimit") : -1; super.readAdditional(compound, spawnData); } @@ -176,13 +202,16 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { } @Override - public void applyLocalTransforms(PoseStack matrixStack, float partialTicks) { } + public void applyLocalTransforms(PoseStack matrixStack, float partialTicks) {} public void updateClientMotion() { float modifier = movementAxis.getAxisDirection() .getStep(); - setContraptionMotion(Vec3.atLowerCornerOf(movementAxis.getNormal()) - .scale((axisMotion + clientOffsetDiff * modifier / 2f) * ServerSpeedProvider.get())); + Vec3 motion = Vec3.atLowerCornerOf(movementAxis.getNormal()) + .scale((axisMotion + clientOffsetDiff * modifier / 2f) * ServerSpeedProvider.get()); + if (sequencedOffsetLimit >= 0) + motion = VecHelper.clampComponentWise(motion, (float) sequencedOffsetLimit); + setContraptionMotion(motion); } public double getAxisCoord() { @@ -192,8 +221,9 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { } public void sendPacket() { - AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> this), - new GantryContraptionUpdatePacket(getId(), getAxisCoord(), axisMotion)); + AllPackets.getChannel() + .send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new GantryContraptionUpdatePacket(getId(), getAxisCoord(), axisMotion, sequencedOffsetLimit)); } @OnlyIn(Dist.CLIENT) @@ -204,6 +234,7 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { GantryContraptionEntity ce = (GantryContraptionEntity) entity; ce.axisMotion = packet.motion; ce.clientOffsetDiff = packet.coord - ce.getAxisCoord(); + ce.sequencedOffsetLimit = packet.sequenceLimit; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java index cce728597..5aea853c7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java @@ -12,17 +12,20 @@ public class GantryContraptionUpdatePacket extends SimplePacketBase { int entityID; double coord; double motion; + double sequenceLimit; - public GantryContraptionUpdatePacket(int entityID, double coord, double motion) { + public GantryContraptionUpdatePacket(int entityID, double coord, double motion, double sequenceLimit) { this.entityID = entityID; this.coord = coord; this.motion = motion; + this.sequenceLimit = sequenceLimit; } public GantryContraptionUpdatePacket(FriendlyByteBuf buffer) { entityID = buffer.readInt(); coord = buffer.readFloat(); motion = buffer.readFloat(); + sequenceLimit = buffer.readFloat(); } @Override @@ -30,6 +33,7 @@ public class GantryContraptionUpdatePacket extends SimplePacketBase { buffer.writeInt(entityID); buffer.writeFloat((float) coord); buffer.writeFloat((float) motion); + buffer.writeFloat((float) sequenceLimit); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorBlockEntity.java index a34d14de0..2ddec2dba 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorBlockEntity.java @@ -9,6 +9,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.IControlContraption; import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; +import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencerInstructions; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; @@ -35,6 +36,7 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity protected ScrollOptionBehaviour movementMode; protected boolean waitingForSpeedChange; protected AssemblyException lastException; + protected double sequencedOffsetLimit; // Custom position sync protected float clientOffsetDiff; @@ -44,6 +46,7 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity setLazyTickRate(3); forceMove = true; needsContraption = true; + sequencedOffsetLimit = -1; } @Override @@ -56,6 +59,11 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity behaviours.add(movementMode); registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); } + + @Override + protected boolean syncSequenceContext() { + return true; + } @Override public void tick() { @@ -113,10 +121,21 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity return; float movementSpeed = getMovementSpeed(); + boolean locked = false; + if (sequencedOffsetLimit > 0) { + sequencedOffsetLimit = Math.max(0, sequencedOffsetLimit - Math.abs(movementSpeed)); + locked = sequencedOffsetLimit == 0; + } float newOffset = offset + movementSpeed; if ((int) newOffset != (int) offset) visitNewPosition(); + if (locked) { + forceMove = true; + resetContraptionToOffset(); + sendData(); + } + if (contraptionPresent) { if (moveAndCollideContraption()) { movedContraption.setContraptionMotion(Vec3.ZERO); @@ -170,6 +189,7 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity @Override public void onSpeedChanged(float prevSpeed) { super.onSpeedChanged(prevSpeed); + sequencedOffsetLimit = -1; if (isPassive()) return; @@ -178,9 +198,16 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity waitingForSpeedChange = false; if (movedContraption != null && Math.signum(prevSpeed) != Math.signum(getSpeed()) && prevSpeed != 0) { + if (!movedContraption.isStalled()) { + offset = Math.round(offset * 16) / 16; + resetContraptionToOffset(); + } movedContraption.getContraption() .stop(level); } + + if (sequenceContext != null && sequenceContext.instruction() == SequencerInstructions.TURN_DISTANCE) + sequencedOffsetLimit = sequenceContext.getEffectiveValue(getTheoreticalSpeed()); } @Override @@ -196,6 +223,8 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity compound.putBoolean("Running", running); compound.putBoolean("Waiting", waitingForSpeedChange); compound.putFloat("Offset", offset); + if (sequencedOffsetLimit >= 0) + compound.putDouble("SequencedOffsetLimit", sequencedOffsetLimit); AssemblyException.write(compound, lastException); super.write(compound, clientPacket); @@ -213,6 +242,8 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity running = compound.getBoolean("Running"); waitingForSpeedChange = compound.getBoolean("Waiting"); offset = compound.getFloat("Offset"); + sequencedOffsetLimit = + compound.contains("SequencedOffsetLimit") ? compound.getDouble("SequencedOffsetLimit") : -1; lastException = AssemblyException.read(compound); super.read(compound, clientPacket); @@ -309,6 +340,8 @@ public abstract class LinearActuatorBlockEntity extends KineticBlockEntity float movementSpeed = Mth.clamp(convertToLinear(getSpeed()), -.49f, .49f) + clientOffsetDiff / 2f; if (level.isClientSide) movementSpeed *= ServerSpeedProvider.get(); + if (sequencedOffsetLimit >= 0) + movementSpeed = (float) Mth.clamp(movementSpeed, -sequencedOffsetLimit, sequencedOffsetLimit); return movementSpeed; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlockEntity.java index 7f40d4d88..7daf574ab 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlockEntity.java @@ -132,6 +132,8 @@ public class MechanicalPistonBlockEntity extends LinearActuatorBlockEntity { int extensionRange = getExtensionRange(); movementSpeed = Mth.clamp(movementSpeed, 0 - offset, extensionRange - offset); + if (sequencedOffsetLimit >= 0) + movementSpeed = (float) Mth.clamp(movementSpeed, -sequencedOffsetLimit, sequencedOffsetLimit); return movementSpeed; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java index 7e73cc880..2ba6b3de1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java @@ -404,7 +404,7 @@ public class MinecartController implements INBTSerializable { } void tick(AbstractMinecart entity) { - entity.setPos(position.x, position.y, position.z); +// entity.setPos(position.x, position.y, position.z); entity.setDeltaMovement(Vec3.ZERO); entity.setYRot(yaw); entity.setXRot(pitch); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlockEntity.java index f2e61ba57..ae9fd10ce 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlockEntity.java @@ -19,6 +19,11 @@ public class GantryShaftBlockEntity extends KineticBlockEntity { super(typeIn, pos, state); } + @Override + protected boolean syncSequenceContext() { + return true; + } + public void checkAttachedCarriageBlocks() { if (!canAssembleOn()) return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java index e27f6e386..206cb444f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java @@ -27,28 +27,23 @@ public class Instruction { int getDuration(float currentProgress, float speed) { speed *= speedModifier.value; speed = Math.abs(speed); - double target = value - currentProgress; switch (instruction) { + // Always overshoot, target will stop early case TURN_ANGLE: double degreesPerTick = KineticBlockEntity.convertToAngular(speed); - int ticks = (int) (target / degreesPerTick); - double degreesErr = target - degreesPerTick*ticks; - return ticks + (degreesPerTick > 2*degreesErr ? 0 : 1); - + return (int) Math.ceil(target / degreesPerTick) + 2; case TURN_DISTANCE: double metersPerTick = KineticBlockEntity.convertToLinear(speed); - int offset = speed > 0 && speedModifier.value < 0 ? 1 : 2; - return (int) (target / metersPerTick + offset); + return (int) Math.ceil(target / metersPerTick) + 2; + // Timing instructions case DELAY: return (int) target; - case AWAIT: return -1; - case END: default: break; @@ -58,7 +53,7 @@ public class Instruction { } float getTickProgress(float speed) { - switch(instruction) { + switch (instruction) { case TURN_ANGLE: return KineticBlockEntity.convertToAngular(speed); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlockEntity.java index fb4bb194a..ba7c59007 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlockEntity.java @@ -2,7 +2,9 @@ package com.simibubi.create.content.contraptions.relays.advanced.sequencer; import java.util.Vector; +import com.simibubi.create.content.contraptions.base.KineticBlockEntity; import com.simibubi.create.content.contraptions.relays.encased.SplitShaftBlockEntity; +import com.simibubi.create.foundation.utility.NBTHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -20,6 +22,35 @@ public class SequencedGearshiftBlockEntity extends SplitShaftBlockEntity { int timer; boolean poweredPreviously; + public record SequenceContext(SequencerInstructions instruction, double relativeValue) { + + static SequenceContext fromGearshift(SequencerInstructions instruction, double kineticSpeed, + int absoluteValue) { + return instruction.needsPropagation() + ? new SequenceContext(instruction, kineticSpeed == 0 ? 0 : absoluteValue / kineticSpeed) + : null; + } + + public double getEffectiveValue(double speedAtTarget) { + return Math.abs(relativeValue * speedAtTarget); + } + + public CompoundTag serializeNBT() { + CompoundTag nbt = new CompoundTag(); + NBTHelper.writeEnum(nbt, "Mode", instruction); + nbt.putDouble("Value", relativeValue); + return nbt; + } + + public static SequenceContext fromNBT(CompoundTag nbt) { + if (nbt.isEmpty()) + return null; + return new SequenceContext(NBTHelper.readEnum(nbt, "Mode", SequencerInstructions.class), + nbt.getDouble("Value")); + } + + } + public SequencedGearshiftBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); instructions = Instruction.createDefault(); @@ -113,6 +144,7 @@ public class SequencedGearshiftBlockEntity extends SplitShaftBlockEntity { currentInstruction = -1; currentInstructionDuration = -1; currentInstructionProgress = 0; + sequenceContext = null; timer = 0; if (!level.hasNeighborSignal(worldPosition)) level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, 0), 3); @@ -125,6 +157,8 @@ public class SequencedGearshiftBlockEntity extends SplitShaftBlockEntity { currentInstructionDuration = instruction.getDuration(0, getTheoreticalSpeed()); currentInstruction = instructionIndex; currentInstructionProgress = 0; + sequenceContext = SequenceContext.fromGearshift(instruction.instruction, getTheoreticalSpeed() * getModifier(), + instruction.value); timer = 0; level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, instructionIndex + 1), 3); } @@ -134,6 +168,9 @@ public class SequencedGearshiftBlockEntity extends SplitShaftBlockEntity { : null; } + @Override + protected void copySequenceContextFrom(KineticBlockEntity sourceBE) {} + @Override public void write(CompoundTag compound, boolean clientPacket) { compound.putInt("InstructionIndex", currentInstruction); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java index 060a0df7e..dd2a73285 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java @@ -44,6 +44,10 @@ public enum SequencerInstructions { descriptiveTranslationKey = translationKey + ".descriptive"; parameterKey = translationKey + "." + parameterName; } + + public boolean needsPropagation() { + return this == TURN_ANGLE || this == TURN_DISTANCE; + } static List getOptions() { List options = new ArrayList<>();