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
Fixed few multiplayer desync issues. #5578
Conversation
Fixed peeps trying to watch ghost rides in multiplayer. Fixed using the wrong tick number for commands, client as ahead one tick in reality. Added some logging scenario_rand when DEBUG_DESYNC is defined.
src/openrct2/world/Climate.cpp
Outdated
@@ -181,7 +181,7 @@ extern "C" | |||
else if (gClimateCurrentWeatherEffect == 2) | |||
{ | |||
// Create new thunder and lightning | |||
uint32 randomNumber = util_rand(); | |||
uint32 randomNumber = scenario_rand(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is thunder not completely client-side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its still driven by a prng which is at least sync so every client should see the thunder at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an option to disable thunders. This may cause a client UI layer not to call this function and it would desync this client, that's why it is client side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More precisely: there is an option to disable lightning flashes. You'll still hear thunder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to double check this, but the thunder and lightning effects should be purely client side and aesthetic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After sleeping over it I just realized that, altho it should still use the same prng stream however not affect it so at least all clients will run the same effects.
Once this is merged https://github.com/OpenRCT2/OpenRCT2/wiki/Multiplayer-issues will have to be updated. |
@ZehM4tt thanks for this PR. While it looks like it indeed solves some desyncs, the map you provided for testing: aaa.sv6.txt still exhibits some. It reproduces quite reliably for me under these conditions:
|
src/openrct2/scenario/scenario.c
Outdated
if (!gInUpdateCode) { | ||
log_warning("scenario_rand called from outside game update"); | ||
assert(false); | ||
//assert(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ZehM4tt any particular reason this is commented out? I mentioned on gitter I hit this condition at times, but the PRNG looks fine regardless. Are there known good paths leading to this point?
Can you either provide justification and remove this line or leave the assert in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its only active with DEBUG_DESYNC and it was triggering even tho its fine to be called at the given time. I would just leave it commented in case someone requires to stop there to investigate the stack or memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit nervous about this. I do not know enough about network to say why it got in, but an assertion is never put in for nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are false positives, its just annoying to have it there while investigating.
src/openrct2/world/map.c
Outdated
@@ -3659,7 +3659,8 @@ void map_update_tiles() | |||
} | |||
|
|||
gGrassSceneryTileLoopPosition++; | |||
gGrassSceneryTileLoopPosition &= 0xFFFF; | |||
// Type is uint16, so why do we need this exactly? | |||
//gGrassSceneryTileLoopPosition &= 0xFFFF; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? Looks redundant, so perhaps should be part of another PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps leave ZehM4tt's changes intact and create an issue for it?
src/openrct2/network/network.cpp
Outdated
@@ -1124,7 +1131,7 @@ void Network::Server_Send_TICK() | |||
// but debug version can check more often. | |||
static sint32 checksum_counter = 0; | |||
checksum_counter++; | |||
if (checksum_counter >= 100) { | |||
if (checksum_counter >= 5) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Back this out, such low value is only needed for testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ops
@@ -174,6 +174,12 @@ static void peep_update_ride_inspected(sint32 rideIndex); | |||
|
|||
bool loc_690FD0(rct_peep *peep, uint8 *rideToView, uint8 *rideSeatToView, rct_map_element *esi); | |||
|
|||
#ifdef DEBUG_DESYNC | |||
#define peep_rand() scenario_rand_data(peep) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
peep
may not be as useful as part of logging, as it's id: https://github.com/OpenRCT2/OpenRCT2/blob/develop/src/openrct2/peep/peep.h#L469
Crash while on ed06a22 |
@ZehM4tt it may not be related directly to your PR, as I don't recall any new places where it could crash, but perhaps I missed something. Can you please take a look at this dump? |
@ZehM4tt can you please post the stack trace as text? Images are not searchable nor they add any value. It also looks like this is irrelevant to your PR and something that hasn't been reported yet, so can you please file a new issue with all the information there? |
I'm not the one who found it to begin with and I have no idea how to trigger it, etc. The picture was merely some indication that it doesn't belong here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a few line notes to address.
I'm not sure the debug stuff should be in this PR, but I'm not going to obstruct this if I'm the only one.
I do not know enough game_update()
either to say anything about that, I'll leave that to IntelOrca, Janisozaur and Duncan.
src/openrct2/peep/peep.c
Outdated
@@ -11344,6 +11350,12 @@ static void peep_easter_egg_peep_interactions(rct_peep *peep) | |||
*/ | |||
static bool peep_should_watch_ride(rct_map_element *mapElement) { | |||
rct_ride *ride = get_ride(mapElement->properties.track.ride_index); | |||
|
|||
// In case of upcoming references we also have the check in here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this comment a bit vague. It isn't clear what it's trying to prevent, nor does it say why (I know it's to prevents desyncs, but the comment should really say that).
src/openrct2/peep/peep.c
Outdated
@@ -11394,6 +11406,9 @@ static bool peep_find_ride_to_look_at(rct_peep *peep, uint8 edge, uint8 *rideToV | |||
|
|||
mapElement = surfaceElement; | |||
do { | |||
if (network_get_mode() != NETWORK_MODE_NONE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put a comment explaining this is to prevent desyncs from interaction with ghost elements.
src/openrct2/scenario/scenario.c
Outdated
if (!gInUpdateCode) { | ||
log_warning("scenario_rand called from outside game update"); | ||
assert(false); | ||
//assert(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit nervous about this. I do not know enough about network to say why it got in, but an assertion is never put in for nothing.
src/openrct2/world/map.c
Outdated
@@ -3659,7 +3659,8 @@ void map_update_tiles() | |||
} | |||
|
|||
gGrassSceneryTileLoopPosition++; | |||
gGrassSceneryTileLoopPosition &= 0xFFFF; | |||
// Type is uint16, so why do we need this exactly? | |||
//gGrassSceneryTileLoopPosition &= 0xFFFF; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps leave ZehM4tt's changes intact and create an issue for it?
@@ -3719,6 +3720,9 @@ static void map_update_grass_length(sint32 x, sint32 y, rct_map_element *mapElem | |||
mapElementAbove++; | |||
if (map_element_get_type(mapElementAbove) == MAP_ELEMENT_TYPE_WALL) | |||
continue; | |||
// Grass should not be affected by ghost elements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well spotted.
@Gymnasiast I addressed your comments. I'm not sure about the one that wants to have comment next to ghost checks, there are quite a few and having a comment next to each one would introduce a lot of clutter, so I'm not exactly for it. @duncanspumpkin expressed concerns about passing the peep data to logging, but I concur. I think I could use such data and even if not, it's a good example of how to use the little debug features we have. |
[ci skip]
@Gymnasiast I addressed all your comment now. |
My concern with the peep debug Rand was. does logging the Id/peep give any additional useful information? For debugging a desync it's rare that you would care about an individual sprite and if you did know which sprite caused the desync how would that help. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My notes are addressed. I'll leave the game_update() bits and related stuff to @janisozaur and @duncanspumpkin .
@duncanspumpkin It did help determine if the order is correct not necessarily the peep in question. If peep A comes before peep B on server then peep A must do all decision making on client before peep B as well. Since all allocation seems to be deterministic on my Windows 10 machine with debug heap this can be quite helpful, but you are right about the data its self, its quite useless. However this is only enabled if DEBUG_DESYNC is defined, its probably best to use their object id for logging. |
This addresses some of the desync causes: * `vehicle_create_car` was using `scenario_rand` when it shouldn't have * ghost elements affected grass growth * ghost elements affecting peep logic[1] It also adds some desync debug facilities, enabled at compile time. It also reverts part of change introduced in OpenRCT2#5185, namely reorder of desync check vs call to `ProcessGameCommandQueue();` [1] It is not ideal to have this check in multiple locations, it is prone to human error. We already have `map_remove_provisional_elements`, but it is possible it does not work as well as it should. This needs further investigation.
Fixed peeps trying to watch ghost rides in multiplayer.
Fixed using the wrong tick number for commands, client was ahead one tick in reality.
Added some logging for scenario_rand when DEBUG_DESYNC is defined.