From d9806305b0ae71fec59357139bc2cd817fdb0f3e Mon Sep 17 00:00:00 2001 From: roosen5 Date: Sun, 9 Dec 2018 20:46:04 +0100 Subject: [PATCH] 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 --- distribution/changelog.txt | 1 + .../drawing/engines/opengl/OpenGLDrawingEngine.cpp | 4 +++- src/openrct2/Context.cpp | 7 +++++++ src/openrct2/drawing/IDrawingEngine.h | 1 + src/openrct2/drawing/X8DrawingEngine.cpp | 4 +++- src/openrct2/drawing/X8DrawingEngine.h | 1 + src/openrct2/network/Network.cpp | 2 +- 7 files changed, 17 insertions(+), 3 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index b8990702de..5030ad561b 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -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. diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 9a6da07598..929719d7e7 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -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(); } diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 7f4078ca06..29c68aa22c 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -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(); } } diff --git a/src/openrct2/drawing/IDrawingEngine.h b/src/openrct2/drawing/IDrawingEngine.h index c59e320300..b93e6d5ad6 100644 --- a/src/openrct2/drawing/IDrawingEngine.h +++ b/src/openrct2/drawing/IDrawingEngine.h @@ -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; diff --git a/src/openrct2/drawing/X8DrawingEngine.cpp b/src/openrct2/drawing/X8DrawingEngine.cpp index 284f267fca..8de6a61c96 100644 --- a/src/openrct2/drawing/X8DrawingEngine.cpp +++ b/src/openrct2/drawing/X8DrawingEngine.cpp @@ -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(); } diff --git a/src/openrct2/drawing/X8DrawingEngine.h b/src/openrct2/drawing/X8DrawingEngine.h index 7a5560f371..9053727815 100644 --- a/src/openrct2/drawing/X8DrawingEngine.h +++ b/src/openrct2/drawing/X8DrawingEngine.h @@ -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; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 5ec62481c1..b94e25b8ef 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -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;