Duplicate Mod Scripts Causing Errors
Description
When creating duplicate mods with identical script names, errors occur during runtime. This issue affects both C# and GDScript mods.
Steps to Reproduce
- Duplicate the
res://Mods/Example Moddirectory tores://Mods/Example Mod 2. - Modify the
idin themod.jsonof the new mod fromexample_modtoexample_mod_2. - Run the game.
Expected Behavior
Both mods should load and execute without errors, printing unique greetings.
Actual Behavior
C# Mods
-
First Kind of Error:
An item with the same key has already been added. Key: res://valkyrienyanko/example_mod/Mod.cs- Points to: ModLoader.cs#L74
-
Second Kind of Error:
Assembly with same name is already loaded- Points to: ModLoader.cs#L73
GDScript Mods
-
Console Output:
Loading C:/Users/VALK-DESKTOP/Documents/_Godot Projects/Template/GodotProject/Mods/Example Mod/mod.pck for example_mod Loading C:/Users/VALK-DESKTOP/Documents/_Godot Projects/Template/GodotProject/Mods/example_mod_2/mod.pck for example_mod_2 Hello from Mod 1 Hello from Mod 1- Expected:
Hello from Mod 1andHello from Mod 2 - Actual:
Hello from Mod 1printed twice
- Expected:
Observations
- C# scripts with the same name in different mods cause errors.
- GDScript mods with the same script names also exhibit unexpected behavior.
Proposed Solutions
-
Switch to GDScript for Mods:
- If GDScript does not have the same naming conflict issues, consider using GDScript for modding.
-
Refactor C# Mod Loading:
- Modify the mod loading logic to search for the first DLL file in the mod folder and load it. This might resolve DLL naming conflicts.
Additional Notes
- Changing DLL names did not resolve the issue.
- Test files provided:
Relevant Issues
- https://github.com/godotengine/godot/issues/75352
Conclusion
The current mod loading mechanism needs to be revised to handle duplicate script names across different mods effectively. Switching to GDScript or refactoring the C# mod loading process are potential solutions to address this issue.
Upon further investigation I have found that LookupScriptsInAssembly(...) is adding each script as a key based on its script path instead of its fully qualified name (namespace + class name).
So res://ExampleMod/valkyrienyanko/Mod.cs from example_mod_1 would conflict with res://ExampleMod/valkyrienyanko/Mod.cs from example_mod_2 even though each Mod.cs is in its own unique namespace.
So the obvious thing to test here would be to change the path to include a unique modders name. E.g. res://ExampleMod/bob123/mod.cs
I have yet to test this to see if this is really what is happening.
But do we really like this way? Is there another away to approach this? Maybe we can create our own LookupScriptsInAssembly(...) method? Is that even possible?
I think it is not designed for modloader.
https://github.com/godotengine/godot-docs/pull/8486