using System; using System.Collections.Generic; using System.Linq; #nullable enable namespace GameCult.Aetheria.State.Verse { public static class AetheriaRuntimeAssets { public static AetheriaRuntimeAssetManifestDocument ProjectManifest( AetheriaRuntimeCatalogSnapshot? catalog, string runId = "", string baseUri = "cultmesh://aetheria.local/assets") { var entries = new Dictionary(StringComparer.Ordinal); Add(entries, MapIcon("entity.player", "Player", "Sprites/Icons/Stroked/Ship")); Add(entries, MapIcon("entity.ship", "Ship", "Sprites/Icons/Stroked/Ship")); Add(entries, MapIcon("entity.orbital", "Orbital", "Sprites/Icons/Stroked/orbital")); Add(entries, MapIcon("entity.station", "Station", "Sprites/Icons/station1")); Add(entries, MapIcon("entity.projectile", "Projectile", "Sprites/Icons/Lightning Bolt")); Add(entries, MapIcon("body.planet", "Planet", "Sprites/Icons/Stroked/Planet")); Add(entries, MapIcon("body.sun", "Sun", "Sprites/Icons/Stroked/Sun")); Add(entries, MapIcon("body.asteroid", "Asteroid", "Sprites/Icons/Stroked/Planet")); Add(entries, MapPrefab("prefab.entity.player", "Player Ship", "Prefabs/Ships/Djinni")); Add(entries, MapPrefab("prefab.entity.ship", "Ship", "Prefabs/Ships/Djinni")); Add(entries, MapPrefab("prefab.entity.station", "Station", "Prefabs/Stations/AsteroidOutpost")); Add(entries, MapPrefab("prefab.entity.orbital", "Orbital", "Prefabs/Stations/Zenith")); Add(entries, MapPrefab("prefab.entity.projectile", "Projectile", "Prefabs/Lightning")); foreach (var inventoryAsset in InventoryUiAssets()) Add(entries, inventoryAsset); foreach (var item in catalog?.Items ?? Array.Empty()) { if (item == null || string.IsNullOrWhiteSpace(item.ItemKey)) continue; var icon = AssetRefFromCatalogIcon(item.ActionBarIcon, $"item.{item.ItemKey}.icon"); if (!string.IsNullOrWhiteSpace(icon.AssetKey)) { Add(entries, new AetheriaRuntimeAssetManifestEntry { Ref = icon, Tags = new[] { "item", item.ItemKey, item.Category ?? "" } .Where(tag => !string.IsNullOrWhiteSpace(tag)) .ToArray() }); } } return new AetheriaRuntimeAssetManifestDocument { PublishedAtUtc = DateTime.UtcNow.ToString("O"), RunId = runId ?? "", BaseUri = string.IsNullOrWhiteSpace(baseUri) ? "cultmesh://aetheria.local/assets" : baseUri, Assets = entries.Values .OrderBy(entry => entry.Ref.AssetKey, StringComparer.Ordinal) .ToArray() }; } public static AetheriaRuntimeAssetRef ResolveEntityIcon(AetheriaRuntimeViewportObject? obj) { if (obj?.Controlled == true) return Sprite("map.entity.player", "Sprites/Icons/Stroked/Ship"); var kind = (obj?.Kind ?? "").Trim().ToLowerInvariant(); if (kind.IndexOf("station", StringComparison.Ordinal) >= 0) return Sprite("map.entity.station", "Sprites/Icons/station1"); if (kind.IndexOf("orbital", StringComparison.Ordinal) >= 0) return Sprite("map.entity.orbital", "Sprites/Icons/Stroked/orbital"); if (kind.IndexOf("projectile", StringComparison.Ordinal) >= 0) return Sprite("map.entity.projectile", "Sprites/Icons/Lightning Bolt"); return Sprite("map.entity.ship", "Sprites/Icons/Stroked/Ship"); } public static AetheriaRuntimeAssetRef ResolveBodyIcon(AetheriaRuntimeBodyView? body) { var kind = (body?.Kind ?? "").Trim().ToLowerInvariant(); if (kind.IndexOf("sun", StringComparison.Ordinal) >= 0 || kind.IndexOf("star", StringComparison.Ordinal) >= 0) return Sprite("map.body.sun", "Sprites/Icons/Stroked/Sun"); if (kind.IndexOf("asteroid", StringComparison.Ordinal) >= 0) return Sprite("map.body.asteroid", "Sprites/Icons/Stroked/Planet"); return Sprite("map.body.planet", "Sprites/Icons/Stroked/Planet"); } public static AetheriaRuntimeAssetRef AssetRefFromCatalogIcon( string? catalogPath, string fallbackAssetKey) { if (string.IsNullOrWhiteSpace(catalogPath)) return AetheriaRuntimeAssetRef.Empty(AetheriaRuntimeAssetKinds.Texture); var resourcePath = NormalizeResourcePath(catalogPath ?? ""); var assetKey = string.IsNullOrWhiteSpace(fallbackAssetKey) ? $"catalog.{resourcePath}".Replace('/', '.').Replace('\\', '.') : fallbackAssetKey; return CultMeshAssetRef( assetKey, AetheriaRuntimeAssetKinds.Texture, resourcePath, "image/*"); } public static AetheriaRuntimeAssetRef InventoryCellBackgroundAtlas() { return Texture( "inventory.cell.background_atlas", "Sprites/Flat UI/Nodes/Nodes8BG"); } public static AetheriaRuntimeAssetRef InventoryCellForegroundAtlas() { return Texture( "inventory.cell.foreground_atlas", "Sprites/Flat UI/Nodes/Nodes8"); } public static AetheriaRuntimeAssetRef InventoryThermalLayerAtlas() { return Texture( "inventory.cell.thermal_layer_atlas", "Sprites/Flat UI/pipes"); } public static IReadOnlyList InventoryUiAssets() { return new[] { new AetheriaRuntimeAssetManifestEntry { Ref = InventoryCellBackgroundAtlas(), Tags = new[] { "inventory", "cell", "background", "atlas" } }, new AetheriaRuntimeAssetManifestEntry { Ref = InventoryCellForegroundAtlas(), Tags = new[] { "inventory", "cell", "foreground", "atlas" } }, new AetheriaRuntimeAssetManifestEntry { Ref = InventoryThermalLayerAtlas(), Tags = new[] { "inventory", "thermal", "layer", "atlas" } } }; } private static AetheriaRuntimeAssetManifestEntry MapIcon( string key, string label, string resourcePath) { return new AetheriaRuntimeAssetManifestEntry { Ref = Sprite($"map.{key}", resourcePath), Tags = new[] { "map", "icon", label } }; } private static AetheriaRuntimeAssetManifestEntry MapPrefab( string key, string label, string resourcePath) { return new AetheriaRuntimeAssetManifestEntry { Ref = Prefab(key, resourcePath), Tags = new[] { "world", "prefab", label } }; } private static AetheriaRuntimeAssetRef Sprite(string key, string resourcePath) { return CultMeshAssetRef( key, AetheriaRuntimeAssetKinds.Sprite, resourcePath, "image/*"); } private static AetheriaRuntimeAssetRef Texture(string key, string resourcePath) { return CultMeshAssetRef( key, AetheriaRuntimeAssetKinds.Texture, resourcePath, "image/*"); } private static AetheriaRuntimeAssetRef Prefab(string key, string resourcePath) { return CultMeshAssetRef( key, AetheriaRuntimeAssetKinds.Prefab, resourcePath, "application/vnd.unity.prefab"); } private static AetheriaRuntimeAssetRef CultMeshAssetRef( string key, string kind, string resourcePath, string mimeType) { var normalizedResourcePath = NormalizeResourcePath(resourcePath); return new AetheriaRuntimeAssetRef { AssetKey = key ?? "", Kind = kind ?? "", Uri = CultMeshAssetUri(key), Transport = AetheriaRuntimeAssetTransports.CultMesh, MimeType = mimeType ?? "", Metadata = string.IsNullOrWhiteSpace(normalizedResourcePath) ? new Dictionary() : new Dictionary(StringComparer.Ordinal) { ["resourcesPath"] = normalizedResourcePath } }; } private static string CultMeshAssetUri(string key) { var path = (key ?? "").Trim().Replace('.', '/').Replace('\\', '/').Trim('/'); return $"cultmesh://aetheria/assets/{path}"; } private static string NormalizeResourcePath(string path) { path ??= ""; const string resourcesPrefix = "Assets/Resources/"; if (path.StartsWith(resourcesPrefix, StringComparison.OrdinalIgnoreCase)) path = path.Substring(resourcesPrefix.Length); var extensionIndex = path.LastIndexOf('.'); if (extensionIndex > 0) path = path.Substring(0, extensionIndex); return path.Replace('\\', '/').Trim('/'); } private static void Add( Dictionary entries, AetheriaRuntimeAssetManifestEntry entry) { var key = entry.Ref?.AssetKey ?? ""; if (key.Length == 0) return; entries[key] = entry; } } }