Jump to content
HAL9000

DMT Modding Tool

Recommended Posts

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

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

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).

 

 

Edited by Umbrella
Answer and tool suggestion (see edit history)

Share this post


Link to post
Share on other sites

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.

 

Share this post


Link to post
Share on other sites
On 5/2/2020 at 11:27 AM, 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.

Share this post


Link to post
Share on other sites
On 4/29/2020 at 10:49 AM, Umbrella said:

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

Share this post


Link to post
Share on other sites

Hi Hal9000, thank you.

 

I understand and agree with your answer. But still:

Quote

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.

 

Quote

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)


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;
    }
}

 

Share this post


Link to post
Share on other sites

Hi Umbrella,

 

I think this is where you're going wrong:

On 5/22/2020 at 1:22 PM, Umbrella said:

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

 

 

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
Posted (edited)

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....

Edited by Shiana (see edit history)

Share this post


Link to post
Share on other sites

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....

 

 

Share this post


Link to post
Share on other sites

  

On 6/1/2020 at 6:42 AM, 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

 

On 6/7/2020 at 6:47 PM, 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

 

Share this post


Link to post
Share on other sites
On 6/7/2020 at 2:47 PM, 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

Share this post


Link to post
Share on other sites
Posted (edited)

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.thumb.png.fe56761c29ae6b446ad11cf8dcb19523.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

Edited by HAL9000 (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

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.

Edited by Gouki (see edit history)

Share this post


Link to post
Share on other sites
On 7/3/2020 at 4:22 PM, nickuk01 said:

Does the 7D2D launcher automatically run DMT mods also?

 

Yes

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...