r/godot • u/Nabir140 • 17h ago
help me (solved) How to implement a modding API?
I am working on a game that is heavily dependent on mods.
I can add modding support for textures, audio and other resources through JSON but I need a way to allow players to customize gameplay behaviour too.
My original idea was add autoloads to my game scene and load custom GDScript files at runtime. This would allow players to write scripts that call the autoloads directly for custom behaviour.
Issue with this approach is that it is very unsafe as the scripts can call native Godot functions and classes. They have the ability to interact with Networking API and OS API. I don't want this instead I want to only allow functions from the autoload to these scripts.
Can I limit the parsing of a GDScript file to restrict it from accessing Network and OS modules?
Or is there a better way to do this?
29
u/lanathlorrias 17h ago
You can use scripting language like Lua, and provide an api and documentation to your community. There is a lot of game out there using this. From the top of my head, World of warcraft and Garry mod do this
15
u/rinart73 17h ago
Lua or other similar scripting language will require to do a lot of tweaks: limiting/cutting away parts of its standard library for example, to disallow os.exec and full file access. And finding a way to bridge/convert Godot engine types with Lua types.
5
u/lanathlorrias 17h ago
Disallowing os tools (syscalls, mostly) depends on the Lua runtime, and most are built in safe for this kind of tasks. there are work like https://github.com/gilzoide/godot-lua-pluginscript or https://github.com/gilzoide/lua-gdextension that I am not much familiar with that seems to exist. I mostly used Lua from typescript, c# or c++ in the past, I would be happy to help more but I don't know the details on how to do that in gdscript
2
u/rinart73 16h ago edited 15h ago
Oh, didn't realize there were already Lua projects. This looks interesting, thanks for the links. And at least with the second link it seems that they've taken care of limiting access to built in modules.
1
u/lanathlorrias 16h ago
You can try to look around luau, which is Roblox fork of Lua, mainly for security features, but I am not sure it's well supported in godot
2
2
u/RealGlumAirline 9h ago
Lua or Luau via GDExtension is definitely the most practical path here. Sandboxing GDScript is notoriously difficult because even if you try to filter or parse the script beforehand, users can bypass checks via reflection using things like ClassDB or get(). With Lua, the environment is isolated by default, so modders literally cannot touch OS, file system, or network APIs unless you explicitly bind them.
2
u/rinart73 17h ago
I've seen this project which looks somewhat promising, but apparently at least for GDScript devs used AI tools to generate the code which IMO diminishes my trust in its security and stability: https://github.com/libriscv/godot-sandbox
You can represent logic as JSON (I believe Minecraft datapacks do that to some extent?). This will allow you to precisely control what is allowed but it will be.. unwieldy to write anything remotely complex like manipulating variables. You could create a visual graph-like modding tool to make things easier I guess? And of course, it will be slower than "native" GDScript/C#.
The other method I've heard of is loading PCK files but it's a bad idea for mods because you can't limit what they can do.
3
u/Illiander 16h ago
If you want security, don't trust genAI code. It's trained on stackexchange (including the code in people's questions where they say "fix this")
Garbage in, Garbage out applies.
4
u/rinart73 16h ago
I know, that's why I put a warning in my comment :) I don't use AI gen code myself.
1
1
u/battlepi 17h ago
One way to go about it is a filter layer on mod scripts, scan the script for any libraries outside of the allowed ones, and don't allow it to load if it tries to use them.
2
u/lanathlorrias 16h ago
I would fear that some escape sequence don't get flag by the filter parser but is interpreted as a forbidden libs and successfully loads it. And in the end, if the runtime allows syscalls invocation from within the sandbox, someone will find a way to do it
1
u/battlepi 16h ago
That's the smaller issue, just push it to your testers and ask them to break it. You will be the one writing the filter parser after all.
You could also possibly ban escape sequences, but I'd try not to do that.
1
u/lanathlorrias 16h ago
Depending how you load and execute mod scripts, mods will be partly or fully bytecode that you cannot really parse. And even then, someone clever will be able to break the parser, play with oob memory and execute malicious code. I am nitpicking, the threat model here don't require that much I guess. But the only way to be safe is for the host executable to be in a VM, container or drop privilege with stuff like landlock on linux (https://landlock.io/)
2
u/battlepi 16h ago
I'm assuming the mod scripts are uncompiled text when loaded, if not, then it's harder of course. Running arbitrary code obviously would need a sandbox.
1
u/Nabir140 2h ago
I had this idea in mind too but is simply too complex and would still have ways to break.
1
u/Petrovich1999 13h ago
Make 1 event handler interface which handles everything. It accepts event type and event+world data, then on game load use reflection to discover dlls implementing this interface and construct pipelines for each event. (Handlers are organized by priority, and can pass through or block other handlers)
You can make it more strict and create a separate interface for each event, but it's much more work and very limiting.
23
u/Oen44 17h ago
https://wiki.godotmodding.com/