[Update] Dark Souls 2: Seamless Co-op - v0.0.4
Hi everyone
This post covers a detailed bugfix report for 0.0.4. I apologise for the delay - as a consequence of prolonged RE sessions I've developed tendonitis in my dominant arm and have been advised to rest.
Reminder to look after yourselves. Your posture and ergonomics matter!
As a quick disclaimer, I am typing this entire Patreon post using speech-to-text software.
Fix a bug that caused enemies to freeze in a world when solo hosting (after someone disconnected)
When a player disconnects from a host world, in the vanilla game, the multiplayer session will be closed. However, in Seamless Co op, the session continues.
As a consequence of this, the class NetEnemyManager, which I have talked about at length, will continue to run despite no other players being present. This is not normal behaviour, and as a consequence, the players who were previously present in the session will still technically retain control of the AI of the enemies that they had encountered. As these enemies were relying on a non existent player to give them commands, they just stood still and did nothing. I have fixed this issue so that the NetEnemyCtrl component for the enemy AI is reset when the session is empty.
This is still a known issue for phantoms who disconnect from the host world. Sometimes this may break enemy AI in a similar way, and I will fix this in the next update.
Fix a bug that caused hosts and pre-existing phantoms to not appear in Steam recent players
There is a feature in the Steamworks API that allows you to add a player to the list of recent players in the overlay. Usually, this function is invoked when another player joins your lobby in the Steam callback associated with updating the lobby data.
However, in Dark Souls 2, this function runs when the player data is received over the peer to peer connection and the player is created.
The way that Dark Souls 2 networks player data is complicated and obtuse. In Seamless Co op, I had to re implement the way that player data was communicated with other clients, and as a result, the call to add a player to the recently played with list was missed.
This has been fixed, and I have changed it so that when you enter a lobby, the player is added to the Steam player recent player list and not just when the peer to peer connection is established.
Fix a bug that caused friendly players in FF/PvP mode to lock bonfires
The way that I implemented friendly fire and PvP modes in Seamless Co op was by changing the inherent team type of the player.
This is successful, however, it caused an issue where, as players were treated as hostile, you could not rest at a bonfire whilst they were nearby.
This has been fixed in this version, and now, even with friendly fire or PvP modes turned on, you will still be able to rest at bonfires as normal.
Fix a bug that caused bonfires not unlocked in your own world to be non-warpable in a host world
The structure of the flags for whether or not a bonfire is unlocked or not is separated into two individual bytes. The first byte is dedicated to the bonfire state in your own world, and the second byte is identical to the first byte, however, it is only applicable for multiplayer sessions.
As I have explained before, the first bit in the byte determines whether or not the bonfire is unlocked. The remaining bits are dedicated to the upgrade level of the bonfire.
Unfortunately, there was one piece of code, which is the code that determines whether or not you can warp to a bonfire or not, that only reads the local byte. As a result, players who did not unlock a bonfire in a world, but the host had unlocked it earlier, were unable to warp to that bonfire.
The bonfire, the code responsible for whether or not you can warp to the bonfire or not, is in a highly mutated function. However, I think I have found a reliable fix for it that should be able to carry over.
Fix a bug that caused damage to be increased by 50% from all sources
As Dark Souls 2 does not have any vanilla scaling for regular enemies, only bosses, I had to implement a way of ensuring that there was a way that I could scale enemies' damage based on the local player's preference.
Unfortunately, the function that I had hooked was shared with all incoming sources of damage, and I was not able to reliably reference where the damage was coming from.
As a consequence of this bug, all damage from all sources, including enemies, fall damage, map objects such as exploding barrels, and even other players, including your own player, was increased by this scaling.
This has been fixed for version 0.0.4, and the new function that I have written for damage scaling is significantly more reliable and will allow me to add for more specific damage scaling options in the future.
Fix a bug that caused enemy & boss damage scaling values to not be applied
As described above, there was a bug in my implementation of the damage scaling hook.
Before mod release, I had unfortunately forgotten to implement functionality to the enemy and boss damage scaling values. This has now been fixed.
Added default damage scaling values to the ini (15% for enemies, 25% for bosses)
As this scaling value was not previously working, and in addition to the bug that caused 50% increased damage, which I described in a post above, I felt like some default damage scaling values might make it more interesting for players who would not normally adjust these values.
Fix a bug that caused some world state areas to sync with the host
The way that Dark Souls 2 saves the map state of an area is a complex interaction between the MapStateActManager class and the MapSnapDataManager class.
When an area is unloaded, the data from MapSnapDataManager will be compressed, cleaned up, and placed into a MapStateActManager buffer. If a buffer does not exist for that area, for example, if you are entering that area for the first time, then a buffer will be created.
Due to some modifications that I have made to ensure that all of the areas in the game are synchronized to the host world, it was possible for the code that saved the map snap data manager buffer to run locally on a guest client and overwrite their saved data with that of the host.
This has now been resolved.
When completing an invasion - on returning to your own world - you get your estus back and gear repaired
A widely criticised mechanic in Dark Souls 2 is that when you complete a multiplayer session, either as a phantom or an invader, your character does not get reset. This means that you do not get any of your consumables back, including your Estus flask, and, most importantly, your durability is not reset. This is a huge sticking point for some invaders, as you must remember to rest at a bonfire between invasions, otherwise, you risk having your gear break mid invasion.
The way that this mechanic works is there is a specific flag inside the function that warps your player character from one map to another that determines whether or not your character requires a reset or not. If this flag is set to false, as it is when you are returning from a multiplayer session, your character state is preserved as it was when you leave the multiplayer session. Conversely, when you die, this flag is reset, and that is why you get your durability and Estus flasks back when you die.
In Seamless Co op, rather than interfere with these flags, which have other repercussions, I decided to add one of my own flags into the game that will detect when you are exiting an invasion to apply the same effect to your player character that the game would be if it was going to reset you.
Disabled the Black Separation crystal for phantoms (currently just breaks the session)
The Black Separation Crystal is usually used for vanilla multiplayer sessions. Some players were using the Black Separation Crystal in seamless co op sessions, which would cause you to disconnect from the game session but not disconnect from the seamless co op session. To fix this issue, I have disabled the ability for the host to send phantoms back to their own world. Phantoms and invaders can use the black separation crystal on themselves, however, I will also disable this for version 0.0.6.
Added implementation for instanced items for each player
This is the mechanic that I reverse engineered for so long that I ended up giving myself arm problems. I spent approximately 80 - 90 hours over the week understanding how Dark Souls 2 preserves map item states. As it currently stands, I could make an entire hour long video on how Dark Souls 2 does this. But I will try and keep it brief here.
Over the course of a few game hooks and a lot of programming, I have written a method by which Seamless Co op can directly reference your local save file to attempt to retrieve the state of the items in the map that you are currently in.
This means that if you have picked up an item in single player in your own world, it should no longer appear if you do the same area in the host world. It will also mean that any items that you pick up in the host world will be gone in your single player world. This was remarkably easy to do in the other games, as they were just event flags. However, Dark Souls 2 is a completely different beast.
Overall
I hope people are enjoying the mod.
As always - thank you for your patience and a huge thank you to all of my supporters <3
Take care,
Yui
