OpenTTD Source 20260206-master-g4d4e37dbf1
network_command.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11#include "network_admin.h"
12#include "network_client.h"
13#include "network_server.h"
14#include "../command_func.h"
15#include "../company_func.h"
16#include "../settings_type.h"
17#include "../airport_cmd.h"
18#include "../aircraft_cmd.h"
19#include "../autoreplace_cmd.h"
20#include "../company_cmd.h"
21#include "../depot_cmd.h"
22#include "../dock_cmd.h"
23#include "../economy_cmd.h"
24#include "../engine_cmd.h"
25#include "../error_func.h"
26#include "../goal_cmd.h"
27#include "../group_cmd.h"
28#include "../industry_cmd.h"
29#include "../landscape_cmd.h"
30#include "../league_cmd.h"
31#include "../misc_cmd.h"
32#include "../news_cmd.h"
33#include "../object_cmd.h"
34#include "../order_cmd.h"
35#include "../rail_cmd.h"
36#include "../road_cmd.h"
37#include "../roadveh_cmd.h"
38#include "../settings_cmd.h"
39#include "../signs_cmd.h"
41#include "../story_cmd.h"
42#include "../subsidy_cmd.h"
43#include "../terraform_cmd.h"
44#include "../timetable_cmd.h"
45#include "../town_cmd.h"
46#include "../train_cmd.h"
47#include "../tree_cmd.h"
48#include "../tunnelbridge_cmd.h"
49#include "../vehicle_cmd.h"
50#include "../viewport_cmd.h"
51#include "../water_cmd.h"
52#include "../waypoint_cmd.h"
54
55#include "../safeguards.h"
56
58static constexpr auto _callback_tuple = std::make_tuple(
59 (CommandCallback *)nullptr, // Make sure this is actually a pointer-to-function.
61 &CcBuildAirport,
63 &CcPlaySound_CONSTRUCTION_WATER,
64 &CcBuildDocks,
65 &CcFoundTown,
66 &CcBuildRoadTunnel,
67 &CcBuildRailTunnel,
69 &CcRoadDepot,
70 &CcRailDepot,
72 &CcPlaySound_EXPLOSION,
73 &CcPlaySound_CONSTRUCTION_OTHER,
74 &CcPlaySound_CONSTRUCTION_RAIL,
75 &CcStation,
76 &CcTerraform,
77 &CcAI,
80 &CcFoundRandomTown,
83 &CcGame,
87);
88
89#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
90/*
91 * We cast specialized function pointers to a generic one, but don't use the
92 * converted value to call the function, which is safe, except that GCC
93 * helpfully thinks it is not.
94 *
95 * "Any pointer to function can be converted to a pointer to a different function type.
96 * Calling the function through a pointer to a different function type is undefined,
97 * but converting such pointer back to pointer to the original function type yields
98 * the pointer to the original function." */
99# pragma GCC diagnostic push
100# pragma GCC diagnostic ignored "-Wcast-function-type"
101#endif
102
103/* Helpers to generate the callback table from the callback list. */
104
105inline constexpr size_t _callback_tuple_size = std::tuple_size_v<decltype(_callback_tuple)>;
106
107template <size_t... i>
108inline auto MakeCallbackTable(std::index_sequence<i...>) noexcept
109{
110 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.
111}
112
114static const auto _callback_table = MakeCallbackTable(std::make_index_sequence<_callback_tuple_size>{});
115
122{
123 return std::ranges::find(_callback_table, callback) != _callback_table.end();
124}
125
126template <typename T> struct CallbackArgsHelper;
127template <typename... Targs>
128struct CallbackArgsHelper<void(*const)(Commands, const CommandCost &, Targs...)> {
129 using Args = std::tuple<std::decay_t<Targs>...>;
130};
131
132
133/* Helpers to generate the command dispatch table from the command traits. */
134
135template <Commands Tcmd> static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data);
136template <Commands Tcmd, size_t cb> static void UnpackNetworkCommand(const CommandPacket &cp);
137template <Commands Tcmd> static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
138using UnpackNetworkCommandProc = void (*)(const CommandPacket &);
139using UnpackDispatchT = std::array<UnpackNetworkCommandProc, _callback_tuple_size>;
141 CommandDataBuffer(*Sanitize)(const CommandDataBuffer &);
142 void (*ReplaceClientId)(CommandPacket &, ClientID);
143 UnpackDispatchT Unpack;
144};
145
146template <Commands Tcmd, size_t Tcb>
147constexpr UnpackNetworkCommandProc MakeUnpackNetworkCommandCallback() noexcept
148{
149 /* Check if the callback matches with the command arguments. If not, don't generate an Unpack proc. */
150 using Tcallback = std::tuple_element_t<Tcb, decltype(_callback_tuple)>;
151 if constexpr (std::is_same_v<Tcallback, CommandCallback * const> || // Callback type is CommandCallback.
152 std::is_same_v<Tcallback, CommandCallbackData * const> || // Callback type is CommandCallbackData.
153 std::is_same_v<typename CommandTraits<Tcmd>::CbArgs, typename CallbackArgsHelper<Tcallback>::Args> || // Callback proc takes all command return values and parameters.
154 (!std::is_void_v<typename CommandTraits<Tcmd>::RetTypes> && std::is_same_v<typename CallbackArgsHelper<typename CommandTraits<Tcmd>::RetCallbackProc const>::Args, typename CallbackArgsHelper<Tcallback>::Args>)) { // Callback return is more than CommandCost and the proc takes all return values.
156 } else {
157 return nullptr;
158 }
159}
160
161template <Commands Tcmd, size_t... i>
162constexpr UnpackDispatchT MakeUnpackNetworkCommand(std::index_sequence<i...>) noexcept
163{
164 return UnpackDispatchT{{ MakeUnpackNetworkCommandCallback<Tcmd, i>()...}};
165}
166
167template <typename T, T... i, size_t... j>
168inline constexpr auto MakeDispatchTable(std::integer_sequence<T, i...>, std::index_sequence<j...>) noexcept
169{
170 return EnumClassIndexContainer<std::array<CommandDispatch, sizeof...(i)>, Commands>{{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &NetworkReplaceCommandClientId<static_cast<Commands>(i)>, MakeUnpackNetworkCommand<static_cast<Commands>(i)>(std::make_index_sequence<_callback_tuple_size>{}) }... }}};
171}
173static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequence<std::underlying_type_t<Commands>, to_underlying(Commands::End)>{}, std::make_index_sequence<_callback_tuple_size>{});
174
175#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
176# pragma GCC diagnostic pop
177#endif
178
183
184
190static size_t FindCallbackIndex(CommandCallback *callback)
191{
192 if (auto it = std::ranges::find(_callback_table, callback); it != std::end(_callback_table)) {
193 return static_cast<size_t>(std::distance(std::begin(_callback_table), it));
194 }
195
196 return std::numeric_limits<size_t>::max();
197}
198
207void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, const CommandDataBuffer &cmd_data)
208{
210 c.company = company;
211 c.cmd = cmd;
212 c.err_msg = err_message;
213 c.callback = callback;
214 c.data = cmd_data;
215
216 if (_network_server) {
217 /* If we are the server, we queue the command in our 'special' queue.
218 * In theory, we could execute the command right away, but then the
219 * client on the server can do everything 1 tick faster than others.
220 * So to keep the game fair, we delay the command with 1 tick
221 * which gives about the same speed as most clients.
222 */
224 c.my_cmd = true;
225
226 _local_wait_queue.push_back(std::move(c));
227 return;
228 }
229
230 c.frame = 0; // The client can't tell which frame, so just make it 0
231
232 /* Clients send their command to the server and forget all about the packet */
234}
235
245void NetworkSyncCommandQueue(NetworkClientSocket *cs)
246{
247 for (auto &p : _local_execution_queue) {
248 CommandPacket &c = cs->outgoing_queue.emplace_back(p);
249 c.callback = nullptr;
250 }
251}
252
257{
258 assert(IsLocalCompany());
259
261
262 auto cp = queue.begin();
263 for (; cp != queue.end(); cp++) {
264 /* The queue is always in order, which means
265 * that the first element will be executed first. */
266 if (_frame_counter < cp->frame) break;
267
268 if (_frame_counter > cp->frame) {
269 /* If we reach here, it means for whatever reason, we've already executed
270 * past the command we need to execute. */
271 FatalError("[net] Trying to execute a packet in the past!");
272 }
273
274 /* We can execute this command */
275 _current_company = cp->company;
276 size_t cb_index = FindCallbackIndex(cp->callback);
277 assert(cb_index < _callback_tuple_size);
278 assert(_cmd_dispatch[cp->cmd].Unpack[cb_index] != nullptr);
279 _cmd_dispatch[cp->cmd].Unpack[cb_index](*cp);
280 }
281 queue.erase(queue.begin(), cp);
282
283 /* Local company may have changed, so we should not restore the old value */
285}
286
295
301static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket *owner)
302{
303 CommandCallback *callback = cp.callback;
304 cp.frame = _frame_counter_max + 1;
305
306 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
307 if (cs->status >= NetworkClientSocket::STATUS_MAP) {
308 /* Callbacks are only send back to the client who sent them in the
309 * first place. This filters that out. */
310 cp.callback = (cs != owner) ? nullptr : callback;
311 cp.my_cmd = (cs == owner);
312 cs->outgoing_queue.push_back(cp);
313 }
314 }
315
316 cp.callback = (nullptr != owner) ? nullptr : callback;
317 cp.my_cmd = (nullptr == owner);
318 _local_execution_queue.push_back(cp);
319}
320
326static void DistributeQueue(CommandQueue &queue, const NetworkClientSocket *owner)
327{
328#ifdef DEBUG_DUMP_COMMANDS
329 /* When replaying we do not want this limitation. */
330 int to_go = UINT16_MAX;
331#else
332 int to_go = _settings_client.network.commands_per_frame;
333 if (owner == nullptr) {
334 /* This is the server, use the commands_per_frame_server setting if higher */
335 to_go = std::max<int>(to_go, _settings_client.network.commands_per_frame_server);
336 }
337#endif
338
339 /* Not technically the most performant way, but consider clients rarely click more than once per tick. */
340 for (auto cp = queue.begin(); cp != queue.end(); /* removing some items */) {
341 /* Do not distribute commands when paused and the command is not allowed while paused. */
342 if (_pause_mode.Any() && !IsCommandAllowedWhilePaused(cp->cmd)) {
343 ++cp;
344 continue;
345 }
346
347 /* Limit the number of commands per client per tick. */
348 if (--to_go < 0) break;
349
350 DistributeCommandPacket(*cp, owner);
351 NetworkAdminCmdLogging(owner, *cp);
352 cp = queue.erase(cp);
353 }
354}
355
358{
359 /* First send the server's commands. */
361
362 /* Then send the queues of the others. */
363 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
364 DistributeQueue(cs->incoming_queue, cs);
365 }
366}
367
374std::optional<std::string_view> NetworkGameSocketHandler::ReceiveCommand(Packet &p, CommandPacket &cp)
375{
376 cp.company = (CompanyID)p.Recv_uint8();
377 cp.cmd = static_cast<Commands>(p.Recv_uint16());
378 if (!IsValidCommand(cp.cmd)) return "invalid command";
379 if (GetCommandFlags(cp.cmd).Test(CommandFlag::Offline)) return "single-player only command";
380 cp.err_msg = p.Recv_uint16();
381 cp.data = _cmd_dispatch[cp.cmd].Sanitize(p.Recv_buffer());
382
383 uint8_t callback = p.Recv_uint8();
384 if (callback >= _callback_table.size() || _cmd_dispatch[cp.cmd].Unpack[callback] == nullptr) return "invalid callback";
385
386 cp.callback = _callback_table[callback];
387 return std::nullopt;
388}
389
396{
397 p.Send_uint8(cp.company);
399 p.Send_uint16(cp.err_msg);
400 p.Send_buffer(cp.data);
401
402 size_t callback = FindCallbackIndex(cp.callback);
403 if (callback > UINT8_MAX || _cmd_dispatch[cp.cmd].Unpack[callback] == nullptr) {
404 Debug(net, 0, "Unknown callback for command; no callback sent (command: {})", cp.cmd);
405 callback = 0; // _callback_table[0] == nullptr
406 }
407 p.Send_uint8 ((uint8_t)callback);
408}
409
411template <class T>
412static inline void SetClientIdHelper(T &data, [[maybe_unused]] ClientID client_id)
413{
414 if constexpr (std::is_same_v<ClientID, T>) {
415 data = client_id;
416 }
417}
418
420template <class Ttuple, size_t... Tindices>
421static inline void SetClientIds(Ttuple &values, ClientID client_id, std::index_sequence<Tindices...>)
422{
423 ((SetClientIdHelper(std::get<Tindices>(values), client_id)), ...);
424}
425
426template <Commands Tcmd>
427static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
428{
429 /* Unpack command parameters. */
430 auto params = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp.data);
431
432 /* Insert client id. */
433 SetClientIds(params, client_id, std::make_index_sequence<std::tuple_size_v<decltype(params)>>{});
434
435 /* Repack command parameters. */
436 cp.data = EndianBufferWriter<CommandDataBuffer>::FromValue(params);
437}
438
444void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
445{
446 _cmd_dispatch[cp.cmd].ReplaceClientId(cp, client_id);
447}
448
449
451template <class T>
452static inline void SanitizeSingleStringHelper([[maybe_unused]] CommandFlags cmd_flags, T &data)
453{
454 if constexpr (std::is_same_v<std::string, T>) {
455 if (!_network_server && cmd_flags.Test(CommandFlag::StrCtrl)) {
457 } else {
459 }
460 }
461}
462
464template <class Ttuple, size_t... Tindices>
465static inline void SanitizeStringsHelper(CommandFlags cmd_flags, Ttuple &values, std::index_sequence<Tindices...>)
466{
467 ((SanitizeSingleStringHelper(cmd_flags, std::get<Tindices>(values))), ...);
468}
469
476template <Commands Tcmd>
478{
479 auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(data);
480 SanitizeStringsHelper(CommandTraits<Tcmd>::flags, args, std::make_index_sequence<std::tuple_size_v<typename CommandTraits<Tcmd>::Args>>{});
481 return EndianBufferWriter<CommandDataBuffer>::FromValue(args);
482}
483
490template <Commands Tcmd, size_t Tcb>
492{
493 auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp.data);
494 Command<Tcmd>::PostFromNet(cp.err_msg, std::get<Tcb>(_callback_tuple), cp.my_cmd, args);
495}
Command definitions related to aircraft.
Command definitions related to airports.
Command definitions related to autoreplace.
void CcBuildBridge(Commands, const CommandCost &result, TileIndex end_tile, TileIndex tile_start, TransportType transport_type, BridgeType, uint8_t)
Callback executed after a build Bridge CMD has been called.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
static ClientNetworkGameSocketHandler * my_client
This is us!
static NetworkRecvStatus SendCommand(const CommandPacket &cp)
Send a command to the server.
Common return value for all commands.
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific enum class.
std::optional< std::string_view > ReceiveCommand(Packet &p, CommandPacket &cp)
Receives a command from the network.
void SendCommand(Packet &p, const CommandPacket &cp)
Sends a command over the network.
CommandFlags GetCommandFlags(Commands cmd)
Get the command flags associated with the given command.
Definition command.cpp:113
bool IsCommandAllowedWhilePaused(Commands cmd)
Returns whether the command is allowed while the game is paused.
Definition command.cpp:137
bool IsValidCommand(Commands cmd)
This function range-checks a Commands.
Definition command.cpp:103
Functions related to commands.
void CommandCallback(Commands cmd, const CommandCost &result, TileIndex tile)
Define a callback function for the client, after the command is finished.
@ Offline
the command cannot be executed in a multiplayer game; single-player only
@ StrCtrl
the command's string may contain control strings
std::vector< uint8_t > CommandDataBuffer
Storage buffer for serialized command data.
Commands
List of commands.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Command definitions related to companies.
Functions related to companies.
bool IsLocalCompany()
Is the current company the local company?
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Command definitions related to depots.
void CcCloneVehicle(Commands, const CommandCost &result, VehicleID veh_id)
This is the Callback method after the cloning attempt of a vehicle.
Command definitions related to docks.
Command definitions related to the economy.
Command definitions related to engines.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:17
Error reporting related functions.
PauseModes _pause_mode
The current pause mode.
Definition gfx.cpp:51
Command definitions related to goals.
Command definitions related to engine groups.
void CcAddVehicleNewGroup(Commands, const CommandCost &result, GroupID new_group, GroupID, VehicleID, bool, const VehicleListIdentifier &)
Open rename window after adding a vehicle to a new group via drag and drop.
void CcCreateGroup(Commands, const CommandCost &result, GroupID new_group, VehicleType vt, GroupID)
Opens a 'Rename group' window for newly created group.
Command definitions related to industries.
Command definitions related to landscape (slopes etc.).
Command definitions related to league tables.
Miscellaneous command definitions.
uint32_t _frame_counter
The current frame.
Definition network.cpp:79
bool _network_server
network-server is active
Definition network.cpp:67
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:78
void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket &cp)
Distribute CommandPacket details over the admin network for logging purposes.
Server part of the admin network protocol.
Client part of the network protocol.
static void SanitizeStringsHelper(CommandFlags cmd_flags, Ttuple &values, std::index_sequence< Tindices... >)
Helper function to perform validation on command data strings.
static constexpr auto _callback_tuple
Typed list of all possible callbacks.
void NetworkFreeLocalCommandQueue()
Free the local command queues.
static void SetClientIds(Ttuple &values, ClientID client_id, std::index_sequence< Tindices... >)
Set all invalid ClientID's to the proper value.
static const auto _callback_table
Type-erased table of callbacks.
static size_t FindCallbackIndex(CommandCallback *callback)
Find the callback index of a callback pointer.
void NetworkExecuteLocalCommandQueue()
Execute all commands on the local command queue that ought to be executed this frame.
bool IsNetworkRegisteredCallback(CommandCallback *callback)
Helper function to ensure that callbacks used when Posting commands are actually registered for the n...
void NetworkDistributeCommands()
Distribute the commands of ourself and the clients.
static CommandQueue _local_wait_queue
Local queue of packets waiting for handling.
static void SetClientIdHelper(T &data, ClientID client_id)
Helper to process a single ClientID argument.
static void SanitizeSingleStringHelper(CommandFlags cmd_flags, T &data)
Validate a single string argument coming from network.
static CommandQueue _local_execution_queue
Local queue of packets waiting for execution.
static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket *owner)
"Send" a particular CommandPacket to all clients.
void NetworkSyncCommandQueue(NetworkClientSocket *cs)
Sync our local command queue to the command queue of the given socket.
static void UnpackNetworkCommand(const CommandPacket &cp)
Unpack a generic command packet into its actual typed components.
static void DistributeQueue(CommandQueue &queue, const NetworkClientSocket *owner)
"Send" a particular CommandQueue to all clients.
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, const CommandDataBuffer &cmd_data)
Prepare a DoCommand to be send over the network.
static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data)
Validate and sanitize strings in command data.
static constexpr auto _cmd_dispatch
Command dispatch table.
Server part of the network protocol.
ClientID
'Unique' identifier to be given to clients
Command definitions related to news messages.
Command definitions related to objects.
Command definitions related to orders.
Command definitions for rail.
Road related functions.
void CcRoadStop(Commands, const CommandCost &result, TileIndex tile, uint8_t width, uint8_t length, RoadStopType, bool is_drive_through, DiagDirection dir, RoadType, RoadStopClassID spec_class, uint16_t spec_index, StationID, bool)
Command callback for building road stops.
Definition road_gui.cpp:197
Command definitions related to road vehicles.
A number of safeguards to prevent using unsafe methods.
Command definitions related to scripts.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Command definitions related to settings.
Types related to global configuration settings.
void CcPlaceSign(Commands, const CommandCost &result, SignID new_sign)
Callback function that is called after a sign is placed.
Command definitions related to signs.
void CcMoveStationName(Commands, const CommandCost &result, StationID station_id)
Callback function that is called after a name is moved.
Command definitions related to stations.
Definition of base types and functions in a cross-platform compatible way.
Command definitions related to stories.
void StrMakeValidInPlace(char *str, StringValidationSettings settings)
Scans the string for invalid characters and replaces them with a question mark '?
Definition string.cpp:157
@ ReplaceWithQuestionMark
Replace the unknown/bad bits with question marks.
Definition string_type.h:45
@ AllowControlCode
Allow the special control codes.
Definition string_type.h:47
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Everything we need to know about a command to be able to execute it.
StringID err_msg
string ID of error message to use.
CommandDataBuffer data
command parameters.
CommandCallback * callback
any callback function executed upon successful completion of the command.
uint32_t frame
the frame in which this packet is executed
CompanyID company
company that is executing the command
bool my_cmd
did the command originate from "me"
Commands cmd
command being executed.
Defines the traits of a command.
uint16_t Recv_uint16()
Read a 16 bits integer from the packet.
Definition packet.cpp:330
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition packet.cpp:316
void Send_uint8(uint8_t data)
Package a 8 bits integer in the packet.
Definition packet.cpp:118
void Send_buffer(const std::vector< uint8_t > &data)
Copy a sized byte buffer into the packet.
Definition packet.cpp:181
std::vector< uint8_t > Recv_buffer()
Extract a sized byte buffer from the packet.
Definition packet.cpp:383
void Send_uint16(uint16_t data)
Package a 16 bits integer in the packet.
Definition packet.cpp:128
Command definitions related to subsidies.
std::vector< CommandPacket > CommandQueue
A "queue" of CommandPackets.
Definition tcp_game.h:135
Command definitions related to terraforming.
Command definitions related to timetables.
Command definitions related to towns.
Command definitions related to trains.
void CcBuildWagon(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray, TileIndex tile, EngineID, bool, CargoType, ClientID)
Callback for building wagons.
Definition train_gui.cpp:29
Command definitions related to tree tiles.
Command definitions related to tunnels and bridges.
Command definitions for vehicles.
void CcBuildPrimaryVehicle(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray)
This is the Callback method after the construction attempt of a primary vehicle.
void CcStartStopVehicle(Commands, const CommandCost &result, VehicleID veh_id, bool)
This is the Callback method after attempting to start/stop a vehicle.
Command definitions related to viewports.
Command definitions related to water tiles.
void CcMoveWaypointName(Commands, const CommandCost &result, StationID waypoint_id)
Callback function that is called after a name is moved.
Command definitions related to waypoints.