Skip to content

Commit e58672c

Browse files
author
Swamp Ig
committed
Backup only if really needed.
1 parent f8cf00e commit e58672c

File tree

1 file changed

+82
-53
lines changed

1 file changed

+82
-53
lines changed

SaveGameFixer.cs

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,20 @@ orderby ass.assembly.GetName().Version descending, ass.path ascending
4545
return true;
4646
}
4747

48+
private static bool hasRun = false;
49+
4850
internal void Awake()
4951
{
5052
try
5153
{
5254
if (!RunTypeElection(typeof(SaveGameFixer), "ModuleManager"))
5355
return;
56+
57+
// Guard against multiple copies of the same DLL
58+
if (hasRun)
59+
return;
60+
hasRun = true;
61+
5462
// So at this point we know we have won the election, and will be using the class versions as in this assembly.
5563

5664
UpdateSaves();
@@ -68,15 +76,42 @@ internal void Awake()
6876
}
6977
#endregion
7078

71-
#region Finding the part
79+
#region State
80+
81+
// Files and directories
7282
private string savesRoot;
83+
private string backupDir = null;
84+
private string logFile = null;
85+
86+
// Bits and pieces for logging
87+
private StringBuilder backupLog = new StringBuilder();
88+
private List<string> logContext = new List<string>();
89+
private int logCtxCur = 0;
90+
91+
// Flags
92+
private bool logOnly = true;
93+
private bool needsBackup = false;
94+
private bool needsSave = false;
95+
private bool partMissing = false;
96+
97+
#endregion
98+
99+
#region Finding the part
100+
73101

74102
private void UpdateSaves()
75103
{
76104
savesRoot = Path.Combine(Path.GetFullPath(KSPUtil.ApplicationRootPath), "saves" + Path.DirectorySeparatorChar);
77105

78106
foreach (string saveDir in Directory.GetDirectories(savesRoot))
79107
UpdateSaveDir(saveDir);
108+
109+
// Write the backup log if needed
110+
if (!logOnly && backupLog.Length > 0)
111+
{
112+
CreateBackupDir();
113+
File.AppendAllText(logFile, backupLog.ToString());
114+
}
80115
}
81116

82117

@@ -85,7 +120,7 @@ private void UpdateSaveDir(string saveDir)
85120
try
86121
{
87122
PushLogContext("Save Game: " + saveDir.Substring(savesRoot.Length, saveDir.Length-savesRoot.Length));
88-
123+
89124
char ds = Path.DirectorySeparatorChar;
90125

91126
// .craft files
@@ -126,11 +161,21 @@ private void UpdateCraft(string vabCraft)
126161
PushLogContext("Craft file: " + vabCraft.Substring(savesRoot.Length, vabCraft.Length-savesRoot.Length));
127162
ConfigNode craft = ConfigNode.Load(vabCraft);
128163

129-
bool needsBackup = false, needsSave = false;
164+
needsBackup = false; needsSave = false; partMissing = false;
165+
130166
foreach (ConfigNode part in craft.GetNodes("PART"))
131-
UpdatePart(part, ref needsBackup, ref needsSave);
167+
UpdatePart(part);
168+
169+
// If a part is missing don't do anything special. The game just locks the craft, it doesn't destory them.
170+
if (partMissing)
171+
{
172+
WriteDebugMessage("Craft has mising parts in the VAB, the craft file will be locked.");
173+
WriteDebugMessage("Delete the craft to get rid of this message.");
174+
}
175+
176+
BackupAndReplace(vabCraft, craft);
177+
132178

133-
BackupAndReplace(vabCraft, craft, needsBackup, needsSave);
134179
}
135180
finally
136181
{
@@ -141,18 +186,28 @@ private void UpdateCraft(string vabCraft)
141186
private void UpdateSFS(string sfsFile)
142187
{
143188
ConfigNode sfs = ConfigNode.Load(sfsFile);
144-
145189
try
146190
{
147191
PushLogContext("Save file: " + sfsFile.Substring(savesRoot.Length, sfsFile.Length-savesRoot.Length));
148192

149-
bool needsBackup = false, needsSave = false;
193+
needsBackup = false; needsSave = false; partMissing = false;
194+
150195
foreach (ConfigNode game in sfs.GetNodes("GAME"))
151196
foreach (ConfigNode flightState in game.GetNodes("FLIGHTSTATE"))
152197
foreach (ConfigNode vessel in flightState.GetNodes("VESSEL"))
153-
UpdateVessel(vessel, ref needsBackup, ref needsSave);
198+
UpdateVessel(vessel);
154199

155-
BackupAndReplace(sfsFile, sfs, needsBackup, needsSave);
200+
// Backup if missing parts.
201+
// TODO: handle missing parts more gracefully, like missing modules are handled.
202+
if (partMissing)
203+
{
204+
WriteLogMessage("Save game has vessels with missing parts. These vessels will be deleted on loading the save.");
205+
WriteLogMessage("The persistence file has been backed up. Note that this will keep occuring every load until");
206+
WriteLogMessage("either the save game is loaded and the ships are destroyed, or the missing parts are not missing.");
207+
needsBackup = true;
208+
}
209+
210+
BackupAndReplace(sfsFile, sfs);
156211
}
157212
finally
158213
{
@@ -161,14 +216,14 @@ private void UpdateSFS(string sfsFile)
161216

162217
}
163218

164-
private void UpdateVessel(ConfigNode vessel, ref bool needsBackup, ref bool needsSave)
219+
private void UpdateVessel(ConfigNode vessel)
165220
{
166221
try
167222
{
168223
PushLogContext("Vessel: " + vessel.GetValue("name"));
169224

170225
foreach (ConfigNode part in vessel.GetNodes("PART"))
171-
UpdatePart(part, ref needsBackup, ref needsSave);
226+
UpdatePart(part);
172227
}
173228
finally
174229
{
@@ -177,7 +232,7 @@ private void UpdateVessel(ConfigNode vessel, ref bool needsBackup, ref bool need
177232
}
178233
#endregion
179234

180-
private void UpdatePart(ConfigNode part, ref bool needsBackup, ref bool needsSave)
235+
private void UpdatePart(ConfigNode part)
181236
{
182237
// The modules saved with the part
183238
ConfigNode[] savedModules = part.GetNodes("MODULE");
@@ -214,8 +269,9 @@ private void UpdatePart(ConfigNode part, ref bool needsBackup, ref bool needsSav
214269

215270
if (available == null)
216271
{
217-
WriteLogMessage("Backup created - part \"" + partName + "\" has been deleted and ship will be destroyed.");
218-
needsBackup = true;
272+
WriteLogMessage("Part \"" + partName + "\" has been deleted.");
273+
partMissing = true;
274+
return;
219275
}
220276

221277
PartModuleList prefabModules = available.partPrefab.Modules;
@@ -232,20 +288,7 @@ private void UpdatePart(ConfigNode part, ref bool needsBackup, ref bool needsSav
232288
return;
233289
needUpdate: ;
234290
}
235-
236291
// Yes we do!
237-
#if false
238-
string prefabNames = "Prefab modules: ";
239-
for (int i = 0; i < prefabModules.Count; ++i)
240-
prefabNames += (prefabModules[i] as PartModule).moduleName + ",";
241-
prefabNames = prefabNames.Substring(0, prefabNames.Length-1);
242-
243-
Debug.Log("[SaveGameFixer] Fixing Part: " + partName + " in file: " + source + "\n" + prefabNames
244-
+ "\nSaved modules: " + string.Join(",", (from s in savedModules select (s==null?"***":s.GetValue("name"))).ToArray())
245-
+ "\nBackup modules: " + string.Join(",", (from s in backupModules select (s==null?"***":s.GetValue("name"))).ToArray())
246-
//+ "\nConfig: \n" + part
247-
);
248-
#endif
249292

250293
// Discard any backups that are already in saved modules
251294
for (int i = 0; i < backupModules.Length; ++i)
@@ -373,11 +416,6 @@ private void UpdatePart(ConfigNode part, ref bool needsBackup, ref bool needsSav
373416

374417
#region Backups
375418

376-
private List<string> logContext = new List<string>();
377-
private int logCtxCur = 0;
378-
private string backupDir = null;
379-
private string logFile = null;
380-
381419
private void PushLogContext(string p)
382420
{
383421
logContext.Add(p);
@@ -397,29 +435,20 @@ private void WriteDebugMessage(string logMessage)
397435

398436
private void WriteLogMessage(string logMessage, bool debugMsg = false)
399437
{
400-
#if DEBUG
401-
string dbg = debugMsg ? "[dbg]" : "[log]";
402-
403-
#else
404-
string dbg = string.Empty;
405-
#endif
406-
CreateBackupDir();
407-
408-
StringBuilder sb = new StringBuilder();
409-
410438
// Write any pending log headers
411439
string indent;
412440
for (; logCtxCur < logContext.Count; logCtxCur++)
413441
{
414-
indent = new String(' ', 4 * logCtxCur + dbg.Length);
415-
sb.Append(indent).AppendLine(logContext[logCtxCur]);
416-
Debug.Log("[SaveGameFixer]" + indent + logContext[logCtxCur]);
442+
indent = new String(' ', 4 * logCtxCur);
443+
backupLog.Append(' ').Append(indent).AppendLine(logContext[logCtxCur]);
444+
Debug.Log(indent + logContext[logCtxCur]);
417445
}
418446
indent = new String(' ', 4 * logCtxCur);
419-
sb.Append(dbg).Append(indent).AppendLine(logMessage);
420-
Debug.Log("[SaveGameFixer]" + dbg + indent + logMessage);
421-
422-
File.AppendAllText(logFile, sb.ToString());
447+
backupLog.Append(debugMsg ? ' ' : '*').Append(indent).AppendLine(logMessage);
448+
if (debugMsg)
449+
Debug.Log(indent + logMessage);
450+
else
451+
Debug.LogWarning(indent + logMessage);
423452
}
424453

425454
private void CreateBackupDir()
@@ -432,11 +461,10 @@ private void CreateBackupDir()
432461
}
433462
}
434463

435-
private void BackupAndReplace(string file, ConfigNode config, bool needsBackup, bool needsSave)
464+
private void BackupAndReplace(string file, ConfigNode config)
436465
{
437-
#if !DEBUG
466+
438467
if (needsBackup)
439-
#endif
440468
{
441469
CreateBackupDir();
442470

@@ -446,13 +474,14 @@ private void BackupAndReplace(string file, ConfigNode config, bool needsBackup,
446474
Directory.CreateDirectory(Path.GetDirectoryName(backupTo));
447475

448476
File.Copy(file, backupTo);
477+
478+
logOnly = false;
449479
}
450480

451481
if(needsSave)
452482
config.Save(file);
453483
}
454484

455-
456485
#endregion
457486
}
458487

0 commit comments

Comments
 (0)