diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index f8075b9be..464c81094 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -1504,8 +1504,10 @@ static void RequireTypedOrbitConsumerKeys(string root) { [Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs")] = new[] { + "private readonly List _daemonBodyViews", + "AetheriaRuntimeDaemonRenderQueries.QueryBodyViews(_daemonZoneSnapshot, _daemonBodyViews);", + "foreach (var bodyView in _daemonBodyViews)", "foreach (var pose in _daemonBodyPoses)", - "foreach (var body in daemonZone?.Bodies ?? Array.Empty())", "beltPosesByBodyKey.TryGetValue(body.BodyKey ?? \"\", out var beltPose)", "_daemonBodyPosesByBodyKey.TryGetValue(planet.Key, out var pose)", "var p = new float2((float)pose.CenterX, (float)pose.CenterZ);", @@ -1835,6 +1837,9 @@ static void RequireDaemonRenderQueryAuthority(string root) "public static AetheriaRuntimeDaemonBodyPose[] QueryBodyPoses(", "public static int QueryBodyPoses(", "new AetheriaRuntimeDaemonBodyPose(", + "AetheriaRuntimeDaemonBodyView", + "public static AetheriaRuntimeDaemonBodyView[] QueryBodyViews(", + "public static int QueryBodyViews(", "AetheriaRuntimeDaemonAsteroidBeltPose", "public static AetheriaRuntimeDaemonAsteroidBeltPose[] QueryAsteroidBeltPoses(", "public static int QueryAsteroidBeltPoses(", @@ -1948,6 +1953,13 @@ static void RequireDaemonRenderQueryAuthority(string root) "ZoneRenderer must query daemon gravity terrain bands instead of calling mirrored Unity Zone gravity math."); } + if (zoneRenderer.Contains("Settings.PlanetSettings.GravityRadius.Evaluate(", StringComparison.Ordinal) || + zoneRenderer.Contains("Settings.PlanetSettings.GravityDepth.Evaluate(", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "ZoneRenderer must lower daemon-authored gravity influence radius/depth instead of reconstructing gravity brushes from Unity settings."); + } + if (zoneRenderer.Contains("Zone.GetOrbitPosition(", StringComparison.Ordinal)) { throw new InvalidOperationException( @@ -2036,6 +2048,7 @@ static void RequireDaemonRenderQueryAuthority(string root) "public AetheriaRuntimeDaemonRenderSettings RenderSettings { get; set; }", "private AetheriaRuntimeRunCheckpointCommit _daemonRunSnapshot;", "private AetheriaRuntimeZoneSnapshotCommit _daemonZoneSnapshot;", + "private readonly List _daemonBodyViews", "private readonly List _daemonBodyPoses", "private readonly Dictionary _daemonBodyPosesByBodyKey", "private readonly Dictionary _bodyViewsByBodyKey", @@ -2061,8 +2074,10 @@ static void RequireDaemonRenderQueryAuthority(string root) " 2000);", "AetheriaRuntimeDaemonRenderQueries.QueryGravityTerrainBand(", "private readonly List _visibleAsteroidInstancePoses", + "foreach (var bodyView in _daemonBodyViews)", + "if (bodyView.IsAsteroidBelt)", + "AetheriaRuntimeDaemonRenderQueries.QueryBodyViews(_daemonZoneSnapshot, _daemonBodyViews);", "foreach (var pose in _daemonBodyPoses)", - "foreach (var body in daemonZone?.Bodies ?? Array.Empty())", "LoadPlanet(body)", "void LoadPlanet(AetheriaRuntimeBodySnapshotCommit body)", "beltPosesByBodyKey.TryGetValue(body.BodyKey ?? \"\", out var beltPose)", diff --git a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs index 921ca5400..2a2e4ad38 100644 --- a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs +++ b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs @@ -985,6 +985,58 @@ public class DaemonRuntimeDocumentTests Assert.AreEqual(3.5, poses[1].GravityWaveSpeed, 0.0001); } + [Test] + public void DaemonRenderQueriesPublishBodyViewsFromZoneSnapshot() + { + var zone = new AetheriaRuntimeZoneSnapshotCommit + { + Orbits = new[] + { + new AetheriaRuntimeOrbitSnapshotCommit + { + OrbitKey = "orbit:planet", + FixedPositionX = 12, + FixedPositionY = -8 + }, + new AetheriaRuntimeOrbitSnapshotCommit + { + OrbitKey = "orbit:belt", + Distance = 30 + } + }, + Bodies = new[] + { + new AetheriaRuntimeBodySnapshotCommit + { + BodyKey = "body:planet", + OrbitKey = "orbit:planet", + Kind = "planet", + GravityInfluenceRadius = 40, + GravityWellDepth = 7 + }, + new AetheriaRuntimeBodySnapshotCommit + { + BodyKey = "body:belt", + OrbitKey = "orbit:belt", + Kind = "asteroid_belt" + } + } + }; + + var views = new List(); + var count = AetheriaRuntimeDaemonRenderQueries.QueryBodyViews(zone, views); + + Assert.AreEqual(2, count); + Assert.AreEqual("body:planet", views[0].Body.BodyKey); + Assert.IsFalse(views[0].IsAsteroidBelt); + Assert.AreEqual(12, views[0].Pose.CenterX, 0.0001); + Assert.AreEqual(-8, views[0].Pose.CenterZ, 0.0001); + Assert.AreEqual(40, views[0].Body.GravityInfluenceRadius, 0.0001); + Assert.AreEqual(7, views[0].Body.GravityWellDepth, 0.0001); + Assert.AreEqual("body:belt", views[1].Body.BodyKey); + Assert.IsTrue(views[1].IsAsteroidBelt); + } + [Test] public void DaemonRenderQueriesPublishAsteroidBeltPosesFromZoneSnapshot() { diff --git a/Assets/Scripts/Zone Display/ZoneRenderer.cs b/Assets/Scripts/Zone Display/ZoneRenderer.cs index b5f88b724..2a57bb176 100644 --- a/Assets/Scripts/Zone Display/ZoneRenderer.cs +++ b/Assets/Scripts/Zone Display/ZoneRenderer.cs @@ -85,6 +85,7 @@ public class ZoneRenderer : MonoBehaviour private bool _showAsteroidUI; private AetheriaRuntimeRunCheckpointCommit _daemonRunSnapshot; private AetheriaRuntimeZoneSnapshotCommit _daemonZoneSnapshot; + private readonly List _daemonBodyViews = new List(); private readonly List _daemonBodyPoses = new List(); private readonly Dictionary _daemonBodyPosesByBodyKey = new Dictionary(StringComparer.Ordinal); @@ -220,17 +221,17 @@ public class ZoneRenderer : MonoBehaviour { ClearZone(); ApplyDaemonFrame(daemonZone, daemonRun); + RefreshDaemonBodyViews(); RefreshDaemonBodyPoses(); RefreshDaemonAsteroidBeltPoses(); var beltPosesByBodyKey = _daemonAsteroidBeltPoses .Where(pose => !string.IsNullOrWhiteSpace(pose.BodyKey)) .ToDictionary(pose => pose.BodyKey, StringComparer.Ordinal); - foreach (var body in daemonZone?.Bodies ?? Array.Empty()) + foreach (var bodyView in _daemonBodyViews) { - if (body == null) - continue; + var body = bodyView.Body; - if (string.Equals(body.Kind ?? "", "asteroid_belt", StringComparison.OrdinalIgnoreCase)) + if (bodyView.IsAsteroidBelt) { if (beltPosesByBodyKey.TryGetValue(body.BodyKey ?? "", out var beltPose)) LoadAsteroidBelt(beltPose); @@ -467,12 +468,8 @@ public class ZoneRenderer : MonoBehaviour } var bodyRadius = Settings.PlanetSettings.BodyRadius.Evaluate(mass) * (float)body.BodyRadiusMultiplier; - var gravityWellRadius = body.GravityInfluenceRadius > 0 - ? (float)body.GravityInfluenceRadius - : Settings.PlanetSettings.GravityRadius.Evaluate(mass) * (float)body.GravityRadiusMultiplier; - var gravityWellDepth = body.GravityWellDepth != 0 - ? (float)body.GravityWellDepth - : Settings.PlanetSettings.GravityDepth.Evaluate(mass) * (float)body.GravityDepthMultiplier; + var gravityWellRadius = Mathf.Max(0f, (float)body.GravityInfluenceRadius); + var gravityWellDepth = (float)body.GravityWellDepth; planet.Body.transform.localScale = bodyRadius * Vector3.one; planet.GravityWell.transform.localScale = gravityWellRadius * Vector3.one; // var depth = planetInstance.GravityWellDepth; @@ -675,6 +672,11 @@ public class ZoneRenderer : MonoBehaviour // MinimapTintQuad.transform.position = gravPos - Vector3.up*10; } + private void RefreshDaemonBodyViews() + { + AetheriaRuntimeDaemonRenderQueries.QueryBodyViews(_daemonZoneSnapshot, _daemonBodyViews); + } + private void RefreshDaemonBodyPoses() { AetheriaRuntimeDaemonRenderQueries.QueryBodyPoses(_daemonZoneSnapshot, _daemonBodyPoses); diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonRenderQueries.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonRenderQueries.cs index 036599cec..985200e7b 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonRenderQueries.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonRenderQueries.cs @@ -137,6 +137,23 @@ namespace GameCult.Aetheria.State.Verse public double GravityWaveSpeed { get; } } + public readonly struct AetheriaRuntimeDaemonBodyView + { + public AetheriaRuntimeDaemonBodyView( + AetheriaRuntimeBodySnapshotCommit body, + AetheriaRuntimeDaemonBodyPose pose, + bool isAsteroidBelt) + { + Body = body ?? throw new ArgumentNullException(nameof(body)); + Pose = pose; + IsAsteroidBelt = isAsteroidBelt; + } + + public AetheriaRuntimeBodySnapshotCommit Body { get; } + public AetheriaRuntimeDaemonBodyPose Pose { get; } + public bool IsAsteroidBelt { get; } + } + public readonly struct AetheriaRuntimeDaemonAsteroidBeltPose { public AetheriaRuntimeDaemonAsteroidBeltPose( @@ -427,6 +444,54 @@ namespace GameCult.Aetheria.State.Verse return poses.Count; } + public static AetheriaRuntimeDaemonBodyView[] QueryBodyViews( + AetheriaRuntimeZoneSnapshotCommit? zone) + { + var views = new List(); + QueryBodyViews(zone, views); + return views.Count == 0 ? Array.Empty() : views.ToArray(); + } + + public static int QueryBodyViews( + AetheriaRuntimeZoneSnapshotCommit? zone, + List views) + { + if (views == null) throw new ArgumentNullException(nameof(views)); + views.Clear(); + if (zone == null) + return 0; + + var orbitPositions = BuildOrbitPositions(zone); + var orbits = BuildOrbitMap(zone); + foreach (var body in zone.Bodies ?? Array.Empty()) + { + if (body == null || !TryResolveBodyCenter(body, orbitPositions, out var center)) + continue; + + var orbitKey = body.OrbitKey ?? ""; + var parentOrbitKey = orbits.TryGetValue(orbitKey, out var orbit) ? orbit.ParentOrbitKey ?? "" : ""; + var parentCenter = orbitPositions.TryGetValue(parentOrbitKey, out var parent) + ? parent + : new AetheriaRuntimeXzPoint(0, 0); + var pose = new AetheriaRuntimeDaemonBodyPose( + body.BodyKey, + orbitKey, + parentOrbitKey, + body.Kind, + center.x, + center.z, + parentCenter.x, + parentCenter.z, + ResolveWaveSpeed(body)); + views.Add(new AetheriaRuntimeDaemonBodyView( + body, + pose, + string.Equals(body.Kind, "asteroid_belt", StringComparison.OrdinalIgnoreCase))); + } + + return views.Count; + } + public static AetheriaRuntimeDaemonAsteroidBeltPose[] QueryAsteroidBeltPoses( AetheriaRuntimeZoneSnapshotCommit? zone) {