Skip to content

Commit

Permalink
Support for WtWSMS CK3 mod (#2193) #minor
Browse files Browse the repository at this point in the history
  • Loading branch information
IhateTrains authored Sep 16, 2024
1 parent 70bff92 commit b09f0a9
Show file tree
Hide file tree
Showing 26 changed files with 1,283 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using ImperatorToCK3.Mappers.TagTitle;
using ImperatorToCK3.Mappers.Trait;
using ImperatorToCK3.UnitTests.TestHelpers;
using Open.Collections;
using System.Collections.Generic;
using System.Linq;
using Xunit;
Expand Down Expand Up @@ -60,8 +61,8 @@ static CharacterCollectionTests() {
areas.LoadAreas(irModFS, irProvinces);
irRegionMapper = new ImperatorRegionMapper(areas, irMapData);
irRegionMapper.LoadRegions(irModFS, colorFactory);
var ck3ModFlags = new List<string>();

var ck3ModFlags = new System.Collections.Generic.OrderedDictionary<string, bool>();
cultures = new CultureCollection(colorFactory, new PillarCollection(colorFactory, ck3ModFlags), ck3ModFlags);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class CultureCollectionTests {
private static readonly ModFilesystem ck3ModFS = new("TestFiles/CK3/game", Array.Empty<Mod>());
private static readonly PillarCollection pillars;
private static readonly ColorFactory colorFactory = new();
private static readonly List<string> ck3ModFlags = [];
private static readonly OrderedDictionary<string, bool> ck3ModFlags = [];

static CultureCollectionTests() {
pillars = new PillarCollection(colorFactory, []) {
Expand Down
193 changes: 193 additions & 0 deletions ImperatorToCK3.UnitTests/CK3/ParserExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using commonItems;
using ImperatorToCK3.CK3;
using System.Collections.Generic;
using Xunit;

namespace ImperatorToCK3.UnitTests.CK3;

[Collection("Sequential")]
[CollectionDefinition("Sequential", DisableParallelization = true)]
public class ParserExtensionsTests {
[Theory]
[InlineData(true, false, false, 0, 0)]
[InlineData(false, true, false, 1, 1)]
[InlineData(false, false, true, 2, 0)]
[InlineData(true, true, false, 0, 1)]
public void CorrectModDependentBranchesAreUsed(bool wtwsms, bool tfe, bool vanilla, int expectedValue1,
int expectedValue2) {
var ck3ModFlags = new Dictionary<string, bool> {["wtwsms"] = wtwsms, ["tfe"] = tfe, ["vanilla"] = vanilla,};

var blocReader = new BufferedReader(
"""
MOD_DEPENDENT = {
IF @wtwsms = { # Interpolated expression without brackets is valid, therefor should be supported.
value1 = 0
} ELSE_IF tfe = {# Simple mod flag string should be supported as well.
value1 = 1
} ELSE = {
value1 = 2
}

IF @[wtwsms|vanilla|tfe] = { # Logical OR, example of more complex interpolated expression.
value2 = 0
}
IF @[tfe] = { # Will override the previous value2.
value2 = 1
}
}
""");

int? value1 = null;
int? value2 = null;
var parser = new Parser();
parser.RegisterModDependentBloc(ck3ModFlags);
parser.RegisterKeyword("value1", reader => value1 = reader.GetInt());
parser.RegisterKeyword("value2", reader => value2 = reader.GetInt());
parser.ParseStream(blocReader);

Assert.Equal(expectedValue1, value1);
Assert.Equal(expectedValue2, value2);
}

[Fact]
public void ExceptionIsThrownWhenUnknownModFlagIsEncounteredInInterpolatedExpression() {
var reader1 = new BufferedReader(
"""
MOD_DEPENDENT = {
IF @[unknown_mod] = { # Undefined mod flag in interpolated expression.
value = 1
} ELSE = {
value = 2
}
}
""");

int? value = null;
Dictionary<string, bool> modFlags = new();

var parser1 = new Parser();
parser1.RegisterModDependentBloc(modFlags);
parser1.RegisterKeyword("value", reader => value = reader.GetInt());
Assert.Throws<NCalc.Exceptions.NCalcParameterNotDefinedException>(() => parser1.ParseStream(reader1));
Assert.Null(value);
}

[Fact]
public void VariableConditionResolvesToFalseWhenVariableIsNotDefined() {
var reader1 = new BufferedReader(
"""
MOD_DEPENDENT = {
IF @unknown_variable = { # Undefined variable in interpolated expression.
value = 1
} ELSE = {
value = 2
}
}
""");

int? value = null;
Dictionary<string, bool> modFlags = new();

var parser1 = new Parser();
parser1.RegisterModDependentBloc(modFlags);
parser1.RegisterKeyword("value", reader => value = reader.GetInt());
parser1.ParseStream(reader1); // Should not throw.
Assert.Equal(2, value);
}

[Fact]
public void ElseIfAfterElseIsIgnored() {
Dictionary<string, bool> ck3ModFlags = new() {{"wtwsms", false}, {"tfe", true}, {"vanilla", false},};

var blocReader = new BufferedReader(
"""
MOD_DEPENDENT = {
IF wtwsms = {
value = 0
} ELSE = {
value = 2
} ELSE_IF tfe = { # Should be ignored, even if the condition is true.
value = 3
}
}
""");

int? value = null;
var parser = new Parser();
parser.RegisterModDependentBloc(ck3ModFlags);
parser.RegisterKeyword("value", reader => value = reader.GetInt());
parser.ParseStream(blocReader);

Assert.Equal(2, value);
}

[Fact]
public void ElseAfterElseIsIgnored() {
Dictionary<string, bool> ck3ModFlags = new() {{"wtwsms", false}, {"tfe", true}, {"vanilla", false},};

var blocReader = new BufferedReader(
"""
MOD_DEPENDENT = {
IF wtwsms = {
value = 0
} ELSE = {
value = 2
} ELSE = {
value = 3
}
}
""");

int? value = null;
var parser = new Parser();
parser.RegisterModDependentBloc(ck3ModFlags);
parser.RegisterKeyword("value", reader => value = reader.GetInt());
parser.ParseStream(blocReader);

Assert.Equal(2, value);
}

[Fact]
public void ElseIfWithoutPrecedingIfIsIgnored() {
Dictionary<string, bool> ck3ModFlags = new() {{"wtwsms", false}, {"tfe", true}, {"vanilla", false},};

var blocReader = new BufferedReader(
"""
MOD_DEPENDENT = {
ELSE_IF tfe = { # Should be ignored, as there is no IF before it.
value = 3
}
}
""");

int? value = null;
var parser = new Parser();
parser.RegisterModDependentBloc(ck3ModFlags);
parser.RegisterKeyword("value", reader => value = reader.GetInt());
parser.ParseStream(blocReader);

Assert.Null(value);
}

[Fact]
public void ElseWithoutPrecedingIfIsIgnored() {
Dictionary<string, bool> ck3ModFlags = new() {{"wtwsms", false}, {"tfe", true}, {"vanilla", false},};

var blocReader = new BufferedReader(
"""
MOD_DEPENDENT = {
ELSE = { # Should be ignored, as there is no IF before it.
value = 3
}
}
""");

int? value = null;
var parser = new Parser();
parser.RegisterModDependentBloc(ck3ModFlags);
parser.RegisterKeyword("value", reader => value = reader.GetInt());
parser.ParseStream(blocReader);

Assert.Null(value);
}
}
2 changes: 1 addition & 1 deletion ImperatorToCK3.UnitTests/CK3/Titles/LandedTitlesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static LandedTitlesTests() {

public LandedTitlesTests() {
var colorFactory = new ColorFactory();
var ck3ModFlags = Array.Empty<string>();
var ck3ModFlags = new OrderedDictionary<string, bool>();
PillarCollection pillars = new(colorFactory, ck3ModFlags);
cultures = new CultureCollection(colorFactory, pillars, ck3ModFlags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class TagTitleMapperTests {
private static readonly ColorFactory ColorFactory = new();

static TagTitleMapperTests() {
var ck3ModFlags = new List<string>();
var ck3ModFlags = new OrderedDictionary<string, bool>();
var pillars = new PillarCollection(ColorFactory, ck3ModFlags);
cultures = new CultureCollection(ColorFactory, pillars, ck3ModFlags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public async Task CoaIsOutputtedForCountryWithFlagSet() {

var ck3Religions = new ReligionCollection(titles);
var ck3RegionMapper = new CK3RegionMapper();
var ck3ModFlags = new List<string>();
var ck3ModFlags = new OrderedDictionary<string, bool>();
titles.ImportImperatorCountries(countries,
Array.Empty<Dependency>(),
new TagTitleMapper(),
Expand Down Expand Up @@ -102,7 +102,7 @@ public async Task CoaIsNotOutputtedForCountryWithoutFlagSet() {

var ck3Religions = new ReligionCollection(titles);
var ck3RegionMapper = new CK3RegionMapper();
var ck3ModFlags = new List<string>();
var ck3ModFlags = new OrderedDictionary<string, bool>();
titles.ImportImperatorCountries(countries,
Array.Empty<Dependency>(),
new TagTitleMapper(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using ImperatorToCK3.Outputter;
using ImperatorToCK3.UnitTests.TestHelpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Xunit;
Expand All @@ -36,7 +37,7 @@ public async Task DynastiesAreOutputted() {
irRegionMapper.LoadRegions(irModFS, new ColorFactory());
var colorFactory = new ColorFactory();
irRegionMapper.LoadRegions(irModFS, colorFactory);
var ck3ModFlags = Array.Empty<string>();
var ck3ModFlags = new OrderedDictionary<string, bool>();
CultureMapper cultureMapper = new(irRegionMapper, new CK3RegionMapper(), new CultureCollection(colorFactory, new PillarCollection(colorFactory, ck3ModFlags), ck3ModFlags));

var characters = new CharacterCollection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace ImperatorToCK3.UnitTests.TestHelpers;

public class TestCK3CultureCollection() : CultureCollection(colorFactory, new PillarCollection(colorFactory, ck3ModFlags), ck3ModFlags) {
private static readonly ColorFactory colorFactory = new();
private static readonly List<string> ck3ModFlags = [];
private static readonly OrderedDictionary<string, bool> ck3ModFlags = [];

public void LoadConverterPillars(string filePath) {
PillarCollection.LoadConverterPillars(filePath);
Expand Down
1 change: 1 addition & 0 deletions ImperatorToCK3.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AI/@EntryIndexedValue">AI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BOM/@EntryIndexedValue">BOM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CCU/@EntryIndexedValue">CCU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CK/@EntryIndexedValue">CK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue">DB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DDS/@EntryIndexedValue">DDS</s:String>
Expand Down
20 changes: 11 additions & 9 deletions ImperatorToCK3/CK3/Cultures/CultureCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
namespace ImperatorToCK3.CK3.Cultures;

public class CultureCollection : IdObjectCollection<string, Culture> {
public CultureCollection(ColorFactory colorFactory, PillarCollection pillarCollection, ICollection<string> ck3ModFlags) {
public CultureCollection(ColorFactory colorFactory, PillarCollection pillarCollection, OrderedDictionary<string, bool> ck3ModFlags) {
this.PillarCollection = pillarCollection;
InitCultureDataParser(colorFactory, ck3ModFlags);
}

private void InitCultureDataParser(ColorFactory colorFactory, ICollection<string> ck3ModFlags) {
private void InitCultureDataParser(ColorFactory colorFactory, OrderedDictionary<string, bool> ck3ModFlags) {
cultureDataParser.RegisterKeyword("INVALIDATED_BY", reader => LoadInvalidatingCultureIds(ck3ModFlags, reader));
cultureDataParser.RegisterModDependentBloc(ck3ModFlags);
cultureDataParser.RegisterKeyword("color", reader => {
try {
cultureData.Color = colorFactory.GetColor(reader);
Expand All @@ -38,14 +39,14 @@ private void InitCultureDataParser(ColorFactory colorFactory, ICollection<string
var heritageId = reader.GetString();
cultureData.Heritage = PillarCollection.GetHeritageForId(heritageId);
if (cultureData.Heritage is null) {
Logger.Warn($"Found unrecognized heritage when parsing cultures: {heritageId}");
Logger.Debug($"Found unrecognized heritage when parsing cultures: {heritageId}");
}
});
cultureDataParser.RegisterKeyword("language", reader => {
var languageId = reader.GetString();
cultureData.Language = PillarCollection.GetLanguageForId(languageId);
if (cultureData.Language is null) {
Logger.Warn($"Found unrecognized language when parsing cultures: {languageId}");
Logger.Debug($"Found unrecognized language when parsing cultures: {languageId}");
}
});
cultureDataParser.RegisterKeyword("traditions", reader => {
Expand All @@ -65,16 +66,16 @@ private void InitCultureDataParser(ColorFactory colorFactory, ICollection<string
cultureDataParser.IgnoreAndLogUnregisteredItems();
}

private void LoadInvalidatingCultureIds(ICollection<string> ck3ModFlags, BufferedReader reader) {
private void LoadInvalidatingCultureIds(OrderedDictionary<string, bool> ck3ModFlags, BufferedReader reader) {
var cultureIdsPerModFlagParser = new Parser();

if (ck3ModFlags.Count == 0) {
cultureIdsPerModFlagParser.RegisterKeyword("vanilla", modCultureIdsReader => {
cultureData.InvalidatingCultureIds = modCultureIdsReader.GetStrings();
});
} else {
foreach (var modFlag in ck3ModFlags) {
cultureIdsPerModFlagParser.RegisterKeyword(modFlag, modCultureIdsReader => {
foreach (var modFlag in ck3ModFlags.Where(f => f.Value)) {
cultureIdsPerModFlagParser.RegisterKeyword(modFlag.Key, modCultureIdsReader => {
cultureData.InvalidatingCultureIds = modCultureIdsReader.GetStrings();
});
}
Expand Down Expand Up @@ -142,11 +143,11 @@ private void ValidateAndLoadCultures(OrderedDictionary<string, CultureData> cult
Logger.Debug($"Loading optional culture {cultureId}...");
}
if (data.Heritage is null) {
Logger.Warn($"Culture {cultureId} has no heritage defined! Skipping.");
Logger.Warn($"Culture {cultureId} has no valid heritage defined! Skipping.");
continue;
}
if (data.Language is null) {
Logger.Warn($"Culture {cultureId} has no language defined! Skipping.");
Logger.Warn($"Culture {cultureId} has no valid language defined! Skipping.");
continue;
}
if (data.NameLists.Count == 0) {
Expand All @@ -158,6 +159,7 @@ private void ValidateAndLoadCultures(OrderedDictionary<string, CultureData> cult
var color = new ColorHash().Rgb(cultureId);
data.Color = new Color(color.R, color.G, color.B);
}

AddOrReplace(new Culture(cultureId, data));
}
}
Expand Down
Loading

0 comments on commit b09f0a9

Please sign in to comment.