C# Modders: have you run rimworld in a debugger?

Started by CannibarRechter, October 04, 2017, 07:56:01 PM

Previous topic - Next topic

CannibarRechter

Hi,

Has anyone been successful running RimWorld in the debugger, and, for example, being successful at setting breakpoints and the like in their own mod code?

If so, what are the elementary steps involved?

Thank you
CR All Mods and Tools Download Link
CR Total Texture Overhaul : Gives RimWorld a Natural Feel
CR Moddable: make RimWorld more moddable.
CR CompFX: display dynamic effects over RimWorld objects

DrMrEd

This was how I first started trying to tackle source code when I looked into modding. However, RimWorldWin.exe is a native .exe, not a .NET assembly, so there's no decompile/recompile to debug option. Also, it's not a debug build, so no debug symbols, which means even if you manage to attach a debugger to the running process, you'll get very limited info.

Sadly without a debugger available, I've resorted to the archaic printf equivalent of debugging. Log.Message() everywhere...

CannibarRechter

This is what I do. To be clear, I'm okay not being able to debug the Rimworld core (even though I do have the source), but rather I want to set breakpoints in my own Assembly, check out variables, and so forth.
CR All Mods and Tools Download Link
CR Total Texture Overhaul : Gives RimWorld a Natural Feel
CR Moddable: make RimWorld more moddable.
CR CompFX: display dynamic effects over RimWorld objects

Kiame

#3
Quote from: CannibarRechter on October 12, 2017, 02:50:45 PM
This is what I do. To be clear, I'm okay not being able to debug the Rimworld core (even though I do have the source), but rather I want to set breakpoints in my own Assembly, check out variables, and so forth.

Modding would be SO MUCH EASIER if breakpoints in the assemblies was possible!

As DrMrEd mentioned I've gone back to the stone age with
#if DEBUG
    Log.Warning(debug message);
#endif

I want to explore using "Conditional" to make the code cleaner to read

[Conditional("DEBUG")]
public static void LogWarning(string message)
{
    Log.Warning(message);
}

Then in the code it's just
    LogWarning(debug message);

w/o the #if/#endif everywhere, though it does 'bloat' the dll as all the messages are compiled, just not executed

Nightinggale

Quote from: DrMrEd on October 12, 2017, 01:15:03 PM
This was how I first started trying to tackle source code when I looked into modding. However, RimWorldWin.exe is a native .exe, not a .NET assembly, so there's no decompile/recompile to debug option. Also, it's not a debug build, so no debug symbols, which means even if you manage to attach a debugger to the running process, you'll get very limited info.
I'm not sure this statement is correct. Civilization 4 was released with an EXE file and a DLL file. Later the source code for the DLL was released, which allows mods to replace the DLL. This created the same issue and over the years the modding community have figured out how to handle the issue. Now the DLL can be compiled with asserts, symbols, breakpoints, ability to debug and profile etc, just like if you build your own EXE. Since the EXE is native and without symbols, that one can't be debugged (well you can if you are crazy good with assembler), but it works just fine with the DLL itself, which is likely what any modder would like to see anyway.

It should be noted that Steam has an anti-cheat system, which can kill games if it detects anything messing with memory, because it could be a see through wall hack or extra money or whatever. Sadly it triggers on connecting a debugger as well. In other words the steam version should be avoided if you want to try your luck with a debugger. This brings up an interesting question: do you have to buy the game again if you have the steam version?

Quote from: Kiame on October 12, 2017, 03:06:16 PMAs DrMrEd mentioned I've gone back to the stone age with
#if DEBUG
    Log.Warning(debug message);
#endif
In C++ you would be able to write it like this:
#ifdef DEBUG
#define DebugLog( X ) Log.Warning( X )
#else
#define DebugLog( X )
#endif

This will allow using DebugLog(debug message) in the code. If DEBUG is set, then the precompiler will replace all DebugLog with Log.Warning. However if DEBUG is not set, then it will realize that DebugLog is a defined flag without contents and it will just remove it before the compiler starts, hence the name precompiler. The result is that a resulting non-DEBUG DLL will not change just because you add more DebugLog statements.

Somehow I suspect the same would be possible in C#, though I don't know how, at least not offhand.
ModCheck - boost your patch loading times and include patchmods in your main mod.

Kiame

#5
Quote from: Nightinggale on October 12, 2017, 11:38:33 PM
#ifdef DEBUG
#define DebugLog( X ) Log.Warning( X )
#else
#define DebugLog( X )
#endif

This will allow using DebugLog(debug message) in the code. If DEBUG is set, then the precompiler will replace all DebugLog with Log.Warning. However if DEBUG is not set, then it will realize that DebugLog is a defined flag without contents and it will just remove it before the compiler starts, hence the name precompiler. The result is that a resulting non-DEBUG DLL will not change just because you add more DebugLog statements.

Somehow I suspect the same would be possible in C#, though I don't know how, at least not offhand.

(Going off topic now ;) )

I believe in this case it really comes down to the compiler. A decent one would probably remove the actual call to DebugLog(x) if DEBUG is not defined since it would try to in-line it which would produce nothing. Some compilers, though, would still have the cpu create a new scope, enter the empty method, then leave the scope.

For C# it's a bit stricter... you may be able to define an unsafe area and do what you've outlined but that's becoming more hack-ish than i'd recommend C# developers go  :D
Thus the Conditional recommendation. The method is compiled but will be skipped at runtime so it's only adding bloat in size and not execution speed/efficiency -- when i say 'bloat' i'm saying maybe a few hundred bytes larger