fix(region): wrap refreshFor(World) dans world.execute (WorldThread assert)
- RegionRegistry.refreshFor dispatche scan ECS + publishSnapshot via world.execute - Publication devient asynchrone (1-tick staleness max, borne par tick loop @100ms) - Null-path enabled.isEmpty publie directement (pas de travail ECS requis) - Amendement D-04 du plan 03-01 : world.execute requis côté initiation de forEachEntityParallel
This commit is contained in:
@@ -168,37 +168,47 @@ public final class RegionRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enabled.isEmpty()) {
|
if (enabled.isEmpty()) {
|
||||||
|
// Aucun travail ECS → publication directe depuis le thread appelant.
|
||||||
publishSnapshot(world, snapshotOf(world, byRegion));
|
publishSnapshot(world, snapshotOf(world, byRegion));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// THREADING (fix WorldThread assert 2026-04-23) : `Store.forEachEntityParallel` exige la
|
||||||
Store<EntityStore> store = world.getEntityStore().getStore();
|
// WorldThread. On dispatche scan + publication via `world.execute(Runnable)` pour satisfaire
|
||||||
ComponentType<EntityStore, TransformComponent> TRANSFORM = transform();
|
// `assertThread`. Conséquence : la publication devient asynchrone (1 tick décalé max) côté
|
||||||
// ComponentType IS-A Query, so TRANSFORM is passed directly (no builder).
|
// consumers de `currentSnapshot(world)` — tolérable car le RegionTickLoop tourne @100ms, donc
|
||||||
store.forEachEntityParallel(TRANSFORM, (index, chunk, cmdBuf) -> {
|
// la fraîcheur du snapshot reste ≤ 100ms dans le pire cas.
|
||||||
TransformComponent t = chunk.getComponent(index, TRANSFORM);
|
world.execute(() -> {
|
||||||
// Pinned API 2026.03.26 returns com.hypixel.hytale.math.vector.Vector3d
|
try {
|
||||||
// (Hytale's own type), NOT org.joml.Vector3d. Same deviation as Phase 02-01.
|
Store<EntityStore> store = world.getEntityStore().getStore();
|
||||||
com.hypixel.hytale.math.vector.Vector3d pos = t.getPosition();
|
ComponentType<EntityStore, TransformComponent> TRANSFORM = transform();
|
||||||
// Copy to locals — getPosition() returns a backing field; never mutated here.
|
// ComponentType IS-A Query, so TRANSFORM is passed directly (no builder).
|
||||||
double x = pos.x, y = pos.y, z = pos.z;
|
store.forEachEntityParallel(TRANSFORM, (index, chunk, cmdBuf) -> {
|
||||||
Ref<EntityStore> ref = null;
|
TransformComponent t = chunk.getComponent(index, TRANSFORM);
|
||||||
for (GravityFlipRegion r : enabled) {
|
// Pinned API 2026.03.26 returns com.hypixel.hytale.math.vector.Vector3d
|
||||||
Box box = r.asBox();
|
// (Hytale's own type), NOT org.joml.Vector3d. Same deviation as Phase 02-01.
|
||||||
if (box.containsPosition(x, y, z)) {
|
com.hypixel.hytale.math.vector.Vector3d pos = t.getPosition();
|
||||||
if (ref == null) ref = chunk.getReferenceTo(index);
|
// Copy to locals — getPosition() returns a backing field; never mutated here.
|
||||||
byRegion.get(r).add(ref);
|
double x = pos.x, y = pos.y, z = pos.z;
|
||||||
|
Ref<EntityStore> ref = null;
|
||||||
|
for (GravityFlipRegion r : enabled) {
|
||||||
|
Box box = r.asBox();
|
||||||
|
if (box.containsPosition(x, y, z)) {
|
||||||
|
if (ref == null) ref = chunk.getReferenceTo(index);
|
||||||
|
byRegion.get(r).add(ref);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
} catch (Throwable th) {
|
||||||
} catch (Throwable th) {
|
// Swallow — publish whatever we collected (possibly empty). The tick loop's
|
||||||
// Swallow — publish whatever we collected (possibly empty). The tick loop's
|
// errorHandler already routes uncaught throwables; this catch keeps the
|
||||||
// errorHandler already routes uncaught throwables; this catch keeps the
|
// scheduler alive across transient ECS-state errors (e.g., world being torn down).
|
||||||
// scheduler alive across transient ECS-state errors (e.g., world being torn down).
|
}
|
||||||
}
|
|
||||||
|
|
||||||
publishSnapshot(world, snapshotOf(world, byRegion));
|
// Publication intra-Runnable : garantit que la table byRegion est complète quand
|
||||||
|
// on la fige dans snapshotOf(...).
|
||||||
|
publishSnapshot(world, snapshotOf(world, byRegion));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Off-thread consumer entry point. Returns {@code null} if no snapshot has been published yet. */
|
/** Off-thread consumer entry point. Returns {@code null} if no snapshot has been published yet. */
|
||||||
|
|||||||
Reference in New Issue
Block a user