159 lines
6.6 KiB
C#
159 lines
6.6 KiB
C#
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Runtime.Loader;
|
|
using CringeBootstrap.Abstractions;
|
|
using CringeLauncher.Utils;
|
|
using CringePlugins.Utils;
|
|
using HarmonyLib;
|
|
using VRage.FileSystem;
|
|
using VRage.Game;
|
|
using VRage.Game.Common;
|
|
using VRage.Game.Components;
|
|
using VRage.Game.Definitions;
|
|
using VRage.ObjectBuilders;
|
|
using VRage.ObjectBuilders.Private;
|
|
using VRage.Plugins;
|
|
|
|
namespace CringeLauncher.Patches;
|
|
|
|
[HarmonyPatch]
|
|
public static class IntrospectionPatches
|
|
{
|
|
[HarmonyPrefix, HarmonyPatch(typeof(Assembly), nameof(Assembly.GetTypes))]
|
|
private static bool GetTypesPrefix(Assembly __instance, ref Type[] __result)
|
|
{
|
|
if (AssemblyLoadContext.GetLoadContext(__instance) is ICoreLoadContext || __instance.FullName?.StartsWith("System.") == true)
|
|
return true;
|
|
|
|
#if DEBUG
|
|
Debugger.Break();
|
|
|
|
__result = [];
|
|
return false;
|
|
#else
|
|
throw new NotSupportedException($"Getting types from {__instance} is not supported");
|
|
#endif
|
|
}
|
|
|
|
[HarmonyPrefix, HarmonyPatch(typeof(MyPlugins), nameof(MyPlugins.LoadPlugins))]
|
|
private static bool LoadPluginsPrefix(List<Assembly> assemblies, List<IPlugin> ___m_plugins, List<IHandleInputPlugin> ___m_handleInputPlugins)
|
|
{
|
|
foreach (var type in assemblies.SelectMany(b => IntrospectionContext.Global.CollectDerivedTypes<IPlugin>(b.GetMainModule())))
|
|
{
|
|
var instance = Activator.CreateInstance(type);
|
|
|
|
if (instance is IPlugin plugin)
|
|
___m_plugins.Add(plugin);
|
|
|
|
if (instance is IHandleInputPlugin handleInputPlugin)
|
|
___m_handleInputPlugins.Add(handleInputPlugin);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
[HarmonyPrefix, HarmonyPatch(typeof(MyObjectBuilderSerializerKeen), nameof(MyObjectBuilderSerializerKeen.RegisterFromAssembly))]
|
|
private static bool RegisterXmlSerializersPrefix(
|
|
MyObjectFactory<MyObjectBuilderDefinitionAttribute, MyObjectBuilder_Base> ___m_objectFactory, Assembly assembly)
|
|
{
|
|
Register(___m_objectFactory, assembly);
|
|
return false;
|
|
}
|
|
|
|
[HarmonyPrefix, HarmonyPatch(typeof(MyComponentFactory), nameof(MyComponentFactory.RegisterFromAssembly))]
|
|
private static bool RegisterComponentsPrefix(
|
|
MyObjectFactory<MyComponentBuilderAttribute, MyComponentBase> ___m_objectFactory, Assembly assembly)
|
|
{
|
|
Register(___m_objectFactory, assembly);
|
|
return false;
|
|
}
|
|
|
|
[HarmonyTranspiler,
|
|
HarmonyPatch(typeof(MyDefinitionManagerBase), nameof(MyDefinitionManagerBase.RegisterTypesFromAssembly))]
|
|
private static IEnumerable<CodeInstruction> RegisterDefinitionTypesTranspiler(
|
|
IEnumerable<CodeInstruction> instructions)
|
|
{
|
|
var getTypesMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetTypes));
|
|
var getDefinitionTypesMethod = AccessTools.DeclaredMethod(typeof(IntrospectionPatches), nameof(GetDefinitionTypes));
|
|
return instructions.MethodReplacer(getTypesMethod, getDefinitionTypesMethod);
|
|
}
|
|
|
|
private static Type[] GetDefinitionTypes(Assembly assembly)
|
|
{
|
|
return IntrospectionContext.Global.CollectAttributedTypes<MyDefinitionTypeAttribute>(assembly.GetMainModule())
|
|
.ToArray();
|
|
}
|
|
|
|
[HarmonyTranspiler,
|
|
HarmonyPatch(typeof(MyObjectBuilderType), nameof(MyObjectBuilderType.RegisterFromAssembly))]
|
|
private static IEnumerable<CodeInstruction> RegisterObjectBuilderTypesTranspiler(
|
|
IEnumerable<CodeInstruction> instructions)
|
|
{
|
|
var getTypesMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetTypes));
|
|
var getDefinitionTypesMethod = AccessTools.DeclaredMethod(typeof(IntrospectionPatches), nameof(GetObjectBuilderTypes));
|
|
return instructions.MethodReplacer(getTypesMethod, getDefinitionTypesMethod);
|
|
}
|
|
|
|
private static Type[] GetObjectBuilderTypes(Assembly assembly)
|
|
{
|
|
return IntrospectionContext.Global.CollectDerivedTypes<MyObjectBuilder_Base>(assembly.GetMainModule())
|
|
.ToArray();
|
|
}
|
|
|
|
[HarmonyTranspiler,
|
|
HarmonyPatch(typeof(MyComponentTypeFactory), nameof(MyComponentTypeFactory.RegisterFromAssembly), typeof(Assembly))]
|
|
private static IEnumerable<CodeInstruction> RegisterComponentTypesTranspiler(IEnumerable<CodeInstruction> instructions)
|
|
{
|
|
var getTypesMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetTypes));
|
|
var getDefinitionTypesMethod = AccessTools.DeclaredMethod(typeof(IntrospectionPatches), nameof(GetComponentTypes));
|
|
return instructions.MethodReplacer(getTypesMethod, getDefinitionTypesMethod);
|
|
}
|
|
|
|
private static Type[] GetComponentTypes(Assembly assembly)
|
|
{
|
|
return IntrospectionContext.Global.CollectDerivedTypes<MyComponentBase>(assembly.GetMainModule())
|
|
.ToArray();
|
|
}
|
|
|
|
private static void Register<TAttribute, TCreatedObjectBase>(MyObjectFactory<TAttribute, TCreatedObjectBase> factory, Assembly assembly)
|
|
where TAttribute : MyFactoryTagAttribute where TCreatedObjectBase : class
|
|
{
|
|
foreach (var type in IntrospectionContext.Global.CollectAttributedTypes<TAttribute>(assembly.GetMainModule()))
|
|
{
|
|
foreach (var attribute in type.GetCustomAttributes<TAttribute>())
|
|
{
|
|
factory.RegisterDescriptor(attribute, type);
|
|
}
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch]
|
|
private static class GameAssembliesPatch
|
|
{
|
|
private static IEnumerable<MethodInfo> TargetMethods()
|
|
{
|
|
return AccessTools.GetDeclaredMethods(typeof(MyPlugins))
|
|
.Where(b => b.Name.StartsWith("Register") &&
|
|
b.GetParameters() is [var param] && param.ParameterType == typeof(string));
|
|
}
|
|
|
|
private static bool Prefix([HarmonyArgument(0)] string file)
|
|
{
|
|
var name = AssemblyName.GetAssemblyName(Path.Join(MyFileSystem.ExePath, file));
|
|
|
|
ref var staticAssembly = ref AccessTools.StaticFieldRefAccess<Assembly>(typeof(MyPlugins), name.Name switch
|
|
{
|
|
"Sandbox.Common" => "m_sandboxAssembly",
|
|
"Sandbox.Game" => "m_sandboxGameAssembly",
|
|
"SpaceEngineers.Game" => "m_gamePluginAssembly",
|
|
"SpaceEngineers.ObjectBuilders" => "m_gameObjBuildersPlugin",
|
|
_ => throw new ArgumentOutOfRangeException(null, $"Unknown assembly name: {name}")
|
|
});
|
|
|
|
staticAssembly = AssemblyLoadContext.GetLoadContext(typeof(GameAssembliesPatch).Assembly)!
|
|
.LoadFromAssemblyName(name);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
} |