refactor: clean GSD comments and translate remaining Java sources to English
- Reduce javadocs to one-liners across config/region/physics/tick/viz/plugin root - Translate residual French comments; no behavioural change - Tests adjusted where assertions referenced French strings
This commit is contained in:
@@ -28,44 +28,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Tick-driven service that toggles the native {@code PhysicsValues.invertedGravity} flag on every
|
||||
* entity present in an enabled {@link GravityFlipRegion}. Mutations are queued via
|
||||
* {@code CommandBuffer.replaceComponent(...)} inside a {@code Store.forEachEntityParallel(...)}
|
||||
* lambda — the ECS engine commits them on the main thread after the parallel pass.
|
||||
*
|
||||
* <p>Phase 03-02: wake-ups per-entity :
|
||||
* <ul>
|
||||
* <li>Players: {@code MovementManager.setDefaultSettings + applyDefaultSettings + update(packetHandler)}</li>
|
||||
* <li>NPCs: {@code Role.getActiveMotionController().updatePhysicsValues(PhysicsValues)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Phase 03-03: seed {@code addForce(0, +0.1, 0)} on NPCs each tick in-region to activate
|
||||
* {@code computeNewFallSpeed} path which honours {@code invertedGravity}.
|
||||
*
|
||||
* <p>Phase 03-04:
|
||||
* <ul>
|
||||
* <li>Per-region tuning consumed : {@code AffectPlayers} / {@code AffectNpcs} / {@code AffectItems}
|
||||
* filter BEFORE any wake / cmdBuf flip ; {@code VerticalForce} replaces the hardcoded 0.1.</li>
|
||||
* <li>{@link FallDamageGuard} notified on entry (pass 1) and exit (pass 2) with the
|
||||
* first-matched region to drive {@link FallDamageSuppressorSystem}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>Hotpath note:</b> Pass 1 (flip) and Pass 2 (restore) each iterate
|
||||
* {@code forEachEntityParallel}. They CANNOT be fused: restore requires the complete
|
||||
* {@code currentlyInRegion} set (computed during Pass 1) to diff against
|
||||
* {@code previouslyInverted}. Merging would either miss restores or double-visit
|
||||
* entities with inconsistent per-chunk state.
|
||||
*
|
||||
* <p><b>Multi-region precedence :</b> for an entity simultaneously inside N regions, the FIRST
|
||||
* region encountered in the iteration of {@code snapshot.byRegion().keySet()} (Java insertion
|
||||
* order via the underlying {@code LinkedHashMap}) drives the config values read this tick
|
||||
* (VerticalForce, AffectXxx, FallDamage, GracePeriodMs). Rule applies consistently to
|
||||
* {@link FallDamageGuard#markInRegion} (same first-matched region) and {@link FallDamageGuard#markExit}
|
||||
* (last-known first-matched region at the previous in-region tick).
|
||||
* Tick-driven service that toggles {@code PhysicsValues.invertedGravity} on every entity currently
|
||||
* inside an enabled region, wakes up players/NPCs so the new settings take effect, and drives the
|
||||
* fall-damage guard on entry/exit transitions.
|
||||
*/
|
||||
public final class GravityApplier {
|
||||
// Lazy ComponentType holders — pattern identique à RegionRegistry.transform()
|
||||
// (évite static-init Hytale PluginBase pendant les tests).
|
||||
// Lazy ComponentType holders — avoids Hytale PluginBase static init during tests.
|
||||
private static volatile ComponentType<EntityStore, PhysicsValues> physicsType;
|
||||
private static volatile ComponentType<EntityStore, UUIDComponent> uuidType;
|
||||
private static volatile ComponentType<EntityStore, TransformComponent> transformType;
|
||||
@@ -145,7 +113,7 @@ public final class GravityApplier {
|
||||
return t;
|
||||
}
|
||||
|
||||
// THREADING: écrit/lu depuis les workers ECS via forEachEntityParallel → ConcurrentHashMap.newKeySet obligatoire.
|
||||
// Written/read from ECS worker threads via forEachEntityParallel — concurrent collection required.
|
||||
private final Set<UUID> previouslyInverted = ConcurrentHashMap.newKeySet();
|
||||
/** First-matched region per UUID at the previous tick — consulted in Pass 2 for markExit. */
|
||||
private final ConcurrentHashMap<UUID, GravityFlipRegion> lastKnownRegion = new ConcurrentHashMap<>();
|
||||
@@ -162,21 +130,17 @@ public final class GravityApplier {
|
||||
this.guard = guard == null ? new FallDamageGuard() : guard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construit un nouveau {@link PhysicsValues} en copiant mass/drag de la source et en fixant
|
||||
* {@code invertedGravity=target}. Pure data — pas d'effet de bord.
|
||||
*/
|
||||
/** Builds a new PhysicsValues copying mass/drag from the source and setting invertedGravity. */
|
||||
static PhysicsValues buildPhysicsValuesWithFlag(PhysicsValues source, boolean target) {
|
||||
FlaggedDecision d = buildFlaggedDecision(source.getMass(), source.getDragCoefficient(), target);
|
||||
return new PhysicsValues(d.mass, d.drag, d.invertedGravity);
|
||||
}
|
||||
|
||||
/** Pure-data seam pour tests unitaires (aucune dépendance sur PhysicsValues). */
|
||||
/** Pure-data seam for unit tests — PhysicsValues static init is unavailable outside the server runtime. */
|
||||
static FlaggedDecision buildFlaggedDecision(double mass, double drag, boolean target) {
|
||||
return new FlaggedDecision(mass, drag, target);
|
||||
}
|
||||
|
||||
/** Holder pure-data pour la décomposition testable de {@link #buildPhysicsValuesWithFlag}. */
|
||||
static final class FlaggedDecision {
|
||||
final double mass;
|
||||
final double drag;
|
||||
@@ -186,7 +150,7 @@ public final class GravityApplier {
|
||||
}
|
||||
}
|
||||
|
||||
/** Tick entry point. NO-OP si world ou snapshot est null. */
|
||||
/** Tick entry point; no-op when world or snapshot is null. */
|
||||
public void apply(World world, RegionSnapshot snapshot) {
|
||||
if (world == null || snapshot == null) return;
|
||||
world.execute(() -> applyOnWorldThread(world, snapshot));
|
||||
@@ -205,8 +169,9 @@ public final class GravityApplier {
|
||||
ComponentType<EntityStore, Player> PLT = playerType();
|
||||
ComponentType<EntityStore, NPCEntity> NPCT = npcEntityType();
|
||||
|
||||
// PASS 1 — pour chaque entité avec PhysicsValues : si dans une région activée, queue le flip ON
|
||||
// via cmdBuf.replaceComponent ET wake-up MovementManager / MotionController.
|
||||
// PASS 1 — flip ON for every entity with PhysicsValues that is inside an enabled region.
|
||||
// Pass 1 and Pass 2 cannot be fused: restore requires the complete currentlyInRegion set
|
||||
// to diff against previouslyInverted.
|
||||
Set<UUID> currentlyInRegion = ConcurrentHashMap.newKeySet();
|
||||
store.forEachEntityParallel(PHYST, (index, chunk, cmdBuf) -> {
|
||||
TransformComponent t;
|
||||
@@ -222,7 +187,7 @@ public final class GravityApplier {
|
||||
com.hypixel.hytale.math.vector.Vector3d pos = t.getPosition();
|
||||
double x = pos.x, y = pos.y, z = pos.z;
|
||||
|
||||
// First-match wins for multi-region precedence (Plan 03-04).
|
||||
// First-match wins for multi-region precedence.
|
||||
GravityFlipRegion matchedRegion = null;
|
||||
for (GravityFlipRegion r : enabledRegions) {
|
||||
if (r.asBox().containsPosition(x, y, z)) { matchedRegion = r; break; }
|
||||
@@ -231,7 +196,6 @@ public final class GravityApplier {
|
||||
|
||||
UUID u = uc.getUuid();
|
||||
|
||||
// --- Plan 03-04 : AffectXxx filters applied BEFORE wake ---
|
||||
EntityKind kind = classify(chunk, index, MMT, PRT, PLT, NPCT);
|
||||
boolean allowed;
|
||||
switch (kind) {
|
||||
@@ -240,8 +204,7 @@ public final class GravityApplier {
|
||||
default: allowed = matchedRegion.isAffectItems(); break;
|
||||
}
|
||||
if (!allowed) {
|
||||
// Entité filtrée : ne PAS la compter dans currentlyInRegion, et
|
||||
// ne PAS notifier le guard — le filtre se comporte comme hors-zone.
|
||||
// Filtered entity behaves as if outside the region.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -249,19 +212,17 @@ public final class GravityApplier {
|
||||
lastKnownRegion.put(u, matchedRegion);
|
||||
guard.markInRegion(u, matchedRegion);
|
||||
|
||||
// --- Flip ECS native (plan 03-01) ---
|
||||
if (!v.isInvertedGravity()) {
|
||||
Ref<EntityStore> ref = chunk.getReferenceTo(index);
|
||||
cmdBuf.replaceComponent(ref, PHYST,
|
||||
new PhysicsValues(v.getMass(), v.getDragCoefficient(), true));
|
||||
}
|
||||
|
||||
// --- Wake-up joueur/NPC (plan 03-02) + seed VerticalForce (plan 03-03 paramétré 03-04) ---
|
||||
wakePlayerOrNpc(chunk, index, v, true, matchedRegion,
|
||||
MMT, PRT, PLT, NPCT);
|
||||
});
|
||||
|
||||
// PASS 2 — restore : pour chaque UUID dans previouslyInverted \ currentlyInRegion.
|
||||
// PASS 2 — restore: for every UUID in previouslyInverted \ currentlyInRegion.
|
||||
Set<UUID> toRestore = ConcurrentHashMap.newKeySet();
|
||||
toRestore.addAll(previouslyInverted);
|
||||
toRestore.removeAll(currentlyInRegion);
|
||||
@@ -284,11 +245,8 @@ public final class GravityApplier {
|
||||
new PhysicsValues(v.getMass(), v.getDragCoefficient(), false));
|
||||
}
|
||||
|
||||
// Wake-up avec flag=false pour restaurer les settings natifs.
|
||||
wakePlayerOrNpc(chunk, index, v, false, null, MMT, PRT, PLT, NPCT);
|
||||
|
||||
// Plan 03-04 : notifier guard.markExit avec la région last-known
|
||||
// (première région matchée au tick précédent).
|
||||
GravityFlipRegion lastRegion = lastKnownRegion.remove(u);
|
||||
if (lastRegion != null) {
|
||||
guard.markExit(u, lastRegion, now);
|
||||
@@ -296,7 +254,7 @@ public final class GravityApplier {
|
||||
});
|
||||
}
|
||||
|
||||
// Update tracker — ces ops sont sur le tick thread après la fin du pass parallel.
|
||||
// Tick-thread update after the parallel pass completes.
|
||||
previouslyInverted.clear();
|
||||
previouslyInverted.addAll(currentlyInRegion);
|
||||
} catch (Throwable th) {
|
||||
@@ -306,7 +264,7 @@ public final class GravityApplier {
|
||||
|
||||
private enum EntityKind { PLAYER, NPC, OTHER }
|
||||
|
||||
/** Classify the entity at {@code index} into player / NPC / other (items fall into other). */
|
||||
/** Classifies the entity at {@code index} into player / NPC / other (items fall into other). */
|
||||
private EntityKind classify(ArchetypeChunk<EntityStore> chunk, int index,
|
||||
ComponentType<EntityStore, MovementManager> MMT,
|
||||
ComponentType<EntityStore, PlayerRef> PRT,
|
||||
@@ -328,15 +286,7 @@ public final class GravityApplier {
|
||||
return EntityKind.OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wake-up dans le MÊME lambda parallèle :
|
||||
* - joueur (MovementManager + PlayerRef + Player) → setDefaultSettings + applyDefaultSettings + update(ph)
|
||||
* - NPC (NPCEntity avec role non-null et active controller non-null) → updatePhysicsValues(targetValues)
|
||||
* - sinon (items, autres) : no-op (le flip cmdBuf.replaceComponent du pass 1 suffit)
|
||||
*
|
||||
* <p>Plan 03-04 : le paramètre {@code matchedRegion} (non-null en entrée, null en sortie)
|
||||
* fournit {@code VerticalForce} — remplace le hardcode 0.1 du plan 03-03.
|
||||
*/
|
||||
/** Wakes up the entity so the new PhysicsValues take effect (player movement refresh or NPC controller update). */
|
||||
private void wakePlayerOrNpc(
|
||||
ArchetypeChunk<EntityStore> chunk, int index,
|
||||
PhysicsValues sourceValues, boolean targetFlag,
|
||||
@@ -347,7 +297,7 @@ public final class GravityApplier {
|
||||
ComponentType<EntityStore, NPCEntity> NPCT) {
|
||||
PhysicsValues targetValues = buildPhysicsValuesWithFlag(sourceValues, targetFlag);
|
||||
|
||||
// --- Branche joueur ---
|
||||
// Player branch.
|
||||
MovementManager mm = null;
|
||||
try { mm = chunk.getComponent(index, MMT); } catch (Throwable ignored) {}
|
||||
if (mm != null) {
|
||||
@@ -363,11 +313,11 @@ public final class GravityApplier {
|
||||
} catch (Throwable th) {
|
||||
errorHandler.accept(th);
|
||||
}
|
||||
return; // un joueur n'est pas un NPC
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Branche NPC ---
|
||||
// NPC branch.
|
||||
NPCEntity npc = null;
|
||||
try { npc = chunk.getComponent(index, NPCT); } catch (Throwable ignored) {}
|
||||
if (npc != null) {
|
||||
@@ -378,9 +328,7 @@ public final class GravityApplier {
|
||||
if (active != null) {
|
||||
active.updatePhysicsValues(targetValues);
|
||||
|
||||
// Plan 03-04 : seed forceVelocity.y paramétré par VerticalForce (remplace
|
||||
// le hardcode 0.1 de Plan 03-03). Uniquement en entrée (targetFlag=true) —
|
||||
// à la sortie le damping natif zéroe forceVelocity.
|
||||
// Seed forceVelocity.y only on entry — on exit the native damping zeroes it.
|
||||
if (targetFlag && matchedRegion != null) {
|
||||
double vf = matchedRegion.getVerticalForce();
|
||||
try {
|
||||
@@ -399,10 +347,10 @@ public final class GravityApplier {
|
||||
return;
|
||||
}
|
||||
|
||||
// sinon : item / autre — no-op
|
||||
// Items / other: no-op.
|
||||
}
|
||||
|
||||
/** Pure data-diff utilitaire pour tests unitaires (pas de runtime Hytale). */
|
||||
/** Pure data-diff helper for unit tests. */
|
||||
public static DiffResult diff(Set<UUID> previous, Set<UUID> current) {
|
||||
Set<UUID> toFlip = new HashSet<>(current);
|
||||
toFlip.removeAll(previous);
|
||||
@@ -417,17 +365,14 @@ public final class GravityApplier {
|
||||
DiffResult(Set<UUID> f, Set<UUID> r) { this.toFlip = f; this.toRestore = r; }
|
||||
}
|
||||
|
||||
// ---- Test hooks (package-private) ----
|
||||
// Test hooks (package-private).
|
||||
|
||||
/** Vue immuable du tracker — pour tests unitaires sémantiques (résolution WARNING 2). */
|
||||
/** Immutable view of the internal tracker for unit tests. */
|
||||
Set<UUID> previouslyInvertedView() {
|
||||
return Collections.unmodifiableSet(previouslyInverted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force une valeur du tracker hors runtime ECS — pour tester la sémantique sans dépendre de World/Store.
|
||||
* Package-private : NE PAS appeler depuis le code de production.
|
||||
*/
|
||||
/** Test-only tracker override; never call from production code. */
|
||||
void __updateTrackerForTest(Set<UUID> newState) {
|
||||
previouslyInverted.clear();
|
||||
previouslyInverted.addAll(newState);
|
||||
|
||||
Reference in New Issue
Block a user