using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using SpaceGame.Api.Shared.Runtime; using SpaceGame.Api.Universe.Simulation; namespace SpaceGame.Api.Definitions; public sealed class ConstructionDefinition { public string? RecipeId { get; set; } public string FacilityCategory { get; set; } = "station"; public List RequiredModules { get; set; } = []; public List Requirements { get; set; } = []; public float CycleTime { get; set; } public float BatchSize { get; set; } = 1f; public float ProductsPerHour { get; set; } public float MaxEfficiency { get; set; } = 1f; public int Priority { get; set; } } public sealed class ItemPriceDefinition { public float Min { get; set; } public float Max { get; set; } public float Avg { get; set; } } public sealed class ItemEffectDefinition { public required string Type { get; set; } public float Product { get; set; } } public sealed class ItemProductionDefinition { public float Time { get; set; } public float Amount { get; set; } public string Method { get; set; } = "default"; public string Name { get; set; } = "Universal"; public List Wares { get; set; } = []; public List Effects { get; set; } = []; } public sealed class StarDefinition { public string Kind { get; set; } = "main-sequence"; public required string Color { get; set; } public required string Glow { get; set; } public float Size { get; set; } public float OrbitRadius { get; set; } public float OrbitSpeed { get; set; } public float OrbitPhaseAtEpoch { get; set; } } public sealed class MoonDefinition { public required string Label { get; set; } public float Size { get; set; } public required string Color { get; set; } public float OrbitRadius { get; set; } public float OrbitSpeed { get; set; } public float OrbitPhaseAtEpoch { get; set; } public float OrbitInclination { get; set; } public float OrbitLongitudeOfAscendingNode { get; set; } } public sealed class SolarSystemDefinition { public required string Id { get; set; } public required string Label { get; set; } public required float[] Position { get; set; } public required List Stars { get; set; } public required AsteroidFieldDefinition AsteroidField { get; set; } public required List ResourceNodes { get; set; } public required List Planets { get; set; } } public sealed class RaceDefinition { public required string Id { get; set; } public required string Name { get; set; } public string Description { get; set; } = string.Empty; public string Icon { get; set; } = string.Empty; [JsonIgnore] public string Label => Name; } public sealed class FactionDefinition { public required string Id { get; set; } public int Version { get; set; } public required string Name { get; set; } public string Description { get; set; } = string.Empty; public string Icon { get; set; } = string.Empty; public string? Race { get; set; } public List Licenses { get; set; } = []; [JsonIgnore] public string Label => Name; [JsonIgnore] public string? RaceId => Race; } public sealed class FactionLicenseDefinition { public required string Type { get; set; } public string Name { get; set; } = string.Empty; public string Icon { get; set; } = string.Empty; public float Price { get; set; } } public sealed class AsteroidFieldDefinition { public int DecorationCount { get; set; } public float RadiusOffset { get; set; } public float RadiusVariance { get; set; } public float HeightVariance { get; set; } } public sealed class ResourceNodeDefinition { public string SourceKind { get; set; } = "local-space"; public string? AnchorReference { get; set; } public float Angle { get; set; } public float RadiusOffset { get; set; } public float InclinationDegrees { get; set; } public int? AnchorPlanetIndex { get; set; } public int? AnchorMoonIndex { get; set; } public float OreAmount { get; set; } public required string ItemId { get; set; } public int ShardCount { get; set; } } public sealed class ItemDefinition { public required string Id { get; set; } public required string Name { get; set; } public string Description { get; set; } = string.Empty; [JsonIgnore] public StorageKind? CargoKind { get; set; } public float Volume { get; set; } = 1f; public int Version { get; set; } public string FactoryName { get; set; } = string.Empty; public string Icon { get; set; } = string.Empty; public string Group { get; set; } = string.Empty; public ItemPriceDefinition? Price { get; set; } public List Illegal { get; set; } = []; public List Production { get; set; } = []; public ConstructionDefinition? Construction { get; set; } [JsonPropertyName("transport")] public string Transport { get => CargoKind?.ToDataValue() ?? string.Empty; set => CargoKind = value.ToNullableStorageKind(); } } public sealed class RecipeOutputDefinition { public required string ItemId { get; set; } public float Amount { get; set; } } public sealed class RecipeInputDefinition { public string ItemId { get; set; } = string.Empty; public float Amount { get; set; } [JsonPropertyName("ware")] public string Ware { set => ItemId = value; } } public sealed class ModuleDockDefinition { public int Capacity { get; set; } public required string Size { get; set; } } public sealed class ModuleCargoDefinition { public float Max { get; set; } public required string Type { get; set; } } public sealed class ModuleWorkforceDefinition { [JsonPropertyName("capacity")] public float SupportedPopulation { get; set; } [JsonPropertyName("max")] public float RequiredWorkforce { get; set; } public string Race { get; set; } = string.Empty; } public sealed class ModuleMountDefinition { public required string Group { get; set; } public required string Size { get; set; } public bool Hittable { get; set; } public List Types { get; set; } = []; } public sealed class ModuleBuildRecipeDefinition { public float Time { get; set; } public float Amount { get; set; } public string Method { get; set; } = "default"; public string Name { get; set; } = "Universal"; public List Wares { get; set; } = []; } public class ModuleDefinition { public ModuleDefinition() { } [SetsRequiredMembers] protected ModuleDefinition(ModuleDefinition source) { Id = source.Id; Name = source.Name; Description = source.Description; Type = source.Type; ModuleType = source.ModuleType; ProductIds = [.. source.ProductIds]; Radius = source.Radius; Hull = source.Hull; Version = source.Version; Macro = source.Macro; MakerRace = source.MakerRace; ExplosionDamage = source.ExplosionDamage; Price = source.Price; Owners = [.. source.Owners]; Cargo = source.Cargo; SerializedWorkforce = source.SerializedWorkforce; Docks = [.. source.Docks]; Shields = [.. source.Shields]; Turrets = [.. source.Turrets]; BuildRecipes = [.. source.BuildRecipes]; } public required string Id { get; set; } public required string Name { get; set; } public string Description { get; set; } = string.Empty; public required string Type { get; set; } [JsonIgnore] public ModuleType ModuleType { get; set; } [JsonPropertyName("product")] public List ProductIds { get; set; } = []; [JsonIgnore] public virtual IReadOnlyList ProductItemIds => []; public float Radius { get; set; } = 12f; public float Hull { get; set; } = 100f; public int Version { get; set; } public string Macro { get; set; } = string.Empty; public string MakerRace { get; set; } = string.Empty; public int ExplosionDamage { get; set; } public ItemPriceDefinition? Price { get; set; } public List Owners { get; set; } = []; public ModuleCargoDefinition? Cargo { get; set; } [JsonPropertyName("workForce")] public ModuleWorkforceDefinition? SerializedWorkforce { get; set; } public List Docks { get; set; } = []; public List Shields { get; set; } = []; public List Turrets { get; set; } = []; [JsonPropertyName("production")] public List BuildRecipes { get; set; } = []; } public abstract class ProductionLaneModuleDefinition : ModuleDefinition { [SetsRequiredMembers] protected ProductionLaneModuleDefinition(ModuleDefinition source, float requiredWorkforce) : base(source) { RequiredWorkforce = requiredWorkforce; } public float RequiredWorkforce { get; init; } } public sealed class ProductionModuleDefinition : ProductionLaneModuleDefinition { [SetsRequiredMembers] internal ProductionModuleDefinition(ModuleDefinition source, float requiredWorkforce) : base(source, requiredWorkforce) { ProductItemIds = [.. source.ProductIds]; } public override IReadOnlyList ProductItemIds { get; } = []; } public sealed class BuildModuleDefinition : ProductionLaneModuleDefinition { [SetsRequiredMembers] internal BuildModuleDefinition(ModuleDefinition source, float requiredWorkforce) : base(source, requiredWorkforce) { } } public sealed class HabitationModuleDefinition : ModuleDefinition { [SetsRequiredMembers] internal HabitationModuleDefinition(ModuleDefinition source, float supportedPopulation) : base(source) { SupportedPopulation = supportedPopulation; } public float SupportedPopulation { get; init; } } public sealed class StorageModuleDefinition : ModuleDefinition { [SetsRequiredMembers] internal StorageModuleDefinition(ModuleDefinition source, StorageKind storageKind, float storageCapacity) : base(source) { StorageKind = storageKind; StorageCapacity = storageCapacity; } public StorageKind StorageKind { get; init; } public float StorageCapacity { get; init; } } public sealed class ModuleRecipeDefinition { public required string ModuleId { get; set; } public float Duration { get; set; } public required List Inputs { get; set; } } public sealed class RecipeDefinition { public required string Id { get; set; } public required string Label { get; set; } public required string FacilityCategory { get; set; } public float Duration { get; set; } public int Priority { get; set; } public List RequiredModules { get; set; } = []; public List Inputs { get; set; } = []; public List Outputs { get; set; } = []; public string? ShipOutputId { get; set; } } public sealed class PlanetDefinition { public required string Label { get; set; } public string PlanetType { get; set; } = "terrestrial"; public string Shape { get; set; } = "sphere"; public List Moons { get; set; } = []; public float OrbitRadius { get; set; } public float OrbitSpeed { get; set; } public float OrbitEccentricity { get; set; } public float OrbitInclination { get; set; } public float OrbitLongitudeOfAscendingNode { get; set; } public float OrbitArgumentOfPeriapsis { get; set; } public float OrbitPhaseAtEpoch { get; set; } public float Size { get; set; } public required string Color { get; set; } public float Tilt { get; set; } public bool HasRing { get; set; } } public sealed class ShipDefinition { public required string Id { get; set; } public int Version { get; set; } public required string Name { get; set; } public string Description { get; set; } = string.Empty; public string Size { get; set; } = string.Empty; public float ExplosionDamage { get; set; } public float Hull { get; set; } public Dictionary Storage { get; set; } = new(StringComparer.Ordinal); public int People { get; set; } public string Purpose { get; set; } = string.Empty; public string Thruster { get; set; } = string.Empty; public string Type { get; set; } = string.Empty; public float Mass { get; set; } public ShipInertiaDefinition? Inertia { get; set; } public ShipDragDefinition? Drag { get; set; } public List Engines { get; set; } = []; public List Shields { get; set; } = []; public List Weapons { get; set; } = []; public List Turrets { get; set; } = []; public List Cargo { get; set; } = []; public List Docks { get; set; } = []; public List Owners { get; set; } = []; public ItemPriceDefinition? Price { get; set; } public List Production { get; set; } = []; [JsonIgnore] public string Label => Name; [JsonIgnore] public string Kind => InferKind(Purpose); [JsonIgnore] public string Class => Type; [JsonIgnore] public float Speed => InferLocalSpeed(Size); [JsonIgnore] public float WarpSpeed => InferWarpSpeed(Size); [JsonIgnore] public float FtlSpeed => InferFtlSpeed(Size); [JsonIgnore] public float SpoolTime => InferSpoolTime(Size); [JsonIgnore] public float CargoCapacity => Cargo.Sum(entry => entry.Max); [JsonIgnore] public StorageKind? CargoKind => Cargo .SelectMany(entry => entry.Types) .Select(type => type.ToNullableStorageKind()) .FirstOrDefault(kind => kind is not null); [JsonIgnore] public float MaxHealth => Hull; [JsonIgnore] public IReadOnlyList Capabilities => InferCapabilities(Purpose, Type, Cargo, Turrets); private static string InferKind(string purpose) => purpose switch { "build" => "construction", "trade" => "transport", "mine" => "mining", "fight" => "military", "auxiliary" => "military", _ => purpose, }; private static List InferCapabilities( string purpose, string type, IReadOnlyCollection cargo, IReadOnlyCollection turrets) { var capabilities = new List { "warp", "ftl" }; if (string.Equals(purpose, "mine", StringComparison.Ordinal) || type.Contains("miner", StringComparison.Ordinal) || turrets.Any(turret => turret.Types.Contains("mining", StringComparer.Ordinal))) { capabilities.Add("mining"); } if (cargo.Any(entry => entry.Types.Contains("container", StringComparer.Ordinal) || entry.Types.Contains("solid", StringComparer.Ordinal) || entry.Types.Contains("liquid", StringComparer.Ordinal))) { capabilities.Add("cargo"); } return capabilities; } private static float InferWarpSpeed(string size) => size switch { "extrasmall" => 4.8f, "small" => 4.2f, "medium" => 3.4f, "large" => 2.4f, "extralarge" => 1.8f, _ => 3f, }; private static float InferLocalSpeed(string size) => size switch { "extrasmall" => 420f, "small" => 320f, "medium" => 230f, "large" => 150f, "extralarge" => 110f, _ => 200f, }; private static float InferFtlSpeed(string size) => size switch { "extrasmall" => 1f, "small" => 0.85f, "medium" => 0.7f, "large" => 0.55f, "extralarge" => 0.45f, _ => 0.6f, }; private static float InferSpoolTime(string size) => size switch { "extrasmall" => 0.8f, "small" => 1f, "medium" => 1.4f, "large" => 2f, "extralarge" => 2.6f, _ => 1.5f, }; } public sealed class ShipInertiaDefinition { public float Pitch { get; set; } public float Yaw { get; set; } public float Roll { get; set; } } public sealed class ShipDragDefinition { public float Forward { get; set; } public float Reverse { get; set; } public float Horizontal { get; set; } public float Vertical { get; set; } public float Pitch { get; set; } public float Yaw { get; set; } public float Roll { get; set; } } public sealed class ShipMountDefinition { public string? Group { get; set; } public required string Size { get; set; } public bool Hittable { get; set; } public List Types { get; set; } = []; } public sealed class ShipCargoDefinition { public float Max { get; set; } public List Types { get; set; } = []; } public sealed class ScenarioDefinition { public required WorldGenerationOptions WorldGeneration { get; set; } public required List InitialStations { get; set; } public required List ShipFormations { get; set; } public required List PatrolRoutes { get; set; } } public sealed class InitialStationDefinition { public required string SystemId { get; set; } public string Label { get; set; } = "Orbital Station"; public string Color { get; set; } = "#8df0d2"; public string Objective { get; set; } = "general"; public List StartingModules { get; set; } = []; public string? FactionId { get; set; } public int? PlanetIndex { get; set; } public int? LagrangeSide { get; set; } public float[]? Position { get; set; } } public sealed class ShipFormationDefinition { public required string ShipId { get; set; } public int Count { get; set; } public required float[] Center { get; set; } public required string SystemId { get; set; } public string? FactionId { get; set; } public Dictionary StartingInventory { get; set; } = new(StringComparer.Ordinal); } public sealed class PatrolRouteDefinition { public required string SystemId { get; set; } public required List Points { get; set; } }