diff --git a/src/main/java/com/mythlane/gravityflip/physics/GravityApplier.java b/src/main/java/com/mythlane/gravityflip/physics/GravityApplier.java index 8539594..eb7a375 100644 --- a/src/main/java/com/mythlane/gravityflip/physics/GravityApplier.java +++ b/src/main/java/com/mythlane/gravityflip/physics/GravityApplier.java @@ -78,6 +78,15 @@ public final class GravityApplier { /** Tick entry point. NO-OP si world ou snapshot est null. */ public void apply(World world, RegionSnapshot snapshot) { if (world == null || snapshot == null) return; + // THREADING (fix WorldThread assert 2026-04-23) : `Store.forEachEntityParallel` exige + // d'être initié depuis la WorldThread (assertThread @Store.java:2362). Le tick loop tourne + // sur `GravityFlip-Detect` (ScheduledExecutorService) → on dispatch tout le travail ECS + // via `world.execute(Runnable)`. Le CommandBuffer reste utilisé côté mutations, mais + // ne résout PAS l'assert côté appelant (amendement D-04 du plan 03-01). + world.execute(() -> applyOnWorldThread(world, snapshot)); + } + + private void applyOnWorldThread(World world, RegionSnapshot snapshot) { Collection enabledRegions = snapshot.byRegion().keySet(); // Stratégie figée (cf. WARNING 1 résolu) : on accepte la duplication du containsPosition // (cf. must_haves trade-off) plutôt que de coupler à un nouveau contrat RegionSnapshot