@@ -87,14 +87,14 @@ protected World(Configuration config) {
8787 ImperatorRegionMapper = new ImperatorRegionMapper ( Areas , MapData ) ;
8888 }
8989
90- internal static void OutputGuiContainer ( ModFilesystem modFS , IEnumerable < string > tagsNeedingFlags , Configuration config ) {
90+ internal static bool OutputGuiContainer ( ModFilesystem modFS , IEnumerable < string > tagsNeedingFlags , Configuration config ) {
9191 Logger . Debug ( "Modifying gui for exporting CoAs..." ) ;
9292
9393 const string relativeTopBarGuiPath = "gui/ingame_topbar.gui" ;
9494 var topBarGuiPath = modFS . GetActualFileLocation ( relativeTopBarGuiPath ) ;
9595 if ( topBarGuiPath is null ) {
9696 Logger . Warn ( $ "{ relativeTopBarGuiPath } not found, can't write CoA export commands!") ;
97- return ;
97+ return false ;
9898 }
9999
100100 // build the GUI snippet we want to insert
@@ -128,7 +128,7 @@ internal static void OutputGuiContainer(ModFilesystem modFS, IEnumerable<string>
128128 } catch ( Exception e ) {
129129 Logger . Warn ( $ "Failed to output modified GUI: { e . Message } ") ;
130130 // bail out but don't crash the whole conversion
131- return ;
131+ return false ;
132132 }
133133
134134 // Create a .mod file for the temporary mod.
@@ -138,17 +138,40 @@ internal static void OutputGuiContainer(ModFilesystem modFS, IEnumerable<string>
138138 name = "IRToCK3 CoA export mod"
139139 path = "mod/coa_export_mod"
140140 """ ;
141- File . WriteAllText ( Path . Combine ( config . ImperatorDocPath , "mod/coa_export_mod/descriptor.mod" ) , modFileContents ) ;
141+ if ( ! TryWriteTextFile ( Path . Combine ( config . ImperatorDocPath , "mod/coa_export_mod/descriptor.mod" ) , modFileContents ) ) {
142+ return false ;
143+ }
142144
143145 var absoluteModPath = Path . Combine ( config . ImperatorDocPath , "mod/coa_export_mod" ) . Replace ( '\\ ' , '/' ) ;
144146 modFileContents = modFileContents . Replace ( "path = \" mod/coa_export_mod\" " , $ "path = \" { absoluteModPath } \" ") ;
145- File . WriteAllText ( Path . Combine ( config . ImperatorDocPath , "mod/coa_export_mod.mod" ) , modFileContents ) ;
147+ return TryWriteTextFile ( Path . Combine ( config . ImperatorDocPath , "mod/coa_export_mod.mod" ) , modFileContents ) ;
148+ }
149+
150+ private static bool TryWriteTextFile ( string filePath , string contents ) {
151+ try {
152+ var directoryPath = Path . GetDirectoryName ( filePath ) ;
153+ if ( directoryPath is not null ) {
154+ FileHelper . EnsureDirectoryExists ( directoryPath ) ;
155+ }
156+
157+ if ( File . Exists ( filePath ) ) {
158+ File . SetAttributes ( filePath , FileAttributes . Normal ) ;
159+ }
160+
161+ using var writer = FileHelper . OpenWriteWithRetries ( filePath , Encoding . UTF8 ) ;
162+ writer . Write ( contents ) ;
163+ return true ;
164+ } catch ( Exception e ) when ( e is UnauthorizedAccessException or IOException or UserErrorException ) {
165+ Logger . Warn ( $ "Failed to write \" { filePath } \" : { e . Message } ") ;
166+ Logger . Debug ( e . ToString ( ) ) ;
167+ return false ;
168+ }
146169 }
147170
148- private void OutputContinueGameJson ( Configuration config ) {
171+ private bool OutputContinueGameJson ( Configuration config ) {
149172 // Set the current save to be used when launching the game with the continuelastsave option.
150173 Logger . Debug ( "Modifying continue_game.json..." ) ;
151- File . WriteAllText ( Path . Join ( config . ImperatorDocPath , "continue_game.json" ) ,
174+ return TryWriteTextFile ( Path . Join ( config . ImperatorDocPath , "continue_game.json" ) ,
152175 contents : $$ """
153176 {
154177 "title": "{{ Path . GetFileNameWithoutExtension ( config . SaveGamePath ) }} ",
@@ -158,7 +181,7 @@ private void OutputContinueGameJson(Configuration config) {
158181 """ ) ;
159182 }
160183
161- private void OutputDlcLoadJson ( Configuration config ) {
184+ private bool OutputDlcLoadJson ( Configuration config ) {
162185 Logger . Debug ( "Outputting dlc_load.json..." ) ;
163186 var dlcLoadBuilder = new StringBuilder ( ) ;
164187 dlcLoadBuilder . AppendLine ( "{" ) ;
@@ -169,19 +192,21 @@ private void OutputDlcLoadJson(Configuration config) {
169192 dlcLoadBuilder . AppendLine ( "]," ) ;
170193 dlcLoadBuilder . AppendLine ( @"""disabled_dlcs"":[]" ) ;
171194 dlcLoadBuilder . AppendLine ( "}" ) ;
172- File . WriteAllText ( Path . Join ( config . ImperatorDocPath , "dlc_load.json" ) , dlcLoadBuilder . ToString ( ) ) ;
195+ return TryWriteTextFile ( Path . Join ( config . ImperatorDocPath , "dlc_load.json" ) , dlcLoadBuilder . ToString ( ) ) ;
173196 }
174197
175- private void LaunchImperatorToExportCountryFlags ( Configuration config ) {
198+ private bool LaunchImperatorToExportCountryFlags ( Configuration config ) {
176199 Logger . Info ( "Retrieving random CoAs from Imperator..." ) ;
177- OutputContinueGameJson ( config ) ;
178- OutputDlcLoadJson ( config ) ;
200+ if ( ! OutputContinueGameJson ( config ) || ! OutputDlcLoadJson ( config ) ) {
201+ Logger . Warn ( "Skipping Imperator launch because the launcher files couldn't be written." ) ;
202+ return false ;
203+ }
179204
180205 string imperatorBinaryName = OperatingSystem . IsWindows ( ) ? "imperator.exe" : "imperator" ;
181206 var imperatorBinaryPath = Path . Combine ( config . ImperatorPath , "binaries" , imperatorBinaryName ) ;
182207 if ( ! File . Exists ( imperatorBinaryPath ) ) {
183208 Logger . Warn ( "Imperator binary not found! Aborting the random CoA extraction!" ) ;
184- return ;
209+ return false ;
185210 }
186211
187212 string dataTypesLogPath = Path . Combine ( config . ImperatorDocPath , "logs/data_types.log" ) ;
@@ -202,7 +227,7 @@ private void LaunchImperatorToExportCountryFlags(Configuration config) {
202227 var imperatorProcess = Process . Start ( processStartInfo ) ;
203228 if ( imperatorProcess is null ) {
204229 Logger . Warn ( "Failed to start Imperator process! Aborting!" ) ;
205- return ;
230+ return false ;
206231 }
207232
208233 imperatorProcess . Exited += HandleImperatorProcessExit ( config , imperatorProcess ) ;
@@ -220,6 +245,8 @@ private void LaunchImperatorToExportCountryFlags(Configuration config) {
220245 Logger . Debug ( "Killing Imperator process..." ) ;
221246 imperatorProcess . Kill ( ) ;
222247 }
248+
249+ return true ;
223250 }
224251
225252 private void WaitForImperatorDataTypesLog ( Process imperatorProcess , string dataTypesLogPath ) {
@@ -279,25 +306,36 @@ private void ReadCoatsOfArmsFromGameLog(string imperatorDocPath) {
279306 }
280307
281308 private void ExtractDynamicCoatsOfArms ( Configuration config ) {
282- var countryFlags = Countries . Select ( country => country . Flag ) . ToArray ( ) ;
283- var missingFlags = CoaMapper . GetAllMissingFlagKeys ( countryFlags ) ;
284- if ( missingFlags . Count == 0 ) {
285- return ;
286- }
309+ try {
310+ var countryFlags = Countries . Select ( country => country . Flag ) . ToArray ( ) ;
311+ var missingFlags = CoaMapper . GetAllMissingFlagKeys ( countryFlags ) ;
312+ if ( missingFlags . Count == 0 ) {
313+ return ;
314+ }
287315
288- Logger . Debug ( "Missing country flag definitions: " + string . Join ( ", " , missingFlags ) ) ;
316+ Logger . Debug ( "Missing country flag definitions: " + string . Join ( ", " , missingFlags ) ) ;
289317
290- var tagsWithMissingFlags = Countries
291- . Where ( country => missingFlags . Contains ( country . Flag ) )
292- . Select ( country => country . Tag ) ;
318+ var tagsWithMissingFlags = Countries
319+ . Where ( country => missingFlags . Contains ( country . Flag ) )
320+ . Select ( country => country . Tag ) ;
293321
294- OutputGuiContainer ( ModFS , tagsWithMissingFlags , config ) ;
295- LaunchImperatorToExportCountryFlags ( config ) ;
296- ReadCoatsOfArmsFromGameLog ( config . ImperatorDocPath ) ;
322+ if ( ! OutputGuiContainer ( ModFS , tagsWithMissingFlags , config ) ) {
323+ Logger . Warn ( "Skipping Imperator launch because the temporary CoA export mod couldn't be prepared." ) ;
324+ return ;
325+ }
326+
327+ if ( ! LaunchImperatorToExportCountryFlags ( config ) ) {
328+ return ;
329+ }
330+ ReadCoatsOfArmsFromGameLog ( config . ImperatorDocPath ) ;
297331
298- var missingFlagsAfterExtraction = CoaMapper . GetAllMissingFlagKeys ( countryFlags ) ;
299- if ( missingFlagsAfterExtraction . Count > 0 ) {
300- Logger . Warn ( "Failed to export the following country flags: " + string . Join ( ", " , missingFlagsAfterExtraction ) ) ;
332+ var missingFlagsAfterExtraction = CoaMapper . GetAllMissingFlagKeys ( countryFlags ) ;
333+ if ( missingFlagsAfterExtraction . Count > 0 ) {
334+ Logger . Warn ( "Failed to export the following country flags: " + string . Join ( ", " , missingFlagsAfterExtraction ) ) ;
335+ }
336+ } catch ( Exception e ) {
337+ Logger . Warn ( $ "Failed to extract dynamic coats of arms: { e . Message } ") ;
338+ Logger . Debug ( e . ToString ( ) ) ;
301339 }
302340 }
303341
0 commit comments