From 89520f56653aac2732b40319b1f2630d8f330bdc Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 27 Jan 2024 12:35:09 +0100 Subject: [PATCH] Add: show in multiplayer the amount of hours a game has been unpaused (#11886) --- src/lang/english.txt | 6 ++-- src/network/core/config.h | 2 +- src/network/core/network_game_info.cpp | 30 +++++++++++++----- src/network/core/network_game_info.h | 12 ++++--- src/network/network_gui.cpp | 43 +++++++++++++++----------- 5 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 0772679215..be42f92e57 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2362,8 +2362,9 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Map size STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Map size of the game{}Click to sort by area STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Date STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Current date -STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Years -STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Number of years{}the game is running +STR_NETWORK_SERVER_LIST_PLAY_TIME_SHORT :{BLACK}{NUM}h {NUM}m +STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION :{BLACK}Play time +STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION_TOOLTIP :{BLACK}Time played while{}game was not paused STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Language, server version, etc. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Click a game from the list to select it @@ -2379,6 +2380,7 @@ STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Server STR_NETWORK_SERVER_LIST_INVITE_CODE :{SILVER}Invite code: {WHITE}{RAW_STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Start date: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Current date: {WHITE}{DATE_SHORT} +STR_NETWORK_SERVER_LIST_PLAY_TIME :{SILVER}Play time: {WHITE}{NUM}h {NUM}m STR_NETWORK_SERVER_LIST_GAMESCRIPT :{SILVER}Game Script: {WHITE}{RAW_STRING} (v{NUM}) STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Password protected! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER OFFLINE diff --git a/src/network/core/config.h b/src/network/core/config.h index cbe10ff589..6beaf9504f 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -46,7 +46,7 @@ static const uint16_t TCP_MTU = 32767; ///< Num static const uint16_t COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility static const byte NETWORK_GAME_ADMIN_VERSION = 3; ///< What version of the admin network do we use? -static const byte NETWORK_GAME_INFO_VERSION = 6; ///< What version of game-info do we use? +static const byte NETWORK_GAME_INFO_VERSION = 7; ///< What version of game-info do we use? static const byte NETWORK_COORDINATOR_VERSION = 6; ///< What version of game-coordinator-protocol do we use? static const byte NETWORK_SURVEY_VERSION = 1; ///< What version of the survey do we use? diff --git a/src/network/core/network_game_info.cpp b/src/network/core/network_game_info.cpp index ecf6569d86..5c7404040d 100644 --- a/src/network/core/network_game_info.cpp +++ b/src/network/core/network_game_info.cpp @@ -14,6 +14,7 @@ #include "../../core/bitmath_func.hpp" #include "../../company_base.h" #include "../../timer/timer_game_calendar.h" +#include "../../timer/timer_game_tick.h" #include "../../debug.h" #include "../../map_func.h" #include "../../game/game.hpp" @@ -123,7 +124,7 @@ void CheckGameCompatibility(NetworkGameInfo &ngi) void FillStaticNetworkServerGameInfo() { _network_game_info.use_password = !_settings_client.network.server_password.empty(); - _network_game_info.start_date = TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); + _network_game_info.calendar_start = TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); _network_game_info.clients_max = _settings_client.network.max_clients; _network_game_info.companies_max = _settings_client.network.max_companies; _network_game_info.map_width = Map::SizeX(); @@ -149,7 +150,8 @@ const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo() */ _network_game_info.companies_on = (byte)Company::GetNumItems(); _network_game_info.spectators_on = NetworkSpectatorCount(); - _network_game_info.game_date = TimerGameCalendar::date; + _network_game_info.calendar_date = TimerGameCalendar::date; + _network_game_info.ticks_playing = TimerGameTick::counter; return &_network_game_info; } @@ -194,6 +196,9 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool /* Update the documentation in game_info.h on changes * to the NetworkGameInfo wire-protocol! */ + /* NETWORK_GAME_INFO_VERSION = 7 */ + p->Send_uint64(info->ticks_playing); + /* NETWORK_GAME_INFO_VERSION = 6 */ p->Send_uint8(send_newgrf_names ? NST_GRFID_MD5_NAME : NST_GRFID_MD5); @@ -227,8 +232,8 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool } /* NETWORK_GAME_INFO_VERSION = 3 */ - p->Send_uint32(info->game_date.base()); - p->Send_uint32(info->start_date.base()); + p->Send_uint32(info->calendar_date.base()); + p->Send_uint32(info->calendar_start.base()); /* NETWORK_GAME_INFO_VERSION = 2 */ p->Send_uint8 (info->companies_max); @@ -267,6 +272,10 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo * to the NetworkGameInfo wire-protocol! */ switch (game_info_version) { + case 7: + info->ticks_playing = p->Recv_uint64(); + FALLTHROUGH; + case 6: newgrf_serialisation = (NewGRFSerializationType)p->Recv_uint8(); if (newgrf_serialisation >= NST_END) return; @@ -321,8 +330,8 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo } case 3: - info->game_date = Clamp(p->Recv_uint32(), 0, CalendarTime::MAX_DATE.base()); - info->start_date = Clamp(p->Recv_uint32(), 0, CalendarTime::MAX_DATE.base()); + info->calendar_date = Clamp(p->Recv_uint32(), 0, CalendarTime::MAX_DATE.base()); + info->calendar_start = Clamp(p->Recv_uint32(), 0, CalendarTime::MAX_DATE.base()); FALLTHROUGH; case 2: @@ -340,8 +349,8 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo info->clients_on = p->Recv_uint8 (); info->spectators_on = p->Recv_uint8 (); if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier - info->game_date = p->Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR; - info->start_date = p->Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR; + info->calendar_date = p->Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR; + info->calendar_start = p->Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR; } if (game_info_version < 6) while (p->Recv_uint8() != 0) {} // Used to contain the map-name. info->map_width = p->Recv_uint16(); @@ -351,6 +360,11 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo if (info->landscape >= NUM_LANDSCAPE) info->landscape = 0; } + + /* For older servers, estimate the ticks running based on the calendar date. */ + if (game_info_version < 7) { + info->ticks_playing = static_cast(std::max(0, info->calendar_date.base() - info->calendar_start.base())) * Ticks::DAY_TICKS; + } } /** diff --git a/src/network/core/network_game_info.h b/src/network/core/network_game_info.h index f91efce132..293a20f92a 100644 --- a/src/network/core/network_game_info.h +++ b/src/network/core/network_game_info.h @@ -16,6 +16,7 @@ #include "core.h" #include "../../newgrf_config.h" #include "../../timer/timer_game_calendar.h" +#include "../../timer/timer_game_tick.h" #include @@ -27,6 +28,8 @@ * Version: Bytes: Description: * all 1 the version of this packet's structure * + * 7+ 8 amount of ticks this game has been running unpaused. + * * 6+ 1 type of storage for the NewGRFs below: * 0 = NewGRF ID and MD5 checksum. * Used as default for version 5 and below, and for @@ -54,8 +57,8 @@ * - 4 byte lookup table index. * For v6+ in case of type 2. * - * 3+ 4 current game date in days since 1-1-0 (DMY) - * 3+ 4 game introduction date in days since 1-1-0 (DMY) + * 3+ 4 current calendar date in days since 1-1-0 (DMY) + * 3+ 4 calendar start date in days since 1-1-0 (DMY) * * 2+ 1 maximum number of companies allowed on the server * 2+ 1 number of companies on the server @@ -92,8 +95,9 @@ enum NewGRFSerializationType { */ struct NetworkServerGameInfo { GRFConfig *grfconfig; ///< List of NewGRF files used - TimerGameCalendar::Date start_date; ///< When the game started - TimerGameCalendar::Date game_date; ///< Current date + TimerGameCalendar::Date calendar_start; ///< When the game started. + TimerGameCalendar::Date calendar_date; ///< Current calendar date. + TimerGameTick::TickCounter ticks_playing; ///< Amount of ticks the game has been running unpaused. uint16_t map_width; ///< Map width uint16_t map_height; ///< Map height std::string server_name; ///< Server name diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 8e92835663..8d4d579b3e 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -97,7 +97,7 @@ public: this->Add(std::make_unique(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP)); this->Add(std::make_unique(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP)); this->Add(std::make_unique(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP)); - this->Add(std::make_unique(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP)); + this->Add(std::make_unique(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION, STR_NETWORK_SERVER_LIST_PLAY_TIME_CAPTION_TOOLTIP)); leaf = std::make_unique(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP); leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK, nullptr, ZOOM_LVL_OUT_4X).width @@ -283,18 +283,20 @@ protected: return (r != 0) ? r < 0 : NGameClientSorter(a, b); } - /** Sort servers by current date */ - static bool NGameDateSorter(NetworkGameList * const &a, NetworkGameList * const &b) + /** Sort servers by calendar date. */ + static bool NGameCalendarDateSorter(NetworkGameList * const &a, NetworkGameList * const &b) { - auto r = a->info.game_date - b->info.game_date; + auto r = a->info.calendar_date - b->info.calendar_date; return (r != 0) ? r < 0 : NGameClientSorter(a, b); } - /** Sort servers by the number of days the game is running */ - static bool NGameYearsSorter(NetworkGameList * const &a, NetworkGameList * const &b) + /** Sort servers by the number of ticks the game is running. */ + static bool NGameTicksPlayingSorter(NetworkGameList * const &a, NetworkGameList * const &b) { - auto r = a->info.game_date - a->info.start_date - b->info.game_date + b->info.start_date; - return (r != 0) ? r < 0: NGameDateSorter(a, b); + if (a->info.ticks_playing == b->info.ticks_playing) { + return NGameClientSorter(a, b); + } + return a->info.ticks_playing < b->info.ticks_playing; } /** @@ -392,18 +394,18 @@ protected: if (const NWidgetBase *nwid = this->GetWidget(WID_NG_DATE); nwid->current_x != 0) { /* current date */ Rect date = nwid->GetCurrentRect(); - TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.game_date); + TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.calendar_date); SetDParam(0, ymd.year); DrawString(date.left, date.right, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER); } if (const NWidgetBase *nwid = this->GetWidget(WID_NG_YEARS); nwid->current_x != 0) { - /* number of years the game is running */ + /* play time */ Rect years = nwid->GetCurrentRect(); - TimerGameCalendar::YearMonthDay ymd_cur = TimerGameCalendar::ConvertDateToYMD(cur_item->info.game_date); - TimerGameCalendar::YearMonthDay ymd_start = TimerGameCalendar::ConvertDateToYMD(cur_item->info.start_date); - SetDParam(0, ymd_cur.year - ymd_start.year); - DrawString(years.left, years.right, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER); + const auto play_time = cur_item->info.ticks_playing / Ticks::TICKS_PER_SECOND; + SetDParam(0, play_time / 60 / 60); + SetDParam(1, (play_time / 60) % 60); + DrawString(years.left, years.right, y + text_y_offset, STR_NETWORK_SERVER_LIST_PLAY_TIME_SHORT, TC_BLACK, SA_HOR_CENTER); } /* draw a lock if the server is password protected */ @@ -652,12 +654,17 @@ public: StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS; tr.top = DrawStringMultiLine(tr, invite_or_address); // server address / invite code - SetDParam(0, sel->info.start_date); + SetDParam(0, sel->info.calendar_start); tr.top = DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_START_DATE); // start date - SetDParam(0, sel->info.game_date); + SetDParam(0, sel->info.calendar_date); tr.top = DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_CURRENT_DATE); // current date + const auto play_time = sel->info.ticks_playing / Ticks::TICKS_PER_SECOND; + SetDParam(0, play_time / 60 / 60); + SetDParam(1, (play_time / 60) % 60); + tr.top = DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_PLAY_TIME); // play time + if (sel->info.gamescript_version != -1) { SetDParamStr(0, sel->info.gamescript_name); SetDParam(1, sel->info.gamescript_version); @@ -857,8 +864,8 @@ GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = { &NGameNameSorter, &NGameClientSorter, &NGameMapSizeSorter, - &NGameDateSorter, - &NGameYearsSorter, + &NGameCalendarDateSorter, + &NGameTicksPlayingSorter, &NGameAllowedSorter };