From de36150dc25bd0e19e1f3b79d72d81f5fcb357fa Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 13 Jun 2026 13:18:03 +0100 Subject: [PATCH] Import typed corporation allegiances --- .voidbot/state/aetheria.cc | Bin 29661 -> 30029 bytes Aetheria.State.Import/Program.cs | 41 ++++++++++++++++-- Aetheria.State.Unity.Smoke/Program.cs | 12 ++++- .../AetheriaRuntimeCatalogSnapshotMapper.cs | 5 ++- Aetheria.State.Verify/Program.cs | 9 +++- .../Documents/AetheriaCorporation.cs | 15 ++++++- Aetheria.State/README.md | 14 +++--- Assets/Scripts/ServerShared/Galaxy.cs | 17 +++++++- GameData/aetheria-world.cc | Bin 19489 -> 19755 bytes ...6bcb5217c5fee889541667442528a98491.msgpack | 2 +- ...a275af9147897cd1f60b23a18cc48b7fee.msgpack | 2 +- ...3921217d7ba077f48246e0b33fc1493431.msgpack | 2 +- ...3fbff428c15ab389a42d0d2aa0e75980fd.msgpack | 4 +- ...6b93b4259541f580967a52464d9686f3aa.msgpack | 2 +- ...fdee0c7ff471c8bb4b4e0b2067eb36da09.msgpack | 2 +- ...cc1c87e1e40afcab2bb8dd8f889fe0918b.msgpack | 4 +- ...1ac1edd3dffac04996b12d9f9d0e8304f1.msgpack | 4 +- ...1368ec2948a11425e377fa92a71d575637.msgpack | 2 +- ...8858c36442af01034165db67b886e94ce3.msgpack | 2 +- ...2cd5bdbf86136a558044079cba7a029ac8.msgpack | 2 +- ...6ba52bd445978bb0cb399047cf64aa722f.msgpack | 2 +- ...3e8ff05893f872c2437a5621f2a2eec71b.msgpack | 2 +- ...9bb06b3f45a746ac5f7739b1cbd896443f.msgpack | 2 +- ...07d0fb3e1d5d58fbc176520a100614f404.msgpack | 2 +- ...48df04cfa2250b7101fc00f9c6f2c1317c.msgpack | 2 +- ...06e97680a29efe7d1436947e3a8eba4c95.msgpack | 2 +- ...2ccd793983d2af31967b7d70a977fd2e02.msgpack | 2 +- ...f91cb8ca685ea96318a795771ae6d911eb.msgpack | 2 +- ...db27aa2b805705e823bed4877c4623cf88.msgpack | 2 +- ...5eead201bac20496fa5a2649e4b1522a37.msgpack | 2 +- ...fa0290206edd7b2e0dc08b0f9842dea0f2.msgpack | 2 +- ...dd6eeb3d8311f3753af60c2b5596719b15.msgpack | 2 +- ...d7e3a5d8fa1509efb8a9249d0e48891299.msgpack | 2 +- ...c76a739617023ffa2c2aeb091cf5580b7d.msgpack | 2 +- ...f5bd89832b6e55959ea4902bfa15bc8117.msgpack | 2 +- ...d52fa612f479ccbad76307db432c0b6147.msgpack | 2 +- ...268eff507c40681c6b1955fa786f99066c.msgpack | 2 +- ...ad0cb1b8ec9229ee0525bb8571edb6ea32.msgpack | 2 +- ...616a532f076ae0a66f2257f9c7899100a9.msgpack | 2 +- ...ae26acc72f64a9ca536b895d59a8675c66.msgpack | 2 +- ...44c85439d1f3caa1caaf24beb34e7d8d50.msgpack | 2 +- ...9500e6c9192f76c38393eb84bee3345ee0.msgpack | 2 +- ...dd6ef83562c3b82a0e03c21a37c241f5b8.msgpack | 2 +- ...5cdcddbcded4980427149dc10ba9eb08a1.msgpack | 4 +- ...baf1c52a76a0e7adce5acb06a2d7f5bd79.msgpack | 2 +- ...79872da971faf89ceef4c395a64f1b5e88.msgpack | 2 +- ...60257125aef40381db5877aa16c02b39e4.msgpack | 2 +- ...ea1ff3e3f204925bb28ccb1d45d2b3d732.msgpack | 2 +- ...786b7af0cd4f808a703d5f242c9b0fd372.msgpack | 2 +- ...05ae7658005ee7019c3810650baf8e6c4f.msgpack | 2 +- ...d65f26dcd9e6b2bc9ef89cb16dd16e4b07.msgpack | 2 +- ...4187f90237d4386c76e3b847376b466dd3.msgpack | 2 +- ...042b3f00710055061bb4b6d9b2306d14c3.msgpack | 4 +- ...36ce1066ae558fc09801457a30674f515b.msgpack | 2 +- ...e298fc6ceb8352b047986733e405d6006b.msgpack | 2 +- ...7cb628668b9e3842a59c0e2dd106a820bb.msgpack | 2 +- ...b30b7614eb776ee14b16bed525675b67b8.msgpack | 2 +- ...6321b14e59b2b62a7e914e74771273097a.msgpack | 2 +- ...d39c7f7412772d7ad9adc1f1db3f39cc10.msgpack | 2 +- ...e152a6e77f714229898548c45b02cc72d6.msgpack | 2 +- ...0ecea7ff27435bd9e9d534bcb0c1b892ef.msgpack | 2 +- ...daf7ada6d75ceaa0a07f1e0dc46d65003f.msgpack | 2 +- ...25c2c88303bdbc1a54a178c895086e6c55.msgpack | 2 +- ...320b70986559345e184297437f13bcae7d.msgpack | 2 +- ...1f7c425775d76ba34c55a9ae879e27b3d8.msgpack | 4 +- ...8181b2c9794fa3a70f803c67de8d0dcff0.msgpack | 2 +- ...918704bf6ad447ce7a4733664d3888359d.msgpack | 2 +- ...9358f522e1794e5a675f77b06e99ee061e.msgpack | 4 +- ...fd4bd127dae7ce9a1cc25669b23daffd1b.msgpack | 2 +- ...72d6a82431bf8c842bc57b1c7f3bae4876.msgpack | 2 +- ...78de0d154287774728c30a461ed0d9e334.msgpack | 2 +- ...5a77b77ba285ba04fa6e1c678d86988867.msgpack | 2 +- ...cb33184e1aade105b24afaba265b148ce4.msgpack | 2 +- ...92a3874ff91d1e08024120231bb836c2bb.msgpack | 2 +- ...30a284a5876d9f55597d457cebba6a2226.msgpack | 2 +- ...04c4d886f2bf72ae35b733603966e28d61.msgpack | 2 +- ...a65e76836067e0661b91eb2fa4cc5c2b3f.msgpack | 2 +- ...6550ff7ce20b046a653debb4e7bc10e047.msgpack | 2 +- ...2888041296cc8e256b3774e29b1b969c4b.msgpack | 2 +- ...d247ef4aa34cfbe648b0b1587836dc48cb.msgpack | 2 +- ...eb069ff9e1ed707a2590cedcffc835ac23.msgpack | 2 +- ...199f861a6986234742cd7d603c9d8cbe86.msgpack | 2 +- ...699d5fc930104242470efeddc8f9500222.msgpack | 2 +- ...ef7f34c156794d697606252db56928e23b.msgpack | 2 +- ...d30298201bd0eced6bfa9c3b7e01d9448c.msgpack | 2 +- ...946ba31ec32b37bfe4b0829825c4e85029.msgpack | 2 +- ...cb793e7bcf5f7afa2c328d12d6561d0f1e.msgpack | 2 +- ...56919b8dd915d9fef8f2361b77d9bf6b99.msgpack | 2 +- ...386b0b8e8f80cfe0ad311061b682ecff95.msgpack | 2 +- ...1c82be1f818ee634833d6e3e637e694344.msgpack | 2 +- ...4f2a1a72a54f72c42a4e4c1d0f231586ba.msgpack | 2 +- ...34144722b989cf3cf2f03431cabc1f3929.msgpack | 2 +- ...a34a37e5fcb7892a29eb02cf5da1c338de.msgpack | 2 +- ...c97b1604f21df8132d6305f350e80ba5b7.msgpack | 2 +- ...98c89c7c57fff60a2c357887e8dc400dc3.msgpack | 2 +- ...c595e7f3aea98935f9e9a6aafdf8b4d9d2.msgpack | 2 +- ...1539aa45529f4c740066eb5301ed36edfd.msgpack | 2 +- ...2e4971d71ab5b8b38ac0c89c3f9a764764.msgpack | 2 +- ...cc7b2c41fe7e5fcc138566aa65f6a2b10b.msgpack | 2 +- ...79e8b3e7a51e9d5145e08f639a88de38be.msgpack | 2 +- ...cb2be74c711de0d5b22f9160aba0ee7ee9.msgpack | 2 +- ...65d32cdc881f54a82297e048ac6adff8ff.msgpack | 2 +- ...0336d40c18572d3f6ed6318a4008af5a89.msgpack | 2 +- ...fcd8fa1e9858c270d58ccf5d2170a3842c.msgpack | 2 +- ...d2064953cbde740647c3a820bacf9c27c3.msgpack | 2 +- ...33d98be75491a3b1b3af0d080505b31b21.msgpack | 2 +- ...76f8e8486ae0dd84c256d8c672c54837ec.msgpack | 2 +- ...7dd3b2bd29116afbf8857d8b5afdc85c8f.msgpack | 2 +- ...26af1122625e375d29d192aacad668e2a7.msgpack | 2 +- ...0d87791a49bb911b2e7ab294e1303e180c.msgpack | 2 +- ...85198b8b38c36fc5417df965fe098c7523.msgpack | 2 +- ...fdf046f5a7951655cf83dc22938e7563b2.msgpack | 2 +- ...f4651415e50cce4eb13240370a1394b928.msgpack | 2 +- ...52a044e5c42314b43945ded225f3009bf9.msgpack | 2 +- ...b76604f01f891d11f6bc9c079621d2b45c.msgpack | 2 +- ...dd6056bad45424aaadc0ed86534053fd43.msgpack | 2 +- ...6a84bb1ad648c6e3f72452f8ee47f98cb5.msgpack | 2 +- ...28230b2636da2c91d4e12ec6c804c8a04a.msgpack | 2 +- ...480afdb5047dee177edeac207ce337e083.msgpack | 2 +- ...7f81911af70edf42cb5275ce8f96dee707.msgpack | 2 +- ...07128f325b6f8981e61bf216400dd09f8e.msgpack | 2 +- ...f4dc349da455027ef5db10f14d88553894.msgpack | 2 +- ...1ade7f7e67031a1f69bec307690212bb53.msgpack | 2 +- ...3ff4da3985d54c314bcaf6ceca29a0d80e.msgpack | 2 +- ...1b1a624f836079caf3f9c892cbc94d0aae.msgpack | 2 +- ...01600dd1985f3e1ddeeb16b10593afc5ab.msgpack | 2 +- ...08e1a83f1dc14096339f67d56c0e0869ff.msgpack | 2 +- ...06d60f0e24b919fdf36a025cfddee87011.msgpack | 2 +- ...0f1c261fbbb7f1961d8acd057a3b287e38.msgpack | 2 +- ...5b07b6b9ec7bba75debf9915460dbe3e1a.msgpack | 2 +- ...2762b088b45c2b873b2816cc7dd4e7672c.msgpack | 2 +- ...e79aecf53d9558fd48290599da73065788.msgpack | 2 +- ...3dd2a11f08fa54e6ffc699ee7ff032399d.msgpack | 2 +- ...36c731b877c242d1dd966801858145a431.msgpack | 2 +- ...8668f9d2c05806983d89a8e9227a63871e.msgpack | 2 +- ...e2540502e68596a3603f76389e57028805.msgpack | 2 +- ...9ab8ab7bd5c5792eaffa4226a6c04eb105.msgpack | 2 +- ...b464103bd76e410747a9c9b7ff24e3c4e1.msgpack | 2 +- ...5ee0f0a8c3001293f5702aa2424e24427e.msgpack | 4 +- ...731eadcb421407c89d781610905a20f024.msgpack | 4 +- ...4a3699e1985d69a91cf8dcb7f4c66bddf5.msgpack | 2 +- ...25da6d94408d6a3d1d9118f6ee39b59f6b.msgpack | 2 +- ...27c780283d518bb03ec1796d41885bd88a.msgpack | 2 +- ...0f473896745b146e5990046afe53ac54b8.msgpack | 4 +- ...e9c2093d642b67286400600a6215e90683.msgpack | 2 +- ...8f723d3a0a7f48de7e52fe545a530c2559.msgpack | 2 +- ...3f7d34327c64a8a33c3dfb1809131717a1.msgpack | 2 +- ...42f2cef8f92eb11513d698d60a8ad234c4.msgpack | 2 +- ...d4f7d77f094191b2e9d7590b6795950780.msgpack | 2 +- ...c4bd13b358f1ffb0937b14289d35ab2d53.msgpack | 2 +- ...6b87f1ba0566a44f3d381b757edb40d25d.msgpack | 2 +- ...e4f0b2d619dceb69ec354fe56f99488b42.msgpack | 4 +- ...beb23a1fa47461adda98ef10295021480f.msgpack | 2 +- ...d3f4d154424deaf2f21dd15d213684d46f.msgpack | 2 +- ...8da4a63ef12a1dc5126b11ebba43840395.msgpack | 4 +- .../Runtime/AetheriaRuntimeCatalogSnapshot.cs | 17 +++++++- .../Runtime/AetheriaRuntimeCatalogStore.cs | 30 ++++++++++++- docs/aetheria-perfect-machine-map.md | 28 +++++++----- 158 files changed, 319 insertions(+), 185 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index a47a9727c3bf7ce604bbddf6f6b6c259b5a15c3b..5ff6f3078bd94f98b17c8fd7481f59a1776b3b62 100644 GIT binary patch delta 1354 zcmZux&x;gS5Z;*;gmVu8SB3cOAwk3A!q*Ay9T#Pe1K`Z+!3d z%uX(I@RDotPI?m!fnXqE&XPYs61*A=cnAbM2>t_N^^e_cjkoUV>ZZ|(azuKQK zYQH_Ge>k_;IKFu7q_@y$to~4&{xRC>9@lSI!Y8t@Qn8q<+98*`I^a&{FlJS1>V-(5XwLLAe5ov*E zDn%02=dxA-mLI)J3$H&117Ra*jW&uJ4^|=qkuVNRn)~YnWAPog*EoO+WDIucYxHkI zf<3rNLjyu`gZAal5->FMhtOFvv!E$q0*oj7JAlS~^DTOB@mORcvw)JJa`Vel*dg?| z2e;xn7%&i8>nX!1I3dXhwK2xE;bG(O(4G7%olM{*=W8o+gY zMkHxmsJyiDRnhpo!a$|AO_F#3O0)igBw_-a&p5B5Q)xv)tcWyLrv*-7AeEtz!bB9fTk+KB)zye3_^Gu*cHv!!vrL-| z={}cc*^2TN2m=z`$eP?k*hdlL^$bO%RodmDmyWntK&iOKYn65w`Aj||h=RKa>@L-0rFfAkAaC5#QQ0n0Bo%`Iqo}V7y zIihAhxP4z!`1GiI**LJX!rkp(p6M)90>DcWC_hbj;KjDQZw-N06o=kJ>WhGwTn>NY z;P~VA%RN$9!f*FKtBKU619&aFPM*fq~4n&a9xzt^`tEOCr~{dU*(os~TI zWODE3)oLCq4&0+1>nRIO_iA!4-?pvp-zceMF61{)i_vCmKEHY6-8cT&UI`vweFIB- B=nMb= delta 1118 zcmYjQJxmlq6qbV!5KU;5!Vq65G$wGsAwNf9BBDqDO%yGNCJwvrZU=T})|uIZwYfwZ zJ7c!f!bCA7Y9ZO$SXdepTcS2LMjI_HeY1PVU9!dQw=?g3-}k=v`FF?npB?XZ3&+N1 zCue5I$BX63v9%{1Cz6nNC!Y#CZFo7uW#@Jan>wFiJzawZ=S6z9%R614Utm7lj-kRF z!=(U?KIU&iZhB~+2 z-5IPyMJg~J0&a6{xTu2WLF8wwKzl62VPL|ANMoarV8p$`eI!wIcZI1>b;^P4uDF3YnYJ zK=RaB8#Gy#v$wQ;$y^y3*g{_Qti0lWPG&I(eeSU2Z_r)8hT8_5h^C}H8Tl^I$f{`I za#r&uD$acVz}in0m-C7Xxn44$Id+8=R45$O!`4tiT#TJaQ++0Qo*A~zG*W35gQU}7 zmdO1!)8&@1*5p}fo7!kIH_e8DbkQ%qX2S8Lx`7q_?Z}1nrxSEB zFF(Rvs4+i6UEFy|R-}99-VFA?#Ts|5Cpo>LB%ByaPhEZ1IW>KoY^`uIwUJzkIR$IP z1`BGXMnrQ8m53scaZP_MJ?&2}dLzkKd30c6b^LILOA~9mhE>UfQtIB_FQh~F`g;4? wekWf#2U=@9U23fS`!;N{vF_c;>PFCp&t&+Ijd}~4$*}a{=7-)EST3*q2YAepcK`qY diff --git a/Aetheria.State.Import/Program.cs b/Aetheria.State.Import/Program.cs index dc328135b..303a0a6d7 100644 --- a/Aetheria.State.Import/Program.cs +++ b/Aetheria.State.Import/Program.cs @@ -91,7 +91,7 @@ await node.PutMigrationLedgerAsync(new AetheriaMigrationLedger }, new AetheriaMigrationCount { - DocumentType = "aetheria.corporation.v1", + DocumentType = "aetheria.corporation.v2", Count = corporations.Length }, new AetheriaMigrationCount @@ -412,7 +412,8 @@ internal static class LegacyCatalogReader AllegianceCount = GetMapCount(payload, 12), OverworldMusic = GetUInt(payload, 13), CombatMusic = GetUInt(payload, 14), - BossMusic = GetUInt(payload, 15) + BossMusic = GetUInt(payload, 15), + Allegiances = ReadAllegiances(payload, 12) } : null, unionKey == 9 @@ -507,12 +508,22 @@ internal static class LegacyCatalogReader for (var index = 0; index < length; index++) { var key = ReadValue(ref reader); - values[key?.ToString() ?? ""] = ReadValue(ref reader); + values[FormatMapKey(key)] = ReadValue(ref reader); } return values; } + private static string FormatMapKey(object? key) + { + return key switch + { + byte[] bytes when bytes.Length == 16 => new Guid(bytes).ToString("D"), + string text => text, + _ => key?.ToString() ?? "" + }; + } + private static object? SkipValue(ref MessagePackReader reader) { reader.Skip(); @@ -598,6 +609,30 @@ internal static class LegacyCatalogReader return payload.TryGetValue(key, out var value) && value is Dictionary map ? map.Count : 0; } + private static AetheriaCorporationAllegiance[] ReadAllegiances(IReadOnlyDictionary payload, int key) + { + if (!payload.TryGetValue(key, out var value) || value is not Dictionary map) + { + return []; + } + + return map + .Select(entry => new AetheriaCorporationAllegiance + { + CorporationLegacyId = NormalizeLegacyId(entry.Key), + Weight = ReadDoubleValue(entry.Value) + }) + .Where(allegiance => !string.IsNullOrWhiteSpace(allegiance.CorporationLegacyId)) + .ToArray(); + } + + private static string NormalizeLegacyId(string legacyId) + { + return Guid.TryParse(legacyId, out var parsed) && parsed != Guid.Empty + ? parsed.ToString("D") + : ""; + } + private static int GetArrayLength(IReadOnlyDictionary payload, int key) { return payload.TryGetValue(key, out var value) && value is object?[] array ? array.Length : 0; diff --git a/Aetheria.State.Unity.Smoke/Program.cs b/Aetheria.State.Unity.Smoke/Program.cs index f632c1695..8fe8dd497 100644 --- a/Aetheria.State.Unity.Smoke/Program.cs +++ b/Aetheria.State.Unity.Smoke/Program.cs @@ -109,12 +109,22 @@ if (catalog.GetManufacturer(manufactured) == null) } var packageCorporation = packageCatalog.Corporations.FirstOrDefault(corporation => !string.IsNullOrWhiteSpace(corporation.GeonameFileLegacyId)); -var packageNameFile = packageCorporation == null ? null : packageCatalog.GetNameFile(packageCorporation); +if (packageCorporation == null) +{ + throw new InvalidOperationException("Package catalog store did not read any corporation name-file links."); +} + +var packageNameFile = packageCatalog.GetNameFile(packageCorporation); if (packageNameFile == null || packageNameFile.Names.Count == 0 || packageNameFile.Names.Count != packageNameFile.NameCount) { throw new InvalidOperationException("Package catalog store did not read corporation/name-file links with full names."); } +if (packageCorporation.Allegiances.Count == 0 || packageCorporation.Allegiances.Count != packageCorporation.AllegianceCount) +{ + throw new InvalidOperationException("Package catalog store did not read corporation allegiance edges."); +} + if (surface?.Schema != "gamecult.eve.surface.v1" || surface.Surface.Id != AetheriaCatalogSurfaceProjector.SurfaceId) { diff --git a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs index b1bf54653..589850683 100644 --- a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs +++ b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs @@ -107,7 +107,10 @@ internal static class AetheriaRuntimeCatalogSnapshotMapper corporation.GeonameFileLegacyId, corporation.BossHullLegacyId, corporation.InfluenceDistance, - corporation.AllegianceCount); + corporation.AllegianceCount, + corporation.Allegiances.Select(allegiance => new AetheriaRuntimeCorporationAllegiance( + allegiance.CorporationLegacyId, + allegiance.Weight)).ToArray()); } private static AetheriaRuntimeNameFile FromState(AetheriaNameFile nameFile) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 06b763a05..a1d8dd0c7 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -22,7 +22,7 @@ var catalog = node.ReadCatalogSnapshot(); var surface = AetheriaCatalogSurfaceProjector.Build(catalog, DateTimeOffset.UtcNow.ToString("O")); RequireCount(ledger, "aetheria.item_definition.v1", items.Length); -RequireCount(ledger, "aetheria.corporation.v1", corporations.Length); +RequireCount(ledger, "aetheria.corporation.v2", corporations.Length); RequireCount(ledger, "aetheria.name_file.v2", nameFiles.Length); if (items.Length == 0) @@ -68,6 +68,7 @@ var weaponItems = items.Count(item => !string.IsNullOrWhiteSpace(item.WeaponCaliber)); var describedCorporations = corporations.Count(corporation => !string.IsNullOrWhiteSpace(corporation.Description)); var corporationNameLinks = corporations.Count(corporation => !string.IsNullOrWhiteSpace(corporation.GeonameFileLegacyId)); +var corporationAllegianceEdges = corporations.Sum(corporation => corporation.Allegiances.Length); if (pricedItems == 0) { @@ -208,6 +209,11 @@ if (corporationNameLinks == 0) throw new InvalidOperationException("Typed corporations did not import geoname file legacy IDs."); } +if (corporationAllegianceEdges == 0 || corporations.Any(corporation => corporation.Allegiances.Length != corporation.AllegianceCount)) +{ + throw new InvalidOperationException("Typed corporations did not import full allegiance edges."); +} + var tradeItems = catalog.TradeItems.ToArray(); if (tradeItems.Length != pricedItems) { @@ -297,6 +303,7 @@ Console.WriteLine($"Typed catalog trade items: {tradeItems.Length}"); Console.WriteLine($"Eve catalog surface: {surface.Surface.Id} ({surface.Surface.Root.Children.Length} root children)"); Console.WriteLine($"Corporations: {corporations.Length}"); Console.WriteLine($"Described/geoname-linked corporations: {describedCorporations}/{corporationNameLinks}"); +Console.WriteLine($"Corporation allegiance edges: {corporationAllegianceEdges}"); Console.WriteLine($"Name files: {nameFiles.Length}"); static void RequireCount(AetheriaMigrationLedger ledger, string documentType, int actual) diff --git a/Aetheria.State/Documents/AetheriaCorporation.cs b/Aetheria.State/Documents/AetheriaCorporation.cs index a48ae592c..1ec88393a 100644 --- a/Aetheria.State/Documents/AetheriaCorporation.cs +++ b/Aetheria.State/Documents/AetheriaCorporation.cs @@ -3,7 +3,7 @@ using MessagePack; namespace Aetheria.State.Documents; -[CultDocument("aetheria.corporation", "aetheria.corporation.v1")] +[CultDocument("aetheria.corporation", "aetheria.corporation.v2")] [MessagePackObject] public sealed class AetheriaCorporation { @@ -43,4 +43,17 @@ public sealed class AetheriaCorporation [Key(10)] public uint BossMusic { get; set; } + + [Key(11)] + public AetheriaCorporationAllegiance[] Allegiances { get; set; } = []; +} + +[MessagePackObject] +public sealed class AetheriaCorporationAllegiance +{ + [Key(0)] + public string CorporationLegacyId { get; set; } = ""; + + [Key(1)] + public double Weight { get; set; } } diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index a627a1e13..bd3fe5f6a 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -58,9 +58,11 @@ stable equipment facets: hardpoint type, hull type, stack size, durability, and weapon range/caliber/type/fire/modifier classifications. Typed corporation documents include the legacy short name, the true description field from key 3, name-file and boss-hull legacy IDs, influence distance, -allegiance count, and music bank IDs. Runtime object graphs, typed behavior -factory construction, and simulation state remain legacy until dedicated typed -runtime documents exist. +allegiance count, full allegiance edges, and music bank IDs. Corporation +documents are `aetheria.corporation.v2` records because runtime generation +needs actual allegiance weights, not only display counts. Runtime object graphs, +typed behavior factory construction, and simulation state remain legacy until +dedicated typed runtime documents exist. Typed name-file documents are `aetheria.name_file.v2` records. They carry the legacy ID, display name, count, compact sample names for surfaces, and the full name array needed to move `Galaxy`/Markov name generation off legacy @@ -94,11 +96,11 @@ published Eve catalog surface. It does not deserialize legacy `DatabaseEntry` objects and does not write state. Unity can use this as the first package boundary once CultLib/Eve runtime packaging is available. `Galaxy` now consumes this package-owned runtime catalog for faction selection -and name generation, so generated sectors use typed corporation and +and name generation, so generated sectors use typed corporation v2 and `aetheria.name_file.v2` records instead of legacy `Faction`/`NameFile` catalog documents. It still projects typed corporations into temporary -`Faction` DTOs because the surrounding simulation has not yet been rebuilt -around typed corporation records. +`Faction` DTOs, including allegiance dictionaries, because the surrounding +simulation has not yet been rebuilt around typed corporation records. `Aetheria.State.Smoke` writes and reopens full typed player settings plus a typed loadout template in addition to world, catalog, run state, zone state, and diff --git a/Assets/Scripts/ServerShared/Galaxy.cs b/Assets/Scripts/ServerShared/Galaxy.cs index c58088a1a..62012b925 100644 --- a/Assets/Scripts/ServerShared/Galaxy.cs +++ b/Assets/Scripts/ServerShared/Galaxy.cs @@ -220,7 +220,8 @@ public class Galaxy private static Faction[] ProjectFactions(AetheriaRuntimeCatalogSnapshot runtimeCatalog) { - var factions = runtimeCatalog.Corporations + var corporations = runtimeCatalog.Corporations.ToArray(); + var factions = corporations .Select(ProjectFaction) .ToArray(); if (factions.Length == 0) @@ -228,6 +229,20 @@ public class Galaxy throw new InvalidOperationException("Typed catalog has no factions for galaxy generation."); } + var factionsByLegacyId = factions.ToDictionary(faction => faction.ID.ToString("D"), StringComparer.OrdinalIgnoreCase); + for (var index = 0; index < corporations.Length; index++) + { + foreach (var allegiance in corporations[index].Allegiances) + { + if (Guid.TryParse(allegiance.CorporationLegacyId, out var corporationId) && + corporationId != Guid.Empty && + factionsByLegacyId.ContainsKey(corporationId.ToString("D"))) + { + factions[index].Allegiance[corporationId] = (float) allegiance.Weight; + } + } + } + return factions; } diff --git a/GameData/aetheria-world.cc b/GameData/aetheria-world.cc index 700d2204552bcdae39910e6cbaec74490cb82d11..675700e02ee03c4908f513a66d8d69e460fbfe75 100644 GIT binary patch delta 364 zcmbu)yGjE=6o6q?2pTVF5sA%$E;a!rXRc?GE?QVwSWASN*)tl9i6qu3v=&?@MGzZ1 zAz%|R(9IhS^vey|2#>ikI6%=C5S8q<$`evtZ9G~Xc}5^<8nk2+6kUZ4$@NY zye32kIyi=bX)Tm_D?Tg5sCvxjN5c!tm2NU&5UtbzNEQ@&2__FZ0JDy~(~?`XN;4Lm zAyACGN9h&w7>GRh_r=@TUfwFcWWpotzQi>#o?R|9OYx&rt}wQj_3Ra8&8*e!(s{@B ze5}{^HxK)R>;Ayrbo#xYK=DML#n*K8-#%2wZ(rT>~%I5I}%z5QxVXSO60C zfWVO|-X4%ACpkGU_ucbdcRM>%%*u%(J57Q@8oV0D%8H3N)(C||sx~JS@WGB8465Z= zYWB&#^*=}b^7sNj&lgup&Yw~pdm`%yWk7^y&oBAH5r tibP*~@9krH(r<0M allegiances) { LegacyId = legacyId; Name = name; @@ -345,6 +346,7 @@ namespace GameCult.Aetheria.State.Unity BossHullLegacyId = bossHullLegacyId; InfluenceDistance = influenceDistance; AllegianceCount = allegianceCount; + Allegiances = allegiances; } public string LegacyId { get; } @@ -355,6 +357,19 @@ namespace GameCult.Aetheria.State.Unity public string BossHullLegacyId { get; } public int InfluenceDistance { get; } public int AllegianceCount { get; } + public IReadOnlyList Allegiances { get; } + } + + public sealed class AetheriaRuntimeCorporationAllegiance + { + public AetheriaRuntimeCorporationAllegiance(string corporationLegacyId, double weight) + { + CorporationLegacyId = corporationLegacyId; + Weight = weight; + } + + public string CorporationLegacyId { get; } + public double Weight { get; } } public sealed class AetheriaRuntimeNameFile diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs index d0bf9d566..5faf17d20 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs @@ -198,7 +198,9 @@ namespace GameCult.Aetheria.State.Unity var bossHullLegacyId = ReadFieldString(ref reader, fields, 5); var influenceDistance = ReadFieldInt32(ref reader, fields, 6); var allegianceCount = ReadFieldInt32(ref reader, fields, 7); - SkipRemaining(ref reader, fields, 8); + SkipFields(ref reader, fields, 8, 11); + var allegiances = ReadFieldCorporationAllegiances(ref reader, fields, 11); + SkipRemaining(ref reader, fields, 12); return new AetheriaRuntimeCorporation( legacyId, name, @@ -207,7 +209,8 @@ namespace GameCult.Aetheria.State.Unity geonameFileLegacyId, bossHullLegacyId, influenceDistance, - allegianceCount); + allegianceCount, + allegiances); } private static AetheriaRuntimeNameFile ReadNameFile(byte[] payload) @@ -253,6 +256,23 @@ namespace GameCult.Aetheria.State.Unity return index >= fields ? Array.Empty() : ReadShapeCells(ref reader); } + private static IReadOnlyList ReadFieldCorporationAllegiances(ref MessagePackReader reader, int fields, int index) + { + if (index >= fields) return Array.Empty(); + var count = reader.ReadArrayHeader(); + var allegiances = new AetheriaRuntimeCorporationAllegiance[count]; + for (var allegiance = 0; allegiance < count; allegiance++) + { + var allegianceFields = reader.ReadArrayHeader(); + var corporationLegacyId = ReadFieldString(ref reader, allegianceFields, 0); + var weight = ReadFieldDouble(ref reader, allegianceFields, 1); + SkipRemaining(ref reader, allegianceFields, 2); + allegiances[allegiance] = new AetheriaRuntimeCorporationAllegiance(corporationLegacyId, weight); + } + + return allegiances; + } + private static IReadOnlyList ReadShapeCells(ref MessagePackReader reader) { var count = reader.ReadArrayHeader(); @@ -407,6 +427,12 @@ namespace GameCult.Aetheria.State.Unity reader.Skip(); } + private static void SkipFields(ref MessagePackReader reader, int fields, int firstIndex, int stopBeforeIndex) + { + for (var field = firstIndex; field < fields && field < stopBeforeIndex; field++) + reader.Skip(); + } + private static void SkipRemaining(ref MessagePackReader reader, int fields, int firstUnhandledIndex) { for (var field = firstUnhandledIndex; field < fields; field++) diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 690159d03..8881ed3ba 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -94,9 +94,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. the package-owned `ActionGameManager.RuntimeCatalog` typed snapshot. - `Galaxy` generation no longer accepts `ILegacyCatalogReader` or `ItemManager`. Sector and tutorial generation receive the package-owned typed runtime - catalog. `Galaxy` projects typed corporation records into temporary legacy - `Faction` DTOs for the existing simulation shape and resolves full name - arrays from `aetheria.name_file.v2` records. `ActionGameManager` still has a + catalog. `Galaxy` projects typed corporation v2 records into temporary legacy + `Faction` DTOs, including allegiance edges, for the existing simulation shape + and resolves full name arrays from `aetheria.name_file.v2` records. + `ActionGameManager` still has a private legacy catalog boot helper that feeds `ItemManager` for item/entity systems; menu/generation paths no longer receive the legacy reader directly. - `DatabaseLink.Value` can resolve legacy links only after @@ -116,13 +117,16 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. payloads, stack size, durability, and weapon range/caliber/type/fire/modifier classifications. Corporation documents now carry the legacy short name, true description from key 3, name-file and boss-hull legacy IDs, influence - distance, allegiance count, and music bank IDs. Empty legacy GUID references - are imported as absent links rather than as `Guid.Empty` catalog IDs. + distance, allegiance count, full allegiance edges, and music bank IDs. Empty + legacy GUID references are imported as absent links rather than as + `Guid.Empty` catalog IDs. Name-file documents are now `aetheria.name_file.v2` records and carry both sample names for compact surfaces and the full legacy name array for future - `Galaxy`/Markov name generation cutover. `Aetheria.State` now owns the - canonical legacy-ID record key mapping for migrated item, corporation, and - name-file documents. + `Galaxy`/Markov name generation cutover. Corporation documents are now + `aetheria.corporation.v2` records because runtime generation needs actual + allegiance edges, not only a count. `Aetheria.State` now owns the canonical + legacy-ID record key mapping for migrated item, corporation, and name-file + documents. - `AetheriaCatalogSnapshot` is the typed catalog read surface over materialized `.cc` records. It exposes trade-item, manufacturer, corporation prefix, and corporation name-file queries, plus equipment, hardpoint, and behavior @@ -167,8 +171,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. masks, 5 interior masks, 3 hardpoint-host hulls, 22 hardpoints, 39 behavior-bearing item definitions, 65 behavior payloads, 661 behavior fields, 18 behavior-side legacy-ID references, 51 hardpoint-tagged equipment items, 3 - hull items, and 18 weapon-facet item definitions. Legacy content includes at - least one overhanging hardpoint (`LonginusX`); migration verification + hull items, 18 weapon-facet item definitions, and 143 corporation allegiance + edges. Legacy content includes at least one overhanging hardpoint + (`LonginusX`); migration verification preserves that payload and does not convert content repair into mapper authority. - `.voidbot/state/aetheria.cc` is the repo Persona state witness. Aetheria is @@ -362,6 +367,9 @@ First Aetheria surfaces to publish: - Done: promote typed name files to `aetheria.name_file.v2` with full name arrays, so future `Galaxy` name generation has a Verse-owned replacement for legacy `NameFile.Names`. + - Done: promote typed corporations to `aetheria.corporation.v2` with full + allegiance edges, so temporary `Faction` DTO projection can preserve + loadout generation behavior without reading legacy faction entries. - Done: expand the stable item mapper to include equipment facets and behavior kind fingerprints needed by future Unity/Eve catalog consumers. - Done: import full item shape-cell masks into typed catalog documents and