diff --git a/Jupiter b/Jupiter index 2359036..b5d253d 160000 --- a/Jupiter +++ b/Jupiter @@ -1 +1 @@ -Subproject commit 23590369846084db28456549162ecfa530fc0a81 +Subproject commit b5d253da72553929b18a805c01fc2999568d99e3 diff --git a/Jupiter Bot.sln b/Jupiter Bot.sln index ca2ba27..df7ca2c 100644 --- a/Jupiter Bot.sln +++ b/Jupiter Bot.sln @@ -121,6 +121,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenX.IRCJoin", "RenX.IRCJoi {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} = {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenX.ModSystem", "RenX.ModSystem\RenX.ModSystem.vcxproj", "{160CD71B-1E13-4816-9977-8BBD73871F31}" + ProjectSection(ProjectDependencies) = postProject + {C188871B-5F32-4946-B301-24CA2EBB275D} = {C188871B-5F32-4946-B301-24CA2EBB275D} + {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} = {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -211,6 +217,10 @@ Global {672B3FC9-0B31-45B4-AAB6-669073F2D291}.Debug|Win32.Build.0 = Debug|Win32 {672B3FC9-0B31-45B4-AAB6-669073F2D291}.Release|Win32.ActiveCfg = Release|Win32 {672B3FC9-0B31-45B4-AAB6-669073F2D291}.Release|Win32.Build.0 = Release|Win32 + {160CD71B-1E13-4816-9977-8BBD73871F31}.Debug|Win32.ActiveCfg = Debug|Win32 + {160CD71B-1E13-4816-9977-8BBD73871F31}.Debug|Win32.Build.0 = Debug|Win32 + {160CD71B-1E13-4816-9977-8BBD73871F31}.Release|Win32.ActiveCfg = Release|Win32 + {160CD71B-1E13-4816-9977-8BBD73871F31}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Release/Bot.lib b/Release/Bot.lib index 818d01d..2e4891d 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 c1ed572..1978e7f 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Core/RenX_Core.cpp b/RenX.Core/RenX_Core.cpp index b9c6b99..76be9f7 100644 --- a/RenX.Core/RenX_Core.cpp +++ b/RenX.Core/RenX_Core.cpp @@ -38,8 +38,9 @@ RenX::Core::Core() { const Jupiter::ReadableString &serverList = Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("Servers")); RenX::Core::translationsFile.readFile(Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("TranslationsFile"), STRING_LITERAL_AS_REFERENCE("Translations.ini"))); - RenX::initTranslations(RenX::Core::translationsFile); + RenX::Core::commandsFile.readFile(Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("CommandsFile"), STRING_LITERAL_AS_REFERENCE("RenXGameCommands.ini"))); + unsigned int wc = serverList.wordCount(WHITESPACE); RenX::Server *server; @@ -136,6 +137,11 @@ Jupiter::INIFile &RenX::Core::getTranslationsFile() return RenX::Core::translationsFile; } +Jupiter::INIFile &RenX::Core::getCommandsFile() +{ + return RenX::Core::commandsFile; +} + int RenX::Core::addCommand(RenX::GameCommand *command) { for (size_t i = 0; i != RenX::Core::servers.size(); i++) diff --git a/RenX.Core/RenX_Core.h b/RenX.Core/RenX_Core.h index cdbd674..c61c558 100644 --- a/RenX.Core/RenX_Core.h +++ b/RenX.Core/RenX_Core.h @@ -150,6 +150,13 @@ namespace RenX */ Jupiter::INIFile &getTranslationsFile(); + /** + * @brief Fetches the commands settings file. + * + * @return Commands settings configuration file. + */ + Jupiter::INIFile &getCommandsFile(); + /** * @brief Copys a command, and passes it to each server. * @@ -174,6 +181,7 @@ namespace RenX Jupiter::ArrayList servers; Jupiter::ArrayList plugins; Jupiter::INIFile translationsFile; + Jupiter::INIFile commandsFile; }; RENX_API Core *getCore(); diff --git a/RenX.Core/RenX_GameCommand.cpp b/RenX.Core/RenX_GameCommand.cpp index 6f65b56..7ff2c63 100644 --- a/RenX.Core/RenX_GameCommand.cpp +++ b/RenX.Core/RenX_GameCommand.cpp @@ -48,4 +48,14 @@ RenX::GameCommand::~GameCommand() break; } } +} + +int RenX::GameCommand::getAccessLevel() +{ + return RenX::GameCommand::access; +} + +void RenX::GameCommand::setAccessLevel(int accessLevel) +{ + RenX::GameCommand::access = accessLevel; } \ No newline at end of file diff --git a/RenX.Core/RenX_GameCommand.h b/RenX.Core/RenX_GameCommand.h index 6c04632..a4f7e41 100644 --- a/RenX.Core/RenX_GameCommand.h +++ b/RenX.Core/RenX_GameCommand.h @@ -45,6 +45,20 @@ namespace RenX { public: + /** + * @brief Fetches a command's minimum access level. + * + * @return Minimum access level. + */ + int getAccessLevel(); + + /** + * @brief Sets a command's minimum access level. + * + * @param accessLevel Access level. + */ + void setAccessLevel(int accessLevel); + /** * @brief Called when a player with the proper access privledges executes this command. * @@ -82,6 +96,9 @@ namespace RenX * Note: This is not automatically generated by any macro, and is available for use. */ virtual ~GameCommand(); + + private: + int access; /** Minimum access level */ }; } diff --git a/RenX.Core/RenX_PlayerInfo.h b/RenX.Core/RenX_PlayerInfo.h index 8f3a59c..bc52efe 100644 --- a/RenX.Core/RenX_PlayerInfo.h +++ b/RenX.Core/RenX_PlayerInfo.h @@ -60,6 +60,7 @@ namespace RenX unsigned int wins = 0; unsigned int loses = 0; unsigned int beaconPlacements = 0; + int access = 0; mutable Jupiter::INIFile varData; // This will be replaced later with a more dedicated type. }; diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index 5ef44ce..3bd7ea4 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -67,6 +67,50 @@ int RenX::Server::think() return 0; } +int RenX::Server::OnRehash() +{ + Jupiter::StringS oldHostname = RenX::Server::hostname; + unsigned short oldPort = RenX::Server::port; + Jupiter::StringS oldClientHostname = RenX::Server::clientHostname; + Jupiter::StringS oldPass = RenX::Server::pass; + unsigned int oldUUIDMode = RenX::Server::uuidMode; + int oldSteamFormat = RenX::Server::steamFormat; + RenX::Server::commands.emptyAndDelete(); + RenX::Server::init(); + if (oldHostname.equalsi(RenX::Server::hostname) && oldPort == RenX::Server::port && oldClientHostname.equalsi(RenX::Server::clientHostname) && oldPass.equalsi(RenX::Server::pass)) + { + if ((oldUUIDMode != RenX::Server::uuidMode || (RenX::Server::uuidMode == 0 && oldSteamFormat != RenX::Server::steamFormat)) && RenX::Server::players.size() != 0) + { + RenX::PlayerInfo *player; + for (Jupiter::DLList::Node *n = RenX::Server::players.getNode(0); n != nullptr; n = n->next) + { + player = n->data; + switch (this->uuidMode) + { + default: + case 0: + if (player->steamid != 0) + player->uuid = this->formatSteamID(player); + else + player->uuid = Jupiter::ReferenceString::empty; + break; + case 1: + player->uuid = player->name; + break; + } + } + } + } + else + RenX::Server::reconnect(); + return 0; +} + +bool RenX::Server::OnBadRehash(bool removed) +{ + return removed; +} + bool RenX::Server::isConnected() const { return RenX::Server::connected; @@ -861,6 +905,10 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) if (action.equals("logged in as")) { player->adminType = buff.getWord(3, RenX::DelimS); + if (player->adminType.equalsi("moderator") && player->access < 1) + player->access = 1; + else if (player->adminType.equalsi("administrator") && player->access < 2) + player->access = 2; for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnAdminLogin(this, player); } @@ -870,10 +918,15 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnAdminLogout(this, player); player->adminType = ""; + player->access = 0; } else if (action.equals("granted")) { player->adminType = buff.getWord(3, RenX::DelimS); + if (player->adminType.equalsi("moderator") && player->access < 1) + player->access = 1; + else if (player->adminType.equalsi("administrator") && player->access < 2) + player->access = 2; for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnAdminGrant(this, player); } @@ -1017,7 +1070,7 @@ bool RenX::Server::connect() bool RenX::Server::reconnect() { - RenX::Server::sock.closeSocket(); + RenX::Server::disconnect(); return RenX::Server::connect(); } @@ -1026,7 +1079,6 @@ void RenX::Server::wipeData() RenX::Server::rconUser.truncate(RenX::Server::rconUser.size()); while (RenX::Server::players.size() != 0) delete RenX::Server::players.remove(0U); - RenX::Server::commands.emptyAndDelete(); } unsigned int RenX::Server::getVersion() const @@ -1047,11 +1099,14 @@ const Jupiter::ReadableString &RenX::Server::getRCONUsername() const RenX::Server::Server(const Jupiter::ReadableString &configurationSection) { RenX::Server::configSection = configurationSection; + init(); +} +void RenX::Server::init() +{ RenX::Server::hostname = Jupiter::IRC::Client::Config->get(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("Hostname"), STRING_LITERAL_AS_REFERENCE("localhost")); RenX::Server::port = (unsigned short)Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("Port"), 7777); RenX::Server::clientHostname = Jupiter::IRC::Client::Config->get(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("ClientAddress")); - RenX::Server::pass = Jupiter::IRC::Client::Config->get(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("Password"), STRING_LITERAL_AS_REFERENCE("renx")); RenX::Server::logChanType = Jupiter::IRC::Client::Config->getShort(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("ChanType")); @@ -1066,12 +1121,34 @@ RenX::Server::Server(const Jupiter::ReadableString &configurationSection) RenX::Server::steamFormat = Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("SteamFormat"), 16); RenX::Server::neverSay = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("NeverSay"), false); - for (size_t i = 0; i < RenX::GameMasterCommandList->size(); i++) - RenX::Server::addCommand(RenX::GameMasterCommandList->get(i)->copy()); + Jupiter::INIFile &commandsFile = RenX::getCore()->getCommandsFile(); + RenX::Server::commandAccessLevels = commandsFile.getSection(RenX::Server::configSection); + RenX::Server::commandAliases = commandsFile.getSection(Jupiter::StringS::Format("%.*s.Aliases", RenX::Server::configSection.size(), RenX::Server::configSection.ptr())); + + RenX::GameCommand *cmd; + for (size_t i = 0, j; i < RenX::GameMasterCommandList->size(); i++) + { + cmd = RenX::GameMasterCommandList->get(i)->copy(); + RenX::Server::addCommand(cmd); + if (commandAccessLevels != nullptr) + { + const Jupiter::ReadableString &accessLevel = RenX::Server::commandAccessLevels->getValue(cmd->getTrigger()); + if (accessLevel.isEmpty() == false) + cmd->setAccessLevel(accessLevel.asInt()); + } + if (commandAliases != nullptr) + { + const Jupiter::ReadableString &aliasList = RenX::Server::commandAliases->getValue(cmd->getTrigger()); + j = aliasList.wordCount(WHITESPACE); + while (j != 0) + cmd->addTrigger(Jupiter::ReferenceString::getWord(aliasList, --j, WHITESPACE)); + } + } } RenX::Server::~Server() { sock.closeSocket(); RenX::Server::wipeData(); + RenX::Server::commands.emptyAndDelete(); } diff --git a/RenX.Core/RenX_Server.h b/RenX.Core/RenX_Server.h index b28848c..9705adb 100644 --- a/RenX.Core/RenX_Server.h +++ b/RenX.Core/RenX_Server.h @@ -30,6 +30,7 @@ #include "Jupiter/CString.h" #include "Jupiter/INIFile.h" #include "Jupiter/Thinker.h" +#include "Jupiter/Rehash.h" #include "RenX.h" #include "RenX_ServerProfile.h" @@ -50,7 +51,7 @@ namespace RenX * @brief Represents a connection to an individiaul Renegade-X server. * There are often more than one of these, such as when communities run multiple servers. */ - class RENX_API Server : public Jupiter::Thinker + class RENX_API Server : public Jupiter::Thinker, public Jupiter::Rehashable { public: // Jupiter::Thinker @@ -61,6 +62,23 @@ namespace RenX */ int think(); + public: // Jupiter::Rehashable + + /** + * @brief Rehashes an object's status. + * + * @return 0. + */ + virtual int OnRehash(); + + /** + * @brief Fires when a non-zero value is returned by an object during a call to rehash(). + * + * @param removed True if the object was removed from the rehashable objects list, false otherwise. + * @return True if the object should be deleted, false otherwise. + */ + virtual bool OnBadRehash(bool removed); + public: // RenX::Server Jupiter::DLList players; /** A list of players in the server */ Jupiter::INIFile varData; /** This may be replaced later with a more dedicated type. */ @@ -481,6 +499,8 @@ namespace RenX /** Private members */ private: + void init(); + /** Tracking variables */ bool connected = false; bool needsCList = false; @@ -513,6 +533,8 @@ namespace RenX Jupiter::StringS IRCPrefix; Jupiter::StringS CommandPrefix; Jupiter::StringS rconUser; + Jupiter::INIFile::Section *commandAccessLevels; + Jupiter::INIFile::Section *commandAliases; }; }