@@ -91,7 +91,7 @@ private void LoadInvalidatingCultureIds(OrderedDictionary<string, bool> ck3ModFl
91
91
cultureIdsPerModFlagParser . ParseStream ( reader ) ;
92
92
}
93
93
94
- public void LoadCultures ( ModFilesystem ck3ModFS ) {
94
+ public void LoadCultures ( ModFilesystem ck3ModFS , Configuration config ) {
95
95
Logger . Info ( "Loading cultures..." ) ;
96
96
97
97
OrderedDictionary < string , CultureData > culturesData = new ( ) ; // Preserves order of insertion.
@@ -102,12 +102,12 @@ public void LoadCultures(ModFilesystem ck3ModFS) {
102
102
parser . ParseGameFolder ( "common/culture/cultures" , ck3ModFS , "txt" , recursive : true , logFilePaths : true ) ;
103
103
104
104
// After we've load all cultures data, we can validate it and create cultures.
105
- ValidateAndLoadCultures ( culturesData ) ;
105
+ ValidateAndLoadCultures ( culturesData , config ) ;
106
106
107
107
ReplaceInvalidatedParents ( ) ;
108
108
}
109
109
110
- public void LoadConverterCultures ( string converterCulturesPath ) {
110
+ public void LoadConverterCultures ( string converterCulturesPath , Configuration config ) {
111
111
Logger . Info ( "Loading converter cultures..." ) ;
112
112
113
113
OrderedDictionary < string , CultureData > culturesData = new ( ) ; // Preserves order of insertion.
@@ -118,7 +118,7 @@ public void LoadConverterCultures(string converterCulturesPath) {
118
118
parser . ParseFile ( converterCulturesPath ) ;
119
119
120
120
// After we've load all cultures data, we can validate it and create cultures.
121
- ValidateAndLoadCultures ( culturesData ) ;
121
+ ValidateAndLoadCultures ( culturesData , config ) ;
122
122
123
123
ReplaceInvalidatedParents ( ) ;
124
124
}
@@ -130,7 +130,7 @@ private CultureData LoadCultureData(BufferedReader cultureReader) {
130
130
return cultureData ;
131
131
}
132
132
133
- private void ValidateAndLoadCultures ( OrderedDictionary < string , CultureData > culturesData ) {
133
+ private void ValidateAndLoadCultures ( OrderedDictionary < string , CultureData > culturesData , Configuration config ) {
134
134
foreach ( var ( cultureId , data ) in culturesData ) {
135
135
if ( data . InvalidatingCultureIds . Any ( ) ) {
136
136
bool isInvalidated = false ;
@@ -148,8 +148,14 @@ private void ValidateAndLoadCultures(OrderedDictionary<string, CultureData> cult
148
148
Logger . Debug ( $ "Loading optional culture { cultureId } ...") ;
149
149
}
150
150
if ( data . Heritage is null ) {
151
- Logger . Warn ( $ "Culture { cultureId } has no valid heritage defined! Skipping.") ;
152
- continue ;
151
+ // Special handling for TFE hunnic culture. #TODO: remove this when it's fixed on TFE side.
152
+ if ( config . FallenEagleEnabled && cultureId == "hunnic" && PillarCollection . GetHeritageForId ( "heritage_turkic" ) is Pillar turkicHeritage ) {
153
+ Logger . Debug ( "Applying turkic heritage to TFE hunnic culture." ) ;
154
+ data . Heritage = turkicHeritage ;
155
+ } else {
156
+ Logger . Warn ( $ "Culture { cultureId } has no valid heritage defined! Skipping.") ;
157
+ continue ;
158
+ }
153
159
}
154
160
if ( data . Language is null ) {
155
161
Logger . Warn ( $ "Culture { cultureId } has no valid language defined! Skipping.") ;
@@ -248,6 +254,38 @@ public void LoadInnovationIds(ModFilesystem ck3ModFS) {
248
254
}
249
255
}
250
256
257
+ internal void WarnAboutCircularParents ( ) {
258
+ // For every culture, check if it isn't set as its own immediate or distant parent.
259
+ Logger . Debug ( "Checking for circular culture parents..." ) ;
260
+ foreach ( var culture in this ) {
261
+ var allParents = GetImmediateAndDistantParentsOfCulture ( culture ) ;
262
+ if ( allParents . Contains ( culture . Id ) ) {
263
+ Logger . Error ( $ "Culture { culture . Id } is set as its own parent!") ;
264
+ }
265
+ }
266
+ }
267
+
268
+ private HashSet < string > GetImmediateAndDistantParentsOfCulture ( Culture cultureToCheck , HashSet < string > ? alreadyChecked = null ) {
269
+ HashSet < string > allParents = [ ] ;
270
+
271
+ // Get immediate parents.
272
+ foreach ( var parentCultureId in cultureToCheck . ParentCultureIds ) {
273
+ // Avoid infinite recursion.
274
+ if ( alreadyChecked ? . Contains ( parentCultureId ) == true ) {
275
+ continue ;
276
+ }
277
+
278
+ allParents . Add ( parentCultureId ) ;
279
+ var parentCulture = this [ parentCultureId ] ;
280
+
281
+ // Add the parent's parents.
282
+ var parentParents = GetImmediateAndDistantParentsOfCulture ( parentCulture , allParents ) ;
283
+ allParents . UnionWith ( parentParents ) ;
284
+ }
285
+
286
+ return allParents ;
287
+ }
288
+
251
289
private readonly IDictionary < string , string > cultureReplacements = new Dictionary < string , string > ( ) ; // replaced culture -> replacing culture
252
290
253
291
protected readonly PillarCollection PillarCollection ;
0 commit comments