Command: Replace binary_length field with auxiliary data

Use for CMD_ADD_PLAN_LINE
This commit is contained in:
Jonathan G Rennison
2022-12-07 20:37:23 +00:00
parent b0329ec77a
commit f32733ef22
23 changed files with 166 additions and 147 deletions

View File

@@ -12,6 +12,7 @@
#include "error.h" #include "error.h"
#include "gui.h" #include "gui.h"
#include "command_func.h" #include "command_func.h"
#include "command_aux.h"
#include "network/network_type.h" #include "network/network_type.h"
#include "network/network.h" #include "network/network.h"
#include "genworld.h" #include "genworld.h"
@@ -565,7 +566,7 @@ enum CommandLogEntryFlag : uint16 {
CLEF_ESTIMATE_ONLY = 0x08, ///< estimate only CLEF_ESTIMATE_ONLY = 0x08, ///< estimate only
CLEF_ONLY_SENDING = 0x10, ///< only sending CLEF_ONLY_SENDING = 0x10, ///< only sending
CLEF_MY_CMD = 0x20, ///< locally generated command CLEF_MY_CMD = 0x20, ///< locally generated command
CLEF_BINARY = 0x40, ///< binary_length is > 0 CLEF_AUX_DATA = 0x40, ///< have auxiliary data
CLEF_SCRIPT = 0x80, ///< command run by AI/game script CLEF_SCRIPT = 0x80, ///< command run by AI/game script
CLEF_TWICE = 0x100, ///< command logged twice (only sending and execution) CLEF_TWICE = 0x100, ///< command logged twice (only sending and execution)
CLEF_RANDOM = 0x200, ///< command changed random seed CLEF_RANDOM = 0x200, ///< command changed random seed
@@ -648,7 +649,7 @@ static void DumpSubCommandLog(char *&buffer, const char *last, const CommandLog
} }
buffer += seprintf(buffer, last, " | %c%c%c%c%c%c%c%c%c%c%c | ", buffer += seprintf(buffer, last, " | %c%c%c%c%c%c%c%c%c%c%c | ",
fc(CLEF_ORDER_BACKUP, 'o'), fc(CLEF_RANDOM, 'r'), fc(CLEF_TWICE, '2'), fc(CLEF_ORDER_BACKUP, 'o'), fc(CLEF_RANDOM, 'r'), fc(CLEF_TWICE, '2'),
fc(CLEF_SCRIPT, 'a'), fc(CLEF_BINARY, 'b'), fc(CLEF_MY_CMD, 'm'), fc(CLEF_ONLY_SENDING, 's'), fc(CLEF_SCRIPT, 'a'), fc(CLEF_AUX_DATA, 'b'), fc(CLEF_MY_CMD, 'm'), fc(CLEF_ONLY_SENDING, 's'),
fc(CLEF_ESTIMATE_ONLY, 'e'), fc(CLEF_TEXT, 't'), fc(CLEF_GENERATING_WORLD, 'g'), fc(CLEF_CMD_FAILED, 'f')); fc(CLEF_ESTIMATE_ONLY, 'e'), fc(CLEF_TEXT, 't'), fc(CLEF_GENERATING_WORLD, 'g'), fc(CLEF_CMD_FAILED, 'f'));
buffer += seprintf(buffer, last, " %7d x %7d, p1: 0x%08X, p2: 0x%08X, ", buffer += seprintf(buffer, last, " %7d x %7d, p1: 0x%08X, p2: 0x%08X, ",
TileX(entry.tile), TileY(entry.tile), entry.p1, entry.p2); TileX(entry.tile), TileY(entry.tile), entry.p1, entry.p2);
@@ -756,17 +757,15 @@ bool IsCommandAllowedWhilePaused(uint32 cmd)
static int _docommand_recursive = 0; static int _docommand_recursive = 0;
struct cmd_text_info_dumper { struct cmd_text_info_dumper {
const char *CommandTextInfo(const char *text, uint32 binary_length) const char *CommandTextInfo(const char *text, const CommandAuxiliaryBase *aux_data)
{ {
char *b = this->buffer; char *b = this->buffer;
const char *last = lastof(this->buffer); const char *last = lastof(this->buffer);
if (text) { if (text) {
b += seprintf(b, last, ", text"); b += seprintf(b, last, ", text: length: %u", (uint) strlen(text));
} }
if (binary_length) { if (aux_data) {
b += seprintf(b, last, ", bin length: %u", binary_length); b += seprintf(b, last, ", aux data");
} else if (text) {
b += seprintf(b, last, ", str length: %u", (uint) strlen(text));
} }
return this->buffer; return this->buffer;
} }
@@ -789,10 +788,10 @@ private:
* @see CommandProc * @see CommandProc
* @return the cost * @return the cost
*/ */
CommandCost DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, DoCommandFlag flags, uint32 cmd, const char *text, uint32 binary_length) CommandCost DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, DoCommandFlag flags, uint32 cmd, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
SCOPE_INFO_FMT([=], "DoCommand: tile: %X (%d x %d), p1: 0x%X, p2: 0x%X, p3: " OTTD_PRINTFHEX64 ", flags: 0x%X, company: %s, cmd: 0x%X (%s)%s", SCOPE_INFO_FMT([=], "DoCommand: tile: %X (%d x %d), p1: 0x%X, p2: 0x%X, p3: " OTTD_PRINTFHEX64 ", flags: 0x%X, company: %s, cmd: 0x%X (%s)%s",
tile, TileX(tile), TileY(tile), p1, p2, p3, flags, scope_dumper().CompanyInfo(_current_company), cmd, GetCommandName(cmd), cmd_text_info_dumper().CommandTextInfo(text, binary_length)); tile, TileX(tile), TileY(tile), p1, p2, p3, flags, scope_dumper().CompanyInfo(_current_company), cmd, GetCommandName(cmd), cmd_text_info_dumper().CommandTextInfo(text, aux_data));
CommandCost res; CommandCost res;
@@ -808,7 +807,7 @@ CommandCost DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, DoComma
if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) { if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) {
if (_docommand_recursive == 1) _cleared_object_areas.clear(); if (_docommand_recursive == 1) _cleared_object_areas.clear();
SetTownRatingTestMode(true); SetTownRatingTestMode(true);
res = command.Execute(tile, flags & ~DC_EXEC, p1, p2, p3, text, binary_length); res = command.Execute(tile, flags & ~DC_EXEC, p1, p2, p3, text, aux_data);
SetTownRatingTestMode(false); SetTownRatingTestMode(false);
if (res.Failed()) { if (res.Failed()) {
goto error; goto error;
@@ -830,7 +829,7 @@ CommandCost DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, DoComma
/* Execute the command here. All cost-relevant functions set the expenses type /* Execute the command here. All cost-relevant functions set the expenses type
* themselves to the cost object at some point */ * themselves to the cost object at some point */
if (_docommand_recursive == 1) _cleared_object_areas.clear(); if (_docommand_recursive == 1) _cleared_object_areas.clear();
res = command.Execute(tile, flags, p1, p2, p3, text, binary_length); res = command.Execute(tile, flags, p1, p2, p3, text, aux_data);
if (res.Failed()) { if (res.Failed()) {
error: error:
_docommand_recursive--; _docommand_recursive--;
@@ -909,10 +908,10 @@ static void AppendCommandLogEntry(const CommandCost &res, TileIndex tile, uint32
* @param binary_length The length of binary data in text * @param binary_length The length of binary data in text
* @return \c true if the command succeeded, else \c false. * @return \c true if the command succeeded, else \c false.
*/ */
bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, uint32 binary_length, bool my_cmd) bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, const CommandAuxiliaryBase *aux_data, bool my_cmd)
{ {
SCOPE_INFO_FMT([=], "DoCommandP: tile: %X (%d x %d), p1: 0x%X, p2: 0x%X, p3: 0x" OTTD_PRINTFHEX64 ", company: %s, cmd: 0x%X (%s), my_cmd: %d%s", SCOPE_INFO_FMT([=], "DoCommandP: tile: %X (%d x %d), p1: 0x%X, p2: 0x%X, p3: 0x" OTTD_PRINTFHEX64 ", company: %s, cmd: 0x%X (%s), my_cmd: %d%s",
tile, TileX(tile), TileY(tile), p1, p2, p3, scope_dumper().CompanyInfo(_current_company), cmd, GetCommandName(cmd), my_cmd, cmd_text_info_dumper().CommandTextInfo(text, binary_length)); tile, TileX(tile), TileY(tile), p1, p2, p3, scope_dumper().CompanyInfo(_current_company), cmd, GetCommandName(cmd), my_cmd, cmd_text_info_dumper().CommandTextInfo(text, aux_data));
/* Cost estimation is generally only done when the /* Cost estimation is generally only done when the
* local user presses shift while doing something. * local user presses shift while doing something.
@@ -945,15 +944,15 @@ bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, C
GameRandomSeedChecker random_state; GameRandomSeedChecker random_state;
uint order_backup_update_counter = OrderBackup::GetUpdateCounter(); uint order_backup_update_counter = OrderBackup::GetUpdateCounter();
CommandCost res = DoCommandPInternal(tile, p1, p2, p3, cmd, callback, text, my_cmd, estimate_only, binary_length); CommandCost res = DoCommandPInternal(tile, p1, p2, p3, cmd, callback, text, my_cmd, estimate_only, aux_data);
CommandLogEntryFlag log_flags; CommandLogEntryFlag log_flags;
log_flags = CLEF_NONE; log_flags = CLEF_NONE;
if (binary_length == 0 && !StrEmpty(text)) log_flags |= CLEF_TEXT; if (!StrEmpty(text)) log_flags |= CLEF_TEXT;
if (estimate_only) log_flags |= CLEF_ESTIMATE_ONLY; if (estimate_only) log_flags |= CLEF_ESTIMATE_ONLY;
if (only_sending) log_flags |= CLEF_ONLY_SENDING; if (only_sending) log_flags |= CLEF_ONLY_SENDING;
if (my_cmd) log_flags |= CLEF_MY_CMD; if (my_cmd) log_flags |= CLEF_MY_CMD;
if (binary_length > 0) log_flags |= CLEF_BINARY; if (aux_data != nullptr) log_flags |= CLEF_AUX_DATA;
if (!random_state.Check()) log_flags |= CLEF_RANDOM; if (!random_state.Check()) log_flags |= CLEF_RANDOM;
if (order_backup_update_counter != OrderBackup::GetUpdateCounter()) log_flags |= CLEF_ORDER_BACKUP; if (order_backup_update_counter != OrderBackup::GetUpdateCounter()) log_flags |= CLEF_ORDER_BACKUP;
AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags, text); AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags, text);
@@ -988,20 +987,20 @@ bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, C
return res.Succeeded(); return res.Succeeded();
} }
CommandCost DoCommandPScript(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, uint32 binary_length) CommandCost DoCommandPScript(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, const CommandAuxiliaryBase *aux_data)
{ {
GameRandomSeedChecker random_state; GameRandomSeedChecker random_state;
uint order_backup_update_counter = OrderBackup::GetUpdateCounter(); uint order_backup_update_counter = OrderBackup::GetUpdateCounter();
CommandCost res = DoCommandPInternal(tile, p1, p2, p3, cmd, callback, text, my_cmd, estimate_only, binary_length); CommandCost res = DoCommandPInternal(tile, p1, p2, p3, cmd, callback, text, my_cmd, estimate_only, aux_data);
CommandLogEntryFlag log_flags; CommandLogEntryFlag log_flags;
log_flags = CLEF_SCRIPT; log_flags = CLEF_SCRIPT;
if (binary_length == 0 && !StrEmpty(text)) log_flags |= CLEF_TEXT; if (!StrEmpty(text)) log_flags |= CLEF_TEXT;
if (estimate_only) log_flags |= CLEF_ESTIMATE_ONLY; if (estimate_only) log_flags |= CLEF_ESTIMATE_ONLY;
if (_networking && !(cmd & CMD_NETWORK_COMMAND)) log_flags |= CLEF_ONLY_SENDING; if (_networking && !(cmd & CMD_NETWORK_COMMAND)) log_flags |= CLEF_ONLY_SENDING;
if (my_cmd) log_flags |= CLEF_MY_CMD; if (my_cmd) log_flags |= CLEF_MY_CMD;
if (binary_length > 0) log_flags |= CLEF_BINARY; if (aux_data != nullptr) log_flags |= CLEF_AUX_DATA;
if (!random_state.Check()) log_flags |= CLEF_RANDOM; if (!random_state.Check()) log_flags |= CLEF_RANDOM;
if (order_backup_update_counter != OrderBackup::GetUpdateCounter()) log_flags |= CLEF_ORDER_BACKUP; if (order_backup_update_counter != OrderBackup::GetUpdateCounter()) log_flags |= CLEF_ORDER_BACKUP;
AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags, text); AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags, text);
@@ -1063,7 +1062,7 @@ void EnqueueDoCommandP(CommandContainer cmd)
* @param estimate_only whether to give only the estimate or also execute the command * @param estimate_only whether to give only the estimate or also execute the command
* @return the command cost of this function. * @return the command cost of this function.
*/ */
CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, uint32 binary_length) CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, const CommandAuxiliaryBase *aux_data)
{ {
/* Prevent recursion; it gives a mess over the network */ /* Prevent recursion; it gives a mess over the network */
assert(_docommand_recursive == 0); assert(_docommand_recursive == 0);
@@ -1113,13 +1112,13 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3,
_cleared_object_areas.clear(); _cleared_object_areas.clear();
SetTownRatingTestMode(true); SetTownRatingTestMode(true);
BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE); BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE);
CommandCost res = command.Execute(tile, flags, p1, p2, p3, text, binary_length); CommandCost res = command.Execute(tile, flags, p1, p2, p3, text, aux_data);
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE);
SetTownRatingTestMode(false); SetTownRatingTestMode(false);
if (!random_state.Check()) { if (!random_state.Check()) {
std::string msg = stdstr_fmt("Random seed changed in test command: company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\" %X (%s)", std::string msg = stdstr_fmt("Random seed changed in test command: company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\"%s (%s)",
(int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, binary_length, GetCommandName(cmd)); (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, aux_data != nullptr ? ", aux data present" : "", GetCommandName(cmd));
DEBUG(desync, 0, "msg: date{%08x; %02x; %02x}; %s", _date, _date_fract, _tick_skip_counter, msg.c_str()); DEBUG(desync, 0, "msg: date{%08x; %02x; %02x}; %s", _date, _date_fract, _tick_skip_counter, msg.c_str());
LogDesyncMsg(std::move(msg)); LogDesyncMsg(std::move(msg));
} }
@@ -1137,8 +1136,8 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3,
if (!_networking || _generating_world || (cmd & CMD_NETWORK_COMMAND) != 0) { if (!_networking || _generating_world || (cmd & CMD_NETWORK_COMMAND) != 0) {
/* Log the failed command as well. Just to be able to be find /* Log the failed command as well. Just to be able to be find
* causes of desyncs due to bad command test implementations. */ * causes of desyncs due to bad command test implementations. */
DEBUG(desync, 1, "cmdf: date{%08x; %02x; %02x}; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\" %X (%s)", DEBUG(desync, 1, "cmdf: date{%08x; %02x; %02x}; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\"%s (%s)",
_date, _date_fract, _tick_skip_counter, (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, binary_length, GetCommandName(cmd)); _date, _date_fract, _tick_skip_counter, (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, aux_data != nullptr ? ", aux data present" : "", GetCommandName(cmd));
} }
cur_company.Restore(); cur_company.Restore();
return_dcpi(res); return_dcpi(res);
@@ -1149,7 +1148,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3,
* send it to the command-queue and abort execution * send it to the command-queue and abort execution
*/ */
if (_networking && !_generating_world && !(cmd & CMD_NETWORK_COMMAND)) { if (_networking && !_generating_world && !(cmd & CMD_NETWORK_COMMAND)) {
NetworkSendCommand(tile, p1, p2, p3, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company, binary_length); NetworkSendCommand(tile, p1, p2, p3, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company, aux_data);
cur_company.Restore(); cur_company.Restore();
/* Don't return anything special here; no error, no costs. /* Don't return anything special here; no error, no costs.
@@ -1158,14 +1157,14 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3,
* reset the storages as we've not executed the command. */ * reset the storages as we've not executed the command. */
return_dcpi(CommandCost()); return_dcpi(CommandCost());
} }
DEBUG(desync, 1, "cmd: date{%08x; %02x; %02x}; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\" %X (%s)", DEBUG(desync, 1, "cmd: date{%08x; %02x; %02x}; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\"%s(%s)",
_date, _date_fract, _tick_skip_counter, (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, binary_length, GetCommandName(cmd)); _date, _date_fract, _tick_skip_counter, (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, aux_data != nullptr ? ", aux data present" : "", GetCommandName(cmd));
/* Actually try and execute the command. If no cost-type is given /* Actually try and execute the command. If no cost-type is given
* use the construction one */ * use the construction one */
_cleared_object_areas.clear(); _cleared_object_areas.clear();
BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND); BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND);
CommandCost res2 = command.Execute(tile, flags | DC_EXEC, p1, p2, p3, text, binary_length); CommandCost res2 = command.Execute(tile, flags | DC_EXEC, p1, p2, p3, text, aux_data);
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND);
if (cmd_id == CMD_COMPANY_CTRL) { if (cmd_id == CMD_COMPANY_CTRL) {

View File

@@ -32,7 +32,7 @@ static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID);
*/ */
#define return_cmd_error(errcode) return CommandCost(errcode); #define return_cmd_error(errcode) return CommandCost(errcode);
CommandCost DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, DoCommandFlag flags, uint32 cmd, const char *text = nullptr, uint32 binary_length = 0); CommandCost DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, DoCommandFlag flags, uint32 cmd, const char *text = nullptr, const CommandAuxiliaryBase *aux_data = nullptr);
inline CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = nullptr) inline CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = nullptr)
{ {
@@ -40,10 +40,10 @@ inline CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag
} }
inline CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags) inline CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
{ {
return DoCommandEx(container->tile, container->p1, container->p2, container->p3, flags, container->cmd & CMD_ID_MASK, container->text.c_str(), container->binary_length); return DoCommandEx(container->tile, container->p1, container->p2, container->p3, flags, container->cmd & CMD_ID_MASK, container->text.c_str(), container->aux_data.get());
} }
bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, uint32 binary_length, bool my_cmd = true); bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, const CommandAuxiliaryBase *aux_data, bool my_cmd = true);
inline bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = nullptr, const char *text = nullptr, bool my_cmd = true) inline bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = nullptr, const char *text = nullptr, bool my_cmd = true)
{ {
@@ -52,13 +52,13 @@ inline bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Command
inline bool DoCommandP(const CommandContainer *container, bool my_cmd = true) inline bool DoCommandP(const CommandContainer *container, bool my_cmd = true)
{ {
return DoCommandPEx(container->tile, container->p1, container->p2, container->p3, container->cmd, container->callback, container->text.c_str(), container->binary_length, my_cmd); return DoCommandPEx(container->tile, container->p1, container->p2, container->p3, container->cmd, container->callback, container->text.c_str(), container->aux_data.get(), my_cmd);
} }
CommandCost DoCommandPScript(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, uint32 binary_length); CommandCost DoCommandPScript(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, const CommandAuxiliaryBase *aux_data);
CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, uint32 binary_length); CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, const CommandAuxiliaryBase *aux_data);
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company, uint32 binary_length); void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company, const CommandAuxiliaryBase *aux_data);
extern Money _additional_cash_required; extern Money _additional_cash_required;

