Sign in to follow this  

Enums and their extendability via mods

This topic is 474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am writing a game (in cocos2d/c++) and I am trying to make it extendable with mods. I am not using a scripting language yet, but even if I added it in the future, my main plan for modding the game is that I will publish parts of the API and let people link dynamic libraries containing their mods.

 

I use enums for multiple purposes in my project. For example list of input actions (run_forward, jump, ui_up, ui_left, use, etc.) is an enum. I can easily imagine, that modders might want some extra input actions for functionalities of their mods.

 

I know that it is not possible to (correctly) extend enums when linking a dynamic library. I would like to read about as many concepts that solve this as possible before designing this mechanism for my game

 

I have some ideas (maybe some static instances of a template, which will be instantiated when linking the dynamic library because they are static and they will add self to some container during this instantiation and they will obtain an unique id during this process). I woudl want it to be easy to use and preferably easy to understand, because I have more important problems to deal with in my game systems than are enums.

 

I do not need things like automatic enum<=>string conversions or any advanced RTTI, just ease of use and extendability (preferably only during dynamic link-time).

 

Thanks in advance for ideas and advices.

Edited by Ivorne

Share this post


Link to post
Share on other sites

One alternative that may work for you is assignable values.

 

You tell the system that you are registering an action with a string.  You may be registering the action "jump" or "order_pizza" or whatever.

 

If the string exists it returns the existing ID.  If it doesn't exist it gets added to the list and the ID is returned.  Now anywhere you need the action you reuse the action ID that you registered earlier.

 

Biggest drawback is that the values are in flux based on registration order. It can break systems that persist between runs, such as game replays and possibly some logging, reporting, or telemetry systems.

 

 

 

Another option is to use an expected-unique ID, such as the hash of the action name. There is still room for collision so you could still require them to all register their hash as they are loaded to check for uniqueness.  

 

A hash will work with replay and persistence. It may also have trouble with logging, but if you require registration of the hash's 'friendly name' for logging purposes and perhaps assert when an unregistered value, it could work out.

 

 

 

Another option is a bigger external registration system, it is still an enum but you maintain a list for mod developers to get appended to. In a larger system you could do some validation, perhaps give the developer a key associated with their work that requires registration or the action's broadcast will fail; that could be checked at load time.

 

This would maintain control over your system, lets you keep them as known enumerated values, and help external developers to be coordinated, but has a cost that end users must frequently check for and install updates.  Since many online games already do this, the burden may be acceptable.

Share this post


Link to post
Share on other sites

yep, strings are what you are looking for. The downsides are slower lookup as string compare is slower than compare int values and risk of subtle bugs due to types so do not use magic strings in your code :) but if you want the ability to extend then enums will block you

Share this post


Link to post
Share on other sites

Half-decent hashing can significantly reduce the performance impact of using strings.

 

What you're describing is something that scripting languages are really specifically designed for though. Be careful not to spend months working on patchwork solutions and then decide to embed an interpreter and end up throwing all that work away.

Share this post


Link to post
Share on other sites

Thank you for answers. You are right that if I want persistence (for save and load, replays, logs etc.) when using mods, I need to derive the persistent ids from string names. External database for mods would work too, but I definitely do not want to centralize anything that I realy do not have to.

 

For this specific problem (names of input actions) I decided to use pointers to instances of an ActionEvent class as runtime IDs and string names as persistent IDs. I will have a global (in current game context) map that maps string names to ActionEvent instances. Each instance of ActioEvent will have its name as a member.

 

Listeners will connect to these ActionEvent instances and will receive callbacks from them. So in runtime, I will be able to use these pointers most of the time instead of string names. String names will be used only when registering new input or new ActionEvent instances and to save user-defined keybinds.

Edited by Ivorne

Share this post


Link to post
Share on other sites

This topic is 474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this