Skip to content

convert to byond-scan and fix a lot of shit - #112

Merged
Absolucy merged 20 commits into
masterfrom
byond-scan
Oct 4, 2026
Merged

Absolucy merged 20 commits into
masterfrom
byond-scan

Conversation

@Absolucy

@Absolucy Absolucy commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

big pr here lol

closes #106

fixes #19
closes #27
likely fixes #44, now covered by a test
closes #65
fixes #87

byond-scan

  • auxtools finds BYOND's functions through byond-scan now. the sigscan module and signatures! macros are gone, use auxtools::find_recipe instead
  • supported builds: 516.1659 - 516.1688 on Windows, 516.1664 - 516.1688 on Linux. pre-516 is dropped
  • a build that's too old gets refused at init with a clear error. a newer one is still tried, and tells you what didn't match
  • MSRV is 1.88 now

linux fixes

  • proc hooks actually work. a few functions were being called the wrong way, which is why hooks never matched and things crashed
  • a library can call a proc it hooked itself and land in the hook, both with Proc::call and by name with Value::call. there's a test for it now. this is prolly what Libraries using auxtools are not able to call procs that the libraries themselves are hooked into, but only on linux. #44 was, but i couldn't run the test against the old code to prove it
  • List::remove works on every supported build (BYOND changed how that function takes its arguments at 516.1674)
  • List::len returns the right number
  • instruction hooking works
  • the debug server's variable name lookup reads the real name count. it was reading a pointer as the count, so a name that didn't exist walked off the end of the table