View File

@@ -621,6 +621,8 @@ enum CommandPauseLevel {
CMDPL_ALL_ACTIONS, ///< All actions may be executed. CMDPL_ALL_ACTIONS, ///< All actions may be executed.
}; };
struct CommandAuxiliaryBase;
/** /**
* Defines the callback type for all command handler functions. * Defines the callback type for all command handler functions.
* *
@@ -640,7 +642,7 @@ enum CommandPauseLevel {
* @return The CommandCost of the command, which can be succeeded or failed. * @return The CommandCost of the command, which can be succeeded or failed.
*/ */
typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text); typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text);
typedef CommandCost CommandProcEx(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length); typedef CommandCost CommandProcEx(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data);
/** /**
* Define a command with the flags which belongs to it. * Define a command with the flags which belongs to it.
@@ -662,9 +664,9 @@ struct Command {
Command(CommandProcEx *procex, const char *name, CommandFlags flags, CommandType type) Command(CommandProcEx *procex, const char *name, CommandFlags flags, CommandType type)
: procex(procex), name(name), flags(flags | CMD_PROCEX), type(type) {} : procex(procex), name(name), flags(flags | CMD_PROCEX), type(type) {}
inline CommandCost Execute(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) const { inline CommandCost Execute(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data) const {
if (this->flags & CMD_PROCEX) { if (this->flags & CMD_PROCEX) {
return this->procex(tile, flags, p1, p2, p3, text, binary_length); return this->procex(tile, flags, p1, p2, p3, text, aux_data);
} else { } else {
return this->proc(tile, flags, p1, p2, text); return this->proc(tile, flags, p1, p2, text);
} }
@@ -733,13 +735,13 @@ struct CommandContainer {
uint32 cmd; ///< command being executed. uint32 cmd; ///< command being executed.
uint64 p3; ///< parameter p3. (here for alignment) uint64 p3; ///< parameter p3. (here for alignment)
CommandCallback *callback; ///< any callback function executed upon successful completion of the command. CommandCallback *callback; ///< any callback function executed upon successful completion of the command.
uint32 binary_length; ///< in case text contains binary data, this describes its length.
std::string text; ///< possible text sent for name changes etc. std::string text; ///< possible text sent for name changes etc.
CommandAuxiliaryPtr aux_data; ///< Auxiliary command data
}; };
inline CommandContainer NewCommandContainerBasic(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = nullptr) inline CommandContainer NewCommandContainerBasic(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = nullptr)
{ {
return { tile, p1, p2, cmd, 0, callback, 0, {} }; return { tile, p1, p2, cmd, 0, callback, {}, nullptr };
} }
#endif /* COMMAND_TYPE_H */ #endif /* COMMAND_TYPE_H */

