@@ -0,0 +1,34 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Reflection; | |||
using Harmony; | |||
using Svelto.Context; | |||
using Svelto.ECS; | |||
using RobocraftX; | |||
using RobocraftX.Multiplayer; | |||
using Unity.Entities; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Commands | |||
{ | |||
[HarmonyPatch] | |||
class CommandPatch | |||
{ | |||
public static void Prefix(UnityContext<FullGameCompositionRoot> contextHolder, EnginesRoot enginesRoot, World physicsWorld, Action reloadGame, MultiplayerInitParameters multiplayerParameters) | |||
{ | |||
Logging.Log("Command Line was loaded"); | |||
// When a game is loaded, register the command engines | |||
// TODO | |||
} | |||
public static MethodBase TargetMethod(HarmonyInstance instance) | |||
{ | |||
var func = (Action<UnityContext<FullGameCompositionRoot>, EnginesRoot, World, Action, MultiplayerInitParameters>)RobocraftX.GUI.CommandLine.CommandLineCompositionRoot.Compose<UnityContext<FullGameCompositionRoot>>; | |||
return func.Method; | |||
} | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Commands | |||
{ | |||
interface ICustomCommandEngine : IEngine, IQueryingEntitiesEngine | |||
{ | |||
string Name { get; } | |||
string Description { get; } | |||
void ExecuteCommand(); | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
public enum EventType | |||
{ | |||
ApplicationInitialized, | |||
MenuActivated, | |||
MenuDestroyed, | |||
MenuSwitchedTo, | |||
GameActivated, | |||
GameDestroyed, | |||
GameReloaded, | |||
GameSwitchedTo | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Harmony; | |||
using RobocraftX; | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
[HarmonyPatch(typeof(FullGameCompositionRoot), "ActivateMenu")] | |||
class GameInitPatch | |||
{ | |||
private static bool firstLoad = true; | |||
public static void Postfix(ref EnginesRoot ____frontEndEnginesRoot) | |||
{ | |||
// A new EnginesRoot is always created when ActivateMenu is called | |||
// so all event emitters and handlers must be re-registered. | |||
Manager.RegisterEngines(____frontEndEnginesRoot); | |||
if (firstLoad) | |||
{ | |||
firstLoad = false; | |||
Logging.Log("Dispatching App Init event"); | |||
Manager.GetEventEmitter("GamecraftModdingAPIApplicationInitializedEventEmitter").Emit(); | |||
} | |||
Logging.Log("Dispatching Menu Activated event"); | |||
Manager.GetEventEmitter("GamecraftModdingAPIMenuActivatedEventEmitter").Emit(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
public interface IEventEmitterEngine : IEngine, IQueryingEntitiesEngine | |||
{ | |||
string Name { get; } | |||
object type { get; } | |||
IEntityFactory Factory { set; } | |||
void Emit(); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Internal; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
public interface IEventHandlerEngine : IEngine, IQueryingEntitiesEngine, IReactOnAddAndRemove<ModEventEntityStruct>, IReactOnAddAndRemove | |||
{ | |||
string Name { get; } | |||
} | |||
} |
@@ -0,0 +1,100 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
/// <summary> | |||
/// Keeps track of event handlers and emitters. | |||
/// This class can be used to add, remove and get event handlers and emitters. | |||
/// </summary> | |||
public static class Manager | |||
{ | |||
private static Dictionary<string, IEventEmitterEngine> _eventEmitters = new Dictionary<string, IEventEmitterEngine>(); | |||
private static Dictionary<string, IEventHandlerEngine> _eventHandlers = new Dictionary<string, IEventHandlerEngine>(); | |||
// event handler management | |||
public static void AddEventHandler(IEventHandlerEngine engine) | |||
{ | |||
_eventHandlers[engine.Name] = engine; | |||
} | |||
public static bool ExistsEventHandler(string name) | |||
{ | |||
return _eventHandlers.ContainsKey(name); | |||
} | |||
public static bool ExistsEventHandler(IEventHandlerEngine engine) | |||
{ | |||
return ExistsEventHandler(engine.Name); | |||
} | |||
public static IEventHandlerEngine GetEventHandler(string name) | |||
{ | |||
return _eventHandlers[name]; | |||
} | |||
public static Dictionary<string, IEventHandlerEngine> GetEventHandlers() | |||
{ | |||
return _eventHandlers; | |||
} | |||
public static void RemoveEventHandler(string name) | |||
{ | |||
_eventHandlers.Remove(name); | |||
} | |||
// event emitter management | |||
public static void AddEventEmitter(IEventEmitterEngine engine) | |||
{ | |||
_eventEmitters[engine.Name] = engine; | |||
} | |||
public static bool ExistsEventEmitter(string name) | |||
{ | |||
return _eventEmitters.ContainsKey(name); | |||
} | |||
public static bool ExistsEventEmitter(IEventEmitterEngine engine) | |||
{ | |||
return ExistsEventEmitter(engine.Name); | |||
} | |||
public static IEventEmitterEngine GetEventEmitter(string name) | |||
{ | |||
return _eventEmitters[name]; | |||
} | |||
public static Dictionary<string, IEventEmitterEngine> GetEventEmitters() | |||
{ | |||
return _eventEmitters; | |||
} | |||
public static void RemoveEventEmitter(string name) | |||
{ | |||
_eventEmitters.Remove(name); | |||
} | |||
public static void RegisterEngines(EnginesRoot enginesRoot) | |||
{ | |||
// Register handlers before emitters so no events are missed | |||
var entityFactory = enginesRoot.GenerateEntityFactory(); | |||
foreach (var key in _eventHandlers.Keys) | |||
{ | |||
enginesRoot.AddEngine(_eventHandlers[key]); | |||
} | |||
foreach (var key in _eventEmitters.Keys) | |||
{ | |||
_eventEmitters[key].Factory = entityFactory; | |||
enginesRoot.AddEngine(_eventEmitters[key]); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
public class ModEventEntityDescriptor : GenericEntityDescriptor<ModEventEntityStruct> | |||
{ | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
using Svelto.ECS.Hybrid; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
public struct ModEventEntityStruct : IEntityStruct | |||
{ | |||
public object type; | |||
public EGID ID { get; set; } | |||
} | |||
} |
@@ -0,0 +1,43 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
class SimpleEventEmitterEngine : IEventEmitterEngine | |||
{ | |||
public string Name { get; set; } | |||
public object type { get; set; } | |||
public IEntityFactory Factory { private get; set; } | |||
public IEntitiesDB entitiesDB { set; private get; } | |||
public void Ready() { } | |||
public void Emit() | |||
{ | |||
Factory.BuildEntity<ModEventEntityDescriptor>(ApiExclusiveGroups.eventID++, ApiExclusiveGroups.eventsExclusiveGroup) | |||
.Init(new ModEventEntityStruct | |||
{ | |||
type = type | |||
}); | |||
} | |||
public SimpleEventEmitterEngine(EventType type, string name) | |||
{ | |||
this.type = type; | |||
this.Name = name; | |||
} | |||
public SimpleEventEmitterEngine(object type, string name) | |||
{ | |||
this.type = type; | |||
this.Name = name; | |||
} | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
using Svelto.ECS; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace GamecraftModdingAPI.Events | |||
{ | |||
class SimpleEventHandlerEngine : IEventHandlerEngine | |||
{ | |||
public object type { get; set; } | |||
public string Name { get; set; } | |||
private readonly Action<IEntitiesDB> onEvent; | |||
public IEntitiesDB entitiesDB { set; private get; } | |||
public void Add(ref ModEventEntityStruct entityView, EGID egid) | |||
{ | |||
if (entityView.type.Equals(this.type)) | |||
{ | |||
onEvent.Invoke(entitiesDB); | |||
} | |||
} | |||
public void Ready() { } | |||
public void Remove(ref ModEventEntityStruct entityView, EGID egid) { } | |||
public SimpleEventHandlerEngine(Action handleEvent, object type, string name) : this((IEntitiesDB db) => { handleEvent.Invoke(); }, type, name) { } | |||
public SimpleEventHandlerEngine(Action<IEntitiesDB> handleEvent, object type, string name) | |||
{ | |||
this.type = type; | |||
this.Name = name; | |||
this.onEvent = handleEvent; | |||
} | |||
} | |||
} |
@@ -3,6 +3,11 @@ | |||
<PropertyGroup> | |||
<TargetFramework>net48</TargetFramework> | |||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> | |||
<Version>0.1.0.0</Version> | |||
<Authors>Exmods</Authors> | |||
<PackageLicenseExpression>GNU General Public Licence 3+</PackageLicenseExpression> | |||
<PackageProjectUrl>https://git.exmods.org/modtainers/GamecraftModdingAPI</PackageProjectUrl> | |||
<NeutralLanguage>en-CA</NeutralLanguage> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
@@ -531,6 +536,19 @@ | |||
<HintPath>..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath> | |||
</Reference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Update="Properties\Settings.Designer.cs"> | |||
<DesignTimeSharedInput>True</DesignTimeSharedInput> | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Settings.settings</DependentUpon> | |||
</Compile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Update="Properties\Settings.settings"> | |||
<Generator>SettingsSingleFileGenerator</Generator> | |||
<LastGenOutput>Settings.Designer.cs</LastGenOutput> | |||
</None> | |||
</ItemGroup> | |||
<!--End Dependencies--> | |||
</Project> |
@@ -0,0 +1,39 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Harmony; | |||
using System.Reflection; | |||
using GamecraftModdingAPI.Utility; | |||
using GamecraftModdingAPI.Events; | |||
namespace GamecraftModdingAPI | |||
{ | |||
static class Main | |||
{ | |||
private static HarmonyInstance harmony; | |||
public static void Init() | |||
{ | |||
var currentAssembly = Assembly.GetExecutingAssembly(); | |||
if (harmony == null) | |||
{ | |||
harmony = HarmonyInstance.Create(currentAssembly.GetName().Name); | |||
harmony.PatchAll(currentAssembly); | |||
} | |||
// create default event objects | |||
Manager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("App Inited event!"); }, | |||
EventType.ApplicationInitialized, "appinit API debug")); | |||
Manager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.ApplicationInitialized, "GamecraftModdingAPIApplicationInitializedEventEmitter")); | |||
Manager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.MenuActivated, "GamecraftModdingAPIMenuActivatedEventEmitter")); | |||
Logging.Log($"{currentAssembly.GetName().Name} {currentAssembly.GetName().Version} start & patch complete"); | |||
} | |||
public static void Shutdown() | |||
{ | |||
var currentAssembly = Assembly.GetExecutingAssembly(); | |||
harmony.UnpatchAll(currentAssembly.GetName().Name); | |||
Logging.Log($"{currentAssembly.GetName().Name} {currentAssembly.GetName().Version} shutdown & unpatch complete"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// This code was generated by a tool. | |||
// Runtime Version:4.0.30319.42000 | |||
// | |||
// Changes to this file may cause incorrect behavior and will be lost if | |||
// the code is regenerated. | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace GamecraftModdingAPI.Properties { | |||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")] | |||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { | |||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); | |||
public static Settings Default { | |||
get { | |||
return defaultInstance; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
<?xml version='1.0' encoding='utf-8'?> | |||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"> | |||
<Profiles> | |||
<Profile Name="(Default)" /> | |||
</Profiles> | |||
</SettingsFile> |
@@ -1,22 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
using Harmony; | |||
using UnityEngine; | |||
namespace TestMod | |||
{ | |||
[HarmonyPatch] | |||
class TestPatch | |||
{ | |||
static void Prefix() | |||
{ | |||
Debug.Log("Test Patch Prefix"); | |||
} | |||
[HarmonyTargetMethod] | |||
static MethodBase HTargetMethod(HarmonyInstance instance) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
} | |||
} |
@@ -1,13 +1,12 @@ | |||
using System; | |||
using IllusionPlugin; | |||
using UnityEngine; | |||
using Harmony; | |||
using System.Reflection; | |||
namespace GamecraftModdingAPI | |||
namespace GamecraftModdingAPI.Tests | |||
{ | |||
// unused by design | |||
public class GamecraftModdingAPIPlugin //: IllusionPlugin.IEnhancedPlugin | |||
public class GamecraftModdingAPIPluginTest //: IllusionPlugin.IEnhancedPlugin | |||
{ | |||
public static HarmonyInstance harmony { get; protected set; } | |||
@@ -21,18 +20,12 @@ namespace GamecraftModdingAPI | |||
public void OnApplicationQuit() | |||
{ | |||
harmony.UnpatchAll(HarmonyID); | |||
Debug.Log(Name + " shutdown complete"); | |||
GamecraftModdingAPI.Main.Shutdown(); | |||
} | |||
public void OnApplicationStart() | |||
{ | |||
if (harmony == null) | |||
{ | |||
harmony = HarmonyInstance.Create(HarmonyID); | |||
harmony.PatchAll(Assembly.GetExecutingAssembly()); | |||
} | |||
Debug.Log(Name + " start & patch complete"); | |||
GamecraftModdingAPI.Main.Init(); | |||
} | |||
public void OnFixedUpdate() { } |
@@ -0,0 +1,16 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Svelto.ECS; | |||
namespace GamecraftModdingAPI.Utility | |||
{ | |||
static class ApiExclusiveGroups | |||
{ | |||
public static readonly ExclusiveGroup eventsExclusiveGroup = new ExclusiveGroup(); | |||
public static uint eventID; | |||
} | |||
} |
@@ -0,0 +1,147 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace GamecraftModdingAPI.Utility | |||
{ | |||
/// <summary> | |||
/// Utility class to access Gamecraft's built-in logging capabilities. | |||
/// The log is saved to %APPDATA%\..\LocalLow\FreeJam\Gamecraft\Player.Log | |||
/// </summary> | |||
static class Logging | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void Log(string msg) | |||
{ | |||
Svelto.Console.Log(msg); | |||
} | |||
/// <summary> | |||
/// Write a regular message to Gamecraft'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 LogDebug(string msg) | |||
{ | |||
Svelto.Console.LogDebug(msg); | |||
} | |||
/// <summary> | |||
/// Write a debug message to Gamecraft's log | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogDebug(object obj) | |||
{ | |||
Svelto.Console.LogDebug(obj.ToString()); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogDebug<T>(string msg, T extraDebug) | |||
{ | |||
Svelto.Console.LogDebug<T>(msg, extraDebug); | |||
} | |||
/// <summary> | |||
/// Write a debug message and object to Gamecraft's log | |||
/// The reason this method exists in Svelto.Console is beyond my understanding | |||
/// </summary> | |||
/// <typeparam name="T">The type of the extra debug object</typeparam> | |||
/// <param name="obj">The object to log</param> | |||
/// <param name="extraDebug">The extra object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogDebug<T>(object obj, T extraDebug) | |||
{ | |||
Svelto.Console.LogDebug<T>(obj.ToString(), extraDebug); | |||
} | |||
[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 Gamecraft'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 Gamecraft's log | |||
/// </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, Dictionary<string, string> extraData = null) | |||
{ | |||
Svelto.Console.LogException(e, extraData); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogException(string msg, Exception e, Dictionary<string, string> extraData = null) | |||
{ | |||
Svelto.Console.LogException(msg, e, extraData); | |||
} | |||
/// <summary> | |||
/// Write an exception message to Gamecraft's log | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
/// <param name="e">The exception to log</param> | |||
/// <param name="extraData">The extra data to pass to the ILogger. | |||
/// This is implemented similar to LogException(Exception e, Dictionary extraData)'s extraData</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogException(object obj, Exception e, Dictionary<string, string> extraData = null) | |||
{ | |||
Svelto.Console.LogException(obj.ToString(), e, extraData); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void LogWarning(string msg) | |||
{ | |||
Svelto.Console.LogWarning(msg); | |||
} | |||
/// <summary> | |||
/// Write a warning message to Gamecraft'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()); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SystemLog(string msg) | |||
{ | |||
Svelto.Console.SystemLog(msg); | |||
} | |||
/// <summary> | |||
/// Write a message to stdout (usually the terminal which is running, like Command Prompt or PowerShell) | |||
/// </summary> | |||
/// <param name="obj">The object to log</param> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SystemLog(object obj) | |||
{ | |||
Svelto.Console.SystemLog(obj.ToString()); | |||
} | |||
} | |||
} |