From 947c591ebd7597697d9dbafabca7463dfaef7c96 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 15 Jul 2026 05:57:17 +0100 Subject: [PATCH] Restore authoritative continuous pilot aim --- Aetheria.State.Daemon.Smoke/Program.cs | 9 ++++++ Aetheria.Unity/Packages/manifest.json | 2 +- Aetheria.Unity/Packages/packages-lock.json | 2 +- .../Tests/DaemonRuntimeDocumentTests.cs | 4 +-- ...AetheriaRuntimeDaemonGameSurfaceBuilder.cs | 29 +++++++++++++++++++ .../AetheriaRuntimeDaemonOperations.cs | 10 +++++-- 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Aetheria.State.Daemon.Smoke/Program.cs b/Aetheria.State.Daemon.Smoke/Program.cs index f7a295c3c..9afc68b38 100644 --- a/Aetheria.State.Daemon.Smoke/Program.cs +++ b/Aetheria.State.Daemon.Smoke/Program.cs @@ -504,6 +504,15 @@ internal sealed class AetheriaDaemonYmirSmokeChecks new AetheriaRuntimeDaemonHealthDocument(), AetheriaRuntimeDaemonCommandBoundaryDocument.Create("daemon")); var combat = Flatten(surface.Surface.Root).Single(node => node.Kind == "combat.presentation"); + var world = Flatten(surface.Surface.Root).Single(node => node.Kind == "world.scene3d"); + var aim = Flatten(surface.Surface.Root).Single(node => node.Kind == "aim.presentation"); + Require(!string.IsNullOrWhiteSpace(world.Props["lookCommand"]) && + world.Props["lookSensitivityRadians"] == "-0.001", + "playable world must advertise the daemon-owned continuous look command and fossil pointer response"); + Require(aim.Props["controlledEntityIndex"] == "0" && + aim.Props["convergenceTargetEntityId"] == run.EntityRecordKey(0, 1) && + aim.Props["minimumConvergenceDistance"] == "50", + "Eve aim presentation must bind the controlled body direction to the fossil convergence semantic"); Require(combat.Props["controlledEntityIndex"] == "0" && combat.Props["selectedTargetEntityIndex"] == "1" && combat.Props["targetVisible"] == "true" && diff --git a/Aetheria.Unity/Packages/manifest.json b/Aetheria.Unity/Packages/manifest.json index 85b53cece..3fa9b5e15 100644 --- a/Aetheria.Unity/Packages/manifest.json +++ b/Aetheria.Unity/Packages/manifest.json @@ -9,6 +9,6 @@ "org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13", "org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1", "org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.1", - "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.23" + "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.24" } } diff --git a/Aetheria.Unity/Packages/packages-lock.json b/Aetheria.Unity/Packages/packages-lock.json index 882821080..80171db0d 100644 --- a/Aetheria.Unity/Packages/packages-lock.json +++ b/Aetheria.Unity/Packages/packages-lock.json @@ -142,7 +142,7 @@ "hash": "d0aa50d31f3b6da96bffc194fdc3aa358f37e332" }, "org.gamecult.eve.unity-scene": { - "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.23", + "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.24", "depth": 0, "source": "git", "dependencies": { diff --git a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs index 0a9017657..e5f3e3bef 100644 --- a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs +++ b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs @@ -3771,8 +3771,8 @@ public class DaemonRuntimeDocumentTests var player = run.Zones[0].Entities[0]; Assert.AreEqual(3, result.AppliedCommandIds.Count); Assert.AreEqual(0, result.RejectedCommandIds.Count); - Assert.AreEqual(0.25, player.DirectionX, 0.0001); - Assert.AreEqual(-0.75, player.DirectionY, 0.0001); + Assert.AreEqual(0.316227766, player.DirectionX, 0.0001); + Assert.AreEqual(-0.948683298, player.DirectionY, 0.0001); Assert.AreEqual(0.8, player.TractorPower, 0.0001); Assert.IsTrue(player.HeatsinksEnabled); } diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs index 38829e55d..2a5ec9f23 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs @@ -608,6 +608,8 @@ namespace GameCult.Aetheria.State.Verse ["movementEnabled"] = isDocked ? "false" : "true", ["presentationMode"] = isDocked ? "docked" : "world", ["movementCommand"] = CommandName(AetheriaRuntimeDaemonCommandKinds.SetMoveVector), + ["lookCommand"] = CommandName(AetheriaRuntimeDaemonCommandKinds.SetLookDirection), + ["lookSensitivityRadians"] = "-0.001", ["focusCommand"] = CommandName(AetheriaRuntimeDaemonCommandKinds.TargetNearest), ["targetCommand"] = CommandName(AetheriaRuntimeDaemonCommandKinds.SetTarget), ["actionCommand"] = CommandName(AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup), @@ -625,6 +627,9 @@ namespace GameCult.Aetheria.State.Verse var combatPresentation = CombatPresentation(run, zone, playerEntityId, simulationSettings); if (combatPresentation != null) presentationChildren.Insert(0, combatPresentation); + var aimPresentation = AimPresentation(run, zone, playerEntityId); + if (aimPresentation != null) + presentationChildren.Insert(0, aimPresentation); return new AetheriaRuntimeSurfaceComponent( id, @@ -647,6 +652,30 @@ namespace GameCult.Aetheria.State.Verse }); } + private static AetheriaRuntimeSurfaceComponent? AimPresentation( + AetheriaRuntimeRunCheckpointCommit run, + AetheriaRuntimeZoneSnapshotCommit zone, + string playerEntityId) + { + var player = FindCurrentEntity(run, zone); + if (player == null) + return null; + + var target = FindTargetEntity(zone, player); + var props = new Dictionary(StringComparer.Ordinal) + { + ["controlledEntityId"] = playerEntityId, + ["controlledEntityIndex"] = player.EntityIndex.ToString(CultureInfo.InvariantCulture), + ["convergenceTargetEntityId"] = target == null + ? "" + : run.EntityRecordKey(zone.ZoneIndex, target.EntityIndex), + ["viewDotRole"] = "aim.marker.view-direction", + ["minimumConvergenceDistance"] = "50", + ["viewDotRadius"] = "0.8" + }; + return Node("aetheria.daemon.game.world.aim", "aim.presentation", props.Select(value => (value.Key, value.Value)).ToArray()); + } + private static AetheriaRuntimeSurfaceComponent? CombatPresentation( AetheriaRuntimeRunCheckpointCommit run, AetheriaRuntimeZoneSnapshotCommit zone, diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperations.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperations.cs index 3dbd5215b..85686efb3 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperations.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperations.cs @@ -529,10 +529,16 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeRunCheckpointCommit run, AetheriaRuntimeDaemonCommandDocument command) { + if (!IsFinite(command.DirectionX) || !IsFinite(command.PositionZ)) + return false; + var length = Math.Sqrt(command.DirectionX * command.DirectionX + command.PositionZ * command.PositionZ); + if (length <= 0.000001) + return false; + return ApplyCurrentEntity(run, command, entity => { - entity.DirectionX = command.DirectionX; - entity.DirectionY = command.PositionZ; + entity.DirectionX = command.DirectionX / length; + entity.DirectionY = command.PositionZ / length; }); }