View File

@@ -922,7 +922,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
/* In network games, we need to try setting the company manager face here to sync it to all clients. /* In network games, we need to try setting the company manager face here to sync it to all clients.
* If a favorite company manager face is selected, choose it. Otherwise, use a random face. */ * If a favorite company manager face is selected, choose it. Otherwise, use a random face. */
if (_company_manager_face != 0) NetworkSendCommand(0, 0, _company_manager_face, 0, CMD_SET_COMPANY_MANAGER_FACE, nullptr, nullptr, _local_company, 0); if (_company_manager_face != 0) NetworkSendCommand(0, 0, _company_manager_face, 0, CMD_SET_COMPANY_MANAGER_FACE, nullptr, nullptr, _local_company, nullptr);
/* Now that we have a new company, broadcast our company settings to /* Now that we have a new company, broadcast our company settings to
* all clients so everything is in sync */ * all clients so everything is in sync */

View File

@@ -190,7 +190,7 @@ CommandCost CmdCreateLeagueTable(TileIndex tile, DoCommandFlag flags, uint32 p1,
return res; return res;
} }
CommandCost CmdCreateLeagueTableElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdCreateLeagueTableElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
std::string text_str, score; std::string text_str, score;
text = StrConsumeToSeparator(text_str, text); text = StrConsumeToSeparator(text_str, text);
@@ -227,7 +227,7 @@ CommandCost CmdUpdateLeagueTableElementData(TileIndex tile, DoCommandFlag flags,
return CmdUpdateLeagueTableElementData(flags, element, company, text, link_type, link_target); return CmdUpdateLeagueTableElementData(flags, element, company, text, link_type, link_target);
} }
CommandCost CmdUpdateLeagueTableElementScore(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdUpdateLeagueTableElementScore(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
return CmdUpdateLeagueTableElementScore(flags, p1, p3, text); return CmdUpdateLeagueTableElementScore(flags, p1, p3, text);
} }

