C
C#3mo ago
Yunivers

Adding modding capabilities to my C# game

Here's a somewhat strange question that may just not have an answer. I'm working on a project where I'd like to have the game be moddable in sorta the same way Minecraft is, where the modder can create a Mixin class of an existing Minecraft class, and then add or replace code of that class. I'd like to go about it in a way that's natively supported by my game, which is also going to be open-source, and I'd prefer to not get an answer that's just "use interfaces and reflection", as that's not very freeing for what the user can actually change about the core game, only allowing additions to aspects of the game that use interfaces, rather than being able to add to or replace any code in the game. For the record, my game does not use a game engine, so suggestions about MelonLoader for Unity are off the table.
15 Replies
Pobiega
Pobiega3mo ago
Well, the way Minecraft is modded is via the mod loaders like forge/fabric etc, and they are actual source changes to a decompiled Minecraft
Yunivers
YuniversOP3mo ago
Yes, I know this lol. But it's the same concept.
Pobiega
Pobiega3mo ago
Sure. So write your own mod loader
Yunivers
YuniversOP3mo ago
Yeah but I'm essentially asking for how I'd do that.
Pobiega
Pobiega3mo ago
Honestly, take a look at forge or fabrics source to get an idea of the core concepts. You'll want any content in the game to be extendable so any place where you load resources into memory or build lists, it should be possible to add to them externally. As for how to load externally compiled dlls, that part you do handle with reflection and interfaces. https://github.com/Remora/Remora.Plugins is an example of how you'd do that You'd only put your mods init functions in the interface, and they'd interact with your built-in modloader within those methods
Yunivers
YuniversOP3mo ago
I was suspecting that they do edit bytecode, and I do have some experience in that front, but I doubt that's a route I can take natively in my app. Also I specified I didn't wanna take the reflection + interfaces route as it's not very versatile in what the modder could do with it. I'd want the modders to be able to edit anything they want with nearly zero limitations
Pobiega
Pobiega3mo ago
You misunderstand. You use reflection to load the plugins not what they do,
Yunivers
YuniversOP3mo ago
Still I don't think those are things I can do at runtime. I see what you mean now, a IPlugin interface that gets 'Assembly.Load'ed, but that doesn't really answer the question on how I'd get the plugins to actually be able to edit anything. Like say I have 48 characters that all implement a base character class, I'd want to be able to edit that character class, and each character individually. Also not using Mono lol Looks like the name MonoMod is kinda misleading, and it does work on framework Effect on game performance only when mods are enabled sounds like an okay trade-off to me. But idk how easy that would be to use both to account for in my game, and to mod for. So I'll have to look into it. and I don't really update .NET lol I'm already limited with the renderer I'm using lol Stuck on Windows 🙏 Well my game wouldn't really be moddable at all if I went with interfaces There's zero possibility to do what I'd want with that Unless I like, did 50 reflection calls every 5 lines of code But that also wouldn't allow for multiple mods at once if I did the... 50 reflection calls every 5 lines of code lol Yeah but there's no way to do pre/post method hooks in an elegant way unless your entire codebase is structured specifically around being able to do that. Which doesn't make for a very enjoyable game developing process. Best you could do is a fuck-load of static eventhandlers everywhere To be honest, at this point, slapping an MIT license on the source code and just letting it fly seems like the best course of option. It's a shame though, a mod-loader would've been so much cooler, alongside the ability to have multiple mods at once
Pobiega
Pobiega3mo ago
Have those characters be in some kind of registry, where they can be removed and replaced by mods. The classes should be open for extensions, probably via virtual methods etc, so a modder can base their replacement on one of the base characters
Yunivers
YuniversOP3mo ago
That's definitely a possibility with how my code is setup, but that's still only a small part of the game. Not very expansive in the grand scheme on things.
Pobiega
Pobiega3mo ago
I don't think you can have your cake and eat it too Either design your game from the ground up for modability, or just allow source/binary mods that will have compatibility issues
Aaron
Aaron3mo ago
adding those hooks everywhere is almost guaranteed to be worse for performance than RuntimeDetour is like I'd just use RuntimeDetour personally it does pretty much everything you need to with so much less work all you really lose is being able to (very easily) patch generics, which is a semi-rare want in the first place, and native arm64 support (but emulation still works fine, and that should be fixed at some point™️)
Evyr
Evyr3mo ago
is something like this https://github.com/Reloaded-Project/Reloaded-II not suitable?
GitHub
GitHub - Reloaded-Project/Reloaded-II: Universal .NET Core Powered ...
Universal .NET Core Powered Modding Framework for any Native Game X86, X64. - Reloaded-Project/Reloaded-II
wasabi
wasabi3mo ago
You make everything interfaces, and let plugins substitute the implementations. It ain't hard. The only time people use things like Detours, or Harmony, or other runtime mods, etc, is when the original app isn't built with a plugin model.
Aaron
Aaron3mo ago
:spinthink: I've never had that problem I don't even know exceptions are thrown on startup in mm
Want results from more Discord servers?
Add your server