diff --git a/Release/Bot.lib b/Release/Bot.lib index 378aaa3..414cb5c 100644 Binary files a/Release/Bot.lib and b/Release/Bot.lib differ diff --git a/Release/Plugins/RenX.Core.lib b/Release/Plugins/RenX.Core.lib index 349325c..5a57c2d 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index 53aecc8..e1b6b22 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -197,11 +197,6 @@ bool RenX::Server::isFullyConnected() const return RenX::Server::fully_connected; } -bool RenX::Server::hasSeenStart() const -{ - return RenX::Server::seenStart; -} - bool RenX::Server::isFirstKill() const { return RenX::Server::firstKill; @@ -222,6 +217,31 @@ bool RenX::Server::isSeamless() const return RenX::Server::seamless; } +bool RenX::Server::isReliable() const +{ + return RenX::Server::reliable; +} + +bool RenX::Server::isMatchPending() const +{ + return RenX::Server::match_state == 0 || RenX::Server::isTravelling(); +} + +bool RenX::Server::isMatchInProgress() const +{ + return RenX::Server::match_state == 1; +} + +bool RenX::Server::isMatchOver() const +{ + return RenX::Server::match_state == 2 || RenX::Server::isMatchOver(); +} + +bool RenX::Server::isTravelling() const +{ + return RenX::Server::match_state == 3; +} + bool RenX::Server::isCompetitive() const { return RenX::Server::competitive; @@ -1289,7 +1309,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) return; Jupiter::ArrayList &xPlugins = *RenX::getCore()->getPlugins(); - Jupiter::ReadableString::TokenizeResult tokens = Jupiter::StringS::tokenize(line, this->rconVersion >= 4 ? RenX::DelimC : RenX::DelimC3); + Jupiter::ReadableString::TokenizeResult tokens = Jupiter::StringS::tokenize(line, this->rconVersion == 3 ? RenX::DelimC3 : RenX::DelimC); for (size_t index = 0; index != tokens.token_count; ++index) tokens.tokens[index].processEscapeSequences(); @@ -1373,7 +1393,6 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) if (this->firstAction == false) { this->firstAction = true; - this->silenceJoins = false; } }; auto parsePlayerData = [this](const Jupiter::ReadableString &data, Jupiter::ReferenceString &name, TeamType &team, int &id, bool &isBot) @@ -1894,9 +1913,20 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) this->autoBalanceTeams = tokens.getToken(17).asBool(); this->spawnCrates = tokens.getToken(19).asBool(); this->crateRespawnAfterPickup = tokens.getToken(21).asDouble(); + this->competitive = tokens.getToken(23).asBool(); + + const Jupiter::ReadableString &match_state_token = tokens.getToken(25); + if (match_state_token.equalsi("PendingMatch"_jrs)) + this->match_state = 0; + else if (match_state_token.equalsi("MatchInProgress"_jrs)) + this->match_state = 1; + else if (match_state_token.equalsi("RoundOver"_jrs) || match_state_token.equalsi("MatchOver"_jrs)) + this->match_state = 2; + else if (match_state_token.equalsi("TravelTheWorld"_jrs)) + this->match_state = 3; + else // Unknown state -- assume it's in progress + this->match_state = 1; } - else if (this->lastCommandParams.equalsi("bIsCompetitive")) - this->competitive = tokens.getToken(0).asBool(); } else if (this->lastCommand.equalsi("mutatorlist"_jrs)) { @@ -2429,6 +2459,8 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) // "winner" | Winner | Reason("TimeLimit" etc) | "GDI=" GDI Score | "Nod=" Nod Score // "tie" | Reason | "GDI=" GDI Score | "Nod=" Nod Score Jupiter::ReferenceString winTieToken = tokens.getToken(2); + this->match_state = 2; + if (winTieToken.equals("winner")) { Jupiter::ReferenceString sWinType = tokens.getToken(4); @@ -2584,9 +2616,8 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) { // Player RenX::PlayerInfo *player = parseGetPlayerOrAdd(tokens.getToken(2)); - if (this->silenceParts == false) - for (size_t i = 0; i < xPlugins.size(); i++) - xPlugins.get(i)->RenX_OnPart(this, player); + for (size_t i = 0; i < xPlugins.size(); i++) + xPlugins.get(i)->RenX_OnPart(this, player); this->removePlayer(player); if (this->gameover_when_empty && this->players.size() == this->bot_count) @@ -3052,15 +3083,16 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) { // Map | Mode="seamless" / "nonseamless" Jupiter::ReferenceString map = tokens.getToken(2); + + this->match_state = 3; if (tokens.getToken(3).equals("seamless")) this->seamless = true; else - { this->seamless = false; - this->silenceParts = true; - } + for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnMapChange(this, map, seamless); + this->map = map; onMapChange(); } @@ -3068,17 +3100,23 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) { // Map Jupiter::ReferenceString map = tokens.getToken(2); + + this->match_state = 0; this->map = map; + for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnMapLoad(this, map); } else if (subHeader.equals("Start;")) { // Map - this->seenStart = true; - this->gameStart = std::chrono::steady_clock::now(); Jupiter::ReferenceString map = tokens.getToken(2); + + this->match_state = 1; + this->reliable = true; + this->gameStart = std::chrono::steady_clock::now(); this->map = map; + for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnMapStart(this, map); } @@ -3195,7 +3233,6 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) RenX::Server::send("ping srv_init_done"_jrs); RenX::Server::gameStart = std::chrono::steady_clock::now(); - this->seenStart = false; this->seamless = true; for (size_t i = 0; i < xPlugins.size(); i++) @@ -3253,7 +3290,6 @@ bool RenX::Server::connect() RenX::Server::sock.setBlocking(false); RenX::Server::sock.send(Jupiter::StringS::Format("a%.*s\n", RenX::Server::pass.size(), RenX::Server::pass.ptr())); RenX::Server::connected = true; - RenX::Server::silenceParts = false; RenX::Server::attempts = 0; return true; } @@ -3286,6 +3322,8 @@ void RenX::Server::wipeData() delete player; } + RenX::Server::reliable = false; + RenX::Server::match_state = 1; RenX::Server::subscribed = false; RenX::Server::fully_connected = false; RenX::Server::bot_count = 0; @@ -3324,7 +3362,6 @@ RenX::Server::Server(Jupiter::Socket &&socket, const Jupiter::ReadableString &co RenX::Server::hostname = RenX::Server::sock.getRemoteHostname(); RenX::Server::sock.send(Jupiter::StringS::Format("a%.*s\n", RenX::Server::pass.size(), RenX::Server::pass.ptr())); RenX::Server::connected = true; - RenX::Server::silenceParts = false; } RenX::Server::Server(const Jupiter::ReadableString &configurationSection) diff --git a/RenX.Core/RenX_Server.h b/RenX.Core/RenX_Server.h index b7ef2e3..f2c2006 100644 --- a/RenX.Core/RenX_Server.h +++ b/RenX.Core/RenX_Server.h @@ -112,13 +112,6 @@ namespace RenX */ bool isFullyConnected() const; - /** - * @brief Checks if a map start event has fired. - * - * @return True if a map start event has fired, false otherwise. - */ - bool hasSeenStart() const; - /** * @brief Checks if the first kill has already been processed. * Note: This does not set to "true" until AFTER the first kill has been fully processed. @@ -154,6 +147,42 @@ namespace RenX */ bool isSeamless() const; + /** + * @brief Checks if the match data is reliable (bot has seen full game) + * This is based on the bot seeing the "Start;" event. + * + * @return True if this server's match data is reliable, false otherwise.. + */ + bool isReliable() const; + + /** + * @brief Checks if the match is pending (hasn't started OR not in game state). + * + * @return True if the match is pending, false otherwise. + */ + bool isMatchPending() const; + + /** + * @brief Checks if the match is in progress (started AND not over). + * + * @return True if a game is in progress, false otherwise. + */ + bool isMatchInProgress() const; + + /** + * @brief Checks if the match has ended (has ended OR not in game state) + * + * @return True if the match as ended, false otherwise. + */ + bool isMatchOver() const; + + /** + * @brief Checks if the server is travelling between levels (not in game state). + * + * @return True if the server is travelling, false otherwise. + */ + bool isTravelling() const; + /** * @brief Checks if the server is marked as competitive. * @@ -265,7 +294,7 @@ namespace RenX /** * @brief Calculates the time since match start. - * Note: if hasSeenStart() is false, this is the time since the connection was established. + * Note: if isReliable() is false, this is the time since the connection was established. * * @return Time since match start. */ @@ -996,10 +1025,6 @@ namespace RenX bool subscribed = false; bool fully_connected = false; bool seamless = false; - bool needsCList = false; - bool silenceParts = false; - bool silenceJoins = false; - bool seenStart = true; bool firstKill = false; bool firstDeath = false; bool firstAction = false; @@ -1012,6 +1037,8 @@ namespace RenX bool spawnCrates = true; bool competitive = false; bool devBot = false; + bool reliable = false; + int match_state = 1; /** 0 = pending, 1 = in progress, 2 = over, 3 = travelling */ int attempts = 0; int playerLimit = 0; int vehicleLimit = 0; diff --git a/RenX.Greetings/RenX_Greetings.cpp b/RenX.Greetings/RenX_Greetings.cpp index 4a884c6..d54a2d4 100644 --- a/RenX.Greetings/RenX_Greetings.cpp +++ b/RenX.Greetings/RenX_Greetings.cpp @@ -37,7 +37,7 @@ void RenX_GreetingsPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerI else server->sendMessage(msg); }; - if (player->isBot == false) + if (player->isBot == false && server->isMatchInProgress()) { switch (RenX_GreetingsPlugin::sendMode) { diff --git a/RenX.Ladder/RenX_Ladder.cpp b/RenX.Ladder/RenX_Ladder.cpp index 890b590..0e04b0b 100644 --- a/RenX.Ladder/RenX_Ladder.cpp +++ b/RenX.Ladder/RenX_Ladder.cpp @@ -42,7 +42,7 @@ bool RenX_LadderPlugin::initialize() void RenX_LadderPlugin::RenX_OnGameOver(RenX::Server *server, RenX::WinType winType, const RenX::TeamType &team, int gScore, int nScore) { - if (server->hasSeenStart() && server->players.size() != server->getBotCount()) // the first game doesn't count! + if (server->isReliable() && server->players.size() != server->getBotCount()) { char chr = static_cast(team); server->varData.set(this->name, "t"_jrs, Jupiter::ReferenceString(&chr, 1)); diff --git a/RenX.Logging/RenX_Logging.cpp b/RenX.Logging/RenX_Logging.cpp index f478370..e3bda27 100644 --- a/RenX.Logging/RenX_Logging.cpp +++ b/RenX.Logging/RenX_Logging.cpp @@ -562,7 +562,8 @@ void RenX_LoggingPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerInf msg = this->joinNoSteamAdminFmt; else msg = this->joinAdminFmt; - if (msg.isNotEmpty()) + + if (msg.isNotEmpty() && server->isMatchPending() == false) { RenX::processTags(msg, server, player); server->sendAdmChan(msg); @@ -578,7 +579,7 @@ void RenX_LoggingPlugin::RenX_OnPart(RenX::Server *server, const RenX::PlayerInf func = &RenX::Server::sendAdmChan; Jupiter::String msg = this->partFmt; - if (msg.isNotEmpty()) + if (msg.isNotEmpty() && (server->isTravelling() == false || server->isSeamless())) { RenX::processTags(msg, server, player); (server->*func)(msg); @@ -2032,8 +2033,6 @@ void RenX_LoggingPlugin::RenX_OnMapChange(RenX::Server *server, const Jupiter::R msg.replace(RenX::tags->INTERNAL_MESSAGE_TAG, map); (server->*func)(msg); } - if (server->isSeamless() == false) - server->sendLogChan(IRCCOLOR "07[Warning]" IRCCOLOR " This server is using non-seamless server travel; this bot will be disconnected."); } void RenX_LoggingPlugin::RenX_OnMapLoad(RenX::Server *server, const Jupiter::ReadableString &map) diff --git a/RenX.Medals/RenX_Medals.cpp b/RenX.Medals/RenX_Medals.cpp index f02adfd..c14bbc7 100644 --- a/RenX.Medals/RenX_Medals.cpp +++ b/RenX.Medals/RenX_Medals.cpp @@ -138,7 +138,7 @@ void RenX_MedalsPlugin::RenX_OnPlayerDelete(RenX::Server *server, const RenX::Pl void RenX_MedalsPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo *player) { - if (player->uuid.isNotEmpty() && player->isBot == false) + if (player->uuid.isNotEmpty() && player->isBot == false && server->isMatchInProgress()) { int worth = getWorth(player); Jupiter::INIFile::Section *section = RenX_MedalsPlugin::config.getSection(RenX_MedalsPlugin::firstSection); @@ -170,7 +170,7 @@ void RenX_MedalsPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo void RenX_MedalsPlugin::RenX_OnGameOver(RenX::Server *server, RenX::WinType winType, const RenX::TeamType &team, int gScore, int nScore) { - if (server->hasSeenStart() && server->players.size() != server->getBotCount()) // No unfair medals for the first game! :D + if (server->isReliable() && server->players.size() != server->getBotCount()) { Jupiter::DLList::Node *n = server->players.getNode(0); RenX::PlayerInfo *pInfo = n->data; diff --git a/RenX.MinPlayers/RenX_MinPlayers.cpp b/RenX.MinPlayers/RenX_MinPlayers.cpp index d2ba173..75993ba 100644 --- a/RenX.MinPlayers/RenX_MinPlayers.cpp +++ b/RenX.MinPlayers/RenX_MinPlayers.cpp @@ -38,13 +38,13 @@ void RenX_MinPlayersPlugin::RenX_OnMapStart(RenX::Server *server, const Jupiter: void RenX_MinPlayersPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo *player) { - if (server->players.size() > RenX_MinPlayersPlugin::player_threshold) + if (server->players.size() > RenX_MinPlayersPlugin::player_threshold && server->isMatchInProgress()) ++RenX_MinPlayersPlugin::phase_bots; } void RenX_MinPlayersPlugin::RenX_OnPart(RenX::Server *server, const RenX::PlayerInfo *player) { - if (server->players.size() <= player_threshold) + if (server->isMatchInProgress() && server->players.size() <= player_threshold) { switch (player->team) { diff --git a/RenX.ServerList/RenX_ServerList.cpp b/RenX.ServerList/RenX_ServerList.cpp index c4c831d..06420db 100644 --- a/RenX.ServerList/RenX_ServerList.cpp +++ b/RenX.ServerList/RenX_ServerList.cpp @@ -399,7 +399,13 @@ void RenX_ServerListPlugin::RenX_OnJoin(RenX::Server *, const RenX::PlayerInfo * this->updateServerList(); } -void RenX_ServerListPlugin::RenX_OnPart(RenX::Server *, const RenX::PlayerInfo *) +void RenX_ServerListPlugin::RenX_OnPart(RenX::Server *server, const RenX::PlayerInfo *) +{ + if (server->isTravelling() == false || server->isSeamless()) + this->updateServerList(); +} + +void RenX_ServerListPlugin::RenX_OnMapLoad(RenX::Server *server, const Jupiter::ReadableString &map) { this->updateServerList(); } diff --git a/RenX.ServerList/RenX_ServerList.h b/RenX.ServerList/RenX_ServerList.h index 3edc271..3179c98 100644 --- a/RenX.ServerList/RenX_ServerList.h +++ b/RenX.ServerList/RenX_ServerList.h @@ -39,6 +39,7 @@ public: // RenX::Plugin void RenX_OnServerDisconnect(RenX::Server *server, RenX::DisconnectReason reason) override; void RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo *player) override; void RenX_OnPart(RenX::Server *server, const RenX::PlayerInfo *player) override; + void RenX_OnMapLoad(RenX::Server *server, const Jupiter::ReadableString &map) override; private: Jupiter::StringS server_list_json; diff --git a/RenX.SetJoin/RenX_SetJoin.cpp b/RenX.SetJoin/RenX_SetJoin.cpp index 08af531..86db478 100644 --- a/RenX.SetJoin/RenX_SetJoin.cpp +++ b/RenX.SetJoin/RenX_SetJoin.cpp @@ -26,7 +26,7 @@ using namespace Jupiter::literals; void RenX_SetJoinPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo *player) { - if (player->uuid.isNotEmpty()) + if (player->uuid.isNotEmpty() && server->isMatchInProgress()) { const Jupiter::ReadableString &setjoin = RenX_SetJoinPlugin::setjoin_file.get(Jupiter::ReferenceString::empty, player->uuid); if (setjoin.isNotEmpty())