View File

@@ -85,6 +85,13 @@ bool Packet::CanWriteToPacket(size_t bytes_to_write)
return this->Size() + bytes_to_write <= this->limit; return this->Size() + bytes_to_write <= this->limit;
} }
void Packet::WriteAtOffset_uint16(size_t offset, uint16 data)
{
assert(offset + 1 < this->buffer.size());
this->buffer[offset] = GB(data, 0, 8);
this->buffer[offset + 1] = GB(data, 8, 8);
}
/* /*

View File

@@ -74,6 +74,8 @@ public:
bool CanWriteToPacket(size_t bytes_to_write); bool CanWriteToPacket(size_t bytes_to_write);
void WriteAtOffset_uint16(size_t offset, uint16);
/* Reading/receiving of packets */ /* Reading/receiving of packets */
size_t ReadRawPacketSize() const; size_t ReadRawPacketSize() const;
bool HasPacketSizeData() const; bool HasPacketSizeData() const;

View File

@@ -1120,7 +1120,7 @@ void NetworkGameLoop()
while (f != nullptr && !feof(f)) { while (f != nullptr && !feof(f)) {
if (_date == next_date && _date_fract == next_date_fract) { if (_date == next_date && _date_fract == next_date_fract) {
if (cp != nullptr) { if (cp != nullptr) {
NetworkSendCommand(cp->tile, cp->p1, cp->p2, cp->p3, cp->cmd & ~CMD_FLAGS_MASK, nullptr, cp->text.c_str(), cp->company, cp->binary_length); NetworkSendCommand(cp->tile, cp->p1, cp->p2, cp->p3, cp->cmd & ~CMD_FLAGS_MASK, nullptr, cp->text.c_str(), cp->company, cp->aux_data);
DEBUG(net, 0, "injecting: date{%08x; %02x; %02x}; %02x; %06x; %08x; %08x; " OTTD_PRINTFHEX64PAD " %08x; \"%s\" (%x) (%s)", _date, _date_fract, _tick_skip_counter, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->p3, cp->cmd, cp->text.c_str(), cp->binary_length, GetCommandName(cp->cmd)); DEBUG(net, 0, "injecting: date{%08x; %02x; %02x}; %02x; %06x; %08x; %08x; " OTTD_PRINTFHEX64PAD " %08x; \"%s\" (%x) (%s)", _date, _date_fract, _tick_skip_counter, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->p3, cp->cmd, cp->text.c_str(), cp->binary_length, GetCommandName(cp->cmd));
cp.reset(); cp.reset();
} }
@@ -1167,7 +1167,7 @@ void NetworkGameLoop()
* string misses because in 99% of the time it's not used. */ * string misses because in 99% of the time it's not used. */
assert(ret == 10 || ret == 9); assert(ret == 10 || ret == 9);
cp->company = (CompanyID)company; cp->company = (CompanyID)company;
cp->binary_length = 0; cp->aux_data = nullptr;
} else if (strncmp(p, "join: ", 6) == 0) { } else if (strncmp(p, "join: ", 6) == 0) {
/* Manually insert a pause when joining; this way the client can join at the exact right time. */ /* Manually insert a pause when joining; this way the client can join at the exact right time. */
int ret = sscanf(p + 6, "date{%x; %x; %x}", &next_date, &next_date_fract, &next_tick_skip_counter); int ret = sscanf(p + 6, "date{%x; %x; %x}", &next_date, &next_date_fract, &next_tick_skip_counter);
@@ -1181,7 +1181,7 @@ void NetworkGameLoop()
cp->p2 = 1; cp->p2 = 1;
cp->p3 = 0; cp->p3 = 0;
cp->callback = nullptr; cp->callback = nullptr;
cp->binary_length = 0; cp->aux_data = nullptr;
_ddc_fastforward = false; _ddc_fastforward = false;
} else if (strncmp(p, "sync: ", 6) == 0) { } else if (strncmp(p, "sync: ", 6) == 0) {
int ret = sscanf(p + 6, "date{%x; %x; %x}; %x; %x", &next_date, &next_date_fract, &next_tick_skip_counter, &sync_state[0], &sync_state[1]); int ret = sscanf(p + 6, "date{%x; %x; %x}; %x; %x", &next_date, &next_date_fract, &next_tick_skip_counter, &sync_state[0], &sync_state[1]);

View File

@@ -1002,7 +1002,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
* the server will give us a client-id and let us in */ * the server will give us a client-id and let us in */
_network_join_status = NETWORK_JOIN_STATUS_REGISTERING; _network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
ShowJoinStatusWindow(); ShowJoinStatusWindow();
NetworkSendCommand(0, CCA_NEW, 0, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company, 0); NetworkSendCommand(0, CCA_NEW, 0, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company, nullptr);
} }
} else { } else {
/* take control over an existing company */ /* take control over an existing company */

View File

@@ -12,6 +12,7 @@
#include "network_client.h" #include "network_client.h"
#include "network_server.h" #include "network_server.h"
#include "../command_func.h" #include "../command_func.h"
#include "../command_aux.h"
#include "../company_func.h" #include "../company_func.h"
#include "../settings_type.h" #include "../settings_type.h"
@@ -143,9 +144,9 @@ static CommandQueue _local_execution_queue;
* @param callback A callback function to call after the command is finished * @param callback A callback function to call after the command is finished
* @param text The text to pass * @param text The text to pass
* @param company The company that wants to send the command * @param company The company that wants to send the command
* @param binary_length The quantity of binary data in text * @param aux_data Auxiliary command data
*/ */
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company, uint32 binary_length) void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company, const CommandAuxiliaryBase *aux_data)
{ {
assert((cmd & CMD_FLAGS_MASK) == 0); assert((cmd & CMD_FLAGS_MASK) == 0);
@@ -157,17 +158,13 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32
c.p3 = p3; c.p3 = p3;
c.cmd = cmd; c.cmd = cmd;
c.callback = callback; c.callback = callback;
if (aux_data != nullptr) c.aux_data.reset(aux_data->Clone());
c.binary_length = binary_length;
if (binary_length == 0) {
if (text != nullptr) { if (text != nullptr) {
c.text.assign(text); c.text.assign(text);
} else { } else {
c.text.clear(); c.text.clear();
} }
} else {
c.text.assign(text, binary_length);
}
if (_network_server) { if (_network_server) {
/* If we are the server, we queue the command in our 'special' queue. /* If we are the server, we queue the command in our 'special' queue.
@@ -328,21 +325,24 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c
cp->p2 = p->Recv_uint32(); cp->p2 = p->Recv_uint32();
cp->p3 = p->Recv_uint64(); cp->p3 = p->Recv_uint64();
cp->tile = p->Recv_uint32(); cp->tile = p->Recv_uint32();
cp->binary_length = p->Recv_uint32();
if (cp->binary_length == 0) {
StringValidationSettings settings = (!_network_server && GetCommandFlags(cp->cmd) & CMD_STR_CTRL) != 0 ? SVS_ALLOW_CONTROL_CODE | SVS_REPLACE_WITH_QUESTION_MARK : SVS_REPLACE_WITH_QUESTION_MARK; StringValidationSettings settings = (!_network_server && GetCommandFlags(cp->cmd) & CMD_STR_CTRL) != 0 ? SVS_ALLOW_CONTROL_CODE | SVS_REPLACE_WITH_QUESTION_MARK : SVS_REPLACE_WITH_QUESTION_MARK;
if (GetCommandFlags(cp->cmd) & CMD_STR_SEP) settings |= SVS_ALLOW_SEPARATOR_CODE; if (GetCommandFlags(cp->cmd) & CMD_STR_SEP) settings |= SVS_ALLOW_SEPARATOR_CODE;
p->Recv_string(cp->text, settings); p->Recv_string(cp->text, settings);
} else {
if (!p->CanReadFromPacket(cp->binary_length + /* callback index */ 1)) return "invalid binary data length";
if (cp->binary_length > MAX_CMD_TEXT_LENGTH) return "over-size binary data length";
p->Recv_binary(cp->text, cp->binary_length);
}
byte callback = p->Recv_uint8(); byte callback = p->Recv_uint8();
if (callback >= lengthof(_callback_table)) return "invalid callback"; if (callback >= lengthof(_callback_table)) return "invalid callback";
cp->callback = _callback_table[callback]; cp->callback = _callback_table[callback];
uint16 aux_data_size = p->Recv_uint16();
if (aux_data_size > 0 && p->CanReadFromPacket(aux_data_size, true)) {
CommandAuxiliarySerialised *aux_data = new CommandAuxiliarySerialised();
cp->aux_data.reset(aux_data);
aux_data->serialised_data.resize(aux_data_size);
p->Recv_binary((char *)(aux_data->serialised_data.data()), aux_data_size);
}
return nullptr; return nullptr;
} }
@@ -359,13 +359,7 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
p->Send_uint32(cp->p2); p->Send_uint32(cp->p2);
p->Send_uint64(cp->p3); p->Send_uint64(cp->p3);
p->Send_uint32(cp->tile); p->Send_uint32(cp->tile);
p->Send_uint32(cp->binary_length);
if (cp->binary_length == 0) {
p->Send_string(cp->text.c_str()); p->Send_string(cp->text.c_str());
} else {
assert(cp->text.size() >= cp->binary_length);
p->Send_binary(cp->text.c_str(), cp->binary_length);
}
byte callback = 0; byte callback = 0;
while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) { while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
@@ -377,4 +371,12 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
callback = 0; // _callback_table[0] == nullptr callback = 0; // _callback_table[0] == nullptr
} }
p->Send_uint8 (callback); p->Send_uint8 (callback);
size_t aux_data_size_pos = p->Size();
p->Send_uint16(0);
if (cp->aux_data != nullptr) {
CommandSerialisationBuffer serialiser(p->GetSerialisationBuffer(), p->GetSerialisationLimit());
cp->aux_data->Serialise(serialiser);
p->WriteAtOffset_uint16(aux_data_size_pos, (uint16)(p->Size() - aux_data_size_pos - 2));
}
} }

