Modular game mode definitions #848
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is my take on the idea of a modular mod system that we discussed a few months ago in Discord. The goal of this PR is to lay the foundation for a OpenCiv3 scenario format, and to allow scenario definitions to be modularized into several files.
Game generation
This PR introduces a new class, GameModeLoader, that implements the logic for loading the new scenario format. The process for loading a scenario consists of several steps:
The game loads the "base" file of a scenario. This can be either a JSON file or a Lua script that returns a table. The format of the data is the same as we use for save files.
The game passes the data to a pipeline of Lua functions loaded from separate scripts. Each of the functions accepts the data as a Lua table, modifies and returns it. The resulting table is passed to the next function in the pipeline.
The final table is converted to JSON and deserialized as SaveGame.
As before, the final game generation is handled by GameSetup class, which generates map and places players on it if the scenario doesn't specify this data.
Basic and standalone modes
This PR uses this new system to redefine the basic and the standalone modes. Previously, these two modes were defined in two separate JSON files. The difference in the "standalone" save was that it excluded the units we didn't have graphics for and updated art names for other units.
With the new system, both modes share the same JSON save as their base, while the logic for replacing the units in standalone mode is defined procedurally in Lua! And, besides being a good example of the new system, it also removes the burden of maintaining two almost identical JSON files :)
Right now, there is no way to define new modes without changing the C# source. However, if we settle on the system, we can easily implement some config or even GUI for defining new modes by selecting a base file and its addons.
Other changes
This PR reorganizes the C7Engine classes related to Lua into a new sub-namespace: C7Engine.Lua.
There is also a new class, JsonConverter, which is used to convert data between Lua tables and JSON objects. This class was written by an LLM. Before going with it, I tried the converter built-in in the Moonsharp (it had bugs that made it unusable), and pure Lua libraries - dkjson and lunajson (they worked too slow under Moonsharp runtime).
There is also a new extension class, ScriptExtensions, for MoonSharp Script class. The goal of new extension methods is to provide logging for errors in Lua code, making debugging more straightforward.