@@ -0,0 +1,88 @@ | |||
using System; | |||
using System.Reflection; | |||
using HarmonyLib; | |||
namespace CLre.API.App | |||
{ | |||
public static class Client | |||
{ | |||
public static event EventHandler<SetupEventArgs> InitStart | |||
{ | |||
add => FrontEnd_SetupContainer_Patch.preSetup += value; | |||
remove => FrontEnd_SetupContainer_Patch.preSetup -= value; | |||
} | |||
public static event EventHandler<SetupEventArgs> LogInitComplete | |||
{ | |||
add => FrontEnd_SetupContainer_Patch.postSyncSetup += value; | |||
remove => FrontEnd_SetupContainer_Patch.postSyncSetup -= value; | |||
} | |||
public static event EventHandler<SetupEventArgs> AsynchronousInitComplete | |||
{ | |||
add => FrontEndGuiEngine_SetMainMenuEnabled_Patch.preMenuEnabled += value; | |||
remove => FrontEndGuiEngine_SetMainMenuEnabled_Patch.preMenuEnabled -= value; | |||
} | |||
public static event EventHandler<SetupEventArgs> InitComplete | |||
{ | |||
add => FrontEndGuiEngine_SetMainMenuEnabled_Patch.postMenuEnabled += value; | |||
remove => FrontEndGuiEngine_SetMainMenuEnabled_Patch.postMenuEnabled -= value; | |||
} | |||
public static string Version | |||
{ | |||
get => Game.Utilities.VersionReader.GetVersion(); | |||
} | |||
} | |||
public struct SetupEventArgs {} | |||
[HarmonyPatch(typeof(FrontEnd.MainFrontEnd), "SetupContainer")] | |||
class FrontEnd_SetupContainer_Patch | |||
{ | |||
internal static event EventHandler<SetupEventArgs> postSyncSetup; | |||
internal static event EventHandler<SetupEventArgs> preSetup; | |||
[HarmonyPrefix] | |||
public static void BeforeMethodCall(FrontEnd.MainFrontEnd __instance) | |||
{ | |||
if (preSetup != null) preSetup(__instance, new SetupEventArgs { }); | |||
} | |||
[HarmonyPostfix] | |||
public static void AfterMethodCall(FrontEnd.MainFrontEnd __instance) | |||
{ | |||
if (postSyncSetup != null) postSyncSetup(__instance, new SetupEventArgs { }); | |||
} | |||
} | |||
[HarmonyPatch] | |||
class FrontEndGuiEngine_SetMainMenuEnabled_Patch | |||
{ | |||
internal static event EventHandler<SetupEventArgs> preMenuEnabled; | |||
internal static event EventHandler<SetupEventArgs> postMenuEnabled; | |||
[HarmonyPrefix] | |||
public static void BeforeMethodCall(object __instance, bool enabled) | |||
{ | |||
if (!enabled) return; | |||
if (preMenuEnabled != null) preMenuEnabled(__instance, new SetupEventArgs { }); | |||
} | |||
[HarmonyPostfix] | |||
public static void AfterMethodCall(object __instance, bool enabled) | |||
{ | |||
if (!enabled) return; | |||
if (postMenuEnabled != null) postMenuEnabled(__instance, new SetupEventArgs { }); | |||
} | |||
[HarmonyTargetMethod] | |||
public static MethodBase ReflectToGetMethodBase() | |||
{ | |||
return AccessTools.Method("FrontEnd.FrontEndGuiEngine:SetMainMenuEnabled"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,144 @@ | |||
using HarmonyLib; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS; | |||
namespace CLre.API.Engines | |||
{ | |||
/// <summary> | |||
/// Engine to be registered before vanilla engines are built. | |||
/// This should be called by any other constructor because this alerts CLre of its existence. | |||
/// </summary> | |||
public abstract class FrontEndEnginePreBuild : ICLreEngine | |||
{ | |||
/// <summary> | |||
/// Construct a new instance of a FrontEndEngine. | |||
/// This should be called by any other constructor because this alerts CLre of its existence. | |||
/// </summary> | |||
public FrontEndEnginePreBuild() | |||
{ | |||
MainFrontEnd_BuildEngines_Patch.beforeBuildEngines.Add(this); | |||
} | |||
public abstract void Ready(); | |||
public abstract IEntitiesDB entitiesDB { get; set; } | |||
public abstract IEntityFactory entityFactory { get; set; } | |||
} | |||
/// <summary> | |||
/// Engine to be registered before obsolete vanilla engines are built. | |||
/// This should be called by any other constructor because this alerts CLre of its existence. | |||
/// </summary> | |||
public abstract class FrontEndObsoleteEnginePreBuild : ICLreEngine | |||
{ | |||
/// <summary> | |||
/// Construct a new instance of a FrontEndEngine. | |||
/// This should be called by any other constructor because this alerts CLre of its existence. | |||
/// </summary> | |||
public FrontEndObsoleteEnginePreBuild() | |||
{ | |||
MainFrontEnd_BuildObsoleteEngines_Patch.beforeBuildEngines.Add(this); | |||
} | |||
public abstract void Ready(); | |||
public abstract IEntitiesDB entitiesDB { get; set; } | |||
public abstract IEntityFactory entityFactory { get; set; } | |||
} | |||
/// <summary> | |||
/// Engine to be registered after vanilla engines are built. | |||
/// </summary> | |||
public abstract class FrontEndEnginePostBuild : ICLreEngine | |||
{ | |||
/// <summary> | |||
/// Construct a new instance of a FrontEndEngine. | |||
/// This should be called by any other constructor because this alerts CLre of its existence. | |||
/// </summary> | |||
public FrontEndEnginePostBuild() | |||
{ | |||
MainFrontEnd_BuildEngines_Patch.afterBuildEngines.Add(this); | |||
} | |||
public abstract void Ready(); | |||
public abstract IEntitiesDB entitiesDB { get; set; } | |||
public abstract IEntityFactory entityFactory { get; set; } | |||
} | |||
/// <summary> | |||
/// Engine to be registered after vanilla obsolete engines are built. | |||
/// </summary> | |||
public abstract class FrontEndObsoleteEnginePostBuild : ICLreEngine | |||
{ | |||
/// <summary> | |||
/// Construct a new instance of a FrontEndEngine. | |||
/// This should be called by any other constructor because this alerts CLre of its existence. | |||
/// </summary> | |||
public FrontEndObsoleteEnginePostBuild() | |||
{ | |||
MainFrontEnd_BuildObsoleteEngines_Patch.afterBuildEngines.Add(this); | |||
} | |||
public abstract void Ready(); | |||
public abstract IEntitiesDB entitiesDB { get; set; } | |||
public abstract IEntityFactory entityFactory { get; set; } | |||
} | |||
[HarmonyPatch(typeof(FrontEnd.MainFrontEnd), "BuildEngines")] | |||
class MainFrontEnd_BuildEngines_Patch | |||
{ | |||
internal static FasterList<FrontEndEnginePreBuild> beforeBuildEngines = new FasterList<FrontEndEnginePreBuild>(); | |||
internal static FasterList<FrontEndEnginePostBuild> afterBuildEngines = new FasterList<FrontEndEnginePostBuild>(); | |||
[HarmonyPrefix] | |||
public static void BeforeMethodCall(FrontEnd.MainFrontEnd __instance) | |||
{ | |||
IEntityFactory factory = AccessTools.Field(typeof(FrontEnd.MainFrontEnd), "_entityFactory").GetValue(__instance) as IEntityFactory; | |||
foreach (ICLreEngine e in beforeBuildEngines) | |||
{ | |||
e.entityFactory = factory; | |||
__instance.AddEngine(e); | |||
} | |||
} | |||
[HarmonyPostfix] | |||
public static void AfterMethodCall(FrontEnd.MainFrontEnd __instance) | |||
{ | |||
IEntityFactory factory = AccessTools.Field(typeof(FrontEnd.MainFrontEnd), "_entityFactory").GetValue(__instance) as IEntityFactory; | |||
foreach (ICLreEngine e in afterBuildEngines) | |||
{ | |||
e.entityFactory = factory; | |||
__instance.AddEngine(e); | |||
} | |||
} | |||
} | |||
[HarmonyPatch(typeof(FrontEnd.MainFrontEnd), "BuildObsoleteEngines")] | |||
class MainFrontEnd_BuildObsoleteEngines_Patch | |||
{ | |||
internal static FasterList<FrontEndObsoleteEnginePreBuild> beforeBuildEngines = new FasterList<FrontEndObsoleteEnginePreBuild>(); | |||
internal static FasterList<FrontEndObsoleteEnginePostBuild> afterBuildEngines = new FasterList<FrontEndObsoleteEnginePostBuild>(); | |||
[HarmonyPrefix] | |||
public static void BeforeMethodCall(FrontEnd.MainFrontEnd __instance) | |||
{ | |||
IEntityFactory factory = AccessTools.Field(typeof(FrontEnd.MainFrontEnd), "_entityFactory").GetValue(__instance) as IEntityFactory; | |||
foreach (ICLreEngine e in beforeBuildEngines) | |||
{ | |||
e.entityFactory = factory; | |||
__instance.AddEngine(e); | |||
} | |||
} | |||
[HarmonyPostfix] | |||
public static void AfterMethodCall(FrontEnd.MainFrontEnd __instance) | |||
{ | |||
IEntityFactory factory = AccessTools.Field(typeof(FrontEnd.MainFrontEnd), "_entityFactory").GetValue(__instance) as IEntityFactory; | |||
foreach (ICLreEngine e in afterBuildEngines) | |||
{ | |||
e.entityFactory = factory; | |||
__instance.AddEngine(e); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
using HarmonyLib; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS; | |||
namespace CLre.API.Engines | |||
{ | |||
public abstract class GameObsoleteEnginePreBuild : ICLreEngine | |||
{ | |||
public GameObsoleteEnginePreBuild() | |||
{ | |||
MainLevel_BuildDeprecatedEngines_Patch.beforeBuildEngines.Add(this); | |||
} | |||
public abstract void Ready(); | |||
public abstract IEntitiesDB entitiesDB { get; set; } | |||
public abstract IEntityFactory entityFactory { get; set; } | |||
} | |||
public abstract class GameObsoleteEnginePostBuild : ICLreEngine | |||
{ | |||
public GameObsoleteEnginePostBuild() | |||
{ | |||
MainLevel_BuildDeprecatedEngines_Patch.afterBuildEngines.Add(this); | |||
} | |||
public abstract void Ready(); | |||
public abstract IEntitiesDB entitiesDB { get; set; } | |||
public abstract IEntityFactory entityFactory { get; set; } | |||
} | |||
[HarmonyPatch(typeof(GameFramework.MainLevel), "BuildDeprecatedEngines")] | |||
class MainLevel_BuildDeprecatedEngines_Patch | |||
{ | |||
internal static FasterList<GameObsoleteEnginePreBuild> beforeBuildEngines = new FasterList<GameObsoleteEnginePreBuild>(); | |||
internal static FasterList<GameObsoleteEnginePostBuild> afterBuildEngines = new FasterList<GameObsoleteEnginePostBuild>(); | |||
[HarmonyPrefix] | |||
public static void BeforeMethodCall(GameFramework.MainLevel __instance) | |||
{ | |||
IEntityFactory factory = AccessTools.Field(typeof(GameFramework.MainLevel), "_entityFactory").GetValue(__instance) as IEntityFactory; | |||
foreach (ICLreEngine e in beforeBuildEngines) | |||
{ | |||
e.entityFactory = factory; | |||
__instance.AddEngine(e); | |||
} | |||
} | |||
[HarmonyPostfix] | |||
public static void AfterMethodCall(GameFramework.MainLevel __instance) | |||
{ | |||
IEntityFactory factory = AccessTools.Field(typeof(GameFramework.MainLevel), "_entityFactory").GetValue(__instance) as IEntityFactory; | |||
foreach (ICLreEngine e in afterBuildEngines) | |||
{ | |||
e.entityFactory = factory; | |||
__instance.AddEngine(e); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
using Svelto.ECS; | |||
namespace CLre.API.Engines | |||
{ | |||
public interface ICLreEngine : IQueryingEntitiesEngine | |||
{ | |||
IEntityFactory entityFactory { get; set; } | |||
} | |||
} |
@@ -0,0 +1,100 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using System.Diagnostics; | |||
namespace CLre.API.Utility | |||
{ | |||
/// <summary> | |||
/// Utility class to access Cardlife's built-in logging capabilities. | |||
/// The log is saved to outputLog#.Log | |||
/// </summary> | |||
public static class Logging | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void Log(string msg) | |||
{ | |||
Svelto.Console.Log(msg); | |||
} | |||
/// <summary> | |||
/// Write a regular message to Cardlife's log | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void Log(object obj) | |||
{ | |||
Svelto.Console.Log(obj.ToString()); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogError(string msg, Dictionary<string, string> extraData = null) | |||
{ | |||
Svelto.Console.LogError(msg, extraData); | |||
} | |||
/// <summary> | |||
/// Write an error message to Cardlife's log | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
/// <param name="extraData">The extra data to pass to the ILogger</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogError(object obj, Dictionary<string, string> extraData = null) | |||
{ | |||
Svelto.Console.LogError(obj.ToString(), extraData); | |||
} | |||
/// <summary> | |||
/// Write an exception to Cardlife's log and to the screen and exit game | |||
/// </summary> | |||
/// <param name="e">The exception to log</param> | |||
/// <param name="extraData">The extra data to pass to the ILogger. | |||
/// This is automatically populated with "OuterException#" and "OuterStacktrace#" entries</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogException(Exception e, string msg = null, Dictionary<string, string> extraData = null) | |||
{ | |||
Svelto.Console.LogException(msg, e, extraData); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogWarning(string msg) | |||
{ | |||
Svelto.Console.LogWarning(msg); | |||
} | |||
/// <summary> | |||
/// Write a warning message to Cardlife's log | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogWarning(object obj) | |||
{ | |||
Svelto.Console.LogWarning(obj.ToString()); | |||
} | |||
// descriptive logging | |||
/// <summary> | |||
/// Write a descriptive message to Cardlife's log only when the API is a Debug build | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void MetaDebugLog(object obj) | |||
{ | |||
#if DEBUG | |||
MetaLog($"[MetaDebug]{obj.ToString()}"); | |||
#endif | |||
} | |||
/// <summary> | |||
/// Write a descriptive message to Cardlife's log including the calling method's name | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void MetaLog(object obj) | |||
{ | |||
var method = (new StackTrace()).GetFrame(1).GetMethod(); | |||
Log($"[{method.DeclaringType.FullName}.{method.Name}] {obj.ToString()}"); | |||
} | |||
} | |||
} |
@@ -3,9 +3,12 @@ using System.Reflection; | |||
using IllusionPlugin; | |||
namespace HelloModdingWorld | |||
using CLre.API.Utility; | |||
using Logging = CLre.API.Utility.Logging; | |||
namespace CLre | |||
{ | |||
public class MyPlugin : IEnhancedPlugin // the Illusion Plugin Architecture (IPA) will ignore classes that don't implement IPlugin' | |||
public class CLre : IEnhancedPlugin // the Illusion Plugin Architecture (IPA) will ignore classes that don't implement IPlugin' | |||
{ | |||
public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; | |||
@@ -19,7 +22,7 @@ namespace HelloModdingWorld | |||
// called when Cardlife starts up | |||
public override void OnApplicationStart() | |||
{ | |||
File.WriteAllText(Name + ".log", "CLre was loaded and started up"); | |||
Logging.MetaLog($"{Name} has been loaded."); | |||
} | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
namespace CLre.Fixes | |||
{ | |||
public class EnchantmentTableFloatParseFix | |||
{ | |||
} | |||
} |