Match fossil impact cell scaling

This commit is contained in:
Meta Vens 2026-07-17 07:07:16 +01:00
commit e08bc67b73
5 changed files with 21 additions and 15 deletions

View file

@ -3490,11 +3490,12 @@ internal sealed class AetheriaDaemonYmirSmokeChecks
}];
var target = Entity(1, 80, "raider");
target.HullItemKey = "disconnected-hull";
var hull = HullCatalogItem("disconnected-hull", 3, 1, 0);
var hull = HullCatalogItem("disconnected-hull", 4, 1, 0);
hull.ShapeCells =
[
new AetheriaRuntimeShapeCell(0, 0),
new AetheriaRuntimeShapeCell(2, 0)
new AetheriaRuntimeShapeCell(1, 0),
new AetheriaRuntimeShapeCell(3, 0)
];
var payload = new AetheriaRuntimeBehaviorPayload(0, AetheriaRuntimeBehaviorKinds.InstantWeapon, 0,
[
@ -3513,7 +3514,7 @@ internal sealed class AetheriaDaemonYmirSmokeChecks
[WearableWeaponCatalogItem("gap-penetrator", payload), hull], [], []);
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "penetration-gap-smoke", GenerationSeed = 0, CurrentZoneIndex = 0,
RunId = "penetration-gap-smoke", GenerationSeed = 91, CurrentZoneIndex = 0,
CurrentEntityKey = "zone.0.entity.0",
Zones = [new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0, Entities = [source, target] }]
};
@ -3529,8 +3530,9 @@ internal sealed class AetheriaDaemonYmirSmokeChecks
var receipt = run.ShotReceipts.Single(value => value.WeaponItemKey == "gap-penetrator");
Require(receipt.Hit && receipt.DamageCells.Count == 1 &&
receipt.DamageCells[0].X == 0 && receipt.DamageCells[0].Y == 0,
$"penetration must stop at the first empty hull sample instead of damaging a disconnected island; " +
receipt.DamageCells[0].X == 1 && receipt.DamageCells[0].Y == 0,
$"impact UV must scale by the full fossil schematic dimensions and penetration must stop " +
$"at the first empty hull sample instead of damaging a disconnected island; " +
$"endpoint={receipt.EndpointX:0.###},{receipt.EndpointZ:0.###} " +
$"cells={string.Join(';', receipt.DamageCells.Select(cell => $"{cell.X},{cell.Y}"))}");
RequireNear(90, Stat(target, "hull"), 0.000001,
@ -3544,7 +3546,7 @@ internal sealed class AetheriaDaemonYmirSmokeChecks
RequireEqual("1", shot.Props["damageCellCount"],
"generic Eve shot receipts must expose the daemon's contiguous penetration result");
var damageCell = shot.Children.Single(node => node.Kind == "shot.damage-cell");
Require(damageCell.Props["x"] == "0" && damageCell.Props["y"] == "0" &&
Require(damageCell.Props["x"] == "1" && damageCell.Props["y"] == "0" &&
damageCell.Props["armorAppliedDamage"] == "0" &&
damageCell.Props["equipmentIndex"] == "-1" &&
damageCell.Props["equipmentAppliedDamage"] == "0" &&

View file

@ -2502,8 +2502,8 @@ namespace GameCult.Aetheria.State.Verse
var localX = dx * right.X + dz * right.Y;
var localY = dx * forward.X + dz * forward.Y;
var radius = string.Equals(target.Kind, "station", StringComparison.OrdinalIgnoreCase) ? 48.0 : 20.0;
var schematicX = (localX / (radius * 2) + 0.5) * Math.Max(1, hull.ShapeWidth - 1);
var schematicY = (localY / (radius * 2) + 0.5) * Math.Max(1, hull.ShapeHeight - 1);
var schematicX = (localX / (radius * 2) + 0.5) * Math.Max(1, hull.ShapeWidth);
var schematicY = (localY / (radius * 2) + 0.5) * Math.Max(1, hull.ShapeHeight);
var first = hull.ShapeCells.OrderBy(cell =>
(cell.X - schematicX) * (cell.X - schematicX) + (cell.Y - schematicY) * (cell.Y - schematicY)).First();
result.Add((first.X, first.Y));

View file

@ -1009,8 +1009,9 @@ lifecycle state.
and mutation for direct weapons and deployables.
- Inputs: hull and hardpoint catalog topology; initialized armor and
maximum-armor grids; shield, equipment, and scalar hull state; deterministic
impact position/direction; damage amount, orthogonal spread, 0.5-cell
penetration, and typed damage type.
impact position/direction; fossil full-width/full-height schematic UV
scaling; damage amount, orthogonal spread, 0.5-cell penetration, and typed
damage type.
- Outputs: one atomic `shield -> armor cell -> equipment -> scalar hull`
result, mutated canonical grids/equipment/hull state, receipts recording
which layers were reached, and one `equipment.destroyed` fact whenever an
@ -1038,9 +1039,10 @@ lifecycle state.
half-cell step, eliminating the fossil's non-advancing infinite loop, and
terminates at the first empty sample instead of crossing a hull gap.
- Verification: daemon smoke proves a rotated asymmetric equipment footprint
receives residual cell damage and a penetrating direct shot cannot reach a
disconnected hull island. The exact contiguous cell count and per-layer cell
outcome remain visible in the generic Eve shot receipt.
receives residual cell damage, a deterministic UV lands on the cell selected
by the fossil's full-dimension arithmetic, and a penetrating direct shot
cannot reach a disconnected hull island. The exact contiguous cell count and
per-layer cell outcome remain visible in the generic Eve shot receipt.
### Daemon Destruction Transaction

View file

@ -141,7 +141,9 @@ then enters the target's shield, armor, hull-cell, equipment, thermal, and crew
damage pipeline.
The implemented damage transaction maps the deterministic impact onto the
target schematic. Damage spread expands through orthogonally adjacent cells.
target schematic using the fossil's normalized UV multiplied by the complete
schematic width and height before nearest-cell selection. Damage spread expands
through orthogonally adjacent cells.
Penetration advances through the schematic in 0.5-cell increments, including
the fix for the fossil path that could fail to advance and loop forever. It
stops at the first sample outside occupied hull topology, preserving the

View file

@ -22,7 +22,7 @@ validation proves contract shape, not wiring, exclusivity, lowering, or parity.
| Collision | fossil entity code contains no ship/station collision gameplay callback; shield collision timing is presentation | Ymir | Ymir-owned contact facts for collidable pairs; immutable entity generations for presentation | visual interpolation only | Ymir world stepping owns entity poses, radial fields, ship/pickup Begin contacts, rejection kicks, and persistent physical-payload contacts. Ship and station bodies deliberately share one negative collision group: the fossil had no rigidbody entity response, and invented circle separation would make its 25-unit center-distance docking rule unreachable. Daemon smoke advances an overlapping ship/station pair, proves the ship remains at 24 units, then accepts docking. The released EveUnity scene sink consumes immutable presented generations and has no provider/command-transport dependency; the canonical Unity product contains no Aetheria or ServerShared gameplay assembly | upstream Box3D parity harness for any future solid-body pair and live interpolation timeline under packet delay |
| Targeting/contacts | sensors + `ActionGameManager` | daemon | contact/target semantics | target HUD and indicators | daemon-owned selection now preserves the executable fossil exactly, including its oddly misnamed `Target Nearest` action selecting `MaxBy(distance)`, stable visible-contact tie order, and previous-from-no-selection choosing the second-to-last distance row when at least three contacts exist. Generic Eve nearest/next/previous/reticle/clear levers route to that owner; explicit scene targeting preserves both EveUnity's `sourceEntityId` and `targetEntityId` instead of falling back to the frame's current ship. Only daemon-visible contacts can be explicitly selected, and `target-not-visible` survives into the denied Eve receipt without disturbing the prior target. Every authored instant lock behavior evaluates on every daemon step independently of trigger/burst selection, so an idle weapon cannot retain a stale completed lock; acquisition and decay derive from facing, elapsed time, and observer-local contact confidence. Smoke proves progressive acquisition, exact target-transfer loss/start chronology, authored angular decay with one loss crossing, reacquisition without replaying start, invalid-target reset, and generic Eve projection of the prior/current lock values. `weapon.lock.started`, `weapon.lock.acquired`, and `weapon.lock.lost` publish stable one-time chronology with target, weapon identity, reason, and prior/current progress through the generic feedback stream | authored reticle/HUD parity; provider audio/effect binding is visual pull work |
| Projectile flight | weapon/projectile classes | Eve presentation for ordinary tracers; Ymir for persistent physical payloads | receipt trajectory/effect facts or persistent payload state | native projectile visual | ordinary instant, charged, constant, GuidedWeapon, and Launcher execution creates no projectile body; each weapon state owns a stable shot sequence and receipts carry origin, endpoint, nominal duration, and effect identity for Eve presentation. Guided receipts additionally retain target-entity/look-direction mode, complete guidance/thrust/lift curves, evaluated thrust and top speed, and dodge frequency; these survive checkpoint restart and reach generic Eve shot facts. The fossil guided projectile only steered, split, faded, and selected hit visuals after the ordinary weapon event had committed damage, so the client path remains derived presentation rather than a Ymir gameplay body. `SpawnProjectile` and its alternate writer are deleted; Ymir projectile contacts are feedback-only for explicitly persisted payload rows and cannot write damage; Ymir.Core remains embedded for world integration, radial fields, circle contacts, pickups, and genuinely persistent/interceptable payloads | generic guided trajectory lowering, provider split/fade asset parameters, and removal of ordinary projectile terminology from runtime contracts |
| Shield/armor/equipment/hull damage | energy-funded shield, schematic armor cells, equipment and scalar hull | daemon canonical damage transaction | aggregate/exact armor grid, entity status, and layer-aware shot/damage receipts | schematic, meters, impacts, damage VFX | owner-exists; wired; exclusive; projected: daemon initializes armor/maximum-armor grids from hull plus hardpoint catalog topology; direct and deployable damage share one `shield -> armor cell -> equipment -> scalar hull` transaction; direct impacts select a cell or complete hardpoint footprint before orthogonal spread and contiguous 0.5-cell penetration that stops at the first hull gap, while splash payloads select the source-facing hull half; rotated equipment interception shares the refit/thermal/schematic footprint owner; the fossil penetration infinite-loop defect is fixed; damage type is typed/pass-through without resistances because the fossil never applied them; Eve exposes aggregate and exact armor state, and each direct-shot receipt owns stable per-cell coordinates plus armor/equipment/hull application for presentation; fake Ymir contacts and presentation cannot decide damage | authoritative collider-UV input for edge impacts, orthogonal-spread/depth fixtures, and generic shield/equipment effect lifecycle |
| Shield/armor/equipment/hull damage | energy-funded shield, schematic armor cells, equipment and scalar hull | daemon canonical damage transaction | aggregate/exact armor grid, entity status, and layer-aware shot/damage receipts | schematic, meters, impacts, damage VFX | owner-exists; wired; exclusive; projected: daemon initializes armor/maximum-armor grids from hull plus hardpoint catalog topology; direct and deployable damage share one `shield -> armor cell -> equipment -> scalar hull` transaction; direct impacts use the fossil's full-width/full-height normalized-UV scaling to select a cell or complete hardpoint footprint before orthogonal spread and contiguous 0.5-cell penetration that stops at the first hull gap, while splash payloads select the source-facing hull half; rotated equipment interception shares the refit/thermal/schematic footprint owner; the fossil penetration infinite-loop defect is fixed; damage type is typed/pass-through without resistances because the fossil never applied them; Eve exposes aggregate and exact armor state, and each direct-shot receipt owns stable per-cell coordinates plus armor/equipment/hull application for presentation; fake Ymir contacts and presentation cannot decide damage | authoritative authored collider-UV topology input, orthogonal-spread/depth fixtures, and generic shield/equipment effect lifecycle |
| Thermal/energy | cell conduction, capacitor/reactor/radiator network, and cockpit thermal exposure | daemon | ship/equipment power, temperature, medical state, risk and death feedback | schematic/post effects | owner-exists; wired; exclusive; projected; generic timing and native asset delivery lowered: catalog hull and installed-item shapes derive cell mass/conductivity/topology; local temperature derives thermal performance, wear potential and online state; all consumers share capacitor-first/reactor-residual transactions; powered radiators pump before reactor settlement; reactor heat then enters the same cell network before conduction/radiation; cockpit-cell temperature drives the fossil nonlinear heatstroke/hypothermia accumulation, linear recovery, severe-risk crossings, and ordinary exactly-once destruction with a typed cause; Eve exposes cockpit, risk, heatstroke source-weight, phasing and death-transition facts; EveUnity generically resolves the original severe pulse plus live/reconnect-safe cause-specific death crossfade; Aetheria deterministically translates the five legacy profiles into URP profiles, persists every override as a real profile sub-asset, advertises them by semantic role through CultMesh CDN, and binds them in the canonical client through a weight-only native sink; rotated equipment topology, parent/child radiation, schematic composition, legacy SSR/AO/roundness equivalents, and live/reconnect death-fade parity remain incomplete | multi-consumer ordering, multi-radiator visibility, rotated topology, generic schematic meters, renderer-feature parity, and live/reconnect death-fade screenshots |
| Weapons | ServerShared behaviors + Unity effects | daemon plus Ymir geometry/kinematics | action capability, weapon state, shot/damage receipts | effects/audio/HUD | instant and constant resource/timing lifecycles are daemon-owned; charged weapons accept one semantic request, spool without requiring a solution, hold at full charge, commit automatically when a solution appears, and perform deterministic once-per-second malfunction hazard checks after the authored safe hold interval with increasing persisted risk; successful instant, constant, charged, deployable, and turret-controlled transactions publish authored transient visibility and consume the owning equipment's temperature-derived wear, with charged visibility applying its authored multiplier and turret wear remaining exact-weapon scoped; GuidedWeapon and Launcher retain ordinary authoritative shot resolution while publishing their complete fossil steering profile as derived presentation; generic Eve `weapon.state` exposes charge hold/risk and feedback exposes readiness, commit, refusal, and malfunction chronology; committed direct damage now enters the shared daemon armor-cell transaction | remaining impact-distribution parity, generic guided/effect lowering, and Unity effect reconciliation |
| Destruction/drops | hull death, 25% equipment rolls, unconditional cargo drops, 25-unit launch, 30-second pickups | daemon | destruction identity, death/drop events, typed pickups | provider-advertised destruction effect and pickups | owner-exists; wired; exclusive; projected: direct and deployable lethal damage commit one deterministic destruction transaction, clear live references, retain only a non-rendered identity tombstone, and emit exact pickups/events; residual cell damage destroys installed equipment before hull, disables its behaviors immediately, and cockpit destruction kills with its fossil cause before scalar hull depletion; the reserved client `DestroyEntity` command is rejected; Aetheria advertises its original big explosion as `effect.feedback.entity.destroyed`, lowered generically by EveUnity | multiplayer reconnect chronology |