Background info - For the game 7 Days To Die, there is a C# wrapper that implements the Harmony API, which allows us to intercept the game's function calls, as well as changing the IL instructions themselves.

I originally used the Transpiler functionality to remove a condition that's used in two checks. Which was easy enough, as I just needed to remove three instructions. Here's a screenshot showing them:

On the left is the old code, which was easy enough to modify. I just needed to remove the instructions at indexes 79, 80, and 81. Which changes the C# code from:

this.cmds[1].enabled = (_world.IsEditor() && flag);


this.cmds[1].enabled = (flag);

Which worked perfectly. However, the DLL was changed in an update. The C# code is the exact same, but the IL instructions differ at this very last condition check. And I can't quite wrap my head around it.

The original was easy enough. IL 79 prepares something for the next function call, IL 80 makes the call, and IL 81 jumps past the next couple of instructions if it returns false. In ASM, the three instructions would basically be pop (call class' function via a pointer), cmp (check the boolean result), and jz (jump if false).

But the updated IL instructions on the right don't make any sense to me. There's no branch, there's no jump. How do I work with that to remove the _world.IsEditor() condition?

Edit: Pastebin of the C# function


It looks like that previous code had an optimization done, so that if the left-hand side value was evaluated as false the right one was not evaluated at all in the && operation as it would never result in true anyway and false can be used directly.

Currently there's no such code but you can clearly see the and being done, preceded by ldloc.0. There's a missing code from the beginning of this function but if local variable at index 0 is your flag you can remove those two instructions (so lines 81 and 82). From the code it looks like on the stack there should already by also a 1 so that the instruction that stores the value with stfld will work. If not you could add a ldc.i4.1 instead of those two that you removed.

| improve this answer | |
  • Your solution worked, thanks a bunch for that. Now I'm trying to wrap my head around it, but it is a bit too abstract for me. I get that flag was put onto the top of the stack as 1, which is the same as true, earlier in the function. But at the end of the code, which is the part to be changed, there's several other instructions pushing to the stack as well, but no popping from the stack. Do the instructions just take the variable from the top of the stack, basically as an automatic push before that instruction is processed? – FiftyTifty Dec 7 '19 at 19:15
  • 1
    yes, IL is stack-based so each instruction takes what it needs from stack and push back the results on top. – Paweł Łukasik Dec 7 '19 at 19:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.