View File

@@ -1563,7 +1563,7 @@ private:
if (_network_server) { if (_network_server) {
DoCommandP(0, CCA_NEW, _network_own_client_id, CMD_COMPANY_CTRL); DoCommandP(0, CCA_NEW, _network_own_client_id, CMD_COMPANY_CTRL);
} else { } else {
NetworkSendCommand(0, CCA_NEW, 0, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company, 0); NetworkSendCommand(0, CCA_NEW, 0, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company, nullptr);
} }
} }

View File

@@ -1211,7 +1211,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p
_settings_client.network.sync_freq = std::min<uint16>(_settings_client.network.sync_freq, 16); _settings_client.network.sync_freq = std::min<uint16>(_settings_client.network.sync_freq, 16);
// have the server and all clients run some sanity checks // have the server and all clients run some sanity checks
NetworkSendCommand(0, 0, 0, 0, CMD_DESYNC_CHECK, nullptr, nullptr, _local_company, 0); NetworkSendCommand(0, 0, 0, 0, CMD_DESYNC_CHECK, nullptr, nullptr, _local_company, nullptr);
SendPacketsState send_state = this->SendPackets(true); SendPacketsState send_state = this->SendPackets(true);
if (send_state != SPS_CLOSED) { if (send_state != SPS_CLOSED) {
@@ -2301,7 +2301,7 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */ /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
ci->client_playas = c->index; ci->client_playas = c->index;
NetworkUpdateClientInfo(ci->client_id); NetworkUpdateClientInfo(ci->client_id);
NetworkSendCommand(0, 0, 0, 0, CMD_RENAME_PRESIDENT, nullptr, ci->client_name.c_str(), c->index, 0); NetworkSendCommand(0, 0, 0, 0, CMD_RENAME_PRESIDENT, nullptr, ci->client_name.c_str(), c->index, nullptr);
} }
/* Announce new company on network. */ /* Announce new company on network. */

