diff --git a/game/Player.cpp b/game/Player.cpp index 7d1dc89..e337bd2 100644 --- a/game/Player.cpp +++ b/game/Player.cpp @@ -260,9 +260,15 @@ void PlayerMgr::SetAllies(Player **applr, int cplrs, SideMask sidmAllies) { // Set allies - for (int n = 0; n < cplrs; n++) + for (int n = 0; n < cplrs; n++) { applr[n]->SetAllies(sidmAllies); + // Send this to the server so it can use it for ally chat + if (gptra != NULL) { + gptra->UpdateAllies(applr[n]->GetSide(), sidmAllies); + } + } + // Recalc enemies. Clear first Gob *pgobT; diff --git a/game/ht.h b/game/ht.h index ee7fbc4..8d29502 100644 --- a/game/ht.h +++ b/game/ht.h @@ -421,6 +421,8 @@ public: virtual bool SendNetMessage(NetMessage *pnm) = 0; virtual void LeaveGame() = 0; virtual void OnEvent(Event *pevt) = 0; + virtual void UpdateAllies(Side side, SideMask sidmAllies) = 0; + virtual void DisconnectSharedAccounts() = 0; virtual ITransportCallback *SetCallback(ITransportCallback *ptcb); virtual ITransportCallback *GetCallback(); virtual IGameCallback *SetGameCallback(IGameCallback *pgcb); diff --git a/game/loginform.cpp b/game/loginform.cpp index adcfe41..e5346d8 100644 --- a/game/loginform.cpp +++ b/game/loginform.cpp @@ -214,6 +214,22 @@ bool LoginForm::AttemptLogin() { "This server does not allow anonymous logins. Please login with an account."); return false; + case knLoginResultAccountInUse: + { + bool fYes = false; + fYes = HtMessageBox(kidfMessageBoxQuery, kfMbKeepTimersEnabled | kfMbWhiteBorder, + "Login Failure", "Your account is already logged in to this server with another device. Would you like to disconnect that device and then login?"); + + // Does the user want to disconnect logged in devices? + if (fYes && gptra != NULL) { + gptra->DisconnectSharedAccounts(); + + // Try to login again + return AttemptLogin(); + } + return false; + } + case knLoginResultFail: default: if (!handler_.anonymous()) { diff --git a/game/xtransport.cpp b/game/xtransport.cpp index 3575d37..804693a 100644 --- a/game/xtransport.cpp +++ b/game/xtransport.cpp @@ -4,6 +4,7 @@ #include "game/serviceurls.h" #include "game/chooseserverform.h" #include "mpshared/xpump.h" +#include "mpshared/mpht.h" namespace wi { @@ -943,4 +944,20 @@ void XTransport::OnWriteEvent(base::Socket *socket) { void XTransport::OnCloseEvent(base::Socket *socket) { } +void XTransport::UpdateAllies(Side side, SideMask sidmAllies) { + if (error_ || xpump_.IsClosed()) { + return; + } + if (state_ == XTS_ROOM) { + return; + } + if (state_ == XTS_GAME) { + xpump_.Send(XMsgGameUpdateAllies::ToBuffer(dword(side), dword(sidmAllies))); + return; + } +} + +void XTransport::DisconnectSharedAccounts() { + xpump_.Send(XMsgDisconnectSharedAccounts::ToBuffer()); +} } // namespace wi diff --git a/game/xtransport.h b/game/xtransport.h index fc8144f..c6b378f 100644 --- a/game/xtransport.h +++ b/game/xtransport.h @@ -40,6 +40,8 @@ public: dword *gameid); virtual dword CanJoinGame(dword gameid); virtual void LeaveRoom(dword hint); + virtual void UpdateAllies(Side side, SideMask sidmAllies); + virtual void DisconnectSharedAccounts(); virtual dword JoinGame(dword gameid, dword roomid); virtual bool SendNetMessage(NetMessage *pnm); diff --git a/mpshared/constants.h b/mpshared/constants.h index 794d8d4..6d23e1b 100644 --- a/mpshared/constants.h +++ b/mpshared/constants.h @@ -57,6 +57,8 @@ const byte XMSG_GAMEUPDATERESULT = 0xd6; const byte XMSG_GAMEKILLED = 0xd7; const byte XMSG_GAMELEAVE = 0xd8; const byte XMSG_GAMELEAVERESULT = 0xd9; +const byte XMSG_GAMEUPDATEALLIES = 0xda; +const byte XMSG_DISCONNECTSHAREDACCOUNTS = 0xe0; STARTLABEL(XMsgLabels) LABEL(XMSG_NONE) @@ -108,6 +110,8 @@ STARTLABEL(XMsgLabels) LABEL(XMSG_GAMEKILLED) LABEL(XMSG_GAMELEAVE) LABEL(XMSG_GAMELEAVERESULT) + LABEL(XMSG_GAMEUPDATEALLIES) + LABEL(XMSG_DISCONNECTSHAREDACCOUNTS) ENDLABEL(XMsgLabels) } // namespace wi diff --git a/mpshared/messages.h b/mpshared/messages.h index f5bdedf..6991f2c 100644 --- a/mpshared/messages.h +++ b/mpshared/messages.h @@ -79,6 +79,7 @@ const dword knLoginResultStaleToken = 3; const dword knLoginResultAuthDown = 4; const dword knLoginResultNoPassword = 5; const dword knLoginResultNoAnons = 6; +const dword knLoginResultAccountInUse = 7; STARTLABEL(LoginResults) LABEL(knLoginResultSuccess) @@ -88,6 +89,7 @@ STARTLABEL(LoginResults) LABEL(knLoginResultAuthDown) LABEL(knLoginResultNoPassword) LABEL(knLoginResultNoAnons) + LABEL(knLoginResultAccountInUse) ENDLABEL(LoginResults) const dword knSignOutResultSuccess = 0; @@ -181,6 +183,8 @@ typedef XMsgS2 XMsgGameReceiveC typedef XMsg1 XMsgGameKilled; typedef XMsg0 XMsgGameLeave; typedef XMsg1 XMsgGameLeaveResult; +typedef XMsg2 XMsgGameUpdateAllies; +typedef XMsg0 XMsgDisconnectSharedAccounts; struct XMsgShowMessage : public XMsg { XMsgShowMessage(const char *message, dword ipRedirect, bool disconnect) : diff --git a/mpshared/xpump.cpp b/mpshared/xpump.cpp index 349aa8f..b705a14 100644 --- a/mpshared/xpump.cpp +++ b/mpshared/xpump.cpp @@ -323,6 +323,12 @@ XMsg *XPump::XMsgFromBuffer(base::ByteBuffer& bb, dword cb) { case XMSG_GAMELEAVERESULT: return XMsgGameLeaveResult::FromBuffer(bb, cb); + case XMSG_GAMEUPDATEALLIES: + return XMsgGameUpdateAllies::FromBuffer(bb, cb); + + case XMSG_DISCONNECTSHAREDACCOUNTS: + return XMsgDisconnectSharedAccounts::FromBuffer(bb, cb); + default: return NULL; } @@ -681,6 +687,20 @@ void XPump::DispatchXMsg(XMsg *pmsg) { } break; + case XMSG_GAMEUPDATEALLIES: + { + XMsgGameUpdateAllies *pmsgT = (XMsgGameUpdateAllies *)pmsg; + // side, allies + notify_->OnUpdateAllies(pmsgT->dw0_, pmsgT->dw1_); + } + break; + + case XMSG_DISCONNECTSHAREDACCOUNTS: + { + notify_->OnDisconnectSharedAccounts(); + } + break; + default: notify_->OnError(-1); Assert(false); diff --git a/mpshared/xpump.h b/mpshared/xpump.h index 77b6c3f..7aee4be 100644 --- a/mpshared/xpump.h +++ b/mpshared/xpump.h @@ -69,10 +69,12 @@ public: virtual void OnGameSendChat(const char *chat) { Assert(); } virtual void OnGameReceiveChat(const char *player, const char *chat) { Assert(); } + virtual void OnUpdateAllies(dword side, dword sidmAllies) { Assert(); } virtual void OnGameNetMessage(NetMessage **ppnm) { Assert(); } virtual void OnGameKilled(dword gameid) { Assert(); } virtual void OnGameLeave() { Assert(); } virtual void OnGameLeaveResult(dword result) { Assert(); } + virtual void OnDisconnectSharedAccounts() { Assert(); } virtual bool OnMessages() { return false; } virtual void OnCloseOk() { return; } virtual void OnError(int error) { Assert(); } diff --git a/server/endpoint.cpp b/server/endpoint.cpp index b65e745..6a2384e 100644 --- a/server/endpoint.cpp +++ b/server/endpoint.cpp @@ -23,7 +23,7 @@ Endpoint::Endpoint(Server& server, base::Socket *socket, dword id, protocolid_(0), state_(ES_HANDSHAKE), game_(NULL), echo_(true), roomid_(0), name_(NULL), anonymous_(true), missed_(0), okecho_(false), admin_(false), muted_(false), sigvisible_(false), seechat_(false), - roomlimiter_(2, 120) { + roomlimiter_(2, 120), teamchat_(false) { did_[0] = 0; xpump_.Attach(socket, this, server.log()); } @@ -156,10 +156,20 @@ void Endpoint::OnLogin(const char *username, const char *token, const char *did) return; } - // Success. Take in the new name, transition to ES_READY + // Endpoint has been authed, so take in the new name RememberName(name_); delete name_; name_ = AllocString(base::Format::ToString(username, id_)); + + // Moderators are allowed to login with multiple devices + if (!server_.AccountSharing() && !IsModerator()) { + if (server_.SharedAccountExists(this, username)) { + xpump_.Send(XMsgLoginResult::ToBuffer(knLoginResultAccountInUse)); + return; + } + } + + // Success. Transition to ES_READY xpump_.Send(XMsgLoginResult::ToBuffer(knLoginResultSuccess)); anonymous_ = false; SetState(ES_READY); @@ -556,6 +566,9 @@ void Endpoint::OnGameJoin(dword gameid, dword roomid) { game_->SignalOnDelete.connect(this, &Endpoint::OnGameDelete); game->AddPlayer(this); + // Team chat should be turned off by default + teamchat_ = false; + SetState(ES_GAME); } @@ -712,6 +725,9 @@ ModeratorCommand Endpoint::GetModeratorCommand(const char *chat) { if (strcmp(arg.c_str(), "/ann") == 0) { return kModeratorCommandAnnouncements; } + if (strcmp(arg.c_str(), "/t") == 0) { + return kModeratorCommandTeam; + } return kModeratorCommandUnknown; } @@ -750,6 +766,51 @@ bool Endpoint::ProcessCommand(const char *chat, std::string *response) { // This will get processed by the game. return false; + case kModeratorCommandTeam: + { + // Player not in game + if (state_ != ES_GAME || game_ == NULL) { + *response = "Command not available."; + return true; + } + + if (!game_->CanSendTeamChat(this, true)) { + teamchat_ = false; + return false; + } + + std::string dummy; + std::string msg; + const char *rest; + GetArgument(chat, 0, &dummy, &rest); + msg = rest; + + if (msg.empty()) { + // Toggle team chat + teamchat_ = !teamchat_; + if (teamchat_) { + this->xpump().Send(XMsgGameReceiveChat::ToBuffer("", + "Team chat has been toggled ON.")); + } else { + this->xpump().Send(XMsgGameReceiveChat::ToBuffer("", + "Team chat has been toggled OFF.")); + } + } else { + if (!teamchat_) { + // Turn on team chat so OnGameSendChat() will process + // it as a team chat then turn it back off. + teamchat_ = true; + this->OnGameSendChat(msg.c_str()); + teamchat_ = false; + } else { + this->OnGameSendChat(msg.c_str()); + } + } + + *response = ""; + return true; + } + case kModeratorCommandFlag: // Write an entry into the log { @@ -779,17 +840,17 @@ bool Endpoint::ProcessCommand(const char *chat, std::string *response) { bool swap = game_->IsSwapAllowed(this); if (anon) { if (swap) { - *response = "/mute, /unmute, /anon, /swap, /kick, /flag [msg], /help."; + *response = "/mute, /unmute, /anon, /swap, /kick, /flag [msg], /t [msg], /help."; } else { - *response = "/mute, /unmute, /anon, /kick, /flag [msg], /help."; + *response = "/mute, /unmute, /anon, /kick, /flag [msg], /t [msg], /help."; } } else if (swap) { - *response = "/mute, /unmute, /swap, /kick, /flag [msg], /help."; + *response = "/mute, /unmute, /swap, /kick, /flag [msg], /t [msg], /help."; } else { - *response = "/mute, /unmute, /kick, /flag [msg], /help."; + *response = "/mute, /unmute, /kick, /flag [msg], /t [msg], /help."; } } else { - *response = "/mute, /unmute, /kick, /flag [msg], /help."; + *response = "/mute, /unmute, /kick, /flag [msg], /t [msg], /help."; } break; @@ -1358,13 +1419,13 @@ bool Endpoint::ProcessCommand(const char *chat, std::string *response) { case kModeratorCommandHelp: if (IsAdmin()) { if (state_ == ES_GAME) { - *response = "/ids [all] [lobby] [roomid] [gameid], /mute [minutes], /unmute , /ban [minutes], /rooms, /kill , /games , /names , /w , /m, /title , /clear, /filter, /sig, /see, /perm , /reg [server] [roomid], /swap, /anon, /rules, /flag [msg], /ann [msg], /help."; + *response = "/ids [all] [lobby] [roomid] [gameid], /mute [minutes], /unmute , /ban [minutes], /rooms, /kill , /games , /names , /w , /m, /title , /clear, /filter, /sig, /see, /perm , /reg [server] [roomid], /swap, /anon, /rules, /flag [msg], /ann [msg], /t [msg], /help."; } else { *response = "/ids [all] [lobby] [roomid] [gameid], /mute [minutes], /unmute , /kick [minutes], /ban [minutes], /rooms, /kill , /games , /names , /w , /m, /title , /clear, /filter, /sig, /see, /perm , /reg [server] [roomid], /rules, /flag [msg], /ann [msg], /help."; } } else { if (state_ == ES_GAME) { - *response = "/ids [all] [lobby] [roomid] [gameid], /mute [minutes], /unmute , /rooms, /games , /w , /m, /title , /sig, /see, /swap, /anon, /rules, /flag [msg], /help."; + *response = "/ids [all] [lobby] [roomid] [gameid], /mute [minutes], /unmute , /rooms, /games , /w , /m, /title , /sig, /see, /swap, /anon, /rules, /flag [msg], /t [msg], /help."; } else { *response = "/ids [all] [lobby] [roomid] [gameid], /mute [minutes], /unmute , /kick [minutes], /rooms, /games , /w , /m, /title , /sig, /see, /rules, /flag [msg], /help."; } @@ -1416,14 +1477,26 @@ void Endpoint::OnGameSendChat(const char *chat) { Room *room = server_.lobby().FindRoom(roomid_); if (room != NULL && !room->moderated()) { // Unmoderated rooms aren't filtered - game_->SendChat(this, chat, NULL); + if (teamchat_) { + game_->SendTeamChat(this, chat, NULL); + } else { + game_->SendChat(this, chat, NULL); + } } else { // Moderated rooms are filtered const char *filtered; if (FilterChat(chat, &filtered)) { - game_->SendChat(this, filtered, chat); + if (teamchat_) { + game_->SendTeamChat(this, filtered, chat); + } else { + game_->SendChat(this, filtered, chat); + } } else { - game_->SendChat(this, filtered, NULL); + if (teamchat_) { + game_->SendTeamChat(this, filtered, NULL); + } else { + game_->SendChat(this, filtered, NULL); + } } } } @@ -1455,6 +1528,8 @@ void Endpoint::OnGameLeave() { game_->RemovePlayer(this, knDisconnectReasonLeftGame); game_ = NULL; + teamchat_ = false; + // Stop logging with the game id xpump_.SetLogId(0); @@ -1518,6 +1593,12 @@ void Endpoint::OnCloseOk() { Dispose(); } +void Endpoint::OnUpdateAllies(dword side, dword sidmAllies) { + if (state_ == ES_GAME && game_ != NULL) { + game_->SetAllies((SideMask)side, (SideMask)sidmAllies); + } +} + void Endpoint::OnHeartbeat() { // If a game is playing, there is a game timer to monitor clients if (game_ != NULL && game_->playing()) { @@ -1630,4 +1711,8 @@ dword Endpoint::gameid() { return game_ == NULL ? 0 : game_->id(); } +void Endpoint::OnDisconnectSharedAccounts() { + server_.DisconnectSharedAccounts(this, name_); +} + } // namespace wi diff --git a/server/endpoint.h b/server/endpoint.h index 410d361..f6a0ad4 100644 --- a/server/endpoint.h +++ b/server/endpoint.h @@ -8,6 +8,7 @@ #include "base/messagequeue.h" #include "inc/basictypes.h" #include "mpshared/xpump.h" +#include "mpshared/mpht.h" #include "server/levelinfo.h" #include "server/lobby.h" #include "server/tokenbucket.h" @@ -31,7 +32,7 @@ enum ModeratorCommand { kModeratorCommandMods, kModeratorCommandWhisper, kModeratorCommandTitle, kModeratorCommandRegisteredOnly, kModeratorCommandAnonBlock, kModeratorCommandSwap, kModeratorCommandFlag, kModeratorCommandHelp, - kModeratorCommandAnnouncements + kModeratorCommandAnnouncements, kModeratorCommandTeam }; class Endpoint : public base::MessageHandler, XPumpNotify, @@ -105,6 +106,8 @@ private: virtual void OnError(int error); virtual void OnClose(int error); virtual void OnCloseOk(); + virtual void OnUpdateAllies(dword side, dword sidmAllies); + virtual void OnDisconnectSharedAccounts(); XPump xpump_; State state_; @@ -126,6 +129,7 @@ private: bool muted_; bool sigvisible_; bool seechat_; + bool teamchat_; std::vector old_names_; std::string chat_fragment_; TokenBucket roomlimiter_; diff --git a/server/game.cpp b/server/game.cpp index f2ce8e2..a516d4b 100644 --- a/server/game.cpp +++ b/server/game.cpp @@ -945,6 +945,17 @@ const char *Game::ColorFromSide(int side) { return s_colors[side]; } +const char *Game::ColorCharFromSide(int side) { + // 0: gray, 1: blue, 2: red, 3: yellow, 4: cyan + static const char *s_colors[] = { + "g", "b", "r", "y", "c" + }; + if (side < 0 || side >= ARRAYSIZE(s_colors)) { + return "unknown"; + } + return s_colors[side]; +} + bool Game::IsSwapAllowed(Endpoint *endpoint) { if (playing_) { return false; @@ -1171,4 +1182,145 @@ bool Game::IsAnonBlockAllowed(Endpoint *endpoint) { return true; } +void Game::SetAllies(SideMask side, SideMask sidmAllies) { + Player *player = HumanPlayerFromColorChar(ColorCharFromSide(side)); + if (player != NULL) + player->SetAllies(sidmAllies); +} + +Player *Game::HumanPlayerFromEndpoint(Endpoint *endpoint) { + Player *pplr; + for (int i = 0; i < kcPlayersMax; i++) { + pplr = playerMgr_.GetPlayer(i); + if (pplr->endpoint() == endpoint) { + break; + } else { + pplr = NULL; + } + } + + if (pplr == NULL) { + return NULL; + } + if (pplr->endpoint() == NULL) { + return NULL; + } + if (pplr->flags() & (kfPlrComputer | kfPlrComputerOvermind | + kfPlrUnfulfilled | kfPlrObserver | kfPlrDisconnectBroadcasted)) { + return NULL; + } + if ((pplr->flags() & kfPlrInUse) == 0) { + return NULL; + } + + return pplr; +} + +void Game::SendTeamChat(Endpoint *endpoint, const char *chat, const char *unfiltered) { + if (endpoint == NULL) { + return; + } + if (!CanSendTeamChat(endpoint, true)) { + return; + } + + // This won't include observing players + Player *pendplr = HumanPlayerFromEndpoint(endpoint); + if (pendplr == NULL) { + return; + } + + // Player name + const char *name = base::Format::ToString("%s to team", endpoint->GetChatName().c_str()); + + // Players + Player *playerBlue, *playerRed, *playerYellow, *playerCyan; + std::vector players; + players.push_back(playerBlue); + players.push_back(playerRed); + players.push_back(playerYellow); + players.push_back(playerCyan); + + // The endpoint sending the chat sees it regardless of the value in pendplr->allies() + endpoint->xpump().Send(XMsgGameReceiveChat::ToBuffer(name, chat)); + + // If this endpoint is a mod, send unfiltered chat too + if (unfiltered != NULL && endpoint->seechat()) { + endpoint->xpump().Send(XMsgGameReceiveChat::ToBuffer("", unfiltered)); + } + + SideMask sides[kcPlayersMax] = {ksideNeutral, ksidmSide1, ksidmSide2, ksidmSide3, ksidmSide4}; + + // Loop through the four human sides + for (int i = 1; i < kcPlayersMax; i++) { + + // Is this an ally? + if (pendplr->allies() & sides[i]) { + + // Skip if this ally is the sending player + if (pendplr->side() == i) + continue; + + // This won't include observing players + players[i] = HumanPlayerFromColorChar(ColorCharFromSide(i)); + if (players[i] == NULL) + continue; + + // Is this ally muted? + if (players[i]->endpoint()->muted()) + continue; + + // Send the message to the ally + players[i]->endpoint()->xpump().Send( + XMsgGameReceiveChat::ToBuffer(name, chat)); + + // Send the unfiltered version if the ally is a mod + if (unfiltered != NULL && players[i]->endpoint()->seechat()) { + players[i]->endpoint()->xpump().Send( + XMsgGameReceiveChat::ToBuffer("", unfiltered)); + } + + // Log the chat + Room *room = server_.lobby().FindRoom(roomid_); + const char *pszRoomName = NULL; + bool private_room = false; + if (room != NULL) { + pszRoomName = room->name(); + private_room = (room->password()[0] != 0); + } + if (unfiltered != NULL) { + server_.logger().LogGameChat(endpoint, roomid_, pszRoomName, + private_room, id(), info().title(), unfiltered); + } else { + server_.logger().LogGameChat(endpoint, roomid_, pszRoomName, + private_room, id(), info().title(), chat); + } + } + } +} + +bool Game::CanSendTeamChat(Endpoint *endpoint, bool broadcast) { + // Game not started yet + if (!playing()) { + if (broadcast) { + endpoint->xpump().Send(XMsgGameReceiveChat::ToBuffer("", + "You cannot use team chat until the game starts.")); + } + return false; + } + + Player *pplr = HumanPlayerFromEndpoint(endpoint); + if (pplr == NULL) { + + // If pplr is NULL, assume it's because the player is observing + if (broadcast) { + endpoint->xpump().Send(XMsgGameReceiveChat::ToBuffer("", + "You cannot use team chat while in observe mode.")); + } + return false; + } + + return true; +} + } // namespace wi diff --git a/server/game.h b/server/game.h index 7b7e88e..d85146c 100644 --- a/server/game.h +++ b/server/game.h @@ -54,6 +54,8 @@ public: void RemovePlayer(Endpoint *endpoint, int nReason, bool disconnect = true); void SendChat(Endpoint *endpoint, const char *chat, const char *unfiltered = NULL); + void SendTeamChat(Endpoint *endpoint, const char *chat, + const char *unfiltered = NULL); void SendAdminChat(const char *name, const char *chat, bool mods_only = false); void OnNetMessage(Endpoint *endpoint, NetMessage *pnm); @@ -63,6 +65,8 @@ public: void OnHeartbeat(); std::vector GetIdsString(Endpoint *endpoint); void KickPlayers(); + void SetAllies(SideMask side, SideMask sidmAllies); + bool CanSendTeamChat(Endpoint *endpoint, bool broadcast); base::signal1 SignalOnDelete; base::signal1 SignalOnInProgress; @@ -96,6 +100,8 @@ private: std::string *response, bool *broadcast); const char *ColorFromSide(int side); Player *HumanPlayerFromColorChar(const char *psz); + Player *HumanPlayerFromEndpoint(Endpoint *endpoint); + const char *ColorCharFromSide(int side); void SwapPlayersCommand(Endpoint *endpoint, const char *chat, std::string *response); diff --git a/server/main.cpp b/server/main.cpp index a19852a..2b21475 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -163,6 +163,9 @@ int main(int argc, char **argv) bool checksync = FindArg(argc, argv, "--checksync"); RLOG() << "Sync checking turned " << (checksync ? "ON." : "OFF."); + bool accountsharing = FindArg(argc, argv, "--accountsharing"); + RLOG() << "Account sharing turned " << (accountsharing ? "ON." : "OFF."); + std::string log_file = ParseString(argc, argv, "--log_file"); wi::XMsgLog *xmsglog = NULL; if (log_file.size() != 0) { @@ -179,7 +182,7 @@ int main(int argc, char **argv) wi::Server server(stats, xmsglog, cache, server_id, checksync, max_rooms, max_games_per_room, max_players_per_room, - max_players, modfile, badwordsfile); + max_players, modfile, badwordsfile, accountsharing); base::SocketAddress listen_address = GetListenAddress(argc, argv); if (!server.Listen(listen_address)) { diff --git a/server/player.h b/server/player.h index 34ae8a5..62cdd4f 100644 --- a/server/player.h +++ b/server/player.h @@ -59,6 +59,8 @@ public: bool statslocked() { return havestats_ && (ws_.ff & kfwsLocked) != 0; } const base::SocketAddress& address() { return address_; } const char *did() { return did_; } + SideMask allies() { return allies_; } + void SetAllies(SideMask sm) { allies_ = sm; } private: base::SocketAddress address_; @@ -80,6 +82,7 @@ private: bool havestats_; bool anonymous_; char did_[64]; + SideMask allies_; }; } // namespace wi diff --git a/server/server.cpp b/server/server.cpp index 51b9ba6..e76cd23 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -23,14 +23,15 @@ const dword kffEndpointIdFreeMaskAfterShift = 0x1f; Server::Server(StatsPoster& poster, XMsgLog *log, LevelInfoCache& cache, dword id, bool checksync, int max_rooms, int max_games_per_room, int max_players_per_room, int max_players, - const std::string& modlist_path, const std::string& badwords_path) : + const std::string& modlist_path, const std::string& badwords_path, + bool account_sharing) : poster_(poster), log_(log), cache_(cache), lobby_(this, max_rooms, max_games_per_room, max_players_per_room), id_(id), checksync_(checksync), max_players_(max_players), modlist_watcher_(modlist_path), badwords_(badwords_path), listener_(NULL), gameidCounter_(1), endpointidCounter_(1), endpoint_count_thread_safe_(0), updater_(NULL), - logger_("log", id), anons_allowed_(true) { + logger_("log", id), anons_allowed_(true), account_sharing_(account_sharing) { start_time_ = base::GetSecondsUnixEpocUTC(); @@ -372,4 +373,47 @@ void Server::SetAnonsAllowed(bool anons_allowed) { anons_allowed_ = anons_allowed; } +bool Server::SharedAccountExists(Endpoint *endpointAsker, const char *name) { + EndpointMap::iterator it = endpointmap_.begin(); + if (it->second->name() != NULL) { + for (; it != endpointmap_.end(); it++) { + + // Do the names match? + if (strcmp(name, it->second->name()) == 0) { + + // Don't count endpointAsker + if (endpointAsker->id() != it->second->id()) { + + // We found a shared account + return true; + } + } + } + } + return false; +} + +void Server::DisconnectSharedAccounts(Endpoint *endpointAsker, const char *name) { + EndpointMap::iterator it = endpointmap_.begin(); + if (it->second->name() != NULL) { + for (; it != endpointmap_.end(); it++) { + + // Do the names match? + if (strcmp(name, it->second->name()) == 0) { + + // Son't disconnect the asker, only other endpoints + if (endpointAsker->id() != it->second->id()) { + + // We found a shared account, dispose of it + it->second->Dispose(); + } + } + } + } +} + +bool Server::AccountSharing() { + return account_sharing_; +} + } // namespace wi diff --git a/server/server.h b/server/server.h index caffcd1..4315bec 100644 --- a/server/server.h +++ b/server/server.h @@ -33,7 +33,8 @@ public: Server(StatsPoster& stats, XMsgLog *log, LevelInfoCache& cache, dword id, bool checksync, int max_rooms, int max_games_per_room, int max_players_per_room, int max_players, - const std::string& modlist_path, const std::string& badwords_path); + const std::string& modlist_path, const std::string& badwords_path, + bool account_sharing); ~Server(); bool Listen(const base::SocketAddress& addr); @@ -45,12 +46,15 @@ public: bool IsModerator(const char *name); bool IsAdmin(const char *name); bool AnonsAllowed(); + bool AccountSharing(); void SetAnonsAllowed(bool anons_allowed); dword GetChatterId(Endpoint *endpointAsker, Endpoint *endpoint); Endpoint *GetEndpointFromChatterId(dword id); const char *GetChatRules(); std::string GetAnnouncements(); void SetAnnouncements(std::string announcements); + bool SharedAccountExists(Endpoint *endpointAsker, const char *name); + void DisconnectSharedAccounts(Endpoint *endpointAsker, const char *name); ChatLimiter& chatlimiter() { return chatlimiter_; } LevelInfoCache& cache() { return cache_; } @@ -89,6 +93,7 @@ private: LevelInfoCache& cache_; bool checksync_; bool anons_allowed_; + bool account_sharing_; dword gameidCounter_; dword endpointidCounter_; dword start_time_;