Skip to content

Commit

Permalink
Merge pull request #1 from brianries/progress_panel_addition
Browse files Browse the repository at this point in the history
Progress panel addition
  • Loading branch information
janxious authored Aug 8, 2018
2 parents f3d96e0 + 49a6f6a commit 79f19ff
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 34 deletions.
114 changes: 87 additions & 27 deletions ModTek/ModTek.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
Expand All @@ -17,11 +18,13 @@
// ReSharper disable FieldCanBeMadeReadOnly.Local

namespace ModTek
{
{
using static Logger;

public static class ModTek
{
public static VersionManifest cachedManifest = null;

private static bool hasLoadedMods; //defaults to false

// file/directory names
Expand Down Expand Up @@ -123,9 +126,21 @@ public static void Init()
jsonMergeCache = LoadOrCreateMergeCache(MergeCachePath);
typeCache = LoadOrCreateTypeCache(TypeCachePath);

// init harmony and patch the stuff that comes with ModTek (contained in Patches.cs)
var harmony = HarmonyInstance.Create("io.github.mpstark.ModTek");
harmony.PatchAll(Assembly.GetExecutingAssembly());
// First step in setting up the progress panel
if (ProgressPanel.Initialize(ModDirectory, $"ModTek v{Assembly.GetExecutingAssembly().GetName().Version}"))
{
// init harmony and patch the stuff that comes with ModTek (contained in Patches.cs)
var harmony = HarmonyInstance.Create("io.github.mpstark.ModTek");
harmony.PatchAll(Assembly.GetExecutingAssembly());

LoadMods();

BuildCachedManifest();
}
else
{
Log("Failed to load progress bar. Skipping mod loading completely.");
}

stopwatch.Stop();
}
Expand Down Expand Up @@ -329,13 +344,24 @@ private static void LoadMod(ModDef modDef)

internal static void LoadMods()
{
ProgressPanel.SubmitWork(ModTek.LoadMoadsLoop);
}

internal static IEnumerator<ProgressReport> LoadMoadsLoop()
{
// Only want to run this function once -- it could get submitted a few times
if (hasLoadedMods)
return;
{
yield break;
}

stopwatch.Start();

string sliderText = "Loading Mods";

Log("");
LogWithDate("Pre-loading mods...");
yield return new ProgressReport(0, sliderText, "Pre-loading mods...");

// find all sub-directories that have a mod.json file
var modDirectories = Directory.GetDirectories(ModDirectory)
Expand All @@ -345,7 +371,7 @@ internal static void LoadMods()
{
hasLoadedMods = true;
Log("No ModTek-compatable mods found.");
return;
yield break;
}

// create ModDef objects for each mod.json file
Expand Down Expand Up @@ -384,10 +410,12 @@ internal static void LoadMods()
PropagateConflictsForward(modDefs);
modLoadOrder = GetLoadOrder(modDefs, out var willNotLoad);

int modLoaded = 0;
// lists guarentee order
foreach (var modName in modLoadOrder)
{
var modDef = modDefs[modName];
yield return new ProgressReport((float)modLoaded++/(float)modLoadOrder.Count, sliderText, string.Format("Loading Mod: {0}", modDef.Name));

try
{
Expand Down Expand Up @@ -417,6 +445,8 @@ internal static void LoadMods()
File.WriteAllText(LoadOrderPath, JsonConvert.SerializeObject(modLoadOrder, Formatting.Indented));

hasLoadedMods = true;

yield break;
}

private static string InferIDFromFile(string path)
Expand Down Expand Up @@ -686,41 +716,47 @@ private static bool AddModEntryToDB(MetadataDatabase db, string path, string typ
return false;
}

internal static void AddModEntries(VersionManifest manifest)
internal static void BuildCachedManifest()
{
if (!hasLoadedMods)
LoadMods();
// First load the default battletech manifest, then it'll get appended to
VersionManifest vanillaManifest = VersionManifestUtilities.LoadDefaultManifest();

// Wrapper to be able to submit a parameterless work function
IEnumerator<ProgressReport> NestedFunc()
{
IEnumerator<ProgressReport> reports = BuildCachedManifestLoop(vanillaManifest);
while (reports.MoveNext())
{
yield return reports.Current;
}
}

ProgressPanel.SubmitWork(NestedFunc);
}


internal static IEnumerator<ProgressReport> BuildCachedManifestLoop(VersionManifest manifest) {

stopwatch.Start();

// there are no mods loaded, just return
if (modLoadOrder == null || modLoadOrder.Count == 0)
return;
yield break;

if (modEntries != null)
{
LogWithDate("Loading another manifest with already setup mod manifests.");
foreach (var modEntry in modEntries)
{
AddModEntry(manifest, modEntry);
}

stopwatch.Stop();
Log("");
LogWithDate($"Done. Elapsed running time: {stopwatch.Elapsed.TotalSeconds} seconds\n");
return;
}
string loadingModText = "Loading Mod Manifests";
yield return new ProgressReport(0.0f, loadingModText, "Setting up mod manifests...");

LogWithDate("Setting up mod manifests...");

var jsonMerges = new Dictionary<string, List<string>>();
modEntries = new List<ModDef.ManifestEntry>();
foreach (var modName in modLoadOrder)
{
if (!modManifest.ContainsKey(modName))
continue;
int modCount = 0;

var manifestMods = modLoadOrder.Where(name => modManifest.ContainsKey(name)).ToList();
foreach (var modName in manifestMods)
{
Log($"\t{modName}:");
yield return new ProgressReport((float)modCount++/(float)manifestMods.Count, loadingModText, string.Format("Loading manifest for {0}", modName));
foreach (var modEntry in modManifest[modName])
{
// type being null means we have to figure out the type from the path (StreamingAssets)
Expand Down Expand Up @@ -840,13 +876,18 @@ internal static void AddModEntries(VersionManifest manifest)
}
}

yield return new ProgressReport(100.0f, "JSON", "Writing JSON file to disk");

// write type cache to disk
WriteJsonFile(TypeCachePath, typeCache);

// perform merges into cache
LogWithDate("Doing merges...");
yield return new ProgressReport(0.0f, "Merges", "Doing Merges...");
int mergeCount = 0;
foreach (var jsonMerge in jsonMerges)
{
yield return new ProgressReport((float)mergeCount++/jsonMerges.Count, "Merges", string.Format("Merging {0}", jsonMerge.Key));
var cachePath = jsonMergeCache.GetOrCreateCachedEntry(jsonMerge.Key, jsonMerge.Value);

// something went wrong (the parent json prob had errors)
Expand All @@ -863,6 +904,8 @@ internal static void AddModEntries(VersionManifest manifest)
modEntries.Add(cacheEntry);
}

yield return new ProgressReport(100.0f, "Merge Cache", "Writing Merge Cache to disk");

// write merge cache to disk
jsonMergeCache.WriteCacheToDisk(Path.Combine(CacheDirectory, MERGE_CACHE_FILE_NAME));

Expand All @@ -872,6 +915,9 @@ internal static void AddModEntries(VersionManifest manifest)
var rebuildDB = false;
var replacementEntries = new List<VersionManifestEntry>();
var removeEntries = new List<string>();

string dbText = "Syncing Database";
yield return new ProgressReport(0.0f, dbText, "");
foreach (var kvp in dbCache)
{
var path = kvp.Key;
Expand All @@ -897,6 +943,8 @@ internal static void AddModEntries(VersionManifest manifest)
}

// add removed entries replacements to db
dbText = "Cleaning Database";
yield return new ProgressReport(100.0f, dbText, "");
if (!rebuildDB)
{
// remove old entries
Expand Down Expand Up @@ -924,12 +972,19 @@ internal static void AddModEntries(VersionManifest manifest)
}

// add needed files to db
dbText = "Populating Database";
int addCount = 0;
yield return new ProgressReport(0.0f, dbText, "");
using (var metadataDatabase = new MetadataDatabase())
{
foreach (var modEntry in modEntries)
{
if (modEntry.AddToDB && AddModEntryToDB(metadataDatabase, modEntry.Path, modEntry.Type))
{
yield return new ProgressReport((float)addCount / (float)modEntries.Count, dbText, string.Format("Added {0}", modEntry.Path));
Log($"\tAdded/Updated {modEntry.Id} ({modEntry.Type})");
}
addCount++;
}
}

Expand All @@ -939,6 +994,11 @@ internal static void AddModEntries(VersionManifest manifest)
stopwatch.Stop();
Log("");
LogWithDate($"Done. Elapsed running time: {stopwatch.Elapsed.TotalSeconds} seconds\n");

// Cache the completed manifest
ModTek.cachedManifest = manifest;

yield break;
}
}
}
4 changes: 4 additions & 0 deletions ModTek/ModTek.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
<HintPath>$(BattleTechGame)\BattleTech_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(BattleTechGame)\BattleTech_Data\Managed\UnityEngine.UI.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="IManifestEntry.cs" />
Expand All @@ -75,6 +78,7 @@
<Compile Include="ModDef.cs" />
<Compile Include="ModTek.cs" />
<Compile Include="Patches.cs" />
<Compile Include="ProgressPanel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
38 changes: 32 additions & 6 deletions ModTek/Patches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,44 @@ public static void Prefix(ref string fileID)
[HarmonyPatch(typeof(VersionManifestUtilities), "LoadDefaultManifest")]
public static class VersionManifestUtilities_LoadDefaultManifest_Patch
{
public static void Postfix(VersionManifest __result)
public static bool Prefix(ref VersionManifest __result)
{
ModTek.AddModEntries(__result);
// Return the cached manifest if it exists -- otherwise call the method as normal
if (ModTek.cachedManifest != null)
{
__result = ModTek.cachedManifest;
return false;
}
else
{
return true;
}
}
}

[HarmonyPatch(typeof(DataManager), new[] { typeof(MessageCenter) })]
public static class DataManager_CTOR_Patch
// This will disable activateAfterInit from functioning for the Start() on the "Main" game object which activates the BattleTechGame object
// This stops the main game object from loading immediately -- so work can be done beforehand
[HarmonyPatch(typeof(ActivateAfterInit), "Start")]
public static class ActivateAfterInit_Start_Patch
{
public static void Prefix()
public static bool Prefix(ActivateAfterInit __instance)
{
ModTek.LoadMods();
Traverse trav = Traverse.Create(__instance);
if (ActivateAfterInit.ActivateAfter.Start.Equals(trav.Field("activateAfter").GetValue<ActivateAfterInit.ActivateAfter>()))
{
GameObject[] gameObjects = trav.Field("activationSet").GetValue<GameObject[]>();
foreach (var gameObject in gameObjects)
{
if ("BattleTechGame".Equals(gameObject.name))
{
// Don't activate through this call!
return false;
}
}
}
// Call the method
return true;
}
}
}

Loading

0 comments on commit 79f19ff

Please sign in to comment.