diff --git a/src/citymania/CMakeLists.txt b/src/citymania/CMakeLists.txt index dfb08fc958..80fae71762 100644 --- a/src/citymania/CMakeLists.txt +++ b/src/citymania/CMakeLists.txt @@ -31,6 +31,8 @@ add_files( cm_commands.cpp cm_commands_gui.hpp cm_commands_gui.cpp + cm_command_log.hpp + cm_command_log.cpp cm_highlight.hpp cm_highlight.cpp cm_highlight_type.hpp diff --git a/src/citymania/cm_bitstream.cpp b/src/citymania/cm_bitstream.cpp index 7c9782dcda..75f29611c6 100644 --- a/src/citymania/cm_bitstream.cpp +++ b/src/citymania/cm_bitstream.cpp @@ -84,4 +84,11 @@ Money BitIStream::ReadMoney() { return (Money)this->ReadBytes64(8); } +std::vector BitIStream::ReadData() { + auto len = this->ReadBytes(2); + std::vector res; + for (auto i = 0; i < len; i++) res.push_back(this->ReadBytes(1)); + return res; +} + } // namespace citymania diff --git a/src/citymania/cm_bitstream.hpp b/src/citymania/cm_bitstream.hpp index 9b0748d483..3459917841 100644 --- a/src/citymania/cm_bitstream.hpp +++ b/src/citymania/cm_bitstream.hpp @@ -42,6 +42,10 @@ public: uint32 ReadBytes(uint amount); uint64 ReadBytes64(uint amount); Money ReadMoney(); + std::vector ReadData(); + bool eof() { + return this->i >= f.size(); + } }; } // namespace citymania diff --git a/src/citymania/cm_console_cmds.cpp b/src/citymania/cm_console_cmds.cpp index 654f32b44e..fb80ee3a5d 100644 --- a/src/citymania/cm_console_cmds.cpp +++ b/src/citymania/cm_console_cmds.cpp @@ -3,6 +3,7 @@ #include "cm_console_cmds.hpp" #include "cm_commands.hpp" +#include "cm_command_log.hpp" #include "cm_export.hpp" #include "../command_func.h" @@ -12,7 +13,6 @@ #include "../fileio_type.h" #include "../map_type.h" #include "../map_func.h" -#include "../network/network_server.h" #include "../strings_func.h" #include "../town.h" #include "../tree_map.h" @@ -30,7 +30,6 @@ namespace citymania { uint32 _replay_save_interval = 0; uint32 _replay_last_save = 0; uint32 _replay_ticks = 0; -bool _replay_started = false; extern uint32 _pause_countdown; static void IConsoleHelp(const char *str) @@ -152,22 +151,8 @@ bool ConResetTownGrowth(byte argc, char *argv[]) { return true; } -struct FakeCommand { - Date date; - DateFract date_fract; - uint res; - uint32 seed; - uint company_id; - uint cmd; - TileIndex tile; - uint32 p1, p2; - std::string text; -}; - -static std::queue _fake_commands; - void MakeReplaySave() { - char *filename = str_fmt("replay_%d.sav", _replay_ticks); + auto filename = fmt::format("replay_{}.sav", _replay_ticks); if (SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, SAVE_DIR) != SL_OK) { IConsolePrint(CC_ERROR, "Replay save failed"); } else { @@ -176,84 +161,6 @@ void MakeReplaySave() { _replay_last_save = _replay_ticks; } -bool DatePredate(Date date1, DateFract date_fract1, Date date2, DateFract date_fract2) { - return date1 < date2 || (date1 == date2 && date_fract1 < date_fract2); -} - -void SkipFakeCommands(Date date, DateFract date_fract) { - uint commands_skipped = 0; - - while (!_fake_commands.empty() && DatePredate(_fake_commands.front().date, _fake_commands.front().date_fract, date, date_fract)) { - _fake_commands.pop(); - commands_skipped++; - } - - if (commands_skipped) { - fprintf(stderr, "Skipped %u commands that predate the current date (%d/%hu)\n", commands_skipped, date, date_fract); - } -} - -void ExecuteFakeCommands(Date date, DateFract date_fract) { - if (!_replay_started) { - SkipFakeCommands(_date, _date_fract); - _replay_started = true; - } - - auto backup_company = _current_company; - while (!_fake_commands.empty() && !DatePredate(date, date_fract, _fake_commands.front().date, _fake_commands.front().date_fract)) { - auto &x = _fake_commands.front(); - - // FIXME - // fprintf(stderr, "Executing command: company=%u cmd=%u(%s) tile=%u p1=%u p2=%u text=%s ... ", x.company_id, x.cmd, GetCommandName(x.cmd), x.tile, x.p1, x.p2, x.text.c_str()); - if (x.res == 0) { - fprintf(stderr, "REJECTED\n"); - _fake_commands.pop(); - continue; - } - - if (_networking) { - /* FIXME - CommandPacket cp; - cp.tile = x.tile; - cp.p1 = x.p1; - cp.p2 = x.p2; - cp.cmd = x.cmd; - cp.text = x.text; - cp.company = (CompanyID)x.company_id; - cp.frame = _frame_counter_max + 1; - cp.callback = nullptr; - cp.my_cmd = false; - - for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { - if (cs->status >= NetworkClientSocket::STATUS_MAP) { - cs->outgoing_queue.Append(&cp); - } - }*/ - } - _current_company = (CompanyID)x.company_id; - /* FIXME - auto res = DoCommandPInternal(x.tile, x.p1, x.p2, x.cmd | CMD_NETWORK_COMMAND, nullptr, x.text.c_str(), false, false); - if (res.Failed() != (x.res != 1)) { - if (!res.Failed()) { - fprintf(stderr, "FAIL (Failing command succeeded)\n"); - } else if (res.GetErrorMessage() != INVALID_STRING_ID) { - char buf[DRAW_STRING_BUFFER]; - GetString(buf, res.GetErrorMessage(), lastof(buf)); - fprintf(stderr, "FAIL (Successful command failed: %s)\n", buf); - } else { - fprintf(stderr, "FAIL (Successful command failed)\n"); - } - } else { - fprintf(stderr, "OK\n"); - } - if (x.seed != (_random.state[0] & 255)) { - fprintf(stderr, "*** DESYNC expected seed %u vs current %u ***\n", x.seed, _random.state[0] & 255); - }*/ - _fake_commands.pop(); - } - _current_company = backup_company; -} - void CheckIntervalSave() { if (_pause_mode == PM_UNPAUSED) { _replay_ticks++; @@ -271,29 +178,6 @@ void SetReplaySaveInterval(uint32 interval) { if (_replay_save_interval) MakeReplaySave(); } -void LoadCommands(const std::string &filename) { - std::queue().swap(_fake_commands); // clear queue - - std::ifstream file(filename, std::ios::in); - std::string str; - while(std::getline(file, str)) { - std::istringstream ss(str); - FakeCommand cmd; - // FIXME ss >> cmd.date >> cmd.date_fract >> cmd.res >> cmd.seed >> cmd.company_id >> cmd.cmd >> cmd.tile >> cmd.p1 >> cmd.p2; - std::string s; - ss.get(); - std::getline(ss, cmd.text); - _fake_commands.push(cmd); - } - - _replay_started = false; -} - -bool IsReplayingCommands() { - return !_fake_commands.empty(); -} - - bool ConLoadCommands(byte argc, char *argv[]) { if (argc == 0) { IConsoleHelp("Loads a file with command queue to execute"); @@ -303,7 +187,9 @@ bool ConLoadCommands(byte argc, char *argv[]) { if (argc > 3) return false; - LoadCommands(argv[1]); + load_replay_commands(argv[1], [](auto error) { + IConsolePrint(CC_ERROR, "{}", error); + }); SetReplaySaveInterval(argc > 2 ? atoi(argv[2]) : 0); return true; diff --git a/src/citymania/cm_console_cmds.hpp b/src/citymania/cm_console_cmds.hpp index 11c40aac55..5d52c74b66 100644 --- a/src/citymania/cm_console_cmds.hpp +++ b/src/citymania/cm_console_cmds.hpp @@ -7,7 +7,6 @@ namespace citymania { void SkipFakeCommands(Date date, DateFract date_fract); void SetReplaySaveInterval(uint32 interval); -void LoadCommands(const std::string &filename); void CheckIntervalSave(); bool IsReplayingCommands(); diff --git a/src/command_func.h b/src/command_func.h index 7f41c6217c..2c3b2f4649 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -22,7 +22,10 @@ struct CommandPacket; -namespace citymania { void ExecuteCurrentCallback(const CommandCost &cost); } +namespace citymania { + extern CommandCost _command_execute_cost; + void ExecuteCurrentCallback(const CommandCost &cost); +} /** * Define a default return value for a failed command. @@ -322,6 +325,7 @@ protected: Tret res = Execute(err_message, reinterpret_cast(callback), my_cmd, estimate_only, network_command, tile, args); InternalPostResult(ExtractCommandCost(res), tile, estimate_only, only_sending, err_message, my_cmd); + citymania::_command_execute_cost = ExtractCommandCost(res); if (!estimate_only && !only_sending && callback != nullptr) { if constexpr (std::is_same_v) { diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 77133b9755..556121823f 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -352,6 +352,19 @@ void NetworkExecuteLocalCommandQueue() _current_company = _local_company; } +namespace citymania { + CommandCost _command_execute_cost; + CommandCost ExecuteCommand(CommandPacket *cp) { + _current_company = cp->company; + size_t cb_index = FindCallbackIndex(cp->callback); + assert(cb_index < _callback_tuple_size); + assert(_cmd_dispatch[cp->cmd].Unpack[cb_index] != nullptr); + _cmd_dispatch[cp->cmd].Unpack[cb_index](cp); + return _command_execute_cost; + } +} + + /** * Free the local command queues. */ diff --git a/src/openttd.cpp b/src/openttd.cpp index 53f1d97ee1..a04d1b50d2 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -71,6 +71,7 @@ #include "linkgraph/linkgraphschedule.h" +#include "citymania/cm_command_log.hpp" #include "citymania/cm_export.hpp" #include "citymania/cm_highlight.hpp" #include "citymania/cm_main.hpp" @@ -674,7 +675,9 @@ int openttd_main(int argc, char *argv[]) ret = 1; return ret; } - citymania::LoadCommands(mgo.opt); + citymania::load_replay_commands(mgo.opt, [](auto error) { + fprintf(stderr, "%s\n", error.c_str()); + }); break; } case 'T': {