From a1589a48b6ec5e7fa280221bb2dea452a8987fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Brammer?= Date: Fri, 30 Nov 2012 22:07:08 +0100 Subject: [PATCH] Make network lobby command line processing available to the editor and dedi Most of the processing was already done by C4MessageInput::ProcessInput and C4MessageInput::ProcessCommand. Simply move the Lobby-only commands there, too, and make them work without a Lobby MainDlg. This required almost only cosmetic changes. --- src/gui/C4GameLobby.cpp | 160 +----------------------------------- src/gui/C4GameLobby.h | 2 +- src/gui/C4MessageInput.cpp | 163 +++++++++++++++++++++++++++++++++---- src/network/C4Network2.h | 1 + 4 files changed, 151 insertions(+), 175 deletions(-) diff --git a/src/gui/C4GameLobby.cpp b/src/gui/C4GameLobby.cpp index b4159d527..615d560dc 100644 --- a/src/gui/C4GameLobby.cpp +++ b/src/gui/C4GameLobby.cpp @@ -446,164 +446,7 @@ namespace C4GameLobby // store input in backbuffer before processing commands // because those might kill the edit field ::MessageInput.StoreBackBuffer(szInputText); - bool fProcessed = false; - // CAUTION when implementing special commands (like /quit) here: - // those must not be executed when text is pasted, because that could crash the GUI system - // when there are additional lines to paste, but the edit field is destructed by the command - if (!fProcessed && *szInputText == '/') - { - // must be 1 char longer than the longest command only. If given commands are longer, they will be truncated, and such a command won't exist anyway - const int32_t MaxCommandLen = 20; - char Command[MaxCommandLen+1]; - const char *szPar = szInputText; - // parse command until first space - int32_t iParPos = SCharPos(' ', szInputText); - if (iParPos<0) - { - // command w/o par - SCopy(szInputText, Command, MaxCommandLen); - szPar += SLen(szPar); - } - else - { - // command with following par - SCopy(szInputText, Command, Min(MaxCommandLen, iParPos)); - szPar += iParPos+1; - } - fProcessed = true; - // evaluate lobby-only commands - // ------------------------------------------------------ - if (SEqualNoCase(Command, "/joinplr")) - { - // compose path from given filename - StdStrBuf plrPath; - plrPath.Format("%s%s", Config.General.UserDataPath, szPar); - // player join - check filename - if (!ItemExists(plrPath.getData())) - { - LobbyError(FormatString(LoadResStr("IDS_MSG_CMD_JOINPLR_NOFILE"), plrPath.getData()).getData()); - } - else - ::Network.Players.JoinLocalPlayer(plrPath.getData(), true); - } - // ------------------------------------------------------ - else if (SEqualNoCase(Command, "/plrclr")) - { - // get player name from input text - int iSepPos = SCharPos(' ', szPar, 0); - C4PlayerInfo *pNfo=NULL; - int32_t idLocalClient = -1; - if (::Network.Clients.GetLocal()) idLocalClient = ::Network.Clients.GetLocal()->getID(); - if (iSepPos>0) - { - // a player name is given: Parse it - StdStrBuf sPlrName; - sPlrName.Copy(szPar, iSepPos); - szPar += iSepPos+1; int32_t id=0; - while ((pNfo = Game.PlayerInfos.GetNextPlayerInfoByID(id))) - { - id = pNfo->GetID(); - if (WildcardMatch(sPlrName.getData(), pNfo->GetName())) break; - } - } - else - // no player name: Set local player - pNfo = Game.PlayerInfos.GetPrimaryInfoByClientID(idLocalClient); - C4ClientPlayerInfos *pCltNfo=NULL; - if (pNfo) pCltNfo = Game.PlayerInfos.GetClientInfoByPlayerID(pNfo->GetID()); - if (!pCltNfo) - { - LobbyError(LoadResStr("IDS_MSG_CMD_PLRCLR_NOPLAYER")); - } - else - { - // may color of this client be set? - if (pCltNfo->GetClientID() != idLocalClient && !::Network.isHost()) - { - LobbyError(LoadResStr("IDS_MSG_CMD_PLRCLR_NOACCESS")); - } - else - { - // get color to set - uint32_t dwNewClr; - if (sscanf(szPar, "%x", &dwNewClr) != 1) - { - LobbyError(LoadResStr("IDS_MSG_CMD_PLRCLR_USAGE")); - } - else - { - // color validation - dwNewClr |= 0xff000000; - if (!dwNewClr) ++dwNewClr; - // request a color change to this color - C4ClientPlayerInfos LocalInfoRequest = *pCltNfo; - C4PlayerInfo *pPlrInfo = LocalInfoRequest.GetPlayerInfoByID(pNfo->GetID()); - assert(pPlrInfo); - if (pPlrInfo) - { - pPlrInfo->SetOriginalColor(dwNewClr); // set this as a new color wish - ::Network.Players.RequestPlayerInfoUpdate(LocalInfoRequest); - } - } - } - } - } - // ------------------------------------------------------ - else if (SEqualNoCase(Command, "/start")) - { - // timeout given? - int32_t iTimeout = Config.Lobby.CountdownTime; - if (!::Network.isHost()) - LobbyError(LoadResStr("IDS_MSG_CMD_HOSTONLY")); - else if (szPar && *szPar && (!sscanf(szPar, "%d", &iTimeout) || iTimeout<0)) - LobbyError(LoadResStr("IDS_MSG_CMD_START_USAGE")); - else - { - // abort previous countdown - if (eCountdownState) ::Network.AbortLobbyCountdown(); - // start new countdown (aborts previous if necessary) - Start(iTimeout); - } - } - // ------------------------------------------------------ - else if (SEqualNoCase(Command, "/abort")) - { - if (!::Network.isHost()) - LobbyError(LoadResStr("IDS_MSG_CMD_HOSTONLY")); - else if (eCountdownState) - ::Network.AbortLobbyCountdown(); - else - LobbyError(LoadResStr("IDS_MSG_CMD_ABORT_NOCOUNTDOWN")); - } - // ------------------------------------------------------ - else if (SEqualNoCase(Command, "/help")) - { - Log(LoadResStr("IDS_TEXT_COMMANDSAVAILABLEDURINGLO")); - LogF("/start [time] - %s", LoadResStr("IDS_TEXT_STARTTHEROUNDWITHSPECIFIE")); - LogF("/abort - %s", LoadResStr("IDS_TEXT_ABORTSTARTCOUNTDOWN")); - LogF("/alert - %s", LoadResStr("IDS_TEXT_ALERTTHEHOSTIFTHEHOSTISAW")); - LogF("/joinplr [filename] - %s", LoadResStr("IDS_TEXT_JOINALOCALPLAYERFROMTHESP")); - LogF("/kick [client] - %s", LoadResStr("IDS_TEXT_KICKTHESPECIFIEDCLIENT")); - LogF("/observer [client] - %s", LoadResStr("IDS_TEXT_SETTHESPECIFIEDCLIENTTOOB")); - LogF("/me [action] - %s", LoadResStr("IDS_TEXT_PERFORMANACTIONINYOURNAME")); - LogF("/sound [sound] - %s", LoadResStr("IDS_TEXT_PLAYASOUNDFROMTHEGLOBALSO")); - LogF("/team [message] - %s", LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOYOUR")); - LogF("/plrclr [player] [RGB] - %s", LoadResStr("IDS_TEXT_CHANGETHECOLOROFTHESPECIF")); - LogF("/plrclr [RGB] - %s", LoadResStr("IDS_TEXT_CHANGEYOUROWNPLAYERCOLOR")); - LogF("/set comment [comment] - %s", LoadResStr("IDS_TEXT_SETANEWNETWORKCOMMENT")); - LogF("/set password [password] - %s", LoadResStr("IDS_TEXT_SETANEWNETWORKPASSWORD")); - LogF("/set maxplayer [number] - %s", LoadResStr("IDS_TEXT_SETANEWMAXIMUMNUMBEROFPLA")); - LogF("/clear - %s", LoadResStr("IDS_MSG_CLEARTHEMESSAGEBOARD")); - } - // ------------------------------------------------------ - else - { - // command not known or not a specific lobby command - forward to messageinput - fProcessed = false; - } - } - // not processed? Then forward to messageinput, which parses additional commands and sends regular messages - if (!fProcessed) ::MessageInput.ProcessInput(szInputText); + ::MessageInput.ProcessInput(szInputText); } // clear edit field after text has been processed pEdt->SelectAll(); pEdt->DeleteSelection(); @@ -862,6 +705,7 @@ namespace C4GameLobby // get lobby MainDlg *pLobby = ::Network.GetLobby(); if (pLobby) pLobby->OnError(szErrorMsg); + else Log(szErrorMsg); } diff --git a/src/gui/C4GameLobby.h b/src/gui/C4GameLobby.h index 0bbf9458a..f9f97c076 100644 --- a/src/gui/C4GameLobby.h +++ b/src/gui/C4GameLobby.h @@ -132,7 +132,6 @@ namespace C4GameLobby private: void SetCountdownState(CountdownState eToState, int32_t iTimer); - void Start(int32_t iCountdownTime); // host only: Do game start with specified countdown time (forwards to network system) int32_t ValidatedCountdownTime(int32_t iTimeout); // correct invalid timeout settings void UpdatePlayerList(); @@ -156,6 +155,7 @@ namespace C4GameLobby void OnCountdownPacket(const C4PacketCountdown &Pkt); // called when a countdown packet is received: Update countdown state bool IsCountdown(); + void Start(int32_t iCountdownTime); // host only: Do game start with specified countdown time (forwards to network system) void UpdatePassword(); void ClearLog(); }; diff --git a/src/gui/C4MessageInput.cpp b/src/gui/C4MessageInput.cpp index a806dab4d..1e50d1259 100644 --- a/src/gui/C4MessageInput.cpp +++ b/src/gui/C4MessageInput.cpp @@ -445,30 +445,159 @@ bool C4MessageInput::ProcessCommand(const char *szCommand) { C4GameLobby::MainDlg *pLobby = ::Network.GetLobby(); // command - char szCmdName[C4MaxName + 1]; - SCopyUntil(szCommand + 1, szCmdName, ' ', C4MaxName); + // must be 1 char longer than the longest command only. If given commands are longer, they will be truncated, and such a command won't exist anyway + const int32_t MaxCommandLen = 20; + char szCmdName[MaxCommandLen + 1]; + SCopyUntil(szCommand + 1, szCmdName, ' ', MaxCommandLen); // parameter const char *pCmdPar = SSearch(szCommand, " "); if (!pCmdPar) pCmdPar = ""; - // dev-scripts + // CAUTION when implementing special commands (like /quit) here: + // those must not be executed when text is pasted, because that could crash the GUI system + // when there are additional lines to paste, but the edit field is destructed by the command + + // lobby-only commands + if (!Game.IsRunning && SEqualNoCase(szCmdName, "joinplr")) + { + // compose path from given filename + StdStrBuf plrPath; + plrPath.Format("%s%s", Config.General.UserDataPath, pCmdPar); + // player join - check filename + if (!ItemExists(plrPath.getData())) + { + C4GameLobby::LobbyError(FormatString(LoadResStr("IDS_MSG_CMD_JOINPLR_NOFILE"), plrPath.getData()).getData()); + } + else + ::Network.Players.JoinLocalPlayer(plrPath.getData(), true); + return true; + } + if (!Game.IsRunning && SEqualNoCase(szCmdName, "plrclr")) + { + // get player name from input text + int iSepPos = SCharPos(' ', pCmdPar, 0); + C4PlayerInfo *pNfo=NULL; + int32_t idLocalClient = -1; + if (::Network.Clients.GetLocal()) idLocalClient = ::Network.Clients.GetLocal()->getID(); + if (iSepPos>0) + { + // a player name is given: Parse it + StdStrBuf sPlrName; + sPlrName.Copy(pCmdPar, iSepPos); + pCmdPar += iSepPos+1; int32_t id=0; + while ((pNfo = Game.PlayerInfos.GetNextPlayerInfoByID(id))) + { + id = pNfo->GetID(); + if (WildcardMatch(sPlrName.getData(), pNfo->GetName())) break; + } + } + else + // no player name: Set local player + pNfo = Game.PlayerInfos.GetPrimaryInfoByClientID(idLocalClient); + C4ClientPlayerInfos *pCltNfo=NULL; + if (pNfo) pCltNfo = Game.PlayerInfos.GetClientInfoByPlayerID(pNfo->GetID()); + if (!pCltNfo) + { + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_PLRCLR_NOPLAYER")); + } + else + { + // may color of this client be set? + if (pCltNfo->GetClientID() != idLocalClient && !::Network.isHost()) + { + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_PLRCLR_NOACCESS")); + } + else + { + // get color to set + uint32_t dwNewClr; + if (sscanf(pCmdPar, "%x", &dwNewClr) != 1) + { + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_PLRCLR_USAGE")); + } + else + { + // color validation + dwNewClr |= 0xff000000; + if (!dwNewClr) ++dwNewClr; + // request a color change to this color + C4ClientPlayerInfos LocalInfoRequest = *pCltNfo; + C4PlayerInfo *pPlrInfo = LocalInfoRequest.GetPlayerInfoByID(pNfo->GetID()); + assert(pPlrInfo); + if (pPlrInfo) + { + pPlrInfo->SetOriginalColor(dwNewClr); // set this as a new color wish + ::Network.Players.RequestPlayerInfoUpdate(LocalInfoRequest); + } + } + } + } + return true; + } + if (!Game.IsRunning && SEqualNoCase(szCmdName, "start")) + { + // timeout given? + int32_t iTimeout = Config.Lobby.CountdownTime; + if (!::Network.isHost()) + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_HOSTONLY")); + else if (pCmdPar && *pCmdPar && (!sscanf(pCmdPar, "%d", &iTimeout) || iTimeout<0)) + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_START_USAGE")); + else if (pLobby) + { + // abort previous countdown + if (::Network.isLobbyCountDown()) ::Network.AbortLobbyCountdown(); + // start new countdown (aborts previous if necessary) + pLobby->Start(iTimeout); + } + else + { + if (iTimeout) + ::Network.StartLobbyCountdown(iTimeout); + else + ::Network.Start(); + } + return true; + } + if (!Game.IsRunning && SEqualNoCase(szCmdName, "abort")) + { + if (!::Network.isHost()) + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_HOSTONLY")); + else if (::Network.isLobbyCountDown()) + ::Network.AbortLobbyCountdown(); + else + C4GameLobby::LobbyError(LoadResStr("IDS_MSG_CMD_ABORT_NOCOUNTDOWN")); + return true; + } + if (SEqual(szCmdName, "help")) { - Log(LoadResStr("IDS_TEXT_COMMANDSAVAILABLEDURINGGA")); - LogF("/private [player] [message] - %s", LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOTHES")); - LogF("/team [message] - %s", LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOYOUR")); - LogF("/me [action] - %s", LoadResStr("IDS_TEXT_PERFORMANACTIONINYOURNAME")); - LogF("/sound [sound] - %s", LoadResStr("IDS_TEXT_PLAYASOUNDFROMTHEGLOBALSO")); + Log(LoadResStr(pLobby ? "IDS_TEXT_COMMANDSAVAILABLEDURINGLO" : "IDS_TEXT_COMMANDSAVAILABLEDURINGGA")); + if (!Game.IsRunning) + { + LogF("/start [time] - %s", LoadResStr("IDS_TEXT_STARTTHEROUNDWITHSPECIFIE")); + LogF("/abort - %s", LoadResStr("IDS_TEXT_ABORTSTARTCOUNTDOWN")); + LogF("/alert - %s", LoadResStr("IDS_TEXT_ALERTTHEHOSTIFTHEHOSTISAW")); + LogF("/joinplr [filename] - %s", LoadResStr("IDS_TEXT_JOINALOCALPLAYERFROMTHESP")); + LogF("/plrclr [player] [RGB] - %s", LoadResStr("IDS_TEXT_CHANGETHECOLOROFTHESPECIF")); + LogF("/plrclr [RGB] - %s", LoadResStr("IDS_TEXT_CHANGEYOUROWNPLAYERCOLOR")); + } + else + { + LogF("/fast [x] - %s", LoadResStr("IDS_TEXT_SETTOFASTMODESKIPPINGXFRA")); + LogF("/slow - %s", LoadResStr("IDS_TEXT_SETTONORMALSPEEDMODE")); + LogF("/chart - %s", LoadResStr("IDS_TEXT_DISPLAYNETWORKSTATISTICS")); + LogF("/nodebug - %s", LoadResStr("IDS_TEXT_PREVENTDEBUGMODEINTHISROU")); + LogF("/script [script] - %s", LoadResStr("IDS_TEXT_EXECUTEASCRIPTCOMMAND")); + } LogF("/kick [client] - %s", LoadResStr("IDS_TEXT_KICKTHESPECIFIEDCLIENT")); LogF("/observer [client] - %s", LoadResStr("IDS_TEXT_SETTHESPECIFIEDCLIENTTOOB")); - LogF("/fast [x] - %s", LoadResStr("IDS_TEXT_SETTOFASTMODESKIPPINGXFRA")); - LogF("/slow - %s", LoadResStr("IDS_TEXT_SETTONORMALSPEEDMODE")); - LogF("/chart - %s", LoadResStr("IDS_TEXT_DISPLAYNETWORKSTATISTICS")); - LogF("/nodebug - %s", LoadResStr("IDS_TEXT_PREVENTDEBUGMODEINTHISROU")); + LogF("/me [action] - %s", LoadResStr("IDS_TEXT_PERFORMANACTIONINYOURNAME")); + LogF("/sound [sound] - %s", LoadResStr("IDS_TEXT_PLAYASOUNDFROMTHEGLOBALSO")); + if (Game.IsRunning) LogF("/private [player] [message] - %s", LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOTHES")); + LogF("/team [message] - %s", LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOYOUR")); LogF("/set comment [comment] - %s", LoadResStr("IDS_TEXT_SETANEWNETWORKCOMMENT")); LogF("/set password [password] - %s", LoadResStr("IDS_TEXT_SETANEWNETWORKPASSWORD")); - LogF("/set maxplayer [4] - %s", LoadResStr("IDS_TEXT_SETANEWMAXIMUMNUMBEROFPLA")); - LogF("/script [script] - %s", LoadResStr("IDS_TEXT_EXECUTEASCRIPTCOMMAND")); + LogF("/set maxplayer [number] - %s", LoadResStr("IDS_TEXT_SETANEWMAXIMUMNUMBEROFPLA")); LogF("/clear - %s", LoadResStr("IDS_MSG_CLEARTHEMESSAGEBOARD")); return true; } @@ -645,12 +774,14 @@ bool C4MessageInput::ProcessCommand(const char *szCommand) } // show chart - if (Game.IsRunning) if (SEqual(szCmdName, "chart")) + if (Game.IsRunning) + if (SEqual(szCmdName, "chart")) return Game.ToggleChart(); // custom command C4MessageBoardCommand *pCmd; - if (Game.IsRunning) if ((pCmd = GetCommand(szCmdName))) + if (Game.IsRunning) + if ((pCmd = GetCommand(szCmdName))) { StdStrBuf Script, CmdScript; // replace %player% by calling player number diff --git a/src/network/C4Network2.h b/src/network/C4Network2.h index d23b8c432..ebd3cd040 100644 --- a/src/network/C4Network2.h +++ b/src/network/C4Network2.h @@ -297,6 +297,7 @@ public: // lobby countdown void StartLobbyCountdown(int32_t iCountdownTime); void AbortLobbyCountdown(); + bool isLobbyCountDown() { return pLobbyCountdown != 0; } // streaming size_t getPendingStreamData() const { return StreamingBuf.getSize() - StreamCompressor.avail_out; }