Skip to content

MacOS Debug Support#86

Open
keyz182 wants to merge 3 commits intoGarethp:mainfrom
keyz182:mac
Open

MacOS Debug Support#86
keyz182 wants to merge 3 commits intoGarethp:mainfrom
keyz182:mac

Conversation

@keyz182
Copy link
Copy Markdown

@keyz182 keyz182 commented Mar 14, 2026

Fix macOS Debug Support

Got debugging working finally on Mac. I did use AI to help track this down, and make some of the changes.

I'm not sure if the build.gradle.kts changes are needed - they were for me to run things from gradle to test though.

What changed

  • RunConfiguration.kt
    • Handle launching Mac ".app" bundles, and removed dead code.
  • RunState.kt
    • Rewrote execute() to use ProcessBuilder directly on macOS/Linux — the IntelliJ process framework failed silently in the Rider sandbox's coroutine context; stdout/stderr redirected to /tmp/rimworld-doorstop.log (avoids the 64 KB pipe buffer deadlock that Doorstop's verbose MEMORY MAP output caused); added missing macOS resources (run.sh, libdoorstop.dylib, dnlib.dll, HotReload.dll); fixed resource filename .doorstop_config.ini → doorstop_config.ini; ported waitForMonoDebugServer() to bind InetSocketAddress("127.0.0.1", port) rather than ServerSocket(port) (on macOS, wildcard and loopback binds on the same port are distinct — wildcard never throws BindException even when Mono is already listening); times out with a clear ExecutionException instead of falling through to a generic Mono handshake error

Notes

  • Doorstop output (verbose MEMORY MAP / BIND_OPCODE dump) is preserved in /tmp/rimworld-doorstop.log for diagnostics


# LINUX: name of Unity executable
# MACOS: name of the .app directory
executable_name="RimWorldLinux"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed changing this to the correct default value. I know it's always set in the calling code, but since this OSX specific it makes sense to make the default make sense for OSX as well

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

debug_address="127.0.0.1:56000"

# If 1 and debug_enabled is 1, Mono debugger server will suspend the game execution until a debugger is attached
debug_suspend="1"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need for this specifically on OSX, or was this added mostly just for debugging purposes? None of the other OS' are configured to suspend until the debugger attaches, so if OSX doesn't actually require it it would be better to stay consistent with the other platforms. It'd also mean we don't need to add the waitForMonoDebugger() polling code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped - barking up the wrong tree.

// Doorstop's verbose stdout (MEMORY MAP + BIND_OPCODE dump) directly to a temp file —
// this avoids the 64KB pipe buffer deadlock without needing a drain thread, and
// preserves the output for diagnostics.
val gameProcess: Process? = if (OS.CURRENT == OS.macOS || OS.CURRENT == OS.Linux) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this change was made? Going through the rimworldState.execute() was working for Linux, wasn't it? And it looks like the process for Linux and OSX only really differs in that the files for OSX were wrong and the run.sh might be different.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More wrong-tree barking up of.

- Update executable name
- debug suspend to 0
- remove waitForMonoDebugServer
- revert processbuilder stuff
@keyz182
Copy link
Copy Markdown
Author

keyz182 commented Apr 16, 2026

There is a remaining issue - the mac "executable" being a folder in reality means the file picker doesn't work, and you have to copy/paste or type the path in instead. Workable as is, probably a follow up PR to sort that out. Maybe if on mac, just open a folder picker instead of file.

rimworldState.execute() fails silently in Rider's coroutine context on
macOS/Linux. Reverts to ProcessBuilder direct launch which is proven to
work. Also removes dead debugWithScript code path from RunConfiguration
(ProcessBuilder in RunState handles this), trims verbose comments, and
aligns doorstop_config.ini debug_suspend with run.sh.
// On macOS/Linux we must bypass rimworldState.execute() for two reasons:
// 1. CommandLineState.execute() has implicit EDT dependencies (console view creation)
// that fail silently when called from this suspend function's coroutine context.
// 2. On macOS, the 'open' command launches apps through launchd, which is SIP-protected
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment here to explain why this is required on mac for future reference

Comment thread build.gradle.kts
val file = file(f)
if (!file.exists()) throw RuntimeException("File ${file} does not exist")
})

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested without these changes and get

Image

So I believe they're needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants