Aetheria/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeLoadoutSnapshotProjector.cs
2026-06-21 09:37:54 +01:00

161 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
#nullable enable
namespace GameCult.Aetheria.State.Unity
{
public static class AetheriaRuntimeLoadoutSnapshotProjector
{
public static string AppendToZone(
AetheriaRuntimeRunCheckpointCommit run,
int zoneIndex,
string parentEntityKey,
AetheriaRuntimeLoadoutTemplateCommit template)
{
if (run == null || template?.RootEntity == null)
return "";
var zones = (run.Zones ?? Array.Empty<AetheriaRuntimeZoneSnapshotCommit>()).ToArray();
var zone = zones.FirstOrDefault(candidate => candidate != null && candidate.ZoneIndex == zoneIndex);
if (zone == null)
return "";
var entities = (zone.Entities ?? Array.Empty<AetheriaRuntimeEntitySnapshotCommit>()).ToList();
var parentIndex = TryParseEntityKey(parentEntityKey, out var parentZoneIndex, out var parsedParentIndex) &&
parentZoneIndex == zoneIndex
? parsedParentIndex
: -1;
var rootIndex = AppendEntity(entities, template.RootEntity, template.Name);
if (parentIndex >= 0 && parentIndex < entities.Count)
{
var children = (entities[parentIndex].ChildEntityIndices ?? Array.Empty<int>()).ToList();
if (!children.Contains(rootIndex))
children.Add(rootIndex);
entities[parentIndex].ChildEntityIndices = children.ToArray();
}
zone.Entities = entities.ToArray();
run.Zones = zones;
return EntityKey(run.RunId, zoneIndex, rootIndex);
}
private static int AppendEntity(
List<AetheriaRuntimeEntitySnapshotCommit> entities,
AetheriaRuntimeEntityLoadoutCommit loadout,
string templateName)
{
var entityIndex = entities.Count;
var entity = new AetheriaRuntimeEntitySnapshotCommit
{
EntityIndex = entityIndex,
Name = string.IsNullOrWhiteSpace(loadout.Name) ? templateName ?? "" : loadout.Name,
Kind = string.IsNullOrWhiteSpace(loadout.Kind) ? "ship" : loadout.Kind,
DirectionX = 0,
DirectionY = 1,
IsActive = true,
HullItemKey = loadout.Hull?.ItemKey ?? "",
FactionKey = loadout.FactionKey ?? "",
Equipment = CloneSlots(loadout.Equipment),
CargoBays = CloneSlots(loadout.CargoBays),
DockingBays = CloneSlots(loadout.DockingBays),
CargoContents = CloneCargo(loadout.CargoContents),
DockingBayContents = CloneCargo(loadout.DockingBayContents),
DockingBayAssignments = (loadout.DockingBayAssignments ?? Array.Empty<int>()).ToArray(),
WeaponGroups = (loadout.WeaponGroups ?? Array.Empty<IReadOnlyList<int>>())
.Select(group => (IReadOnlyList<int>)(group ?? Array.Empty<int>()).ToArray())
.ToArray(),
TargetEntityIndex = -1,
ShutdownPerformance = 0.25
};
entities.Add(entity);
var childIndices = new List<int>();
foreach (var child in loadout.Children ?? Array.Empty<AetheriaRuntimeEntityLoadoutCommit>())
{
if (child == null)
continue;
childIndices.Add(AppendEntity(entities, child, ""));
}
entity.ChildEntityIndices = childIndices.ToArray();
return entityIndex;
}
private static AetheriaRuntimeLoadoutItemSlotCommit[] CloneSlots(
IReadOnlyList<AetheriaRuntimeLoadoutItemSlotCommit>? slots)
{
return (slots ?? Array.Empty<AetheriaRuntimeLoadoutItemSlotCommit>())
.Where(slot => slot != null)
.Select(CloneSlot)
.ToArray();
}
private static AetheriaRuntimeCargoBayLoadoutCommit[] CloneCargo(
IReadOnlyList<AetheriaRuntimeCargoBayLoadoutCommit>? cargo)
{
return (cargo ?? Array.Empty<AetheriaRuntimeCargoBayLoadoutCommit>())
.Select(bay => new AetheriaRuntimeCargoBayLoadoutCommit
{
Items = CloneSlots(bay?.Items)
})
.ToArray();
}
private static AetheriaRuntimeLoadoutItemSlotCommit CloneSlot(AetheriaRuntimeLoadoutItemSlotCommit slot)
{
return new AetheriaRuntimeLoadoutItemSlotCommit
{
X = slot.X,
Y = slot.Y,
Item = CloneItem(slot.Item)
};
}
private static AetheriaRuntimeLoadoutItemCommit CloneItem(AetheriaRuntimeLoadoutItemCommit? item)
{
return new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = item?.ItemKey ?? "",
Quality = item?.Quality ?? 1.0,
Durability = item?.Durability ?? 1.0,
Quantity = item?.Quantity ?? 1,
Enabled = item?.Enabled ?? true,
OverrideShutdown = item?.OverrideShutdown ?? false
};
}
private static string EntityKey(string runId, int zoneIndex, int entityIndex)
{
return $"global:aetheria.run_state.{(string.IsNullOrWhiteSpace(runId) ? "local" : runId)}.zone.{zoneIndex}.entity.{entityIndex}.v1";
}
private static bool TryParseEntityKey(string entityKey, out int zoneIndex, out int entityIndex)
{
zoneIndex = -1;
entityIndex = -1;
if (string.IsNullOrWhiteSpace(entityKey))
return false;
var parts = entityKey.Split('.');
for (var i = 0; i < parts.Length - 1; i++)
{
if (string.Equals(parts[i], "zone", StringComparison.Ordinal) &&
int.TryParse(parts[i + 1], out zoneIndex))
{
continue;
}
if (string.Equals(parts[i], "entity", StringComparison.Ordinal) &&
int.TryParse(parts[i + 1], out entityIndex))
{
continue;
}
}
return zoneIndex >= 0 && entityIndex >= 0;
}
}
}