Skip to content

Commit

Permalink
Save patch log and dump when loading from cache
Browse files Browse the repository at this point in the history
This ensures that modders have access to a full history of what ModuleManager did even when the log was taken from a run where it loaded from cache
  • Loading branch information
blowfishpro committed Jan 10, 2019
1 parent 52d8b18 commit 7145003
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 13 deletions.
1 change: 1 addition & 0 deletions ModuleManager/FilePathRepository.cs
Expand Up @@ -20,5 +20,6 @@ internal static class FilePathRepository

internal static readonly string logsDirPath = Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "Logs"), "ModuleManager");
internal static readonly string logPath = Path.Combine(logsDirPath, "ModuleManager.log");
internal static readonly string patchLogPath = Path.Combine(logsDirPath, "MMPatch.log");
}
}
96 changes: 83 additions & 13 deletions ModuleManager/MMPatchLoader.cs
Expand Up @@ -11,8 +11,10 @@
using UnityEngine;
using Debug = UnityEngine.Debug;

using ModuleManager.Collections;
using ModuleManager.Logging;
using ModuleManager.Extensions;
using ModuleManager.Threading;
using ModuleManager.Tags;
using ModuleManager.Patches;
using ModuleManager.Progress;
Expand Down Expand Up @@ -41,6 +43,8 @@ public class MMPatchLoader

private const float yieldInterval = 1f/30f; // Patch at ~30fps

private const float TIME_TO_WAIT_FOR_LOGS = 0.05f;

private IBasicLogger logger;

public static void AddPostPatchCallback(ModuleManagerPostPatchCallback callback)
Expand Down Expand Up @@ -79,10 +83,53 @@ public IEnumerable<IProtoUrlConfig> Run()

if (!useCache)
{
IPatchProgress progress = new PatchProgress(logger);
if (!Directory.Exists(logsDirPath)) Directory.CreateDirectory(logsDirPath);
MessageQueue<ILogMessage> externalLogQueue = new MessageQueue<ILogMessage>();
MessageQueue<ILogMessage> patchLogQueue = new MessageQueue<ILogMessage>();
bool logThreadExitFlag = false;
ITaskStatus loggingThreadStatus = BackgroundTask.Start(delegate
{
QueueLogger externalLogger = new QueueLogger(externalLogQueue);
using (StreamLogger streamLogger = new StreamLogger(new FileStream(patchLogPath, FileMode.Create), externalLogger))
{
while (!logThreadExitFlag)
{
float waitTargetTime = Time.realtimeSinceStartup + TIME_TO_WAIT_FOR_LOGS;

foreach (ILogMessage message in patchLogQueue.TakeAll())
{
message.LogTo(streamLogger);
}

foreach (ILogMessage message in externalLogQueue.TakeAll())
{
message.LogTo(logger);
}

float timeRemaining = waitTargetTime - Time.realtimeSinceStartup;
if (timeRemaining > 0)
System.Threading.Thread.Sleep((int)(timeRemaining * 1000));
}

foreach (ILogMessage message in patchLogQueue.TakeAll())
{
message.LogTo(streamLogger);
}

foreach (ILogMessage message in externalLogQueue.TakeAll())
{
message.LogTo(logger);
}

streamLogger.Info("Done!");
}
});
IBasicLogger patchLogger = new LogSplitter(logger, new QueueLogger(patchLogQueue));

IPatchProgress progress = new PatchProgress(patchLogger);
status = "Pre patch init";
logger.Info(status);
IEnumerable<string> mods = ModListGenerator.GenerateModList(progress, logger);
patchLogger.Info(status);
IEnumerable<string> mods = ModListGenerator.GenerateModList(progress, patchLogger);

// If we don't use the cache then it is best to clean the PartDatabase.cfg
if (!keepPartDB && File.Exists(partDatabasePath))
Expand All @@ -93,14 +140,14 @@ public IEnumerable<IProtoUrlConfig> Run()
#region Sorting Patches

status = "Extracting patches";
logger.Info(status);
patchLogger.Info(status);

UrlDir gameData = GameDatabase.Instance.root.children.First(dir => dir.type == UrlDir.DirectoryType.GameData && dir.name == "");
INeedsChecker needsChecker = new NeedsChecker(mods, gameData, progress, logger);
INeedsChecker needsChecker = new NeedsChecker(mods, gameData, progress, patchLogger);
ITagListParser tagListParser = new TagListParser(progress);
IProtoPatchBuilder protoPatchBuilder = new ProtoPatchBuilder(progress);
IPatchCompiler patchCompiler = new PatchCompiler();
PatchExtractor extractor = new PatchExtractor(progress, logger, needsChecker, tagListParser, protoPatchBuilder, patchCompiler);
PatchExtractor extractor = new PatchExtractor(progress, patchLogger, needsChecker, tagListParser, protoPatchBuilder, patchCompiler);

// Have to convert to an array because we will be removing patches
IEnumerable<IPatch> extractedPatches =
Expand All @@ -112,7 +159,7 @@ public IEnumerable<IProtoUrlConfig> Run()
#region Applying patches

status = "Applying patches";
logger.Info(status);
patchLogger.Info(status);

IPass currentPass = null;
float nextUpdate = Time.realtimeSinceStartup + yieldInterval;
Expand All @@ -132,20 +179,20 @@ public IEnumerable<IProtoUrlConfig> Run()
}
});

