So, to be more specific, I created a graph which shows general concept of modding system usage. It doesn’t matter at the moment how the mods will be actually created, but the basic configuration of engine seems necessary. There needs to be some class that stores list of mods and feeds them to specific handlers.
I can start working on red part which shouldn’t be intrusive and leave the rest of engine intact. The question is synchronising mods with other clients (or just local client-server), which may wait some months until online game is implemented.
Regarding graph:
By “start game” you mean “load map”? If so - what about mods that have effect on pregame (like new campaigns set or that “Hi-res main menu” package converted into mod)?
IMO but first part should be modifying our handlers to implement functions like addNewCreature(some input) which will be used to initialize existing content and then reuse this code for mods. But this is my approach to this.
there is already function that loads all “mods” in filesystem - CResourceHandler::loadModsFilesystems(). Not sure if you know about this or not. It check for presence of any Mods/*/filesystem.json files and adds information from them to global filesystem. These files have same format as /config/filesystem.json
Right now there is no way to access filesystem of individual mod (trivial to add) or to enable\disable specific mods (your part I presume)
Version checking\transfer of missing mods may wait. But you also may need some way to send game configuration to server (list of active mods, enabled/disabled options, etc.)
Not sure what exactly you mean by “synchronizing”. When game starts the mods should already be synchronized, that is server and all clients should have all the mods present and in the same versions (or compatible). [Even if we add support for mod transferring, it should be done in pregame, before the actual game.]
For now, as only SP is functional, it can be safely assumed that server will have the same mods as client.
Sounds to be the right way to go.
The “new creature” input has to be designed (basically our CCreature + URI’s to graphics, sounds, and so). Then current parser of H3 txt config adjusted to generate that info, and also we’ll need some more generalized interface, that could be used with mods loader.
Something like
struct CreatureInfo
{
CCreature *c;
URI animation, portrait, portraitSmall, sounds, ....;
};
struct ICreatureProvider
{
virtual vector<CreatureInfo> retreiveCreatures() = 0;
};
struct HeroesTxtLoader : ICreatureProvider
{
//use ZCRTRAITS.TXT and so on
};
struct ModLoader : ICreatureProvider
{
//use particular mod package to get creature
};
I’d say that mods for pregame should use different mechanism. The actual game doesn’t need to know about changes to pregame, especially since game can be launched without using pregame.
I think this is must-have feature but definitely very low-priority for now.
struct HeroesTxtLoader
struct ModLoader
I don’t think that there has to be strong separation between them.
For example WoG can be handled as mod but will take part of data from its own *.txt’s
Some of original data needs loading from Json (everything that was hardcoded in H3)
Treating H3 data as one mod should be more easier:
1 - Parse ALL of original .txt data in std::vector but do not add it to game
2 - for each mod do:
3 - - for each entry in mod’s json data do:
4 - - - use creatureinfo from H3 txt’s (if present) as base. Json data will have “id” field for this.
5 - - - read Json data into creatureInfo replacing any existing fields
6 - - - check if creature is valid (kinda optional)
7 - - - add creature to game (now or during “configure loaders” stage - doesn’t really matters)
Note regarding #3: vcmi data is also “mod” in this case. So on first run this will load H3\VCMI data in the game.
Note regarding #5: This will allow to
a) complete data missing from H3 txt’s
b) fix any incorrect data (Json data will replace data from txt’s)
c) load creature from scratch (only for mods)
For now I’ll try to connect ModHandler with existing game state structures, and the try to implement some simplest options, like the ones that currently are hardcoded (for example from GameConstants), regarding mechanics. Once we have working base, we may implement some more complex features.
Still, I’m currently busy with engineer thesis / work
Regarding ModHandler:
Filesystem separation per mod is not needed right now. It can be done on filesystem side without any costly re-scanning so changing active mods should be fast.
Not sure. What if player will add one more mod and starts any previously saved game?
Consider H3 as one unremovable mod? There will be a lot issues like that. And I can’t think of any easier way to handle this.
I also have been thinking how to reorganize town buildings to allow some client-server separation like the one proposed to creatures. So - some random thoughts about that.
It is clear that here we will need two separate structures: current library-side CBuilding and client-side CStructure. This means that at least for towns something like CreatureInfo won’t work as it - there is just too much gui-only data.
Question: how to organize loading so client can handle CStructure’s loading?
There should be some way for library like “new town registered” callback or interface class with onTownAdded method (probably better) which will pass data used in lib loading (pointer to lib structure + txt + json) to client or server to load all remaining fields.
Question: where to store these client-side structures? Even creatures are not simple set of URI’s (look at CRANIM.TXT). And town buildings have position, several structures like hordes that are heavily hardcoded right now, town hall extra buildings, etc - this all has to be stored somewhere on client without any hardcoding if possible.
Wasn’t mod support supposed to be done after cheatproof multiplayer? If so, why Warmonger is committing mod handler to trunk?
If OH3 were a mod, what would it mod actually? An empty game with no items? I think it should be either removable (because there is no reason not to) or not a mod. The second option seems to be more compelling.
We’re far from mod support of any kind, but can do some work in that direction: design, reorganization, testing etc. This mod handler won’t do much more than just add some config options for now. But we’ll be ready for further improvements.
I’m talking about internal implementation mostly. Replace “mod” with something like “content source” if you wish.
So far it looks that H3 content will be initialized in the same way as mods. Which means that H3 data can be handled as mod.
And it is unlikely that it will be possible to remove (some of) existing content without breaking the game due to hardcoded mechanics. Which means that H3 content can’t be made removable at least for now.
Some of existing content can be easily removed – creatures, towns, spells, advmap objects, artifacts… Actual mods should be able to remove them if modders wish to do so.
BTW, there are still a lot of things to discuss like mod compatibility, relation of cheatproofness and mods and map/mod interoperability. No need to write any code yet.
Tow Dragon… I couldn’t be so calm beeing one of top2 faces of such big project as VCMI (and I am always a quickie but not always to hasty). Modders won’t be so calmly waiting so they definately would try ERA for a year or two… which means even more hassle for VCMI compability hence then mod support and basic data would be needed to be based on ERA rather than pure WoG (but adopting some part of ERA mod support mechanics rather won’t be bad).
I think the mod system should be simple in the beginning.
A folder ‘mods’ is not really necessary because there is nothing else in the vcmi folder (except the binaries). Every mod should have its own folder but they should not be inside eachother. If there are mods inside mods then what happens if a mod depends on two different mods?
Each mod should include a simple text file with a list of required mods.
The vcmi binary should have a command-line switch to load a mod: vcmi --mod wog.
This would load the mod in the folder named wog, read the text file and load the mod in the folder heroes3 (wog depends on the original game).
Assets like images, sounds and videos should override assets with the same name from required mods.
The config files for towns, creatures, …… should include a syntax to remove things. All of these should be loaded in reverse order from least important to most important. A modder can remove creatures not by overriding the entire file but by removing them using the syntax in his file.
Switching mods when they have been loaded is too difficult because lots can go wrong in the code. There could be a list of mods and loading a different mod could restart vcmi with a different command-line.
The command-line is not bad for Windows, it can be used through shortcuts.
This way the modding system should be simple to implement but powerful.
I supposed that the long-term plan was to make the original game just another mod.
I think that making an installer that takes an installed original game (without wog) and copies the needed files to a new folder with a new structure and installs wog would be the best option. Then the original is only a mod. If distributing wog is a problem, the installer could be made to download wog itself.
Having a nice clean directory is a good idea. The vcmi directory would look like this:
VCMI
vcmiclient.exe
vcmiserver.exe
libvcmi.dll
Heroes3
config
data
mp3
......
wog
......
... more mods ...
AI
Scripting
The rest of the system that I described comes from another game Freespace II (see hard-light.net/). It works very well and is not too complicated for modders or users.
Mods are just directories under the main folder. They include a text file with the dependencies. They have a launcher program that allows to select the mod and different versions of the binaries. This way the list of mods and their order never changes once the game binary has been started.
I’m not sure if you read our goals and assumptions… any number of mods should be possible to run at once. Mods are not going to use any independent binaries. It doesn’t say anything about total conversions.
We want to get independent of WoG eventually, probably even sooner than later.
Also, having dozens of folders in main directory is just bad visually.
I also don’t want binaries for mods, I meant different versions (0.88, 0.89, …) of vcmi. Don’t know if this is a good idea, though.
Once you eliminate all hard-coded elements from the code, total conversions should not be a problem.
I still think a launcher approach is best, even is it is integrated into the binary. It would work like this:
standard mod is original or wog (just installed game)
mod menu in-game, shows list of mods and selected mods (probably need load order), perhaps tow lists (selected, not selected) and buttons to change the order.
write mod selection to config file
if mod selection changed, restart the program.
The problem is that the user will not know the right loading order for the mods. The mods still need to include a list of dependencies.
How about a simple mode where only one mod can be selected (with dependecies done automatically) and an expert mode like the lists described above.
Many games work like this and it should make implementing mod changes easier.
I support this, I never liked wog’s additions. I would also suggest making mods that recreate Restoration of Erathia and Armageddon’s Blade. This could make supporting the different map types easier (don’t know if it is implemented yet).
You still don’t get the general modding concept. Mods are NOT supposed to be total conversion, just small extensions to original game. A mod can be just a single artifact, creature or map object. Or skin change. There is no point in running it alone, rather in large amounts.
We don’t need “load order”. It’s just a disadvantage of ERA-style modding. We want to build dependency tree automatically and free users from this complicated labour.
Again, there is no need for that.
Instead of proposing anti-features, please suggest something that could actually enchance the game experience, convenience, robustness, safety. Or a way to actually implement the mod system. The point of VCMI is to make the very best mod system possible, just like Unreal Tournament has for example.
Ok, now I get it. I was thinking of larger mods, for example adding a town and a campaign. Sorry about the misunderstanding.
What happens if a user selects two mods that both try to change the same interface graphic? There will be an order somewhere so the user should be able to choose.