Merge pull request #15816 from ZehMatt/refactor/15630

Close #15630: Refactor TrackDesign
This commit is contained in:
Michael Steenbeek 2021-11-07 19:53:32 +01:00 committed by GitHub
commit 084b752fb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 588 additions and 531 deletions

View File

@ -81,7 +81,7 @@ static void window_install_track_design(rct_window* w);
*/ */
rct_window* window_install_track_open(const utf8* path) rct_window* window_install_track_open(const utf8* path)
{ {
_trackDesign = track_design_open(path); _trackDesign = TrackDesignImport(path);
if (_trackDesign == nullptr) if (_trackDesign == nullptr)
{ {
context_show_error(STR_UNABLE_TO_LOAD_FILE, STR_NONE, {}); context_show_error(STR_UNABLE_TO_LOAD_FILE, STR_NONE, {});
@ -422,7 +422,7 @@ static void window_install_track_text_input(rct_window* w, rct_widgetindex widge
static void window_install_track_update_preview() static void window_install_track_update_preview()
{ {
track_design_draw_preview(_trackDesign.get(), _trackDesignPreviewPixels.data()); TrackDesignDrawPreview(_trackDesign.get(), _trackDesignPreviewPixels.data());
} }
static void window_install_track_design(rct_window* w) static void window_install_track_design(rct_window* w)

View File

@ -5325,7 +5325,8 @@ static void window_ride_measurements_design_save(rct_window* w)
if (gTrackDesignSaveMode) if (gTrackDesignSaveMode)
{ {
auto errMessage = _trackDesign->CreateTrackDesignScenery(); TrackDesignState tds{};
auto errMessage = _trackDesign->CreateTrackDesignScenery(tds);
if (errMessage != STR_NONE) if (errMessage != STR_NONE)
{ {
context_show_error(STR_CANT_SAVE_TRACK_DESIGN, errMessage, {}); context_show_error(STR_CANT_SAVE_TRACK_DESIGN, errMessage, {});

View File

@ -133,7 +133,7 @@ static void window_track_place_clear_mini_preview()
*/ */
rct_window* window_track_place_open(const track_design_file_ref* tdFileRef) rct_window* window_track_place_open(const track_design_file_ref* tdFileRef)
{ {
_trackDesign = track_design_open(tdFileRef->path); _trackDesign = TrackDesignImport(tdFileRef->path);
if (_trackDesign == nullptr) if (_trackDesign == nullptr)
{ {
return nullptr; return nullptr;
@ -197,7 +197,7 @@ static void window_track_place_mouseup(rct_window* w, rct_widgetindex widgetInde
window_track_place_draw_mini_preview(_trackDesign.get()); window_track_place_draw_mini_preview(_trackDesign.get());
break; break;
case WIDX_MIRROR: case WIDX_MIRROR:
track_design_mirror(_trackDesign.get()); TrackDesignMirror(_trackDesign.get());
_currentTrackPieceDirection = (0 - _currentTrackPieceDirection) & 3; _currentTrackPieceDirection = (0 - _currentTrackPieceDirection) & 3;
w->Invalidate(); w->Invalidate();
_windowTrackPlaceLast.SetNull(); _windowTrackPlaceLast.SetNull();
@ -268,8 +268,7 @@ static void window_track_place_toolupdate(rct_window* w, rct_widgetindex widgetI
// Check if tool map position has changed since last update // Check if tool map position has changed since last update
if (mapCoords == _windowTrackPlaceLast) if (mapCoords == _windowTrackPlaceLast)
{ {
place_virtual_track( TrackDesignPreviewDrawOutlines(_trackDesign.get(), GetOrAllocateRide(PreviewRideId), { mapCoords, 0 });
_trackDesign.get(), PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(PreviewRideId), { mapCoords, 0 });
return; return;
} }
@ -309,7 +308,7 @@ static void window_track_place_toolupdate(rct_window* w, rct_widgetindex widgetI
widget_invalidate(w, WIDX_PRICE); widget_invalidate(w, WIDX_PRICE);
} }
place_virtual_track(_trackDesign.get(), PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(PreviewRideId), trackLoc); TrackDesignPreviewDrawOutlines(_trackDesign.get(), GetOrAllocateRide(PreviewRideId), trackLoc);
} }
/** /**
@ -413,7 +412,7 @@ static void window_track_place_clear_provisional()
auto ride = get_ride(_window_track_place_ride_index); auto ride = get_ride(_window_track_place_ride_index);
if (ride != nullptr) if (ride != nullptr)
{ {
place_virtual_track(_trackDesign.get(), PTD_OPERATION_REMOVE_GHOST, true, ride, _windowTrackPlaceLastValid); TrackDesignPreviewRemoveGhosts(_trackDesign.get(), ride, _windowTrackPlaceLastValid);
_window_track_place_last_was_valid = false; _window_track_place_last_was_valid = false;
} }
} }
@ -426,7 +425,7 @@ void TrackPlaceClearProvisionalTemporarily()
auto ride = get_ride(_window_track_place_ride_index); auto ride = get_ride(_window_track_place_ride_index);
if (ride != nullptr) if (ride != nullptr)
{ {
place_virtual_track(_trackDesign.get(), PTD_OPERATION_REMOVE_GHOST, true, ride, _windowTrackPlaceLastValid); TrackDesignPreviewRemoveGhosts(_trackDesign.get(), ride, _windowTrackPlaceLastValid);
} }
} }
} }
@ -471,9 +470,7 @@ static int32_t window_track_place_get_base_z(const CoordsXY& loc)
if (surfaceElement->GetWaterHeight() > 0) if (surfaceElement->GetWaterHeight() > 0)
z = std::max(z, surfaceElement->GetWaterHeight()); z = std::max(z, surfaceElement->GetWaterHeight());
return z return z + TrackDesignGetZPlacement(_trackDesign.get(), GetOrAllocateRide(PreviewRideId), { loc, z });
+ place_virtual_track(
_trackDesign.get(), PTD_OPERATION_GET_PLACE_Z, true, GetOrAllocateRide(PreviewRideId), { loc, z });
} }
/** /**

View File

@ -186,10 +186,10 @@ private:
bool LoadDesignPreview(utf8* path) bool LoadDesignPreview(utf8* path)
{ {
_loadedTrackDesign = track_design_open(path); _loadedTrackDesign = TrackDesignImport(path);
if (_loadedTrackDesign != nullptr) if (_loadedTrackDesign != nullptr)
{ {
track_design_draw_preview(_loadedTrackDesign.get(), _trackDesignPreviewPixels.data()); TrackDesignDrawPreview(_loadedTrackDesign.get(), _trackDesignPreviewPixels.data());
return true; return true;
} }
return false; return false;

View File

@ -21,12 +21,6 @@
#include "RideSetSettingAction.h" #include "RideSetSettingAction.h"
#include "RideSetVehicleAction.h" #include "RideSetVehicleAction.h"
static int32_t place_virtual_track(
const TrackDesign& td6, uint8_t ptdOperation, bool placeScenery, Ride* ride, const CoordsXYZ& loc)
{
return place_virtual_track(const_cast<TrackDesign*>(&td6), ptdOperation, placeScenery, ride, loc);
}
TrackDesignAction::TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td) TrackDesignAction::TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td)
: _loc(location) : _loc(location)
, _td(td) , _td(td)
@ -95,26 +89,36 @@ GameActions::Result::Ptr TrackDesignAction::Query() const
return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE);
} }
money32 cost = 0;
bool placeScenery = true; bool placeScenery = true;
cost = place_virtual_track(_td, PTD_OPERATION_PLACE_QUERY, placeScenery, ride, _loc);
uint32_t flags = 0;
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
flags |= GAME_COMMAND_FLAG_GHOST;
if (GetFlags() & GAME_COMMAND_FLAG_REPLAY)
flags |= GAME_COMMAND_FLAG_REPLAY;
auto queryRes = TrackDesignPlace(const_cast<TrackDesign*>(&_td), flags, placeScenery, ride, _loc);
if (_trackDesignPlaceStateSceneryUnavailable) if (_trackDesignPlaceStateSceneryUnavailable)
{ {
placeScenery = false; placeScenery = false;
cost = place_virtual_track(_td, PTD_OPERATION_PLACE_QUERY, placeScenery, ride, _loc); queryRes = TrackDesignPlace(const_cast<TrackDesign*>(&_td), flags, placeScenery, ride, _loc);
} }
rct_string_id error_reason = gGameCommandErrorText;
auto gameAction = RideDemolishAction(ride->id, RIDE_MODIFY_DEMOLISH); auto gameAction = RideDemolishAction(ride->id, RIDE_MODIFY_DEMOLISH);
gameAction.SetFlags(GetFlags()); gameAction.SetFlags(GetFlags());
GameActions::ExecuteNested(&gameAction); GameActions::ExecuteNested(&gameAction);
if (cost == MONEY32_UNDEFINED)
if (queryRes->Error != GameActions::Status::Ok)
{ {
return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, error_reason); res->Error = queryRes->Error;
res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
res->ErrorMessage = queryRes->ErrorMessage;
res->ErrorMessageArgs = queryRes->ErrorMessageArgs;
return res;
} }
res->Cost = cost;
res->Cost = queryRes->Cost;
res->SetData(ride_id_t{ RIDE_ID_NULL }); res->SetData(ride_id_t{ RIDE_ID_NULL });
return res; return res;
@ -157,42 +161,52 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const
return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE);
} }
money32 cost = 0; // Query first, this is required again to determine if scenery is available.
bool placeScenery = true; bool placeScenery = true;
cost = place_virtual_track(_td, PTD_OPERATION_PLACE_QUERY, placeScenery, ride, _loc);
uint32_t flags = 0;
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
flags |= GAME_COMMAND_FLAG_GHOST;
if (GetFlags() & GAME_COMMAND_FLAG_REPLAY)
flags |= GAME_COMMAND_FLAG_REPLAY;
auto queryRes = TrackDesignPlace(const_cast<TrackDesign*>(&_td), flags, placeScenery, ride, _loc);
if (_trackDesignPlaceStateSceneryUnavailable) if (_trackDesignPlaceStateSceneryUnavailable)
{ {
placeScenery = false; placeScenery = false;
cost = place_virtual_track(_td, PTD_OPERATION_PLACE_QUERY, placeScenery, ride, _loc); queryRes = TrackDesignPlace(const_cast<TrackDesign*>(&_td), flags, placeScenery, ride, _loc);
} }
if (cost != MONEY32_UNDEFINED) if (queryRes->Error != GameActions::Status::Ok)
{ {
uint8_t operation;
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
{
operation = PTD_OPERATION_PLACE_GHOST;
}
else
{
operation = PTD_OPERATION_PLACE;
}
if (GetFlags() & GAME_COMMAND_FLAG_REPLAY)
{
operation |= PTD_OPERATION_FLAG_IS_REPLAY;
}
cost = place_virtual_track(_td, operation, placeScenery, ride, _loc);
}
if (cost == MONEY32_UNDEFINED)
{
rct_string_id error_reason = gGameCommandErrorText;
auto gameAction = RideDemolishAction(ride->id, RIDE_MODIFY_DEMOLISH); auto gameAction = RideDemolishAction(ride->id, RIDE_MODIFY_DEMOLISH);
gameAction.SetFlags(GetFlags()); gameAction.SetFlags(GetFlags());
GameActions::ExecuteNested(&gameAction); GameActions::ExecuteNested(&gameAction);
return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, error_reason);
res->Error = queryRes->Error;
res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
res->ErrorMessage = queryRes->ErrorMessage;
res->ErrorMessageArgs = queryRes->ErrorMessageArgs;
return res;
}
// Execute.
flags |= GAME_COMMAND_FLAG_APPLY;
auto execRes = TrackDesignPlace(const_cast<TrackDesign*>(&_td), flags, placeScenery, ride, _loc);
if (execRes->Error != GameActions::Status::Ok)
{
auto gameAction = RideDemolishAction(ride->id, RIDE_MODIFY_DEMOLISH);
gameAction.SetFlags(GetFlags());
GameActions::ExecuteNested(&gameAction);
res->Error = execRes->Error;
res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
res->ErrorMessage = execRes->ErrorMessage;
res->ErrorMessageArgs = execRes->ErrorMessageArgs;
return res;
} }
if (entryIndex != OBJECT_ENTRY_INDEX_NULL) if (entryIndex != OBJECT_ENTRY_INDEX_NULL)
@ -250,7 +264,7 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const
gameAction.SetFlags(GetFlags()); gameAction.SetFlags(GetFlags());
r = GameActions::ExecuteNested(&gameAction); r = GameActions::ExecuteNested(&gameAction);
} }
res->Cost = cost; res->Cost = execRes->Cost;
res->SetData(ride_id_t{ ride->id }); res->SetData(ride_id_t{ ride->id });
return res; return res;

View File

@ -963,8 +963,9 @@ std::unique_ptr<TrackDesign> Ride::SaveToTrackDesign() const
return nullptr; return nullptr;
} }
auto tds = TrackDesignState{};
auto td = std::make_unique<TrackDesign>(); auto td = std::make_unique<TrackDesign>();
auto errMessage = td->CreateTrackDesign(*this); auto errMessage = td->CreateTrackDesign(tds, *this);
if (errMessage != STR_NONE) if (errMessage != STR_NONE)
{ {
context_show_error(STR_CANT_SAVE_TRACK_DESIGN, errMessage, {}); context_show_error(STR_CANT_SAVE_TRACK_DESIGN, errMessage, {});

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include "../actions/GameActionResult.h"
#include "../common.h" #include "../common.h"
#include "../object/Object.h" #include "../object/Object.h"
#include "../rct12/RCT12.h" #include "../rct12/RCT12.h"
@ -19,6 +20,20 @@ struct Ride;
#define TRACK_PREVIEW_IMAGE_SIZE (370 * 217) #define TRACK_PREVIEW_IMAGE_SIZE (370 * 217)
struct TrackDesignState
{
CoordsXYZ PreviewMin;
CoordsXYZ PreviewMax;
CoordsXYZ Origin;
uint8_t PlaceOperation{};
int16_t PlaceZ{};
int16_t PlaceSceneryZ{};
bool EntranceExitPlaced{};
bool HasScenery{};
bool PlaceScenery{};
bool IsReplay{};
};
/* Track Entrance entry */ /* Track Entrance entry */
struct TrackDesignEntranceElement struct TrackDesignEntranceElement
{ {
@ -134,14 +149,14 @@ struct TrackDesign
std::string name; std::string name;
public: public:
rct_string_id CreateTrackDesign(const Ride& ride); rct_string_id CreateTrackDesign(TrackDesignState& tds, const Ride& ride);
rct_string_id CreateTrackDesignScenery(); rct_string_id CreateTrackDesignScenery(TrackDesignState& tds);
void Serialise(DataSerialiser& stream); void Serialise(DataSerialiser& stream);
private: private:
uint8_t _saveDirection; uint8_t _saveDirection;
rct_string_id CreateTrackDesignTrack(const Ride& ride); rct_string_id CreateTrackDesignTrack(TrackDesignState& tds, const Ride& ride);
rct_string_id CreateTrackDesignMaze(const Ride& ride); rct_string_id CreateTrackDesignMaze(TrackDesignState& tds, const Ride& ride);
CoordsXYE MazeGetFirstElement(const Ride& ride); CoordsXYE MazeGetFirstElement(const Ride& ride);
}; };
@ -206,16 +221,20 @@ extern bool _trackDesignPlaceStateSceneryUnavailable;
extern bool gTrackDesignSaveMode; extern bool gTrackDesignSaveMode;
extern ride_id_t gTrackDesignSaveRideIndex; extern ride_id_t gTrackDesignSaveRideIndex;
[[nodiscard]] std::unique_ptr<TrackDesign> track_design_open(const utf8* path); [[nodiscard]] std::unique_ptr<TrackDesign> TrackDesignImport(const utf8* path);
void track_design_mirror(TrackDesign* td6); void TrackDesignMirror(TrackDesign* td6);
money32 place_virtual_track(TrackDesign* td6, uint8_t ptdOperation, bool placeScenery, Ride* ride, const CoordsXYZ& coords); GameActions::Result::Ptr TrackDesignPlace(
TrackDesign* td6, uint32_t flags, bool placeScenery, Ride* ride, const CoordsXYZ& coords);
void TrackDesignPreviewRemoveGhosts(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords);
void TrackDesignPreviewDrawOutlines(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords);
int32_t TrackDesignGetZPlacement(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Track design preview // Track design preview
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void track_design_draw_preview(TrackDesign* td6, uint8_t* pixels); void TrackDesignDrawPreview(TrackDesign* td6, uint8_t* pixels);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Track design saving // Track design saving

View File

@ -75,7 +75,7 @@ public:
public: public:
std::tuple<bool, TrackRepositoryItem> Create(int32_t, const std::string& path) const override std::tuple<bool, TrackRepositoryItem> Create(int32_t, const std::string& path) const override
{ {
auto td6 = track_design_open(path.c_str()); auto td6 = TrackDesignImport(path.c_str());
if (td6 != nullptr) if (td6 != nullptr)
{ {
TrackRepositoryItem item; TrackRepositoryItem item;