Skip to content

Commit 4815df2

Browse files
authored
Make Imperator spouses not nullable (#355)
* Make Imperator spouses not nullable This means we no longer need to add null checks for them in converter logic. see https://discord.com/channels/612683871112396800/612683871112396802/896687063087349771 * Spouse linking tests
1 parent f691a84 commit 4815df2

File tree

7 files changed

+67
-41
lines changed

7 files changed

+67
-41
lines changed

ImperatorToCK3.UnitTests/Imperator/Characters/CharactersTests.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using Xunit;
33

44
namespace ImperatorToCK3.UnitTests.Imperator.Characters {
5+
[Collection("Sequential")]
6+
[CollectionDefinition("Sequential", DisableParallelization = true)]
57
public class CharactersTests {
68
private readonly ImperatorToCK3.Imperator.Genes.GenesDB genesDB = new();
79
[Fact]
@@ -14,8 +16,7 @@ public void CharactersDefaultToEmpty() {
1416
[Fact]
1517
public void CharactersCanBeLoaded() {
1618
var reader = new BufferedReader(
17-
"=\n" +
18-
"{\n" +
19+
"= {\n" +
1920
"\t42={}\n" +
2021
"\t43={}\n" +
2122
"}"
@@ -33,5 +34,27 @@ public void CharactersCanBeLoaded() {
3334
}
3435
);
3536
}
37+
[Fact]
38+
public void SpousesAreLinked() {
39+
var reader = new BufferedReader(
40+
"= {\n" +
41+
"\t42={}\n" +
42+
"\t43={ spouse = { 42 } }\n" +
43+
"}"
44+
);
45+
var characters = new ImperatorToCK3.Imperator.Characters.Characters(reader, genesDB);
46+
Assert.Equal((ulong)42, characters.StoredCharacters[43].Spouses[42].Id);
47+
}
48+
49+
[Fact]
50+
public void MissingSpousesAreDropped() {
51+
var reader = new BufferedReader(
52+
"= {\n" +
53+
"\t43={ spouse = { 42 } }\n" + // character 42 is missing definition
54+
"}"
55+
);
56+
var characters = new ImperatorToCK3.Imperator.Characters.Characters(reader, genesDB);
57+
Assert.Empty(characters.StoredCharacters[43].Spouses);
58+
}
3659
}
3760
}

ImperatorToCK3.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue">DB</s:String>
23
<s:Boolean x:Key="/Default/UserDictionary/Words/=Antigonid/@EntryIndexedValue">True</s:Boolean>
34
<s:Boolean x:Key="/Default/UserDictionary/Words/=aquitane/@EntryIndexedValue">True</s:Boolean>
45
<s:Boolean x:Key="/Default/UserDictionary/Words/=Biggus/@EntryIndexedValue">True</s:Boolean>

ImperatorToCK3/CK3/Characters/Character.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,7 @@ Date ck3BookmarkDate
172172

173173
if (provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper).Count == 0 && ImperatorCharacter.Spouses.Count > 0) {
174174
var firstSpouse = ImperatorCharacter.Spouses.First().Value;
175-
if (firstSpouse is not null) {
176-
impProvForProvinceMapper = firstSpouse.ProvinceId;
177-
}
175+
impProvForProvinceMapper = firstSpouse.ProvinceId;
178176
}
179177

180178
var ck3ProvinceNumbers = provinceMapper.GetCK3ProvinceNumbers(impProvForProvinceMapper);

ImperatorToCK3/CK3/World.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,19 +559,20 @@ private void PurgeLandlessVanillaCharacters(Date ck3BookmarkDate) {
559559
private void LinkSpouses() {
560560
var spouseCounter = 0;
561561
foreach (var ck3Character in Characters.Values) {
562-
var newSpouses = new Dictionary<ulong, Character>();
563562
// make links between Imperator characters
564563
if (ck3Character.ImperatorCharacter is null) {
565564
// imperatorRegnal characters do not have ImperatorCharacter
566565
continue;
567566
}
568567
foreach (var impSpouseCharacter in ck3Character.ImperatorCharacter.Spouses.Values) {
569-
if (impSpouseCharacter is not null) {
570-
var ck3SpouseCharacter = impSpouseCharacter.CK3Character;
571-
ck3Character.Spouses[ck3SpouseCharacter.ID] = ck3SpouseCharacter;
572-
ck3SpouseCharacter.Spouses[ck3Character.ID] = ck3Character;
573-
++spouseCounter;
568+
var ck3SpouseCharacter = impSpouseCharacter.CK3Character;
569+
if (ck3SpouseCharacter is null) {
570+
Logger.Warn($"Imperator spouse {impSpouseCharacter.Id} has no CK3 character!");
571+
continue;
574572
}
573+
ck3Character.Spouses[ck3SpouseCharacter.ID] = ck3SpouseCharacter;
574+
ck3SpouseCharacter.Spouses[ck3Character.ID] = ck3Character;
575+
++spouseCounter;
575576
}
576577
}
577578
Logger.Info($"{spouseCounter} spouses linked in CK3.");

ImperatorToCK3/Imperator/Characters/Character.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using System.Collections.Generic;
2-
using commonItems;
1+
using commonItems;
32
using ImperatorToCK3.Imperator.Families;
3+
using System.Collections.Generic;
4+
using System.Linq;
45

56
namespace ImperatorToCK3.Imperator.Characters {
67
public class Character {
@@ -33,7 +34,8 @@ public string Culture {
3334
public Date? DeathDate { get; private set; }
3435
public bool IsDead => DeathDate is not null;
3536
public string? DeathReason { get; set; }
36-
public Dictionary<ulong, Character?> Spouses { get; set; } = new();
37+
private HashSet<ulong> parsedSpouseIds = new();
38+
public Dictionary<ulong, Character> Spouses { get; set; } = new();
3739
public Dictionary<ulong, Character?> Children { get; set; } = new();
3840
public KeyValuePair<ulong, Character?> Mother { get; set; } = new();
3941
public KeyValuePair<ulong, Character?> Father { get; set; } = new();
@@ -141,9 +143,7 @@ static Character() {
141143
parsedCharacter.Wealth = ParserHelpers.GetDouble(reader);
142144
});
143145
parser.RegisterKeyword("spouse", reader => {
144-
foreach (var spouse in ParserHelpers.GetULongs(reader)) {
145-
parsedCharacter.Spouses.Add(spouse, null);
146-
}
146+
parsedCharacter.parsedSpouseIds = ParserHelpers.GetULongs(reader).ToHashSet();
147147
});
148148
parser.RegisterKeyword("children", reader => {
149149
foreach (var child in ParserHelpers.GetULongs(reader)) {
@@ -170,5 +170,20 @@ public static Character Parse(BufferedReader reader, string idString, Genes.Gene
170170

171171
return parsedCharacter;
172172
}
173+
174+
// Returns counter of linked spouses
175+
public int LinkSpouses(Dictionary<ulong, Character> characters) {
176+
var counter = 0;
177+
foreach (var spouseId in parsedSpouseIds) {
178+
if (characters.TryGetValue(spouseId, out var spouseToLink)) {
179+
Spouses.Add(spouseToLink.Id, spouseToLink);
180+
++counter;
181+
} else {
182+
Logger.Warn($"Spouse ID: {spouseId} has no definition!");
183+
}
184+
}
185+
186+
return counter;
187+
}
173188
}
174189
}

ImperatorToCK3/Imperator/Characters/Characters.cs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using System.Collections.Generic;
1+
using commonItems;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using System.Text;
3-
using commonItems;
45

56
namespace ImperatorToCK3.Imperator.Characters {
67
public class Characters : Parser {
@@ -10,6 +11,11 @@ public Characters(BufferedReader reader, Genes.GenesDB? genesDB) {
1011
RegisterKeys();
1112
ParseStream(reader);
1213
ClearRegisteredRules();
14+
15+
Logger.Info("Linking Characters with Spouses...");
16+
LinkSpouses();
17+
Logger.Info("Linking Characters with Mothers and Fathers...");
18+
LinkMothersAndFathers();
1319
}
1420
public Dictionary<ulong, Character> StoredCharacters { get; } = new();
1521
public void LinkFamilies(Families.Families families) {
@@ -44,26 +50,12 @@ public void LinkFamilies(Families.Families families) {
4450

4551
Logger.Info($"{counter} families linked to characters.");
4652
}
47-
public void LinkSpouses() {
48-
var spouseCounter = 0;
49-
foreach (var (characterID, character) in StoredCharacters) {
50-
if (character.Spouses.Count == 0) {
51-
continue;
52-
}
53-
var newSpouses = new Dictionary<ulong, Character?>();
54-
foreach (var spouseID in character.Spouses.Keys) {
55-
if (StoredCharacters.TryGetValue(spouseID, out var spouseToLink)) {
56-
newSpouses.Add(spouseToLink.Id, spouseToLink);
57-
++spouseCounter;
58-
} else {
59-
Logger.Warn($"Spouse ID: {spouseID} has no definition!");
60-
}
61-
}
62-
character.Spouses = newSpouses;
63-
}
53+
private void LinkSpouses() {
54+
var spouseCounter = StoredCharacters.Values.Sum(character => character.LinkSpouses(StoredCharacters));
6455
Logger.Info($"{spouseCounter} spouses linked.");
6556
}
66-
public void LinkMothersAndFathers() {
57+
58+
private void LinkMothersAndFathers() {
6759
var motherCounter = 0;
6860
var fatherCounter = 0;
6961
foreach (var (characterID, character) in StoredCharacters) {

ImperatorToCK3/Imperator/World.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,6 @@ public World(Configuration configuration, ConverterVersion converterVersion) {
143143
Logger.Info("Linking Characters with Families");
144144
Characters.LinkFamilies(Families);
145145
Families.RemoveUnlinkedMembers();
146-
Logger.Info("Linking Characters with Spouses");
147-
Characters.LinkSpouses();
148-
Logger.Info("Linking Characters with Mothers and Fathers");
149-
Characters.LinkMothersAndFathers();
150146
Logger.Info("Linking Characters with Countries");
151147
Characters.LinkCountries(Countries);
152148
Logger.Info("Linking Provinces with Pops");

0 commit comments

Comments
 (0)