Fix #19574: Handle exits in null locations (#19727)

In park/replay from dump #19574 there was a calamity that happened
likely due to a plugin. Pretty much all rides were deleted in single
tick, which caused the park to mark some locations as null and then it
tripped on one of the many assertions. In many of the places it already
bails out if ride or vehicle is a nullptr, so I followed with similar
approach for invalid ride exits.
This commit is contained in:
Michał Janiszewski 2023-03-28 00:16:55 +02:00 committed by GitHub
parent 4bf35b267c
commit 1f7ef64627
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 22 deletions

View File

@ -68,6 +68,7 @@
- Fix: [#19493] SV4 saves not importing the correct vehicle colours.
- Fix: [#19517] Crash when peeps try to exit or enter hacked rides that have no waypoints specified.
- Fix: [#19524] Staff counter shows incorrect values if there are more than 32767 staff members.
- Fix: [#19574] Handle exits in null locations.
- Fix: [#19641, #19643] Missing water tile in Infernal Views and Six Flags Hollands river.
0.4.3 (2022-12-14)

View File

@ -3597,7 +3597,10 @@ uint8_t Guest::GetWaypointedSeatLocation(const Ride& ride, const CarEntry* vehic
void Guest::UpdateRideLeaveEntranceWaypoints(const Ride& ride)
{
const auto& station = ride.GetStation(CurrentRideStation);
Guard::Assert(!station.Entrance.IsNull());
if (station.Entrance.IsNull())
{
return;
}
uint8_t direction_entrance = station.Entrance.direction;
TileElement* tile_element = RideGetStationStartTrackElement(ride, CurrentRideStation);
@ -3684,7 +3687,10 @@ void Guest::UpdateRideAdvanceThroughEntrance()
{
const auto& station = ride->GetStation(CurrentRideStation);
auto entranceLocation = station.Entrance.ToCoordsXYZD();
Guard::Assert(!entranceLocation.IsNull());
if (entranceLocation.IsNull())
{
return;
}
const auto& rtd = GetRideTypeDescriptor(ride->type);
rtd.UpdateLeaveEntrance(this, *ride, entranceLocation);
@ -3770,7 +3776,6 @@ static void PeepGoToRideExit(Peep* peep, const Ride& ride, int16_t x, int16_t y,
Guard::Assert(peep->CurrentRideStation.ToUnderlying() < OpenRCT2::Limits::MaxStationsPerRide);
auto exit = ride.GetStation(peep->CurrentRideStation).Exit;
Guard::Assert(!exit.IsNull());
x = exit.x;
y = exit.y;
x *= 32;
@ -3778,8 +3783,16 @@ static void PeepGoToRideExit(Peep* peep, const Ride& ride, int16_t x, int16_t y,
x += 16;
y += 16;
int16_t x_shift = DirectionOffsets[exit_direction].x;
int16_t y_shift = DirectionOffsets[exit_direction].y;
auto [x_shift, y_shift] = [exit_direction]() {
if (exit_direction < DirectionOffsets.size())
{
return std::pair(DirectionOffsets[exit_direction].x, DirectionOffsets[exit_direction].y);
}
else
{
return std::pair(0, 0);
}
}();
int16_t shift_multiplier = 20;
@ -3877,8 +3890,11 @@ static void PeepUpdateRideNoFreeVehicleRejoinQueue(Guest* peep, Ride& ride)
int32_t x = entranceLocation.x * 32;
int32_t y = entranceLocation.y * 32;
x += 16 - DirectionOffsets[entranceLocation.direction].x * 20;
y += 16 - DirectionOffsets[entranceLocation.direction].y * 20;
if (entranceLocation.direction < DirectionOffsets.size())
{
x += 16 - DirectionOffsets[entranceLocation.direction].x * 20;
y += 16 - DirectionOffsets[entranceLocation.direction].y * 20;
}
peep->SetDestination({ x, y }, 2);
peep->SetState(PeepState::QueuingFront);
@ -4188,8 +4204,16 @@ void Guest::UpdateRideLeaveVehicle()
}
}
int16_t xShift = DirectionOffsets[specialDirection].x;
int16_t yShift = DirectionOffsets[specialDirection].y;
auto [xShift, yShift] = [specialDirection]() {
if (specialDirection < DirectionOffsets.size())
{
return std::pair(DirectionOffsets[specialDirection].x, DirectionOffsets[specialDirection].y);
}
else
{
return std::pair(0, 0);
}
}();
platformLocation.x = vehicle->x + xShift * shiftMultiplier;
platformLocation.y = vehicle->y + yShift * shiftMultiplier;
@ -4237,7 +4261,10 @@ void Guest::UpdateRideLeaveVehicle()
}
auto exitLocation = station.Exit.ToCoordsXYZD();
Guard::Assert(!exitLocation.IsNull());
if (exitLocation.IsNull())
{
return;
}
TileElement* trackElement = RideGetStationStartTrackElement(*ride, CurrentRideStation);
@ -4297,8 +4324,17 @@ void Guest::UpdateRidePrepareForExit()
auto exit = ride->GetStation(CurrentRideStation).Exit;
auto newDestination = exit.ToCoordsXY().ToTileCentre();
auto xShift = DirectionOffsets[exit.direction].x;
auto yShift = DirectionOffsets[exit.direction].y;
auto [xShift, yShift] = [exit]() {
if (exit.direction < DirectionOffsets.size())
{
return std::pair(DirectionOffsets[exit.direction].x, DirectionOffsets[exit.direction].y);
}
else
{
return std::pair(0, 0);
}
}();
int16_t shiftMultiplier = 20;
@ -4618,7 +4654,12 @@ void Guest::UpdateRideApproachSpiralSlide()
{
auto exit = ride->GetStation(CurrentRideStation).Exit;
waypoint = 1;
Var37 = (exit.direction * 4) | (Var37 & 0x30) | waypoint;
auto directionTemp = exit.direction;
if (exit.direction == INVALID_DIRECTION)
{
directionTemp = 0;
}
Var37 = (directionTemp * 4) | (Var37 & 0x30) | waypoint;
CoordsXY targetLoc = ride->GetStation(CurrentRideStation).Start;
assert(rtd.HasFlag(RIDE_TYPE_FLAG_IS_SPIRAL_SLIDE));

View File

@ -61,8 +61,8 @@ static RideId _footpathQueueChain[64];
// This is the coordinates that a user of the bin should move to
// rct2: 0x00992A4C
const CoordsXY BinUseOffsets[4] = {
{ 11, 16 },
const std::array<CoordsXY, NumOrthogonalDirections> BinUseOffsets = {
CoordsXY{ 11, 16 },
{ 16, 21 },
{ 21, 16 },
{ 16, 11 },
@ -70,13 +70,13 @@ const CoordsXY BinUseOffsets[4] = {
// These are the offsets for bench positions on footpaths, 2 for each edge
// rct2: 0x00981F2C, 0x00981F2E
const CoordsXY BenchUseOffsets[8] = {
{ 7, 12 }, { 12, 25 }, { 25, 20 }, { 20, 7 }, { 7, 20 }, { 20, 25 }, { 25, 12 }, { 12, 7 },
const std::array<CoordsXY, NumOrthogonalDirections* 2> BenchUseOffsets = {
CoordsXY{ 7, 12 }, { 12, 25 }, { 25, 20 }, { 20, 7 }, { 7, 20 }, { 20, 25 }, { 25, 12 }, { 12, 7 },
};
/** rct2: 0x00981D6C, 0x00981D6E */
const CoordsXY DirectionOffsets[4] = {
{ -1, 0 },
const std::array<CoordsXY, NumOrthogonalDirections> DirectionOffsets = {
CoordsXY{ -1, 0 },
{ 0, 1 },
{ 1, 0 },
{ 0, -1 },

View File

@ -180,9 +180,9 @@ extern uint8_t gFootpathConstructSlope;
extern uint8_t gFootpathGroundFlags;
// Given a direction, this will return how to increase/decrease the x and y coordinates.
extern const CoordsXY DirectionOffsets[NumOrthogonalDirections];
extern const CoordsXY BinUseOffsets[NumOrthogonalDirections];
extern const CoordsXY BenchUseOffsets[NumOrthogonalDirections * 2];
extern const std::array<CoordsXY, NumOrthogonalDirections> DirectionOffsets;
extern const std::array<CoordsXY, NumOrthogonalDirections> BinUseOffsets;
extern const std::array<CoordsXY, NumOrthogonalDirections * 2> BenchUseOffsets;
TileElement* MapGetFootpathElement(const CoordsXYZ& coords);
void FootpathInterruptPeeps(const CoordsXYZ& footpathPos);