From be3db3d734867fe6603c19f943d5081cb9fbf5b8 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 16 Jun 2026 16:13:54 +0100 Subject: [PATCH] Keep orbit consumer edges on typed keys --- .voidbot/state/aetheria.cc | Bin 183631 -> 183667 bytes Aetheria.State.Verify/Program.cs | 79 ++++++++++++++++++ Aetheria.State/README.md | 5 ++ Assets/Scripts/Gameplay/ActionGameManager.cs | 15 ++-- .../ServerShared/Behaviors/ResourceScanner.cs | 2 +- Assets/Scripts/Zone Display/ZoneRenderer.cs | 11 +-- docs/aetheria-perfect-machine-map.md | 6 +- 7 files changed, 101 insertions(+), 17 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 55687ffedb07c4200e073fbb32f23d8d69b2f27e..92149a1bcb32a989bfe150d336994979b6a7c2ce 100644 GIT binary patch delta 1747 zcmaJ?PiS0480SrwVp0f52{nzB2~u@+ciG*ftxeS$Ou8;oQd65^KL{daP(EtX87T_cV7j%{sIg3a*k4l||Z&sJXC-&JJE#%f4Zk zjeUl~T=cNgq>ly1tG3dsw2z6#P#kxYM$AIolcd|F65DE}&%>Co&d&wKd~W0TZRE6s%cv=g!r!qB`k997?TGB@!9ZvmxPpe9J%*9#I^& zX}FnTwik^7x1{LcA$=aNas?%g9XGaj+!AusrxI~u835SO4-^xvA+6A)uYqgl>dSEC z5D<%7jK)ocn@j>DaliDXrd&aVpMEnh+(9SYX)P1SD^%?Qkr}9l6qXh9!5wsPpb6u+ zmH>PPOkSjLv6T&r9^h4N21F>~Dv>R~fJtnN_A$N4ls0qUqI`ONdm?@5@{Bq24VqeCuUqfpk$2rxIOk?A0EV^z z096^;3aFDJiP~caS;W>OrPpP@Mz!l8Er0rW`tnnAX8S}i^&)o`@<^PyypuEZ;ADI6 z5Y@;+85r~CGr@rwKZ?Rh?#z|BDm{5HpO&AWG}m7X4zI30WDNc>1t5Zmw=x%KA|n_^ zk1CtZlBdypcq*uxLvNv}^XJ!L=fIWHwHhTvf>f}3Mm8L4GF&46C1N)8Llx~>Nz2o- z=8yM+3G>N4w7*_oTUlB@y#lg_;$atz4gWvu%8+~L!U}ZaX)pY1OJxJ5hT9^eb-07Z ztI^>zkKRJlW_AbFP<7p0dn1@WV0UD8#G`hjX0Gm_dT`k+T?yh@Oj=-lH)>g3++h*S z8_d1==n{G?cWkk`U@8g1`|YpAa{1YE1^#}fNu;itUoOF=ySr%ei5nim4bSLJtDs$W z#bN*E_g!>q!oM-q^v69j{vkP5b?=M3k9J0(qyEWBeCWCC75eo7dV3T)ZnJK``yIMJ K;bX_=H~t2hFLE&e delta 1618 zcmZ`)-)me&6y{D=NmIJEYMK^`o(K^`cbDC4YHTWEAvTrzD^yfckWTi_?oRjKJKLGL zNjDEk!3Q4-+H%1u6~PC8J}4HIVg*A|eDOtn@S#uoA4nB^6Ff8b?%gibmtp7JGv|Eg zJKs6`_qE+WU)%lFCuFqxGjL77FG>t5Mi%N^D$%NQ*oD=S7rbGAcHZ!W)_ z`a<>z+#Ajm(8$k?D?!Y__gvM(B)a)XBG23;x< zZCV~)bQ{4zAfgtNAl4#~bPZhXuo!bcMOblxfub7&$&?6I+3RXhMpNM1jFM2SvJf*k zDu$8;LUiIT@CY$+mD6Ntt$eCkq_~J~|6$tSkzj2G`ZSMQ`H1wYCVDDHpwp_m^qh zB$K1q3G5ct=AD~l%DmqrW1FtQeN0%k8bFeaB2-m@1%aGuOB6N*OBiMpNk*?WM=^*# zm|Q@moR)!lO6X;ga|x}3{a!mhY+rfQa%7k{z9-YkhqXO>hNP2Bez5=eOG74P4Po8Y zzO*LSRRvw4xMSE_S6Lt$I1T34)8510NppS5d(8a#qIY!cWEK)+^6cz^$5Y{F1zWW@ z13YwFin!Izg_4vnA9`=e+h=~N;c=)*ic3qGT#;ux4A|Oqh;%F^!^u$$zvNuxkzkeL zbSY>`5jt^J93Gr0%<+tQHpJagtX=Cmf=%(r4H{d>l@><-GZA_Uq(6)V)u|LDbR{6Nkw zFq;uMaoO{A`UF$m planet.OrbitId == followOrbit", + "planet => planet.OrbitId == rootOrbit", + "body => body.OrbitId == orbit.ID", + "body => body.Orbit == orbit.ID", + "GetOrbitPosition(planetInstance.OrbitId)", + "Zone.Orbits[planetInstance.OrbitId].Parent", + "zone.Orbits[belt.Orbit]", + "GetOrbitPosition(planet.OrbitId)" + }; + + var hits = checkedFiles + .Where(File.Exists) + .SelectMany(path => File.ReadLines(path) + .Select((line, index) => new { Path = path, LineNumber = index + 1, Line = line })) + .Where(line => forbiddenSymbols.Any(symbol => line.Line.Contains(symbol, StringComparison.Ordinal))) + .Select(line => $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}") + .ToArray(); + + if (hits.Length > 0) + { + throw new InvalidOperationException( + "Orbit consumer edges must read typed OrbitKey surfaces rather than wrapper GUID fields in gameplay, renderer, and sensor code: " + + string.Join("; ", hits)); + } + + var requiredSymbols = new Dictionary + { + [Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs")] = new[] + { + "Zone.Orbits.Values.MinBy(orbit => lengthsq(Zone.GetOrbitPosition(orbit.OrbitKey) - entityPosition))", + "planet => planet.OrbitKey == followOrbit.OrbitKey", + "planet => planet.OrbitKey == rootOrbit.OrbitKey", + "Zone.TryGetOrbit(rootOrbit.ParentOrbitKey, out var parentOrbit)", + "Zone.GetOrbitPosition(followOrbit.OrbitKey)", + "Zone.GetOrbitPosition(rootOrbit.OrbitKey)" + }, + [Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs")] = new[] + { + "body => body.OrbitKey == orbit.OrbitKey", + "Zone.GetOrbitPosition(planetInstance.OrbitKey)", + "Zone.GetOrbitPosition(planetInstance.Orbit.ParentOrbitKey)" + }, + [Path.Combine(root, "Assets", "Scripts", "ServerShared", "Behaviors", "ResourceScanner.cs")] = new[] + { + "Entity.Zone.GetOrbitPosition(planet.OrbitKey)" + } + }; + + var missingSymbols = requiredSymbols + .Where(pair => !File.Exists(pair.Key) || pair.Value.Any(symbol => !File.ReadAllText(pair.Key).Contains(symbol, StringComparison.Ordinal))) + .SelectMany(pair => + { + var text = File.Exists(pair.Key) ? File.ReadAllText(pair.Key) : ""; + return pair.Value + .Where(symbol => !text.Contains(symbol, StringComparison.Ordinal)) + .Select(symbol => $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}"); + }) + .ToArray(); + + if (missingSymbols.Length > 0) + { + throw new InvalidOperationException( + "Orbit consumer edges must stay keyed at the public runtime wrapper surface: " + + string.Join("; ", missingSymbols)); + } +} + static void RequireTypedFactionShellLinks(string root) { var checkedFiles = new[] diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index 822f744d7..65efc3ff5 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -137,6 +137,11 @@ rule: `OrbitalEntity` and `OrbitalEntityConstructionBlueprint` retain `OrbitKey`, runtime loadout generation seeds the empty value as `""`, and `Zone` resolves orbit keys for orbital entity movement and dock camera parent lookup. +Renderer and gameplay orbit consumers now stay on that keyed edge too: +intro-cutscene planet selection, zone planet/belt loading, gas-giant parent +lighting, asteroid-belt UI setup, and `ResourceScanner` planet range checks all +read `OrbitKey` from runtime wrappers and ask `Zone` to resolve it instead of +reading wrapper GUID orbit fields directly. The package runtime catalog snapshot indexes items by canonical item key; Unity gameplay, HUD, inventory, trade, ship, and zone helper lookups use `ItemKey` directly instead of deriving `ItemId` and searching by legacy GUID. diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index c590e635f..13a5f2dd7 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -2901,20 +2901,21 @@ public class ActionGameManager : MonoBehaviour { ZoneRenderer.PerspectiveEntity = ship; var entityPosition = ship.Position.xz; - var followOrbit = Zone.Orbits.Keys.MinBy(o => lengthsq(Zone.GetOrbitPosition(o) - entityPosition)); - var followPlanetId = Zone.PlanetInstances.Values.First(planet => planet.OrbitId == followOrbit).ID; + var followOrbit = Zone.Orbits.Values.MinBy(orbit => lengthsq(Zone.GetOrbitPosition(orbit.OrbitKey) - entityPosition)); + var followPlanetId = Zone.PlanetInstances.Values.First(planet => planet.OrbitKey == followOrbit.OrbitKey).ID; var followPlanet = ZoneRenderer.Planets[followPlanetId]; DockCamera.Follow = followPlanet.Body.transform; var rootOrbit = followOrbit; - while (Zone.Orbits[rootOrbit].Parent != Guid.Empty) - rootOrbit = Zone.Orbits[rootOrbit].Parent; - var rootPlanetId = Zone.PlanetInstances.Values.First(planet => planet.OrbitId == rootOrbit).ID; + while (!string.IsNullOrWhiteSpace(rootOrbit.ParentOrbitKey) && + Zone.TryGetOrbit(rootOrbit.ParentOrbitKey, out var parentOrbit)) + rootOrbit = parentOrbit; + var rootPlanetId = Zone.PlanetInstances.Values.First(planet => planet.OrbitKey == rootOrbit.OrbitKey).ID; var rootPlanet = ZoneRenderer.Planets[rootPlanetId]; DockCamera.LookAt = rootPlanet.Body.transform; var shipVelocity = ship.GetBehavior().Limit; - var followOrbitPosition = Zone.GetOrbitPosition(followOrbit); - var shipDirection = normalize(Zone.GetOrbitPosition(rootOrbit) - followOrbitPosition); + var followOrbitPosition = Zone.GetOrbitPosition(followOrbit.OrbitKey); + var shipDirection = normalize(Zone.GetOrbitPosition(rootOrbit.OrbitKey) - followOrbitPosition); ship.Position.xz = followOrbitPosition - shipDirection * shipVelocity * IntroDuration; var startTime = Time.time; diff --git a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs index 4738fd7b1..a57272da1 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs @@ -75,7 +75,7 @@ public class ResourceScanner : Behavior, IAlwaysUpdatedBehavior } else if (Entity.Zone.TryGetPlanet(ScanTargetBodyKey, out var planet)) { - if(length(Entity.Position.xz - Entity.Zone.GetOrbitPosition(planet.OrbitId)) < Range) + if(length(Entity.Position.xz - Entity.Zone.GetOrbitPosition(planet.OrbitKey)) < Range) { _scanTime += dt; if (_scanTime > ScanDuration) diff --git a/Assets/Scripts/Zone Display/ZoneRenderer.cs b/Assets/Scripts/Zone Display/ZoneRenderer.cs index 145d04532..8100928a4 100644 --- a/Assets/Scripts/Zone Display/ZoneRenderer.cs +++ b/Assets/Scripts/Zone Display/ZoneRenderer.cs @@ -191,14 +191,14 @@ public class ZoneRenderer : MonoBehaviour SlimeRenderer.ZoneRadius = zone.Radius; foreach (var orbit in zone.Orbits.Values) { - var planet = zone.PlanetInstances.Values.FirstOrDefault(body => body.OrbitId == orbit.ID); + var planet = zone.PlanetInstances.Values.FirstOrDefault(body => body.OrbitKey == orbit.OrbitKey); if (planet != null) { LoadPlanet(planet); continue; } - var belt = zone.AsteroidBelts.Values.FirstOrDefault(body => body.Orbit == orbit.ID); + var belt = zone.AsteroidBelts.Values.FirstOrDefault(body => body.OrbitKey == orbit.OrbitKey); if (belt != null) LoadAsteroidBelt(belt); } @@ -506,7 +506,7 @@ public class ZoneRenderer : MonoBehaviour foreach (var planet in Planets) { var planetInstance = Zone.PlanetInstances[planet.Key]; - var p = Zone.GetOrbitPosition(planetInstance.OrbitId); + var p = Zone.GetOrbitPosition(planetInstance.OrbitKey); var height = Zone.GetHeight(p); if (-height > maxDepth) maxDepth = -height; planet.Value.transform.position = new Vector3(p.x, 0, p.y); @@ -517,7 +517,7 @@ public class ZoneRenderer : MonoBehaviour Zone.Time * ((GasGiant) Zone.PlanetInstances[planet.Key]).GravityWavesSpeed); if (!(planet.Value is SunObject)) { - var toParent = normalize(Zone.GetOrbitPosition(Zone.Orbits[planetInstance.OrbitId].Parent) - p); + var toParent = normalize(Zone.GetOrbitPosition(planetInstance.Orbit.ParentOrbitKey) - p); gasGiantObject.SunMaterial.LightingDirection = new Vector3(toParent.x, 0, toParent.y); } } @@ -628,7 +628,6 @@ public class AsteroidBeltUI private Vector3[] _normals; private Vector2[] _uvs; private int[] _indices; - private Guid _orbitParent; private Mesh _mesh; private float _size; private Zone _zone; @@ -647,8 +646,6 @@ public class AsteroidBeltUI _zone = zone; Filter = meshFilter; _collider = collider; - var orbit = zone.Orbits[belt.Orbit]; - _orbitParent = orbit.Parent; _vertices = new Vector3[_belt.AsteroidCount * 4]; _normals = new Vector3[_belt.AsteroidCount * 4]; _uvs = new Vector2[_belt.AsteroidCount * 4]; diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 76064fdf9..06a32fcad 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -1370,8 +1370,10 @@ First Aetheria surfaces to publish: typed orbit keys with `Zone` owning orbit-key resolution. Orbital runtime entities and runtime construction blueprints now also retain typed `OrbitKey` values, with `Zone` owning orbital movement and dock-camera - parent-orbit resolution for that seam. Remaining broader simulation paths - still derive legacy GUIDs until those structures move to typed keys. + parent-orbit resolution for that seam. Renderer, intro-cutscene, and + `ResourceScanner` orbit readers now also consume the wrapper `OrbitKey` + edge instead of wrapper GUID orbit fields. Remaining broader simulation + paths still derive legacy GUIDs until those structures move to typed keys. - Done: delete the `ItemInstance.ItemId` legacy-GUID projection; diagnostics now report `ItemKey` so item instances expose only typed item-key identity. - Done: delete `Entity`/`EquippedCargoBay` cargo and consumable GUID lookup