├── .gitmodules ├── Build.All.bat ├── DotNet35.props ├── LICENSE ├── Managed.Games ├── Assemblies.props ├── SlimeRancher │ └── .gitkeep └── Universal │ └── .gitkeep ├── Managed.UnityEngine ├── Managed │ └── .gitkeep ├── UnityEngine.2017.props ├── UnityEngine.4.props ├── UnityEngine.5.props └── UnityEngine.Auto.props ├── PluginManager.Core ├── Extensions │ ├── GameObject.cs │ ├── Texture.cs │ ├── Texture2D.cs │ └── TextureFormat.cs ├── OnGameInitAttribute.cs ├── PluginManager.Core.csproj ├── PluginManager.cs └── Properties │ └── AssemblyInfo.cs ├── PluginManager.Setup ├── PathDiscovery.cs ├── PluginManager.Setup.csproj └── Program.cs ├── PluginManager.sln ├── PluginManager.sln.DotSettings └── README.md /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Plugin.Templates/Template.NET35"] 2 | path = Plugin.Templates/Template.NET35 3 | url = https://github.com/UnityPluginManager/Template.NET35.git 4 | [submodule "Plugin.Templates/Template.NET46"] 5 | path = Plugin.Templates/Template.NET46 6 | url = https://github.com/UnityPluginManager/Template.NET46.git 7 | [submodule "Plugin.Projects/Universal.SamplePlugin"] 8 | path = Plugin.Projects/Universal.SamplePlugin 9 | url = https://github.com/UnityPluginManager/Universal.SamplePlugin.git 10 | [submodule "Plugin.Projects/SlimeRancher.DebugMenu"] 11 | path = Plugin.Projects/SlimeRancher.DebugMenu 12 | url = https://github.com/UnityPluginManager/SlimeRancher.DebugMenu.git 13 | -------------------------------------------------------------------------------- /Build.All.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set BaseDir=%cd% 4 | 5 | cd %BaseDir%\PluginManager.Core 6 | dotnet build 7 | 8 | cd %BaseDir%\PluginManager.Setup 9 | dotnet build 10 | 11 | echo Press any key to exit . . . 12 | pause > nul 13 | -------------------------------------------------------------------------------- /DotNet35.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 UPM Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Managed.Games/Assemblies.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)\$(TargetGame)\Assembly-CSharp.dll 5 | False 6 | 7 | 8 | 9 | 10 | 11 | $(MSBuildThisFileDirectory)\$(TargetGame)\Assembly-UnityScript.dll 12 | False 13 | 14 | 15 | 16 | 17 | 18 | $(MSBuildThisFileDirectory)\$(TargetGame)\Assembly-Boo.dll 19 | False 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Managed.Games/SlimeRancher/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnityPluginManager/PluginManager/c4268fb527861415661827557eea601f22bb7b51/Managed.Games/SlimeRancher/.gitkeep -------------------------------------------------------------------------------- /Managed.Games/Universal/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnityPluginManager/PluginManager/c4268fb527861415661827557eea601f22bb7b51/Managed.Games/Universal/.gitkeep -------------------------------------------------------------------------------- /Managed.UnityEngine/Managed/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnityPluginManager/PluginManager/c4268fb527861415661827557eea601f22bb7b51/Managed.UnityEngine/Managed/.gitkeep -------------------------------------------------------------------------------- /Managed.UnityEngine/UnityEngine.2017.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UI.dll 5 | False 6 | 7 | 8 | 9 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.AccessibilityModule.dll 10 | False 11 | 12 | 13 | 14 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ParticleSystemModule.dll 15 | False 16 | 17 | 18 | 19 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.PhysicsModule.dll 20 | False 21 | 22 | 23 | 24 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.VehiclesModule.dll 25 | False 26 | 27 | 28 | 29 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ClothModule.dll 30 | False 31 | 32 | 33 | 34 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.AIModule.dll 35 | False 36 | 37 | 38 | 39 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.AnimationModule.dll 40 | False 41 | 42 | 43 | 44 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.TextRenderingModule.dll 45 | False 46 | 47 | 48 | 49 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UIModule.dll 50 | False 51 | 52 | 53 | 54 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.TerrainPhysicsModule.dll 55 | False 56 | 57 | 58 | 59 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.IMGUIModule.dll 60 | False 61 | 62 | 63 | 64 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ClusterInputModule.dll 65 | False 66 | 67 | 68 | 69 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ClusterRendererModule.dll 70 | False 71 | 72 | 73 | 74 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UNETModule.dll 75 | False 76 | 77 | 78 | 79 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.DirectorModule.dll 80 | False 81 | 82 | 83 | 84 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UnityAnalyticsModule.dll 85 | False 86 | 87 | 88 | 89 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.PerformanceReportingModule.dll 90 | False 91 | 92 | 93 | 94 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UnityConnectModule.dll 95 | False 96 | 97 | 98 | 99 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.WebModule.dll 100 | False 101 | 102 | 103 | 104 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ARModule.dll 105 | False 106 | 107 | 108 | 109 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.VRModule.dll 110 | False 111 | 112 | 113 | 114 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UIElementsModule.dll 115 | False 116 | 117 | 118 | 119 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.StyleSheetsModule.dll 120 | False 121 | 122 | 123 | 124 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.AssetBundleModule.dll 125 | False 126 | 127 | 128 | 129 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.AudioModule.dll 130 | False 131 | 132 | 133 | 134 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.CrashReportingModule.dll 135 | False 136 | 137 | 138 | 139 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.GameCenterModule.dll 140 | False 141 | 142 | 143 | 144 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.GridModule.dll 145 | False 146 | 147 | 148 | 149 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ImageConversionModule.dll 150 | False 151 | 152 | 153 | 154 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.InputModule.dll 155 | False 156 | 157 | 158 | 159 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.JSONSerializeModule.dll 160 | False 161 | 162 | 163 | 164 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ParticlesLegacyModule.dll 165 | False 166 | 167 | 168 | 169 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.Physics2DModule.dll 170 | False 171 | 172 | 173 | 174 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.ScreenCaptureModule.dll 175 | False 176 | 177 | 178 | 179 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.SharedInternalsModule.dll 180 | False 181 | 182 | 183 | 184 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.SpriteMaskModule.dll 185 | False 186 | 187 | 188 | 189 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.SpriteShapeModule.dll 190 | False 191 | 192 | 193 | 194 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.TerrainModule.dll 195 | False 196 | 197 | 198 | 199 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.TilemapModule.dll 200 | False 201 | 202 | 203 | 204 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UnityWebRequestModule.dll 205 | False 206 | 207 | 208 | 209 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UnityWebRequestAudioModule.dll 210 | False 211 | 212 | 213 | 214 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UnityWebRequestTextureModule.dll 215 | False 216 | 217 | 218 | 219 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UnityWebRequestWWWModule.dll 220 | False 221 | 222 | 223 | 224 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.VideoModule.dll 225 | False 226 | 227 | 228 | 229 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.WindModule.dll 230 | False 231 | 232 | 233 | 234 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.CoreModule.dll 235 | False 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Managed.UnityEngine/UnityEngine.4.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Managed.UnityEngine/UnityEngine.5.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.UI.dll 5 | False 6 | 7 | 8 | 9 | $(MSBuildThisFileDirectory)\Managed\UnityEngine.dll 10 | False 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Managed.UnityEngine/UnityEngine.Auto.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(MSBuildThisFileDirectory)\UnityEngine.5.props 6 | 7 | 8 | 9 | 10 | $(MSBuildThisFileDirectory)\UnityEngine.2017.props 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /PluginManager.Core/Extensions/GameObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using JetBrains.Annotations; 3 | using UnityEngine; 4 | 5 | namespace PluginManager.Core.Extensions 6 | { 7 | public static class GameObjectExtensions 8 | { 9 | [PublicAPI] 10 | public static void RemoveComponent(this GameObject self, Type component) 11 | { 12 | UnityEngine.Object.Destroy(self.GetComponent(component)); 13 | } 14 | 15 | [PublicAPI] 16 | public static void RemoveComponent(this GameObject self) 17 | { 18 | self.RemoveComponent(typeof(T)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PluginManager.Core/Extensions/Texture.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Annotations; 2 | using UnityEngine; 3 | 4 | namespace PluginManager.Core.Extensions 5 | { 6 | public static class TextureExtensions 7 | { 8 | [PublicAPI] 9 | public static Vector2 GetDimensions(this Texture self) 10 | { 11 | return new Vector2(self.width, self.height); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PluginManager.Core/Extensions/Texture2D.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Annotations; 2 | using UnityEngine; 3 | 4 | namespace PluginManager.Core.Extensions 5 | { 6 | public static class Texture2DExtensions 7 | { 8 | [PublicAPI] 9 | public static Texture2D ToReadable(this Texture2D self) 10 | { 11 | var newTexture = new Texture2D(self.width, self.height); 12 | RenderTexture prevRender = RenderTexture.active; 13 | 14 | RenderTexture newRender = RenderTexture.GetTemporary(self.width, self.height, 0, 15 | self.format.ToRenderTextureFormat(), RenderTextureReadWrite.Linear); 16 | 17 | Graphics.Blit(self, newRender); 18 | RenderTexture.active = newRender; 19 | 20 | newTexture.ReadPixels(new Rect(0, 0, self.width, self.height), 0, 0); 21 | newTexture.Apply(); 22 | 23 | RenderTexture.active = prevRender; 24 | RenderTexture.ReleaseTemporary(newRender); 25 | 26 | return newTexture; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /PluginManager.Core/Extensions/TextureFormat.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using JetBrains.Annotations; 3 | using UnityEngine; 4 | 5 | namespace PluginManager.Core.Extensions 6 | { 7 | public static class TextureFormatExtensions 8 | { 9 | /// Converts a TextureFormat to a RenderTextureFormat. 10 | [PublicAPI] 11 | [SuppressMessage("ReSharper", "SwitchStatementMissingSomeCases")] 12 | public static RenderTextureFormat ToRenderTextureFormat(this TextureFormat self) 13 | { 14 | switch (self) 15 | { 16 | case TextureFormat.ARGB32: return RenderTextureFormat.ARGB32; 17 | case TextureFormat.RGB565: return RenderTextureFormat.RGB565; 18 | case TextureFormat.ARGB4444: return RenderTextureFormat.ARGB4444; 19 | case TextureFormat.RGFloat: return RenderTextureFormat.RGFloat; 20 | case TextureFormat.RGHalf: return RenderTextureFormat.RGHalf; 21 | case TextureFormat.RFloat: return RenderTextureFormat.RFloat; 22 | case TextureFormat.RHalf: return RenderTextureFormat.RHalf; 23 | case TextureFormat.R8: return RenderTextureFormat.R8; 24 | case TextureFormat.BGRA32: return RenderTextureFormat.BGRA32; 25 | case TextureFormat.RG16: return RenderTextureFormat.RG16; 26 | default: return RenderTextureFormat.Default; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PluginManager.Core/OnGameInitAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using JetBrains.Annotations; 3 | using UnityEngine; 4 | 5 | namespace PluginManager.Core 6 | { 7 | [AttributeUsage(AttributeTargets.Class)] 8 | [BaseTypeRequired(typeof(MonoBehaviour))] 9 | public class OnGameInitAttribute : Attribute 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PluginManager.Core/PluginManager.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net35 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /PluginManager.Core/PluginManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Reflection; 5 | using JetBrains.Annotations; 6 | using UnityEngine; 7 | 8 | namespace PluginManager.Core 9 | { 10 | public class PluginManager : MonoBehaviour 11 | { 12 | readonly string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins"); 13 | 14 | [UsedImplicitly] 15 | internal static void Initialize() 16 | { 17 | var gameObject = new GameObject("UPM Root"); 18 | DontDestroyOnLoad(gameObject.transform.root); 19 | gameObject.AddComponent(); 20 | } 21 | 22 | void Awake() 23 | { 24 | if (!Directory.Exists(pluginDirectory)) return; 25 | 26 | foreach (string fileName in Directory.GetFiles(pluginDirectory, "*.dll", SearchOption.AllDirectories)) 27 | { 28 | try 29 | { 30 | Assembly plugin = Assembly.LoadFile(Path.GetFullPath(fileName)); 31 | 32 | foreach (Type component in plugin.GetTypes() 33 | .Where(t => t.IsSubclassOf(typeof(MonoBehaviour))) 34 | .Where(t => t.IsDefined(typeof(OnGameInitAttribute), false))) 35 | { 36 | var componentObject = new GameObject(plugin.FullName); 37 | componentObject.transform.SetParent(transform); 38 | componentObject.AddComponent(component); 39 | } 40 | } 41 | catch (Exception e) 42 | { 43 | Debug.LogError(e.ToString()); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /PluginManager.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("UnityEngine")] 4 | [assembly: InternalsVisibleTo("UnityEngine.CoreModule")] 5 | -------------------------------------------------------------------------------- /PluginManager.Setup/PathDiscovery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Mono.Cecil; 4 | 5 | namespace PluginManager.Setup 6 | { 7 | static class PathDiscovery 8 | { 9 | public static string FindDataDirectory() 10 | { 11 | // test #1: Data 12 | if (Directory.Exists("Data")) return "Data"; 13 | 14 | // test #2: ExecutableName_Data 15 | foreach (string fileName in Directory.EnumerateFiles(".", "*.exe")) 16 | { 17 | string exeName = Path.GetFileNameWithoutExtension(fileName); 18 | string potentialPath = $"{exeName}_Data"; 19 | if (Directory.Exists(potentialPath)) return potentialPath; 20 | } 21 | 22 | // test #3: Any path ending in "_Data" 23 | foreach (string path in Directory.EnumerateDirectories(".", "*_Data")) 24 | return path; 25 | 26 | throw new DirectoryNotFoundException("Could not locate 'Data' directory."); 27 | } 28 | 29 | public static string FindManagedDirectory() 30 | { 31 | return Path.Combine(FindDataDirectory(), "Managed"); 32 | } 33 | 34 | public static string GetAssemblyPath(IAssemblyResolver resolver, string name) => 35 | GetAssemblyPath(resolver, name, null); 36 | 37 | public static string GetAssemblyPath(IAssemblyResolver resolver, string name, Version version) => 38 | GetAssemblyPath(resolver, new AssemblyNameDefinition(name, version)); 39 | 40 | public static string GetAssemblyPath(IAssemblyResolver resolver, AssemblyNameReference def) 41 | { 42 | using (AssemblyDefinition asm = resolver.Resolve(def)) 43 | return asm.MainModule.FileName; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /PluginManager.Setup/PluginManager.Setup.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net46 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /PluginManager.Setup/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text; 5 | using Mono.Cecil; 6 | using Mono.Cecil.Cil; 7 | 8 | namespace PluginManager.Setup 9 | { 10 | static class Program 11 | { 12 | const string CoreLibrary = "PluginManager.Core.dll"; 13 | 14 | static void Main() 15 | { 16 | string managedPath = PathDiscovery.FindManagedDirectory(); 17 | 18 | var resolver = new DefaultAssemblyResolver(); 19 | resolver.AddSearchDirectory(managedPath); 20 | 21 | Version version = GetUnityVersion(); 22 | 23 | // as of Unity 2017.2, the UnityEngine assembly has been split into multiple assemblies 24 | // the assembly containing the GameObject class is UnityEngine.CoreModule 25 | string coreName = version.Major < 2017 || (version.Major == 2017 && version.Minor == 1) 26 | ? "UnityEngine" 27 | : "UnityEngine.CoreModule"; 28 | 29 | string corePath = PathDiscovery.GetAssemblyPath(resolver, coreName); 30 | byte[] coreData = File.ReadAllBytes(corePath); 31 | 32 | Console.WriteLine("Unity {0} detected.", version); 33 | 34 | ModuleDefinition unityCore = ModuleDefinition.ReadModule( 35 | new MemoryStream(coreData), 36 | new ReaderParameters { AssemblyResolver = resolver }); 37 | 38 | TypeDefinition gameObject = unityCore.GetType("UnityEngine", "GameObject"); 39 | 40 | // UPM works by adding a static constructor to the GameObject class, 41 | // which calls an initialization function in PluginManager.Core 42 | SetStaticCtor(gameObject, GenStaticCtor(unityCore, il => 43 | { 44 | ModuleDefinition upm = ModuleDefinition.ReadModule(CoreLibrary); 45 | TypeDefinition upmMain = upm.GetType("PluginManager.Core", "PluginManager"); 46 | MethodDefinition upmInit = upmMain.Methods.Single(m => m.Name == "Initialize"); 47 | 48 | il.Emit(OpCodes.Call, unityCore.ImportReference(upmInit)); 49 | il.Emit(OpCodes.Ret); 50 | 51 | upm.Dispose(); 52 | })); 53 | 54 | unityCore.Write(corePath); 55 | 56 | // We need to copy PluginManager.Core.dll into the Managed directory 57 | File.Copy(CoreLibrary, Path.Combine(managedPath, CoreLibrary), true); 58 | 59 | Console.WriteLine("UPM installed."); 60 | } 61 | 62 | /// Retrieves the version from the game files 63 | /// An instance of containing the game's Unity version 64 | /// Thrown when an unsupported version of Unity is in use 65 | static Version GetUnityVersion() 66 | { 67 | string dataPath = PathDiscovery.FindDataDirectory(); 68 | var dataFiles = new[] { "globalgamemanagers", "mainData" }; 69 | 70 | if (!dataFiles.Any(p => File.Exists(Path.Combine(dataPath, p)))) 71 | throw new NotSupportedException("Unsupported Unity version."); 72 | 73 | string dataFile = dataFiles.First(p => File.Exists(Path.Combine(dataPath, p))); 74 | using (FileStream ggm = File.OpenRead(Path.Combine(dataPath, dataFile))) 75 | using (var reader = new BinaryReader(ggm)) 76 | { 77 | reader.ReadUInt32(); // metadataSize 78 | reader.ReadUInt32(); // fileSize 79 | uint format = reader.ReadUInt32(); 80 | reader.ReadUInt32(); // dataOffset 81 | 82 | if (format >= 9) 83 | reader.ReadUInt32(); // endianness 84 | 85 | if (7 <= format && format <= 13) 86 | reader.ReadUInt32(); // longObjectIDs 87 | 88 | var sb = new StringBuilder(); 89 | 90 | for (;;) 91 | { 92 | byte b = reader.ReadByte(); 93 | if (b == 0) break; 94 | sb.Append((char)b); 95 | } 96 | 97 | string[] split = sb.ToString().Split('.', 'b', 'f', 'p'); 98 | 99 | return new Version 100 | ( 101 | Convert.ToInt32(split.Length > 0 ? split[0] : "0"), // major 102 | Convert.ToInt32(split.Length > 1 ? split[1] : "0"), // minor 103 | Convert.ToInt32(split.Length > 2 ? split[2] : "0"), // build 104 | 105 | // do we really care about this? 106 | Convert.ToInt32(split.Length > 3 ? split[3] : "0") // revision 107 | ); 108 | } 109 | } 110 | 111 | static MethodDefinition GenStaticCtor(ModuleDefinition module, Action generator) 112 | { 113 | var cctor = new MethodDefinition(".cctor", 114 | MethodAttributes.Private | MethodAttributes.Static | 115 | MethodAttributes.HideBySig | MethodAttributes.SpecialName | 116 | MethodAttributes.RTSpecialName | MethodAttributes.ReuseSlot, 117 | module.TypeSystem.Void); 118 | 119 | generator(cctor.Body.GetILProcessor()); 120 | return cctor; 121 | } 122 | 123 | static void ClearStaticCtors(TypeDefinition t) 124 | { 125 | foreach (MethodDefinition method in t.Methods 126 | .Where(m => m.Name == ".cctor") 127 | .ToList()) 128 | { 129 | t.Methods.Remove(method); 130 | } 131 | } 132 | 133 | static void SetStaticCtor(TypeDefinition t, MethodDefinition cctor) 134 | { 135 | ClearStaticCtors(t); 136 | t.Methods.Add(cctor); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /PluginManager.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.0.0 5 | MinimumVisualStudioVersion = 10.0.0.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginManager.Setup", "PluginManager.Setup\PluginManager.Setup.csproj", "{01C46972-F038-4C03-BC5F-BD6223FF6476}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginManager.Core", "PluginManager.Core\PluginManager.Core.csproj", "{BABD6EBF-3A33-4F77-B751-DCD0C5F5E95B}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {01C46972-F038-4C03-BC5F-BD6223FF6476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {01C46972-F038-4C03-BC5F-BD6223FF6476}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {01C46972-F038-4C03-BC5F-BD6223FF6476}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {01C46972-F038-4C03-BC5F-BD6223FF6476}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {BABD6EBF-3A33-4F77-B751-DCD0C5F5E95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {BABD6EBF-3A33-4F77-B751-DCD0C5F5E95B}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {BABD6EBF-3A33-4F77-B751-DCD0C5F5E95B}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {BABD6EBF-3A33-4F77-B751-DCD0C5F5E95B}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /PluginManager.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | Implicit 3 | Implicit 4 | True 5 | True 6 | True 7 | True 8 | True 9 | True 10 | True 11 | True 12 | True 13 | False 14 | True 15 | False 16 | UseVarWhenEvident 17 | UseVarWhenEvident 18 | UseVarWhenEvident 19 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 20 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 21 | True 22 | True 23 | True 24 | True 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Plugin Manager 2 | ## Introduction 3 | Unity Plugin Manager (herein, UPM) is a tool for creating plugins and mods for games developed with the Unity engine. 4 | 5 | ## How it works 6 | UPM injects a static constructor into the GameObject class found within the UnityEngine namespace. This way, it is able to execute code before anything else in the game. Using this, it loads plugins from a folder named "Plugins" in the game's folder, and instantiates any MonoBehaviour derivatives with the [OnGameInit] attribute. 7 | 8 | ## Compiling 9 | In order to build UPM or create plugins, you will need the [.NET Core SDK](https://www.microsoft.com/net/core) and at least one of the following: 10 | 11 | * An installation of Unity 5.x or 2017.x 12 | * A game developed in Unity 5.x or 2017.x 13 | 14 | Within the UPM repository is a directory named `Managed.UnityEngine`. This directory needs to contain specific files from one of the aforementioned prerequisites. 15 | 16 | ### Option A: Unity Installation 17 | 1. Browse to your Unity installation directory (usually `C:\Program Files\Unity [version]\Editor`) 18 | 2. Browse to `Data\Managed` and copy `UnityEngine.dll` to the `Managed.UnityEngine\Managed` directory in the UPM repository 19 | 4. If it exists, browse to `Data\Managed\UnityEngine` and copy everything _except_ UnityEngine.dll to the `Managed.UnityEngine\Managed` directory in the UPM repository 20 | 5. Browse to `Data\UnityExtensions\Unity\GUISystem\Standalone` and copy `UnityEngine.UI.dll` to the `Managed.UnityEngine\Managed` directory in the UPM repository 21 | 22 | ### Option B: Game 23 | 1. Browse to the game's `Managed` directory (usually inside the game's `Data` folder) 24 | 2. Copy every file with `UnityEngine` in its name to the `Managed.UnityEngine\Managed` directory in the UPM repository 25 | 26 | --- 27 | 28 | You should now be able to compile UPM by either using `Build.All.bat`, `PluginManager.sln` or manually calling `dotnet build` in the appropriate directories. 29 | 30 | ## Usage 31 | After building UPM, you should have _at least_ the following files: 32 | 33 | * PluginManager.Setup.exe (`PluginManager.Setup/bin/...`) 34 | * PluginManager.Core.dll (`PluginManager.Core/bin/...`) 35 | * Mono.Cecil.dll (`PluginManager.Setup/bin/...`) 36 | 37 | Any other files are not necessary for usage of UPM. 38 | 39 | Place the aforementioned files into the directory where your target game is located, and run `PluginManager.Setup.exe` (using Mono to do so, if not on Windows) 40 | 41 | If UPM installed successfully, you should see a message stating `UPM installed.` 42 | 43 | You are now free to create a `Plugins` directory and place your plugins in there. 44 | 45 | ## Creating plugins 46 | The creation of plugins is a relatively simple process. 47 | 48 | 1. Make a new folder for your target game in the `Managed.Games` folder, if one does not exist 49 | 2. Put the `Assembly-CSharp.dll`, `Assembly-UnityScript.dll` and/or `Assembly-Boo.dll` files from your target game in that folder, if they are present in its `Managed` folder 50 | 3. Make a new folder for your plugin in the `Plugin.Projects` folder 51 | 4. Copy one of the templates into that folder (NET46 is only for Unity 2017 projects using the new Mono runtime!) 52 | 5. Edit Config.props to point to your target game 53 | 54 | You can compile your plugin by opening a command prompt in its folder and entering `dotnet build`. 55 | 56 | Refer to the [sample plugin](https://github.com/UnityPluginManager/Universal.SamplePlugin) as an example of how to get started. 57 | --------------------------------------------------------------------------------