From 2e55f58b6b343916b45afd7de1d66738947b502d Mon Sep 17 00:00:00 2001 From: Samsuik Date: Wed, 5 Nov 2025 13:32:14 +0000 Subject: [PATCH] fix entity data becoming desynced after an explosion --- .../explosion/SpecialisedExplosion.java | 19 +++++++++++++++++++ .../sakura/explosion/TntExplosion.java | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java index 107e707..7403666 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java @@ -4,6 +4,7 @@ import ca.spottedleaf.moonrise.common.util.WorldUtil; import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices; import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup; import it.unimi.dsi.fastutil.objects.*; +import me.samsuik.sakura.entity.EntityState; import me.samsuik.sakura.mechanics.MechanicVersion; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; @@ -26,11 +27,13 @@ public abstract class SpecialisedExplosion extends ServerExplo private static final double ENTITY_DISPATCH_DISTANCE_SQR = 32.0 * 32.0; protected final T cause; // preferred over source + protected final Deque sourceEntities = new ArrayDeque<>(); private Vec3 dispatchPosition; private final List bufferedExplosions = new ObjectArrayList<>(); private AABB bounds; private final Set gameEvents = new ObjectOpenHashSet<>(); private final Deque explosionsToSend = new ArrayDeque<>(); + private final Map entityStates = new Reference2ObjectOpenHashMap<>(); public SpecialisedExplosion( final ServerLevel level, @@ -46,6 +49,7 @@ public abstract class SpecialisedExplosion extends ServerExplo this.cause = entity; this.dispatchPosition = center; this.bounds = new AABB(center, center); + this.sourceEntities.add(entity); } public final Queue getExplosionsToSend() { @@ -61,7 +65,16 @@ public abstract class SpecialisedExplosion extends ServerExplo @Override public final int explode() { this.createBlockCache(); + + // Handle batching, entities, blocks and events final int blocksDestroyed = this.handleExplosion(); + + // Apply entity states (this is so plugins have up to date entity information) + this.entityStates.forEach((entity, state) -> { + state.apply(entity); + entity.updateBukkitHandle(entity); // restore entity handle + }); + this.clearBlockCache(); return blocksDestroyed; } @@ -77,6 +90,12 @@ public abstract class SpecialisedExplosion extends ServerExplo ? this.calculateExplodedPositions() : List.of(); + // Poll the sourceEntities queue and keep track of the entity state + final Entity head = this.sourceEntities.poll(); + if (head != null) { + this.entityStates.put(head, EntityState.of(this.cause)); + } + // Buffer explosions to reduce the amount of calculations and improve locality this.bounds = this.bounds.expand(center); this.bufferedExplosions.add(center); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java index 09e8235..b24e31b 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java @@ -70,6 +70,13 @@ public final class TntExplosion extends SpecialisedExplosion { // Merge the found entity into the explosion source this.level().mergeHandler.mergeEntity(mergeEntity, cause); + + // To keep track of this for merged entities we'd need to sort the connected entity list. + // Which I don't think is worth the cost. If you're running a cannon server and want people + // to have access to accurate entity data consider turning off merging or make it accessible. + + // Add the found entity to the source entities + this.sourceEntities.add(foundEntity); } entities.finishRawIterator(); }