2026-06-25 18:09:33 +01:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using GameCult.Aetheria.State.Verse;
|
|
|
|
|
using Unity.Mathematics;
|
|
|
|
|
|
2026-06-28 15:18:57 +01:00
|
|
|
public sealed class AetheriaUnityEntityBlueprintMaterializer
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
2026-06-28 14:33:52 +01:00
|
|
|
private readonly AetheriaUnityLoadoutItemFactory _loadoutItemFactory;
|
2026-06-25 18:09:33 +01:00
|
|
|
|
2026-06-28 15:18:57 +01:00
|
|
|
public AetheriaUnityEntityBlueprintMaterializer(
|
2026-06-28 14:33:52 +01:00
|
|
|
AetheriaUnityLoadoutItemFactory loadoutItemFactory)
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
2026-06-28 14:33:52 +01:00
|
|
|
_loadoutItemFactory = loadoutItemFactory ?? throw new ArgumentNullException(nameof(loadoutItemFactory));
|
2026-06-25 18:09:33 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-28 15:18:57 +01:00
|
|
|
public EntityConstructionBlueprint MaterializeTemplate(AetheriaRuntimeLoadoutTemplateSnapshot template)
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
|
|
|
|
if (template == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
2026-06-28 15:18:57 +01:00
|
|
|
var blueprint = MaterializeLoadoutEntity(template.RootEntity);
|
2026-06-25 18:09:33 +01:00
|
|
|
if (blueprint != null && string.IsNullOrWhiteSpace(blueprint.Name))
|
|
|
|
|
blueprint.Name = template.Name;
|
|
|
|
|
return blueprint;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-28 15:18:57 +01:00
|
|
|
public EntityConstructionBlueprint MaterializeLoadoutEntity(AetheriaRuntimeEntityLoadoutSnapshot entity)
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
|
|
|
|
if (entity == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var hull = CreateEquippableItem(entity.Hull);
|
|
|
|
|
if (hull == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var blueprint = CreateBlueprint(entity.Kind);
|
|
|
|
|
if (blueprint is ShipConstructionBlueprint shipBlueprint)
|
|
|
|
|
{
|
|
|
|
|
shipBlueprint.Direction = new float2(0, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blueprint.Name = entity.Name;
|
|
|
|
|
blueprint.FactionKey = entity.FactionKey ?? "";
|
|
|
|
|
blueprint.Hull = hull;
|
|
|
|
|
blueprint.Equipment = CreateEquippableSlots(entity.Equipment);
|
|
|
|
|
blueprint.CargoBays = CreateEquippableSlots(entity.CargoBays);
|
|
|
|
|
blueprint.DockingBays = CreateEquippableSlots(entity.DockingBays);
|
|
|
|
|
blueprint.CargoContents = CreateCargoBayContents(entity.CargoContents);
|
|
|
|
|
blueprint.DockingBayContents = CreateCargoBayContents(entity.DockingBayContents);
|
|
|
|
|
blueprint.DockingBayAssignments = entity.DockingBayAssignments.ToArray();
|
|
|
|
|
blueprint.WeaponGroups = entity.WeaponGroups.Select(group => group.ToArray()).ToArray();
|
|
|
|
|
blueprint.Children = entity.Children
|
2026-06-28 15:18:57 +01:00
|
|
|
.Select(MaterializeLoadoutEntity)
|
2026-06-25 18:09:33 +01:00
|
|
|
.Where(child => child != null)
|
|
|
|
|
.ToArray();
|
|
|
|
|
return blueprint;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-28 15:18:57 +01:00
|
|
|
public EntityConstructionBlueprint MaterializeObservedEntity(
|
2026-06-25 18:09:33 +01:00
|
|
|
AetheriaRuntimeEntitySnapshot entity,
|
|
|
|
|
bool isCurrentEntity)
|
|
|
|
|
{
|
|
|
|
|
if (entity == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var hull = CreateEquippableItem(new AetheriaRuntimeLoadoutItemSnapshot(
|
|
|
|
|
entity.HullItemKey,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
true,
|
|
|
|
|
false));
|
|
|
|
|
if (hull == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var blueprint = CreateBlueprint(entity.Kind);
|
|
|
|
|
if (blueprint is ShipConstructionBlueprint shipBlueprint)
|
|
|
|
|
{
|
|
|
|
|
shipBlueprint.Position = new float3((float)entity.PositionX, (float)entity.PositionY, (float)entity.PositionZ);
|
|
|
|
|
shipBlueprint.Direction = new float2((float)entity.DirectionX, (float)entity.DirectionY);
|
|
|
|
|
shipBlueprint.IsPlayerShip = isCurrentEntity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blueprint.Name = entity.Name ?? "";
|
|
|
|
|
blueprint.FactionKey = entity.FactionKey ?? "";
|
|
|
|
|
blueprint.Hull = hull;
|
|
|
|
|
blueprint.Equipment = CreateEquippableSlots(entity.Equipment);
|
|
|
|
|
blueprint.CargoBays = CreateEquippableSlots(entity.CargoBays);
|
|
|
|
|
blueprint.DockingBays = CreateEquippableSlots(entity.DockingBays);
|
|
|
|
|
blueprint.CargoContents = CreateCargoBayContents(entity.CargoContents);
|
|
|
|
|
blueprint.DockingBayContents = CreateCargoBayContents(entity.DockingBayContents);
|
|
|
|
|
blueprint.DockingBayAssignments = entity.DockingBayAssignments.ToArray();
|
|
|
|
|
blueprint.WeaponGroups = entity.WeaponGroups.Select(group => group.ToArray()).ToArray();
|
|
|
|
|
blueprint.Children = Array.Empty<EntityConstructionBlueprint>();
|
|
|
|
|
return blueprint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static EntityConstructionBlueprint CreateBlueprint(string kind)
|
|
|
|
|
{
|
|
|
|
|
return string.Equals(kind, "orbital", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|
? new OrbitalEntityConstructionBlueprint()
|
|
|
|
|
: new ShipConstructionBlueprint();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private (int2 position, EquippableItem item)[] CreateEquippableSlots(
|
|
|
|
|
IReadOnlyList<AetheriaRuntimeLoadoutItemSlotSnapshot> slots)
|
|
|
|
|
{
|
|
|
|
|
return (slots ?? Array.Empty<AetheriaRuntimeLoadoutItemSlotSnapshot>())
|
|
|
|
|
.Select(slot => (position: new int2(slot.X, slot.Y), item: CreateEquippableItem(slot.Item)))
|
|
|
|
|
.Where(slot => slot.item != null)
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private (int2 position, EquippableItem item)[] CreateEquippableSlots(
|
|
|
|
|
IReadOnlyList<AetheriaRuntimeEntityItemSlotSnapshot> slots)
|
|
|
|
|
{
|
|
|
|
|
return (slots ?? Array.Empty<AetheriaRuntimeEntityItemSlotSnapshot>())
|
|
|
|
|
.Select(slot => (position: new int2(slot.X, slot.Y), item: CreateEquippableItem(new AetheriaRuntimeLoadoutItemSnapshot(
|
|
|
|
|
slot.ItemKey,
|
|
|
|
|
slot.Quality,
|
|
|
|
|
slot.Durability,
|
|
|
|
|
slot.Quantity,
|
|
|
|
|
slot.Enabled,
|
|
|
|
|
slot.OverrideShutdown,
|
|
|
|
|
slot.Temperature))))
|
|
|
|
|
.Where(slot => slot.item != null)
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private (int2 position, ItemInstance item)[][] CreateCargoBayContents(
|
|
|
|
|
IReadOnlyList<AetheriaRuntimeCargoBayLoadoutSnapshot> bays)
|
|
|
|
|
{
|
|
|
|
|
return (bays ?? Array.Empty<AetheriaRuntimeCargoBayLoadoutSnapshot>())
|
|
|
|
|
.Select(bay => (bay.Items ?? Array.Empty<AetheriaRuntimeLoadoutItemSlotSnapshot>())
|
2026-06-28 14:33:52 +01:00
|
|
|
.Select(slot => (position: new int2(slot.X, slot.Y), item: _loadoutItemFactory.CreateLoadoutItem(slot.Item)))
|
2026-06-25 18:09:33 +01:00
|
|
|
.Where(slot => slot.item != null)
|
|
|
|
|
.ToArray())
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private EquippableItem CreateEquippableItem(AetheriaRuntimeLoadoutItemSnapshot item)
|
|
|
|
|
{
|
2026-06-28 14:33:52 +01:00
|
|
|
var instance = _loadoutItemFactory.CreateLoadoutItem(item) as EquippableItem;
|
2026-06-25 18:09:33 +01:00
|
|
|
if (instance != null && item.Durability > 0)
|
|
|
|
|
instance.Durability = (float)item.Durability;
|
|
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
}
|