diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f77e261fa..8617688162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,7 @@ find_package(Threads REQUIRED) find_package(ZLIB) find_package(LibLZMA) find_package(LZO) -find_package(ZSTD 1.4) +find_package(ZSTD) find_package(PNG) if(WIN32 OR EMSCRIPTEN) @@ -308,6 +308,7 @@ link_package(PNG TARGET PNG::PNG ENCOURAGED) link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED) link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED) link_package(LZO) +link_package(ZSTD TARGET ZSTD::ZSTD ENCOURAGED) if(NOT WIN32 AND NOT EMSCRIPTEN) link_package(CURL ENCOURAGED) diff --git a/src/citymania/cm_console_cmds.cpp b/src/citymania/cm_console_cmds.cpp index 28da9faedd..70206a3b60 100644 --- a/src/citymania/cm_console_cmds.cpp +++ b/src/citymania/cm_console_cmds.cpp @@ -221,12 +221,12 @@ bool ConLoadCommands(std::span argv) { return true; } -bool ConStartRecord(std::span argv) { +bool ConStartRecord(std::span /* argv */) { StartRecording(); return true; } -bool ConStopRecord(std::span argv) { +bool ConStopRecord(std::span /* argv */) { StopRecording(); return true; } diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index 01b883a2d1..dfceef2b2e 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -106,6 +106,7 @@ namespace StationAction { }; StationAction::Mode _station_action = StationAction::Create{}; +StationID _selected_join_station = StationID::Invalid(); static const int MAX_TILE_EXTENT_LEFT = ZOOM_BASE * TILE_PIXELS; ///< Maximum left extent of tile relative to north corner. static const int MAX_TILE_EXTENT_RIGHT = ZOOM_BASE * TILE_PIXELS; ///< Maximum right extent of tile relative to north corner. @@ -155,9 +156,9 @@ void OnStationDeleted(const Station *station) { // } } -// const Station *_last_built_station; +const Station *_last_built_station; void OnStationPartBuilt(const Station *station) { - // _last_built_station = station; + _last_built_station = station; // CheckRedrawStationCoverage(); } @@ -651,12 +652,16 @@ bool HasSelectedStationHighlight() { } static void UpdateStationAction(std::optional area, up cmdptr) { - if (UseImprovedStationJoin()) return; - _station_action = StationAction::Create{}; - if (!area.has_value()) return; + if (UseImprovedStationJoin()) { + auto join_area = GetStationJoinArea(_selected_join_station); + if (!join_area.Intersects(*area)) return; + _station_action = StationAction::Join{_selected_join_station}; + return; + } + if (_fn_mod) { if (!_settings_game.station.distant_join_stations) return; // TODO ctrl with overbuilding errors out in vanilla, shows empty picker here @@ -1061,9 +1066,13 @@ void StationSelectAction::HandleMouseRelease() { // TODO station sign click if (!IsValidTile(this->cur_tile)) return; _station_action = StationAction::Create{}; + _selected_join_station = StationID::Invalid(); if (IsTileType(this->cur_tile, MP_STATION)) { auto st = Station::GetByTile(this->cur_tile); - if (st) _station_action = StationAction::Join{st->index}; + if (st) { + _station_action = StationAction::Join{st->index}; + _selected_join_station = st->index; + } } } @@ -1114,16 +1123,28 @@ StationBuildTool::StationBuildTool() { extern void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc); +template +bool PostBuildStationCommand(Taction *action, Tcallback callback, Targ arg, StationID join_to) { + auto cmd = action->GetCommand(arg, join_to); + if (UseImprovedStationJoin()) { + cmd->with_callback([](bool res)->bool { + if (!res) return false; + if (_last_built_station == nullptr) return false; + _selected_join_station = _last_built_station->index; + return true; + }); + } + return cmd ? cmd->post(callback) : false; +} + template bool ExecuteBuildCommand(Taction *action, Tcallback callback, Targ arg) { std::visit(Overload{ [&](StationAction::Join &a) { - auto cmd = action->GetCommand(arg, a.station); - return cmd ? cmd->post(callback) : false; + return PostBuildStationCommand(action, callback, arg, a.station); }, [&](StationAction::Create &) { - auto cmd = action->GetCommand(arg, NEW_STATION); - return cmd ? cmd->post(callback) : false; + return PostBuildStationCommand(action, callback, arg, NEW_STATION); }, [&](StationAction::Picker &) { auto cmd = action->GetCommand(arg, StationID::Invalid()); diff --git a/src/network/core/config.cpp b/src/network/core/config.cpp index d1942ce131..c946e5ea2d 100644 --- a/src/network/core/config.cpp +++ b/src/network/core/config.cpp @@ -12,6 +12,7 @@ #include "../../stdafx.h" #include "../../string_func.h" +#include "../../rev.h" #include "../../safeguards.h" diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 1c639e75ce..bb0c2812e9 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -316,7 +316,17 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendIdentify() auto p = std::make_unique(my_client, PACKET_CLIENT_IDENTIFY); p->Send_string(_settings_client.network.client_name); // Client name p->Send_uint8 (_network_join.company); // PlayAs - p->Send_uint8 (citymania::GetAvailableLoadFormats()); // Compressnion formats that we can decompress + + /* CityMania additional fields, vanilla servers just ignore them */ + p->Send_uint8 (citymania::GetAvailableLoadFormats()); // Compressinon formats that we can decompress + p->Send_uint8 ('C'); // CMclient join marker + p->Send_uint8 ('M'); // CMclient join marker + p->Send_string(_citymania_survey_key); + p->Send_string(_openttd_build_date); + p->Send_string(_citymania_revision_hash); + p->Send_uint8 (_citymania_revision_modified); + /* End CityMania fields */ + my_client->SendPacket(std::move(p)); return NETWORK_RECV_STATUS_OKAY; } @@ -359,6 +369,11 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGetMap() return NETWORK_RECV_STATUS_OKAY; } +static uint32_t u32_duration(const std::chrono::steady_clock::time_point &begin, const std::chrono::steady_clock::time_point &end) { + auto ms = std::chrono::duration_cast(end - begin).count(); + return ClampTo(ms); +} + /** Tell the server we received the complete map. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk() { @@ -368,6 +383,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk() my_client->status = STATUS_ACTIVE; auto p = std::make_unique(my_client, PACKET_CLIENT_MAP_OK); + p->Send_uint32(u32_duration(my_client->cm_map_begin, my_client->cm_map_done)); + p->Send_uint32(u32_duration(my_client->cm_map_done, my_client->cm_map_loaded)); my_client->SendPacket(std::move(p)); return NETWORK_RECV_STATUS_OKAY; } @@ -773,6 +790,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packe if (this->savegame != nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + this->cm_map_begin = std::chrono::steady_clock::now(); this->savegame = std::make_shared(); _frame_counter = _frame_counter_server = _frame_counter_max = p.Recv_uint32(); @@ -829,6 +847,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); this->savegame->Reset(); + this->cm_map_done = std::chrono::steady_clock::now(); /* The map is done downloading, load it */ ClearErrorMessages(); @@ -838,6 +857,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, this->savegame); this->savegame = nullptr; + this->cm_map_loaded = std::chrono::steady_clock::now(); /* Long savegame loads shouldn't affect the lag calculation! */ this->last_packet = std::chrono::steady_clock::now(); diff --git a/src/network/network_client.h b/src/network/network_client.h index 6205ed9b1b..523b7f41eb 100644 --- a/src/network/network_client.h +++ b/src/network/network_client.h @@ -36,6 +36,10 @@ private: ServerStatus status = STATUS_INACTIVE; ///< Status of the connection with the server. + std::chrono::steady_clock::time_point cm_map_begin; + std::chrono::steady_clock::time_point cm_map_done; + std::chrono::steady_clock::time_point cm_map_loaded; + protected: friend void NetworkExecuteLocalCommandQueue(); friend void NetworkClose(bool close_admins); diff --git a/src/rev.cpp.in b/src/rev.cpp.in index c6c909736a..e82ba4bc1a 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -96,3 +96,7 @@ const std::string_view _openttd_content_version = "15.0"; * have to adjust the major by 16. */ const uint32_t _openttd_newgrf_version = (15 + 16) << 24 | 0 << 20 | 0 << 19 | 28004; + +const std::string _citymania_survey_key = "cmclient"; +const std::string _citymania_revision_hash = "${REV_HASH}"; +const uint8_t _citymania_revision_modified = ${REV_MODIFIED}; diff --git a/src/rev.h b/src/rev.h index cb4b7931f1..fa742508cd 100644 --- a/src/rev.h +++ b/src/rev.h @@ -18,6 +18,9 @@ extern const uint8_t _openttd_revision_modified; extern const uint8_t _openttd_revision_tagged; extern const std::string_view _openttd_content_version; extern const uint32_t _openttd_newgrf_version; +extern const std::string _citymania_survey_key; +extern const std::string _citymania_revision_hash; +extern const uint8_t _citymania_revision_modified; bool IsReleasedVersion();