From 33f289dcac98bd5407344e5c7dcf9698d8cc3498 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 16 Jun 2026 16:07:20 +0100 Subject: [PATCH] Move orbital runtime seam onto typed orbit keys --- .voidbot/state/aetheria.cc | Bin 184038 -> 183631 bytes Aetheria.State.Verify/Program.cs | 94 ++++++++++++++++++ Aetheria.State/README.md | 5 + Assets/Scripts/Gameplay/ActionGameManager.cs | 4 +- .../EntityConstructionBlueprintProjector.cs | 6 +- .../Scripts/ServerShared/LoadoutGenerator.cs | 4 +- Assets/Scripts/ServerShared/OrbitalEntity.cs | 13 ++- Assets/Scripts/ServerShared/Zone.cs | 5 + Assets/Scripts/ServerShared/ZoneGenerator.cs | 6 +- docs/aetheria-perfect-machine-map.md | 8 +- 10 files changed, 125 insertions(+), 20 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index f42fcb0f843aee348b49022dcfeef6440520f01c..55687ffedb07c4200e073fbb32f23d8d69b2f27e 100644 GIT binary patch delta 1795 zcmZ`)O^6&t6sBueG`sGQ6|)=28f%593)9Wa{$$xz#OUfq)}O4AfEy5Mr)y>^)7>?x zs-DS2a1aloL9)`20wL-_@dx|~Dtijb#$3E;j=_s3uc8M%3BIcC>6wA`GEBXGRrP)E z``)YHua5ux-uTxaq4A~F((%=$WpAOhsBhgsQ^`&A)zeR76os6jpVLsb8bs$CZGv z@b5aKNJ)6_~dpEJzz$?sz?Beu~hu2V(+h6bmYO(4t-0r%~mwH!DfVTQr0l zY$=8=3pj7YP0S*|#AIG3Q&#U2MI*_0bo)0$0df=-5eZ}wHv6WhqPAmu@CnSKyuyh%uU!Z;wcBkMfvBJ$* zu&NQ&lrW>0xdTgzzzhcq&h#DaIuEFJ3y$~XUmHf_YOG?B?Z6?cfi~vuHWv*H+JgR> z;3)zY)doQ5%N;b;wKnQ;fa1zN1wjc=lOA59lST~Rovg!;h$9v#&n-=rh z^*vgIEW?xuTzjbJC|f_{9s|;tMS7o;s8Z+RMOu|t5^v{7@?m*mV#uw@?A56g&ku#5 zNpaJ!*)6TulNqy~@^ML;2IcH_;WOgJL$>WQMAGFwd z>`jAJ1Nc#O!Q)yz_h#bm%v{-YCiPEc_?fAq!sceyAs~e5KhP%aTTo3shCG$Z(#fHl4)9(Qopq}0 z4VGv+IJjvtm?RykFF)!asU;q2Kn)EZUTF;k0)@b^96RJTvdv>hfjXaNZ(`XBQo z?@S)or@lZ1hv?ZE=e{T4YAB9{k&j9!m^mt&HGNZW3z$!4s#wsyM$iYpLsR1+GiGzne1N<^SIU<^m&oKx(HIZRi(CHzc$tc? delta 1824 zcmZWqU1(fI6y{DtF=>>dO_YS-s7MXnO?H!PW7aC&YKTx`lg&Oz5SrP0XLqN$cV?NH zo9*Uh!73&ATNfNDRDGzF7K#Ot;6syIQG8P${dp0@=f3)+XJ&tGpYHCNIp=)mJKs6; z)8#{dUpaK^DjJ^4W@fXqb5k?NXVx!yBhBy8PM>Yw+RVybbg&s8kiCQXl)L=Uz>{e2 z`i04Xi<1N1?&JV^?yFRmP+g&tk)({dW)V#mMNm%)S!6o7N$bgN!D&)bCBj%U!Og}d zT5FJe>oT^NG2sDr4j3G;sBtP)g;g;ZHLNtLD@-(oEcTcNm9mj=ai;Wm=mksqpM1@Ftq8Mdo?bG%y)pMdtg*7 zOT?!N@>N(!aUKeZrBByg%vR z)kYjz+*KkKh1#I{Hf&pnP_9meOG4t1ZBbmL6|%+PA3aZfM`9mik=UXUyr>5UelB-i1O>71)#iJM_g1|+FB%y z2;&Mb#VklN9ssHU$MBWy;%qmeTb?xUeS@B8_(aOOyWMMT0xRKIFG@kIr-jj`Jz{0Z z0{}2nAOVd_K(VSol5?@rz=ls^;K=HsTZOHil!1n%CTbHaN+KXuQt%(DVPAkk;m}-~ zL`NF;UKSu!9=AjE5?5nchM08>oI+3Ah1y?=MRC}|)XfA;>IzWGHB?fs0z50;j$SO) zEvuv@o7|_kCP}qQ8?q~=O-idad|&Z4hSh~N`+`I15EwEzq1%}WUEz#_j5!HGSgzwl zGEfpw5-A#PSy4gll2${|ZZLI&aK9pCo|e=n7n-@Tqs`QbA@ljF_pFyUKdgGk#{oer zfE01LJysPOR$&m$$u)1%Ih@LS*n7?Rd2eQHIs#-i;{y)OpWmPOc-1?4_N>F~dRTLy z-GDkpJLSvi&agVEx7c!Wv>bOwP+{f<6k6WVqGR6TTFbt$4EisKGj`pqxlwB^4FR#S zvz`VT%Pp8u>L`xAm4^^-l>Wc$SfiAQV`AqsT z)5?5M@IGy(N5;&(x4l90(H?qi{Pp}|?v>?5=L+*KWT4tBOPF)R-o$|2S!Q>~d&X4u z(2HkQa?-Cb4Vxi`c15JM@$U0 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( + "Orbital runtime entities and construction blueprints must retain typed OrbitKey state, with Zone owning orbit-key resolution: " + + string.Join("; ", hits)); + } + + var requiredSymbols = new Dictionary + { + [Path.Combine(root, "Assets", "Scripts", "ServerShared", "OrbitalEntity.cs")] = new[] + { + "public string OrbitKey = \"\";", + "OrbitKey = orbitKey ?? \"\";", + "Zone.GetOrbitPosition(OrbitKey)", + "Zone.GetOrbitVelocity(OrbitKey)" + }, + [Path.Combine(root, "Assets", "Scripts", "ServerShared", "EntityConstructionBlueprintProjector.cs")] = new[] + { + "OrbitKey = orbital.OrbitKey,", + "blueprint.OrbitKey", + "public string OrbitKey = \"\";" + }, + [Path.Combine(root, "Assets", "Scripts", "ServerShared", "LoadoutGenerator.cs")] = new[] + { + "new OrbitalEntity(ItemManager, null, hull, \"\", ItemManager.GameplaySettings.DefaultEntitySettings)" + }, + [Path.Combine(root, "Assets", "Scripts", "ServerShared", "ZoneGenerator.cs")] = new[] + { + "turret.OrbitKey = Zone.OrbitKey(turretOrbit.ID);", + "station.OrbitKey = Zone.OrbitKey(lagrangeOrbit.ID);" + }, + [Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs")] = new[] + { + "Zone.TryGetOrbit(orbital.OrbitKey, out var orbit)", + "planet => planet.OrbitKey == parentOrbitKey" + }, + [Path.Combine(root, "Assets", "Scripts", "ServerShared", "Zone.cs")] = new[] + { + "public float2 GetOrbitVelocity(string 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( + "Orbital runtime seam must stay on typed orbit keys through the entity owner, blueprint projector, and docking path: " + + string.Join("; ", missingSymbols)); + } +} + static void RequireTypedFactionShellLinks(string root) { var checkedFiles = new[] diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index 5e04eb7b0..822f744d7 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -132,6 +132,11 @@ resolves body/orbit keys locally while checkpointing or restoring state. Orbit-targeting agent runtime also now retains typed orbit keys directly: `PatrolOrbitsTask`, `MoveToOrbitState`, and `StationTowing` no longer own raw orbit GUID targets, and `Zone` resolves orbit keys for agent orbit movement. +Orbital runtime entities and their construction blueprints now follow the same +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. 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 1d4f62561..c590e635f 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -2962,8 +2962,8 @@ public class ActionGameManager : MonoBehaviour FollowCamera.enabled = false; var orbital = (OrbitalEntity) entity; DockCamera.Follow = ZoneRenderer.EntityInstances[orbital].transform; - var parentOrbit = Zone.Orbits[orbital.OrbitId].Parent; - var parentOrbitPlanet = Zone.PlanetInstances.Values.FirstOrDefault(planet => planet.OrbitId == parentOrbit)?.ID ?? Guid.Empty; + var parentOrbitKey = Zone.TryGetOrbit(orbital.OrbitKey, out var orbit) ? orbit.ParentOrbitKey : ""; + var parentOrbitPlanet = Zone.PlanetInstances.Values.FirstOrDefault(planet => planet.OrbitKey == parentOrbitKey)?.ID ?? Guid.Empty; if (ZoneRenderer.Planets.ContainsKey(parentOrbitPlanet)) DockCamera.LookAt = ZoneRenderer.Planets[parentOrbitPlanet].Body.transform; else DockCamera.LookAt = ZoneRenderer.ZoneRoot; diff --git a/Assets/Scripts/ServerShared/EntityConstructionBlueprintProjector.cs b/Assets/Scripts/ServerShared/EntityConstructionBlueprintProjector.cs index 98f6838fc..14c61832f 100644 --- a/Assets/Scripts/ServerShared/EntityConstructionBlueprintProjector.cs +++ b/Assets/Scripts/ServerShared/EntityConstructionBlueprintProjector.cs @@ -12,7 +12,7 @@ public static class EntityConstructionBlueprintProjector if (entity is OrbitalEntity orbital) blueprint = new OrbitalEntityConstructionBlueprint { - Orbit = orbital.OrbitId, + OrbitKey = orbital.OrbitKey, SecurityLevel = orbital.SecurityLevel, SecurityRadius = orbital.SecurityRadius }; @@ -66,7 +66,7 @@ public static class EntityConstructionBlueprintProjector private static OrbitalEntity InstantiateFromBlueprint(ItemManager itemManager, Zone zone, OrbitalEntityConstructionBlueprint blueprint, bool instantiate = false) { - var entity = new OrbitalEntity(itemManager, zone, instantiate ? (EquippableItem) itemManager.Instantiate(blueprint.Hull) : blueprint.Hull, blueprint.Orbit, blueprint.Settings); + var entity = new OrbitalEntity(itemManager, zone, instantiate ? (EquippableItem) itemManager.Instantiate(blueprint.Hull) : blueprint.Hull, blueprint.OrbitKey, blueprint.Settings); Restore(itemManager, zone, blueprint, entity, instantiate); entity.SecurityLevel = blueprint.SecurityLevel; entity.SecurityRadius = blueprint.SecurityRadius; @@ -128,7 +128,7 @@ public class ShipConstructionBlueprint : EntityConstructionBlueprint public class OrbitalEntityConstructionBlueprint : EntityConstructionBlueprint { - public Guid Orbit; + public string OrbitKey = ""; public int Story = -1; public SecurityLevel SecurityLevel; public float SecurityRadius; diff --git a/Assets/Scripts/ServerShared/LoadoutGenerator.cs b/Assets/Scripts/ServerShared/LoadoutGenerator.cs index 9bf076017..ee04c898c 100644 --- a/Assets/Scripts/ServerShared/LoadoutGenerator.cs +++ b/Assets/Scripts/ServerShared/LoadoutGenerator.cs @@ -81,7 +81,7 @@ public class LoadoutGenerator return null; } var hull = ItemManager.CreateEquippableInstance(hullRow); - var entity = new OrbitalEntity(ItemManager, null, hull, Guid.Empty, ItemManager.GameplaySettings.DefaultEntitySettings); + var entity = new OrbitalEntity(ItemManager, null, hull, "", ItemManager.GameplaySettings.DefaultEntitySettings); entity.Faction = Faction; OutfitEntity(entity); return EntityConstructionBlueprintProjector.CaptureBlueprint(entity) as OrbitalEntityConstructionBlueprint; @@ -96,7 +96,7 @@ public class LoadoutGenerator return null; } var hull = ItemManager.CreateEquippableInstance(hullRow); - var entity = new OrbitalEntity(ItemManager, null, hull, Guid.Empty, ItemManager.GameplaySettings.DefaultEntitySettings); + var entity = new OrbitalEntity(ItemManager, null, hull, "", ItemManager.GameplaySettings.DefaultEntitySettings); entity.Faction = Faction; var emptyShape = entity.UnoccupiedSpace; diff --git a/Assets/Scripts/ServerShared/OrbitalEntity.cs b/Assets/Scripts/ServerShared/OrbitalEntity.cs index 853cf9fee..02a9f1144 100644 --- a/Assets/Scripts/ServerShared/OrbitalEntity.cs +++ b/Assets/Scripts/ServerShared/OrbitalEntity.cs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -using System; using System.Collections; using System.Collections.Generic; using Unity.Mathematics; @@ -11,23 +10,23 @@ using float2 = Unity.Mathematics.float2; public class OrbitalEntity : Entity { - public Guid OrbitId; + public string OrbitKey = ""; public SecurityLevel SecurityLevel; public float SecurityRadius; public LocationStory Story; public bool CanTow; - public OrbitalEntity(ItemManager itemManager, Zone zone, EquippableItem hull, Guid orbit, EntitySettings settings) : base(itemManager, zone, hull, settings) + public OrbitalEntity(ItemManager itemManager, Zone zone, EquippableItem hull, string orbitKey, EntitySettings settings) : base(itemManager, zone, hull, settings) { - OrbitId = orbit; + OrbitKey = orbitKey ?? ""; } public override void Update(float delta) { - if (OrbitId != Guid.Empty) + if (!string.IsNullOrWhiteSpace(OrbitKey)) { - Position.xz = Zone.GetOrbitPosition(OrbitId); - Velocity = Zone.GetOrbitVelocity(OrbitId); + Position.xz = Zone.GetOrbitPosition(OrbitKey); + Velocity = Zone.GetOrbitVelocity(OrbitKey); } base.Update(delta); diff --git a/Assets/Scripts/ServerShared/Zone.cs b/Assets/Scripts/ServerShared/Zone.cs index 6b8964705..393b414fb 100644 --- a/Assets/Scripts/ServerShared/Zone.cs +++ b/Assets/Scripts/ServerShared/Zone.cs @@ -244,6 +244,11 @@ public class Zone return float2.zero; } + public float2 GetOrbitVelocity(string orbitKey) + { + return GetOrbitVelocity(ParseOrbitGuid(orbitKey)); + } + public int NearestAsteroid(Guid planetDataID, float2 position) { var belt = AsteroidBelts[planetDataID]; diff --git a/Assets/Scripts/ServerShared/ZoneGenerator.cs b/Assets/Scripts/ServerShared/ZoneGenerator.cs index 36220b466..c21093d20 100644 --- a/Assets/Scripts/ServerShared/ZoneGenerator.cs +++ b/Assets/Scripts/ServerShared/ZoneGenerator.cs @@ -277,7 +277,7 @@ public static class ZoneGenerator blueprint.Orbits.Add(turretOrbit); var turret = loadoutGenerator.GenerateTurretLoadout(); if (turret == null) return; - turret.Orbit = turretOrbit.ID; + turret.OrbitKey = Zone.OrbitKey(turretOrbit.ID); blueprint.Entities.Add(turret); } @@ -297,7 +297,7 @@ public static class ZoneGenerator var orbit = selectedStationOrbits[i]; var lagrangeOrbit = CreateLagrangeOrbit(orbit); var station = GetLoadoutGenerator(story.Faction).GenerateStationLoadout(); - station.Orbit = lagrangeOrbit.ID; + station.OrbitKey = Zone.OrbitKey(lagrangeOrbit.ID); station.SecurityLevel = story.Security; station.SecurityRadius = blueprint.Radius; station.Story = i; @@ -314,7 +314,7 @@ public static class ZoneGenerator var lagrangeOrbit = CreateLagrangeOrbit(orbit); var station = GetLoadoutGenerator(nearestFaction).GenerateStationLoadout(); if (station == null) continue; - station.Orbit = lagrangeOrbit.ID; + station.OrbitKey = Zone.OrbitKey(lagrangeOrbit.ID); station.SecurityLevel = security; station.SecurityRadius = blueprint.Radius; blueprint.Entities.Add(station); diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 3a50c4d8a..76064fdf9 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -1367,9 +1367,11 @@ First Aetheria surfaces to publish: through commit/readback state, with the behaviors retaining keyed runtime state directly and `Zone` owning GUID parsing/resolution at the current Unity body runtime boundary. Patrol/tow orbit task targets now also retain - typed orbit keys with `Zone` owning orbit-key resolution. Remaining broader - simulation paths still derive legacy GUIDs until those structures move to - typed keys. + 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. - 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