2026-06-17 09:19:11 +01:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2026-06-21 20:40:56 +01:00
|
|
|
using System.Globalization;
|
2026-06-17 09:19:11 +01:00
|
|
|
using System.Linq;
|
2026-06-25 18:09:33 +01:00
|
|
|
using GameCult.Mesh;
|
2026-06-17 09:19:11 +01:00
|
|
|
|
|
|
|
|
#nullable enable
|
|
|
|
|
|
2026-06-21 09:54:15 +01:00
|
|
|
namespace GameCult.Aetheria.State.Verse
|
2026-06-17 09:19:11 +01:00
|
|
|
{
|
2026-06-28 03:08:54 +01:00
|
|
|
public static class AetheriaRuntimeStateRefResolver
|
|
|
|
|
{
|
2026-06-21 20:40:56 +01:00
|
|
|
public static bool TryResolveDaemonStateRef(
|
|
|
|
|
AetheriaRuntimeDaemonFrameDocument? frame,
|
|
|
|
|
AetheriaRuntimeDaemonHealthDocument? health,
|
|
|
|
|
AetheriaRuntimeDaemonCommandBoundaryDocument? commandBoundary,
|
|
|
|
|
string stateRef,
|
|
|
|
|
out string value)
|
|
|
|
|
{
|
|
|
|
|
value = "";
|
|
|
|
|
frame ??= new AetheriaRuntimeDaemonFrameDocument();
|
|
|
|
|
health ??= new AetheriaRuntimeDaemonHealthDocument();
|
|
|
|
|
commandBoundary ??= new AetheriaRuntimeDaemonCommandBoundaryDocument();
|
|
|
|
|
|
|
|
|
|
var run = frame.Run ?? new AetheriaRuntimeRunCheckpointCommit();
|
|
|
|
|
var zone = FindCurrentZone(run);
|
|
|
|
|
var entity = FindCurrentEntity(run, zone);
|
|
|
|
|
var target = FindTargetEntity(zone, entity);
|
|
|
|
|
|
|
|
|
|
switch (stateRef)
|
|
|
|
|
{
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameDaemonId:
|
|
|
|
|
value = frame.DaemonId ?? "";
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameVerseId:
|
|
|
|
|
value = health.VerseId ?? "";
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameId:
|
|
|
|
|
value = frame.FrameId.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameTime:
|
|
|
|
|
value = frame.SimulationTimeSeconds.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameStatus:
|
|
|
|
|
value = health.Status ?? "";
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameObservedCommands:
|
|
|
|
|
value = health.ObservedCommandCount.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameAppliedCommands:
|
|
|
|
|
value = health.AppliedCommandCount.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.FrameRejectedCommands:
|
|
|
|
|
value = health.RejectedCommandCount.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentRunId:
|
|
|
|
|
value = run.RunId ?? "";
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentZoneIndex:
|
|
|
|
|
value = run.CurrentZoneIndex.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentEntityKey:
|
|
|
|
|
value = run.CurrentEntityKey ?? "";
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentEntityName:
|
|
|
|
|
value = string.IsNullOrWhiteSpace(entity?.Name) ? "(no current entity)" : entity!.Name;
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentEntityPosition:
|
|
|
|
|
value = FormatPosition(entity);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentTargetName:
|
|
|
|
|
value = string.IsNullOrWhiteSpace(target?.Name) ? "(none)" : target!.Name;
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentEquipmentCount:
|
|
|
|
|
value = Count(entity?.Equipment).ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentCargoBayCount:
|
|
|
|
|
value = Count(entity?.CargoContents).ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CurrentWeaponGroupCount:
|
|
|
|
|
value = Count(entity?.WeaponGroups).ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CommandBoundaryId:
|
|
|
|
|
value = commandBoundary.BoundaryId ?? "";
|
|
|
|
|
return true;
|
|
|
|
|
case AetheriaRuntimeDaemonStateRefs.CommandCount:
|
|
|
|
|
value = Count(commandBoundary.Commands).ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 22:40:43 +01:00
|
|
|
public static bool TryResolveDaemonItemStatRef(
|
|
|
|
|
AetheriaRuntimeDaemonFrameDocument? frame,
|
|
|
|
|
AetheriaRuntimeCatalogSnapshot? catalog,
|
|
|
|
|
string stateRef,
|
|
|
|
|
out string value)
|
|
|
|
|
{
|
|
|
|
|
value = "";
|
|
|
|
|
if (!AetheriaRuntimeDaemonItemStatQueries.TryReadItemStatRef(
|
|
|
|
|
stateRef,
|
|
|
|
|
out var itemKey,
|
|
|
|
|
out var behaviorKind,
|
|
|
|
|
out var behaviorGroup,
|
|
|
|
|
out var fieldKey))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var item = FindDaemonItem(frame?.Run, itemKey);
|
|
|
|
|
var typedItem = catalog?.FindItem(itemKey);
|
|
|
|
|
var field = typedItem?.BehaviorPayloads?
|
|
|
|
|
.FirstOrDefault(candidate =>
|
|
|
|
|
string.Equals(candidate.Kind, behaviorKind, StringComparison.Ordinal) &&
|
|
|
|
|
candidate.Group == behaviorGroup)
|
|
|
|
|
?.Fields?
|
|
|
|
|
.FirstOrDefault(candidate => candidate.Key == fieldKey);
|
|
|
|
|
if (item == null || field == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
value = AetheriaRuntimeDaemonItemStatQueries.EvaluatePerformanceStat(
|
|
|
|
|
field.Value,
|
|
|
|
|
item,
|
2026-06-21 22:50:14 +01:00
|
|
|
item.Temperature)
|
2026-06-21 22:40:43 +01:00
|
|
|
.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-27 16:13:52 +01:00
|
|
|
public static CultMeshStateRefResolver CreateEveSurfaceCultMeshStateRefResolver(
|
2026-06-29 02:15:04 +01:00
|
|
|
Func<AetheriaRuntimeDaemonFrameDocument?> frameProvider,
|
|
|
|
|
Func<AetheriaRuntimeDaemonHealthDocument?> healthProvider,
|
|
|
|
|
Func<AetheriaRuntimeDaemonCommandBoundaryDocument?> commandBoundaryProvider,
|
2026-06-27 16:13:52 +01:00
|
|
|
Func<AetheriaRuntimeCatalogSnapshot?>? catalogProvider = null,
|
|
|
|
|
CultMeshRouteHint? routeHint = null)
|
2026-06-21 21:02:53 +01:00
|
|
|
{
|
2026-06-25 18:09:33 +01:00
|
|
|
var daemonRefs = CultMesh.StateRefResolver(
|
|
|
|
|
"aetheria.daemon.refs",
|
2026-06-29 02:15:04 +01:00
|
|
|
(stateRef, _context) => TryResolveDaemonStateRef(
|
|
|
|
|
frameProvider?.Invoke(),
|
|
|
|
|
healthProvider?.Invoke(),
|
|
|
|
|
commandBoundaryProvider?.Invoke(),
|
|
|
|
|
stateRef,
|
|
|
|
|
out var value)
|
2026-06-21 22:40:43 +01:00
|
|
|
? value
|
2026-06-25 18:09:33 +01:00
|
|
|
: "",
|
|
|
|
|
new[]
|
|
|
|
|
{
|
|
|
|
|
CultMesh.ProjectionSource(AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest.ToString()),
|
|
|
|
|
CultMesh.ProjectionSource(AetheriaRuntimeVerseRecordKeys.DaemonHealth.ToString()),
|
|
|
|
|
CultMesh.ProjectionSource(AetheriaRuntimeVerseRecordKeys.DaemonCommandBoundary.ToString())
|
|
|
|
|
},
|
2026-06-27 16:13:52 +01:00
|
|
|
routeHint);
|
2026-06-25 18:09:33 +01:00
|
|
|
|
|
|
|
|
var itemStatRefs = CultMesh.StateRefResolver(
|
|
|
|
|
"aetheria.daemon.item_stats.refs",
|
|
|
|
|
(stateRef, _context) =>
|
2026-06-27 16:13:52 +01:00
|
|
|
{
|
|
|
|
|
if (!stateRef.StartsWith(AetheriaRuntimeDaemonItemStatQueries.StateRefPrefix + "/", StringComparison.Ordinal))
|
|
|
|
|
return "";
|
|
|
|
|
|
2026-06-29 02:15:04 +01:00
|
|
|
return TryResolveDaemonItemStatRef(
|
|
|
|
|
frameProvider?.Invoke(),
|
|
|
|
|
catalogProvider?.Invoke(),
|
|
|
|
|
stateRef,
|
|
|
|
|
out var value)
|
2026-06-25 18:09:33 +01:00
|
|
|
? value
|
2026-06-27 16:13:52 +01:00
|
|
|
: "";
|
|
|
|
|
},
|
2026-06-25 18:09:33 +01:00
|
|
|
new[]
|
|
|
|
|
{
|
|
|
|
|
CultMesh.ProjectionSource(AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest.ToString()),
|
|
|
|
|
CultMesh.ProjectionSource("catalog:aetheria.runtime")
|
|
|
|
|
},
|
2026-06-27 16:13:52 +01:00
|
|
|
routeHint);
|
2026-06-25 18:09:33 +01:00
|
|
|
|
|
|
|
|
return daemonRefs.Or(itemStatRefs);
|
2026-06-21 22:40:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeLoadoutItemCommit? FindDaemonItem(
|
|
|
|
|
AetheriaRuntimeRunCheckpointCommit? run,
|
|
|
|
|
string itemKey)
|
|
|
|
|
{
|
|
|
|
|
if (run == null || string.IsNullOrWhiteSpace(itemKey))
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
foreach (var zone in run.Zones ?? Array.Empty<AetheriaRuntimeZoneSnapshotCommit>())
|
|
|
|
|
foreach (var entity in zone.Entities ?? Array.Empty<AetheriaRuntimeEntitySnapshotCommit>())
|
|
|
|
|
{
|
|
|
|
|
var item = FindDaemonItem(entity.Equipment, itemKey)
|
|
|
|
|
?? FindDaemonItem(entity.CargoBays, itemKey)
|
|
|
|
|
?? FindDaemonItem(entity.DockingBays, itemKey)
|
|
|
|
|
?? FindDaemonItem(entity.CargoContents, itemKey)
|
|
|
|
|
?? FindDaemonItem(entity.DockingBayContents, itemKey);
|
|
|
|
|
if (item != null)
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeLoadoutItemCommit? FindDaemonItem(
|
|
|
|
|
IReadOnlyList<AetheriaRuntimeLoadoutItemSlotCommit>? slots,
|
|
|
|
|
string itemKey)
|
|
|
|
|
{
|
|
|
|
|
foreach (var slot in slots ?? Array.Empty<AetheriaRuntimeLoadoutItemSlotCommit>())
|
|
|
|
|
{
|
|
|
|
|
if (IsItemMatch(slot?.Item, itemKey))
|
|
|
|
|
return slot?.Item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeLoadoutItemCommit? FindDaemonItem(
|
|
|
|
|
IReadOnlyList<AetheriaRuntimeCargoBayLoadoutCommit>? cargoBays,
|
|
|
|
|
string itemKey)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cargoBay in cargoBays ?? Array.Empty<AetheriaRuntimeCargoBayLoadoutCommit>())
|
|
|
|
|
{
|
|
|
|
|
var item = FindDaemonItem(cargoBay?.Items, itemKey);
|
|
|
|
|
if (item != null)
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool IsItemMatch(AetheriaRuntimeLoadoutItemCommit? item, string itemKey)
|
|
|
|
|
{
|
|
|
|
|
return item != null &&
|
|
|
|
|
string.Equals(item.ItemKey ?? "", itemKey ?? "", StringComparison.Ordinal);
|
2026-06-21 21:02:53 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 20:40:56 +01:00
|
|
|
private static AetheriaRuntimeZoneSnapshotCommit FindCurrentZone(AetheriaRuntimeRunCheckpointCommit run)
|
|
|
|
|
{
|
|
|
|
|
return run.Zones.FirstOrDefault(zone => zone.ZoneIndex == run.CurrentZoneIndex)
|
|
|
|
|
?? run.Zones.FirstOrDefault()
|
|
|
|
|
?? new AetheriaRuntimeZoneSnapshotCommit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeEntitySnapshotCommit? FindCurrentEntity(
|
|
|
|
|
AetheriaRuntimeRunCheckpointCommit run,
|
|
|
|
|
AetheriaRuntimeZoneSnapshotCommit zone)
|
|
|
|
|
{
|
|
|
|
|
var entityIndex = TryParseEntityIndex(run.CurrentEntityKey);
|
|
|
|
|
if (entityIndex >= 0)
|
|
|
|
|
return zone.Entities.FirstOrDefault(entity => entity.EntityIndex == entityIndex);
|
|
|
|
|
|
|
|
|
|
return zone.Entities.FirstOrDefault();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeEntitySnapshotCommit? FindTargetEntity(
|
|
|
|
|
AetheriaRuntimeZoneSnapshotCommit zone,
|
|
|
|
|
AetheriaRuntimeEntitySnapshotCommit? entity)
|
|
|
|
|
{
|
|
|
|
|
if (entity == null || entity.TargetEntityIndex < 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
return zone.Entities.FirstOrDefault(candidate => candidate.EntityIndex == entity.TargetEntityIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int TryParseEntityIndex(string key)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
var marker = ".entity.";
|
|
|
|
|
var markerIndex = key.LastIndexOf(marker, StringComparison.Ordinal);
|
|
|
|
|
if (markerIndex < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
var start = markerIndex + marker.Length;
|
|
|
|
|
var end = start;
|
|
|
|
|
while (end < key.Length && char.IsDigit(key[end]))
|
|
|
|
|
end++;
|
|
|
|
|
|
|
|
|
|
return int.TryParse(key.Substring(start, end - start), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)
|
|
|
|
|
? value
|
|
|
|
|
: -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string FormatPosition(AetheriaRuntimeEntitySnapshotCommit? entity)
|
|
|
|
|
{
|
|
|
|
|
if (entity == null)
|
|
|
|
|
return "(none)";
|
|
|
|
|
|
|
|
|
|
return string.Join(", ", new[]
|
|
|
|
|
{
|
|
|
|
|
entity.PositionX.ToString("0.###", CultureInfo.InvariantCulture),
|
|
|
|
|
entity.PositionY.ToString("0.###", CultureInfo.InvariantCulture),
|
|
|
|
|
entity.PositionZ.ToString("0.###", CultureInfo.InvariantCulture)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int Count<T>(IReadOnlyCollection<T>? values)
|
|
|
|
|
{
|
|
|
|
|
return values?.Count ?? 0;
|
|
|
|
|
}
|
2026-06-17 09:19:11 +01:00
|
|
|
}
|
|
|
|
|
}
|