feat(phase-2): pure-Java chain resolution algorithm

Adds com.mythlane.chainlightning.chain package with 7 types (Vec3,
ChainEntity, EntitySource, RayCaster, ChainParameters, ChainHit,
ChainResolver). Algorithm: ray-cast primary target then BFS hops with
distanceSquared closest-neighbor selection, deterministic lexicographic
tie-breaker on entity id, max 5 targets, 8-block radius, damage curve
[8,6,4,3,2]. Strict no-Hytale-imports boundary — runtime adapters land
in Phase 3.

JUnit 5 suite: 25 tests green (Vec3 5 + ChainParameters 10 +
ChainResolver 10). All 10 mandatory cases covered (no primary,
primary-only, full chain, overflow, out-of-radius, no-double-hit,
closest, tie-breaker determinism, dead entity, custom maxTargets).
This commit is contained in:
2026-04-26 19:29:20 +02:00
parent edca00fa4a
commit cd5d0bedd3
11 changed files with 553 additions and 0 deletions
@@ -0,0 +1,44 @@
package com.mythlane.chainlightning.chain;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
final class Vec3Test {
@Test
void distanceSquared_zeroToZero_isZero() {
Vec3 a = new Vec3(0, 0, 0);
assertEquals(0.0, a.distanceSquared(a), 1e-9);
}
@Test
void distanceSquared_pythagorean345_is25() {
Vec3 a = new Vec3(0, 0, 0);
Vec3 b = new Vec3(3, 4, 0);
assertEquals(25.0, a.distanceSquared(b), 1e-9);
}
@Test
void distanceSquared_isCommutative() {
Vec3 a = new Vec3(1, 2, 3);
Vec3 b = new Vec3(-4, 5, 6);
assertEquals(a.distanceSquared(b), b.distanceSquared(a), 1e-9);
}
@Test
void distance_pythagorean345_is5() {
Vec3 a = new Vec3(0, 0, 0);
Vec3 b = new Vec3(3, 4, 0);
assertEquals(5.0, a.distance(b), 1e-9);
}
@Test
void distanceSquared_negativeCoordinates_works() {
Vec3 a = new Vec3(-1, -1, -1);
Vec3 b = new Vec3(1, 1, 1);
assertEquals(12.0, a.distanceSquared(b), 1e-9);
assertTrue(a.distance(b) > 3.4 && a.distance(b) < 3.5);
}
}