From c724eea30953e1824f90f42a8bc2c1866bd2129b Mon Sep 17 00:00:00 2001 From: JustinAJ Date: Thu, 14 Jan 2016 04:06:47 -0500 Subject: [PATCH] Bot: * Added "Error: Command disabled." error message CoreCommands: * Added "Error: Command disabled." error message RenX.Core: * Fixed all known crashing/corruption issues related to the new BanDatabase. * Replaced 'banCheck' processLine lambda function * bIsCompetitive is now tracked as 'competitive' * Added checks for commands disabled when 'competitive' is true RenX.Commands: * Combined Date and Time fields in BanSearch IRC Command results. * Added error message for when certain commands are disabled/not supported by a server * Global ban checks are now run after a "ban" or "addban" command is executed --- Bot/IRC_Bot.cpp | 29 +-- CoreCommands/CoreCommands.cpp | 17 +- Jupiter | 2 +- Release/Bot.lib | Bin 24762 -> 24762 bytes Release/Plugins/RenX.Core.lib | Bin 153594 -> 155250 bytes RenX.Commands/RenX_Commands.cpp | 70 +++--- RenX.Core/RenX_BanDatabase.cpp | 15 +- RenX.Core/RenX_BanDatabase.h | 3 +- RenX.Core/RenX_Core.cpp | 20 +- RenX.Core/RenX_Core.h | 15 +- RenX.Core/RenX_Server.cpp | 366 ++++++++++++++++-------------- RenX.Core/RenX_Server.h | 21 ++ RenX.ModSystem/RenX_ModSystem.cpp | 14 +- RenX.ModSystem/RenX_ModSystem.h | 4 +- 14 files changed, 329 insertions(+), 247 deletions(-) diff --git a/Bot/IRC_Bot.cpp b/Bot/IRC_Bot.cpp index d919e1f..615ffe6 100644 --- a/Bot/IRC_Bot.cpp +++ b/Bot/IRC_Bot.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013-2015 Jessica James. + * Copyright (C) 2013-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,19 +16,6 @@ * Written by Jessica James */ -/** - * Long term plan: - * Eventually, this file and its header will no longer be a part of this project. - * The features made available by this core will slowly be transferred away in pieces - * to other locations, such as the internal Jupiter library, or various plugins. - * - * There is a relatively thin line between what will go in Jupiter, and what will be - * pushed to plugins. - * Example: The "Command" and "Plugin" classes ended up in Jupiter; they're abstract concepts - * that doesn't put a specific behavior on any mechanisms. The "IRCCommand" class, however, - * alters the behavior of the IRC Client, and thus should be contained within a plugin. - */ - #include #include #include @@ -38,9 +25,11 @@ #include "IRC_Bot.h" #include "IRC_Command.h" +using namespace Jupiter::literals; + IRC_Bot::IRC_Bot(const Jupiter::ReadableString &configSection) : Client(configSection) { - IRC_Bot::commandPrefix = this->readConfigValue(STRING_LITERAL_AS_REFERENCE("Prefix")); + IRC_Bot::commandPrefix = this->readConfigValue("Prefix"_jrs); for (size_t i = 0; i != IRCMasterCommandList->size(); i++) IRC_Bot::addCommand(IRCMasterCommandList->get(i)->copy()); IRC_Bot::setCommandAccessLevels(); @@ -200,11 +189,13 @@ void IRC_Bot::OnChat(const Jupiter::ReadableString &channel, const Jupiter::Read if (cmd != nullptr) { IRCCommand::active_server = this; - int cAccess = cmd->getAccessLevel(chan); - if (cAccess >= 0 && Jupiter::IRC::Client::getAccessLevel(channel, nick) >= cAccess) - cmd->trigger(this, channel, nick, parameters); + int command_access = cmd->getAccessLevel(chan); + if (command_access < 0) + this->sendNotice(nick, "Error: Command disabled."_jrs); + else if (Jupiter::IRC::Client::getAccessLevel(channel, nick) < command_access) + this->sendNotice(nick, "Access Denied."_jrs); else - this->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Access Denied.")); + cmd->trigger(this, channel, nick, parameters); IRCCommand::active_server = IRCCommand::selected_server; } } diff --git a/CoreCommands/CoreCommands.cpp b/CoreCommands/CoreCommands.cpp index 72a1b12..b5af7c5 100644 --- a/CoreCommands/CoreCommands.cpp +++ b/CoreCommands/CoreCommands.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014-2015 Jessica James. + * Copyright (C) 2014-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -68,7 +68,7 @@ CONSOLE_COMMAND_INIT(HelpConsoleCommand) void HelpIRCCommand::create() { - this->addTrigger(STRING_LITERAL_AS_REFERENCE("help")); + this->addTrigger("help"_jrs); } void HelpIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) @@ -90,18 +90,23 @@ void HelpIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &cha source->sendNotice(nick, Jupiter::StringS::Format("Access level %d commands: %.*s", i, triggers.size(), triggers.ptr())); } } - source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("For command-specific help, use: help ")); + source->sendNotice(nick, "For command-specific help, use: help "_jrs); } else { IRCCommand *cmd = source->getCommand(Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE)); if (cmd) { - if (access >= cmd->getAccessLevel(chan)) + int command_access = cmd->getAccessLevel(chan); + + if (command_access < 0) + source->sendNotice(nick, "Error: Command disabled."_jrs); + else if (access < command_access) + source->sendNotice(nick, "Access Denied."_jrs); + else source->sendNotice(nick, cmd->getHelp(Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE))); - else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Access Denied.")); } - else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Command not found.")); + else source->sendNotice(nick, "Error: Command not found."_jrs); } } } diff --git a/Jupiter b/Jupiter index 5b83899..5eca27a 160000 --- a/Jupiter +++ b/Jupiter @@ -1 +1 @@ -Subproject commit 5b83899a03642d18deb6a85dabfb1afd8d76422e +Subproject commit 5eca27adc30fef1d51156d94de85a34f4e5793d0 diff --git a/Release/Bot.lib b/Release/Bot.lib index 9b08312dc2c7a351fc98b81b162e709de199db45..8ecbe065b7457c147cdb7bba48ab58d7ce70b581 100644 GIT binary patch delta 1981 zcmZuxJ4{ni7;bq83bBrHKmTEe(PdAdiU$smnA2343rZ1%* zW^EtvZEE(7{lBXh@EpM7-k)nU~d9-*W9-lPNoF2KE!jLFvIf!3AR0m z?|TMRxN89M{?!GTILB=Z%T%LgJ*XC8nlIF;3u~>j( z`2b=c0z8*Kh?p}tBg9JZE{Mz6Mrv)O%Xmz0hTlOxEOQ70BcUt{qy>>7%LCaDshjEu zBOVWPLt?Xc!s=#sN01+iM7e%MDL{ouV2dI*79A0|61<5T^z`g(q=;5hgll?c2IA>% zxSgnFL~9I1Cu7$crVmQ6mO#;;G2R)9-yA`FY2>PkuZ!c`5hBUj$#!fReb6vbsmetQ zULM2vtvD~ZaHY-!zf#46{B8^p%?|P?!1D?hxJLNOSw|J~qxb$bbC_06%~)Y4*$nP6 z7h@E>is4mJlhPZwoDES~;sP zDXvLlb>rBOJD2BpegQu-{(pR1zza{>jftWsO+MKi@nt8zs%yq!KEeA(eLcK_-XnzL zAe{BH{-VK&r|n4#r=3{y8*yP=n5Z-FzBe<^N>`kB?z!jwW;?In&g-Almv#2_ zbanMuU_LEvS`+;LT&Qkqy?#*ud?sU8Z?75uW{w5*#k%Fq2V3#puX?7E^O+!JH5Ahi zS!9NKf5JY9ORiB$;5vRbG&NWf0xJ7#!dN zAqoB{c&%fS;fB~n+0mL~f?>`n#4b2v46}?&us?;m8_wGdCsTr~2l0$6$ncy`f*lv) z2d*Iv?ifNmKBVn}*xlo#yYGwZA>|eaE>A%AYjta5NpocUrMq9qWr8A4jf|i4^f6rV zEKjn7G_#uIIy}-wdU=|0sDIUG=`hblWA}$K*W&Of<14tV*-kWTiRNo_3p9GUra2%% zdlF-_UOs~ynayV};=jBJrb#`hvs@YxW+~u5G`I=Eqge0tQL$c}=f_b$)1FTw7V&W` z=R@p+kLNP@5wrW}gjfmQ`EeQBNUe=@8BZ9@@Y~OaWe#9qD3E4>v>-BMc_0S?ZBuPQ z#G^rONNo0QP}}V85b^_|FxL+$1!yn{tYPFv!eatgf;VBKfu5a}6wykGaLmrlK{VM7 zcVab+Xo;ZcbmRuZ41NhVVkr7E!aGCpTVsf?j9t_4tD^XJ1W2-WvK@Jo2O6fzHMwZP zs}mTXkMe@mE49b?l`0^BE`RL36SFXw$Nf`m9zSi z;F>hHY7!fA_sTraFW~1U|Bvqoxca2soGN(IPH1E5bXEn|9&>59xu%GoA?Q^}P;LkEnmS0@Rsu`|LFL_}Gbso-i`~{?b BTEzeW diff --git a/Release/Plugins/RenX.Core.lib b/Release/Plugins/RenX.Core.lib index bb9c23f2a102f45c3501bd1c8161b9df551a0726..1d8d80ee0ebdaa8f9931def8d17fe84a4adc8657 100644 GIT binary patch delta 18606 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 - const Jupiter::ReadableString &banner = entry->varData.get(pluginInstance.getName()); - strftime(timeStr, sizeof(timeStr), "%b %d %Y; Time: %H:%M:%S", localtime(&(entry->timestamp))); + strftime(timeStr, sizeof(timeStr), "%b %d %Y, %H:%M:%S", localtime(&(entry->timestamp))); if ((entry->flags & 0x7FFF) == 0) types = " NULL;"_jrs; @@ -1193,7 +1192,7 @@ void BanSearchIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString out.format("ID: %lu (%sactive); Date: %s; IP: %.*s/%u; Steam: %llu; Types:%.*s Name: %.*s; Banner: %.*s", i, entry->is_active() ? "" : "in", timeStr, ip_str.size(), ip_str.ptr(), entry->prefix_length, entry->steamid, types.size(), types.ptr(), - entry->name.size(), entry->name.ptr(), banner.size(), banner.ptr()); + entry->name.size(), entry->name.ptr(), entry->banner.size(), entry->banner.ptr()); if (entry->rdns.isNotEmpty()) { @@ -1639,8 +1638,10 @@ void DisarmIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &c player = server->getPlayerByPartName(parameters); if (player != nullptr) { - server->disarm(player); - source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("All deployables (c4, beacons, etc) belonging to ") + RenX::getFormattedPlayerName(player) + STRING_LITERAL_AS_REFERENCE(IRCCOLOR " have been disarmed.")); + if (server->disarm(player)) + source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("All deployables (c4, beacons, etc) belonging to ") + RenX::getFormattedPlayerName(player) + STRING_LITERAL_AS_REFERENCE(IRCCOLOR " have been disarmed.")); + else + source->sendMessage(channel, "Error: Server does not support disarms."_jrs); } else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Player not found.")); @@ -1688,8 +1689,10 @@ void DisarmC4IRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString player = server->getPlayerByPartName(parameters); if (player != nullptr) { - server->disarmC4(player); - source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("All C4 belonging to ") + RenX::getFormattedPlayerName(player) + STRING_LITERAL_AS_REFERENCE(IRCCOLOR " have been disarmed.")); + if (server->disarmC4(player)) + source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("All C4 belonging to ") + RenX::getFormattedPlayerName(player) + STRING_LITERAL_AS_REFERENCE(IRCCOLOR " have been disarmed.")); + else + source->sendMessage(channel, "Error: Server does not support disarms."_jrs); } else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Player not found.")); @@ -1739,8 +1742,10 @@ void DisarmBeaconIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableStr player = server->getPlayerByPartName(parameters); if (player != nullptr) { - server->disarmBeacon(player); - source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("All beacons belonging to ") + RenX::getFormattedPlayerName(player) + STRING_LITERAL_AS_REFERENCE(IRCCOLOR " have been disarmed.")); + if (server->disarmBeacon(player)) + source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("All beacons belonging to ") + RenX::getFormattedPlayerName(player) + STRING_LITERAL_AS_REFERENCE(IRCCOLOR " have been disarmed.")); + else + source->sendMessage(channel, "Error: Server does not support disarms."_jrs); } else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Player not found.")); @@ -1799,7 +1804,7 @@ void MineBanIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString & source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Channel not attached to any connected Renegade X servers.")); } } - else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Too Few Parameters. Syntax: disarmb ")); + else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Too Few Parameters. Syntax: mineban ")); } const Jupiter::ReadableString &MineBanIRCCommand::getHelp(const Jupiter::ReadableString &) @@ -1887,8 +1892,8 @@ void TempBanIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString & RenX::PlayerInfo *player; RenX::Server *server; unsigned int kicks = 0; - Jupiter::StringS name = Jupiter::StringS::getWord(parameters, 0, WHITESPACE); - Jupiter::StringS reason = parameters.wordCount(WHITESPACE) > 1 ? Jupiter::StringS::gotoWord(parameters, 1, WHITESPACE) : STRING_LITERAL_AS_REFERENCE("No reason"); + Jupiter::ReferenceString name = Jupiter::ReferenceString::getWord(parameters, 0, WHITESPACE); + Jupiter::ReferenceString reason = parameters.wordCount(WHITESPACE) > 1 ? Jupiter::ReferenceString::gotoWord(parameters, 1, WHITESPACE) : "No reason"_jrs; Jupiter::String banner(nick.size() + 4); banner += nick; banner += "@IRC"; @@ -1965,7 +1970,10 @@ void KickBanIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString & if (kicks == 0) source->sendMessage(channel, "Player \""_jrs + name + "\" not found."_jrs); else + { source->sendMessage(channel, Jupiter::StringS::Format("%u players kicked.", kicks)); + RenX::getCore()->banCheck(); + } } else source->sendMessage(channel, STRING_LITERAL_AS_REFERENCE("Error: Channel not attached to any connected Renegade X servers.")); } @@ -2125,6 +2133,7 @@ void AddBanIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &c flags |= RenX::BanDatabase::Entry::FLAG_USE_RDNS; RenX::banDatabase->add(name, ip, prefix_length, steamid, rdns, banner, reason, duration); + RenX::getCore()->banCheck(); } } } @@ -2397,21 +2406,18 @@ void RefundIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &c RenX::Server *server = RenX::getCore()->getServer(i); if (server->isLogChanType(type) && server->players.size() != 0) { - for (Jupiter::DLList::Node *node = server->players.getNode(0); node != nullptr; node = node->next) + player = server->getPlayerByPartName(playerName); + if (player != nullptr) { - player = node->data; - if (player->name.findi(playerName) != Jupiter::INVALID_INDEX) + if (server->giveCredits(player, credits)) { - if (server->giveCredits(player, credits)) - { - msg.format("You have been refunded %.0f credits by %.*s.", credits, nick.size(), nick.ptr()); - server->sendMessage(player, msg); - msg.format("%.*s has been refunded %.0f credits.", player->name.size(), player->name.ptr(), credits); - } - else - msg.set("Error: Server does not support refunds."); - source->sendMessage(channel, msg); + msg.format("You have been refunded %.0f credits by %.*s.", credits, nick.size(), nick.ptr()); + server->sendMessage(player, msg); + msg.format("%.*s has been refunded %.0f credits.", player->name.size(), player->name.ptr(), credits); } + else + msg.set("Error: Server does not support refunds."); + source->sendMessage(channel, msg); } } } @@ -2784,11 +2790,10 @@ void DisarmGameCommand::trigger(RenX::Server *source, RenX::PlayerInfo *player, source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: Player not found.")); else if (target->access >= player->access) source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: You can not disarm higher level moderators.")); + else if (source->disarm(target) == false) + source->sendMessage(player, "Error: Server does not support disarms."_jrs); else - { - source->disarm(target); source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Player has been disarmed.")); - } } else source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: Too few parameters. Syntax: disarm ")); @@ -2819,11 +2824,10 @@ void DisarmC4GameCommand::trigger(RenX::Server *source, RenX::PlayerInfo *player source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: Player not found.")); else if (target->access >= player->access) source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: You can not disarm higher level moderators.")); + else if (source->disarmC4(target) == false) + source->sendMessage(player, "Error: Server does not support disarms."_jrs); else - { - source->disarmC4(target); source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Player has been disarmed.")); - } } else source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: Too few parameters. Syntax: disarmc4 ")); @@ -2856,11 +2860,10 @@ void DisarmBeaconGameCommand::trigger(RenX::Server *source, RenX::PlayerInfo *pl source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: Player not found.")); else if (target->access >= player->access) source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: You can not disarm higher level moderators.")); + else if (source->disarmBeacon(target) == false) + source->sendMessage(player, "Error: Server does not support disarms."_jrs); else - { - source->disarmBeacon(target); source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Player has been disarmed.")); - } } else source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Error: Too few parameters. Syntax: disarmb ")); @@ -3019,6 +3022,7 @@ void KickBanGameCommand::trigger(RenX::Server *source, RenX::PlayerInfo *player, { source->banPlayer(target, player->name, reason); source->sendMessage(player, STRING_LITERAL_AS_REFERENCE("Player has been banned and kicked from the game.")); + RenX::getCore()->banCheck(); } } else diff --git a/RenX.Core/RenX_BanDatabase.cpp b/RenX.Core/RenX_BanDatabase.cpp index 3c71f20..414f12a 100644 --- a/RenX.Core/RenX_BanDatabase.cpp +++ b/RenX.Core/RenX_BanDatabase.cpp @@ -44,7 +44,7 @@ void RenX::BanDatabase::process_data(Jupiter::DataBuffer &buffer, FILE *file, fp entry->length = buffer.pop(); entry->steamid = buffer.pop(); entry->ip = buffer.pop(); - entry->prefix_length = buffer.pop(); + entry->prefix_length = buffer.pop(); entry->rdns = buffer.pop(); entry->name = buffer.pop(); entry->banner = buffer.pop(); @@ -53,6 +53,8 @@ void RenX::BanDatabase::process_data(Jupiter::DataBuffer &buffer, FILE *file, fp // Read varData from buffer to entry for (size_t varData_entries = buffer.pop(); varData_entries != 0; --varData_entries) entry->varData.set(buffer.pop(), buffer.pop()); + + RenX::BanDatabase::entries.add(entry); } void RenX::BanDatabase::process_header(FILE *file) @@ -77,9 +79,13 @@ void RenX::BanDatabase::process_file_finish(FILE *file) { puts("Warning: Unsupported ban database file version. The database will be removed and rewritten."); this->create_header(file); + fgetpos(file, std::addressof(RenX::BanDatabase::eof)); RenX::BanDatabase::read_version = RenX::BanDatabase::write_version; } + return; } + + fgetpos(file, std::addressof(RenX::BanDatabase::eof)); } void RenX::BanDatabase::upgrade_database() @@ -97,7 +103,8 @@ void RenX::BanDatabase::upgrade_database() void RenX::BanDatabase::write(RenX::BanDatabase::Entry *entry) { - FILE *file = fopen(filename.c_str(), "ab"); + FILE *file = fopen(filename.c_str(), "r+b"); + fsetpos(file, std::addressof(RenX::BanDatabase::eof)); if (file != nullptr) { RenX::BanDatabase::write(entry, file); @@ -136,6 +143,7 @@ void RenX::BanDatabase::write(RenX::BanDatabase::Entry *entry, FILE *file) // push buffer to file buffer.push_to(file); + fgetpos(file, std::addressof(RenX::BanDatabase::eof)); } void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason, time_t length, uint16_t flags) @@ -193,7 +201,8 @@ bool RenX::BanDatabase::deactivate(size_t index) if (file != nullptr) { fsetpos(file, &entry->pos); - fputc(entry->flags, file); + fseek(file, sizeof(size_t), SEEK_CUR); + fwrite(std::addressof(entry->flags), sizeof(entry->flags), 1, file); fclose(file); } return true; diff --git a/RenX.Core/RenX_BanDatabase.h b/RenX.Core/RenX_BanDatabase.h index 744262e..048bc33 100644 --- a/RenX.Core/RenX_BanDatabase.h +++ b/RenX.Core/RenX_BanDatabase.h @@ -176,7 +176,7 @@ namespace RenX * @param entry Entry to write to the database. * @param file FILE stream to write to. */ - static void write(Entry *entry, FILE *file); + void write(Entry *entry, FILE *file); /** * @brief Deactivates a ban entry. @@ -214,6 +214,7 @@ namespace RenX /** Database version */ const uint8_t write_version = 3U; uint8_t read_version = write_version; + fpos_t eof; Jupiter::CStringS filename; Jupiter::ArrayList entries; diff --git a/RenX.Core/RenX_Core.cpp b/RenX.Core/RenX_Core.cpp index 82f9596..6ab3069 100644 --- a/RenX.Core/RenX_Core.cpp +++ b/RenX.Core/RenX_Core.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014-2015 Jessica James. + * Copyright (C) 2014-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -94,6 +94,11 @@ RenX::Server *RenX::Core::getServer(unsigned int index) return RenX::Core::servers.get(index); } +Jupiter::ArrayList RenX::Core::getServers() +{ + return RenX::Core::servers; +} + Jupiter::ArrayList RenX::Core::getServers(int type) { Jupiter::ArrayList r; @@ -150,14 +155,17 @@ Jupiter::INIFile &RenX::Core::getCommandsFile() int RenX::Core::addCommand(RenX::GameCommand *command) { - for (size_t i = 0; i != RenX::Core::servers.size(); i++) - { - RenX::Server *server = RenX::Core::servers.get(i); - server->addCommand(command->copy()); - } + for (size_t i = 0; i != RenX::Core::servers.size(); ++i) + RenX::Core::servers.get(i)->addCommand(command->copy()); return RenX::Core::servers.size(); } +void RenX::Core::banCheck() +{ + for (size_t index = 0; index != RenX::Core::servers.size(); ++index) + RenX::Core::servers.get(index)->banCheck(); +} + int RenX::Core::think() { size_t index = 0; diff --git a/RenX.Core/RenX_Core.h b/RenX.Core/RenX_Core.h index 1c952b9..90199c7 100644 --- a/RenX.Core/RenX_Core.h +++ b/RenX.Core/RenX_Core.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014-2015 Jessica James. + * Copyright (C) 2014-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -98,6 +98,14 @@ namespace RenX */ RenX::Server *getServer(unsigned int index); + /** + * @brief Fetches the list of servers + * Note: This copies the array of pointers, not the objects themselves. + * + * @return Copy of the list of servers. + */ + Jupiter::ArrayList getServers(); + /** * @brief Constructs a list of servers based on their type. * @@ -165,6 +173,11 @@ namespace RenX */ int addCommand(GameCommand *command); + /** + * @brief Performs a ban check on every player on each server, and kicks as appropriate. + */ + void banCheck(); + /** * @brief Initializes the Core. */ diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index 19b93e8..ae074e7 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -169,6 +169,11 @@ bool RenX::Server::isSeamless() const return RenX::Server::seamless; } +bool RenX::Server::isCompetitive() const +{ + return RenX::Server::competitive; +} + bool RenX::Server::isPublicLogChanType(int type) const { return RenX::Server::logChanType == type; @@ -295,7 +300,8 @@ RenX::PlayerInfo *RenX::Server::getPlayerByName(const Jupiter::ReadableString &n idToken.shiftRight(6); else if (name.matchi("pid?*")) idToken.shiftRight(3); - else return nullptr; + else + return nullptr; int id = idToken.asInt(10); for (Jupiter::DLList::Node *node = RenX::Server::players.getNode(0); node != nullptr; node = node->next) @@ -379,6 +385,164 @@ void RenX::Server::forceKickPlayer(const RenX::PlayerInfo *player, const Jupiter RenX::Server::forceKickPlayer(player->id, reason); } +void RenX::Server::banCheck() +{ + for (Jupiter::DLList::Node *node = RenX::Server::players.getNode(0); node != nullptr; node = node->next) + this->banCheck(node->data); +} + +void RenX::Server::banCheck(RenX::PlayerInfo *player) +{ + const Jupiter::ArrayList &entries = RenX::banDatabase->getEntries(); + RenX::BanDatabase::Entry *entry = nullptr; + uint32_t netmask; + + RenX::BanDatabase::Entry *last_to_expire[7]; + for (size_t index = 0; index != sizeof(last_to_expire); ++index) + last_to_expire[index] = nullptr; + + auto handle_type = [&entry, &last_to_expire](size_t index) + { + if (last_to_expire[index] == nullptr) + last_to_expire[index] = entry; + else if (last_to_expire[index]->length == 0) + { + // favor older bans if they're also permanent + if (entry->length == 0 && entry->timestamp < last_to_expire[index]->timestamp) + last_to_expire[index] = entry; + } + else if (entry->length == 0 || entry->timestamp + entry->length > last_to_expire[index]->timestamp + last_to_expire[index]->length) + last_to_expire[index] = entry; + }; + + for (size_t i = 0; i != entries.size(); i++) + { + entry = entries.get(i); + if (entry->is_active()) + { + if (entry->length != 0 && entry->timestamp + entry->length < time(0)) + banDatabase->deactivate(i); + else + { + if (entry->prefix_length >= 32) + netmask = 0xFFFFFFFF; + else + netmask = Jupiter_prefix_length_to_netmask(entry->prefix_length); + + printf("%d vs %d" ENDL, (entry->ip & netmask), (player->ip32 & netmask)); + if ((this->localSteamBan && entry->steamid != 0 && entry->steamid == player->steamid) + || (this->localIPBan && entry->ip != 0 && (entry->ip & netmask) == (player->ip32 & netmask)) + || (this->localRDNSBan && entry->rdns.isNotEmpty() && entry->is_rdns_ban() && player->rdns.match(entry->rdns)) + || (this->localNameBan && entry->name.isNotEmpty() && entry->name.equalsi(player->name))) + { + player->ban_flags |= entry->flags; + if (entry->is_type_game()) + handle_type(0); + if (entry->is_type_chat()) + handle_type(1); + if (entry->is_type_bot()) + handle_type(2); + if (entry->is_type_vote()) + handle_type(3); + if (entry->is_type_mine()) + handle_type(4); + if (entry->is_type_ladder()) + handle_type(5); + if (entry->is_type_alert()) + handle_type(6); + } + } + } + } + + char timeStr[256]; + if (last_to_expire[0] != nullptr) // Game ban + { + strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[0]->timestamp + last_to_expire[0]->length))); + if (last_to_expire[0]->length == 0) + this->forceKickPlayer(player, Jupiter::StringS::Format("You were permanently banned from the server on %s for: %.*s", timeStr, last_to_expire[0]->reason.size(), last_to_expire[0]->reason.ptr())); + else + this->forceKickPlayer(player, Jupiter::StringS::Format("You are banned from the server until %s for: %.*s", timeStr, last_to_expire[0]->reason.size(), last_to_expire[0]->reason.ptr())); + + player->ban_flags |= RenX::BanDatabase::Entry::FLAG_TYPE_BOT; // implies FLAG_TYPE_BOT + } + else + { + if (last_to_expire[1] != nullptr) // Chat ban + { + strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[1]->timestamp + last_to_expire[1]->length))); + this->mute(player); + if (last_to_expire[1]->length == 0) + this->sendMessage(player, Jupiter::StringS::Format("You were permanently muted on this server on %s for: %.*s", timeStr, last_to_expire[1]->reason.size(), last_to_expire[1]->reason.ptr())); + else + this->sendMessage(player, Jupiter::StringS::Format("You are muted on this server until %s for: %.*s", timeStr, last_to_expire[1]->reason.size(), last_to_expire[1]->reason.ptr())); + + player->ban_flags |= RenX::BanDatabase::Entry::FLAG_TYPE_BOT; // implies FLAG_TYPE_BOT + } + else if (last_to_expire[2] != nullptr) // Bot ban + { + strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[2]->timestamp + last_to_expire[2]->length))); + if (last_to_expire[2]->length == 0) + this->sendMessage(player, Jupiter::StringS::Format("You were permanently bot-muted on this server on %s for: %.*s", timeStr, last_to_expire[2]->reason.size(), last_to_expire[2]->reason.ptr())); + else + this->sendMessage(player, Jupiter::StringS::Format("You are bot-muted on this server until %s for: %.*s", timeStr, last_to_expire[2]->reason.size(), last_to_expire[2]->reason.ptr())); + } + if (last_to_expire[3] != nullptr) // Vote ban + { + strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[3]->timestamp + last_to_expire[3]->length))); + if (last_to_expire[3]->length == 0) + this->sendMessage(player, Jupiter::StringS::Format("You were permanently vote-muted on this server on %s for: %.*s", timeStr, last_to_expire[3]->reason.size(), last_to_expire[3]->reason.ptr())); + else + this->sendMessage(player, Jupiter::StringS::Format("You are vote-muted on this server until %s for: %.*s", timeStr, last_to_expire[3]->reason.size(), last_to_expire[3]->reason.ptr())); + } + if (last_to_expire[4] != nullptr) // Mine ban + { + this->mineBan(player); + strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[4]->timestamp + last_to_expire[4]->length))); + if (last_to_expire[4]->length == 0) + this->sendMessage(player, Jupiter::StringS::Format("You were permanently mine-banned on this server on %s for: %.*s", timeStr, last_to_expire[4]->reason.size(), last_to_expire[4]->reason.ptr())); + else + this->sendMessage(player, Jupiter::StringS::Format("You are mine-banned on this server until %s for: %.*s", timeStr, last_to_expire[4]->reason.size(), last_to_expire[4]->reason.ptr())); + } + if (last_to_expire[5] != nullptr) // Ladder ban + { + strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[5]->timestamp + last_to_expire[5]->length))); + if (last_to_expire[5]->length == 0) + this->sendMessage(player, Jupiter::StringS::Format("You were permanently ladder-banned on this server on %s for: %.*s", timeStr, last_to_expire[5]->reason.size(), last_to_expire[5]->reason.ptr())); + else + this->sendMessage(player, Jupiter::StringS::Format("You are ladder-banned on this server until %s for: %.*s", timeStr, last_to_expire[5]->reason.size(), last_to_expire[5]->reason.ptr())); + } + if (last_to_expire[6] != nullptr) // Alert + { + unsigned int serverCount = serverManager->size(); + IRC_Bot *server; + Jupiter::IRC::Client::Channel *channel; + unsigned int channelCount; + Jupiter::String &fmtName = RenX::getFormattedPlayerName(player); + Jupiter::StringL msg = Jupiter::StringL::Format(IRCCOLOR "04[Alert] " IRCCOLOR IRCBOLD "%.*s" IRCBOLD IRCCOLOR " is marked for monitoring by %.*s for: \"%.*s\". Please keep an eye on them in ", fmtName.size(), fmtName.ptr(), last_to_expire[6]->banner.size(), last_to_expire[6]->banner.ptr(), last_to_expire[6]->reason.size(), last_to_expire[6]->reason.ptr()); + Jupiter::StringS msg2 = Jupiter::StringS::Format(IRCCOLOR "04[Alert] " IRCCOLOR IRCBOLD "%.*s" IRCBOLD IRCCOLOR " is marked for monitoring by %.*s for: \"%.*s\"." IRCCOLOR, fmtName.size(), fmtName.ptr(), last_to_expire[6]->banner.size(), last_to_expire[6]->banner.ptr(), last_to_expire[6]->reason.size(), last_to_expire[6]->reason.ptr()); + for (unsigned int a = 0; a < serverCount; a++) + { + server = serverManager->getServer(a); + channelCount = server->getChannelCount(); + for (unsigned int b = 0; b < channelCount; b++) + { + channel = server->getChannel(b); + if (this->isAdminLogChanType(channel->getType())) + { + server->sendMessage(channel->getName(), msg2); + msg += channel->getName(); + for (unsigned int c = 0; c < channel->getUserCount(); c++) + if (channel->getUserPrefix(c) != 0 && channel->getUser(c)->getNickname().equals(server->getNickname()) == false) + server->sendMessage(channel->getUser(c)->getUser()->getNickname(), msg); + msg -= channel->getName().size(); + } + } + } + } + } +}; + void RenX::Server::banPlayer(int id, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason) { if (RenX::Server::rconBan) @@ -406,9 +570,9 @@ void RenX::Server::banPlayer(const RenX::PlayerInfo *player, const Jupiter::Read RenX::Server::forceKickPlayer(player, Jupiter::StringS::Format("You are permanently banned from the server for: %.*s", reason.size(), reason.ptr())); } else if (banner.isNotEmpty()) - RenX::Server::forceKickPlayer(player, Jupiter::StringS::Format("You are banned from the server by %.*s for the next %d days, %d:%d:%d for: %.*s", banner.size(), banner.ptr(), length / 86400, length % 3600, (length % 3600) / 60, length % 60, reason.size(), reason.ptr())); + RenX::Server::forceKickPlayer(player, Jupiter::StringS::Format("You are banned from the server by %.*s for the next %lld days, %.2d:%.2d:%.2d for: %.*s", banner.size(), banner.ptr(), static_cast(length / 86400), static_cast(length % 3600), static_cast((length % 3600) / 60), static_cast(length % 60), reason.size(), reason.ptr())); else - RenX::Server::forceKickPlayer(player, Jupiter::StringS::Format("You are banned from the server for the next %d days, %d:%d:%d for: %.*s", length/86400, length%3600, (length%3600)/60, length%60, reason.size(), reason.ptr())); + RenX::Server::forceKickPlayer(player, Jupiter::StringS::Format("You are banned from the server for the next %lld days, %.2d:%.2d:%.2d for: %.*s", static_cast(length/86400), static_cast(length%3600), static_cast((length%3600)/60), static_cast(length%60), reason.size(), reason.ptr())); } bool RenX::Server::removePlayer(int id) @@ -521,7 +685,7 @@ bool RenX::Server::unmute(const RenX::PlayerInfo *player) bool RenX::Server::giveCredits(int id, double credits) { - return RenX::Server::send(Jupiter::StringS::Format("givecredits pid%d %f", id, credits)) > 0; + return RenX::Server::competitive == false && RenX::Server::send(Jupiter::StringS::Format("givecredits pid%d %f", id, credits)) > 0; } bool RenX::Server::giveCredits(RenX::PlayerInfo *player, double credits) @@ -531,7 +695,7 @@ bool RenX::Server::giveCredits(RenX::PlayerInfo *player, double credits) bool RenX::Server::kill(int id) { - return RenX::Server::send(Jupiter::StringS::Format("kill pid%d", id)) > 0; + return RenX::Server::competitive == false && RenX::Server::send(Jupiter::StringS::Format("kill pid%d", id)) > 0; } bool RenX::Server::kill(RenX::PlayerInfo *player) @@ -541,7 +705,7 @@ bool RenX::Server::kill(RenX::PlayerInfo *player) bool RenX::Server::disarm(int id) { - return RenX::Server::send(Jupiter::StringS::Format("disarm pid%d", id)) > 0; + return RenX::Server::competitive == false && RenX::Server::send(Jupiter::StringS::Format("disarm pid%d", id)) > 0; } bool RenX::Server::disarm(RenX::PlayerInfo *player) @@ -551,7 +715,7 @@ bool RenX::Server::disarm(RenX::PlayerInfo *player) bool RenX::Server::disarmC4(int id) { - return RenX::Server::send(Jupiter::StringS::Format("disarmc4 pid%d", id)) > 0; + return RenX::Server::competitive == false && RenX::Server::send(Jupiter::StringS::Format("disarmc4 pid%d", id)) > 0; } bool RenX::Server::disarmC4(RenX::PlayerInfo *player) @@ -561,7 +725,7 @@ bool RenX::Server::disarmC4(RenX::PlayerInfo *player) bool RenX::Server::disarmBeacon(int id) { - return RenX::Server::send(Jupiter::StringS::Format("disarmb pid%d", id)) > 0; + return RenX::Server::competitive == false && RenX::Server::send(Jupiter::StringS::Format("disarmb pid%d", id)) > 0; } bool RenX::Server::disarmBeacon(RenX::PlayerInfo *player) @@ -1033,156 +1197,6 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) isBot = false; id = idToken.asInt(10); }; - auto banCheck = [this](RenX::PlayerInfo *player) - { - const Jupiter::ArrayList &entries = RenX::banDatabase->getEntries(); - RenX::BanDatabase::Entry *entry = nullptr; - uint32_t netmask; - - RenX::BanDatabase::Entry *last_to_expire[7]; - for (size_t index = 0; index != sizeof(last_to_expire); ++index) - last_to_expire[index] = nullptr; - - auto handle_type = [entry](RenX::BanDatabase::Entry *&last_to_expire) - { - if (last_to_expire == nullptr) - last_to_expire = entry; - else if (last_to_expire->length == 0) - { - // favor older bans if they're also permanent - if (entry->length == 0 && entry->timestamp < last_to_expire->timestamp) - last_to_expire = entry; - } - else if (entry->length == 0 || entry->timestamp + entry->length > last_to_expire->timestamp + last_to_expire->length) - last_to_expire = entry; - }; - - for (size_t i = 0; i != entries.size(); i++) - { - entry = entries.get(i); - if (entry->is_active()) - { - if (entry->length != 0 && entry->timestamp + entry->length < time(0)) - banDatabase->deactivate(i); - else - { - if (entry->prefix_length >= 32) - netmask = 0xFFFFFFFF; - else - netmask = Jupiter_prefix_length_to_netmask(entry->prefix_length); - - if ((this->localSteamBan && entry->steamid != 0 && entry->steamid == player->steamid) - || (this->localIPBan && entry->ip != 0 && (entry->ip & netmask) == (player->ip32 & netmask)) - || (this->localRDNSBan && entry->rdns.isNotEmpty() && entry->is_rdns_ban() && player->rdns.match(entry->rdns)) - || (this->localNameBan && entry->name.isNotEmpty() && entry->name.equalsi(player->name))) - { - player->ban_flags |= entry->flags; - if (entry->is_type_game()) - handle_type(last_to_expire[0]); - if (entry->is_type_chat()) - handle_type(last_to_expire[1]); - if (entry->is_type_bot()) - handle_type(last_to_expire[2]); - if (entry->is_type_vote()) - handle_type(last_to_expire[3]); - if (entry->is_type_mine()) - handle_type(last_to_expire[4]); - if (entry->is_type_ladder()) - handle_type(last_to_expire[5]); - if (entry->is_type_alert()) - handle_type(last_to_expire[6]); - } - } - } - } - - char timeStr[256]; - if (last_to_expire[0] != nullptr) // Game ban - { - strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[0]->timestamp + last_to_expire[0]->length))); - if (last_to_expire[0]->length == 0) - this->forceKickPlayer(player, Jupiter::StringS::Format("You were permanently banned from the server on %s for: %.*s", timeStr, last_to_expire[0]->reason.size(), last_to_expire[0]->reason.ptr())); - else - this->forceKickPlayer(player, Jupiter::StringS::Format("You are banned from the server until %s for: %.*s", timeStr, last_to_expire[0]->reason.size(), last_to_expire[0]->reason.ptr())); - - player->ban_flags |= RenX::BanDatabase::Entry::FLAG_TYPE_BOT; // implies FLAG_TYPE_BOT - } - else - { - if (last_to_expire[1] != nullptr) // Chat ban - { - strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[1]->timestamp + last_to_expire[1]->length))); - this->mute(player); - if (last_to_expire[1]->length == 0) - this->sendMessage(player, Jupiter::StringS::Format("You were permanently muted on this server on %s for: %.*s", timeStr, last_to_expire[1]->reason.size(), last_to_expire[1]->reason.ptr())); - else - this->sendMessage(player, Jupiter::StringS::Format("You are muted on this server until %s for: %.*s", timeStr, last_to_expire[1]->reason.size(), last_to_expire[1]->reason.ptr())); - - player->ban_flags |= RenX::BanDatabase::Entry::FLAG_TYPE_BOT; // implies FLAG_TYPE_BOT - } - else if (last_to_expire[2] != nullptr) // Bot ban - { - strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[2]->timestamp + last_to_expire[2]->length))); - if (last_to_expire[2]->length == 0) - this->sendMessage(player, Jupiter::StringS::Format("You were permanently bot-muted on this server on %s for: %.*s", timeStr, last_to_expire[2]->reason.size(), last_to_expire[2]->reason.ptr())); - else - this->sendMessage(player, Jupiter::StringS::Format("You are bot-muted on this server until %s for: %.*s", timeStr, last_to_expire[2]->reason.size(), last_to_expire[2]->reason.ptr())); - } - if (last_to_expire[3] != nullptr) // Vote ban - { - strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[3]->timestamp + last_to_expire[3]->length))); - if (last_to_expire[3]->length == 0) - this->sendMessage(player, Jupiter::StringS::Format("You were permanently vote-muted on this server on %s for: %.*s", timeStr, last_to_expire[3]->reason.size(), last_to_expire[3]->reason.ptr())); - else - this->sendMessage(player, Jupiter::StringS::Format("You are vote-muted on this server until %s for: %.*s", timeStr, last_to_expire[3]->reason.size(), last_to_expire[3]->reason.ptr())); - } - if (last_to_expire[4] != nullptr) // Mine ban - { - this->mineBan(player); - strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[4]->timestamp + last_to_expire[4]->length))); - if (last_to_expire[4]->length == 0) - this->sendMessage(player, Jupiter::StringS::Format("You were permanently mine-banned on this server on %s for: %.*s", timeStr, last_to_expire[4]->reason.size(), last_to_expire[4]->reason.ptr())); - else - this->sendMessage(player, Jupiter::StringS::Format("You are mine-banned on this server until %s for: %.*s", timeStr, last_to_expire[4]->reason.size(), last_to_expire[4]->reason.ptr())); - } - if (last_to_expire[5] != nullptr) // Ladder ban - { - strftime(timeStr, sizeof(timeStr), "%b %d %Y at %H:%M:%S", localtime(std::addressof(last_to_expire[5]->timestamp + last_to_expire[5]->length))); - if (last_to_expire[5]->length == 0) - this->sendMessage(player, Jupiter::StringS::Format("You were permanently ladder-banned on this server on %s for: %.*s", timeStr, last_to_expire[5]->reason.size(), last_to_expire[5]->reason.ptr())); - else - this->sendMessage(player, Jupiter::StringS::Format("You are ladder-banned on this server until %s for: %.*s", timeStr, last_to_expire[5]->reason.size(), last_to_expire[5]->reason.ptr())); - } - if (last_to_expire[6] != nullptr) // Alert - { - unsigned int serverCount = serverManager->size(); - IRC_Bot *server; - Jupiter::IRC::Client::Channel *channel; - unsigned int channelCount; - Jupiter::String &fmtName = RenX::getFormattedPlayerName(player); - Jupiter::StringL msg = Jupiter::StringL::Format(IRCCOLOR "04[Alert] " IRCCOLOR IRCBOLD "%.*s" IRCBOLD IRCCOLOR " is marked for monitoring by %.*s for: \"%.*s\". Please keep an eye on them in ", fmtName.size(), fmtName.ptr(), last_to_expire[6]->banner.size(), last_to_expire[6]->banner.ptr(), last_to_expire[6]->reason.size(), last_to_expire[6]->reason.ptr()); - Jupiter::StringS msg2 = Jupiter::StringS::Format(IRCCOLOR "04[Alert] " IRCCOLOR IRCBOLD "%.*s" IRCBOLD IRCCOLOR " is marked for monitoring by %.*s for: \"%.*s\"." IRCCOLOR, fmtName.size(), fmtName.ptr(), last_to_expire[6]->banner.size(), last_to_expire[6]->banner.ptr(), last_to_expire[6]->reason.size(), last_to_expire[6]->reason.ptr()); - for (unsigned int a = 0; a < serverCount; a++) - { - server = serverManager->getServer(a); - channelCount = server->getChannelCount(); - for (unsigned int b = 0; b < channelCount; b++) - { - channel = server->getChannel(b); - if (this->isAdminLogChanType(channel->getType())) - { - server->sendMessage(channel->getName(), msg2); - msg += channel->getName(); - for (unsigned int c = 0; c < channel->getUserCount(); c++) - if (channel->getUserPrefix(c) != 0 && channel->getUser(c)->getNickname().equals(server->getNickname()) == false) - server->sendMessage(channel->getUser(c)->getUser()->getNickname(), msg); - msg -= channel->getName().size(); - } - } - } - } - } - }; auto getPlayerOrAdd = [&](const Jupiter::ReadableString &name, int id, RenX::TeamType team, bool isBot, uint64_t steamid, const Jupiter::ReadableString &ip) { RenX::PlayerInfo *r = this->getPlayer(id); @@ -1204,7 +1218,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) this->players.add(r); r->uuid = calc_uuid(r); - banCheck(r); + this->banCheck(r); for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnPlayerCreate(this, r); @@ -1233,7 +1247,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) if (recalcUUID) { this->setUUIDIfDifferent(r, calc_uuid(r)); - banCheck(r); + this->banCheck(r); } } return r; @@ -1598,18 +1612,23 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) } else if (this->lastCommand.equalsi("gameinfo"_jrs)) { - // "PlayerLimit" | PlayerLimit | "VehicleLimit" | VehicleLimit | "MineLimit" | MineLimit | "TimeLimit" | TimeLimit | "bPassworded" | bPassworded | "bSteamRequired" | bSteamRequired | "bPrivateMessageTeamOnly" | bPrivateMessageTeamOnly | "bAllowPrivateMessaging" | bAllowPrivateMessaging | "bAutoBalanceTeams" | bAutoBalanceTeams | "bSpawnCrates" | bSpawnCrates | "CrateRespawnAfterPickup" | CrateRespawnAfterPickup - this->playerLimit = tokens.getToken(1).asInt(); - this->vehicleLimit = tokens.getToken(3).asInt(); - this->mineLimit = tokens.getToken(5).asInt(); - this->timeLimit = tokens.getToken(7).asInt(); - this->passworded = tokens.getToken(9).asBool(); - this->steamRequired = tokens.getToken(11).asBool(); - this->privateMessageTeamOnly = tokens.getToken(13).asBool(); - this->allowPrivateMessaging = tokens.getToken(15).asBool(); - this->autoBalanceTeams = tokens.getToken(17).asBool(); - this->spawnCrates = tokens.getToken(19).asBool(); - this->crateRespawnAfterPickup = tokens.getToken(21).asDouble(); + if (this->lastCommandParams.isEmpty()) + { + // "PlayerLimit" | PlayerLimit | "VehicleLimit" | VehicleLimit | "MineLimit" | MineLimit | "TimeLimit" | TimeLimit | "bPassworded" | bPassworded | "bSteamRequired" | bSteamRequired | "bPrivateMessageTeamOnly" | bPrivateMessageTeamOnly | "bAllowPrivateMessaging" | bAllowPrivateMessaging | "bAutoBalanceTeams" | bAutoBalanceTeams | "bSpawnCrates" | bSpawnCrates | "CrateRespawnAfterPickup" | CrateRespawnAfterPickup | bIsCompetitive | "bIsCompetitive" + this->playerLimit = tokens.getToken(1).asInt(); + this->vehicleLimit = tokens.getToken(3).asInt(); + this->mineLimit = tokens.getToken(5).asInt(); + this->timeLimit = tokens.getToken(7).asInt(); + this->passworded = tokens.getToken(9).asBool(); + this->steamRequired = tokens.getToken(11).asBool(); + this->privateMessageTeamOnly = tokens.getToken(13).asBool(); + this->allowPrivateMessaging = tokens.getToken(15).asBool(); + this->autoBalanceTeams = tokens.getToken(17).asBool(); + this->spawnCrates = tokens.getToken(19).asBool(); + this->crateRespawnAfterPickup = tokens.getToken(21).asDouble(); + } + else if (this->lastCommandParams.equalsi("bIsCompetitive")) + this->competitive = tokens.getToken(0).asBool(); } else if (this->lastCommand.equalsi("mutatorlist"_jrs)) { @@ -2233,7 +2252,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) if (player != nullptr) { player->id = tokens.getToken(3).asInt(); - banCheck(player); + this->banCheck(player); for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnIDChange(this, player, oldID); } @@ -2638,6 +2657,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) RenX::Server::sock.send("s\n"_jrs); RenX::Server::send("serverinfo"_jrs); RenX::Server::send("gameinfo"_jrs); + RenX::Server::send("gameinfo bIsCompetitive"_jrs); RenX::Server::send("mutatorlist"_jrs); RenX::Server::send("rotation"_jrs); RenX::Server::fetchClientList(); diff --git a/RenX.Core/RenX_Server.h b/RenX.Core/RenX_Server.h index f96ebb2..4fa2ebc 100644 --- a/RenX.Core/RenX_Server.h +++ b/RenX.Core/RenX_Server.h @@ -138,6 +138,13 @@ namespace RenX */ bool isSeamless() const; + /** + * @brief Checks if the server is marked as competitive. + * + * @return True if the server is a competitive server, false otherwise. + */ + bool isCompetitive() const; + /** * @brief Checks if a channel type is a public channel type. * @@ -334,6 +341,19 @@ namespace RenX */ void forceKickPlayer(const RenX::PlayerInfo *player, const Jupiter::ReadableString &reason); + /** + * @brief Checks if any players are in the ban list, and kicks any players listed. + */ + void banCheck(); + + /** + * @brief Checks if a player is in the ban list, and kicks them if they are. + * Note: Check a player's ban_flags to see what ban types are active on them. + * + * @param player Data of the player to check. + */ + void banCheck(RenX::PlayerInfo *player); + /** * @brief Bans a player from the server. * @@ -911,6 +931,7 @@ namespace RenX bool allowPrivateMessaging = true; bool autoBalanceTeams = true; bool spawnCrates = true; + bool competitive = false; int attempts = 0; int playerLimit = 0; int vehicleLimit = 0; diff --git a/RenX.ModSystem/RenX_ModSystem.cpp b/RenX.ModSystem/RenX_ModSystem.cpp index f555cef..4c4f1c1 100644 --- a/RenX.ModSystem/RenX_ModSystem.cpp +++ b/RenX.ModSystem/RenX_ModSystem.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014-2015 Jessica James. + * Copyright (C) 2014-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -173,9 +173,11 @@ int RenX_ModSystemPlugin::auth(RenX::Server *server, const RenX::PlayerInfo *pla player->gamePrefix = section->get(STRING_LITERAL_AS_REFERENCE("GamePrefix"), group->gamePrefix); player->access = section->getInt(STRING_LITERAL_AS_REFERENCE("Access"), group->access); if (player->access != 0) + { server->sendMessage(player, Jupiter::StringS::Format("You are now authenticated with access level %d; group: %.*s.", player->access, group->name.size(), group->name.ptr())); - if (server->getRCONUsername().equals("DevBot"_jrs)) - server->sendData(Jupiter::StringS::Format("d%d\n", player->id)); + if (server->getRCONUsername().equals("DevBot"_jrs)) + server->sendData(Jupiter::StringS::Format("d%d\n", player->id)); + } Jupiter::String playerName = RenX::getFormattedPlayerName(player); server->sendLogChan(IRCCOLOR "03[Authentication] " IRCBOLD "%.*s" IRCBOLD IRCCOLOR " is now authenticated with access level %d; group: %.*s.", playerName.size(), playerName.ptr(), player->access, group->name.size(), group->name.ptr()); return player->access; @@ -354,6 +356,12 @@ void RenX_ModSystemPlugin::RenX_OnPlayerDelete(RenX::Server *server, const RenX: } } +void RenX_ModSystemPlugin::RenX_OnIDChange(RenX::Server *server, const RenX::PlayerInfo *player, int oldID) +{ + if (player->access != 0 && server->getRCONUsername().equals("DevBot"_jrs)) + server->sendData(Jupiter::StringS::Format("d%d\n", player->id)); +} + void RenX_ModSystemPlugin::RenX_OnAdminLogin(RenX::Server *server, const RenX::PlayerInfo *player) { ModGroup *group = nullptr; diff --git a/RenX.ModSystem/RenX_ModSystem.h b/RenX.ModSystem/RenX_ModSystem.h index db069ec..a01ccff 100644 --- a/RenX.ModSystem/RenX_ModSystem.h +++ b/RenX.ModSystem/RenX_ModSystem.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014-2015 Jessica James. + * Copyright (C) 2014-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -95,6 +95,8 @@ public: // RenX::Plugin void RenX_OnPlayerCreate(RenX::Server *server, const RenX::PlayerInfo *player) override; void RenX_OnPlayerDelete(RenX::Server *server, const RenX::PlayerInfo *player) override; + void RenX_OnIDChange(RenX::Server *server, const RenX::PlayerInfo *player, int oldID) override; + void RenX_OnAdminLogin(RenX::Server *server, const RenX::PlayerInfo *player) override; void RenX_OnAdminGrant(RenX::Server *server, const RenX::PlayerInfo *player) override; void RenX_OnAdminLogout(RenX::Server *server, const RenX::PlayerInfo *player) override;