Merge master into moddable-ships-wiring
#3 landed the same --top-speed fix this branch already carried; both conflicting files keep this branch's version (same behavior, stronger test). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
07cfa26d6c
6 changed files with 83 additions and 35 deletions
|
|
@ -47,14 +47,7 @@ public class Faction
|
|||
[Inspectable, CultReference(typeof(Faction), many: true), CultInspectorRange(0, 1), JsonProperty("allegiance"), Key(12)]
|
||||
public Dictionary<CultRecordRef<Faction>, float> Allegiance = new Dictionary<CultRecordRef<Faction>, float>();
|
||||
|
||||
[Inspectable, JsonProperty("overworldMusic"), Key(13)]
|
||||
public uint OverworldMusic;
|
||||
|
||||
[Inspectable, JsonProperty("combatMusic"), Key(14)]
|
||||
public uint CombatMusic;
|
||||
|
||||
[Inspectable, JsonProperty("bossMusic"), Key(15)]
|
||||
public uint BossMusic;
|
||||
// Keys 13 to 15 (overworldMusic, combatMusic, bossMusic) held Wwise ids; retired, never reuse them.
|
||||
|
||||
// Key 16 is reserved for Relations (operator ruling faction-relations-field).
|
||||
|
||||
|
|
|
|||
|
|
@ -58,10 +58,14 @@ public class Galaxy
|
|||
Seed = savedGame.Seed;
|
||||
|
||||
Factions = savedGame.Factions.Select(faction => cultCache.Get(faction)).ToArray();
|
||||
for (var i = 0; i < Factions.Length; i++)
|
||||
{
|
||||
FactionRelationships[Factions[i]] = savedGame.Relationships[i];
|
||||
}
|
||||
if (savedGame.Standings != null)
|
||||
foreach (var standing in savedGame.Standings)
|
||||
FactionRelationships[cultCache.Get(standing.Faction)] = standing.Relationship;
|
||||
else
|
||||
// A save before Standings wrote Relationships in an order it did not record; it is right only for a
|
||||
// galaxy that never reordered, and is all that save holds.
|
||||
for (var i = 0; i < Factions.Length; i++)
|
||||
FactionRelationships[Factions[i]] = savedGame.Relationships[i];
|
||||
|
||||
var savedZones = savedGame.Zones.Select(zone => cultCache.Get(zone)).ToArray();
|
||||
Zones = savedZones.Select(zone =>
|
||||
|
|
|
|||
|
|
@ -417,11 +417,7 @@ public abstract class EquippableItemData : CraftedItemData
|
|||
[Inspectable, CultInspectorAssetGuid, JsonProperty("actionIcon"), Key(20)]
|
||||
public string ActionBarIcon;
|
||||
|
||||
[Inspectable, JsonProperty("soundBank"), Key(21)]
|
||||
public uint SoundBank;
|
||||
|
||||
[Inspectable, JsonProperty("audioStats"), Key(22)]
|
||||
public List<AudioStat> AudioStats = new List<AudioStat>();
|
||||
// Keys 21 (soundBank) and 22 (audioStats) held Wwise ids; audio is native Unity plus AquaSynth now. Retired; never reuse them.
|
||||
|
||||
[IgnoreMember]
|
||||
public abstract HardpointType HardpointType { get; }
|
||||
|
|
@ -455,16 +451,6 @@ public abstract class EquippableItemData : CraftedItemData
|
|||
}
|
||||
}
|
||||
|
||||
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class AudioStat
|
||||
{
|
||||
[Inspectable, JsonProperty("parameter"), Key(0)]
|
||||
public uint Parameter;
|
||||
|
||||
[Inspectable, JsonProperty("stat"), Key(1)]
|
||||
public PerformanceStat Stat = new PerformanceStat();
|
||||
}
|
||||
|
||||
[CultDocument("aetheria.geardata", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class GearData : EquippableItemData
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ public class SavedGame
|
|||
[Key(11)]
|
||||
public bool IsTutorial;
|
||||
|
||||
// Read only by a save written before Standings: its entries follow galaxy.Factions order, not Factions order, so
|
||||
// Galaxy trusts it only when the two orders cannot differ (see Galaxy's save constructor).
|
||||
[Key(12)]
|
||||
public FactionRelationship[] Relationships;
|
||||
|
||||
|
|
@ -61,6 +63,21 @@ public class SavedGame
|
|||
// gets Regions, Partition and Deal from its saved graph, boss zones, Exit and seed.
|
||||
[Key(15)]
|
||||
public List<SavedProvince> Provinces;
|
||||
|
||||
// Each faction's standing, keyed by the faction itself so no list order can misplace it. Written by RunSave.Capture;
|
||||
// null in a save written before it, which then reads Relationships.
|
||||
[Key(16)]
|
||||
public List<SavedStanding> Standings;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class SavedStanding
|
||||
{
|
||||
[Key(0)]
|
||||
public CultRecordRef<Faction> Faction;
|
||||
|
||||
[Key(1)]
|
||||
public FactionRelationship Relationship;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
|
|
@ -87,7 +104,8 @@ public static class RunSave
|
|||
DiscoveredZones = galaxy.DiscoveredZones.Select(dz => Array.IndexOf(galaxy.Zones, dz)).ToArray(),
|
||||
Background = galaxy.Background,
|
||||
Factions = factions.Select(f => cache.RefOf(f)).ToArray(),
|
||||
Relationships = galaxy.Factions.Select(f => galaxy.FactionRelationships[f]).ToArray(),
|
||||
Standings = galaxy.Factions.Select(f => new SavedStanding
|
||||
{Faction = cache.RefOf(f), Relationship = galaxy.FactionRelationships[f]}).ToList(),
|
||||
HomeZones = galaxy.HomeZones.ToDictionary(
|
||||
x => Array.IndexOf(factions, x.Key),
|
||||
x => Array.IndexOf(galaxy.Zones, x.Value)),
|
||||
|
|
|
|||
|
|
@ -224,9 +224,11 @@ at the same commit.
|
|||
stat); `SoundBank` is catalog key 21 (`:403-404`).
|
||||
- Gone since B5: the `AetherDrive` audio calls and its `RpmAudioParameter` and
|
||||
`TorqueRatioAudioParameter` fields (grep 0), and the `EntityInstance` block that read
|
||||
`item.Data.SoundBank` (grep 0). Follow-up `wwise-catalog-fields` still names both; its live
|
||||
set is `SoundBank` (key 21), `AudioStats` (key 22) and `Faction.OverworldMusic`,
|
||||
`CombatMusic`, `BossMusic` (`Corporations.cs:52-59`, keys 13 to 15).
|
||||
`item.Data.SoundBank` (grep 0). Follow-up `wwise-catalog-fields` retired the rest: `SoundBank`
|
||||
(key 21), `AudioStats` (key 22, with `AudioStat`) and `Faction.OverworldMusic`, `CombatMusic`,
|
||||
`BossMusic` (keys 13 to 15) are deleted, their keys left as never-reuse comments. The shipped
|
||||
`GameData/Aetheria.cc` still carries the old values (29 equippables with a `SoundBank`, 2 factions
|
||||
with music); the reader skips unknown keys and the next catalog write drops them.
|
||||
- `WwiseMetadata.cs` (91 lines) and `WwiseSoundBinding.cs` (21 lines) are used only by that
|
||||
surface; both have `.meta` files. A repo-wide grep outside `docs` finds the Wwise symbols in
|
||||
exactly these files: `ChargedWeapon.cs`, `InstantWeapon.cs`, `Reactor.cs`, `Thruster.cs`,
|
||||
|
|
|
|||
|
|
@ -150,6 +150,48 @@ public sealed class RunSaveTests : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
// Galaxy.Factions and Galaxy.HomeZones.Keys are two orders of the same factions. A saved standing belongs to its
|
||||
// faction, whichever order the galaxy lists them in.
|
||||
[Fact]
|
||||
public void StandingsSurviveSaveAndContinueWhenFactionOrderDiffersFromHomeZoneOrder()
|
||||
{
|
||||
using (var cache = AetheriaStores.Open(Catalog, catalogWritable: true))
|
||||
{
|
||||
cache.Upsert(new Faction { Name = "Borealis", ShortName = "BOR" });
|
||||
cache.Upsert(new Faction { Name = "Corvid", ShortName = "COR" });
|
||||
cache.FlushAsync().Wait();
|
||||
}
|
||||
|
||||
using (var cache = Open())
|
||||
{
|
||||
var factions = cache.GetAll<Faction>().OrderBy(f => f.Name, StringComparer.Ordinal).ToArray();
|
||||
var game = Game(cache, factions);
|
||||
RunSave.Commit(cache, game, Zones(2, null, -1), new ProvenanceLedger());
|
||||
}
|
||||
|
||||
var expected = new Dictionary<string, FactionRelationship>
|
||||
{
|
||||
{ "Adrasteia", FactionRelationship.Hated }, { "Borealis", FactionRelationship.Friendly }, { "Corvid", FactionRelationship.Beloved }
|
||||
};
|
||||
|
||||
using (var cache = Open())
|
||||
{
|
||||
var galaxy = new Galaxy(cache, cache.GetGlobal<SavedGame>(), _ => { });
|
||||
Assert.NotEqual(galaxy.Factions, galaxy.HomeZones.Keys);
|
||||
foreach (var faction in galaxy.Factions) galaxy.FactionRelationships[faction] = expected[faction.Name];
|
||||
var itemManager = new ItemManager(1u, cache, new ProvenanceLedger(), TestSettings(), _ => { });
|
||||
galaxy.Zones[0].Contents = new Zone(itemManager, new PlanetSettings(), new ZonePack(), galaxy.Zones[0], galaxy);
|
||||
var (game, zones) = RunSave.Capture(cache, galaxy, galaxy.Zones[0].Contents, null, new SavedActionBarBinding[0], 0);
|
||||
RunSave.Commit(cache, game, zones, RunSave.Lots(cache));
|
||||
}
|
||||
|
||||
using (var cache = Open())
|
||||
{
|
||||
var galaxy = new Galaxy(cache, cache.GetGlobal<SavedGame>(), _ => { });
|
||||
Assert.Equal(expected, galaxy.Factions.ToDictionary(f => f.Name, f => galaxy.FactionRelationships[f]));
|
||||
}
|
||||
}
|
||||
|
||||
// The run's credits ride the save: what Capture is given is what a later Continue reads from the run store.
|
||||
[Fact]
|
||||
public void CreditsSurviveContinue()
|
||||
|
|
@ -753,11 +795,14 @@ public sealed class RunSaveTests : IDisposable
|
|||
return new ZonePack { Orbits = { root, moon }, Planets = { body } };
|
||||
}
|
||||
|
||||
private static SavedGame Game(CultCache cache) => new SavedGame
|
||||
private static SavedGame Game(CultCache cache) => Game(cache, cache.GetAll<Faction>().Single());
|
||||
|
||||
// HomeZones lists the factions in reverse of their saved order.
|
||||
private static SavedGame Game(CultCache cache, params Faction[] factions) => new SavedGame
|
||||
{
|
||||
Factions = new[] { cache.RefOf(cache.GetAll<Faction>().Single()) },
|
||||
Relationships = new[] { FactionRelationship.Neutral },
|
||||
HomeZones = new Dictionary<int, int> { { 0, 0 } },
|
||||
Factions = factions.Select(f => cache.RefOf(f)).ToArray(),
|
||||
Relationships = factions.Select(_ => FactionRelationship.Neutral).ToArray(),
|
||||
HomeZones = factions.Select((_, i) => factions.Length - 1 - i).ToDictionary(i => i, _ => 0),
|
||||
BossZones = new Dictionary<int, int>(),
|
||||
DiscoveredZones = new[] { 0 },
|
||||
ActionBarBindings = new SavedActionBarBinding[0],
|
||||
|
|
|
|||
Loading…
Reference in a new issue