diff --git a/README.md b/README.md index 20966895..9be38426 100644 --- a/README.md +++ b/README.md @@ -484,7 +484,8 @@ Some commands only work on the game server and not on the proxy server. The chat * `$song ` (Episode 3 only): Plays a specific song in the current lobby. * Administration commands (game server only) - * `$ann `: Sends an announcement message. The message text is sent to all players in all games and lobbies. + * `$ann `: Sends an announcement message. The message is sent as temporary on-screen text to all players in all games and lobbies. + * `$ann! `: Sends an announcement message. The message is sent as a Simple Mail message to all players in all games and lobbies. * `$ax `: Sends a message to the server's terminal. This cannot be used to run server shell commands; it only prints text to stderr. * `$silence `: Silences a player (remove their ability to chat) or unsilences a player. The identifier may be the player's name or Guild Card number. * `$kick `: Disconnects a player. The identifier may be the player's name or Guild Card number. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index a1ece250..e6ae370a 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -265,6 +265,12 @@ static void server_command_announce(shared_ptr c, const std::string& arg send_text_message(s, args); } +static void server_command_announce_mail(shared_ptr c, const std::string& args) { + auto s = c->require_server_state(); + check_license_flag(c, License::Flag::ANNOUNCE); + send_simple_mail(s, 0, s->name, args); +} + static void server_command_arrow(shared_ptr c, const std::string& args) { auto l = c->require_lobby(); c->lobby_arrow_color = stoull(args, nullptr, 0); @@ -2141,6 +2147,7 @@ struct ChatCommandDefinition { static const unordered_map chat_commands({ {"$allevent", {server_command_lobby_event_all, nullptr}}, {"$ann", {server_command_announce, nullptr}}, + {"$ann!", {server_command_announce_mail, nullptr}}, {"$arrow", {server_command_arrow, proxy_command_arrow}}, {"$auction", {server_command_auction, proxy_command_auction}}, {"$ax", {server_command_ax, nullptr}}, diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 4c90586e..c66f7e9c 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -18,6 +18,7 @@ #include "Compression.hh" #include "FileContentsCache.hh" #include "PSOProtocol.hh" +#include "ProxyServer.hh" #include "StaticGameData.hh" #include "Text.hh" @@ -806,10 +807,10 @@ void send_text_message(shared_ptr l, const string& text) { } void send_text_message(shared_ptr s, const string& text) { - // TODO: We should have a collection of all clients (even those not in any - // lobby) and use that instead here - for (auto& l : s->all_lobbies()) { - send_text_message(l, text); + for (auto& it : s->channel_to_client) { + if (it.second->license && !is_patch(it.second->version())) { + send_text_message(it.second, text); + } } } @@ -917,7 +918,7 @@ void send_chat_message( template void send_simple_mail_t(shared_ptr c, uint32_t from_guild_card_number, const string& from_name, const string& text) { CmdT cmd; - cmd.player_tag = 0x00010000; + cmd.player_tag = from_guild_card_number ? 0x00010000 : 0; cmd.from_guild_card_number = from_guild_card_number; cmd.from_name.encode(from_name, c->language()); cmd.to_guild_card_number = c->license->serial_number; @@ -927,7 +928,7 @@ void send_simple_mail_t(shared_ptr c, uint32_t from_guild_card_number, c void send_simple_mail_bb(shared_ptr c, uint32_t from_guild_card_number, const string& from_name, const string& text) { SC_SimpleMail_BB_81 cmd; - cmd.player_tag = 0x00010000; + cmd.player_tag = from_guild_card_number ? 0x00010000 : 0; cmd.from_guild_card_number = from_guild_card_number; cmd.from_name.encode(from_name, c->language()); cmd.to_guild_card_number = c->license->serial_number; @@ -961,6 +962,14 @@ void send_simple_mail(shared_ptr c, uint32_t from_guild_card_number, con } } +void send_simple_mail(shared_ptr s, uint32_t from_guild_card_number, const string& from_name, const string& text) { + for (const auto& it : s->channel_to_client) { + if (it.second->license && !is_patch(it.second->version())) { + send_simple_mail(it.second, from_guild_card_number, from_name, text); + } + } +} + //////////////////////////////////////////////////////////////////////////////// // info board diff --git a/src/SendCommands.hh b/src/SendCommands.hh index 904e4bd4..8d8d51d0 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -218,7 +218,12 @@ void send_chat_message( char private_flags); void send_simple_mail( std::shared_ptr c, - uint32_t from_serial_number, + uint32_t from_guild_card_number, + const std::string& from_name, + const std::string& text); +void send_simple_mail( + std::shared_ptr s, + uint32_t from_guild_card_number, const std::string& from_name, const std::string& text); diff --git a/src/ServerShell.cc b/src/ServerShell.cc index fa528ea4..d63ee923 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -458,6 +458,13 @@ CommandDefinition c_announce( +[](CommandArgs& args) { send_text_message(args.s, args.args); }); +CommandDefinition c_announce_mail( + "announce-mail", "announce-mail MESSAGE\n\ + Send an announcement message via Simple Mail to all players.", + true, + +[](CommandArgs& args) { + send_simple_mail(args.s, 0, args.s->name, args.args); + }); CommandDefinition c_create_tournament( "create-tournament", "create-tournament TOURNAMENT-NAME MAP-NAME NUM-TEAMS [OPTIONS...]\n\