-
Notifications
You must be signed in to change notification settings - Fork 250
Rework of party member quest progression PR #769 #848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Rework of party member quest progression PR #769 #848
Conversation
9cf7866 to
bbde0e3
Compare
8616912 to
3298ed7
Compare
Definitely is not compatible with 1.8.0 servers. The community loves Members being able to advance quests (instead of only Party Leader), but it introduced a bunch of problems with duplicate quest triggers. This rework deals with it (hopefully). The most fundamental problem is that ScopedQuestOverride() doesn't work, because quest progress is executed on a different thread; the ScopedQuestOverride() is destructed before the quest OnEvent...() routines are invoked. So all the Members send their updates to the server even when told not to. The server just ignored them all before, but now with Member quest progression enabled, it ends up causing replicated quest updates. Some quests ignore it, many break. The engine is in control of the content of events passed to the OnEvent routines. I could not find a reliable way to pass any context to the OnEvent routines through that barrier (it runs async, so matching up was nigh-on impossible). So ended up implementing a dedup history server-side, where there is enough context to figure this out. The worst-case flow (when a Member triggers progress), is: 1) Member sends update. 2) Update is forwarded to Leader, only. 3) Leader OnEvent hooks send the Leader update to the server. 4) Leader SendsToParty 5) Party members reflect the updates to the Server, but are dropped by the dedup history because the Leader has already sent it. 6) Entries in the dedup history time out in seconds (needs some tuning), so quests can rewind and stages can be triggered multiple times to evaluate. Merged with old duplicate quest stage "fix"
…experimented with live. Fix server crash if connection fails server authentication Make the QuestStageDedupHistory timeout a server variable, because it looks like we're going to need to tweak it.
3298ed7 to
9ad8969
Compare
…g them. Due to network delays, blocking the send isn't enough, Leader can enter the scene after a follower. Goal is Leader not to accept updates during a scene; follower could skip it ahead.
…checking instead of playercontrols check.
Needs SceneService moved into its own files, but that has to wait pending merge with Miredirex RE branch or it will just be harder.
Improved logging.
Many iterations of rewind management to settle on this: can't be the way it should be because Member scenes play much faster than leader's. Full description from the code:
// Party all playing a scene firing events in parallel can deliver updates that get through the
// server dedup logic due to the network delay. So when playing a scene, reject rewinds
// You'd think that would be it, but due to Member playing scenes 2-4x faster than Leader
// (unfixed bug), we need the leader to rewind Member to try to stay more in sync.
e4475b6 to
25fa8c9
Compare
Claim is that if NPC casted slow time effects the magnitude was doubled. The bug was is set the TARGET to the Player, instead of the CASTER.
…ne are ignored. Unless they include a SceneEnd flag. Those updates are sent when a scene ends and forces everyone to accept the update to catch up.
|
Substantial logic change. Remote updates received while playing a scene are ignored. Unless they include a SceneEnd flag. Those updates are sent when a scene ends and forces everyone to accept the update to catch up. Many variations of scene support have been tried, this seems to be the best compromise. Unless multiple players click the option to continue. That's often going to do something unpredictable, don't do that. To unstick players, at Scene End, send a "poke" quest stage update that is not deduped, to catch everyone up. A future improvement may send such a poke every time player interaction causes a quest stage change, but have to figure out how to detect that. |
d9d9ac7 to
639e016
Compare
… a scene is playing, do not allow rewinds.
639e016 to
cfdd227
Compare
Some more accurate / complete logs.
5e2f603 to
3323bb6
Compare
The community loves Members being able to advance quests (instead of only Party Leader), but it introduced a bunch of problems with duplicate quest triggers. This rework deals with it (hopefully).
A large credit goes to co-author @miredirex for reverse engineering a couple more methods to make this work, especially having more awareness of when a Player is in a scene (BGSScene) or not. That's the key to making cutscenes sync, or at least sync much, much better. That, and deduplicating the storm of duplicate attempts to advance the quest stage that was introduced with Member-can-progress-quests PR #769. That introduced several bugs that are fixed here.
A lot of the effort in this PR was figuring out the real-world situations in which quests can and cannot rewind, and making sure the fix supported that. You can find the information in ck.uesp.net starting with SetStage(), but it isn't all consolidated in one place. Find comments in the code, it's too long and complicated to re-explain here (likely introducing errors)
The most fundamental problem is that ScopedQuestOverride() doesn't work, because quest progress is queued and executed later on the current or different thread; the ScopedQuestOverride() is destructed before the quest OnEvent...() routines are invoked. So all the Members send their updates to the server even when told not to. The server just ignored them all before, but now with Member quest progression enabled, it ends up causing replicated quest updates. Some quests ignore it, many break.
The engine is in control of the content of events passed to the OnEvent routines. I could not find a reliable way to pass any context to the OnEvent routines through that barrier (it runs async, so matching up was nigh-on impossible). So ended up implementing a dedup history server-side, where there is enough context to figure this out.
The worst-case flow (when a Member triggers progress), is:
Merged with old duplicate quest stage "fix"