View File

@@ -966,7 +966,7 @@ uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
VehicleID veh = GB(p1, 0, 20); VehicleID veh = GB(p1, 0, 20);
VehicleOrderID sel_ord = GB(p2, 0, 16); VehicleOrderID sel_ord = GB(p2, 0, 16);
@@ -1758,7 +1758,7 @@ CommandCost CmdReverseOrderList(TileIndex tile, DoCommandFlag flags, uint32 p1,
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
VehicleOrderID sel_ord = GB(p3, 0, 16); VehicleOrderID sel_ord = GB(p3, 0, 16);
VehicleID veh = GB(p1, 0, 20); VehicleID veh = GB(p1, 0, 20);

View File

@@ -47,3 +47,19 @@ void PlanLine::UpdateVisualExtents()
this->viewport_extents = { (int)(min_x * TILE_SIZE * 2 * ZOOM_LVL_BASE), (int)(min_y * TILE_SIZE * ZOOM_LVL_BASE), this->viewport_extents = { (int)(min_x * TILE_SIZE * 2 * ZOOM_LVL_BASE), (int)(min_y * TILE_SIZE * ZOOM_LVL_BASE),
(int)((max_x + 1) * TILE_SIZE * 2 * ZOOM_LVL_BASE), (int)((max_y + 1) * TILE_SIZE * ZOOM_LVL_BASE) }; (int)((max_x + 1) * TILE_SIZE * 2 * ZOOM_LVL_BASE), (int)((max_y + 1) * TILE_SIZE * ZOOM_LVL_BASE) };
} }
bool Plan::ValidateNewLine()
{
extern bool AddPlanLine(PlanID plan, TileVector tiles);
bool ret = false;
if (this->temp_line->tiles.size() > 1) {
this->temp_line->MarkDirty();
this->last_tile = this->temp_line->tiles.back();
this->SetVisibility(true, false);
TileVector tiles = std::move(this->temp_line->tiles);
this->temp_line->Clear();
ret = AddPlanLine(this->index, std::move(tiles));
}
return ret;
}

