Create minimal API endpoints from explored/understood code

This commit is contained in:
NGnius (Graham) 2020-12-02 11:56:50 -05:00
parent 0f5555ab4c
commit 05e196b4c1
7 changed files with 414 additions and 3 deletions

88
CLre/API/App/Client.cs Normal file
View file

@ -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");
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -0,0 +1,9 @@
using Svelto.ECS;
namespace CLre.API.Engines
{
public interface ICLreEngine : IQueryingEntitiesEngine
{
IEntityFactory entityFactory { get; set; }
}
}

100
CLre/API/Utility/Logging.cs Normal file
View file

@ -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()}");
}
}
}

View file

@ -3,9 +3,12 @@ using System.Reflection;
using IllusionPlugin; 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; public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
@ -19,7 +22,7 @@ namespace HelloModdingWorld
// called when Cardlife starts up // called when Cardlife starts up
public override void OnApplicationStart() public override void OnApplicationStart()
{ {
File.WriteAllText(Name + ".log", "CLre was loaded and started up"); Logging.MetaLog($"{Name} has been loaded.");
} }
} }
} }

View file

@ -0,0 +1,7 @@
namespace CLre.Fixes
{
public class EnchantmentTableFloatParseFix
{
}
}