Hi everyone
Development of the mod continues. In this post I'll be discussing even more discoveries and interesting fixes for the development of the enemy synchronisation aspect of the mod.
Enemy synchronisation
I've gone on about this a lot in my previous posts, but I'd argue it's a pretty important mechanic to get right in the co-op mod considering if enemies are in different places doing different things for different people in the same world it leads to a very frustrating online gameplay experience.
Of interest for me this week was the following game networking packets:
NetP2pPacketAiFlag
NetP2pPacketAiData
NetP2pPacketAiGroup
As the name suggests, these are networking packets that communicate different entities AI states. Usually these contain an enemy location param ID, followed back the data to be applied to that enemy.
This works in the base game, because you only ever have 1 multiplayer map loaded in at any time. The issue is that in seamless, you can have multiple maps loaded and this leads to the enemy location param ID NOT being unique.
For example, enemy location param ID 100 could be present in two maps relating to two different enemies, but with the data available in the vanilla game there's no real way of differentiating the two.
To fix this, I had to re-write the networking protocol for these packets to create a new, unique enemy ID from merging the high bits of the map ID with the lower bits of the enemy location param ID. This allows for accurate application of the data to the correct entity.
This was most apparent with one of the main story bosses which activated only after a period of time:
In the game's event script, "EventConditionChr_CompareLogicEzStateFlag" is a virtual function checking some parts of the enemy AI state. The condition for this particular boss is that it has emerged from the ground - once this happens the boss becomes active and the music and boss health bar appears
For the host, the logic state is set correctly, but it was not networked correctly, meaning that the guest players never receive the AI flag update for the boss, causing it to never activate.
This was only a minor bug, but it allowed me to debug that there was at least 3 enemy state synchronisation packets which were not working at all.
The result of fixing all 3 of these packets means enemy sync is working flawlessly (from my experience anyways). The little hitches before - such as enemies occasionally splitting off on different clients - seem to be fixed
I'm extremely proud about this, because it was one of my main sticking points when I was first considering whether I should or shouldn't make this mod.
EnemyDeadCounter
A mechanic unique to Dark Souls II is the enemy dead counter. This makes it so that enemies will only re-spawn a pre-defined number of times before no longer re-appearing when resting at a bonfire.
With the addition of this mechanic, they also removed event flags defining whether an enemy would respawn or not.
In previous games. An event flag would be set in your save file when a boss or non-respawnable enemy would be defeated, meaning when a respawnable action occured (area reaload, bonfire rest) then the enemy would not come back.
In Dark Souls II they moved this condition to the EnemyDeadCounter. Bosses and certain unique enemies just have a "respawn_count" parameter defined as 0, meaning they will not respawn.
There is no networking for this in the base game, aside from an initialiser value on connecting, because it is never expected that players could do a respawnable action whilst in a session. In addition to this, phantoms are limited to 1 area's worth of enemy information, whereas the host can access all 42 areas at once.
I rewrote this class early on in development, but forgot to add networking functionality to update this value when new enemies are defeated, leading to bugs like inactive bosses respawning for the remote player only.
Once I'd found the responsible function, it was fairly straightforward to add my own networking to update the counter, and now it is working as intended with non-respawnable bosses not respawning for guest players.
What I'm working on right now:
People seem to like seeing a list of what I'm currently working on, so here is an updated list from last post.
Done:
Creating a system where some area-specific flags are not saved correctly to the guest world
Right now, if you are a guest and you kill a boss in the hosts' world. When you go back to your own world the boss will still be there, but in a dead state (meaning the fog wall won't be there, and the boss will be technically dead but just standing there idle.
It was not actually a problem relating to guest event flags as I first thought, but the EnemyDeadCounter which I described in this post.
Fixing 'The Abyss'
The Abyss is a purely single-player only area in the game accessed via a covenant. It's currently semi-functional, however the boss of this area can only be accessed by the host
The abyss should now function in multiplayer, meaning now every single map should work in a session.
Fixing the 'duplicate player' bug
Occasionally, a rare race condition can happen if you warp at the same time as the host, causing the host to spawn twice. This will inevitably crash the next time you hit a load screen. I know what causes it I just need to get around to fixing it.
I have re-written the way that player data synchronisation works, so now instead of the host sending all player data to the connecting player, each player is responsible for sending their own information.
To be done:
Creating a system where items are not instanced correctly
At the moment a guest player can pick up an item in the host world and it will regenerate when they re-spawn.
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
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 need to get around to fixing it.
Thank you for your patience, and a huge thank you to all of my supporters <3