Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Added automated Load attributes #127

Merged
merged 6 commits into from
Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions PathfinderAPI/Meta/Load/ActionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Action;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ActionAttribute : BaseAttribute
{
public string XmlName { get; }

public ActionAttribute(string xmlName)
{
this.XmlName = xmlName;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
ActionManager.RegisterAction((Type)targettedInfo, XmlName);
}
}
}
20 changes: 20 additions & 0 deletions PathfinderAPI/Meta/Load/AdministratorAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Administrator;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class)]
public class AdministratorAttribute : BaseAttribute
{
public AdministratorAttribute()
{
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
AdministratorManager.RegisterAdministrator((Type)targettedInfo);
}
}
}
62 changes: 62 additions & 0 deletions PathfinderAPI/Meta/Load/AttributeManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Xml.Linq;
using System.Linq;
using System;
using System.Reflection;
using BepInEx.Hacknet;
using HarmonyLib;
using Mono.Cecil.Cil;
using MonoMod.Cil;

namespace Pathfinder.Meta.Load
{
[HarmonyPatch]
internal static class AttributeManager
{
[HarmonyILManipulator]
[HarmonyPatch(typeof(HacknetChainloader), nameof(HacknetChainloader.LoadPlugin))]
private static void OnPluginLoadIL(ILContext il)
{
var c = new ILCursor(il);

c.GotoNext(
x => x.MatchLdloc(1),
x => x.MatchCallvirt(AccessTools.Method(typeof(HacknetPlugin), nameof(HacknetPlugin.Load)))
);

c.Emit(OpCodes.Ldloc, 1);
c.Emit(OpCodes.Call, AccessTools.Method(typeof(AttributeManager), nameof(ReadAttributesFor)));
}

public static void ReadAttributesFor(HacknetPlugin plugin)
{
var pluginType = plugin.GetType();
if(pluginType.GetCustomAttribute<IgnorePluginAttribute>() != null)
return;
ReadAttributesOnType(plugin, pluginType);
foreach(var type in pluginType.Assembly.GetTypes())
{
if(type == pluginType) continue;
ReadAttributesOnType(plugin, type);
}
}

private static void ReadAttributesOnType(HacknetPlugin plugin, Type type)
{
foreach (var attribute in type.GetCustomAttributes<BaseAttribute>())
{
attribute.CallOn(plugin, type);
}
foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
{
if (member.MemberType == MemberTypes.NestedType)
{
ReadAttributesOnType(plugin, (Type)member);
}
else foreach (var attribute in member.GetCustomAttributes<BaseAttribute>())
{
attribute.CallOn(plugin, member);
}
}
}
}
}
17 changes: 17 additions & 0 deletions PathfinderAPI/Meta/Load/BaseAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;

