Hi everyone
Development of the mod continues. In this post I'll be discussing even more discoveries and workarounds I've had to create to get the mod working in a more playable state
World state progression
In previous posts I've discussed about MapSnapDataManager. This is a class that holds up to 3 loaded maps, and saves object and enemy states so if you run back and forth between a few maps the game doesn't have to start from scratch every time.
You might notice, in the vanilla game, that if you ran through a few maps without touching a bonfire:
Map A -> Map B -> Map C -> Map D
If you clear all of the enemies in every map, then if you ran backwards from map D back to map A, the enemies and object states in Map A will be reset even if you haven't warped or rested. This is just because when you load map D, MapSnapDataManager "forgets" the clear info about Map A so your progress is gone.
A really easy bug to encounter in seamless is based on the limitation of this class, and it's when players run through different maps asynchronously. If players load maps in different orders, then MapSnapDataManager will "forget" maps at different points, meaning it's very possible to be in a map which is in a completely different state to the host.
The fix
In previous posts, I've mentioned about preserving object states. In seamless co-op, the host periodically informs other players about the state of objects in maps that aren't loaded. This way, if a guest players warps to a different map the host doesn't have loaded, then the object state will reflect that of the host world accurately.
This past few days, I've done the same thing but with enemy states. The issue of MapSnapDataManager "forgetting" the last loaded map is no longer a problem because I have written my own implementation of the system from scratch.
Seamless will keep logs of certain parts of enemy generator instances, such as health, location, and enemy flags, and keep them permanently until another player rests at a bonfire. This means that you could clear every single enemy in every map, and still backtrack through the game and have the enemies remain in the same state as they were before with no resetting.
Of course if a player rests at a bonfire, this list is cleared.
The primary objective of this re-implementation was not to "fix" the behavior in the base game, but as a necessary step to ensure that players can play as seamlessly as possible through the game.
The best way to play all of the seamless co-op mods is to stick together. This is least stressful for the mod, but at the very least this will resolve some of the glaring issues that splitting up amongst the group would have caused.
I've tested this and it seems to be working as intended. There are still some lingering issues with players being far away from each other, however these will be addressed in a more long-term perspective and aren't essential for a preliminary release.
Other adjustments / fixes / features added the past week:
Disaster enemies will now drop a "transient curse" which is an item you can burn in any bonfire for an effect (described further down)
EnemyGeneratorDeadCounter now persists from multiplayer sessions (i.e. if you kill an enemy in the host world, it will also count as a kill in your own world)
Phantoms entering the abyss with the host will also inherit the phantom colour associated with being an abyss intruder. Dying in the abyss now also triggers spectator mode similar to being in a boss fight.
EventTaskObjCtrl objects (i.e. primal bonfires) will no longer force interactions from every player when activated
DemoCtrl (cutscene) synchronisation for so that hosts and guests, but not invaders, can skip cutscenes and have it communicated to different clients
Visual effect synchronisation for bonfire actions
Ability to skip the ending credits in the first NG cycle (mentioned in this post)
Note on the bonfire burn context menu
The bonfire burn context menu is hardcoded in Dark Souls II. When selected, an array of 3 items (sublime bone dust, bonfire ascetic, and human effigy) is created with an associated list of functions to create a "FexCommandSelectJob".
This is then used to create the window seen in the image below, and selecting any of the items will then create a "FixOrderJobSequence" which is just a command window with the "Yes" / "No" selection boxes, and a pre-defined function that runs when you select either.
In seamless co-op, you can use bonfire ascetics and sublime bone dust online. But I had to restrict bonfire ascetic use to hosts only and remove the human effigy to avoid confusion. In doing so, I discovered that the function that creates this FexCommandSelectJob, actually accepts a vector of item/function pairs.
As a result, I added a new item - a transient curse - to the bonfire burn context menu, hid the bonfire ascetic for non-host players, and removed the human effigy from the menu.
I've also made it very easy to just add as many items as I like to the burn menu, but that would only be useful for further modding or development of seamless co-op.
Although this isn't strictly a pre-alpha release requirement, I had a lot of fun doing a deep dive into the menu system and learnt a lot in the process.
To be done:
Creating a system where items are not instanced correctly
This is unfortunately very annoying to do because, unlike the other souls games, ItemLot pickups are not associated with event flags. They are directly attached to the object that they spawn from themselves, meaning I have to access unloaded object data during a session
This is probably the biggest sticking point for me right now. And it is not game breaking so it is less of a priority. It allows guest players to duplicate items, which is relatively harmless but also looks very bad. I'm looking into it this week.
Fixing bonfire warps
Currently, if one player sits at a bonfire whilst another player is just starting the warp animation, it will softlock the player warping. Meaning they have to restart. I know what causes it I just STILL need to get around to fixing it :P
I'm currently working on a video to "formally" announce the mod.
As always - thank you for your patience and a huge thank you to all of my supporters <3
Take care,
Yui