Store tool handlers as shared pointers

This commit is contained in:
dP
2025-10-08 16:45:05 +05:00
parent 0ba1ed61a5
commit f149f369a1
5 changed files with 100 additions and 90 deletions

View File

@@ -731,7 +731,7 @@ template <ImplementsRemoveHandler Handler>
void RemoveAction<Handler>::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<Handler>::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<Handler>::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<cmd::BuildRailStation *>(cmdptr.get());
if (cmd == nullptr) return;
@@ -960,16 +960,16 @@ bool SizedPlacementAction<Handler>::HandleMousePress() {
template <ImplementsSizedPlacementHandler Handler>
void SizedPlacementAction<Handler>::HandleMouseRelease() {
if (!IsValidTile(this->cur_tile)) return;
this->handler.Execute(this->cur_tile);
this->handler->Execute(this->cur_tile);
}
template <ImplementsSizedPlacementHandler Handler>
ToolGUIInfo SizedPlacementAction<Handler>::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 <ImplementsDragNDropPlacementHandler Handler>
void DragNDropPlacementAction<Handler>::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 <ImplementsDragNDropPlacementHandler Handler>
ToolGUIInfo DragNDropPlacementAction<Handler>::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,14 +1091,23 @@ StationBuildTool::StationBuildTool() {
ResetHighlightCoverageStation();
}
template<typename Thandler, typename Tcallback, typename Targ>
bool StationBuildTool::ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) {
if (auto mode = std::get_if<StationAction::Join>(&_station_action)) {
auto cmd = handler->GetCommand(arg, mode->station);
return cmd ? cmd->post(callback) : false;
}
extern void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc);
// Vanilla joining behaviour
template<typename Thandler, typename Tcallback, typename Targ>
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<Command>{std::move(cmd)}, callback](bool test, StationID to_join) -> bool {
if (!cmd) return false;
@@ -1117,8 +1126,12 @@ bool StationBuildTool::ExecuteBuildCommand(Thandler *handler, Tcallback callback
if (!ohl.has_value()) return false;
auto area = ohl->GetArea();
if (!area.has_value()) return false;
SetActiveHighlightObject(ohl);
ShowSelectStationIfNeeded(area.value(), proc);
// SetActiveHighlightObject(ohl);
ShowSelectStationWindow(*area, std::move(proc));
return true;
}
}, _station_action);
return true;
}
@@ -1159,14 +1172,14 @@ up<Command> 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<Command> RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea area, StationID to_join) {
@@ -1184,14 +1197,14 @@ up<Command> 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<ObjectHighlight> RailStationBuildTool::DragNDropPlacementHandler::GetObjectHighlight(TileArea area) {
@@ -1203,7 +1216,7 @@ std::optional<ObjectHighlight> RailStationBuildTool::SizedPlacementHandler::GetO
}
RailStationBuildTool::RailStationBuildTool() : mode(Mode::SIZED) {
this->action = make_up<SizedPlacementAction<SizedPlacementHandler>>(SizedPlacementHandler(*this));
this->action = make_up<SizedPlacementAction<SizedPlacementHandler>>(*this);
}
void RailStationBuildTool::Update(Point pt, TileIndex tile) {
@@ -1292,14 +1305,14 @@ up<Command> 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<ObjectHighlight> RoadStopBuildTool::DragNDropPlacementHandler::GetObjectHighlight(TileArea area) {
@@ -1400,13 +1413,13 @@ up<Command> DockBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, Sta
return make_up<cmd::BuildDock>(
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<ObjectHighlight> DockBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) {
@@ -1489,14 +1502,14 @@ up<Command> 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<ObjectHighlight> AirportBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) {

View File

@@ -76,11 +76,12 @@ concept ImplementsRemoveHandler = std::derived_from<Handler, RemoveHandler>;
template<ImplementsRemoveHandler Handler>
class RemoveAction : public Action {
private:
Handler handler;
sp<Handler> handler;
TileIndex start_tile = INVALID_TILE;
TileIndex cur_tile = INVALID_TILE;
public:
RemoveAction(const Handler &handler) : handler{handler} {}
template<typename T>
RemoveAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~RemoveAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override;
@@ -102,10 +103,11 @@ concept ImplementsStationSelectHandler = std::derived_from<Handler, StationSelec
template<ImplementsStationSelectHandler Handler>
class StationSelectAction : public Action {
private:
Handler handler;
sp<Handler> handler;
TileIndex cur_tile = INVALID_TILE;
public:
StationSelectAction(const Handler &handler) : handler{handler} {}
template<typename T>
StationSelectAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~StationSelectAction() override = default;
void Update(Point pt, TileIndex tile) override;
bool HandleMousePress() override;
@@ -137,13 +139,14 @@ concept ImplementsSizedPlacementHandler = std::derived_from<Handler, SizedPlacem
template<ImplementsSizedPlacementHandler Handler>
class SizedPlacementAction : public PlacementAction {
private:
Handler handler;
sp<Handler> handler;
TileIndex cur_tile = INVALID_TILE;
public:
SizedPlacementAction(const Handler &handler) : handler{handler} {}
template<typename T>
SizedPlacementAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~SizedPlacementAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override { return this->handler.GetArea(this->cur_tile); }
std::optional<TileArea> 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> handler;
public:
DragNDropPlacementAction(const Handler &handler) :handler{handler} {};
template<typename T>
DragNDropPlacementAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~DragNDropPlacementAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override;
@@ -201,8 +205,6 @@ public:
if (this->action) this->action->OnStationRemoved(station);
}
protected:
template<typename Thandler, typename Tcallback, typename Targ>
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<Command> GetCommand(TileArea area) override;

View File

@@ -17,39 +17,17 @@ template<class T> using up=std::unique_ptr<T>;
template<class T> using sp=std::shared_ptr<T>;
template<class T> using wp=std::weak_ptr<T>;
/* C++14 implementation of make_unique */
template<class T> struct _Unique_if {
typedef std::unique_ptr<T> _Single_object;
};
template <typename T, typename... Args>
constexpr auto make_up(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
template<class T> struct _Unique_if<T[]> {
typedef std::unique_ptr<T[]> _Unknown_bound;
};
template <typename T, typename... Args>
constexpr auto make_sp(Args&&... args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
template<class T, size_t N> struct _Unique_if<T[N]> {
typedef void _Known_bound;
};
template<class T, class... Args>
typename _Unique_if<T>::_Single_object
make_up(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
typename _Unique_if<T>::_Unknown_bound
make_up(size_t n) {
typedef typename std::remove_extent<T>::type U;
return std::unique_ptr<T>(new U[n]());
}
template<class T, class... Args>
typename _Unique_if<T>::_Known_bound
make_up(Args&&...) = delete;
// template<typename T> const auto make_up = std::make_unique<T>;
// template<typename T> const auto make_sp = std::make_shared<T>;
template<typename T, class... Args> const auto make_sp = std::make_shared<T, Args...>;
// template<typename T, class... Args> constexpr auto make_sp = std::make_shared<T, Args...>;
enum class GameType: uint8_t {
@@ -73,6 +51,15 @@ enum class ControllerType: uint8_t {
TOWN_DEFENCE = 6,
};
// For use with std::visit
template<typename ... Ts>
struct Overload : Ts ... {
using Ts::operator() ...;
};
template<class... Ts> Overload(Ts...) -> Overload<Ts...>;
// Some utility funcitons for strings
namespace string {

View File

@@ -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"

View File

@@ -2520,3 +2520,10 @@ void ShowSelectWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
{
ShowSelectBaseStationIfNeeded<Waypoint>(ta, std::move(proc));
}
namespace citymania {
void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc) {
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
new SelectStationWindow<Station>(&_select_station_desc, ta, std::move(proc));
}
}