Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[Open Source] ModTool - Mod Support for Unity

Discussion in 'Assets and Asset Store' started by HelloMeow, Nov 21, 2016.

  1. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    This would happen with previous versions of ModTool sometimes. Some packages use Mono.Cecil, which ModTool also uses. This is fixed in version 2.0, because ModTool uses its own version of this library, with a different name.
     
  2. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Hi,

    I'm using ModTool v2 now. I passed a dll to the mod via the exporter and Visual Studio / Unity shows no errors when using functions from that dll.

    Letting prepare the mod, results in errors about those functions not being found, in the Log. The mod directory is created but the platforms folder inside are empty.

    Can I still utilise dlls? How? Or do I have to take a different route to pass a set of defined methods to a mod?

    Thank you for ModTool ! When it works, it is a huge comfort !
     
  3. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    Yes, you should be able to include dll files by selecting them in the shared assets window. Can you share the error message?

    There are two ways of sharing code with mods. The easiest way is to use assembly definitions. If you select an assembly definition and select all associated script files in the shared assets window, the mod will be able to use those scripts.

    The second method of sharing code is by selecting precompiled dll files in the shared assets window.
     
  4. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Hi, here're the messages:

    upload_2022-6-25_20-40-27.png

    and EDITED: NOT ANYMORE attached is the Mod package and the project you can get from EDITED: DELETED it's a simple demo


    Edit: I already created the DLL and have it in use and would like to not move the code inside the main project.
     
    Last edited: Jun 26, 2022
  5. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Oh, and 1 idea: can you let compress the resulting exported files (I don't know if you alread do because the export fails) into 1 file and support loading from that 1 file from the defult Mods folder? Would make distribution and reception through users easier when they don't have to manage multiple files or decompress themself.
     
  6. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    The errors appear to be caused by Unity when building the asset bundles. I think it's a bug on Unity's side.

    The x86 platform of bUtilitiesDLL is unchecked, which I think is excluding it from compilation when building asset bundles. If you enable this, I think it should work.

    Also, AutoRunScript.cs is not associated with an assembly definition and will probably break any references when loading the mod.

    Currently mods are still folders. I do have a working version that uses a zip archive to package mods, but this adds a bunch of overhead. It's fine for small mods, but with larger mods the memory usage is significantly higher. Eventually I want to support both folders and zip archives.
     
    uani likes this.
  7. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    I thank you, the export succeeds. The code does not have effect yet though. Before I debug letting load and the code, do I have to target x86 when building? And IL2CPP is no hindrance? What do you mean by
    ? It is supposed to be unique to the mod, only calling used libraries like UnityEngine and my bUtilitiesDLL. I apologize for not digging deeper into assembly definitions, Unity's doc is too long and I didn't see relevant info on what "a d" do. Do I have to do something particular? What?
     
  8. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    Ah, if it is supposed to be unique for each mod, you do not want to use assembly definitions. I never considered including a script like that. That's interesting.

    Unfortunately IL2CPP is not supported. This is because IL2CPP does not support loading .net code at runtime.
     
  9. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    :) :| :( ah, eh, ouh .. :) any idea of a possible outlook to achieve mod support with IL2CPP ?
     
  10. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    What if the mod code itself is all residing in a DLL and the main project know which entry point to call?
     
  11. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    It's not very likely. If you want to create assets and code in the editor and want to preserve references between the two, you need to use Mono. IL2CPP has too many limitations.

    There is a modding project (MelonLoader) that does have some IL2CPP support, but it still has some limitations. And I don't think it lets you use the Unity editor to create mods.
     
  12. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    1 other question:

    ModManager.ModRemoved does not incur a Mod.Unload() of the removed mod ? I would like a mod to remain loaded when the files are removed or are they not copied to RAM / main project runtime or can Unity load files from disk after it started? In that latter case and you do not let unload I guess I would have to let unload such a mod ?
     
  13. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    When a mod's files are changed or removed when the mod is loaded, it will remove or refresh the mod once it is unloaded. You should still be able to load scenes and assets from it while it is loaded.
     
    uani likes this.
  14. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    mod works in unity editor: my letting load and start code of my main project and the mod code itself works inside the game view of the main project in unity editor, unloading, reloading: everything works inside editor.
    But as a standalone Mono runtime the main project application discovers the mod but instructing to get it loaded and started has no effect.
    Ie. mod works with editor but not standalone. I haven't debugged standalone yet, i just finished all debugging and covering all possibilities and now would want to "ship" the moddable version of my application.
    Do you have an idea what is different between Editor and standalone and what I have to or can look out for?
     
  15. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    There shouldn't be any differences. If a mod doesn't load it might be invalid for some reason. You can check Mod.errors for any possible error messages. If there are none, you might find out more by checking the game's log file.
     
  16. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    fair enough, i'll see what i find there
     
  17. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    The issue is

    Code (CSharp):
    1. Fallback handler could not load library PROJECTNAME_Data/MonoBleedingEdge/data-000002581812F060.dll
    2. ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
    3. Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies.
    4.   at (wrapper managed-to-native) System.Reflection.Assembly.GetTypes(System.Reflection.Assembly,bool)
    5.   at System.Reflection.Assembly.GetTypes () [0x00000] in <d744450a80a74703b521360ee53ddc26>:0
    6.   at ModTool.AssemblyResource.LoadAssemblies () [0x00111] in <0a017fac95174003bdffd47f7b8a08db>:0
    7. UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
    on mod.Load() (mod being a Mod).

    Note: A folder PROJECTNAME_Data/MonoBleedingEdge/ does not exist, it is either PROJECTNAME_Data/ or MonoBleedingEdge/.
    The netstandard.dll file is not in the generated output Managed folder. Copying it thither from the Unity Editor installation files does not help.


    And subsequently in the Loaded event handler:

    Code (CSharp):
    1. Shader 'Standard': fallback shader 'VertexLit' not found
    2. ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
    3. Could not load type of field 'AutoRun:checker' (9) due to: Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies.
    4. Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies.
    5.   at (wrapper managed-to-native) System.Reflection.Assembly.GetTypes(System.Reflection.Assembly,bool)
    6.   at System.Reflection.Assembly.GetTypes () [0x00000] in <d744450a80a74703b521360ee53ddc26>:0
    7.   at ModTool.Mod.GetInstances[T] (System.Reflection.Assembly assembly, System.Object[] args) [0x00006] in <0a017fac95174003bdffd47f7b8a08db>:0
    8.   at ModTool.Mod.GetInstances[T] (System.Object[] args) [0x00020] in <0a017fac95174003bdffd47f7b8a08db>:0
    9. UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
    and

    Code (CSharp):
    1. The script 'AutoRun' could not be instantiated!
    2. 0x00007ff92853ee8d (UnityPlayer) UnityMain
    3. 0x00007ff928543f13 (UnityPlayer) UnityMain
    4. 0x00007ff92852dd25 (UnityPlayer) UnityMain
    5. 0x00007ff928af976e (UnityPlayer) UnityMain
    6. 0x00007ff92839a92f (UnityPlayer)
    7. 0x00007ff92839a9ef (UnityPlayer)
    8. 0x00007ff928341753 (UnityPlayer)
    9. 0x00007ff92839ae6c (UnityPlayer)
    10. 0x00007ff92806881a (UnityPlayer)
    11. 0x00007ff9280674a1 (UnityPlayer)
    12. 0x00007ff92806707d (UnityPlayer)
    13. 0x00007ff928066af7 (UnityPlayer)
    14. 0x00007ff92806667b (UnityPlayer)
    15. 0x00007ff927de715d (UnityPlayer)
    16. 0x0000024f04ab16da (Mono JIT Code) (wrapper managed-to-native) UnityEngine.Object:Internal_CloneSingle (UnityEngine.Object)
    17. 0x0000024f04ab14d3 (Mono JIT Code) UnityEngine.Object:Instantiate<T_REF> (T_REF)
    18. 0x0000024f0bbb05bb (Mono JIT Code) bUtilities.MainScript:StartMod (ModTool.Mod)
    19. 0x0000024f0bbb0364 (Mono JIT Code) ModTool.ModManager:OnModLoaded (ModTool.Mod)
    20. 0x0000024f0bbacb34 (Mono JIT Code) ModTool.Resource`1<T_REF>:OnLoaded ()
    21. 0x0000024f0bb9cf06 (Mono JIT Code) ModTool.Resource/<Loading>d__28:MoveNext ()
    22. 0x0000024f04ac3320 (Mono JIT Code) UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)
    where "AutoRun" is a script on the prefab I search for and let instantiate in my mod starting code.


    It is NOT fixed bei either Unity API Level .NET Standard 2.1 and .NET Framework, deleting all obj, Logs, Library folders and all VS files inside the project root, compressed standalone or uncompressed standalone output, presence of any .csproj files generated for every type.


    I use VS 2022 and Unity 2022.1.6f1
     
  18. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    I'm not sure what the issue is. I can load your mod fine, even on Android. Do you have any extra code that could reference netstandard? Do the game project and mod project have the same scripting backend?
     
  19. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    mod and main project were built with .NET Standard 2.1. That requires the host platform to provide its functionality. This can be circumvented by copying the netstandard.dll to the project program root folder. I tried various netstandard.dll : from dotnet, nuget, unity. The closest I got was that the dll was taken but required classes were not found inside.

    I switched the mod to .NET Framework API in Unity Editor Project Settings. NOW it works !

    :) Thank you !
     
  20. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Hello, you state "ModTool relies on AssetBundles, which means mods that are exported with a different version of Unity can have some issues." in the doc.

    Is the safest version of Unity the main project is build with the same version down to the 3rd version number the mod was created with? eg. 2022.1.7f1 or would 2022.1 suffice? Or does this depend on a package version (additionally) ?
     
  21. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    That's hard to say. In the last couple of years I haven't seen many issues when loading asset bundles from similar Unity versions. Issues used to be way more common.

    The exporter will only export mods with the exact same Unity version anyways. It checks the version and doesn't export if the version isn't the same. Do you think only showing a warning would be better?
     
  22. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Hi,

    hmm, regarding mod creation I think I consider requiring the exact version of Unity the modtool package is built with as acceptable (a warning I would prefer to pop up after modtool package import not when the mod creator wants to let export).

    When wanting to load a mod, can I, if i updated the main project Unity version since the mod was created, identify the Unity version of the mod first to possibly display a warning first or can i check for something not having loaded? I start the mod by running that "AutoRun.cs" functionality I created thus I coild skip starting mods which loaded with errors. You already provide an error output. I guess i would skip starting AutoRun for any error.
     
  23. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    Yeah I think a warning after importing the exporter would make more sense. Especially because issues between Unity versions are much less common now.

    Before you load a mod, you can find the mod's Unity version in the mod's ModInfo.
     
  24. IlIlIlIlIlIlIlIlIlIlIlIlIl

    IlIlIlIlIlIlIlIlIlIlIlIlIl

    Joined:
    Jul 14, 2019
    Posts:
    2
    Code (CSharp):
    1. private void OnModLoaded(Mod mod)
    2.     {
    3.         Debug.Log("Loaded Mod: " + mod.name );
    4.  
    5.         AssetBundleRequest assetBundleRequest = mod.GetAssetsAsync<ScriptableObject>();
    6.         foreach (ScriptableObject item in assetBundleRequest.allAssets)
    7.         {
    8.             Debug.Log(item is BagItem);
    9.         }
    10.        
    11.     }
    Hello, I want to know how to read scriptableobject. When I want to convert scriptableobject to other classes, I cannot convert it.
     
  25. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    You're loading all ScriptableObjects, but you can load just the BagItems like this:

    Code (CSharp):
    1. AssetBundleRequest assetBundleRequest = mod.GetAssetsAsync<BagItem>();
    Then you have to cast them.

    Code (CSharp):
    1. foreach (var asset in assetBundleRequest.allAssets)
    2. {
    3.     BagItem item = asset as BagItem;
    4. }
     
  26. IlIlIlIlIlIlIlIlIlIlIlIlIl

    IlIlIlIlIlIlIlIlIlIlIlIlIl

    Joined:
    Jul 14, 2019
    Posts:
    2
    Code (CSharp):
    1. private void OnModLoaded(Mod mod)
    2.     {
    3.         Debug.Log("Loaded Mod: " + mod.name );
    4.  
    5.         AssetBundleRequest assetBundleRequest = mod.GetAssetsAsync<BagItem>();
    6.         Debug.Log(assetBundleRequest.allAssets.Length);
    7.         foreach (var Asset in assetBundleRequest.allAssets)
    8.         {
    9.             BagItem item = Asset as BagItem;
    10.             Debug.Log(item);
    11.         }
    12.  
    13.         foreach (var item in mod.assetPaths)
    14.         {
    15.             Debug.Log(item);
    16.         }
    17.  
    18.         AssetBundleRequest assetBundleRequest_1 = mod.GetAssetsAsync<ScriptableObject>();
    19.         foreach (var item in assetBundleRequest_1.allAssets)
    20.         {
    21.             Debug.Log(item);
    22.         }
    23.  
    24.     }
    When I load only the BagItem, I can't access it, but show that the file exists

    2022-08-25 105215.png
     
  27. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    Your code works on my end. I can access my custom ScriptableObject assets like that. However, Mod.GetAssetsAsync is asynchronous. This means it loads the assets in the background and it might not finish loading them until a later point in time.

    In your case it might still be loading the assets when you try to access them. Does it work if you try Mod.GetAssets instead? If so, that is probably the issue.

    You can use AssetBundleRequest.completed or AssetBundleRequest.isDone to wait for it to complete.
     
  28. IceKontroI

    IceKontroI

    Joined:
    Jun 18, 2019
    Posts:
    8
    @HelloMeow This looks like a really powerful and useful tool. Is it possible to have an AddonMod depend on CoreMod, and then for AddonMod to able to change some aspect of CoreMod? Like swapping out a prefab's mesh, or editing some code in a prefab's script. That way, user downloads CoreMod + AddonMod, and we get the functionality of CoreMod, but with changes applied by AddonMod.
     
  29. IceKontroI

    IceKontroI

    Joined:
    Jun 18, 2019
    Posts:
    8
    To clarify, I'm wondering if a high level structure like this is possible with your tool:

    A mod can declare dependencies on any number of other mods. When a dependency is declared, all source files of that dependency become accessible to the mod. If the mod chooses to modify source files of one of its dependencies, let's say it changes logic in a C# script and changes the texture used in a Material, then its changed files get used instead of the original mod's.

    Of course, implementation of mod loading would have to account for the dependencies graph.
     
  30. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    279
    That's not something ModTool can do currently.
     
  31. whitegreenstudios88

    whitegreenstudios88

    Joined:
    Dec 12, 2021
    Posts:
    10
    hi, is modtool 2.0 support webgl? tq
     
  32. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Hello,
    I have another issue of the type https://forum.unity.com/threads/open-source-modtool-mod-support-for-unity.442185/page-3#post-8234055 but this time I haven't found a solution yet.

    The mod code

    Code (CSharp):
    1. placedVolcano = Instantiate(volcano, targetPlace, Quaternion.identity);
    results in the runtime log message

    Code (CSharp):
    1. Shader 'Standard': fallback shader 'VertexLit' not found
    2. MissingMethodException: Method not found: !!0 ModTool.ObjectManager.Instantiate<!0>(!!0,UnityEngine.Vector3,UnityEngine.Quaternion,string)
    3.   at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00020] in C:\build\output\unity\unity\Runtime\Export\Scripting\Coroutines.cs:17
    4. UnityEngine.MonoBehaviour:StartCoroutineManaged2(MonoBehaviour, IEnumerator)
    5. UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) (at C:\build\output\unity\unity\Runtime\Export\Scripting\MonoBehaviour.bindings.cs:112)
    6. AutoRun:repeatableProcessCompleted(Int32)
    7. AutoRun:Start()
    8.  
    9. (Filename: C:/build/output/unity/unity/Runtime/Export/Scripting/Coroutines.cs Line: 17)
    and the mod is not discernible as being run.

    But inside Editor the mod runs and no messages are printed to the log.

    Even only instantiating and setting the position afterwards has the same result.

    Note: even an explicit "GameObject." prefix is no avail.


    Addendum:

    Using the Instantiate method I provide through my dll file from my main application works.
    The issue remaining is

    Code (CSharp):
    1. Fallback handler could not load library ..._Data/MonoBleedingEdge/data-000001E3639E99E0.dll
    2. Shader 'Standard': fallback shader 'VertexLit' not found
    and meshes from loaded mods are not lit by (realtime directional) light.
     
    Last edited: Apr 8, 2023