PatchApplier applier = new PatchApplier(progress, logger);
PatchApplier applier = new PatchApplier(progress, patchLogger);
databaseConfigs = applier.ApplyPatches(patchList);

StatusUpdate(progress);

logger.Info("Done patching");
patchLogger.Info("Done patching");

#endregion Applying patches

#region Saving Cache

foreach (KeyValuePair<string, int> item in progress.Counter.warningFiles)
{
logger.Warning(item.Value + " warning" + (item.Value > 1 ? "s" : "") + " related to GameData/" + item.Key);
patchLogger.Warning(item.Value + " warning" + (item.Value > 1 ? "s" : "") + " related to GameData/" + item.Key);
}

if (progress.Counter.errors > 0 || progress.Counter.exceptions > 0)
Expand All @@ -156,7 +203,7 @@ public IEnumerable<IProtoUrlConfig> Run()
+ "\n";
}

logger.Warning("Errors in patch prevents the creation of the cache");
patchLogger.Warning("Errors in patch prevents the creation of the cache");
try
{
if (File.Exists(cachePath))
Expand All @@ -166,13 +213,13 @@ public IEnumerable<IProtoUrlConfig> Run()
}
catch (Exception e)
{
logger.Exception("Exception while deleting stale cache ", e);
patchLogger.Exception("Exception while deleting stale cache ", e);
}
}
else
{
status = "Saving Cache";
logger.Info(status);
patchLogger.Info(status);
CreateCache(databaseConfigs, progress.Counter.patchedNodes);
}

Expand All @@ -182,12 +229,35 @@ public IEnumerable<IProtoUrlConfig> Run()

SaveModdedTechTree();
SaveModdedPhysics();

logThreadExitFlag = true;

while (loggingThreadStatus.IsRunning)
{
System.Threading.Thread.Sleep(100);
}

if (loggingThreadStatus.IsExitedWithError)
{
logger.Error("The patching thread threw an exception");
throw loggingThreadStatus.Exception;
}
}
else
{
status = "Loading from Cache";
logger.Info(status);
databaseConfigs = LoadCache();

if (File.Exists(patchLogPath))
{
logger.Info("Dumping patch log");
logger.Info("\n#### BEGIN PATCH LOG ####\n\n\n" + File.ReadAllText(patchLogPath) + "\n\n\n#### END PATCH LOG ####");
}
else
{
logger.Error("Patch log does not exist: " + patchLogPath);
}
}

logger.Info(status + "\n" + errors);
Expand Down

0 comments on commit 7145003

Please sign in to comment.