From 1bf3a2759a91c58c0727926953d4ac2a99f23b35 Mon Sep 17 00:00:00 2001 From: juanmuscaria Date: Fri, 29 Jan 2021 17:01:27 -0300 Subject: [PATCH] First commit --- .gitignore | 8 + .../Properties/AssemblyInfo.cs | 5 + Duskers-Assembly-CSharp/README.md | 27 ++++ DuskersModloader.sln | 33 +++++ ExampleMod1/ExampleMod1.csproj | 95 ++++++++++++ ExampleMod1/MyExampleMod1.cs | 25 ++++ ExampleMod1/Properties/AssemblyInfo.cs | 35 +++++ ModLoader/Loader.cs | 138 ++++++++++++++++++ ModLoader/ModLoader.csproj | 69 +++++++++ ModLoader/Modding/Commands.cs | 57 ++++++++ ModLoader/Modding/Mod.cs | 7 + ModLoader/Patches/GameplayManager/Patches.cs | 15 ++ ModLoader/Properties/AssemblyInfo.cs | 35 +++++ ModLoader/packages.config | 4 + README.md | 2 + libs/README.md | 1 + 16 files changed, 556 insertions(+) create mode 100644 .gitignore create mode 100644 Duskers-Assembly-CSharp/Properties/AssemblyInfo.cs create mode 100644 Duskers-Assembly-CSharp/README.md create mode 100644 DuskersModloader.sln create mode 100644 ExampleMod1/ExampleMod1.csproj create mode 100644 ExampleMod1/MyExampleMod1.cs create mode 100644 ExampleMod1/Properties/AssemblyInfo.cs create mode 100644 ModLoader/Loader.cs create mode 100644 ModLoader/ModLoader.csproj create mode 100644 ModLoader/Modding/Commands.cs create mode 100644 ModLoader/Modding/Mod.cs create mode 100644 ModLoader/Patches/GameplayManager/Patches.cs create mode 100644 ModLoader/Properties/AssemblyInfo.cs create mode 100644 ModLoader/packages.config create mode 100644 README.md create mode 100644 libs/README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eadd058 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ +/DuskersModloader.sln.DotSettings.user +/libs/ +/Duskers-Assembly-CSharp/* diff --git a/Duskers-Assembly-CSharp/Properties/AssemblyInfo.cs b/Duskers-Assembly-CSharp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d1e4e4a --- /dev/null +++ b/Duskers-Assembly-CSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: AssemblyVersion("0.0.0.0")] \ No newline at end of file diff --git a/Duskers-Assembly-CSharp/README.md b/Duskers-Assembly-CSharp/README.md new file mode 100644 index 0000000..7461d99 --- /dev/null +++ b/Duskers-Assembly-CSharp/README.md @@ -0,0 +1,27 @@ +# How to patch Assembly-CSharp-firstpass.dll + +* You will need to decompile the dll source using some kind of tool (I used rider's built in decompiler). +* Drop all source here +* Add the following code to Steamworks.SteamAPI Init method +``` +Debug.logger.Log("Trying to load Harmony and ModLoader."); +try +{ + string managedPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + Assembly harmony = Assembly.LoadFrom(Path.Combine(managedPath, "0Harmony.dll")); + Assembly modLoader = Assembly.LoadFrom(Path.Combine(managedPath, "ModLoader.dll")); + Type modLoaderType = modLoader.GetType("ModLoader.Loader", true); + MethodInfo startMethod = modLoaderType.GetMethod("Start", new Type[0]); + startMethod.Invoke(null, new object[0]); +} +catch (Exception e) +{ + Debug.LogError("Unable to start modloader!"); + Debug.LogException(e); +} +``` +* Compile it. +* Can't compile because `(LayerMask) -1` is invalid for some reason. +* Remove it ignoring the consequences. +* Try compiling again. +* Now it compiled, replace the original file and drop the modloader and harmony dll together with it. \ No newline at end of file diff --git a/DuskersModloader.sln b/DuskersModloader.sln new file mode 100644 index 0000000..3d63073 --- /dev/null +++ b/DuskersModloader.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModLoader", "ModLoader\ModLoader.csproj", "{65C06865-5AA3-42C9-B905-D7BEBEEADBFC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duskers-Assembly-CSharp", "Duskers-Assembly-CSharp\Duskers-Assembly-CSharp.csproj", "{146A110D-4903-4763-8E58-770EF2F57672}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mods", "Mods", "{CCF36A88-3EF1-4A0F-8C45-28FB5009A5BF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleMod1", "ExampleMod1\ExampleMod1.csproj", "{0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {65C06865-5AA3-42C9-B905-D7BEBEEADBFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65C06865-5AA3-42C9-B905-D7BEBEEADBFC}.Release|Any CPU.Build.0 = Release|Any CPU + {65C06865-5AA3-42C9-B905-D7BEBEEADBFC}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {65C06865-5AA3-42C9-B905-D7BEBEEADBFC}.Debug|Any CPU.Build.0 = Release|Any CPU + {146A110D-4903-4763-8E58-770EF2F57672}.Release|Any CPU.ActiveCfg = Release|Any CPU + {146A110D-4903-4763-8E58-770EF2F57672}.Release|Any CPU.Build.0 = Release|Any CPU + {146A110D-4903-4763-8E58-770EF2F57672}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {146A110D-4903-4763-8E58-770EF2F57672}.Debug|Any CPU.Build.0 = Release|Any CPU + {0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3} = {CCF36A88-3EF1-4A0F-8C45-28FB5009A5BF} + EndGlobalSection +EndGlobal diff --git a/ExampleMod1/ExampleMod1.csproj b/ExampleMod1/ExampleMod1.csproj new file mode 100644 index 0000000..36ca82a --- /dev/null +++ b/ExampleMod1/ExampleMod1.csproj @@ -0,0 +1,95 @@ + + + + + Debug + AnyCPU + {0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3} + Library + Properties + ExampleMod1 + ExampleMod1 + v3.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Lib.Harmony.2.0.4\lib\net35\0Harmony.dll + + + ..\libs\Assembly-CSharp.dll + + + ..\libs\Mono.Posix.dll + + + ..\libs\Mono.Security.dll + + + + ..\libs\System.dll + + + ..\libs\System.Configuration.dll + + + + ..\libs\System.Core.dll + + + + ..\libs\System.Security.dll + + + + ..\libs\System.Xml.dll + + + ..\libs\UnityEngine.dll + + + ..\libs\UnityEngine.Networking.dll + + + ..\libs\UnityEngine.UI.dll + + + + + + + + + {65c06865-5aa3-42c9-b905-d7bebeeadbfc} + ModLoader + + + + + + diff --git a/ExampleMod1/MyExampleMod1.cs b/ExampleMod1/MyExampleMod1.cs new file mode 100644 index 0000000..d086b7f --- /dev/null +++ b/ExampleMod1/MyExampleMod1.cs @@ -0,0 +1,25 @@ +using ModLoader.Modding; + +namespace ExampleMod1 +{ + public class MyExampleMod1 : IMod + { + public void Load() + { + CommandManager.Manager.AddCommand(new ExampleCommand()); + } + } + + public class ExampleCommand : BaseCommand + { + public ExampleCommand() : base("example1", "") + { + } + + public override bool Execute(ExecutedCommand command, bool partOfMultiCommand) + { + ConsoleWindow3.SendConsoleResponse("An example command from ExampleMod1", ConsoleMessageType.SpecialInfo); + return true; + } + } +} \ No newline at end of file diff --git a/ExampleMod1/Properties/AssemblyInfo.cs b/ExampleMod1/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..39fd3da --- /dev/null +++ b/ExampleMod1/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ExampleMod1")] +[assembly: AssemblyDescription("Some example mod")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ExampleMod1")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0A0BA294-ABFE-4CCA-92E4-D99284AC8AD3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/ModLoader/Loader.cs b/ModLoader/Loader.cs new file mode 100644 index 0000000..1d1e0d3 --- /dev/null +++ b/ModLoader/Loader.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; +using HarmonyLib; +using ModLoader.Modding; +using UnityEngine; + +namespace ModLoader +{ + public class Loader + { + public static readonly List Mods = new List(); + + //Called from Steamworks.SteamAPI#Init() method + public static void Start() + { + //Load our patches + var harmony = new Harmony("com.juanmuscaria.ModLoader"); + harmony.PatchAll(); + + //Start loading other mods + var modFolder = GETModFolder(); + Debug.Log("Searching '{}' for mods.".Replace("{}",modFolder.FullName)); + + foreach (var modFile in Directory.GetFiles(modFolder.FullName, "*.dll")) + { + Debug.Log("Loading mod file:" + modFile); + foreach (var type in Assembly.LoadFile(modFile).GetExportedTypes()) + { + try + { + if (!type.IsDefined(typeof(IMod), true) && + !typeof(IMod).IsAssignableFrom(type)) continue; + Debug.Log("Found '"+ type + "' in '" + modFile + "'"); + var ctor = type.GetConstructor(Type.EmptyTypes); + if (ctor != null) + { + Mods.Add((IMod) ctor.Invoke(null)); + } + } + catch (Exception ex) + { + Debug.LogError("Failed to load '"+ type + "' in '" + modFile + "'"); + Debug.LogError(ex); + } + } + } + + foreach (var mod in Mods) + { + mod.Load(); + } + + CommandManager.Manager.AddCommand(new ModloaderCommand()); + } + + + //Get the mod directory + private static DirectoryInfo GETModFolder() + { + var directoryInfo = new DirectoryInfo(Application.dataPath).Parent; + if (directoryInfo != null) + { + string path = directoryInfo.FullName; + if (SystemInfo.operatingSystem.Contains("Windows")) + { + path = path + "\\Mods"; + } + else //Assume linux + { + path = path + "/Mods"; + } + + return new DirectoryInfo(path); + } + + throw new ModloaderException("Unable to determine the mod folder."); + } + } + + [Serializable] + public class ModloaderException : Exception + { + public ModloaderException() { } + public ModloaderException(string message) : base(message) { } + public ModloaderException(string message, Exception inner) : base(message, inner) { } + + protected ModloaderException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + public class ModloaderCommand : BaseCommand + { + public ModloaderCommand() : base("modloader", "modloader") + { + } + + public override bool Execute(ExecutedCommand command, bool partOfMultiCommand) + { + if (command.Arguments.Count == 0) + { + ConsoleWindow3.SendConsoleResponse("Modloader v0.0.0 by juanmuscaria", ConsoleMessageType.SpecialInfo); + ConsoleWindow3.SendConsoleResponse("Use modloader mods to list all installed mods", ConsoleMessageType.SpecialInfo); + } + else + { + if (command.Arguments[0].ToLower().Equals("mods")) + { + ConsoleWindow3.SendConsoleResponse("Modloader v0.0.0 by juanmuscaria", ConsoleMessageType.SpecialInfo); + if (Loader.Mods.Count > 0) + { + foreach (var mod in Loader.Mods) + { + ConsoleWindow3.SendConsoleResponse("--------------------", ConsoleMessageType.SpecialInfo); + ConsoleWindow3.SendConsoleResponse("Mod name: " + mod.GetType().Assembly.GetName().Name, ConsoleMessageType.SpecialInfo); + ConsoleWindow3.SendConsoleResponse("Mod description: " , ConsoleMessageType.SpecialInfo); + ConsoleWindow3.SendConsoleResponse("Mod version: " + mod.GetType().Assembly.GetName().Version, ConsoleMessageType.SpecialInfo); + } + ConsoleWindow3.SendConsoleResponse("--------------------", ConsoleMessageType.SpecialInfo); + } + else + { + ConsoleWindow3.SendConsoleResponse("You have no mod installed :(", ConsoleMessageType.Error); + } + } + else + { + ConsoleWindow3.SendConsoleResponse("Modloader v0.0.0 by juanmuscaria", ConsoleMessageType.SpecialInfo); + ConsoleWindow3.SendConsoleResponse("Unknown subcommand " + command.Arguments[0].ToLower(), ConsoleMessageType.Error); + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/ModLoader/ModLoader.csproj b/ModLoader/ModLoader.csproj new file mode 100644 index 0000000..2bf5c8b --- /dev/null +++ b/ModLoader/ModLoader.csproj @@ -0,0 +1,69 @@ + + + + + Debug + AnyCPU + {65C06865-5AA3-42C9-B905-D7BEBEEADBFC} + Library + Properties + ModLoader + ModLoader + v3.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Lib.Harmony.2.0.4\lib\net35\0Harmony.dll + True + + + ..\libs\Assembly-CSharp.dll + + + + + + + ..\libs\UnityEngine.dll + + + + + + + + + + + + + + + + diff --git a/ModLoader/Modding/Commands.cs b/ModLoader/Modding/Commands.cs new file mode 100644 index 0000000..55de368 --- /dev/null +++ b/ModLoader/Modding/Commands.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ModLoader.Modding +{ + public class CommandManager : ICommandable + { + public static readonly CommandManager Manager = new CommandManager(); + private CommandManager() + { + } + + private List _commands = new List(); + + public void AddCommand(BaseCommand command) + { + _commands.Add(command); + } + + public List QueryAvailableCommands() + { + return _commands.Cast().ToList(); + } + + public List QueryContextCommands() + { + return new List(); + } + + public void ExecuteCommand(ExecutedCommand command, bool partOfMultiCommand) + { + if (command.Command is BaseCommand) + { + var commandToRun = (BaseCommand) command.Command; + command.Handled = commandToRun.Execute(command, partOfMultiCommand); + } + } + + public List QueryDeveloperSpecialCaseCommands() + { + return new List(); + } + + public string CommandHeader { get; } + public bool IsPrimaryCommandContext { get; set; } + } + public abstract class BaseCommand : CommandDefinition + { + + protected BaseCommand(string name, string usage) : base(name, usage) + { + + } + + public abstract bool Execute(ExecutedCommand command, bool partOfMultiCommand); + } +} \ No newline at end of file diff --git a/ModLoader/Modding/Mod.cs b/ModLoader/Modding/Mod.cs new file mode 100644 index 0000000..5f3c197 --- /dev/null +++ b/ModLoader/Modding/Mod.cs @@ -0,0 +1,7 @@ +namespace ModLoader.Modding +{ + public interface IMod + { + void Load(); + } +} \ No newline at end of file diff --git a/ModLoader/Patches/GameplayManager/Patches.cs b/ModLoader/Patches/GameplayManager/Patches.cs new file mode 100644 index 0000000..d79e535 --- /dev/null +++ b/ModLoader/Patches/GameplayManager/Patches.cs @@ -0,0 +1,15 @@ +using HarmonyLib; +using ModLoader.Modding; + +namespace ModLoader.Patches.GameplayManager +{ + [HarmonyPatch(typeof(global::GameplayManager))] + [HarmonyPatch("Start")] + public class Start + { + static void Prefix(global::GameplayManager __instance) + { + ConsoleWindow3.Instance.AddCommandableObject(CommandManager.Manager); + } + } +} \ No newline at end of file diff --git a/ModLoader/Properties/AssemblyInfo.cs b/ModLoader/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8097d2d --- /dev/null +++ b/ModLoader/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Duskers ModLoader")] +[assembly: AssemblyDescription("Load mods into Duskers")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ModLoader")] +[assembly: AssemblyCopyright("Copyright © juanmuscaria 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("65C06865-5AA3-42C9-B905-D7BEBEEADBFC")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/ModLoader/packages.config b/ModLoader/packages.config new file mode 100644 index 0000000..b6b588f --- /dev/null +++ b/ModLoader/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1afac2d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Duskers ModLoader +This is a work in progress modloader for Duskers. \ No newline at end of file diff --git a/libs/README.md b/libs/README.md new file mode 100644 index 0000000..e9fbe68 --- /dev/null +++ b/libs/README.md @@ -0,0 +1 @@ +Thow all dlls inside (duskers installation dir)/Duskers_data/Managed here \ No newline at end of file