diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 8095f2600..20db81b93 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -11829,9 +11829,9 @@ static void RequireMainMenuContinueRunState(string root) { "public static class AetheriaUnityDaemonEntitySnapshotProjector", "public static AetheriaRuntimeEntitySnapshot[] CreateSnapshots(", - "public static int EntityIndexFromRecordKey(string recordKey)", "public static string DaemonEntityRecordKey(string runId, int zoneIndex, int entityIndex)", "new AetheriaRuntimeEntitySnapshot(", + "entity.EntityIndex,", "CreateItemSlots(entity.Equipment)", "CreateWeaponStates(runId, zoneIndex, entity.WeaponStates)", "CreateBehaviorStates(entity.BehaviorStates)", @@ -12023,7 +12023,7 @@ static void RequireMainMenuContinueRunState(string root) "if (string.IsNullOrWhiteSpace(render.RunId))", "Aetheria zone-render feed does not identify a run id.", "AetheriaUnityDaemonEntitySnapshotProjector.CreateSnapshots(runId, render.ZoneIndex, render.EntitySnapshots)", - "AetheriaUnityDaemonEntitySnapshotProjector.EntityIndexFromRecordKey(entity.RecordKey)", + ".OrderBy(entity => entity.EntityIndex)", "_entityProjector.TryApplyInPlace(", "zoneRenderer?.ApplyZoneRender(render)", "_zoneContextProjector.ResolveContext(targetZone, render)", @@ -12798,10 +12798,18 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root) if (!daemonEntitySnapshotProjector.Contains("new AetheriaRuntimeEntitySnapshot(", StringComparison.Ordinal) || !daemonEntitySnapshotProjector.Contains("CreateWeaponStates(runId, zoneIndex, entity.WeaponStates)", StringComparison.Ordinal) || - !daemonEntitySnapshotProjector.Contains("public static int EntityIndexFromRecordKey(string recordKey)", StringComparison.Ordinal)) + !daemonEntitySnapshotProjector.Contains("entity.EntityIndex,", StringComparison.Ordinal)) { throw new InvalidOperationException( - "Unity observer entity projection no longer flows through the dedicated daemon snapshot projector."); + "Unity observer entity projection no longer carries typed daemon entity indices through the dedicated daemon snapshot projector."); + } + + if (daemonEntitySnapshotProjector.Contains("EntityIndexFromRecordKey", StringComparison.Ordinal) || + observedFrameApplier.Contains("EntityIndexFromRecordKey", StringComparison.Ordinal) || + observedEntityProjector.Contains("EntityIndexFromRecordKey", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Unity observer entity projection must use typed daemon entity indices instead of parsing synthetic record keys."); } if (!observedEntityProjector.Contains("public bool TryApplyInPlace(", StringComparison.Ordinal) || @@ -12880,7 +12888,7 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root) "observer.LastObservedState?.ZoneRender", "private bool TryRestoreEntityGraphFromZoneRender(", "AetheriaUnityDaemonEntitySnapshotProjector.CreateSnapshots(runId, render.ZoneIndex, render.EntitySnapshots)", - "AetheriaUnityDaemonEntitySnapshotProjector.EntityIndexFromRecordKey(entity.RecordKey)", + ".OrderBy(entity => entity.EntityIndex)", "_entityProjector.Replace(entitySnapshots, currentEntityKey, _getZone())", "_entityProjector.TryApplyInPlace(", "_entityIndex.TryResolveEntityByRecordKey(currentEntityKey, out var currentEntity)", diff --git a/Assets/Scripts/Gameplay/AetheriaUnityDaemonEntitySnapshotProjector.cs b/Assets/Scripts/Gameplay/AetheriaUnityDaemonEntitySnapshotProjector.cs index 134546192..4b5c4bb8e 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityDaemonEntitySnapshotProjector.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityDaemonEntitySnapshotProjector.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Linq; using GameCult.Aetheria.State.Verse; -using Regex = System.Text.RegularExpressions.Regex; public static class AetheriaUnityDaemonEntitySnapshotProjector { @@ -31,14 +30,6 @@ public static class AetheriaUnityDaemonEntitySnapshotProjector .ToArray(); } - public static int EntityIndexFromRecordKey(string recordKey) - { - var match = Regex.Match(recordKey ?? "", @"\.entity\.(\d+)\.v1$"); - return match.Success && int.TryParse(match.Groups[1].Value, out var index) - ? index - : int.MaxValue; - } - public static string DaemonEntityRecordKey(string runId, int zoneIndex, int entityIndex) { return string.IsNullOrWhiteSpace(runId) @@ -53,6 +44,7 @@ public static class AetheriaUnityDaemonEntitySnapshotProjector { return new AetheriaRuntimeEntitySnapshot( DaemonEntityRecordKey(runId, zoneIndex, entity.EntityIndex), + entity.EntityIndex, entity.Name ?? "", entity.Kind ?? "", entity.PositionX, diff --git a/Assets/Scripts/Gameplay/AetheriaUnityObservedEntityProjector.cs b/Assets/Scripts/Gameplay/AetheriaUnityObservedEntityProjector.cs index 3d6734e9a..ec05eda8e 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityObservedEntityProjector.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityObservedEntityProjector.cs @@ -123,8 +123,7 @@ public sealed class AetheriaUnityObservedEntityProjector private static void ApplyPoseAndSimpleRuntimeState(Entity entity, AetheriaRuntimeEntitySnapshot entitySnapshot) { - entity.DaemonEntityIndex = - AetheriaUnityDaemonEntitySnapshotProjector.EntityIndexFromRecordKey(entitySnapshot.RecordKey); + entity.DaemonEntityIndex = entitySnapshot.EntityIndex; entity.Name = entitySnapshot.Name ?? ""; entity.CultPosition = new CultMath.float3((float)entitySnapshot.PositionX, (float)entitySnapshot.PositionY, (float)entitySnapshot.PositionZ); entity.CultDirection = new CultMath.float2((float)entitySnapshot.DirectionX, (float)entitySnapshot.DirectionY); diff --git a/Assets/Scripts/Gameplay/AetheriaUnityObservedFrameApplier.cs b/Assets/Scripts/Gameplay/AetheriaUnityObservedFrameApplier.cs index 412158ca1..a9ece783d 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityObservedFrameApplier.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityObservedFrameApplier.cs @@ -91,7 +91,7 @@ public sealed class AetheriaUnityObservedFrameApplier } var entitySnapshots = AetheriaUnityDaemonEntitySnapshotProjector.CreateSnapshots(runId, render.ZoneIndex, render.EntitySnapshots) - .OrderBy(entity => AetheriaUnityDaemonEntitySnapshotProjector.EntityIndexFromRecordKey(entity.RecordKey)) + .OrderBy(entity => entity.EntityIndex) .ToArray(); if (entitySnapshots.Length == 0) diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs index dfb611e0d..32711c9be 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs @@ -793,6 +793,7 @@ namespace GameCult.Aetheria.State.Verse { public AetheriaRuntimeEntitySnapshot( string recordKey, + int entityIndex, string name, string kind, double positionX, @@ -830,6 +831,7 @@ namespace GameCult.Aetheria.State.Verse double shutdownPerformance) { RecordKey = recordKey; + EntityIndex = entityIndex; Name = name; Kind = kind; PositionX = positionX; @@ -868,6 +870,7 @@ namespace GameCult.Aetheria.State.Verse } public string RecordKey { get; } + public int EntityIndex { get; } public string Name { get; } public string Kind { get; } public double PositionX { get; }