I have a game that defines many behaviours and will also eventually support plugins on those behaviours. Each behaviour has a class associated with it, derived from a common base. Right now I have a registration function that adds all these classes into a registry. I’m looking for a way that I can avoid this manual registration.
I have code that looks like this now:
Add<Behaviours.StdOneTenMult>( "stdOneTenMult");
Add<Behaviours.BlueBuddies>( "blueBuddies" );
Add<Behaviours.RagingRed>( "ragingRed" );
Add<Behaviours.FirstHandMult>( "firstHandMult" );
Add<Behaviours.Charity>( "charity" );
Add<Behaviours.PurityChips>( "purityChips" );
...
I’m wondering if there’s a way I can define a namespace, or assembly, and just iterate over the types in it looking for the ones that implement a given base or interface.
The above also manually sets an ID for the class, since I couldn’t figure out how to declare a “static” property on a class that is accessed in a generic fashion (kind of like a static-interface for a class). These are small enough objects, that if needed, I could just instantiate them and ask them for the id.
Namespaces are only a organisational thing. You can get a type’s assembly (System.Type.Assembly) and then enumerate it’s types: Assembly.GetTypes Method (System.Reflection)
Can potentially be pretty slow, and would miss any types that belong to other assemblies. It’d probably make more sense to cache these at editor time, using UnityEditor.TypeCache to do so, with some serialized type solution.
But I’m getting a strong whiff of code smell here. I imagine there’s more straightforward or cleaner ways to do what you want.
I’m open to other options, but this is really just a large list of behaviours that get added. Ah, note, this is not a Unity MonoBehaviour, it just shares a similar name, that might be misleading. From other genres, these could, for example, be the items in an RPG or base-builder. The types themselves have all the information they need to integrate into the game, along with the info on where they appear.
This same logic will extend to a plugin system, eventually. Modders will be able to write these behaviours and I need a way lot identify them dynamically from the mods as well.
I would personally author them all ahead of time as assets (like scriptable objects), and then just have a top-level scriptable object that references them all. You make things pretty flexible by taking advantage of [SerializeReference] as well.
A way to dynamically load these could be done via text assets as well, using JSON or any other similar/simple format, without the need to load code from users.
And honestly if your game is interesting enough, people will mod it anyway without needing to inherently support it yourself.
This can be done in .NET by using the AssemblyLoadContext class: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=net-8.0. This class can be used to create code that dynamically loads classes in other assemblies that implement a specific interface as plug-ins.
It cannot be done in .NET framework that Unity uses.
BUT, are you sure you want to do something like this? It will be a big security risk. If anybody can write code that is a plug-in to you game, that means it is very easy to write malicious code that does horrible things to anyone that uses it and the blame will be on you, because your game is responsible for not allowing mods that could be a security risk.
This kind of thing; dynamically loaded code that changes certain behaviors in a game, is usually done with mods that use a scripting language the game supports and not the language the game is written, because with a scripting custom language you can control what kind of code can be run.
1 Like
I didn’t tried this but this could be your solution for modding the game