Fix #13250: Crash when opening parks with new ride types (#13256)

This only happens when a new ride type is added and the park is opened in the older version of the game where the ride type does not exist.

Reworked so that invalid rides are not loadable. Force reload of title if current scenario is corrupted.
This commit is contained in:
Duncan 2020-11-01 13:49:43 +00:00 committed by GitHub
parent 89cc45908f
commit dcabc8451e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 78 additions and 11 deletions

View File

@ -3651,6 +3651,7 @@ STR_6394 :Objective
STR_6395 :Maintenance
STR_6396 :Disable screensaver and monitor power saving
STR_6397 :{SMALLFONT}{BLACK}If checked, screensaver and other monitor power saving features will be inhibited while OpenRCT2 is running.
STR_6398 :File contains unsupported ride types. Please update to a newer version of OpenRCT2.
#############
# Scenarios #

View File

@ -1286,9 +1286,12 @@ static rct_window* window_ride_open(Ride* ride)
*/
rct_window* window_ride_main_open(Ride* ride)
{
rct_window* w;
if (ride->type >= RIDE_TYPE_COUNT)
{
return nullptr;
}
w = window_bring_to_front_by_number(WC_RIDE, ride->id);
rct_window* w = window_bring_to_front_by_number(WC_RIDE, ride->id);
if (w == nullptr)
{
w = window_ride_open(ride);
@ -1323,6 +1326,9 @@ rct_window* window_ride_main_open(Ride* ride)
*/
static rct_window* window_ride_open_station(Ride* ride, StationIndex stationIndex)
{
if (ride->type >= RIDE_TYPE_COUNT)
return nullptr;
if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_VEHICLES))
return window_ride_main_open(ride);

View File

@ -564,7 +564,7 @@ namespace OpenRCT2
auto fs = FileStream(path, FILE_MODE_OPEN);
if (!LoadParkFromStream(&fs, path, loadTitleScreenOnFail))
{
throw std::runtime_error("Failed to load park");
return false;
}
return true;
}
@ -610,6 +610,11 @@ namespace OpenRCT2
}
auto result = parkImporter->LoadFromStream(stream, info.Type == FILE_TYPE::SCENARIO, false, path.c_str());
// From this point onwards the currently loaded park will be corrupted if loading fails
// so reload the title screen if that happens.
loadTitleScreenFirstOnFail = true;
_objectManager->LoadObjects(result.RequiredObjects.data(), result.RequiredObjects.size());
parkImporter->Import();
gScenarioSavePath = path;
@ -663,6 +668,11 @@ namespace OpenRCT2
}
catch (const ObjectLoadException& e)
{
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
title_load();
}
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
auto intent = Intent(WC_OBJECT_LOAD_ERROR);
@ -675,22 +685,36 @@ namespace OpenRCT2
}
catch (const UnsupportedRCTCFlagException& e)
{
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
title_load();
}
auto windowManager = _uiContext->GetWindowManager();
auto ft = Formatter();
ft.Add<uint16_t>(e.Flag);
windowManager->ShowError(STR_FAILED_TO_LOAD_IMCOMPATIBLE_RCTC_FLAG, STR_NONE, ft);
}
catch (const UnsupportedRideTypeException&)
{
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
title_load();
}
auto windowManager = _uiContext->GetWindowManager();
windowManager->ShowError(STR_FILE_CONTAINS_UNSUPPORTED_RIDE_TYPES, STR_NONE, {});
}
catch (const std::exception& e)
{
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
title_load();
}
Console::Error::WriteLine(e.what());
}
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
title_load();
}
return false;
}

View File

@ -86,3 +86,14 @@ public:
{
}
};
class UnsupportedRideTypeException : public std::exception
{
public:
ObjectEntryIndex const Type;
explicit UnsupportedRideTypeException(ObjectEntryIndex type)
: Type(type)
{
}
};

View File

@ -138,6 +138,12 @@ public:
log_warning("Ride not found. ride index = %d.", rideIndex);
return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS);
}
if (ride->type >= RIDE_TYPE_COUNT)
{
log_warning("Ride type not found. ride type = %d.", ride->type);
return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS);
}
const rct_preview_track* trackBlock = get_track_def_from_ride(ride, trackType);
trackBlock += tileElement->AsTrack()->GetSequenceIndex();

View File

@ -3901,6 +3901,8 @@ enum
STR_DISABLE_SCREENSAVER = 6396,
STR_DISABLE_SCREENSAVER_TIP = 6397,
STR_FILE_CONTAINS_UNSUPPORTED_RIDE_TYPES = 6398,
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
/* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings
};

View File

@ -523,6 +523,12 @@ public:
rideType = RCT2RideTypeToOpenRCT2RideType(src->type, rideEntry);
}
}
if (rideType >= RIDE_TYPE_COUNT)
{
log_error("Invalid ride type for a ride in this save.");
throw UnsupportedRideTypeException(rideType);
}
dst->type = rideType;
dst->subtype = subtype;
// pad_002;
@ -1727,6 +1733,10 @@ void load_from_sv6(const char* path)
log_error("Error loading: %s", loadError.what());
show_error(ERROR_TYPE_FILE_LOAD, STR_GAME_SAVE_FAILED);
}
catch (const UnsupportedRideTypeException&)
{
show_error(ERROR_TYPE_FILE_LOAD, STR_FILE_CONTAINS_UNSUPPORTED_RIDE_TYPES);
}
catch (const std::exception&)
{
show_error(ERROR_TYPE_FILE_LOAD, STR_FILE_CONTAINS_INVALID_DATA);

View File

@ -196,7 +196,7 @@ static void ride_ratings_update_state_2()
{
const ride_id_t rideIndex = gRideRatingsCalcData.CurrentRide;
auto ride = get_ride(rideIndex);
if (ride == nullptr || ride->status == RIDE_STATUS_CLOSED)
if (ride == nullptr || ride->status == RIDE_STATUS_CLOSED || ride->type >= RIDE_TYPE_COUNT)
{
gRideRatingsCalcData.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE;
return;

View File

@ -2190,6 +2190,10 @@ void track_paint(paint_session* session, Direction direction, int32_t height, co
session->TrackColours[SCHEME_3] = ghost_id;
}
if (ride->type >= RIDE_TYPE_COUNT)
{
return;
}
TRACK_PAINT_FUNCTION_GETTER paintFunctionGetter = RideTypeDescriptors[ride->type].TrackPaintFunction;
if (paintFunctionGetter != nullptr)
{

View File

@ -1966,6 +1966,9 @@ void Vehicle::Update()
if (curRide == nullptr)
return;
if (curRide->type >= RIDE_TYPE_COUNT)
return;
if (HasUpdateFlag(VEHICLE_UPDATE_FLAG_TESTING))
UpdateMeasurements();
@ -6219,7 +6222,7 @@ GForces Vehicle::GetGForces() const
void Vehicle::SetMapToolbar() const
{
auto curRide = GetRide();
if (curRide != nullptr)
if (curRide != nullptr && curRide->type < RIDE_TYPE_COUNT)
{
const Vehicle* vehicle = GetHead();