other fixes

  • a hook's return value doesn't leak when BYOND isn't going to read it. New() is the common case: every hooked New() that returned a string, list or datum leaked one reference per call
  • a hooked proc that BYOND calls with a completion callback has the callback run now
  • Proc::call passes the same proc_type BYOND's own direct calls do (2, was 0). with 0, a ..() with no parent proc could return garbage
  • set_bytecode doesn't overwrite the field next to the bytecode pointer anymore
  • call_datum_proc_by_name with a bad proc name gives you an error instead of killing the process
  • runtime errors inside a DM proc called from auxtools get reported normally, and DM try/catch works
  • a Proc doesn't go stale when BYOND moves its proc table, which happens whenever DM code makes a new verb with new /some/verb(dest, "name"). this was the random debugger crash in extremely high suspended procs force proc array reallocation #87. Proc::entry is a method now instead of a field, so proc.entry becomes proc.entry(). a Proc also can't be written out as a struct literal anymore, get one from Proc::find, Proc::find_override or Proc::from_id. it still can't be sent to another thread, same as before
  • a failed auxtools_init stays failed. every later call returns the same error and does nothing, instead of running setup again on top of the half-finished first try (that's where doubled procs and "Proc is already hooked" came from). any hooks the failed init already registered get removed too (an error in auxtools_init should prevent future auxtools_init calls from doing stuff #27)
  • byond_ffi_fn! works from other crates now. it was exported but pointed at a private module, so it never compiled outside auxtools
  • HookFailure and ProcHook are exported now. Proc::hook hands back a HookFailure, but other crates couldn't name the type, so they couldn't tell "already hooked" from "proc not found"
  • a hook that registers another hook doesn't panic anymore
  • auxcov finds its existing tracker now

debug server

  • evaluating an expression (watch, hover, debug console, breakpoint condition) that calls a proc with a breakpoint in it doesn't crash the game anymore. breakpoints are skipped while an expression is being evaluated
  • a debugger that disconnects doesn't crash the game the next time something pauses
  • you can attach again after detaching, without restarting the game. detaching also takes every breakpoint back out
  • a world shutdown or reboot hangs up on the debugger and frees the port without waiting for the debugger to close its end. that covers a debugger that connected a moment before the shutdown too, and a server on port 0 (where the OS picks the port). the next world can listen on the same port right away
  • a panic inside the debug server drops the debugger instead of killing the game. whatever it had paused is forgotten too, so the next debugger to attach can't read or write frames the game has already moved past
  • #dis doesn't remove and re-add the proc's breakpoints to read it
  • unsetting a breakpoint on a proc that doesn't exist replies with the right message type
  • setting a breakpoint again with no condition clears its old condition
  • requests that arrive in the same tick as a pause request aren't thrown away
  • step ids wrap around instead of overflowing after ~32k steps
  • calling enable_debugging twice is an error instead of running the server twice per instruction
  • a request claiming to be over 1 MiB closes the connection instead of being allocated
  • an /alist shows as /alist {len = N} and expands to its real key/value pairs. it used to show a /list with wrong or empty rows
  • a /vector expands to x, y, z, len and size, and a /pixloc to x, y, z, step_x, step_y and loc, and a /callee to proc, file, line, src, usr, args and caller. they used to be a single line with nothing to expand. a callee only expands while its proc is still running
  • the debug console's help text shows the real debug server version. it was hardcoded to 2.2.2
  • new live test: cargo run -p debug_test (needs BYOND_PATH). only run on windows 1685, 1687 and 1688 and linux 1687 so far

lists

  • List::is_list asks BYOND's own islist(), so verbs, filters, /alist etc. count as lists. it isn't a const fn anymore
  • /alist support: List::is_alist and List::alist_pairs, which gives every key and value in the order for (var/k in A) does. numbers are keys in an alist, not positions, so walking one with get(1..=len) doesn't work. get, set and len work on alists. auxtools finds BYOND's alist table at init now (alist_table_ptr and alist_table_count), so an unsupported build fails there if it doesn't match. you can't create an alist from Rust yet, only read and write ones DM gives you

raw types

  • the structs in raw_types were checked against the 516.1688 binaries and the byond-re notes, on both platforms
  • ExecutionContext is the real size now (152 bytes on Windows, 148 on Linux, was 164). everything after iterator_index was 4 bytes off. iterator_filtered_type is gone, use iterator_filter_type, iterator_filter_bitflags and iterator_kind
  • ProcInstance has override_depth
  • ProcEntry is 44 bytes and StringEntry is 32, they were each 4 short. StringEntry has encoding and is_proc_name
  • AssociativeListEntry.color is a u8 (same layout)
  • VariableNameIdTable has its two fields the other way round on Linux

tested on

  • windows: 1659, 1669, 1673, 1674, 1679, 1684 - 1688
  • linux: 1664, 1669, 1675, 1679, 1681, 1684 - 1688

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ccaaeac251

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread auxtools/src/raw_types/funcs.cpp
Comment thread auxtools/src/raw_types/values.rs
@Absolucy Absolucy added the enhancement New feature or request label Oct 4, 2026

@sohpeach sohpeach left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(lazy ai review)
Reviewed for regressions and newly introduced bugs only. I couldn't check the binary-level claims (calling conventions, struct offsets, recipe patterns) without the BYOND binaries, so those are taken as given. The rest looked right to me, including the hook result cleanup, the debug server reconnect/shutdown rework, and the auxcov type_id fix.

1. auxtools/src/lib.rs:85-98: one failed auxtools_init disables auxtools until the process exits, across world reboots and auxtools_full_shutdown.

I know the latch is deliberate (#27, and the new test says so). Two cases where it regresses something that worked before:

  • Failures that only apply to one world. A compile-time #[hook] whose proc isn't in the loaded .dmb fails with ProcNotFound. So does a library's own #[init(partial)] returning Err. Before, the next world retried partial init, so a reboot into a fixed .dmb (a TGS deployment, for example) recovered without restarting DreamDaemon. Now every later world gets the cached FAILED (...) until the process restarts.
  • auxtools_full_shutdown. It takes the library back to InitLevel::Full. With PIN_DLL on by default, the DLL and this OnceLock stay loaded, so a later init can never retry either.

The error path already runs clear_hooks() / clear_procs(), the same cleanup auxtools_shutdown does, so retrying after a failed partial init looks safe. One option is to latch only full-stage failures (symbol resolution, pin_dll, hooks::init, run_full_init) and let the shutdown entry points clear anything else. That would need something resettable, like Mutex<Option<String>>, instead of OnceLock.

2. Heads-up, not a bug: these public API removals will break downstream crates, so it's worth saying so in the PR description.

Removed: auxtools::sigscan and its #[macro_export] macros (signature!, signatures!, find_signature(s)!, find_signature(s)_result!, version_dependent_signature!, universal_signature!, …), auxtools::BYONDCORE, and auxtools_impl::convert_signature.

Also changed: Proc::entry went from a public field to a method, so Proc can no longer be built with a struct literal. List::is_list is no longer a const fn, and it now calls into BYOND, so it only works after init.

Anything that depends on this repo by git and uses these will stop compiling. find_recipe plus the byond_scan re-export covers what sigscan did. A pub const BYONDCORE: &str = byond_scan::MODULE_NAME; shim would cost nothing.

@Absolucy
Absolucy merged commit d76e783 into master Oct 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

2 participants