From 3823fc94f1b754ef6cb3fe0d423a5022bfe494ba Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 23 Dec 2023 10:23:40 -0800 Subject: [PATCH] add $si command --- .gitignore | 1 + CMakeLists.txt | 8 ++++++++ README.md | 1 + src/ChatCommands.cc | 16 ++++++++++++++++ src/Main.cc | 18 +++++++++++++++++- src/ProxyServer.cc | 4 ++++ src/ProxyServer.hh | 2 ++ src/ReceiveSubcommands.cc | 18 ++++++++++++------ src/Revision-generate.sh | 19 +++++++++++++++++++ src/Revision.hh | 6 ++++++ src/ServerState.cc | 3 ++- src/ServerState.hh | 1 + 12 files changed, 89 insertions(+), 8 deletions(-) create mode 100755 src/Revision-generate.sh create mode 100644 src/Revision.hh diff --git a/.gitignore b/.gitignore index 91cf872f..e0a3f866 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .DS_Store # Build products +src/Revision.cc newserv # CMake files diff --git a/CMakeLists.txt b/CMakeLists.txt index a6a80165..28461009 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,12 @@ find_package(resource_file QUIET) +# Git metadata + +add_custom_target(newserv-Revision-cc ALL COMMAND ./Revision-generate.sh WORKING_DIRECTORY src) + + + # Executable definition set(SOURCES @@ -100,6 +106,7 @@ set(SOURCES src/ReceiveCommands.cc src/ReceiveSubcommands.cc src/ReplaySession.cc + src/Revision.cc src/SaveFileFormats.cc src/SendCommands.cc src/Server.cc @@ -122,6 +129,7 @@ endif() add_executable(newserv ${SOURCES}) target_include_directories(newserv PUBLIC ${LIBEVENT_INCLUDE_DIR} ${Iconv_INCLUDE_DIRS}) target_link_libraries(newserv phosg ${LIBEVENT_LIBRARIES} ${Iconv_LIBRARIES} pthread) +add_dependencies(newserv newserv-Revision-cc) if(resource_file_FOUND) target_compile_definitions(newserv PUBLIC HAVE_RESOURCE_FILE) diff --git a/README.md b/README.md index 34647008..a1521712 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,7 @@ Some commands only work on the game server and not on the proxy server. The chat * Information commands * `$li`: Shows basic information about the lobby or game you're in. If you're on the proxy server, shows information about your connection instead (remote Guild Card number, client ID, etc.). + * `$si`: Shows basic information about the server. * `$ping`: Shows round-trip ping time from the server to you. On the proxy server, shows the ping time from you to the proxy and from the proxy to the server. * `$matcount` (game server only): Shows how many of each type of material you've used. * `$what` (game server only): Shows the type, name, and stats of the nearest item on the ground. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 1c2d1b3f..a1a137a1 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -14,6 +14,7 @@ #include "Loggers.hh" #include "ProxyServer.hh" #include "ReceiveCommands.hh" +#include "Revision.hh" #include "SendCommands.hh" #include "Server.hh" #include "StaticGameData.hh" @@ -91,6 +92,20 @@ static void check_is_leader(shared_ptr l, shared_ptr c) { //////////////////////////////////////////////////////////////////////////////// // Message commands +static void server_command_server_info(shared_ptr c, const std::string&) { + auto s = c->require_server_state(); + string uptime_str = format_duration(now() - s->creation_time); + string build_date = format_time(BUILD_TIMESTAMP); + send_text_message_printf(c, + "Revision: $C6%s$C7\n$C6%s$C7\nUptime: $C6%s$C7\nLobbies: $C6%zu$C7\nClients: $C6%zu$C7(g) $C6%zu$C7(p)", + GIT_REVISION_HASH, + build_date.c_str(), + uptime_str.c_str(), + s->id_to_lobby.size(), + s->channel_to_client.size(), + s->proxy_server->num_sessions()); +} + static void server_command_lobby_info(shared_ptr c, const std::string&) { vector lines; @@ -1906,6 +1921,7 @@ static const unordered_map chat_commands({ {"$saverec", {server_command_saverec, nullptr}}, {"$sc", {server_command_send_client, proxy_command_send_client}}, {"$secid", {server_command_secid, proxy_command_secid}}, + {"$si", {server_command_server_info, nullptr}}, {"$silence", {server_command_silence, nullptr}}, {"$song", {server_command_song, proxy_command_song}}, {"$spec", {server_command_toggle_spectator_flag, nullptr}}, diff --git a/src/Main.cc b/src/Main.cc index 7306a94a..415b0bd2 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -35,6 +35,7 @@ #include "Quest.hh" #include "QuestScript.hh" #include "ReplaySession.hh" +#include "Revision.hh" #include "SaveFileFormats.hh" #include "SendCommands.hh" #include "Server.hh" @@ -49,6 +50,7 @@ using namespace std; bool use_terminal_colors = false; +void print_version_info(); void print_usage(); template @@ -204,6 +206,14 @@ Action a_help( print_usage(); }); +Action a_version( + "version", "\ + version\n\ + Show newserv\'s revision and build date.\n", + +[](Arguments&) -> void { + print_version_info(); + }); + static void a_compress_decompress_fn(Arguments& args) { const auto& action = args.get(0); bool is_prs = ends_with(action, "-prs"); @@ -1890,8 +1900,14 @@ Action a_run_server_replay_log( state->proxy_server.reset(); // Break reference cycle }); +void print_version_info() { + string build_date = format_time(BUILD_TIMESTAMP); + fprintf(stderr, "newserv-%s built %s UTC\n", GIT_REVISION_HASH, build_date.c_str()); +} + void print_usage() { - fputs("\ + print_version_info(); + fputs("\n\ Usage:\n\ newserv [ACTION] [OPTIONS...]\n\ \n\ diff --git a/src/ProxyServer.cc b/src/ProxyServer.cc index 790a1e85..31090eca 100644 --- a/src/ProxyServer.cc +++ b/src/ProxyServer.cc @@ -910,6 +910,10 @@ void ProxyServer::destroy_sessions() { this->unlinked_sessions_to_destroy.clear(); } +size_t ProxyServer::num_sessions() const { + return this->id_to_session.size(); +} + size_t ProxyServer::delete_disconnected_sessions() { size_t count = 0; for (auto it = this->id_to_session.begin(); it != this->id_to_session.end();) { diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index b74e7e42..841ecec7 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -190,6 +190,8 @@ public: void delete_session(uint64_t id); void delete_session(struct bufferevent* bev); + size_t num_sessions() const; + size_t delete_disconnected_sessions(); private: diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index bbaafdaa..780b7ae9 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -2959,12 +2959,18 @@ static void on_quest_F960_result_bb(shared_ptr c, uint8_t, uint8_t, void G_SetMesetaSlotPrizeResult_BB_6xE3 cmd_6xE3 = {{0xE3, sizeof(G_SetMesetaSlotPrizeResult_BB_6xE3) >> 2, 0x0000}, item}; send_command_t(c, 0x60, 0x00, cmd_6xE3); - p->add_item(item); - send_create_inventory_item_to_lobby(c, c->lobby_client_id, item); - - if (c->log.should_log(LogLevel::INFO)) { - string name = s->item_name_index->describe_item(c->version(), item); - c->log.info("Awarded item %s", name.c_str()); + try { + p->add_item(item); + send_create_inventory_item_to_lobby(c, c->lobby_client_id, item); + if (c->log.should_log(LogLevel::INFO)) { + string name = s->item_name_index->describe_item(c->version(), item); + c->log.info("Awarded item %s", name.c_str()); + } + } catch (const out_of_range&) { + if (c->log.should_log(LogLevel::INFO)) { + string name = s->item_name_index->describe_item(c->version(), item); + c->log.info("Attempted to award item %s, but inventory was full", name.c_str()); + } } } } diff --git a/src/Revision-generate.sh b/src/Revision-generate.sh new file mode 100755 index 00000000..1181527b --- /dev/null +++ b/src/Revision-generate.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +GIT_REVISION_HASH=$(git rev-parse --short HEAD) +TIMESTAMP_SECS=$(date +%s) + +if [ -z "$GIT_REVISION_HASH" ]; then + GIT_REVISION_HASH="????" +else + if ! git diff-index --quiet HEAD -- ; then + GIT_REVISION_HASH="$GIT_REVISION_HASH+" + fi +fi + +cat > Revision.cc <($TIMESTAMP_SECS) * 1000000; +EOF diff --git a/src/Revision.hh b/src/Revision.hh new file mode 100644 index 00000000..c6430b9d --- /dev/null +++ b/src/Revision.hh @@ -0,0 +1,6 @@ +#pragma once + +#include + +extern const char* GIT_REVISION_HASH; +extern const uint64_t BUILD_TIMESTAMP; diff --git a/src/ServerState.cc b/src/ServerState.cc index 153617ee..3daa0f85 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -30,7 +30,8 @@ ServerState::QuestF960Result::QuestF960Result(const JSON& json, std::shared_ptr< } ServerState::ServerState(shared_ptr base, const string& config_filename, bool is_replay) - : base(base), + : creation_time(now()), + base(base), config_filename(config_filename), is_replay(is_replay), dns_server_port(0), diff --git a/src/ServerState.hh b/src/ServerState.hh index 02fce67b..1bafa468 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -59,6 +59,7 @@ struct ServerState : public std::enable_shared_from_this { return (b == BehaviorSwitch::OFF_BY_DEFAULT) || (b == BehaviorSwitch::ON_BY_DEFAULT); } + uint64_t creation_time; std::shared_ptr base; std::string config_filename;