Fix #8358: infinite loop when changing vehicle count on stopped ride. (#8375)

The sprite_remove in Sprite.cpp tries to find itself inside the quadrant.
It does not find itself, and because the rest of the code assumes that it will always find it
The normal code tries to set the value of the next_in_quadrant so that whoever points at it, will now point at its next sprite.
But because it didn't find whoever was pointing to it, it would set the pointer to SPRITE_INDEX_NULL to its next sprite.
This would lead to cycles in the linked list

The reason that the sprite was not found is that during the entry of a ride, the position of a peep is set to LOCATION_NULL
Exiting a ride sets it back to whatever the location is of an exit.
However stopping a ride that still has people in it would go wrong, as the people are removed from the ride through ride_remove_peeps

This function was called during the PaintWindows.
The fact that this function is called during the painting is the problem, because of the tweening:
Before painting all the positions are stored (Which would at that point be the LOCATION_NULL), during the painting
the peep would be removed from the ride, setting their location to the enrance/exit
After painting is done all the positions are restored again, so the patched position is forgotten and then it would be
removing a sprite with location LOCATION_NULL and that goes wrong

The fix is to have the window update outside of paint
This commit is contained in:
roosen5 2018-12-09 20:46:04 +01:00 committed by Michał Janiszewski
parent 04af3932ac
commit d9806305b0
7 changed files with 17 additions and 3 deletions

View File

@ -34,6 +34,7 @@
- Fix: [#8187] Cannot set land ownership over ride entrances or exits in sandbox mode.
- Fix: [#8200] Incorrect behaviour when removing entrances and exits that are on the same tile.
- Fix: [#8204] Crash when tile element has no surface elements.
- Fix: [#8358] Infinite loop when changing vehicle count on stopped ride.
- Improved: [#2940] Allow mouse-dragging to set patrol area (Singleplayer only).
- Improved: [#7730] Draw extreme vertical and lateral Gs red in the ride window's graph tab.
- Improved: [#7930] Automatically create folders for custom content.

View File

@ -274,8 +274,10 @@ public:
{
window_update_all_viewports();
window_draw_all(&_bitsDPI, 0, 0, _width, _height);
}
// TODO move this out from drawing
void UpdateWindows() override
{
window_update_all();
}

View File

@ -862,6 +862,7 @@ namespace OpenRCT2
_drawingEngine->BeginDraw();
_painter->Paint(*_drawingEngine);
_drawingEngine->EndDraw();
_drawingEngine->UpdateWindows();
}
}
@ -909,6 +910,12 @@ namespace OpenRCT2
_drawingEngine->EndDraw();
sprite_position_tween_restore();
// Note: It's important to call UpdateWindows after restoring the sprite positions, not in between,
// otherwise the window updates to positions of sprites could be reverted.
// This can be observed when changing ride settings using the mouse wheel that removes all
// vehicles and peeps from the ride: it can freeze the game.
_drawingEngine->UpdateWindows();
}
}

View File

@ -61,6 +61,7 @@ namespace OpenRCT2::Drawing
virtual void BeginDraw() abstract;
virtual void EndDraw() abstract;
virtual void PaintWindows() abstract;
virtual void UpdateWindows() abstract;
virtual void PaintRain() abstract;
virtual void CopyRect(int32_t x, int32_t y, int32_t width, int32_t height, int32_t dx, int32_t dy) abstract;
virtual int32_t Screenshot() abstract;

View File

@ -224,8 +224,10 @@ void X8DrawingEngine::PaintWindows()
DrawAllDirtyBlocks();
window_update_all_viewports();
DrawAllDirtyBlocks();
}
// TODO move this out from drawing
void X8DrawingEngine::UpdateWindows()
{
window_update_all();
}

View File

@ -95,6 +95,7 @@ namespace OpenRCT2
void BeginDraw() override;
void EndDraw() override;
void PaintWindows() override;
void UpdateWindows() override;
void PaintRain() override;
void CopyRect(int32_t x, int32_t y, int32_t width, int32_t height, int32_t dx, int32_t dy) override;
int32_t Screenshot() override;

View File

@ -30,7 +30,7 @@
// This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
#define NETWORK_STREAM_VERSION "11"
#define NETWORK_STREAM_VERSION "12"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static rct_peep* _pickup_peep = nullptr;