diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 436232b86..e5d0be56a 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Aetheria.State.Smoke/Aetheria.State.Smoke.csproj b/Aetheria.State.Smoke/Aetheria.State.Smoke.csproj index ca788873d..e9e2dc0f7 100644 --- a/Aetheria.State.Smoke/Aetheria.State.Smoke.csproj +++ b/Aetheria.State.Smoke/Aetheria.State.Smoke.csproj @@ -9,5 +9,6 @@ + diff --git a/Aetheria.State.Smoke/Program.cs b/Aetheria.State.Smoke/Program.cs index ca402191b..ade754924 100644 --- a/Aetheria.State.Smoke/Program.cs +++ b/Aetheria.State.Smoke/Program.cs @@ -2,6 +2,8 @@ using Aetheria.State; using Aetheria.State.Documents; using Aetheria.State.Migration; using GameCult.Caching; +using GameCult.Aetheria.State.Unity; +using GameCult.Eve.Surface; var root = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory(); var statePath = AetheriaStatePaths.ResolveDefaultStatePath(root); @@ -105,20 +107,24 @@ await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-s await node.PutOperationsSurfaceAsync(AetheriaOperationsSurfaceProjector.Build(drainStatus)); await node.PutProviderAdvertisementAsync(AetheriaProviderAdvertisementProjector.Build(statePath, now)); - AetheriaEveCommandBridge.QueueCommand( + AetheriaRuntimeEveCommandLog.QueueCommand( statePath, - AetheriaProviderAdvertisementProjector.ProviderId, - AetheriaCatalogSurfaceProjector.SurfaceId, - "aetheria.catalog.refresh", - new Dictionary { ["source"] = "state-smoke" }, - "aetheria-state-smoke"); - AetheriaEveCommandBridge.QueueCommand( + new EveSurfaceCommandRequest( + AetheriaProviderAdvertisementProjector.ProviderId, + AetheriaCatalogSurfaceProjector.SurfaceId, + "aetheria.catalog.refresh", + new Dictionary { ["source"] = "state-smoke" }, + DateTimeOffset.UtcNow, + "aetheria-state-smoke")); + AetheriaRuntimeEveCommandLog.QueueCommand( statePath, - AetheriaProviderAdvertisementProjector.ProviderId, - AetheriaCatalogSurfaceProjector.SurfaceId, - "aetheria.catalog.unknown", - new Dictionary { ["source"] = "state-smoke" }, - "aetheria-state-smoke"); + new EveSurfaceCommandRequest( + AetheriaProviderAdvertisementProjector.ProviderId, + AetheriaCatalogSurfaceProjector.SurfaceId, + "aetheria.catalog.unknown", + new Dictionary { ["source"] = "state-smoke" }, + DateTimeOffset.UtcNow, + "aetheria-state-smoke")); var eveCommandReport = await AetheriaEveCommandBridge.ApplyPendingAsync(node); var eveCommandStatus = new AetheriaEveCommandDrainStatus { diff --git a/Aetheria.State/AetheriaEveCommandBridge.cs b/Aetheria.State/AetheriaEveCommandBridge.cs index 8af91ac55..bf3d81610 100644 --- a/Aetheria.State/AetheriaEveCommandBridge.cs +++ b/Aetheria.State/AetheriaEveCommandBridge.cs @@ -1,4 +1,3 @@ -using System.Buffers; using Aetheria.State.Documents; using MessagePack; @@ -80,43 +79,6 @@ public static class AetheriaEveCommandBridge return report; } - public static void QueueCommand( - string stateFilePath, - string providerId, - string surfaceId, - string command, - IReadOnlyDictionary? payload = null, - string clientId = "aetheria-state") - { - var issuedAtUtc = DateTimeOffset.UtcNow.UtcDateTime.ToString("O"); - var commandId = Guid.NewGuid().ToString("N"); - var pendingDirectory = GetPendingDirectory(stateFilePath); - Directory.CreateDirectory(pendingDirectory); - - var finalPath = Path.Combine( - pendingDirectory, - $"{issuedAtUtc.Replace(':', '-')}.{StableToken(surfaceId)}.{StableToken(command)}.{commandId}.cc"); - var tempPath = finalPath + ".tmp"; - - var buffer = new ArrayBufferWriter(); - var writer = new MessagePackWriter(buffer); - writer.WriteArrayHeader(8); - writer.Write(CommandSchema); - writer.Write(commandId); - writer.Write(providerId ?? ""); - writer.Write(surfaceId ?? ""); - writer.Write(command ?? ""); - writer.Write(issuedAtUtc); - writer.Write(clientId ?? ""); - WritePayload(ref writer, payload); - writer.Flush(); - - File.WriteAllBytes(tempPath, buffer.WrittenSpan.ToArray()); - if (File.Exists(finalPath)) - File.Delete(finalPath); - File.Move(tempPath, finalPath); - } - private static AetheriaPendingEveCommand ReadCommand(string path) { var reader = new MessagePackReader(File.ReadAllBytes(path)); @@ -199,17 +161,6 @@ public static class AetheriaEveCommandBridge }; } - private static void WritePayload(ref MessagePackWriter writer, IReadOnlyDictionary? payload) - { - payload ??= new Dictionary(0, StringComparer.Ordinal); - writer.WriteMapHeader(payload.Count); - foreach (var entry in payload.OrderBy(entry => entry.Key, StringComparer.Ordinal)) - { - writer.Write(entry.Key ?? ""); - writer.Write(entry.Value ?? ""); - } - } - private static IReadOnlyDictionary ReadPayload(ref MessagePackReader reader) { var count = reader.ReadMapHeader(); @@ -225,20 +176,6 @@ public static class AetheriaEveCommandBridge return payload; } - private static string StableToken(string value) - { - if (string.IsNullOrWhiteSpace(value)) - return "empty"; - - var chars = value - .Select(character => char.IsLetterOrDigit(character) ? character : '-') - .ToArray(); - var token = new string(chars).Trim('-').ToLowerInvariant(); - while (token.Contains("--", StringComparison.Ordinal)) - token = token.Replace("--", "-", StringComparison.Ordinal); - return string.IsNullOrWhiteSpace(token) ? "empty" : token; - } - private static string ReadString(ref MessagePackReader reader) { return reader.ReadString() ?? ""; diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 76ce87dac..f10855484 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -900,6 +900,10 @@ First Aetheria surfaces to publish: validates provider/surface/command templates, invokes the current refresh handlers, republishes accepted surfaces, rejects unknown commands, and records typed command-drain status. + - Done: delete provider-side Eve command emission from + `AetheriaEveCommandBridge`; renderer/runtime command files are queued + through `AetheriaRuntimeEveCommandLog`, while the provider bridge only + validates, applies, reports, and deletes accounted commands. - Extend the command bridge beyond refresh commands as gameplay/editor Eve surfaces acquire provider-owned handlers. - Wire the presenter into a Unity scene/prefab for the first runtime surface