Very pre-alpha, not usable yet.
ModEasy is a small, customizable library that provides easy modding support to any project. A Mod can stand for module or modification and is a package of data and/or code that adds onto or overrides the original data and/or code.
MIT, see LICENSE file for details or https://choosealicense.com/licenses/mit/.
- Support Linux, Windows, and MacOS.
- Functional out of the box.
- Mod configuration via simple ini files.
- Mod types of: configuration files (no code), pre-compiled library (dll, so, etc), and Lua.
- Mod dependency handling. Automatically builds a dependency tree that loads mods in a certain order allowing mod inter-dependency with the option for load order overrides.
- API registration for both the core project and mods that allows calling those registered functions from each supported mod type.
- Network code for querying info and retrieving mods from an online repository.
- Custom configuration file type(s). Add additional configuration file loaders and/or override the default.
- Custom Mod handlers to add additional modding languages.
- Customize functionality of the network code.
- Add hooks to the API registration code.
- Single header option if possible.
To build you need cmake, and a c++ 11 capable compiler.
sudo apt install build-essential cmake
mkdir build && cd build && cmake .. && make -j2
You can make the -j# be “number of core” - 1 for faster build times.
If you want to run the unit tests, after the above commands run:
As stated above the library tries to function out of the box. Once you install the library using it in your code is fairly simple.
modding = std::make_unique(“mods”); //the modding folder relative to your executable.
//register your core API functions
//initiate all mods
- mods_path: string. a path, either absolute or relative to the binary, that points to a location to load mods from.
High-level Design and Extending Functionality
Library is broken into 6 parts:
- Configuration: Focused on loading configuration formats.
- Dependency: Builds a loading order based on required and optional dependencies.
- Implementation: Handles loading different mod types (lua/configuration/etc).
- API: Holds API objects from each mod and the core program.
- WebMediator: Handles http post and get requests to online mod repositories.
- ModFrameworkCore: Core class that organizes and mediates everything.
The Configuration sub-system is based around recursive key/value objects and file parsers. These two aspects are handled by the ConfigStore and ConfigLoader classes respectively.
The ConfigLoader base class forces derivatives to implement the validate, parse, and serialize functions. By default we include a ConfigLoaderINI class that loads .ini style config files.
- Validate checks a given file is the right format.
- Parse takes a file path and populates a ConfigStore object with the data therein.
- Serialize converts a ConfigStore into the configuration file format and saves it to the given path.
In the ModFrameworkCore, you can set the default ConfigLoader. There is also a function to register new formates and associate them with a ConfigLoader child class.
The ConfigStore class allows storing string values and nested ConfigStore objects in key/value pairs. ConfigStore has the getStr, getNested, and set functions that return and take string and ConfigStore variables. There are no customizable parts to the ConfigStore.
Just a note, ConfigStore uses unordered_maps for the two type of data stored. You can get their iterators with the beginStr, endStr, beginNested, and endNested functions. Unordered_maps use forward iterators so you can only test equivalence (==) and non-equivalence (!=) when using them in a for loop. Trying to use less then greater then or the variants will fail. http://www.cplusplus.com/reference/iterator/ForwardIterator/
The Dependency sub-system makes sure that mods will be loaded in the correct order. This is a self-contained sub-system and doesn't need any user extensions.
The Implementation sub-system deals with actually loading the meat of the Mod. By default there are 3 implementation mod types:
- config: Mods just used to load up collection's of configuration files.
- pre-compiled: Mods that load pre-compiled libraries.
- Lua: Mods in the Lua language.
New mod types are defined by creating a new derivative of the ModHandler. ModHandler derivatives need to implement the load function.
The load function is given the directory path and ConfigStore object for the mod and is supposed to do everything needed to get a mod loaded and working.