Difference between revisions of "How to reload mod at runtime (UMM)"

From Nexus Mods Wiki
Jump to: navigation, search
(Created page with " This feature is added in version 0.14.0. You can compile assembly and load it into game without restarting. In Visual Studio, set the assembly version as "1.0.*". To su...")
 
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
  
This feature is added in version 0.14.0. You can compile assembly and load it into game without restarting.
+
This feature is added in version 0.14.1. You can compile assembly and load it into game without restarting.
  
 
In Visual Studio, set the assembly version as "1.0.*". To successfully load assembly, its version must be greater than the previous one. The "1.0.*" will allow the compiler to automatically increment the version number.
 
In Visual Studio, set the assembly version as "1.0.*". To successfully load assembly, its version must be greater than the previous one. The "1.0.*" will allow the compiler to automatically increment the version number.
Line 7: Line 7:
 
<pre>start XCOPY /Y /R "$(TargetPath)" "D:\Games\YourGame\Mods\$(ProjectName)\$(ProjectName).dll*"</pre>
 
<pre>start XCOPY /Y /R "$(TargetPath)" "D:\Games\YourGame\Mods\$(ProjectName)\$(ProjectName).dll*"</pre>
  
In the source code of your mod, you need to specify UMM that the mod can be reloaded. Add this lines to ''EntryMethod''.
+
In the source code of your mod, you need to specify that the mod can be reloaded. Add ''EnableReloading ''attribute to the main class and&nbsp;set&nbsp;''Unload ''function to ''modEntry''.
<pre>modEntry.CanReload = true;
+
<pre>[EnableReloading]</pre>
modEntry.OnUnload = Unload;</pre>
+
<pre>modEntry.OnUnload = Unload;</pre>
  
In mod options should appear Reload''button.''
+
In mod options should appear Reload&nbsp;button''.''
  
 
https://i.ibb.co/hVXqBnJ/reload.png
 
https://i.ibb.co/hVXqBnJ/reload.png
Line 23: Line 23:
 
namespace ExampleMod
 
namespace ExampleMod
 
{
 
{
 +
&nbsp;  #if DEBUG
 +
&nbsp; &nbsp; [EnableReloading]
 +
    #endif
 
     static class Main
 
     static class Main
 
     {
 
     {
Line 29: Line 32:
 
             HarmonyInstance.Create(modEntry.Info.Id).PatchAll(Assembly.GetExecutingAssembly());
 
             HarmonyInstance.Create(modEntry.Info.Id).PatchAll(Assembly.GetExecutingAssembly());
 
             #if DEBUG
 
             #if DEBUG
            modEntry.CanReload = true;
 
 
             modEntry.OnUnload = Unload;
 
             modEntry.OnUnload = Unload;
 
             #endif
 
             #endif
Line 57: Line 59:
 
namespace ExampleMod
 
namespace ExampleMod
 
{
 
{
 +
&nbsp;  #if DEBUG
 +
&nbsp; &nbsp; [EnableReloading]
 +
    #endif
 
     static class Main
 
     static class Main
 
     {
 
     {
Line 70: Line 75:
 
             obj = new GameObject(name, typeof(CustomObject))
 
             obj = new GameObject(name, typeof(CustomObject))
 
             #if DEBUG
 
             #if DEBUG
            modEntry.CanReload = true;
 
 
             modEntry.OnUnload = Unload;
 
             modEntry.OnUnload = Unload;
 
             #endif
 
             #endif
Line 94: Line 98:
 
namespace ExampleMod
 
namespace ExampleMod
 
{
 
{
 +
&nbsp;  ​​​​​​​#if DEBUG
 +
&nbsp; &nbsp; [EnableReloading]
 +
    #endif
 
     static class Main
 
     static class Main
 
     {
 
     {
 
         static bool Load(UnityModManager.ModEntry modEntry)
 
         static bool Load(UnityModManager.ModEntry modEntry)
 
         {
 
         {
            #if DEBUG
 
            modEntry.CanReload = true;
 
            #endif
 
 
             modEntry.OnGUI = OnGUI;
 
             modEntry.OnGUI = OnGUI;
 
             return true;
 
             return true;
Line 113: Line 117:
 
     }
 
     }
 
}</pre>
 
}</pre>
 +
 +
[[Category:Unity Mod Manager]]

Latest revision as of 15:11, 9 March 2019

This feature is added in version 0.14.1. You can compile assembly and load it into game without restarting.

In Visual Studio, set the assembly version as "1.0.*". To successfully load assembly, its version must be greater than the previous one. The "1.0.*" will allow the compiler to automatically increment the version number.

For convenience, configure the Post-build Event Command Line so that the assembly file is automatically copied to the game.

start XCOPY /Y /R "$(TargetPath)" "D:\Games\YourGame\Mods\$(ProjectName)\$(ProjectName).dll*"

In the source code of your mod, you need to specify that the mod can be reloaded. Add EnableReloading attribute to the main class and set Unload function to modEntry.

[EnableReloading]
modEntry.OnUnload = Unload;

In mod options should appear Reload button.

reload.png

You only need to create the Unload function and remove all patches and objects of old assembly. In fact, old assembly can not be unloaded. It stays in shadows and if we do not remove the scripts they can still work. I will write a few examples to make it clearer.

Another new field attribute is SaveOnReload. It allows to copy fields to your new assembly. But it works only with static fields and cannot copy the types created by your assembly.

using UnityEngine;
using UnityModManagerNet;

namespace ExampleMod
{
    #if DEBUG
    [EnableReloading]
    #endif
    static class Main
    {
        static bool Load(UnityModManager.ModEntry modEntry)
        {
            HarmonyInstance.Create(modEntry.Info.Id).PatchAll(Assembly.GetExecutingAssembly());
            #if DEBUG
            modEntry.OnUnload = Unload;
            #endif
            return true;
        }
        #if DEBUG
        static bool Unload(UnityModManager.ModEntry modEntry)
        {
            HarmonyInstance.Create(modEntry.Info.Id).UnpatchAll();
            
            return true;
        }
        #endif
        [HarmonyPatch(typeof(SomeClass), "Method")]
        static class SomeClass_Method_Patch
        {
            static void Prefix()
            {
            }
        }
    }
}
using UnityEngine;
using UnityModManagerNet;

namespace ExampleMod
{
    #if DEBUG
    [EnableReloading]
    #endif
    static class Main
    {
        [SaveOnReload] // Works
        public static string name;
        //[SaveOnReload] This does not work because the CustomObject from the old assembly and the new one is not the same.
        public static CustomObject obj;

        static bool Load(UnityModManager.ModEntry modEntry)
        {
            if (name == null)
                name = Game.GetNextName();
            obj = new GameObject(name, typeof(CustomObject))
            #if DEBUG
            modEntry.OnUnload = Unload;
            #endif
            return true;
        }
        #if DEBUG
        static bool Unload(UnityModManager.ModEntry modEntry)
        {
            GameObject.Destroy(obj);
            
            return true;
        }
        #endif
        class CustomObject : SomeGameObject
        {
        }
    }
}
using UnityEngine;
using UnityModManagerNet;

namespace ExampleMod
{
    ​​​​​​​#if DEBUG
    [EnableReloading]
    #endif
    static class Main
    {
        static bool Load(UnityModManager.ModEntry modEntry)
        {
            modEntry.OnGUI = OnGUI;
            return true;
        }

        static void OnGUI(UnityModManager.ModEntry modEntry)
        {
            if (GUILayout.Button("New button"))
            {
            }
        }
    }
}