View File

@@ -18,7 +18,6 @@
#include "map_func.h" #include "map_func.h"
#include "date_func.h" #include "date_func.h"
#include "viewport_func.h" #include "viewport_func.h"
#include "core/endian_func.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -111,30 +110,6 @@ struct PlanLine {
} }
} }
TileIndex *Export(uint *buffer_length)
{
const uint cnt = (uint) this->tiles.size();
const uint datalen = sizeof(TileIndex) * cnt;
TileIndex *buffer = (TileIndex *) malloc(datalen);
if (buffer) {
for (uint i = 0; i < cnt; i++) {
buffer[i] = TO_LE32(this->tiles[i]);
}
if (buffer_length) *buffer_length = datalen;
}
return buffer;
}
bool Import(const TileIndex* data, const uint data_length)
{
for (uint i = data_length; i != 0; i--, data++) {
TileIndex t = FROM_LE32(*data);
if (t >= MapSize()) return false;
this->tiles.push_back(t);
}
return true;
}
void AddLineToCalculateCentreTile(uint64 &x, uint64 &y, uint32 &count) const void AddLineToCalculateCentreTile(uint64 &x, uint64 &y, uint32 &count) const
{ {
for (size_t i = 0; i < this->tiles.size(); i++) { for (size_t i = 0; i < this->tiles.size(); i++) {
@@ -226,24 +201,7 @@ struct Plan : PlanPool::PoolItem<&_plan_pool> {
return this->temp_line->AppendTile(tile); return this->temp_line->AppendTile(tile);
} }
bool ValidateNewLine() bool ValidateNewLine();
{
bool ret = false;
if (this->temp_line->tiles.size() > 1) {
uint buffer_length = 0;
const TileIndex *buffer = this->temp_line->Export(&buffer_length);
uint tiles = (uint)this->temp_line->tiles.size();
this->temp_line->MarkDirty();
this->last_tile = this->temp_line->tiles.back();
this->temp_line->Clear();
if (buffer) {
this->SetVisibility(true, false);
ret = DoCommandPEx(0, this->index, tiles, 0, CMD_ADD_PLAN_LINE, nullptr, (const char *) buffer, buffer_length);
free(buffer);
}
}
return ret;
}
bool IsListable() bool IsListable()
{ {

View File

@@ -9,6 +9,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "command_func.h" #include "command_func.h"
#include "command_aux.h"
#include "plans_base.h" #include "plans_base.h"
#include "plans_func.h" #include "plans_func.h"
#include "window_func.h" #include "window_func.h"
@@ -43,6 +44,36 @@ CommandCost CmdAddPlan(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2
return CommandCost(); return CommandCost();
} }
struct PlanLineCmdData : public CommandAuxiliarySerialisable<PlanLineCmdData> {
TileVector tiles;
virtual void Serialise(CommandSerialisationBuffer &buffer) const override
{
buffer.Send_uint32((uint32)this->tiles.size());
for (TileIndex t : this->tiles) {
buffer.Send_uint32(t);
}
}
CommandCost Deserialise(CommandDeserialisationBuffer &buffer)
{
uint32 size = buffer.Recv_uint32();
if (!buffer.CanRecvBytes(size * 4)) return CMD_ERROR;
this->tiles.resize(size);
for (uint i = 0; i < size; i++) {
this->tiles[i] = buffer.Recv_uint32();
}
return CommandCost();
}
};
bool AddPlanLine(PlanID plan, TileVector tiles)
{
PlanLineCmdData data;
data.tiles = std::move(tiles);
return DoCommandPEx(0, plan, 0, 0, CMD_ADD_PLAN_LINE, nullptr, nullptr, &data);
}
/** /**
* Create a new line in a plan. * Create a new line in a plan.
* @param tile unused * @param tile unused
@@ -50,25 +81,25 @@ CommandCost CmdAddPlan(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2
* @param p1 plan id * @param p1 plan id
* @param p2 number of nodes * @param p2 number of nodes
* @param text list of tile indexes that compose the line * @param text list of tile indexes that compose the line
* @param binary_length binary length of text * @param aux_data auxiliary data
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdAddPlanLine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdAddPlanLine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
Plan *p = Plan::GetIfValid(p1); Plan *p = Plan::GetIfValid(p1);
if (p == nullptr) return CMD_ERROR; if (p == nullptr) return CMD_ERROR;
CommandCost ret = CheckOwnership(p->owner); CommandCost ret = CheckOwnership(p->owner);
if (ret.Failed()) return ret; if (ret.Failed()) return ret;
if (p2 > (MAX_CMD_TEXT_LENGTH / sizeof(TileIndex))) return_cmd_error(STR_ERROR_TOO_MANY_NODES);
if (!text || binary_length != p2 * 4) return CMD_ERROR; CommandAuxData<PlanLineCmdData> data;
ret = data.Load(aux_data);
if (ret.Failed()) return ret;
if (data->tiles.size() > (MAX_CMD_TEXT_LENGTH / sizeof(TileIndex))) return_cmd_error(STR_ERROR_TOO_MANY_NODES);
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
PlanLine *pl = p->NewLine(); PlanLine *pl = p->NewLine();
if (!pl) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_LINES); if (!pl) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_LINES);
if (!pl->Import((const TileIndex *) text, p2)) { pl->tiles = std::move(data->tiles);
delete pl;
p->lines.pop_back();
return CMD_ERROR;
}
pl->UpdateVisualExtents(); pl->UpdateVisualExtents();
if (p->IsListable()) { if (p->IsListable()) {
pl->SetVisibility(p->visible); pl->SetVisibility(p->visible);

View File

@@ -73,7 +73,7 @@ CommandCost CmdScheduledDispatch(TileIndex tile, DoCommandFlag flags, uint32 p1,
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
VehicleID veh = GB(p1, 0, 20); VehicleID veh = GB(p1, 0, 20);
uint schedule_index = GB(p1, 20, 12); uint schedule_index = GB(p1, 20, 12);
@@ -185,7 +185,7 @@ CommandCost CmdScheduledDispatchSetDuration(TileIndex tile, DoCommandFlag flags,
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdScheduledDispatchSetStartDate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdScheduledDispatchSetStartDate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
VehicleID veh = GB(p1, 0, 20); VehicleID veh = GB(p1, 0, 20);
uint schedule_index = GB(p1, 20, 12); uint schedule_index = GB(p1, 20, 12);
@@ -330,7 +330,7 @@ CommandCost CmdScheduledDispatchClear(TileIndex tile, DoCommandFlag flags, uint3
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdScheduledDispatchAddNewSchedule(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdScheduledDispatchAddNewSchedule(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
VehicleID veh = GB(p1, 0, 20); VehicleID veh = GB(p1, 0, 20);

View File

@@ -313,7 +313,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return GetStorage()->callback_value[index]; return GetStorage()->callback_value[index];
} }
/* static */ bool ScriptObject::DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint cmd, const char *text, uint32 binary_length, Script_SuspendCallbackProc *callback) /* static */ bool ScriptObject::DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint cmd, const char *text, const CommandAuxiliaryBase *aux_data, Script_SuspendCallbackProc *callback)
{ {
if (!ScriptObject::CanSuspend()) { if (!ScriptObject::CanSuspend()) {
throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator."); throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
@@ -325,7 +325,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
} }
std::string text_validated; std::string text_validated;
if (binary_length == 0 && !StrEmpty(text) && (GetCommandFlags(cmd) & CMD_STR_CTRL) == 0) { if (!StrEmpty(text) && (GetCommandFlags(cmd) & CMD_STR_CTRL) == 0) {
/* The string must be valid, i.e. not contain special codes. Since some /* The string must be valid, i.e. not contain special codes. Since some
* can be made with GSText, make sure the control codes are removed. */ * can be made with GSText, make sure the control codes are removed. */
text_validated = text; text_validated = text;
@@ -349,7 +349,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
if (!estimate_only && _networking && !_generating_world) SetLastCommand(tile, p1, p2, p3, cmd); if (!estimate_only && _networking && !_generating_world) SetLastCommand(tile, p1, p2, p3, cmd);
/* Try to perform the command. */ /* Try to perform the command. */
CommandCost res = ::DoCommandPScript(tile, p1, p2, p3, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, text, false, estimate_only, binary_length); CommandCost res = ::DoCommandPScript(tile, p1, p2, p3, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, text, false, estimate_only, aux_data);
/* We failed; set the error and bail out */ /* We failed; set the error and bail out */
if (res.Failed()) { if (res.Failed()) {

View File

@@ -18,6 +18,8 @@
#include "../script_suspend.hpp" #include "../script_suspend.hpp"
#include "../squirrel.hpp" #include "../squirrel.hpp"
struct CommandAuxiliaryBase;
/** /**
* The callback function for Mode-classes. * The callback function for Mode-classes.
*/ */
@@ -69,7 +71,7 @@ protected:
/** /**
* Executes a raw DoCommand for the script. * Executes a raw DoCommand for the script.
*/ */
static bool DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint cmd, const char *text = nullptr, uint32 binary_length = 0, Script_SuspendCallbackProc *callback = nullptr); static bool DoCommandEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint cmd, const char *text = nullptr, const CommandAuxiliaryBase *aux_data = nullptr, Script_SuspendCallbackProc *callback = nullptr);
static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text = nullptr, Script_SuspendCallbackProc *callback = nullptr) static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text = nullptr, Script_SuspendCallbackProc *callback = nullptr)
{ {

View File

@@ -2647,7 +2647,7 @@ void SyncCompanySettings()
if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue; if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue;
uint32 old_value = (uint32)sd->AsIntSetting()->Read(old_object); uint32 old_value = (uint32)sd->AsIntSetting()->Read(old_object);
uint32 new_value = (uint32)sd->AsIntSetting()->Read(new_object); uint32 new_value = (uint32)sd->AsIntSetting()->Read(new_object);
if (old_value != new_value) NetworkSendCommand(0, 0, new_value, 0, CMD_CHANGE_COMPANY_SETTING, nullptr, sd->name, _local_company, 0); if (old_value != new_value) NetworkSendCommand(0, 0, new_value, 0, CMD_CHANGE_COMPANY_SETTING, nullptr, sd->name, _local_company, nullptr);
} }
} }

View File

@@ -2087,7 +2087,7 @@ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID statio
* @param text Unused. * @param text Unused.
* @return The cost of this operation or an error. * @return The cost of this operation or an error.
*/ */
CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
bool type = HasBit(p2, 0); bool type = HasBit(p2, 0);
bool is_drive_through = HasBit(p2, 1); bool is_drive_through = HasBit(p2, 1);

View File

@@ -162,7 +162,7 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint32 val,
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
VehicleID veh = GB(p1, 0, 20); VehicleID veh = GB(p1, 0, 20);

View File

@@ -199,7 +199,7 @@ extern CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
/* Unpack parameters */ /* Unpack parameters */
Axis axis = Extract<Axis, 6, 1>(p1); Axis axis = Extract<Axis, 6, 1>(p1);
@@ -344,7 +344,7 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
* @param text Unused. * @param text Unused.
* @return The cost of this operation or an error. * @return The cost of this operation or an error.
*/ */
CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length) CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, const CommandAuxiliaryBase *aux_data)
{ {
StationID station_to_join = GB(p2, 16, 16); StationID station_to_join = GB(p2, 16, 16);
byte width = GB(p1, 0, 8); byte width = GB(p1, 0, 8);