• If you have a mod, tool or prefab, please use the Resources section. Click Mods at the top of the forums.

DMT Modding Tool

Status
Not open for further replies.
Just checking in to say this to Hal: AWESOME job, as usual. You're the boss! See ya around!
Hey Morte ^^ good to see you. How's things? If you get some time come hang out on Guppy's discord server. I'm usually lurking in the DMT section

 
Hello,

I use 3 IHarmony patches. Each one calls harmony.PatchAll() in its Start() method. As a consequence, all 3 patches are applied 3 times !

How can I make sure all 3 patches only get applied once ? Should I call harmony.PatchAll() a single time (but how to ensure all patches have been seen) ? Is there a Patch() method that would apply the current IHarmony and not the other ones ?

Thank you !

The call to PatchAll() is:

var harmony = HarmonyInstance.Create(GetType().ToString());
harmony.PatchAll(Assembly.GetExecutingAssembly());


Edit:
- Using harmony.Patch(original, null, new HarmonyMathod(postfix)); did not apply the patch.

- Using a global bool flag to ensure PatchAll is called once does the trick.

- I checked that the problem only occurs within one mod. Calling PatchAll from one mod does not reapply patches in other mods.

Using a global bool flag like I did is enough only because the problem does not happen cross-mod. I feel the single-call check should be moved to the DMT library, because other users might run into the same mistake (Am I the only one tricked here ?). I can't see a use case where we want to apply patches multiple times (even then, it could be 2 different methods).

 
Last edited by a moderator:
Unhandled Exception: System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at LocalisationTable.ReadFromStream(BinaryReader br, String path)
   at LocalisationTable.Load(String path)
   at DMT.Tasks.LocalisationPatch.PatchTextFile(PatchData data, String sourcePath, String destPath, String patchFilePath)
   at DMT.Tasks.LocalisationPatch.Patch(PatchData data)
   at DMT.PatchData.Patch()
   at DMTViewer.Program.Main(String[] args)

process exited with error code -532462766
 

not sure what i'm doing wrong but i cant get any mods/modlets to build correctly, I have uninstalled and reinstalled the game. i have verified the file integrity, and i cant figure it out. I'm new to modding 7 days to die and don't know what i'm doing.

 
FrostX1 said:
Unhandled Exception: System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at LocalisationTable.ReadFromStream(BinaryReader br, String path)
   at LocalisationTable.Load(String path)
   at DMT.Tasks.LocalisationPatch.PatchTextFile(PatchData data, String sourcePath, String destPath, String patchFilePath)
   at DMT.Tasks.LocalisationPatch.Patch(PatchData data)
   at DMT.PatchData.Patch()
   at DMTViewer.Program.Main(String[] args)

process exited with error code -532462766
 

not sure what i'm doing wrong but i cant get any mods/modlets to build correctly, I have uninstalled and reinstalled the game. i have verified the file integrity, and i cant figure it out. I'm new to modding 7 days to die and don't know what i'm doing.
Make sure you have the latest version of DMT.  DMT no longer handles localization like it did previously.  That's done by the game now.

 
Hello,

I use 3 IHarmony patches. Each one calls harmony.PatchAll() in its Start() method. As a consequence, all 3 patches are applied 3 times !

How can I make sure all 3 patches only get applied once ? Should I call harmony.PatchAll() a single time (but how to ensure all patches have been seen) ? Is there a Patch() method that would apply the current IHarmony and not the other ones ?

Thank you !

The call to PatchAll() is:

var harmony = HarmonyInstance.Create(GetType().ToString());
harmony.PatchAll(Assembly.GetExecutingAssembly());


Edit:
- Using harmony.Patch(original, null, new HarmonyMathod(postfix)); did not apply the patch.

- Using a global bool flag to ensure PatchAll is called once does the trick.

- I checked that the problem only occurs within one mod. Calling PatchAll from one mod does not reapply patches in other mods.

Using a global bool flag like I did is enough only because the problem does not happen cross-mod. I feel the single-call check should be moved to the DMT library, because other users might run into the same mistake (Am I the only one tricked here ?). I can't see a use case where we want to apply patches multiple times (even then, it could be 2 different methods).


Hi Umbrella,

It's up to the modder to implement the patch call, each mod is split into it's own dll for this reason. You wouldn't want DMT making assumptions about running the patches as the modder may want to do something unusual / bespoke. 

If you're in control of the mod you can just remove the other two patchall calls. Each patch doesn't require a patchall call, one call grabs all the patches in the given assembly (dll file). 

Have a look at the bootstraping section on Harmony for how to run individual patches and for detecting already run patches. https://github.com/pardeike/Harmony/wiki/Bootstrapping

Cheers,

Hal

 
Hi Hal9000, thank you.

I understand and agree with your answer. But still:

If you're in control of the mod you can just remove the other two patchall calls.
The problem is that each of my file (in the same mod, each implementing IHarmony and requiring someone to call PatchAll once) then needs to make assumption on other file. If I remove PatchAll from one patch, I assume another single patch will apply PatchAll. From a design perspective, it does not make much sens. From a practical perspective, whenever you remove/add some patch to your harmony folder, you need to check for the single call.

You wouldn't want DMT making assumptions
Agreed, but honestly 99% of modders want to apply each of their patch once. What I suggest is the DMT tool to have an extra method PatchAllOnce, so exotic use cases can do whatever they were doing before, but most users can just call PatchAllOnce() in each of their patch and no longer worry about if it's already done, or what happens when they remove a patch file.

