Skip to content
Permalink
Browse files

Much more robust mod loading

  • Loading branch information...
pipe01 committed Jan 22, 2018
1 parent 870b85f commit 7a617af4dedc46b42191a47d3641805547050309
Showing with 116 additions and 84 deletions.
  1. +1 −63 .gitattributes
  2. +59 −14 Bootstrapper.cs
  3. +29 −2 Mod.cs
  4. +24 −2 ModLoader.cs
  5. +2 −2 PiTung Bootstrap Tests/ModLoaderTest.cs
  6. +1 −1 Properties/AssemblyInfo.cs
@@ -1,63 +1 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary

###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
*.csproj filter=gitignore
@@ -1,4 +1,5 @@
using Harmony;
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -22,44 +23,88 @@ public void Patch()
ModCount = 0;

MDebug.WriteLine("PiTUNG Framework version {0}", 0, PiTung.FrameworkVersion);
MDebug.WriteLine("Booting up...");
MDebug.WriteLine("-------------Patching-------------");

var harmony = HarmonyInstance.Create("me.pipe01.pitung");
harmony.PatchAll(Assembly.GetExecutingAssembly());

foreach (var mod in ModLoader.GetMods())
{
string modStr = $"Mod \"{mod.FullName}\"";

if (mod.ModAssembly == null)
{
MDebug.WriteLine($"[ERROR] Mod '{mod.ModName}' failed to load: couldn't load assembly.");
MDebug.WriteLine($"[ERROR] {modStr} failed to load: couldn't load assembly.");
continue;
}

mod.BeforePatch();

harmony.PatchAll(mod.ModAssembly);

foreach (var patch in mod.GetMethodPatches())
if (mod.FrameworkVersion != PiTung.FrameworkVersion)
{
if (patch.Prefix)
if (mod.RequireFrameworkVersion)
{
harmony.Patch(patch.BaseMethod, new HarmonyMethod(patch.PatchMethod), null);
MDebug.WriteLine($"[ERROR] {modStr} failed to load: wrong PiTUNG version.");
continue;
}
else if (patch.Postfix)
else
{
harmony.Patch(patch.BaseMethod, null, new HarmonyMethod(patch.PatchMethod));
MDebug.WriteLine($"[WARNING] {modStr} may not work properly: wrong PiTUNG version");
}
}

mod.AfterPatch();
try
{
mod.BeforePatch();
}
catch (Exception ex)
{
MDebug.WriteLine($"[ERROR] {modStr} failed to load: error while executing before-patch method.");
MDebug.WriteLine("More details: " + ex.Message, 1);

continue;
}

try
{
harmony.PatchAll(mod.ModAssembly);

foreach (var patch in mod.GetMethodPatches())
{
if (patch.Prefix)
{
harmony.Patch(patch.BaseMethod, new HarmonyMethod(patch.PatchMethod), null);
}
else if (patch.Postfix)
{
harmony.Patch(patch.BaseMethod, null, new HarmonyMethod(patch.PatchMethod));
}
}
}
catch (Exception ex)
{
MDebug.WriteLine($"[ERROR] {modStr} failed to load: error while patching methods.");
MDebug.WriteLine("More details: " + ex.Message, 1);
continue;
}

try
{
mod.AfterPatch();
}
catch (Exception ex)
{
MDebug.WriteLine($"[ERROR] {modStr} failed to load: error while executing after-patch method.");
MDebug.WriteLine("More details: " + ex.Message, 1);

continue;
}

ModCount++;
MDebug.WriteLine($"'{mod.ModName}' loaded successfully.");
MDebug.WriteLine($"'{mod.FullName}' loaded successfully.");
}

SceneManager.activeSceneChanged += SceneManager_activeSceneChanged;

MDebug.WriteLine("Patched successfully!");
MDebug.WriteLine("----------Done patching!----------");
}

/// <summary>
31 Mod.cs
@@ -29,11 +29,38 @@ protected Mod()
/// </summary>
public string FullPath { get; internal set; }

public abstract string ModName { get; }
public abstract string ModAuthor { get; }
/// <summary>
/// The mod's name.
/// </summary>
public abstract string Name { get; }

/// <summary>
/// Your name.
/// </summary>
public abstract string Author { get; }

/// <summary>
/// The mod's version.
/// </summary>
public abstract Version ModVersion { get; }

/// <summary>
/// The version of PiTUNG this mod is using.
/// </summary>
public abstract Version FrameworkVersion { get; }


/// <summary>
/// If false, the mod will be loaded even when being loaded in a different framework version.
/// </summary>
public bool RequireFrameworkVersion { get; } = true;

/// <summary>
/// The mod's full name. Format: {Author}'s {Name} v{ModVersion}
/// </summary>
public string FullName => $"{Author}'s {Name} v{ModVersion}";


/// <summary>
/// The keys the mod will be notified about. You can alternatively use the <see cref="Mod.SubscribeToKey(KeyCode)"/> and <see cref="Mod.SubscribeToKeys(KeyCode[])"/> methods.
/// </summary>
@@ -23,7 +23,20 @@ public static IEnumerable<Mod> GetMods()
if (Path.GetFileNameWithoutExtension(item).EndsWith("-disabled"))
continue;

yield return GetMod(item);
Mod mod = null;

try
{
mod = GetMod(item);
}
catch (ReflectionTypeLoadException ex)
{
MDebug.WriteLine($"[ERROR] Mod {Path.GetFileName(item)} failed to load.");
MDebug.WriteLine("More details: " + ex.Message, 2);
}

if (mod != null)
yield return mod;
}
}

@@ -34,8 +47,17 @@ public static IEnumerable<Mod> GetMods()
/// <returns>A mod.</returns>
private static Mod GetMod(string modPath)
{
var ass = Assembly.LoadFrom(modPath);
Assembly ass;

try
{
ass = Assembly.LoadFrom(modPath);
}
catch (ReflectionTypeLoadException)
{
throw;
}

Mod mod = null;

foreach (var item in ass.GetExportedTypes())
@@ -20,8 +20,8 @@ public void CheckIfAllModsAreLoaded()
var mod = mods.First();

Assert.IsNotNull(mod.ModAssembly);
Assert.IsNotNull(mod.ModName);
Assert.IsNotNull(mod.ModAuthor);
Assert.IsNotNull(mod.Name);
Assert.IsNotNull(mod.Author);
Assert.IsNotNull(mod.ModVersion);
}
}
@@ -32,7 +32,7 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.*")]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

[assembly: InternalsVisibleTo("PiTung Bootstrap Tests")]

0 comments on commit 7a617af

Please sign in to comment.
You can’t perform that action at this time.