feat(03-04): ajoute 6 champs optionnels sur GravityFlipRegion (Task 1)

- POJO: FallDamage (false), GracePeriodMs (2500), VerticalForce (0.1),
  AffectPlayers/Npcs/Items (true) avec getters/setters
- CODEC: 6 .append sans nonNull validator (sémantique optionnelle)
- Tests: 6 round-trip + back-compat defaults (9 tests total)
This commit is contained in:
2026-04-23 14:00:12 +02:00
parent ffb716ca1c
commit a834c59b66
4 changed files with 242 additions and 11 deletions
@@ -13,8 +13,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Round-trip tests for {@link GravityFlipRegion#CODEC}. Verifies the codec preserves
* Name + Box + Enabled fields across encode -> decode cycles via the BSON intermediate
* representation that all Hytale codecs share.
* the legacy Name + Box + Enabled fields across encode -> decode cycles via the BSON
* intermediate representation, and (Plan 03-04) the 6 optional tuning fields :
* FallDamage, GracePeriodMs, VerticalForce, AffectPlayers, AffectNpcs, AffectItems.
*
* <p>Back-compat invariant (test {@link #roundTripPreservesDefaultsWhenNewFieldsAbsent}) :
* a BSON encoded without the 6 new keys must decode with all Java defaults preserved.
*/
class GravityFlipRegionCodecTest {
@@ -64,6 +68,89 @@ class GravityFlipRegionCodecTest {
assertEquals("", decoded.getName(), "empty name must survive round-trip without substitution");
}
// ---------- Plan 03-04 : 6 nouveaux champs optionnels ----------
@Test
void roundTripPreservesDefaultsWhenNewFieldsAbsent() {
// Region construite via constructeur legacy 3-arg (comme un regions.json legacy).
GravityFlipRegion src = new GravityFlipRegion(
"legacy",
new Box(new Vector3d(0, 0, 0), new Vector3d(1, 1, 1)),
true);
GravityFlipRegion decoded = roundTrip(src);
// Tous les 6 nouveaux champs doivent exposer leurs defaults Java.
assertFalse(decoded.isFallDamage(), "default FallDamage=false");
assertEquals(2500, decoded.getGracePeriodMs(), "default GracePeriodMs=2500");
assertEquals(0.1, decoded.getVerticalForce(), 1e-9, "default VerticalForce=0.1");
assertTrue(decoded.isAffectPlayers(), "default AffectPlayers=true");
assertTrue(decoded.isAffectNpcs(), "default AffectNpcs=true");
assertTrue(decoded.isAffectItems(), "default AffectItems=true");
}
@Test
void roundTripFallDamageTrue() {
GravityFlipRegion src = baseRegion();
src.setFallDamage(true);
GravityFlipRegion decoded = roundTrip(src);
assertTrue(decoded.isFallDamage());
}
@Test
void roundTripGracePeriodCustom() {
GravityFlipRegion src = baseRegion();
src.setGracePeriodMs(5000);
GravityFlipRegion decoded = roundTrip(src);
assertEquals(5000, decoded.getGracePeriodMs());
}
@Test
void roundTripVerticalForceCustom() {
GravityFlipRegion src = baseRegion();
src.setVerticalForce(0.5);
GravityFlipRegion decoded = roundTrip(src);
assertEquals(0.5, decoded.getVerticalForce(), 1e-9);
}
@Test
void roundTripAffectPlayersFalse() {
GravityFlipRegion src = baseRegion();
src.setAffectPlayers(false);
GravityFlipRegion decoded = roundTrip(src);
assertFalse(decoded.isAffectPlayers());
// Les autres filtres restent à true (non-clobber).
assertTrue(decoded.isAffectNpcs());
assertTrue(decoded.isAffectItems());
}
@Test
void roundTripAllNewFieldsCustom() {
GravityFlipRegion src = baseRegion();
src.setFallDamage(true);
src.setGracePeriodMs(1234);
src.setVerticalForce(0.75);
src.setAffectPlayers(false);
src.setAffectNpcs(false);
src.setAffectItems(false);
GravityFlipRegion decoded = roundTrip(src);
assertTrue(decoded.isFallDamage());
assertEquals(1234, decoded.getGracePeriodMs());
assertEquals(0.75, decoded.getVerticalForce(), 1e-9);
assertFalse(decoded.isAffectPlayers());
assertFalse(decoded.isAffectNpcs());
assertFalse(decoded.isAffectItems());
}
private static GravityFlipRegion baseRegion() {
return new GravityFlipRegion(
"r",
new Box(new Vector3d(0, 0, 0), new Vector3d(1, 1, 1)),
true);
}
private static GravityFlipRegion roundTrip(GravityFlipRegion src) {
ExtraInfo info = new ExtraInfo();
BsonValue encoded = GravityFlipRegion.CODEC.encode(src, info);