Modding system: settings, hot-reload, dependencies, and notifications#2001
Modding system: settings, hot-reload, dependencies, and notifications#2001DevL0rd wants to merge 12 commits into
Conversation
|
Also if you ever have GitHub secrets I would really recommend NOT running these checks / builds for PRs. People can abuse that, and say force GitHub secrets to be printed out into the GitHub actions. If you ever use any later. You can however run these checks only when someone approves the PR. I would recommend nipping that soon so no one can abuse your GitHub actions <3 Even if you don't have secrets right now, I would still recommend it. <3 For now it was good to see that apple and android build doesn't like the mod loader haha, so I will fix that right now. Love yah fellow humans. Thanks for the smiles :) |
|
This feature set looks INSANE! I'll go through it with PJB when I'm not dead asleep, but awesome job it seems so far! |
haha thanks. I've been a software engineer for 15 years now, but I'd like to disclose use of claude for organizing and execution, and hope it doesn't detract from my care and experience I put into my code. While I kept the code clean organized and standardized, and planned the architectural changes, claude did the heavy lifting. I hope this is acceptable. If there is anyway I can help more on mods system or own that bit, or manage helper library side of things—specifically, building out a shared toolkit of mid-level abstractions to eliminate boilerplate for common game-side interactions—let me know, I will be doing it for myself anyways, and don't mind offloading that kinda work when I have time. Anyways PJB clearly knew what was up when starting with mod integration. If I'm not stepping on toes and PJB finds it useful, I certainly have more to add to the mod system, and things I'd wanna change like how hot reload re extracts. But if you find this kind of help useful, let me know and I'll continue |
No secrets in the repository, I keep our release configs totally separate because of this!
I was under the impression that iOS support would be impossible due to code signing, is there a workaround? I just merged latest main into the mods branch, so would you mind rebasing just your commits on top of that? It will fix the diff so we can review. Thanks for the work on this so far! |
Asset mods are still an option. |
- Add define_settings/setting_get/setting_set to the mod API; the loader stores typed settings per mod, persists them + enabled state in mods/.config, and generates a schema so disabled mods still show their settings - Replace the per-mod enabled CVar with config.json; add live enable/disable - Add a file-watcher (inotify/Win32) hot-reload that reloads a single native mod in place when its library changes, plus refresh() for newly added mods - Add a master-detail 'Mods' tab to the settings window (mod list + Refresh, per-mod enable toggle and auto-generated setting controls)
- Add an FSEvents file watcher for hot-reload on macOS (+ link CoreServices) - Remove the Mods button from the prelaunch/home menu (the Mods settings tab is the primary mod UI now) - Remove the bundled tools/cat_mod example (relocated to its own repo)
- Replace the per-mod-tab Mods window with a master-detail UI (list + Refresh on the left; description, Enabled toggle, and settings on the right), still rendering a mod's own custom panel - Remove the Mods tab from Settings; open the Mods window from the title screen and the in-game quick menu instead
Enable/disable is now a ConfigVar<bool> the loader registers and persists via config::Save(), like the game's own settings. The per-mod config.json holds only setting values (no enabled key), so the settings system can never clobber the enabled flag. The CVar key embeds the mod id verbatim (no escaping).
- mod.json gains 'priority' (load order, lower first) and 'dependencies' (mod ids); mods load dependency-first then by priority (topological sort), cycles flagged. A mod won't enable until its dependencies are installed + active. - Mods UI: dedicated window lists each mod's dependencies + status, greys out the enable toggle when deps are unmet, and tags failed mods '[failed]'. - On-screen toasts for hot-reload success and for load/enable/reload/crash errors; a failed hook install now marks the mod failed instead of silently running with a dead hook. - Build the game with -fno-partial-inlining when code mods are enabled so hooked functions keep a prologue funchook can patch (fixes silent hook failures). - Failures never disable a mod (it stays enabled and retries on rebuild/relaunch); the watched library path is recorded before load so even a failed load retries.
- Gate RTLD_DEEPBIND on the macro, not __linux__ (Android defines __linux__ but Bionic has no RTLD_DEEPBIND; macOS/iOS lack it too). - Drop the in-game-TU CoreServices/FSEvents watcher: its header collides with the game headers (Carbon MachineExceptions) and FSEvents is macOS-only. macOS/iOS fall back to no file watcher (mods still load + Refresh works).
- macOS x86_64: pre-set FUNCHOOK_CPU from the Apple target arch. funchook picks its backend from the build host's arch (CMAKE_SYSTEM_PROCESSOR), which is wrong when an arm64 runner cross-compiles to x86_64 (it built the arm64 backend). - iOS: quote the MACOSX_BUNDLE_* / entitlement values in set_target_properties so an empty bundle var on iOS doesn't make the call arg-count invalid.
Re-add Apple hot-reload using kqueue (EVFILT_VNODE) instead of FSEvents: it's plain BSD (no CoreServices/Carbon header clash) and works on both macOS and iOS. Watches the mods dir, each mod entry, and files within mod folders; an EVFILT_USER event wakes the kevent wait for clean shutdown.
funchook's arm64 trampolines call the __clear_cache libcall, but clang's compiler-rt builtins aren't linked on iOS/tvOS (macOS provides it). Supply it via sys_icache_invalidate, guarded to non-macOS Apple to avoid a duplicate symbol.
OK awesome! So, I went ahead and cherry picked and re-based and did the whole dance. all looking good now! So I have my main machine on Linux, cause I want grey hairs as fast as possible, have a Windows VM with VFIO pass-through so those 2 cases are tested. But yeah i'm not really sure about Apple side of things, how do you guys validate builds on apple devices? Anyways, thanks for reviewing guys! |
|
Quick additions, I added some simple changes to UI and menu bar so mods can add new menu items. Needed it for my experiment doing multiplayer mod. And will likely expand more on this when you decide on how mods is going to look. |
Hello @PJB3005 Love your work <3
I was building my own modding system, and then saw a little late that you already started one! I saw we had the exact same methods in mind to implement modding! So i scrapped my branch and went ahead and put my upgrades here since your branch seemed a bit more progressed and cleaner.
I hope you find this helpful and that i'm not stepping on toes here. There are so many file changes because I merged current main into your mods branch, sorry if that makes it a little messy to track.
I am PR-ing directly to your wip mods branch, and have 2 mods of my own running on this. and I ported your cat mod on over also! I retained the menu system you were tinkering with in there in the mods menu also.
Here is a screen shot:

A few example mods and your ported cat mod:
https://github.com/DevL0rd/Dusklight-Mortal-NPCs
https://github.com/DevL0rd/Dusklight-Bottled-NPCS
(Let me know, i can transfer this repo to you and you can use the layout and deploy scripts)
https://github.com/DevL0rd/Dusklight-Chloe-The-Cat
Changes:
mod.jsongainsdependencies(mod ids) andpriority. Mods load dependencies-first then by priority (topological sort); cycles are flagged; a mod won't enable until its dependencies are active. The UI lists each mod's dependencies and their status.-fno-partial-inliningwhen code mods are enabled, so hooked functions keep a prologue funchook can patch.Untested: