Mind the gap

- Fixed trapdoors and doors causing a contraption to flicker when activated
- Hastily added a few ticks of extra time before a contraption is discarded on the client to close the time gap between entity and chunk render
This commit is contained in:
simibubi 2022-06-20 00:50:05 +02:00
parent d1570736c5
commit 56ec2f127c
7 changed files with 44 additions and 25 deletions

View file

@ -90,6 +90,15 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
protected boolean prevPosInvalid; protected boolean prevPosInvalid;
private boolean skipActorStop; 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) { public AbstractContraptionEntity(EntityType<?> entityTypeIn, Level worldIn) {
super(entityTypeIn, worldIn); super(entityTypeIn, worldIn);
prevPosInvalid = true; prevPosInvalid = true;
@ -168,7 +177,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
callback.accept(passenger, transformedVector.x, callback.accept(passenger, transformedVector.x,
transformedVector.y + SeatEntity.getCustomEntitySeatOffset(passenger) - 1 / 8f, transformedVector.z); transformedVector.y + SeatEntity.getCustomEntitySeatOffset(passenger) - 1 / 8f, transformedVector.z);
} }
protected Vec3 getPassengerPosition(Entity passenger, float partialTicks) { protected Vec3 getPassengerPosition(Entity passenger, float partialTicks) {
UUID id = passenger.getUUID(); UUID id = passenger.getUUID();
if (passenger instanceof OrientedContraptionEntity) { if (passenger instanceof OrientedContraptionEntity) {
@ -309,6 +318,14 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
tickContraption(); tickContraption();
super.tick(); super.tick();
if (level.isClientSide())
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
if (!contraption.deferInvalidate)
return;
contraption.deferInvalidate = false;
ContraptionRenderDispatcher.invalidate(contraption);
});
if (!(level instanceof ServerLevelAccessor sl)) if (!(level instanceof ServerLevelAccessor sl))
return; return;
@ -695,7 +712,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
StructureBlockInfo info = contraption.blocks.get(localPos); StructureBlockInfo info = contraption.blocks.get(localPos);
contraption.blocks.put(localPos, new StructureBlockInfo(info.pos, newState, info.nbt)); contraption.blocks.put(localPos, new StructureBlockInfo(info.pos, newState, info.nbt));
if (info.state != newState && !(newState.getBlock() instanceof SlidingDoorBlock)) if (info.state != newState && !(newState.getBlock() instanceof SlidingDoorBlock))
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ContraptionRenderDispatcher.invalidate(contraption)); contraption.deferInvalidate = true;
contraption.invalidateColliders(); contraption.invalidateColliders();
} }
@ -851,4 +868,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
return initialized; return initialized;
} }
public boolean isAliveOrStale() {
return isAlive() || level.isClientSide() ? staleTicks > 0 : false;
}
} }

View file

@ -151,6 +151,7 @@ public abstract class Contraption {
public List<BlockEntity> specialRenderedTileEntities; public List<BlockEntity> specialRenderedTileEntities;
protected ContraptionWorld world; protected ContraptionWorld world;
public boolean deferInvalidate;
public Contraption() { public Contraption() {
blocks = new HashMap<>(); blocks = new HashMap<>();

View file

@ -45,10 +45,15 @@ public class ContraptionHandler {
for (Iterator<WeakReference<AbstractContraptionEntity>> iterator = values.iterator(); iterator.hasNext();) { for (Iterator<WeakReference<AbstractContraptionEntity>> iterator = values.iterator(); iterator.hasNext();) {
WeakReference<AbstractContraptionEntity> weakReference = iterator.next(); WeakReference<AbstractContraptionEntity> weakReference = iterator.next();
AbstractContraptionEntity contraptionEntity = weakReference.get(); AbstractContraptionEntity contraptionEntity = weakReference.get();
if (contraptionEntity == null || !contraptionEntity.isAlive()) { if (contraptionEntity == null || !contraptionEntity.isAliveOrStale()) {
iterator.remove(); iterator.remove();
continue; continue;
} }
if (!contraptionEntity.isAlive()) {
contraptionEntity.staleTicks--;
continue;
}
ContraptionCollider.collideEntities(contraptionEntity); ContraptionCollider.collideEntities(contraptionEntity);
} }
} }

View file

@ -2,16 +2,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement;
import org.apache.commons.lang3.tuple.MutablePair; 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.core.BlockPos;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; 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 { public abstract class MovingInteractionBehaviour {
@ -22,7 +17,7 @@ public abstract class MovingInteractionBehaviour {
contraptionEntity.contraption.actors.remove(index); contraptionEntity.contraption.actors.remove(index);
contraptionEntity.contraption.actors.add(index, MutablePair.of(info, ctx)); contraptionEntity.contraption.actors.add(index, MutablePair.of(info, ctx));
if (contraptionEntity.level.isClientSide) if (contraptionEntity.level.isClientSide)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> invalidate(contraptionEntity.contraption)); contraptionEntity.contraption.deferInvalidate = true;
} }
protected void setContraptionBlockData(AbstractContraptionEntity contraptionEntity, BlockPos pos, protected void setContraptionBlockData(AbstractContraptionEntity contraptionEntity, BlockPos pos,
@ -32,11 +27,6 @@ public abstract class MovingInteractionBehaviour {
contraptionEntity.setBlock(pos, info); contraptionEntity.setBlock(pos, info);
} }
@OnlyIn(Dist.CLIENT)
protected void invalidate(Contraption contraption) {
ContraptionRenderDispatcher.invalidate(contraption);
}
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
AbstractContraptionEntity contraptionEntity) { AbstractContraptionEntity contraptionEntity) {
return true; return true;

View file

@ -26,7 +26,7 @@ public class ContraptionEntityRenderer<C extends AbstractContraptionEntity> exte
double cameraZ) { double cameraZ) {
if (entity.getContraption() == null) if (entity.getContraption() == null)
return false; return false;
if (!entity.isAlive()) if (!entity.isAliveOrStale())
return false; return false;
if (!entity.isReadyForRender()) if (!entity.isReadyForRender())
return false; return false;

View file

@ -21,24 +21,26 @@ public class ContraptionRenderInfo {
this.renderWorld = renderWorld; this.renderWorld = renderWorld;
} }
public int getEntityId() { public int getEntityId() {
return contraption.entity.getId(); return contraption.entity.getId();
} }
public boolean isDead() { public boolean isDead() {
return !contraption.entity.isAlive(); return !contraption.entity.isAliveOrStale();
} }
public void beginFrame(BeginFrameEvent event) { public void beginFrame(BeginFrameEvent event) {
matrices.clear(); matrices.clear();
AbstractContraptionEntity entity = contraption.entity; AbstractContraptionEntity entity = contraption.entity;
visible = event.getFrustum().isVisible(entity.getBoundingBoxForCulling().inflate(2)); visible = event.getFrustum()
.isVisible(entity.getBoundingBoxForCulling()
.inflate(2));
} }
public boolean isVisible() { public boolean isVisible() {
return visible && contraption.entity.isAlive() && contraption.entity.isReadyForRender(); return visible && contraption.entity.isAliveOrStale() && contraption.entity.isReadyForRender();
} }
/** /**

View file

@ -762,7 +762,7 @@ public class Carriage {
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
private void invalidate(CarriageContraptionEntity entity) { private void invalidate(CarriageContraptionEntity entity) {
ContraptionRenderDispatcher.invalidate(entity.getContraption()); entity.getContraption().deferInvalidate = true;
entity.updateRenderedPortalCutoff(); entity.updateRenderedPortalCutoff();
} }