namespace Pathfinder.Meta.Load
{
public abstract class BaseAttribute : Attribute
{
internal protected abstract void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo);

internal void ThrowOnInvalidOperation(bool evaluation, string message)
{
if(evaluation)
throw new InvalidOperationException(message);
}
}
}
30 changes: 30 additions & 0 deletions PathfinderAPI/Meta/Load/CommandAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Hacknet;
using Pathfinder.Command;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CommandAttribute : BaseAttribute
{
public string CommandName { get; }
public bool AddAutocomplete { get; set; }
public bool CaseSensitive { get; set; }

public CommandAttribute(string commandName, bool addAutocomplete = true, bool caseSensitive = false)
{
CommandName = commandName;
AddAutocomplete = addAutocomplete;
CaseSensitive = caseSensitive;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
var methodInfo = (MethodInfo)targettedInfo;
var commandAction = (Action<OS, string[]>)methodInfo.CreateDelegate(typeof(Action<OS, string[]>));
CommandManager.RegisterCommand(CommandName, commandAction, AddAutocomplete, CaseSensitive);
}
}
}
26 changes: 26 additions & 0 deletions PathfinderAPI/Meta/Load/ComputerExecutorAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Replacements;
using Pathfinder.Util.XML;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ComputerExecutorAttribute : BaseAttribute
{
public string Element { get; }
public ParseOption ParseOptions { get; set; }

public ComputerExecutorAttribute(string element, ParseOption parseOptions = ParseOption.None)
{
Element = element;
ParseOptions = parseOptions;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
ContentLoader.RegisterExecutor((Type)targettedInfo, Element, ParseOptions);
}
}
}
23 changes: 23 additions & 0 deletions PathfinderAPI/Meta/Load/ConditionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Action;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ConditionAttribute : BaseAttribute
{
public string XmlName { get; }

public ConditionAttribute(string xmlName)
{
this.XmlName = xmlName;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
ConditionManager.RegisterCondition((Type)targettedInfo, XmlName);
}
}
}
20 changes: 20 additions & 0 deletions PathfinderAPI/Meta/Load/DaemonAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Daemon;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class)]
public class DaemonAttribute : BaseAttribute
{
public DaemonAttribute()
{
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
DaemonManager.RegisterDaemon((Type)targettedInfo);
}
}
}
80 changes: 80 additions & 0 deletions PathfinderAPI/Meta/Load/EventAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System.Linq;
using System;
using System.Reflection;
using Pathfinder.Event;
using BepInEx.Hacknet;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
public class EventAttribute : BaseAttribute
{
private EventHandlerOptions eventHandlerOptions;
public int Priority
{
set => eventHandlerOptions.Priority = value;
}
public bool ContinueOnCancel
{
set => eventHandlerOptions.ContinueOnCancel = value;
}
public bool ContinueOnThrow
{
set => eventHandlerOptions.ContinueOnThrow = value;
}

public EventAttribute()
{
}

public EventAttribute(int priority, bool continueOnCancel = false, bool continueOnThrow = false)
{
eventHandlerOptions = new EventHandlerOptions{
Priority = priority,
ContinueOnCancel = continueOnCancel,
ContinueOnThrow = continueOnThrow
};
}

public EventAttribute(bool continueOnCancel = false, bool continueOnThrow = false)
{
eventHandlerOptions = new EventHandlerOptions{
ContinueOnCancel = continueOnCancel,
ContinueOnThrow = continueOnThrow
};
}

private void CallOn(HacknetPlugin plugin, MethodInfo info)
{
if(!info.IsStatic)
throw new InvalidOperationException("EventAttribute can not register event handlers to instance methods");
var eventType = info.GetParameters().FirstOrDefault()?.ParameterType;
EventManager.AddHandler(eventType, info);
}

private void CallOn(HacknetPlugin plugin, Type type)
{
foreach(var method in type.GetMethods(
BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
))
{
if(method.GetCustomAttribute<IgnoreEventAttribute>() != null)
continue;
var parameter = method.GetParameters().FirstOrDefault();
if(method.ReturnType == typeof(void)
&& (parameter?.ParameterType?.IsSubclassOf(typeof(PathfinderEvent)) ?? false))
CallOn(plugin, method);
}
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
if(targettedInfo is MethodInfo method)
CallOn(plugin, method);
else
CallOn(plugin, (Type) targettedInfo);
}
}
}
23 changes: 23 additions & 0 deletions PathfinderAPI/Meta/Load/ExecutableAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Executable;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ExecutableAttribute : BaseAttribute
{
public string XmlName { get; }

public ExecutableAttribute(string xmlName)
{
XmlName = xmlName;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
ExecutableManager.RegisterExecutable((Type)targettedInfo, XmlName);
}
}
}
26 changes: 26 additions & 0 deletions PathfinderAPI/Meta/Load/ExtensionInfoExecutorAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Replacements;
using Pathfinder.Util.XML;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ExtensionInfoExecutorAttribute : BaseAttribute
{
public string Element { get; }
public ParseOption ParseOptions { get; set; }

public ExtensionInfoExecutorAttribute(string element, ParseOption parseOptions = ParseOption.None)
{
Element = element;
ParseOptions = parseOptions;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
ExtensionInfoLoader.RegisterExecutor((Type)targettedInfo, Element, ParseOptions);
}
}
}
23 changes: 23 additions & 0 deletions PathfinderAPI/Meta/Load/GoalAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Reflection;
using BepInEx.Hacknet;
using Pathfinder.Mission;

namespace Pathfinder.Meta.Load
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class GoalAttribute : BaseAttribute
{
public string XmlName { get; }

public GoalAttribute(string xmlName)
{
this.XmlName = xmlName;
}

protected internal override void CallOn(HacknetPlugin plugin, MemberInfo targettedInfo)
{
GoalManager.RegisterGoal((Type)targettedInfo, XmlName);
}
}
}
Loading