diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 80b36b59a..64a272164 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 832248105..14a434ca8 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -19,6 +19,7 @@ RequireTypedOrbitalEntityOrbitKeys(root); RequireTypedOrbitConsumerKeys(root); RequireKeyedOrbitRuntimeWrappers(root); RequireNativeZoneKeyResolution(root); +RequireTypedAsteroidZoneApi(root); RequireTypedFactionShellLinks(root); RequireFactionKeyIdentity(root); RequireEveRuntimeBootstrap(root); @@ -1262,6 +1263,54 @@ static void RequireNativeZoneKeyResolution(string root) } } +static void RequireTypedAsteroidZoneApi(string root) +{ + var zoneSourcePath = Path.Combine(root, "Assets", "Scripts", "ServerShared", "Zone.cs"); + var zoneSource = File.Exists(zoneSourcePath) + ? File.ReadAllText(zoneSourcePath) + : throw new InvalidOperationException("Cannot verify typed asteroid Zone API; Zone source is missing."); + + var forbiddenSymbols = new[] + { + "public int NearestAsteroid(Guid planetDataID, float2 position)", + "public bool AsteroidExists(Guid planetDataID, int asteroid)", + "public void MineAsteroid(Entity miner, Guid asteroidBelt, int asteroid, float damage, float efficiency, float penetration)", + "BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt.Key)));", + "private void UpdateAsteroidTransforms(Guid planetDataID)", + "MineAsteroid(miner, belt.ID, asteroid, damage, efficiency, penetration);" + }; + var hits = forbiddenSymbols + .Where(symbol => zoneSource.Contains(symbol, StringComparison.Ordinal)) + .Select(symbol => $"Assets/Scripts/ServerShared/Zone.cs: contains {symbol}") + .ToArray(); + if (hits.Length > 0) + { + throw new InvalidOperationException( + "Zone asteroid helpers must keep typed body-key or runtime-object authority rather than Guid overloads: " + + string.Join("; ", hits)); + } + + var requiredSymbols = new[] + { + "foreach (var belt in AsteroidBelts.Values)", + "BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt)));", + "public int NearestAsteroid(string asteroidBeltKey, float2 position)", + "if (!TryGetAsteroidBelt(asteroidBeltKey, out var belt))", + "public bool AsteroidExists(string asteroidBeltKey, int asteroid)", + "private void UpdateAsteroidTransforms(AsteroidBelt belt)", + "public void MineAsteroid(Entity miner, string asteroidBeltKey, int asteroid, float damage, float efficiency, float penetration)" + }; + var missingSymbols = requiredSymbols + .Where(symbol => !zoneSource.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingSymbols.Length > 0) + { + throw new InvalidOperationException( + "Zone asteroid helpers must route through typed body keys or runtime belt objects: " + + string.Join(", ", missingSymbols)); + } +} + static void RequireFactionKeyIdentity(string root) { var checkedFiles = new[] diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index 87f4d0ded..6bccea6ec 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -150,6 +150,10 @@ instead of reading a raw wrapper orbit GUID. body and orbit lookups resolve through key-indexed runtime dictionaries rather than reparsing GUIDs from `BodyKey` or `OrbitKey` strings before touching the Guid-indexed substrate. +The live asteroid helper surface follows the same rule: nearest-asteroid, +asteroid-exists, transform-update, and mining paths now use typed body keys or +runtime `AsteroidBelt` objects directly instead of Guid asteroid-belt helper +overloads. 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/ServerShared/Zone.cs b/Assets/Scripts/ServerShared/Zone.cs index ca4a70a38..ee59cce19 100644 --- a/Assets/Scripts/ServerShared/Zone.cs +++ b/Assets/Scripts/ServerShared/Zone.cs @@ -173,11 +173,11 @@ public class Zone orbit.Value.Velocity = (orbit.Value.Position - orbit.Value.PreviousPosition) / deltaTime; } - foreach (var belt in AsteroidBelts) + foreach (var belt in AsteroidBelts.Values) { - Array.Copy(belt.Value.NewTransforms, belt.Value.Transforms, belt.Value.Transforms.Length); - belt.Value.OrbitPosition = belt.Value.NewOrbitPosition; - BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt.Key))); + Array.Copy(belt.NewTransforms, belt.Transforms, belt.Transforms.Length); + belt.OrbitPosition = belt.NewOrbitPosition; + BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt))); } foreach(var agent in Agents) @@ -245,9 +245,10 @@ public class Zone : float2.zero; } - public int NearestAsteroid(Guid planetDataID, float2 position) + public int NearestAsteroid(string asteroidBeltKey, float2 position) { - var belt = AsteroidBelts[planetDataID]; + if (!TryGetAsteroidBelt(asteroidBeltKey, out var belt)) + return -1; var asteroidPositions = belt.Transforms; int nearest = 0; @@ -255,7 +256,7 @@ public class Zone for (int i = 0; i < belt.AsteroidCount; i++) { var dist = lengthsq(asteroidPositions[i].xz - position); - if (AsteroidExists(planetDataID, i) && dist < nearestDistance) + if (belt.ContainsAsteroid(i) && dist < nearestDistance) { nearest = i; nearestDistance = dist; @@ -265,17 +266,13 @@ public class Zone return nearest; } - public bool AsteroidExists(Guid planetDataID, int asteroid) => AsteroidBelts[planetDataID].ContainsAsteroid(asteroid); - public bool AsteroidExists(string asteroidBeltKey, int asteroid) { return TryGetAsteroidBelt(asteroidBeltKey, out var belt) && belt.ContainsAsteroid(asteroid); } - private void UpdateAsteroidTransforms(Guid planetDataID) + private void UpdateAsteroidTransforms(AsteroidBelt belt) { - var belt = AsteroidBelts[planetDataID]; - belt.NewOrbitPosition = GetOrbitPosition(belt.Orbit.ParentOrbitKey); for (var i = 0; i < belt.AsteroidCount; i++) { @@ -298,9 +295,10 @@ public class Zone } } - public void MineAsteroid(Entity miner, Guid asteroidBelt, int asteroid, float damage, float efficiency, float penetration) + public void MineAsteroid(Entity miner, string asteroidBeltKey, int asteroid, float damage, float efficiency, float penetration) { - var belt = AsteroidBelts[asteroidBelt]; + if (!TryGetAsteroidBelt(asteroidBeltKey, out var belt)) + return; //var asteroidTransform = belt.Transforms[asteroid]; var size = belt.GetAsteroid(asteroid).Size; @@ -337,12 +335,6 @@ public class Zone } } - public void MineAsteroid(Entity miner, string asteroidBeltKey, int asteroid, float damage, float efficiency, float penetration) - { - if (TryGetAsteroidBelt(asteroidBeltKey, out var belt)) - MineAsteroid(miner, belt.ID, asteroid, damage, efficiency, penetration); - } - public SecurityLevel GetSecurityLevel(float2 pos) { if (GalaxyZone.Owner==null) return SecurityLevel.Open; diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index c9b084781..c5367460a 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -1377,9 +1377,10 @@ First Aetheria surfaces to publish: runtime wrappers no longer publish separate wrapper orbit GUID fields either; they retain `OrbitKey` plus their runtime `Orbit` object. `Zone`'s key-facing lookup surface also resolves through native key-indexed runtime - dictionaries instead of reparsing GUIDs from key strings. Remaining broader - simulation paths still derive legacy GUIDs until those structures move to - typed keys. + dictionaries instead of reparsing GUIDs from key strings. Zone asteroid + helpers now also route through typed body keys or runtime `AsteroidBelt` + objects instead of Guid overloads. 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