Defer ticking on TEs we eagerly create until they get a description packet (#2018)

This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-08-15 17:04:50 -07:00
1 parent 69aed42b89
commit bf9492dffb
7 files changed
+105 -8

No files matched your search

@@ -387,6 +387,7 @@ public enum Mixins implements IMixins {
, "celeritas.terrain.MixinWorld_WorkerMutationGuard"
, "celeritas.terrain.MixinTileEntity_AwaitingDescriptor"
, "celeritas.terrain.MixinNetHandlerPlayClient_DescriptorRepair"
, "celeritas.terrain.MixinWorld_AwaitingDescriptor"
, "celeritas.terrain.MixinRenderRegion"
, "celeritas.terrain.MixinSectionRenderDataStorage"
, "celeritas.terrain.MixinDefaultChunkRenderer"
@@ -1,8 +1,12 @@
package com.gtnewhorizons.angelica.mixins.interfaces;
public interface IAwaitingDescriptorTE {
public interface AwaitingDescriptorTE {
boolean angelica$isAwaitingDescriptor();
void angelica$setAwaitingDescriptor(boolean awaiting);
int angelica$getDescriptorWaitTicks();
void angelica$setDescriptorWaitTicks(int ticks);
}
@@ -0,0 +1,58 @@
package com.gtnewhorizons.angelica.utils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.tileentity.TileEntity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.gtnewhorizons.angelica.mixins.interfaces.AwaitingDescriptorTE;
public final class AwaitingDescriptor {
private static final Logger LOGGER = LogManager.getLogger("Angelica");
private static final int WAIT_TICKS = 100;
private static final Map<Class<?>, Boolean> SENDS_DESCRIPTOR = new ConcurrentHashMap<>();
private AwaitingDescriptor() {}
public static void begin(TileEntity te) {
if (!SENDS_DESCRIPTOR.computeIfAbsent(te.getClass(), AwaitingDescriptor::sendsDescriptor)) return;
final AwaitingDescriptorTE tile = (AwaitingDescriptorTE) te;
tile.angelica$setAwaitingDescriptor(true);
tile.angelica$setDescriptorWaitTicks(WAIT_TICKS);
}
public static void end(AwaitingDescriptorTE tile) {
tile.angelica$setAwaitingDescriptor(false);
tile.angelica$setDescriptorWaitTicks(0);
}
public static boolean defersUpdate(TileEntity te) {
final AwaitingDescriptorTE tile = (AwaitingDescriptorTE) te;
final int waiting = tile.angelica$getDescriptorWaitTicks();
if (waiting <= 0) return false;
tile.angelica$setDescriptorWaitTicks(waiting - 1);
if (waiting == 1) stopWaitingOn(te.getClass());
return true;
}
private static boolean sendsDescriptor(Class<?> cls) {
try {
return cls.getMethod("getDescriptionPacket").getDeclaringClass() != TileEntity.class;
} catch (NoSuchMethodException e) {
return false;
}
}
private static void stopWaitingOn(Class<?> cls) {
if (!Boolean.TRUE.equals(SENDS_DESCRIPTOR.put(cls, Boolean.FALSE))) return;
LOGGER.warn("{} declares getDescriptionPacket() but never sent one", cls.getName());
}
}
@@ -23,10 +23,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.gtnewhorizon.gtnhlib.hash.Fnv1a64;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.event.ChunkBiomeDataChangedEvent;
import com.gtnewhorizons.angelica.mixins.interfaces.IAwaitingDescriptorTE;
import com.gtnewhorizons.angelica.mixins.interfaces.IChunkTileEntityMapHolder;
import com.gtnewhorizons.angelica.rendering.RenderThreadContext;
import com.gtnewhorizons.angelica.rendering.celeritas.world.WorldSlice;
import com.gtnewhorizons.angelica.utils.AwaitingDescriptor;
import com.gtnewhorizons.angelica.utils.ConcurrentTileEntityMap;
@Mixin(Chunk.class)
@@ -138,7 +138,7 @@ public abstract class MixinChunk implements IChunkTileEntityMapHolder {
te.xCoord = (this.xPosition << 4) + x;
te.yCoord = worldY;
te.zCoord = (this.zPosition << 4) + z;
((IAwaitingDescriptorTE) te).angelica$setAwaitingDescriptor(true);
AwaitingDescriptor.begin(te);
this.addTileEntity(te);
}
}
@@ -8,7 +8,8 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import com.gtnewhorizons.angelica.mixins.interfaces.IAwaitingDescriptorTE;
import com.gtnewhorizons.angelica.mixins.interfaces.AwaitingDescriptorTE;
import com.gtnewhorizons.angelica.utils.AwaitingDescriptor;
@Mixin(NetHandlerPlayClient.class)
public class MixinNetHandlerPlayClient_DescriptorRepair {
@@ -17,8 +18,8 @@ public class MixinNetHandlerPlayClient_DescriptorRepair {
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getTileEntity(III)Lnet/minecraft/tileentity/TileEntity;"))
private TileEntity angelica$remeshOnFirstDescriptor(WorldClient world, int x, int y, int z) {
final TileEntity te = world.getTileEntity(x, y, z);
if (te instanceof IAwaitingDescriptorTE awaiting && awaiting.angelica$isAwaitingDescriptor()) {
awaiting.angelica$setAwaitingDescriptor(false);
if (te instanceof AwaitingDescriptorTE awaiting && awaiting.angelica$isAwaitingDescriptor()) {
AwaitingDescriptor.end(awaiting);
world.markBlockForUpdate(x, y, z);
}
return te;
@@ -5,13 +5,15 @@ import net.minecraft.tileentity.TileEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import com.gtnewhorizons.angelica.mixins.interfaces.IAwaitingDescriptorTE;
import com.gtnewhorizons.angelica.mixins.interfaces.AwaitingDescriptorTE;
@Mixin(TileEntity.class)
public abstract class MixinTileEntity_AwaitingDescriptor implements IAwaitingDescriptorTE {
public abstract class MixinTileEntity_AwaitingDescriptor implements AwaitingDescriptorTE {
@Unique private boolean angelica$awaitingDescriptor;
@Unique private int angelica$descriptorWaitTicks;
@Override
public boolean angelica$isAwaitingDescriptor() {
return this.angelica$awaitingDescriptor;
@@ -21,4 +23,14 @@ public abstract class MixinTileEntity_AwaitingDescriptor implements IAwaitingDes
public void angelica$setAwaitingDescriptor(boolean awaiting) {
this.angelica$awaitingDescriptor = awaiting;
}
@Override
public int angelica$getDescriptorWaitTicks() {
return this.angelica$descriptorWaitTicks;
}
@Override
public void angelica$setDescriptorWaitTicks(int ticks) {
this.angelica$descriptorWaitTicks = ticks;
}
}
@@ -0,0 +1,21 @@
package com.gtnewhorizons.angelica.mixins.early.celeritas.terrain;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import com.gtnewhorizons.angelica.utils.AwaitingDescriptor;
@Mixin(World.class)
public class MixinWorld_AwaitingDescriptor {
@Redirect(method = "updateEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/tileentity/TileEntity;updateEntity()V"))
private void angelica$skipUntilDescriptorArrives(TileEntity te) {
if (!AwaitingDescriptor.defersUpdate(te)) {
te.updateEntity();
}
}
}