Could you add this extra method to the tool ? I know I will use it for every mod I make (and I still have found no use case where I would not)

Code:
public static class Harmonys {
    private static bool Applied = false;
    public static void ApplyOnce(HarmonyInstance harmony, Assembly assembly, Type patch) {
        /* Important: the call to Assembly.GetExecutingAssembly() need be done by the caller
        TODO: check method is patched when skipping ?
        */
        Debug.Log(String.Format("Harmonys.ApplyOnce {0} -> {1}", patch.ToString(), Applied));
        if (Applied) return;
        Debug.Log(String.Format("Harmonys.Applying {0}", patch.ToString()));
        harmony.PatchAll(assembly);
        Applied = true;
    }
}
 
Hi Umbrella,

I think this is where you're going wrong:

The problem is that each of my file (in the same mod, each implementing IHarmony and requiring someone to call PatchAll once)


The IHarmony interface isn't for each patch, it's for a patch manager class. So you'd define and implement the interface once for the mod (usually, though more complicated patching can use it multiple times) and that then controls how the patches are applied (usually with a PatchAll or something more complicated if needed). That's what I meant by the modder being responsible for how the patching is applied. 

Then when the game starts each mod's IHarmony interface is called and that's what drives your changes. DMT makes no assumptions on how you're going to do that. 

Does that make sense? 

Cheers,

Hal

 
Please can somone tell me how to get this working on a hosted server ?

Ive got it working fine on my dedicated server and join with single player just fine but when i upload the 3 .dll files to the server it goes bonkers and wont start :-) please help

 
hmm.. seems Patcher Skripts (IPatcherMod, not IHarmony) cannot be compiled, because Cecil is not available Mono. But i see a Mono.Cecil.dll in the dmt folder....

 
Last edited by a moderator:
okay, seems to work if i copy the .dll from the DMT directory to the mod directory where i have the .cs files.

But another question came up:

I am wrinting a IHarmony Patch, which accesses some variables inside a class, which are privater and have no getters/setters. So i wrote an IPatcherMod, to turn these into public variables instead.

BUT now comes the crux:

The IHarmony script can't compile, because the IPatcherMod is called at runtime, while at compiletime the variables are still public, and the dmt compiler prevents the compilation because of that reason....

 
sparrow8332 said:
Please can somone tell me how to get this working on a hosted server ?

Ive got it working fine on my dedicated server and join with single player just fine but when i upload the 3 .dll files to the server it goes bonkers and wont start 🙂 please help
 Post your log file from the server that's erroring

Shiana said:
okay, seems to work if i copy the .dll from the DMT directory to the mod directory where i have the .cs files.

But another question came up:

I am wrinting a IHarmony Patch, which accesses some variables inside a class, which are privater and have no getters/setters. So i wrote an IPatcherMod, to turn these into public variables instead.

BUT now comes the crux:

The IHarmony script can't compile, because the IPatcherMod is called at runtime, while at compiletime the variables are still public, and the dmt compiler prevents the compilation because of that reason....


There's definitely something strange in your setup. IPatcherMod is used by DMT and shouldn't be in the server files. They are used during the DMT build rather than runtime of the game. Cecil should not be included with the dlls that end up in the server folders. 

You don't need to change the field accessor type, you can get the value in the Harmony patch using reflection

Cheers,

Hal

 
Shiana said:
okay, seems to work if i copy the .dll from the DMT directory to the mod directory where i have the .cs files.

But another question came up:

I am wrinting a IHarmony Patch, which accesses some variables inside a class, which are privater and have no getters/setters. So i wrote an IPatcherMod, to turn these into public variables instead.

BUT now comes the crux:

The IHarmony script can't compile, because the IPatcherMod is called at runtime, while at compiletime the variables are still public, and the dmt compiler prevents the compilation because of that reason....
For a Harmony patch, you can access a private variable from the same class by adding it to the parameter list, with 3 leading underscores

public static void Postfix(XUiC_ItemStack __instance, bool ___bLocked, bool ___isDragAndDrop)


In the XUiC_ItemStack class, there's a private variable:  bool isDragAndDrop

If you want to change its value, you can add ref to it:   ref bool ___isDragAndDrop

 
argh..... why did you make it soo easy! i am always looking for the hard path.... 

ddbb7228da54396d959bdc34d7f7b781.jpeg


 
Last edited by a moderator:
Hey guys,

DMT v2 is now released. The major change is it now uses Harmony v2 instead of v1. This is a breaking change so I've bumped the DMT release to v2 as well. There are some upgrade processes you'll need to do for your mod. A lot of them can be done by DMT by using the "Attempt Hamony Auto Update" checkbox when building 

image.png

Further details of the updates required can be found here: https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0 

We've also removed the requirement for the mod.xml. Now both vanilla and DMT uses the ModInfo.xml file. Again, there is an auto-update function built in that should serve most cases. Once the update is done you should delete the mod.xml file to remove any warnings that are generated in DMT. 

Cheers,

Hal

 
Last edited by a moderator:
Thanks HAL9000

It worked perfect for me to compile the belt mod.

Spherei Core y legacy distain Terrain,they cause an error when starting the game, it does not even reach the menu, I hope that spherei fixes it and that it works for A19.

 
Last edited by a moderator:
Do Clients and the Server both need DMT 2.0 or just the Server? Regards
It depends on the mod. If it's a server only mod then the clients don't need it but anything that has changes on the client (new assets, code or xml changes) then the players also need to apply the mod

 
Status
Not open for further replies.
Back
Top