diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index aabb27563..5928f748a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -90,6 +90,15 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit protected boolean prevPosInvalid; private boolean skipActorStop; + /* + * staleTicks are a band-aid to prevent a frame or two of missing blocks between + * contraption discard and off-thread block placement on disassembly + * + * FIXME this timeout should be longer but then also cancelled early based on a + * chunk rebuild listener + */ + public int staleTicks = 3; + public AbstractContraptionEntity(EntityType entityTypeIn, Level worldIn) { super(entityTypeIn, worldIn); prevPosInvalid = true; @@ -168,7 +177,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit callback.accept(passenger, transformedVector.x, transformedVector.y + SeatEntity.getCustomEntitySeatOffset(passenger) - 1 / 8f, transformedVector.z); } - + protected Vec3 getPassengerPosition(Entity passenger, float partialTicks) { UUID id = passenger.getUUID(); if (passenger instanceof OrientedContraptionEntity) { @@ -309,6 +318,14 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit tickContraption(); super.tick(); + if (level.isClientSide()) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + if (!contraption.deferInvalidate) + return; + contraption.deferInvalidate = false; + ContraptionRenderDispatcher.invalidate(contraption); + }); + if (!(level instanceof ServerLevelAccessor sl)) return; @@ -695,7 +712,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit StructureBlockInfo info = contraption.blocks.get(localPos); contraption.blocks.put(localPos, new StructureBlockInfo(info.pos, newState, info.nbt)); if (info.state != newState && !(newState.getBlock() instanceof SlidingDoorBlock)) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ContraptionRenderDispatcher.invalidate(contraption)); + contraption.deferInvalidate = true; contraption.invalidateColliders(); } @@ -851,4 +868,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit return initialized; } + public boolean isAliveOrStale() { + return isAlive() || level.isClientSide() ? staleTicks > 0 : false; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 601272f14..227bb0312 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -151,6 +151,7 @@ public abstract class Contraption { public List specialRenderedTileEntities; protected ContraptionWorld world; + public boolean deferInvalidate; public Contraption() { blocks = new HashMap<>(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java index 0437622ed..84f6b2a49 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java @@ -45,10 +45,15 @@ public class ContraptionHandler { for (Iterator> iterator = values.iterator(); iterator.hasNext();) { WeakReference weakReference = iterator.next(); AbstractContraptionEntity contraptionEntity = weakReference.get(); - if (contraptionEntity == null || !contraptionEntity.isAlive()) { + if (contraptionEntity == null || !contraptionEntity.isAliveOrStale()) { iterator.remove(); continue; } + if (!contraptionEntity.isAlive()) { + contraptionEntity.staleTicks--; + continue; + } + ContraptionCollider.collideEntities(contraptionEntity); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java index 9f2796e04..5f411f98f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java @@ -2,16 +2,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import org.apache.commons.lang3.tuple.MutablePair; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; - import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; public abstract class MovingInteractionBehaviour { @@ -22,7 +17,7 @@ public abstract class MovingInteractionBehaviour { contraptionEntity.contraption.actors.remove(index); contraptionEntity.contraption.actors.add(index, MutablePair.of(info, ctx)); if (contraptionEntity.level.isClientSide) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> invalidate(contraptionEntity.contraption)); + contraptionEntity.contraption.deferInvalidate = true; } protected void setContraptionBlockData(AbstractContraptionEntity contraptionEntity, BlockPos pos, @@ -32,11 +27,6 @@ public abstract class MovingInteractionBehaviour { contraptionEntity.setBlock(pos, info); } - @OnlyIn(Dist.CLIENT) - protected void invalidate(Contraption contraption) { - ContraptionRenderDispatcher.invalidate(contraption); - } - public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, AbstractContraptionEntity contraptionEntity) { return true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java index 55c5e0c88..9a9a965c5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java @@ -26,7 +26,7 @@ public class ContraptionEntityRenderer exte double cameraZ) { if (entity.getContraption() == null) return false; - if (!entity.isAlive()) + if (!entity.isAliveOrStale()) return false; if (!entity.isReadyForRender()) return false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java index a903397f7..857a1ec4b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java @@ -21,24 +21,26 @@ public class ContraptionRenderInfo { this.renderWorld = renderWorld; } - public int getEntityId() { - return contraption.entity.getId(); - } + public int getEntityId() { + return contraption.entity.getId(); + } - public boolean isDead() { - return !contraption.entity.isAlive(); - } + public boolean isDead() { + return !contraption.entity.isAliveOrStale(); + } - public void beginFrame(BeginFrameEvent event) { + public void beginFrame(BeginFrameEvent event) { matrices.clear(); AbstractContraptionEntity entity = contraption.entity; - visible = event.getFrustum().isVisible(entity.getBoundingBoxForCulling().inflate(2)); + visible = event.getFrustum() + .isVisible(entity.getBoundingBoxForCulling() + .inflate(2)); } public boolean isVisible() { - return visible && contraption.entity.isAlive() && contraption.entity.isReadyForRender(); + return visible && contraption.entity.isAliveOrStale() && contraption.entity.isReadyForRender(); } /** diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index 30e83ad1d..a0ca3a827 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -762,7 +762,7 @@ public class Carriage { @OnlyIn(Dist.CLIENT) private void invalidate(CarriageContraptionEntity entity) { - ContraptionRenderDispatcher.invalidate(entity.getContraption()); + entity.getContraption().deferInvalidate = true; entity.updateRenderedPortalCutoff(); }