Try to fix cmclient command callbacks

This commit is contained in:
Pavel Stupnikov
2023-01-03 15:35:06 +04:00
parent 6bc46c2119
commit cb888544ce
15 changed files with 1040 additions and 894 deletions

View File

@@ -74,7 +74,7 @@ inline constexpr size_t _callback_tuple_size = std::tuple_size_v<decltype(_callb
template <size_t... i>
inline auto MakeCallbackTable(std::index_sequence<i...>) noexcept {
return std::array<CommandCallback *, sizeof...(i)>{{ reinterpret_cast<CommandCallback *>(reinterpret_cast<void(*)()>(std::get<i>(_callback_tuple)))... }}; // MingW64 fails linking when casting a pointer to its own type. To work around, cast it to some other type first.
return std::array<::CommandCallback *, sizeof...(i)>{{ reinterpret_cast<::CommandCallback *>(reinterpret_cast<void(*)()>(std::get<i>(_callback_tuple)))... }}; // MingW64 fails linking when casting a pointer to its own type. To work around, cast it to some other type first.
}
/** Type-erased table of callbacks. */
static auto _callback_table = MakeCallbackTable(std::make_index_sequence<_callback_tuple_size>{});\n
@@ -87,7 +87,7 @@ struct CallbackArgsHelper<void(*const)(Commands, const CommandCost &, Targs...)>
# pragma GCC diagnostic pop
#endif
static size_t FindCallbackIndex(CommandCallback *callback) {
static size_t FindCallbackIndex(::CommandCallback *callback) {
if (auto it = std::find(std::cbegin(_callback_table), std::cend(_callback_table), callback); it != std::cend(_callback_table)) {
return static_cast<size_t>(std::distance(std::cbegin(_callback_table), it));
}
@@ -102,7 +102,7 @@ template <Commands Tcmd, size_t Tcb, typename... Targs>
constexpr auto MakeCallback() noexcept {
/* Check if the callback matches with the command arguments. If not, don''t generate an Unpack proc. */
using Tcallback = std::tuple_element_t<Tcb, decltype(_callback_tuple)>;
if constexpr (std::is_same_v<Tcallback, CommandCallback * const> ||
if constexpr (std::is_same_v<Tcallback, ::CommandCallback * const> ||
std::is_same_v<Tcallback, CommandCallbackData * const> ||
std::is_same_v<typename CommandTraits<Tcmd>::CbArgs, typename CallbackArgsHelper<Tcallback>::Args> ||
(!std::is_void_v<typename CommandTraits<Tcmd>::RetTypes> && std::is_same_v<typename CallbackArgsHelper<typename CommandTraits<Tcmd>::RetCallbackProc const>::Args, typename CallbackArgsHelper<Tcallback>::Args>)) {
@@ -170,8 +170,9 @@ def run():
f.write(
f' ~{name}() override {{}}\n'
f'\n'
f' bool do_post(CommandCallback * callback) override;\n'
f' bool do_test() override;\n'
f' bool _post(::CommandCallback * callback) override;\n'
f' CommandCost _do(DoCommandFlag flags) override;\n'
f' Commands get_command() override;\n'
f'}};\n\n'
)
f.write(
@@ -198,7 +199,7 @@ def run():
' * but the table is not the same.\n'
' */\n'
'static constexpr auto _callback_tuple = std::make_tuple(\n'
' (CommandCallback *)nullptr, // Make sure this is actually a pointer-to-function.\n'
' (::CommandCallback *)nullptr, // Make sure this is actually a pointer-to-function.\n'
)
for i, cb in enumerate(callbacks):
comma = ',' if i != len(callbacks) - 1 else ''
@@ -226,12 +227,13 @@ def run():
sep_args_type_list = ', ' + args_type_list
sep_this_args_list = ', ' + this_args_list
f.write(
f'Commands {name}::get_command() {{ return {constant}; }}\n'
f'static constexpr auto _{name}_dispatch = MakeDispatchTable<{constant}{sep_args_type_list}>();\n'
f'bool {name}::do_post(CommandCallback *callback) {{\n'
f'bool {name}::_post(::CommandCallback *callback) {{\n'
f' return _{name}_dispatch[FindCallbackIndex(callback)](this->error, this->tile{sep_this_args_list});\n'
'}\n'
f'bool {name}::do_test() {{\n'
f' return {cost_getter}(::Command<{constant}>::Do(DC_NONE, {test_args_list})).Succeeded();\n'
f'CommandCost {name}::_do(DoCommandFlag flags) {{\n'
f' return {cost_getter}(::Command<{constant}>::Do(flags, {test_args_list}));\n'
'}\n'
)
f.write('\n')

View File

@@ -42,6 +42,8 @@ add_files(
cm_minimap.cpp
cm_misc_gui.hpp
cm_misc_gui.cpp
cm_rail_gui.hpp
cm_rail_gui.cpp
cm_station_gui.hpp
cm_station_gui.cpp
cm_tooltips.hpp

View File

@@ -128,7 +128,7 @@ up<Command> GetBlueprintCommand(TileIndex start, const Blueprint::Item &item) {
end_tile = new_tile;
tdir = NextTrackdir(tdir);
}
return make_up<cmd::BuildRailroadTrack>(
return std::make_unique<cmd::BuildRailroadTrack>(
end_tile,
start_tile,
_cur_railtype,

View File

@@ -8,6 +8,7 @@
#include "../group_cmd.h"
#include "../engine_type.h"
#include "../livery.h"
#include "../network/network_type.h"
#include "../misc_cmd.h"
#include "../news_type.h"
#include "../object_type.h"
@@ -23,43 +24,59 @@ enum StationClassID : byte;
namespace citymania {
typedef std::function<bool(bool)> CommandCallback;
extern bool _auto_command;
extern CommandCallback _current_callback;
class Command {
public:
TileIndex tile = 0;
bool automatic = false;
CompanyID company = INVALID_COMPANY;
StringID error = (StringID)0;
CommandCallback callback = nullptr;
Command() {}
Command(TileIndex tile) :tile{tile} {}
virtual ~Command() {}
virtual bool do_post(CommandCallback *callback)=0;
virtual bool do_test()=0;
virtual bool _post(::CommandCallback *callback)=0;
virtual CommandCost _do(DoCommandFlag flags)=0;
virtual Commands get_command()=0;
template <typename Tcallback>
bool post(Tcallback callback) {
CompanyID old = _current_company;
if (this->company != INVALID_COMPANY)
_current_company = company;
bool res = this->do_post(reinterpret_cast<CommandCallback *>(reinterpret_cast<void(*)()>(callback)));
_auto_command = this->automatic;
_current_callback = this->callback;
bool res = this->_post(reinterpret_cast<::CommandCallback *>(reinterpret_cast<void(*)()>(callback)));
assert(_current_callback == nullptr);
_current_callback = nullptr;
_auto_command = false;
_current_company = old;
return res;
}
bool post() {
return this->post<CommandCallback *>(nullptr);
return this->post<::CommandCallback *>(nullptr);
}
bool test() {
CommandCost call(DoCommandFlag flags) {
CompanyID old = _current_company;
if (this->company != INVALID_COMPANY)
_current_company = company;
bool res = this->do_test();
auto res = this->_do(flags);
_current_company = old;
return res;
}
bool test() {
return this->call(DC_NONE).Succeeded();
}
Command &with_tile(TileIndex tile) {
this->tile = tile;
return *this;
@@ -79,6 +96,11 @@ public:
this->company = company;
return *this;
}
Command &with_callback(CommandCallback callback) {
this->callback = callback;
return *this;
}
};
} // namaespace citymania

View File

@@ -3,10 +3,13 @@
#include "cm_commands.hpp"
#include "../command_func.h"
#include "../debug.h"
#include "../network/network.h"
#include "../network/network_client.h"
#include <queue>
#include <vector>
namespace citymania {
@@ -14,6 +17,9 @@ const uint32 MAX_CALLBACK_LIFETIME = 30; // it should be executed within few fr
std::map<size_t, std::pair<uint32, std::vector<CommandCallback>>> _command_callbacks;
std::queue<std::pair<size_t, uint32>> _command_sent;
CommandCallback _current_callback = nullptr;
bool _auto_command = false;
std::queue<std::pair<size_t, CommandCallback>> _callback_queue;
uint GetCurrentQueueDelay();
@@ -24,11 +30,62 @@ void hash_combine(std::size_t& seed, const T& v, const Rest&... rest)
(hash_combine(seed, rest), ...);
}
size_t GetCommandHash(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text) {
} // namespace citymania
namespace std {
template<typename T>
struct hash<std::vector<T>> {
typedef std::vector<T> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& in) const {
size_t size = in.size();
size_t seed = 0;
for (size_t i = 0; i < size; i++)
citymania::hash_combine(seed, in[i]);
return seed;
}
};
} // namespace std
namespace citymania {
size_t GetCommandHash(Commands cmd, CompanyID company_id, StringID err_msg, ::CommandCallback callback, TileIndex tile, const CommandDataBuffer &data) {
size_t res = 0;
// hash_combine(res, tile, p1, p2, cmd, text);
hash_combine(res, cmd, (uint16)company_id, err_msg, callback, (uint32)tile, data);
return res;
}
void ExecuteCurrentCallback(const CommandCost &cost) {
if (_current_callback != nullptr) {
_current_callback(cost.Succeeded());
_current_callback == nullptr;
}
}
void BeforeNetworkCommandExecution(const CommandPacket* cp) {
if (!cp->my_cmd) return;
size_t hash = GetCommandHash(cp->cmd, cp->company, cp->err_msg, cp->callback, cp->tile, cp->data);
while (!_callback_queue.empty() && _callback_queue.front().first != hash) {
Debug(misc, 0, "CM Dismissing command from callback queue: cmd={}", cp->cmd);
_callback_queue.pop();
}
if (_callback_queue.empty()) {
Debug(misc, 0, "CM Received unexpected network command: cmd={}", cp->cmd);
return;
}
_current_callback = _callback_queue.front().second;
_callback_queue.pop();
return;
}
void AfterNetworkCommandExecution(const CommandPacket* cp) {
_current_callback = nullptr;
}
void AddCommandCallback(const CommandPacket *cp) {
size_t hash = GetCommandHash(cp->cmd, cp->company, cp->err_msg, cp->callback, cp->tile, cp->data);
_callback_queue.push(std::make_pair(hash, _current_callback));
_current_callback = nullptr;
}
/*
void AddCommandCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text, CommandCallback callback) {
if (!_networking) {
@@ -43,21 +100,8 @@ void AddCommandCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const
// fprintf(stderr, "CALLBACK %lu (%u %u %u %u %s)\n", hash, tile, p1, p2, (uint)(cmd & CMD_ID_MASK), text.c_str());
}
bool DoCommandWithCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, ::CommandCallback *callback, const std::string &text, CommandCallback cm_callback) {
if (_networking) {
AddCommandCallback(tile, p1, p2, cmd, text, cm_callback);
return DoCommandP(tile, p1, p2, cmd, callback, text);
}
auto res = DoCommandP(tile, p1, p2, cmd, callback, text);
cm_callback(res);
return res;
}
bool DoCommandWithCallback(const CommandContainer &cc, CommandCallback callback) {
return DoCommandWithCallback(cc.tile, cc.p1, cc.p2, cc.cmd, cc.callback, cc.text, callback);
}
*/
void HandleCommandExecution(bool res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text) {
//void HandleCommandExecution(bool res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text) {
/* FIXME
auto hash = GetCommandHash(tile, p1, p2, cmd & CMD_ID_MASK, text);
auto p = _command_callbacks.find(hash);
@@ -66,7 +110,7 @@ void HandleCommandExecution(bool res, TileIndex tile, uint32 p1, uint32 p2, uint
for (auto &cb : p->second.second)
cb(res);
_command_callbacks.erase(p); */
}
//}
void ClearOldCallbacks() {
while(!_command_sent.empty() && _command_sent.front().second + MAX_CALLBACK_LIFETIME < _frame_counter) {
@@ -107,16 +151,17 @@ void FlushCommandQueue() {
void HandleNextClientFrame() {
_commands_this_frame = 0;
FlushCommandQueue();
ClearOldCallbacks();
// ClearOldCallbacks();
}
/*void SendClientCommand(const CommandPacket *cp) {
void SendClientCommand(const CommandPacket *cp) {
AddCommandCallback(cp);
if (_outgoing_queue.empty() && CanSendCommand()) {
MyClient::SendCommand(cp);
_commands_this_frame++;
return;
}
_outgoing_queue.push(*cp);
}*/
}
} // namespace citymania

View File

@@ -3,21 +3,22 @@
#include "../command_type.h"
#include "../tile_type.h"
#include "../network/network_internal.h"
#include "generated/cm_gen_commands.hpp"
struct CommandPacket;
namespace citymania {
typedef std::function<bool(bool)> CommandCallback;
// void AddCommandCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text, CommandCallback callback);
// bool DoCommandWithCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, ::CommandCallback *callback, const std::string &text, CommandCallback cm_callback);
// bool DoCommandWithCallback(const CommandContainer &cc, CommandCallback callback);
void HandleCommandExecution(bool res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text);
// void HandleCommandExecution(bool res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, const std::string &text);
void AddCommandCallback(const CommandPacket *cp);
void ExecuteCurrentCallback(const CommandCost &cost);
void BeforeNetworkCommandExecution(const CommandPacket* cp);
void AfterNetworkCommandExecution(const CommandPacket* cp);
void InitCommandQueue();
void HandleNextClientFrame();
// void SendClientCommand(const CommandPacket *cp);
void SendClientCommand(const CommandPacket *cp);
} // namespace citymania

View File

@@ -472,7 +472,7 @@ void ObjectHighlight::UpdateTiles() {
auto add_track = [this, z](TileIndex tile, TileIndex end_tile, Trackdir trackdir, SpriteID palette, TileIndex point1, TileIndex point2) {
if (trackdir == INVALID_TRACKDIR) return;
for(;;) {
while(tile <= MapSize()) {
this->sprites.emplace_back(
RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, z * TILE_HEIGHT + 7 /* z_offset */),
SPR_AUTORAIL_BASE + _AutorailTilehSprite[0][TrackdirToTrack(trackdir)],

View File

@@ -31,7 +31,6 @@
#include <sstream>
extern const Station *_viewport_highlight_station;
extern TileHighlightData _thd;
extern void MarkCatchmentTilesDirty();

View File

@@ -43,6 +43,10 @@ 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...>;
enum class GameType: uint8 {
GENERIC = 0,
@@ -65,9 +69,6 @@ enum class ControllerType: uint8 {
TOWN_DEFENCE = 6,
};
// template<typename T> const auto make_up = std::make_unique<T>;
// template<typename T> const auto make_sp = std::make_shared<T>;
} // namespace citymania
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -233,7 +233,7 @@ std::tuple<bool, bool, bool> CommandHelperBase::InternalPostBefore(Commands cmd,
* However, in case of incoming network commands,
* map generation or the pause button we do want
* to execute. */
bool estimate_only = citymania::_estimate_mod && IsLocalCompany() && !_generating_world && !network_command && !(flags & CMD_NO_EST);
bool estimate_only = citymania::_estimate_mod && IsLocalCompany() && !_generating_world && !network_command && !(flags & CMD_NO_EST) && !citymania::_auto_command;
/* We're only sending the command, so don't do
* fancy things for 'success'. */

View File

@@ -18,6 +18,9 @@
#include "misc/endian_buffer.hpp"
#include "tile_map.h"
struct CommandPacket;
namespace citymania { extern void ExecuteCurrentCallback(const CommandCost &cost); }
/**
* Define a default return value for a failed command.
*
@@ -338,6 +341,7 @@ protected:
std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res, args));
}
}
citymania::ExecuteCurrentCallback(ExtractCommandCost(res));
}
return ExtractCommandCost(res).Succeeded();

View File

@@ -286,14 +286,15 @@ void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *cal
c.my_cmd = true;
_local_wait_queue.Append(&c);
citymania::AddCommandCallback(&c);
return;
}
c.frame = 0; // The client can't tell which frame, so just make it 0
/* Clients send their command to the server and forget all about the packet */
MyClient::SendCommand(&c);
// FIXME citymania::SendClientCommand(&c);
// MyClient::SendCommand(&c);
citymania::SendClientCommand(&c);
}
/**
@@ -542,6 +543,8 @@ CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data)
template <Commands Tcmd, size_t Tcb>
void UnpackNetworkCommand(const CommandPacket* cp)
{
citymania::BeforeNetworkCommandExecution(cp);
auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp->data);
Command<Tcmd>::PostFromNet(cp->err_msg, std::get<Tcb>(_callback_tuple), cp->my_cmd, cp->tile, args);
citymania::AfterNetworkCommandExecution(cp);
}

View File

@@ -52,6 +52,7 @@
#include "citymania/cm_hotkeys.hpp"
#include "citymania/cm_highlight.hpp"
#include "citymania/cm_station_gui.hpp"
#include "citymania/cm_rail_gui.hpp"
#include "safeguards.h"
@@ -66,8 +67,6 @@ static bool _convert_signal_button; ///< convert signal button in the s
static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
static SignalType _cur_signal_type; ///< set the signal type (for signal GUI)
extern TileIndex _rail_track_endtile; // CM rail_cmd.cpp
static const int HOTKEY_MASK = 0x1000;
static const int HOTKEY_POLYRAIL = 0x1000;
static const int HOTKEY_NEW_POLYRAIL = 0x1001;
@@ -111,17 +110,6 @@ void CcPlaySound_CONSTRUCTION_RAIL(Commands cmd, const CommandCost &result, Tile
if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_CONSTRUCTION_RAIL, tile);
}
static void GenericPlaceRail(TileIndex tile, Track track)
{
if (_remove_button_clicked) {
Command<CMD_REMOVE_SINGLE_RAIL>::Post(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
tile, track);
} else {
Command<CMD_BUILD_SINGLE_RAIL>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
tile, _cur_railtype, track, _settings_client.gui.auto_remove_signals);
}
}
/**
* Try to add an additional rail-track at the entrance of a depot
* @param tile Tile to use for adding the rail-track
@@ -373,185 +361,6 @@ static void BuildRailClick_Remove(Window *w)
}
}
/* FIXME static CommandContainer DoRailroadTrackCmd(TileIndex start_tile, TileIndex end_tile, Track track)
{
CommandContainer ret = {
start_tile, // tile
end_tile, // p1
((uint32)_cur_railtype | ((uint32)track << 6) | ((uint32)_settings_client.gui.auto_remove_signals << 11)), // p2
_remove_button_clicked ?
CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), // cmd
CcPlaySound_CONSTRUCTION_RAIL, // callback
"" // text
};
return ret;
}
*/
namespace citymania {
/*
static bool DoAutodirTerraform(bool diagonal, TileIndex start_tile, TileIndex end_tile, Track track, CommandContainer &rail_cmd, TileIndex s1, TileIndex e1, TileIndex s2, TileIndex e2) {
auto rail_callback = [rail_cmd, start_tile, end_tile, track, estimate=citymania::_estimate_mod](bool res) -> bool {
if (DoCommand(&rail_cmd, DC_AUTO | DC_NO_WATER).GetErrorMessage() != STR_ERROR_ALREADY_BUILT ||
_rail_track_endtile == INVALID_TILE) {
if (!DoCommandP(&rail_cmd)) return false;
}
if (!estimate && _rail_track_endtile != INVALID_TILE)
StoreRailPlacementEndpoints(start_tile, _rail_track_endtile, track, true);
return res;
};
auto h1 = TileHeight(s1);
auto h2 = TileHeight(s2);
uint32 diag_flag = diagonal ? 1 : 0;
uint32 p2_1 = ((h1 < h2 ? LM_RAISE : LM_LEVEL) << 1) | diag_flag;
uint32 p2_2 = ((h2 < h1 ? LM_RAISE : LM_LEVEL) << 1) | diag_flag;
auto l1_fail = (!DoCommand(e1, s1, p2_1, DC_AUTO | DC_NO_WATER, CMD_LEVEL_LAND).Succeeded());
auto l2_fail = (!DoCommand(e2, s2, p2_2, DC_AUTO | DC_NO_WATER, CMD_LEVEL_LAND).Succeeded());
if (l1_fail && l2_fail) return rail_callback(true);
if (l2_fail) return citymania::DoCommandWithCallback(e1, s1, p2_1, CMD_LEVEL_LAND, CcTerraform, "", rail_callback);
if (!l1_fail) DoCommandP(e1, s1, p2_1, CMD_LEVEL_LAND, CcTerraform);
return citymania::DoCommandWithCallback(e2, s2, p2_2, CMD_LEVEL_LAND, CcTerraform, "", rail_callback);
}
static bool HandleAutodirTerraform(TileIndex start_tile, TileIndex end_tile, Track track, CommandContainer &rail_cmd) {
bool eq = (TileX(end_tile) - TileY(end_tile) == TileX(start_tile) - TileY(start_tile));
bool ez = (TileX(end_tile) + TileY(end_tile) == TileX(start_tile) + TileY(start_tile));
// StoreRailPlacementEndpoints(start_tile, end_tile, track, true);
switch (_thd.cm_poly_dir) {
case TRACKDIR_X_NE:
return DoAutodirTerraform(false, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 1, 0), end_tile,
TILE_ADDXY(start_tile, 1, 1), TILE_ADDXY(end_tile, 0, 1));
break;
case TRACKDIR_X_SW:
return DoAutodirTerraform(false, start_tile, end_tile, track, rail_cmd,
start_tile, TILE_ADDXY(end_tile, 1, 0),
TILE_ADDXY(start_tile, 0, 1), TILE_ADDXY(end_tile, 1, 1));
break;
case TRACKDIR_Y_SE:
return DoAutodirTerraform(false, start_tile, end_tile, track, rail_cmd,
start_tile, TILE_ADDXY(end_tile, 0, 1),
TILE_ADDXY(start_tile, 1, 0), TILE_ADDXY(end_tile, 1, 1));
break;
case TRACKDIR_Y_NW:
return DoAutodirTerraform(false, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 0, 1), end_tile,
TILE_ADDXY(start_tile, 1, 1), TILE_ADDXY(end_tile, 1, 0));
break;
case TRACKDIR_LEFT_N: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 1, 0), TILE_ADDXY(end_tile, eq, 0),
TILE_ADDXY(start_tile, 1, 1), TILE_ADDXY(end_tile, 0, !eq));
break;
}
case TRACKDIR_RIGHT_N: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 0, 1), TILE_ADDXY(end_tile, 0, eq),
TILE_ADDXY(start_tile, 1, 1), TILE_ADDXY(end_tile, !eq, 0));
break;
}
case TRACKDIR_LEFT_S: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 1, 0), TILE_ADDXY(end_tile, 1, !eq),
start_tile, TILE_ADDXY(end_tile, eq, 1));
break;
}
case TRACKDIR_RIGHT_S: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 0, 1), TILE_ADDXY(end_tile, !eq, 1),
start_tile, TILE_ADDXY(end_tile, 1, eq));
break;
}
case TRACKDIR_UPPER_E: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
start_tile, TILE_ADDXY(end_tile, 0, !ez),
TILE_ADDXY(start_tile, 1, 0), TILE_ADDXY(end_tile, !ez, 1));
break;
}
case TRACKDIR_LOWER_E: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 1, 1), TILE_ADDXY(end_tile, ez, 1),
TILE_ADDXY(start_tile, 1, 0), TILE_ADDXY(end_tile, 0, ez));
break;
}
case TRACKDIR_UPPER_W: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
start_tile, TILE_ADDXY(end_tile, !ez, 0),
TILE_ADDXY(start_tile, 0, 1), TILE_ADDXY(end_tile, 1, !ez));
break;
}
case TRACKDIR_LOWER_W: {
return DoAutodirTerraform(true, start_tile, end_tile, track, rail_cmd,
TILE_ADDXY(start_tile, 1, 1), TILE_ADDXY(end_tile, 1, ez),
TILE_ADDXY(start_tile, 0, 1), TILE_ADDXY(end_tile, ez, 0));
break;
}
default:
break;
}
return true;
}*/
} // namespace citymania
//FIXME
static void DoRailroadTrack(Track track)
{
if (_remove_button_clicked) {
Command<CMD_REMOVE_RAILROAD_TRACK>::Post(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
TileVirtXY(_thd.selend.x, _thd.selend.y), TileVirtXY(_thd.selstart.x, _thd.selstart.y), track);
} else {
Command<CMD_BUILD_RAILROAD_TRACK>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
TileVirtXY(_thd.selend.x, _thd.selend.y), TileVirtXY(_thd.selstart.x, _thd.selstart.y), _cur_railtype, track, _settings_client.gui.auto_remove_signals, false);
}
}
static void HandleAutodirPlacement()
{
Track trackstat = static_cast<Track>( _thd.drawstyle & HT_DIR_MASK); // 0..5
if (_thd.drawstyle & HT_RAIL) { // one tile case
GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat);
return;
}
DoRailroadTrack(trackstat);
}
// end FIXME
/*
static void HandleAutodirPlacement()
{
Track track = (Track)(_thd.drawstyle & HT_DIR_MASK); // 0..5
TileIndex start_tile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
TileIndex end_tile = TileVirtXY(_thd.selend.x, _thd.selend.y);
/* FIXME
CommandContainer cmd = (_thd.drawstyle & HT_RAIL) ?
GenericPlaceRailCmd(end_tile, track) : // one tile case
DoRailroadTrackCmd(start_tile, end_tile, track); // multitile selection
/* When overbuilding existing tracks in polyline mode we want to move the
* snap point over the last overbuilt track piece. In such case we don't
* wan't to show any errors to the user. Don't execute the command right
* away, first check if overbuilding. */
/* if (citymania::_estimate_mod || !(_thd.place_mode & HT_POLY) || _remove_button_clicked) {
if (!DoCommandP(&cmd)) return;
} else if (_thd.cm_poly_terra) {
citymania::HandleAutodirTerraform(start_tile, end_tile, track, cmd);
return;
} else if (DoCommand(&cmd, DC_AUTO | DC_NO_WATER).GetErrorMessage() != STR_ERROR_ALREADY_BUILT ||
_rail_track_endtile == INVALID_TILE) {
if (!DoCommandP(&cmd)) return;
} */
/* Save new snap points for the polyline tool, no matter if the command
* succeeded, the snapping will be extended over overbuilt track pieces. */
/*if (!citymania::_estimate_mod && _rail_track_endtile != INVALID_TILE) {
StoreRailPlacementEndpoints(start_tile, _rail_track_endtile, track, true);
}
}*/
/**
* Build new signals or remove signals or (if only one tile marked) edit a signal.
*
@@ -1002,7 +811,7 @@ struct BuildRailToolbarWindow : Window {
break;
case DDSP_PLACE_RAIL:
HandleAutodirPlacement();
citymania::HandleAutodirPlacement(_cur_railtype, _remove_button_clicked);
break;
case DDSP_BUILD_SIGNALS: