From cddb8a4605570666e076ab0e0f7b1f986f393e17 Mon Sep 17 00:00:00 2001 From: Charles Pigott Date: Fri, 3 Jan 2020 12:14:06 +0000 Subject: [PATCH] Fix #7587: Crash when loading saves with waypoints with invalid locations --- src/saveload/waypoint_sl.cpp | 45 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/saveload/waypoint_sl.cpp b/src/saveload/waypoint_sl.cpp index c0570f81d3..0cba4b8d06 100644 --- a/src/saveload/waypoint_sl.cpp +++ b/src/saveload/waypoint_sl.cpp @@ -9,6 +9,7 @@ #include "../stdafx.h" #include "../waypoint_base.h" +#include "../debug.h" #include "../newgrf_station.h" #include "../vehicle_base.h" #include "../town.h" @@ -98,33 +99,45 @@ void MoveWaypointsToBaseStations() /* All saveload conversions have been done. Create the new waypoints! */ for (OldWaypoint &wp : _old_waypoints) { - Waypoint *new_wp = new Waypoint(wp.xy); + TileIndex t = wp.xy; + /* Sometimes waypoint (sign) locations became disconnected from their actual location in + * the map array. If this is the case, try to locate the actual location in the map array */ + if (!IsTileType(t, MP_RAILWAY) || GetRailTileType(t) != 2 /* RAIL_TILE_WAYPOINT */ || _m[t].m2 != wp.index) { + DEBUG(sl, 0, "Found waypoint tile %u with invalid position", t); + for (t = 0; t < MapSize(); t++) { + if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp.index) { + DEBUG(sl, 0, "Found actual waypoint position at %u", t); + break; + } + } + } + if (t == MapSize()) { + SlErrorCorrupt("Waypoint with invalid tile"); + } + + Waypoint *new_wp = new Waypoint(t); new_wp->town = wp.town; new_wp->town_cn = wp.town_cn; new_wp->name = wp.name; new_wp->delete_ctr = 0; // Just reset delete counter for once. new_wp->build_date = wp.build_date; new_wp->owner = wp.owner; + new_wp->string_id = STR_SV_STNAME_WAYPOINT; - new_wp->string_id = STR_SV_STNAME_WAYPOINT; + /* The tile might've been reserved! */ + bool reserved = !IsSavegameVersionBefore(SLV_100) && HasBit(_m[t].m5, 4); - TileIndex t = wp.xy; - if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp.index) { - /* The tile might've been reserved! */ - bool reserved = !IsSavegameVersionBefore(SLV_100) && HasBit(_m[t].m5, 4); + /* The tile really has our waypoint, so reassign the map array */ + MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t)); + new_wp->facilities |= FACIL_TRAIN; + new_wp->owner = GetTileOwner(t); - /* The tile really has our waypoint, so reassign the map array */ - MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t)); - new_wp->facilities |= FACIL_TRAIN; - new_wp->owner = GetTileOwner(t); + SetRailStationReservation(t, reserved); - SetRailStationReservation(t, reserved); - - if (wp.spec != nullptr) { - SetCustomStationSpecIndex(t, AllocateSpecToStation(wp.spec, new_wp, true)); - } - new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); + if (wp.spec != nullptr) { + SetCustomStationSpecIndex(t, AllocateSpecToStation(wp.spec, new_wp, true)); } + new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); wp.new_index = new_wp->index; }