From f149f369a17531ffc4e7d2f31bd8a03003b41f16 Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 8 Oct 2025 16:45:05 +0500 Subject: [PATCH] Store tool handlers as shared pointers --- src/citymania/cm_station_gui.cpp | 107 +++++++++++++++++-------------- src/citymania/cm_station_gui.hpp | 25 ++++---- src/citymania/cm_type.hpp | 49 ++++++-------- src/rail_gui.cpp | 2 +- src/station_gui.cpp | 7 ++ 5 files changed, 100 insertions(+), 90 deletions(-) diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index bf627a45b8..ba960bb644 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -731,7 +731,7 @@ template void RemoveAction::HandleMouseRelease() { auto area = this->GetArea(); if (!area.has_value()) return; - this->handler.Execute(area.value()); + this->handler->Execute(area.value()); this->start_tile = INVALID_TILE; } @@ -750,7 +750,7 @@ ToolGUIInfo RemoveAction::GetGUIInfo() { CommandCost cost; if (area.has_value()) { hlmap.AddTileAreaWithBorder(area.value(), CM_PALETTE_TINT_RED_DEEP); - auto cmd = this->handler.GetCommand(area.value()); + auto cmd = this->handler->GetCommand(area.value()); if (cmd) cost = cmd->test(); } return {hlmap, data, cost}; @@ -905,7 +905,7 @@ void SizedPlacementAction::Update(Point, TileIndex tile) { auto area = this->GetArea(); if (!area.has_value()) return; - auto cmdptr = this->handler.GetCommand(tile, INVALID_STATION); + auto cmdptr = this->handler->GetCommand(tile, INVALID_STATION); auto cmd = dynamic_cast(cmdptr.get()); if (cmd == nullptr) return; @@ -960,16 +960,16 @@ bool SizedPlacementAction::HandleMousePress() { template void SizedPlacementAction::HandleMouseRelease() { if (!IsValidTile(this->cur_tile)) return; - this->handler.Execute(this->cur_tile); + this->handler->Execute(this->cur_tile); } template ToolGUIInfo SizedPlacementAction::GetGUIInfo() { if (!IsValidTile(this->cur_tile)) return {}; - auto [sct, rad] = this->handler.GetCatchmentParams(); + auto [sct, rad] = this->handler->GetCatchmentParams(); return this->PrepareGUIInfo( - this->handler.GetObjectHighlight(this->cur_tile), - this->handler.GetCommand(this->cur_tile, INVALID_STATION), + this->handler->GetObjectHighlight(this->cur_tile), + this->handler->GetCommand(this->cur_tile, INVALID_STATION), sct, rad ); @@ -1004,7 +1004,7 @@ template void DragNDropPlacementAction::HandleMouseRelease() { auto area = this->GetArea(); if (!area.has_value()) return; - this->handler.Execute(area.value()); + this->handler->Execute(area.value()); this->start_tile = INVALID_TILE; } @@ -1012,11 +1012,11 @@ template ToolGUIInfo DragNDropPlacementAction::GetGUIInfo() { auto area = this->GetArea(); if (!area.has_value()) return {}; - auto ohl = this->handler.GetObjectHighlight(area.value()); - auto [sct, rad] = this->handler.GetCatchmentParams(); + auto ohl = this->handler->GetObjectHighlight(area.value()); + auto [sct, rad] = this->handler->GetCatchmentParams(); return this->PrepareGUIInfo( - this->handler.GetObjectHighlight(area.value()), - this->handler.GetCommand(area.value(), INVALID_STATION), + this->handler->GetObjectHighlight(area.value()), + this->handler->GetCommand(area.value(), INVALID_STATION), sct, rad ); @@ -1091,34 +1091,47 @@ StationBuildTool::StationBuildTool() { ResetHighlightCoverageStation(); } +extern void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc); + template -bool StationBuildTool::ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) { - if (auto mode = std::get_if(&_station_action)) { - auto cmd = handler->GetCommand(arg, mode->station); - return cmd ? cmd->post(callback) : false; - } +bool ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) { + std::visit(Overload{ + [&](StationAction::Join &action) { + Debug(misc, 0, "Join to {}", action.station); + auto cmd = handler->GetCommand(arg, action.station); + return cmd ? cmd->post(callback) : false; + }, + [&](StationAction::Create &) { + Debug(misc, 0, "Create new station"); + auto cmd = handler->GetCommand(arg, NEW_STATION); + return cmd ? cmd->post(callback) : false; + }, + [&](StationAction::Picker &) { + Debug(misc, 0, "Show picker"); + auto cmd = handler->GetCommand(arg, INVALID_STATION); + auto proc = [cmd=sp{std::move(cmd)}, callback](bool test, StationID to_join) -> bool { + if (!cmd) return false; + auto station_cmd = dynamic_cast(cmd.get()); + if (station_cmd == nullptr) return false; + station_cmd->station_to_join = to_join; + if (test) { + return cmd->test().Succeeded(); + } else { + ResetSelectedStationToJoin(); + return cmd->post(callback); + } + }; - // Vanilla joining behaviour - auto cmd = handler->GetCommand(arg, INVALID_STATION); - auto proc = [cmd=sp{std::move(cmd)}, callback](bool test, StationID to_join) -> bool { - if (!cmd) return false; - auto station_cmd = dynamic_cast(cmd.get()); - if (station_cmd == nullptr) return false; - station_cmd->station_to_join = to_join; - if (test) { - return cmd->test().Succeeded(); - } else { - ResetSelectedStationToJoin(); - return cmd->post(callback); + auto ohl = handler->GetObjectHighlight(arg); + if (!ohl.has_value()) return false; + auto area = ohl->GetArea(); + if (!area.has_value()) return false; + // SetActiveHighlightObject(ohl); + ShowSelectStationWindow(*area, std::move(proc)); + return true; } - }; + }, _station_action); - auto ohl = handler->GetObjectHighlight(arg); - if (!ohl.has_value()) return false; - auto area = ohl->GetArea(); - if (!area.has_value()) return false; - SetActiveHighlightObject(ohl); - ShowSelectStationIfNeeded(area.value(), proc); return true; } @@ -1159,14 +1172,14 @@ up RailStationBuildTool::SizedPlacementHandler::GetCommand(TileIndex ti _railstation.station_class, _railstation.station_type, to_join, - _fn_mod + true ); cmd->with_error(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION); return cmd; } bool RailStationBuildTool::SizedPlacementHandler::Execute(TileIndex tile) { - return this->tool.ExecuteBuildCommand(this, &CcStation, tile); + return ExecuteBuildCommand(this, &CcStation, tile); } up RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea area, StationID to_join) { @@ -1184,14 +1197,14 @@ up RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea _railstation.station_class, _railstation.station_type, to_join, - _fn_mod + true ); cmd->with_error(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION); return cmd; } bool RailStationBuildTool::DragNDropPlacementHandler::Execute(TileArea area) { - return this->tool.ExecuteBuildCommand(this, &CcStation, area); + return ExecuteBuildCommand(this, &CcStation, area); } std::optional RailStationBuildTool::DragNDropPlacementHandler::GetObjectHighlight(TileArea area) { @@ -1203,7 +1216,7 @@ std::optional RailStationBuildTool::SizedPlacementHandler::GetO } RailStationBuildTool::RailStationBuildTool() : mode(Mode::SIZED) { - this->action = make_up>(SizedPlacementHandler(*this)); + this->action = make_up>(*this); } void RailStationBuildTool::Update(Point pt, TileIndex tile) { @@ -1292,14 +1305,14 @@ up RoadStopBuildTool::DragNDropPlacementHandler::GetCommand(TileArea ar _roadstop_gui_settings.roadstop_class, _roadstop_gui_settings.roadstop_type, to_join, - _fn_mod + true ); return res; } bool RoadStopBuildTool::DragNDropPlacementHandler::Execute(TileArea area) { - return this->tool.ExecuteBuildCommand(this, &CcRoadStop, area); + return ExecuteBuildCommand(this, &CcRoadStop, area); } std::optional RoadStopBuildTool::DragNDropPlacementHandler::GetObjectHighlight(TileArea area) { @@ -1400,13 +1413,13 @@ up DockBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, Sta return make_up( tile, to_join, - _fn_mod + true ); } bool DockBuildTool::SizedPlacementHandler::Execute(TileIndex tile) { - return this->tool.ExecuteBuildCommand(this, &CcBuildDocks, tile); + return ExecuteBuildCommand(this, &CcBuildDocks, tile); } std::optional DockBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) { @@ -1489,14 +1502,14 @@ up AirportBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, airport_type, layout, to_join, - _fn_mod + true ); cmd->with_error(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE); return cmd; } bool AirportBuildTool::SizedPlacementHandler::Execute(TileIndex tile) { - this->tool.ExecuteBuildCommand(this, &CcBuildAirport, tile); + ExecuteBuildCommand(this, &CcBuildAirport, tile); } std::optional AirportBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) { diff --git a/src/citymania/cm_station_gui.hpp b/src/citymania/cm_station_gui.hpp index f57cef7e54..1bf954308c 100644 --- a/src/citymania/cm_station_gui.hpp +++ b/src/citymania/cm_station_gui.hpp @@ -76,11 +76,12 @@ concept ImplementsRemoveHandler = std::derived_from; template class RemoveAction : public Action { private: - Handler handler; + sp handler; TileIndex start_tile = INVALID_TILE; TileIndex cur_tile = INVALID_TILE; public: - RemoveAction(const Handler &handler) : handler{handler} {} + template + RemoveAction(T &tool) { this->handler = make_sp(tool); }; ~RemoveAction() override = default; void Update(Point pt, TileIndex tile) override; std::optional GetArea() const override; @@ -102,10 +103,11 @@ concept ImplementsStationSelectHandler = std::derived_from class StationSelectAction : public Action { private: - Handler handler; + sp handler; TileIndex cur_tile = INVALID_TILE; public: - StationSelectAction(const Handler &handler) : handler{handler} {} + template + StationSelectAction(T &tool) { this->handler = make_sp(tool); }; ~StationSelectAction() override = default; void Update(Point pt, TileIndex tile) override; bool HandleMousePress() override; @@ -137,13 +139,14 @@ concept ImplementsSizedPlacementHandler = std::derived_from class SizedPlacementAction : public PlacementAction { private: - Handler handler; + sp handler; TileIndex cur_tile = INVALID_TILE; public: - SizedPlacementAction(const Handler &handler) : handler{handler} {} + template + SizedPlacementAction(T &tool) { this->handler = make_sp(tool); }; ~SizedPlacementAction() override = default; void Update(Point pt, TileIndex tile) override; - std::optional GetArea() const override { return this->handler.GetArea(this->cur_tile); } + std::optional GetArea() const override { return this->handler->GetArea(this->cur_tile); } bool HandleMousePress() override; void HandleMouseRelease() override; ToolGUIInfo GetGUIInfo() override; @@ -167,9 +170,10 @@ class DragNDropPlacementAction : public PlacementAction { private: TileIndex start_tile = INVALID_TILE; TileIndex cur_tile = INVALID_TILE; - Handler handler; + sp handler; public: - DragNDropPlacementAction(const Handler &handler) :handler{handler} {}; + template + DragNDropPlacementAction(T &tool) { this->handler = make_sp(tool); }; ~DragNDropPlacementAction() override = default; void Update(Point pt, TileIndex tile) override; std::optional GetArea() const override; @@ -201,8 +205,6 @@ public: if (this->action) this->action->OnStationRemoved(station); } protected: - template - bool ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg); }; // RailStationBuildTool @@ -211,6 +213,7 @@ private: class RemoveHandler : public citymania::RemoveHandler { public: RailStationBuildTool &tool; + // TODO storing tools in handlers isn't safe because of shared pointers RemoveHandler(RailStationBuildTool &tool) : tool(tool) {} ~RemoveHandler() override = default; up GetCommand(TileArea area) override; diff --git a/src/citymania/cm_type.hpp b/src/citymania/cm_type.hpp index 4ee075e909..d824fbb3ce 100644 --- a/src/citymania/cm_type.hpp +++ b/src/citymania/cm_type.hpp @@ -17,39 +17,17 @@ template using up=std::unique_ptr; template using sp=std::shared_ptr; template using wp=std::weak_ptr; -/* C++14 implementation of make_unique */ -template struct _Unique_if { - typedef std::unique_ptr _Single_object; -}; +template +constexpr auto make_up(Args&&... args) { + return std::make_unique(std::forward(args)...); +} -template struct _Unique_if { - typedef std::unique_ptr _Unknown_bound; -}; +template +constexpr auto make_sp(Args&&... args) { + return std::make_shared(std::forward(args)...); +} -template struct _Unique_if { - typedef void _Known_bound; -}; - -template - typename _Unique_if::_Single_object - make_up(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); - } - -template - typename _Unique_if::_Unknown_bound - make_up(size_t n) { - typedef typename std::remove_extent::type U; - return std::unique_ptr(new U[n]()); - } - -template - typename _Unique_if::_Known_bound - make_up(Args&&...) = delete; - -// template const auto make_up = std::make_unique; -// template const auto make_sp = std::make_shared; -template const auto make_sp = std::make_shared; +// template constexpr auto make_sp = std::make_shared; enum class GameType: uint8_t { @@ -73,6 +51,15 @@ enum class ControllerType: uint8_t { TOWN_DEFENCE = 6, }; + +// For use with std::visit +template +struct Overload : Ts ... { + using Ts::operator() ...; +}; +template Overload(Ts...) -> Overload; + + // Some utility funcitons for strings namespace string { diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 15db979b90..ed8b2ef5f7 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -7,7 +7,6 @@ /** @file rail_gui.cpp %File for dealing with rail construction user interface */ -#include "citymania/cm_highlight_type.hpp" #include "stdafx.h" #include "gui.h" #include "window_gui.h" @@ -52,6 +51,7 @@ #include "debug.h" #include "citymania/cm_blueprint.hpp" #include "citymania/cm_commands.hpp" +#include "citymania/cm_highlight_type.hpp" #include "citymania/cm_hotkeys.hpp" #include "citymania/cm_highlight.hpp" #include "citymania/cm_station_gui.hpp" diff --git a/src/station_gui.cpp b/src/station_gui.cpp index b9e96eb818..fab9930446 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2520,3 +2520,10 @@ void ShowSelectWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc) { ShowSelectBaseStationIfNeeded(ta, std::move(proc)); } + +namespace citymania { + void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc) { + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); + new SelectStationWindow(&_select_station_desc, ta, std::move(proc)); + } +}