diff --git a/HTTPServer/HTTPServer.cpp b/HTTPServer/HTTPServer.cpp new file mode 100644 index 0000000..96c0b56 --- /dev/null +++ b/HTTPServer/HTTPServer.cpp @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2015-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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#include "Jupiter/INIFile.h" +#include "Jupiter/IRC_Client.h" +#include "HTTPServer.h" + +using namespace Jupiter::literals; + +HTTPServerPlugin::HTTPServerPlugin() +{ + HTTPServerPlugin::server.bind(Jupiter::IRC::Client::Config->get(HTTPServerPlugin::name, "BindAddress"_jrs, "0.0.0.0"_jrs), Jupiter::IRC::Client::Config->getInt(HTTPServerPlugin::name, "BindPort"_jrs, 80)); +} + +int HTTPServerPlugin::think() +{ + return HTTPServerPlugin::server.think(); +} + +// Plugin instantiation and entry point. +HTTPServerPlugin pluginInstance; + +HTTPServerPlugin &getHTTPServerPlugin() +{ + return pluginInstance; +} + +Jupiter::HTTP::Server &getHTTPServer() +{ + return pluginInstance.server; +} + +extern "C" __declspec(dllexport) Jupiter::Plugin *getPlugin() +{ + return &pluginInstance; +} diff --git a/HTTPServer/HTTPServer.h b/HTTPServer/HTTPServer.h new file mode 100644 index 0000000..0dabdee --- /dev/null +++ b/HTTPServer/HTTPServer.h @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#if !defined _HTTPSERVER_H_HEADER +#define _HTTPSERVER_H_HEADER + + /** + * @file HTTPServer.h + * @brief Provides an interface to push HTTP data to HTTP clients. + */ + +#if defined _WIN32 + +#include "Jupiter/Plugin.h" +#include "Jupiter/Reference_String.h" +#include "Jupiter/String.h" +#include "Jupiter/HTTP_Server.h" + +#if defined HTTPSERVER_EXPORTS +#define HTTPSERVER_API __declspec(dllexport) +#else // HTTPSERVER_EXPORTS +#define HTTPSERVER_API __declspec(dllimport) +#endif // HTTPSERVER_EXPORTS + +#else // _WIN32 +#define HTTPSERVER_API +#endif // _WIN32 + +/** DLL Linkage Nagging */ +#if defined _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4251) +#endif + +/** +* @brief Instantiates an instance of Jupiter::HTTP::Server to permit declaration of HTTP pages. +*/ +class HTTPSERVER_API HTTPServerPlugin : public Jupiter::Plugin +{ +public: + HTTPServerPlugin(); + Jupiter::HTTP::Server server; + +public: // Jupiter::Plugin + const Jupiter::ReadableString &getName() override { return name; } + int think() override; + +private: + STRING_LITERAL_AS_NAMED_REFERENCE(name, "HTTPServer"); +}; + +HTTPSERVER_API HTTPServerPlugin &getHTTPServerPlugin(); +HTTPSERVER_API Jupiter::HTTP::Server &getHTTPServer(); + +/** Re-enable warnings */ +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#endif // _HTTPSERVER_H_HEADER \ No newline at end of file diff --git a/HTTPServer/HTTPServer.vcxproj b/HTTPServer/HTTPServer.vcxproj new file mode 100644 index 0000000..52d83e0 --- /dev/null +++ b/HTTPServer/HTTPServer.vcxproj @@ -0,0 +1,84 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {BB048D6F-F001-4E9B-95F4-886081E0807A} + HTTPServer + + + + Application + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\Plugins\ + AllRules.ruleset + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + ../Bot;../Jupiter + _CRT_SECURE_NO_WARNINGS;HTTPSERVER_EXPORTS;%(PreprocessorDefinitions) + + + true + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HTTPServer/HTTPServer.vcxproj.filters b/HTTPServer/HTTPServer.vcxproj.filters new file mode 100644 index 0000000..2db592d --- /dev/null +++ b/HTTPServer/HTTPServer.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Resource Files + + + Resource Files + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/Jupiter b/Jupiter index 993a313..0fba343 160000 --- a/Jupiter +++ b/Jupiter @@ -1 +1 @@ -Subproject commit 993a313b81c7fa061d0101bdc2ac101b8b5e2114 +Subproject commit 0fba343102afa3d397e613c85ca451d0085522f8 diff --git a/Release/Bot.lib b/Release/Bot.lib index e6a1efb..8016e2f 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 bb052b4..8d90ffc 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Core/RenX.Core.vcxproj b/RenX.Core/RenX.Core.vcxproj index d9de636..896baa5 100644 --- a/RenX.Core/RenX.Core.vcxproj +++ b/RenX.Core/RenX.Core.vcxproj @@ -77,6 +77,7 @@ + @@ -89,6 +90,7 @@ + diff --git a/RenX.Core/RenX.Core.vcxproj.filters b/RenX.Core/RenX.Core.vcxproj.filters index 28e0f83..b1c8e83 100644 --- a/RenX.Core/RenX.Core.vcxproj.filters +++ b/RenX.Core/RenX.Core.vcxproj.filters @@ -59,6 +59,9 @@ Header Files + + Header Files + @@ -88,5 +91,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/RenX.Core/RenX_LadderDatabase.cpp b/RenX.Core/RenX_LadderDatabase.cpp new file mode 100644 index 0000000..ba0e9d8 --- /dev/null +++ b/RenX.Core/RenX_LadderDatabase.cpp @@ -0,0 +1,469 @@ +/** +* Copyright (C) 2015-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 +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +* +* Written by Jessica James +*/ + +#include "RenX_LadderDatabase.h" +#include "RenX_Server.h" +#include "RenX_PlayerInfo.h" +#include "RenX_BanDatabase.h" + +Jupiter::ArrayList _ladder_databases; +Jupiter::ArrayList &RenX::ladder_databases = _ladder_databases; + +RenX::LadderDatabase::LadderDatabase() +{ + _ladder_databases.add(this); +} + +RenX::LadderDatabase::~LadderDatabase() +{ + while (RenX::LadderDatabase::head != nullptr) + { + RenX::LadderDatabase::end = RenX::LadderDatabase::head; + RenX::LadderDatabase::head = RenX::LadderDatabase::head->next; + delete RenX::LadderDatabase::end; + } +} + +void RenX::LadderDatabase::process_data(Jupiter::DataBuffer &buffer, FILE *file, fpos_t pos) +{ + RenX::LadderDatabase::Entry *entry = new RenX::LadderDatabase::Entry(); + + // read data from buffer to entry + entry->steam_id = buffer.pop(); + entry->total_score = buffer.pop(); + + entry->total_kills = buffer.pop(); + entry->total_deaths = buffer.pop(); + entry->total_headshot_kills = buffer.pop(); + entry->total_vehicle_kills = buffer.pop(); + entry->total_building_kills = buffer.pop(); + entry->total_defence_kills = buffer.pop(); + entry->total_captures = buffer.pop(); + entry->total_game_time = buffer.pop(); + entry->total_games = buffer.pop(); + entry->total_gdi_games = buffer.pop(); + entry->total_nod_games = buffer.pop(); + entry->total_wins = buffer.pop(); + entry->total_gdi_wins = buffer.pop(); + entry->total_nod_wins = buffer.pop(); + entry->total_beacon_placements = buffer.pop(); + entry->total_beacon_disarms = buffer.pop(); + entry->total_proxy_placements = buffer.pop(); + entry->total_proxy_disarms = buffer.pop(); + + entry->top_score = buffer.pop(); + entry->top_kills = buffer.pop(); + entry->most_deaths = buffer.pop(); + entry->top_headshot_kills = buffer.pop(); + entry->top_vehicle_kills = buffer.pop(); + entry->top_building_kills = buffer.pop(); + entry->top_defence_kills = buffer.pop(); + entry->top_captures = buffer.pop(); + entry->top_game_time = buffer.pop(); + entry->top_beacon_placements = buffer.pop(); + entry->top_beacon_disarms = buffer.pop(); + entry->top_proxy_placements = buffer.pop(); + entry->top_proxy_disarms = buffer.pop(); + + entry->most_recent_ip = buffer.pop(); + entry->last_game = buffer.pop(); + entry->most_recent_name = buffer.pop(); + + // push data to list + if (RenX::LadderDatabase::head == nullptr) + { + RenX::LadderDatabase::head = entry; + RenX::LadderDatabase::end = RenX::LadderDatabase::head; + } + else + { + RenX::LadderDatabase::end->next = entry; + entry->prev = end; + end = entry; + } + + entry->rank = ++RenX::LadderDatabase::entries; +} + +void RenX::LadderDatabase::process_header(FILE *file) +{ + int chr = fgetc(file); + if (chr != EOF) + RenX::LadderDatabase::read_version = chr; +} + +void RenX::LadderDatabase::create_header(FILE *file) +{ + fputc(RenX::LadderDatabase::write_version, file); +} + +RenX::LadderDatabase::Entry *RenX::LadderDatabase::getHead() const +{ + return RenX::LadderDatabase::head; +} + +RenX::LadderDatabase::Entry *RenX::LadderDatabase::getPlayerEntry(uint64_t steamid) const +{ + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next) + if (itr->steam_id == steamid) + return itr; + return nullptr; +} + +std::pair RenX::LadderDatabase::getPlayerEntryAndIndex(uint64_t steamid) const +{ + size_t index = 0; + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) + if (itr->steam_id == steamid) + return std::pair(itr, index); + return std::pair(nullptr, Jupiter::INVALID_INDEX); +} + +RenX::LadderDatabase::Entry *RenX::LadderDatabase::getPlayerEntryByName(const Jupiter::ReadableString &name) const +{ + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next) + if (itr->most_recent_name.equalsi(name)) + return itr; + return nullptr; +} + +std::pair RenX::LadderDatabase::getPlayerEntryAndIndexByName(const Jupiter::ReadableString &name) const +{ + size_t index = 0; + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) + if (itr->most_recent_name.equalsi(name)) + return std::pair(itr, index); + return std::pair(nullptr, Jupiter::INVALID_INDEX); +} + +RenX::LadderDatabase::Entry *RenX::LadderDatabase::getPlayerEntryByPartName(const Jupiter::ReadableString &name) const +{ + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next) + if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) + return itr; + return nullptr; +} + +std::pair RenX::LadderDatabase::getPlayerEntryAndIndexByPartName(const Jupiter::ReadableString &name) const +{ + size_t index = 0; + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) + if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) + return std::pair(itr, index); + return std::pair(nullptr, Jupiter::INVALID_INDEX); +} + +Jupiter::SLList RenX::LadderDatabase::getPlayerEntriesByPartName(const Jupiter::ReadableString &name, size_t max) const +{ + Jupiter::SLList list; + if (max == 0) + { + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next) + if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) + list.add(new RenX::LadderDatabase::Entry(*itr)); + } + else + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next) + if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) + { + list.add(new RenX::LadderDatabase::Entry(*itr)); + if (--max == 0) + return list; + } + return list; +} + +Jupiter::SLList> RenX::LadderDatabase::getPlayerEntriesAndIndexByPartName(const Jupiter::ReadableString &name, size_t max) const +{ + Jupiter::SLList> list; + size_t index = 0; + if (max == 0) + { + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) + if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) + list.add(new std::pair(*itr, index)); + } + else + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) + if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) + { + list.add(new std::pair(*itr, index)); + if (--max) + return list; + } + return list; +} + +RenX::LadderDatabase::Entry *RenX::LadderDatabase::getPlayerEntryByIndex(size_t index) const +{ + for (RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; itr != nullptr; itr = itr->next, --index) + if (index == 0) + return itr; + return nullptr; +} + +size_t RenX::LadderDatabase::getEntries() const +{ + return RenX::LadderDatabase::entries; +} + +std::chrono::steady_clock::time_point RenX::LadderDatabase::getLastSortTime() const +{ + return RenX::LadderDatabase::last_sort; +} + +void RenX::LadderDatabase::append(RenX::LadderDatabase::Entry *entry) +{ + ++RenX::LadderDatabase::entries; + if (RenX::LadderDatabase::head == nullptr) + { + RenX::LadderDatabase::head = entry; + RenX::LadderDatabase::end = RenX::LadderDatabase::head; + return; + } + RenX::LadderDatabase::end->next = entry; + entry->prev = RenX::LadderDatabase::end; + RenX::LadderDatabase::end = entry; +} + +void RenX::LadderDatabase::write(const Jupiter::CStringType &filename) +{ + return RenX::LadderDatabase::write(filename.c_str()); +} + +void RenX::LadderDatabase::write(const char *filename) +{ + if (RenX::LadderDatabase::entries != 0) + { + FILE *file = fopen(filename, "wb"); + if (file != nullptr) + { + size_t rank = 0; + Jupiter::DataBuffer buffer; + RenX::LadderDatabase::create_header(file); + RenX::LadderDatabase::Entry *entry = RenX::LadderDatabase::head; + while (entry != nullptr) + { + // update rank + entry->rank = ++rank; + + // push data from entry to buffer + buffer.push(entry->steam_id); + buffer.push(entry->total_score); + + buffer.push(entry->total_kills); + buffer.push(entry->total_deaths); + buffer.push(entry->total_headshot_kills); + buffer.push(entry->total_vehicle_kills); + buffer.push(entry->total_building_kills); + buffer.push(entry->total_defence_kills); + buffer.push(entry->total_captures); + buffer.push(entry->total_game_time); + buffer.push(entry->total_games); + buffer.push(entry->total_gdi_games); + buffer.push(entry->total_nod_games); + buffer.push(entry->total_wins); + buffer.push(entry->total_gdi_wins); + buffer.push(entry->total_nod_wins); + buffer.push(entry->total_beacon_placements); + buffer.push(entry->total_beacon_disarms); + buffer.push(entry->total_proxy_placements); + buffer.push(entry->total_proxy_disarms); + + buffer.push(entry->top_score); + buffer.push(entry->top_kills); + buffer.push(entry->most_deaths); + buffer.push(entry->top_headshot_kills); + buffer.push(entry->top_vehicle_kills); + buffer.push(entry->top_building_kills); + buffer.push(entry->top_defence_kills); + buffer.push(entry->top_captures); + buffer.push(entry->top_game_time); + buffer.push(entry->top_beacon_placements); + buffer.push(entry->top_beacon_disarms); + buffer.push(entry->top_proxy_placements); + buffer.push(entry->top_proxy_disarms); + + buffer.push(entry->most_recent_ip); + buffer.push(entry->last_game); + buffer.push(entry->most_recent_name); + + // push buffer to file + buffer.push_to(file); + + // iterate + entry = entry->next; + } + fclose(file); + } + } +} + +void RenX::LadderDatabase::sort_entries() +{ + if (RenX::LadderDatabase::entries <= 1) + return; + + RenX::LadderDatabase::Entry *itr = RenX::LadderDatabase::head; + RenX::LadderDatabase::Entry *itr2, *ptr; + + // iterate forward (search for out-of-order content) + while (itr->next != nullptr) + { + // out-of-order content found + if (itr->next->total_score > itr->total_score) + { + // pull content out + ptr = itr->next; + itr->next = ptr->next; + if (itr->next != nullptr) + itr->next->prev = itr; + + // iterate backwards from our iterator, and insert + itr2 = itr; + while (true) + { + if (itr2->prev == nullptr) + { + // push ptr to head + ptr->next = itr2; + ptr->prev = nullptr; + itr2->prev = ptr; + RenX::LadderDatabase::head = ptr; + break; + } + itr2 = itr2->prev; + if (itr2->total_score > ptr->total_score) + { + // insert ptr after itr2 + ptr->next = itr2->next; + ptr->next->prev = ptr; + ptr->prev = itr2; + itr2->next = ptr; + break; + } + } + } + else // continue iterating + itr = itr->next; + } + + RenX::LadderDatabase::end = itr; + RenX::LadderDatabase::last_sort = std::chrono::steady_clock::now(); +} + +void RenX::LadderDatabase::updateLadder(RenX::Server *server, const RenX::TeamType &team, bool output_times) +{ + if (server->players.size() != 0) + { + // update player stats in memory + RenX::PlayerInfo *player; + RenX::LadderDatabase::Entry *entry; + for (Jupiter::DLList::Node *node = server->players.getNode(0); node != nullptr; node = node->next) + { + player = node->data; + if (player->steamid != 0 && (player->ban_flags & RenX::BanDatabase::Entry::FLAG_TYPE_LADDER) == 0) + { + entry = RenX::LadderDatabase::getPlayerEntry(player->steamid); + if (entry == nullptr) + { + entry = new RenX::LadderDatabase::Entry(); + RenX::LadderDatabase::append(entry); + entry->steam_id = player->steamid; + } + + entry->total_score += static_cast(player->score); + + entry->total_kills += player->kills; + entry->total_deaths += player->deaths; + entry->total_headshot_kills += player->headshots; + entry->total_vehicle_kills += player->vehicleKills; + entry->total_building_kills += player->buildingKills; + entry->total_defence_kills += player->defenceKills; + entry->total_captures += player->captures; + entry->total_game_time += static_cast(std::chrono::duration_cast(server->getGameTime(player)).count()); + ++entry->total_games; + switch (player->team) + { + case RenX::TeamType::GDI: + ++entry->total_gdi_games; + if (player->team == team) + ++entry->total_wins, ++entry->total_gdi_wins; + break; + case RenX::TeamType::Nod: + ++entry->total_nod_games; + if (player->team == team) + ++entry->total_wins, ++entry->total_nod_wins; + break; + default: + if (player->team == team) + ++entry->total_wins; + break; + } + entry->total_beacon_placements += player->beaconPlacements; + entry->total_beacon_disarms += player->beaconDisarms; + entry->total_proxy_placements += player->proxy_placements; + entry->total_proxy_disarms += player->proxy_disarms; + + auto set_if_greater = [](uint32_t &src, const uint32_t &cmp) + { + if (cmp > src) + src = cmp; + }; + + set_if_greater(entry->top_score, static_cast(player->score)); + set_if_greater(entry->top_kills, player->kills); + set_if_greater(entry->most_deaths, player->deaths); + set_if_greater(entry->top_headshot_kills, player->headshots); + set_if_greater(entry->top_vehicle_kills, player->vehicleKills); + set_if_greater(entry->top_building_kills, player->buildingKills); + set_if_greater(entry->top_defence_kills, player->defenceKills); + set_if_greater(entry->top_captures, player->captures); + set_if_greater(entry->top_game_time, static_cast(std::chrono::duration_cast(server->getGameTime(player)).count())); + set_if_greater(entry->top_beacon_placements, player->beaconPlacements); + set_if_greater(entry->top_beacon_disarms, player->beaconDisarms); + set_if_greater(entry->top_proxy_placements, player->proxy_placements); + set_if_greater(entry->top_proxy_disarms, player->proxy_disarms); + + entry->most_recent_ip = player->ip32; + entry->last_game = time(nullptr); + entry->most_recent_name = player->name; + } + } + + // sort new stats + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + RenX::LadderDatabase::sort_entries(); + std::chrono::steady_clock::duration sort_duration = std::chrono::steady_clock::now() - start_time; + + // write new stats + start_time = std::chrono::steady_clock::now(); + RenX::LadderDatabase::write(this->getFilename()); + std::chrono::steady_clock::duration write_duration = std::chrono::steady_clock::now() - start_time; + + if (output_times) + { + Jupiter::StringS str = Jupiter::StringS::Format("Ladder: %u entries sorted in %f seconds; Database written in %f seconds." ENDL, + RenX::LadderDatabase::getEntries(), + static_cast(sort_duration.count()) * (static_cast(std::chrono::steady_clock::duration::period::num / static_cast(std::chrono::steady_clock::duration::period::den) * static_cast(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num))), + static_cast(write_duration.count()) * (static_cast(std::chrono::steady_clock::duration::period::num) / static_cast(std::chrono::steady_clock::duration::period::den) * static_cast(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num))); + str.println(stdout); + server->sendLogChan(str); + } + } +} diff --git a/RenX.Core/RenX_LadderDatabase.h b/RenX.Core/RenX_LadderDatabase.h new file mode 100644 index 0000000..422158d --- /dev/null +++ b/RenX.Core/RenX_LadderDatabase.h @@ -0,0 +1,201 @@ +/** +* Copyright (C) 2015-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 +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +* +* Written by Jessica James +*/ + +#if !defined _RENX_LADDERDATABASE_H_HEADER +#define _RENX_LADDERDATABASE_H_HEADER + +#include +#include "Jupiter/Database.h" +#include "Jupiter/String.h" +#include "Jupiter/SLList.h" +#include "Jupiter/ArrayList.h" +#include "RenX.h" + +/** DLL Linkage Nagging */ +#if defined _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4251) +#endif + +namespace RenX +{ + class Server; + + class RENX_API LadderDatabase : public Jupiter::Database + { + public: // Jupiter::Database + /** + * @brief Processes a chunk of data in a database. + * + * @param buffer Buffer to process + * @param file File being processed + * @param pos position that the buffer starts at in the file + */ + void process_data(Jupiter::DataBuffer &buffer, FILE *file, fpos_t pos) override; + + /** + * @brief Processes the header for a database. + * + * @param file File being processed + */ + void process_header(FILE *file) override; + + /** + * @brief Generates a header for a database. + * + * @param file File being created + */ + void create_header(FILE *file) override; + + public: // LadderDatabase + struct RENX_API Entry + { + size_t rank; + + uint64_t steam_id, total_score; + uint32_t total_kills, total_deaths, total_headshot_kills, total_vehicle_kills, total_building_kills, total_defence_kills, total_captures, total_game_time, total_games, total_gdi_games, total_nod_games, total_wins, total_gdi_wins, total_nod_wins, total_beacon_placements, total_beacon_disarms, total_proxy_placements, total_proxy_disarms, // totals (15) + top_score, top_kills, most_deaths, top_headshot_kills, top_vehicle_kills, top_building_kills, top_defence_kills, top_captures, top_game_time, top_beacon_placements, top_beacon_disarms, top_proxy_placements, top_proxy_disarms, // tops (12) + most_recent_ip; // other (1) + time_t last_game; + Jupiter::StringS most_recent_name; + Entry *next = nullptr; + Entry *prev = nullptr; + }; + + /** + * @brief Fetches the head of the entry list. + * + * @return Head of the ladder entry list. + */ + Entry *getHead() const; + + /** + * @brief Fetches a ladder entry by Steam ID. + * + * @param steamid Steam ID to search ladder for + * @return Ladder entry with a matching steamid if one exists, nullptr otherwise. + */ + Entry *getPlayerEntry(uint64_t steamid) const; + std::pair getPlayerEntryAndIndex(uint64_t steamid) const; + + /** + * @brief Searches for a ladder entry by name + * + * @param name Name to search ladder for + * @return Ladder entry with a matching name if one exists, nullptr otherwise. + */ + Entry *getPlayerEntryByName(const Jupiter::ReadableString &name) const; + std::pair getPlayerEntryAndIndexByName(const Jupiter::ReadableString &name) const; + + /** + * @brief Searches for a ladder entry by part name + * + * @param name Part of name to search ladder for + * @return Ladder entry with a matching name if one exists, nullptr otherwise. + */ + Entry *getPlayerEntryByPartName(const Jupiter::ReadableString &name) const; + std::pair getPlayerEntryAndIndexByPartName(const Jupiter::ReadableString &name) const; + + /** + * @brief Fetches all entries matching a part name. + * + * @param name Part of name to search for + * @param max Maximum number of entries to return + * @return List containing entries with matching names. + */ + Jupiter::SLList getPlayerEntriesByPartName(const Jupiter::ReadableString &name, size_t max) const; + Jupiter::SLList> getPlayerEntriesAndIndexByPartName(const Jupiter::ReadableString &name, size_t max) const; + + /** + * @brief Fetches a ladder entry at a specified index + * + * @param index Index of the element to fetch + * @return Ladder entry with a matching name if one exists, nullptr otherwise. + */ + Entry *getPlayerEntryByIndex(size_t index) const; + + /** + * @brief Fetches the total number of ladder entries in the list. + * + * @return Total number of entries. + */ + size_t getEntries() const; + + /** + * @brief Returns the last time that the contents of this database object were modified (i.e: initialized or written). + */ + std::chrono::steady_clock::time_point getLastSortTime() const; + + /** + * @brief Places a ladder entry at the end of the list, regardless of order + * Note: This does not copy data from the pointer -- the pointer is added to the list. + * + * @param entry Ladder entry to add + */ + void append(Entry *entry); + + /** + * @brief Writes the current ladder data to the disk. + */ + void write(const Jupiter::CStringType &filename); + void write(const char *filename); + + /** + * @brief Sorts the ladder data in memory. + */ + void sort_entries(); + + /** + * @brief Pushes the player data from the server into the ladder, sorts the data, and writes it to file storage. + * + * @param server Renegade-X server to pull player data from + * @param team Team which just won + * @param output_times True if the sort/write times should be output, false otherwise. + */ + void updateLadder(RenX::Server *server, const RenX::TeamType &team, bool output_times); + + /** + * @brief Constructor for the LadderDatabase class + */ + LadderDatabase(); + + /** + * @brief Deconstructor for the LadderDatabase class + */ + ~LadderDatabase(); + private: + + /** Database version */ + const uint8_t write_version = 0; + uint8_t read_version = write_version; + + std::chrono::steady_clock::time_point last_sort = std::chrono::steady_clock::now(); + size_t entries = 0; + Entry *head = nullptr; + Entry *end; + }; + + RENX_API extern Jupiter::ArrayList &ladder_databases; +} + +/** Re-enable warnings */ +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#endif //_RENX_LADDERDATABASE_H_HEADER \ No newline at end of file diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index 679f404..d92057a 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -2762,7 +2762,7 @@ void RenX::Server::disconnect(RenX::DisconnectReason reason) for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnServerDisconnect(this, reason); - RenX::Server::sock.closeSocket(); + RenX::Server::sock.close(); RenX::Server::wipeData(); RenX::Server::connected = false; } @@ -2916,7 +2916,7 @@ void RenX::Server::init() RenX::Server::~Server() { - sock.closeSocket(); + sock.close(); RenX::Server::wipeData(); RenX::Server::commands.emptyAndDelete(); } diff --git a/RenX.Core/RenX_Tags.cpp b/RenX.Core/RenX_Tags.cpp index d0a3e88..257b4c6 100644 --- a/RenX.Core/RenX_Tags.cpp +++ b/RenX.Core/RenX_Tags.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Jessica James. + * Copyright (C) 2015-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 @@ -27,10 +27,13 @@ #include "RenX_Plugin.h" #include "RenX_Tags.h" +using namespace Jupiter::literals; + struct TagsImp : RenX::Tags { TagsImp(); void processTags(Jupiter::StringType &msg, const RenX::Server *server, const RenX::PlayerInfo *player, const RenX::PlayerInfo *victim, const RenX::BuildingInfo *building); + void processTags(Jupiter::StringType &msg, const RenX::LadderDatabase::Entry &entry); void sanitizeTags(Jupiter::StringType &fmt); const Jupiter::ReadableString &getUniqueInternalTag(); Jupiter::StringS get_building_health_bar(const RenX::BuildingInfo *building); @@ -54,14 +57,14 @@ RenX::Tags *RenX::tags = &_tags; TagsImp::TagsImp() { this->tagItr = 0; - this->uniqueTag = STRING_LITERAL_AS_REFERENCE("\0\0\0\0\0\0"); + this->uniqueTag = "\0\0\0\0\0\0"_jrs; - const Jupiter::ReadableString &configSection = Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("TagDefinitions"), STRING_LITERAL_AS_REFERENCE("RenX.Tags")); - TagsImp::bar_width = Jupiter::IRC::Client::Config->getInt(configSection, STRING_LITERAL_AS_REFERENCE("BarWidth"), 19); + const Jupiter::ReadableString &configSection = Jupiter::IRC::Client::Config->get("RenX"_jrs, "TagDefinitions"_jrs, "RenX.Tags"_jrs); + TagsImp::bar_width = Jupiter::IRC::Client::Config->getInt(configSection, "BarWidth"_jrs, 19); /** Global formats */ - this->dateFmt = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("DateFormat"), STRING_LITERAL_AS_REFERENCE("%A, %B %d, %Y")); - this->timeFmt = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("TimeFormat"), STRING_LITERAL_AS_REFERENCE("%H:%M:%S"));; + this->dateFmt = Jupiter::IRC::Client::Config->get(configSection, "DateFormat"_jrs, "%A, %B %d, %Y"_jrs); + this->timeFmt = Jupiter::IRC::Client::Config->get(configSection, "TimeFormat"_jrs, "%H:%M:%S"_jrs);; /** Internal message tags */ @@ -101,6 +104,7 @@ TagsImp::TagsImp() this->INTERNAL_TEAM_LONG_TAG = this->getUniqueInternalTag(); this->INTERNAL_PING_TAG = this->getUniqueInternalTag(); this->INTERNAL_SCORE_TAG = this->getUniqueInternalTag(); + this->INTERNAL_SCORE_PER_MINUTE_TAG = this->getUniqueInternalTag(); this->INTERNAL_CREDITS_TAG = this->getUniqueInternalTag(); this->INTERNAL_KILLS_TAG = this->getUniqueInternalTag(); this->INTERNAL_DEATHS_TAG = this->getUniqueInternalTag(); @@ -110,10 +114,24 @@ TagsImp::TagsImp() this->INTERNAL_VEHICLE_KILLS_TAG = this->getUniqueInternalTag(); this->INTERNAL_BUILDING_KILLS_TAG = this->getUniqueInternalTag(); this->INTERNAL_DEFENCE_KILLS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_GAME_TIME_TAG = this->getUniqueInternalTag(); + this->INTERNAL_GAMES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_GDI_GAMES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_NOD_GAMES_TAG = this->getUniqueInternalTag(); this->INTERNAL_WINS_TAG = this->getUniqueInternalTag(); - this->INTERNAL_LOSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_GDI_WINS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_NOD_WINS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_TIES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_LOSSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_GDI_LOSSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_NOD_LOSSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_WIN_LOSS_RATIO_TAG = this->getUniqueInternalTag(); + this->INTERNAL_GDI_WIN_LOSS_RATIO_TAG = this->getUniqueInternalTag(); + this->INTERNAL_NOD_WIN_LOSS_RATIO_TAG = this->getUniqueInternalTag(); this->INTERNAL_BEACON_PLACEMENTS_TAG = this->getUniqueInternalTag(); this->INTERNAL_BEACON_DISARMS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_PROXY_PLACEMENTS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_PROXY_DISARMS_TAG = this->getUniqueInternalTag(); this->INTERNAL_CAPTURES_TAG = this->getUniqueInternalTag(); this->INTERNAL_STEALS_TAG = this->getUniqueInternalTag(); this->INTERNAL_STOLEN_TAG = this->getUniqueInternalTag(); @@ -146,10 +164,24 @@ TagsImp::TagsImp() this->INTERNAL_VICTIM_VEHICLE_KILLS_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_BUILDING_KILLS_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_DEFENCE_KILLS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_GAME_TIME_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_GAMES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_GDI_GAMES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_NOD_GAMES_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_WINS_TAG = this->getUniqueInternalTag(); - this->INTERNAL_VICTIM_LOSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_GDI_WINS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_NOD_WINS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_TIES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_LOSSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_GDI_LOSSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_NOD_LOSSES_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_WIN_LOSS_RATIO_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_GDI_WIN_LOSS_RATIO_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_NOD_WIN_LOSS_RATIO_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_BEACON_PLACEMENTS_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_BEACON_DISARMS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_PROXY_PLACEMENTS_TAG = this->getUniqueInternalTag(); + this->INTERNAL_VICTIM_PROXY_DISARMS_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_CAPTURES_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_STEALS_TAG = this->getUniqueInternalTag(); this->INTERNAL_VICTIM_STOLEN_TAG = this->getUniqueInternalTag(); @@ -173,117 +205,151 @@ TagsImp::TagsImp() this->INTERNAL_NEW_NAME_TAG = this->getUniqueInternalTag(); this->INTERNAL_WIN_SCORE_TAG = this->getUniqueInternalTag(); this->INTERNAL_LOSE_SCORE_TAG = this->getUniqueInternalTag(); + this->INTERNAL_LAST_GAME_TAG = this->getUniqueInternalTag(); + this->INTERNAL_RANK_TAG = this->getUniqueInternalTag(); /** External (config) tags */ /** Global tags */ - this->dateTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("DateTag"), STRING_LITERAL_AS_REFERENCE("{DATE}")); - this->timeTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("TimeTag"), STRING_LITERAL_AS_REFERENCE("{TIME}")); + this->dateTag = Jupiter::IRC::Client::Config->get(configSection, "DateTag"_jrs, "{DATE}"_jrs); + this->timeTag = Jupiter::IRC::Client::Config->get(configSection, "TimeTag"_jrs, "{TIME}"_jrs); /** Server tags */ - this->rconVersionTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("RCONVersionTag"), STRING_LITERAL_AS_REFERENCE("{RVER}")); - this->gameVersionTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("GameVersionTag"), STRING_LITERAL_AS_REFERENCE("{GVER}")); - this->rulesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("RulesTag"), STRING_LITERAL_AS_REFERENCE("{RULES}")); - this->userTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("UserTag"), STRING_LITERAL_AS_REFERENCE("{USER}")); - this->serverNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ServerNameTag"), STRING_LITERAL_AS_REFERENCE("{SERVERNAME}")); - this->mapTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("MapTag"), STRING_LITERAL_AS_REFERENCE("{MAP}")); - this->mapGUIDTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("MapGUIDTag"), STRING_LITERAL_AS_REFERENCE("{MGUID}")); - this->serverHostnameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ServerHostnameTag"), STRING_LITERAL_AS_REFERENCE("{SERVERHOST}")); - this->serverPortTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ServerPortTag"), STRING_LITERAL_AS_REFERENCE("{SERVERPORT}")); - this->socketHostnameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("SocketHostnameTag"), STRING_LITERAL_AS_REFERENCE("{SOCKHOST}")); - this->socketPortTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("SocketPortTag"), STRING_LITERAL_AS_REFERENCE("{SOCKPORT}")); - this->serverPrefixTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ServerPrefixTag"), STRING_LITERAL_AS_REFERENCE("{SERVERPREFIX}")); + this->rconVersionTag = Jupiter::IRC::Client::Config->get(configSection, "RCONVersionTag"_jrs, "{RVER}"_jrs); + this->gameVersionTag = Jupiter::IRC::Client::Config->get(configSection, "GameVersionTag"_jrs, "{GVER}"_jrs); + this->rulesTag = Jupiter::IRC::Client::Config->get(configSection, "RulesTag"_jrs, "{RULES}"_jrs); + this->userTag = Jupiter::IRC::Client::Config->get(configSection, "UserTag"_jrs, "{USER}"_jrs); + this->serverNameTag = Jupiter::IRC::Client::Config->get(configSection, "ServerNameTag"_jrs, "{SERVERNAME}"_jrs); + this->mapTag = Jupiter::IRC::Client::Config->get(configSection, "MapTag"_jrs, "{MAP}"_jrs); + this->mapGUIDTag = Jupiter::IRC::Client::Config->get(configSection, "MapGUIDTag"_jrs, "{MGUID}"_jrs); + this->serverHostnameTag = Jupiter::IRC::Client::Config->get(configSection, "ServerHostnameTag"_jrs, "{SERVERHOST}"_jrs); + this->serverPortTag = Jupiter::IRC::Client::Config->get(configSection, "ServerPortTag"_jrs, "{SERVERPORT}"_jrs); + this->socketHostnameTag = Jupiter::IRC::Client::Config->get(configSection, "SocketHostnameTag"_jrs, "{SOCKHOST}"_jrs); + this->socketPortTag = Jupiter::IRC::Client::Config->get(configSection, "SocketPortTag"_jrs, "{SOCKPORT}"_jrs); + this->serverPrefixTag = Jupiter::IRC::Client::Config->get(configSection, "ServerPrefixTag"_jrs, "{SERVERPREFIX}"_jrs); /** Player tags */ - this->nameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("NameTag"), STRING_LITERAL_AS_REFERENCE("{NAME}")); - this->rawNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("RawNameTag"), STRING_LITERAL_AS_REFERENCE("{RNAME}")); - this->ipTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("IPTag"), STRING_LITERAL_AS_REFERENCE("{IP}")); - this->rdnsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("RDNSTag"), STRING_LITERAL_AS_REFERENCE("{RDNS}")); - this->steamTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("SteamTag"), STRING_LITERAL_AS_REFERENCE("{STEAM}")); - this->uuidTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("UUIDTag"), STRING_LITERAL_AS_REFERENCE("{UUID}")); - this->idTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("IDTag"), STRING_LITERAL_AS_REFERENCE("{ID}")); - this->characterTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("CharacterTag"), STRING_LITERAL_AS_REFERENCE("{CHAR}")); - this->vehicleTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VehicleTag"), STRING_LITERAL_AS_REFERENCE("{VEH}")); - this->adminTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("AdminTag"), STRING_LITERAL_AS_REFERENCE("{ADMIN}")); - this->prefixTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("PrefixTag"), STRING_LITERAL_AS_REFERENCE("{PREFIX}")); - this->gamePrefixTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("GamePrefixTag"), STRING_LITERAL_AS_REFERENCE("{GPREFIX}")); - this->teamColorTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("TeamColorTag"), STRING_LITERAL_AS_REFERENCE("{TCOLOR}")); - this->teamShortTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ShortTeamTag"), STRING_LITERAL_AS_REFERENCE("{TEAMS}")); - this->teamLongTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("LongTeamTag"), STRING_LITERAL_AS_REFERENCE("{TEAML}")); - this->pingTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("PingTag"), STRING_LITERAL_AS_REFERENCE("{PING}")); - this->scoreTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ScoreTag"), STRING_LITERAL_AS_REFERENCE("{SCORE}")); - this->creditsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("CreditsTag"), STRING_LITERAL_AS_REFERENCE("{CREDITS}")); - this->killsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("KillsTag"), STRING_LITERAL_AS_REFERENCE("{KILLS}")); - this->deathsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("DeathsTag"), STRING_LITERAL_AS_REFERENCE("{DEATHS}")); - this->kdrTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("KDRTag"), STRING_LITERAL_AS_REFERENCE("{KDR}")); - this->suicidesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("SuicidesTag"), STRING_LITERAL_AS_REFERENCE("{SUICIDES}")); - this->headshotsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("HeadshotsTag"), STRING_LITERAL_AS_REFERENCE("{HEADSHOTS}")); - this->vehicleKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VehicleKillsTag"), STRING_LITERAL_AS_REFERENCE("{VEHICLEKILLS}")); - this->buildingKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingKillsTag"), STRING_LITERAL_AS_REFERENCE("{BUILDINGKILLS}")); - this->defenceKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("DefenceKillsTag"), STRING_LITERAL_AS_REFERENCE("{DEFENCEKILLS}")); - this->winsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("WinsTag"), STRING_LITERAL_AS_REFERENCE("{WINS}")); - this->losesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("LosesTag"), STRING_LITERAL_AS_REFERENCE("{LOSES}")); - this->beaconPlacementsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BeaconPlacementsTag"), STRING_LITERAL_AS_REFERENCE("{BEACONPLACEMENTS}")); - this->beaconDisarmsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BeaconDisarmsTag"), STRING_LITERAL_AS_REFERENCE("{BEACONDISARMS}")); - this->capturesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("CapturesTag"), STRING_LITERAL_AS_REFERENCE("{CAPTURES}")); - this->stealsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("StealsTag"), STRING_LITERAL_AS_REFERENCE("{STEALS}")); - this->stolenTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("StolenTag"), STRING_LITERAL_AS_REFERENCE("{STOLEN}")); - this->accessTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("AccessTag"), STRING_LITERAL_AS_REFERENCE("{ACCESS}")); + this->nameTag = Jupiter::IRC::Client::Config->get(configSection, "NameTag"_jrs, "{NAME}"_jrs); + this->rawNameTag = Jupiter::IRC::Client::Config->get(configSection, "RawNameTag"_jrs, "{RNAME}"_jrs); + this->ipTag = Jupiter::IRC::Client::Config->get(configSection, "IPTag"_jrs, "{IP}"_jrs); + this->rdnsTag = Jupiter::IRC::Client::Config->get(configSection, "RDNSTag"_jrs, "{RDNS}"_jrs); + this->steamTag = Jupiter::IRC::Client::Config->get(configSection, "SteamTag"_jrs, "{STEAM}"_jrs); + this->uuidTag = Jupiter::IRC::Client::Config->get(configSection, "UUIDTag"_jrs, "{UUID}"_jrs); + this->idTag = Jupiter::IRC::Client::Config->get(configSection, "IDTag"_jrs, "{ID}"_jrs); + this->characterTag = Jupiter::IRC::Client::Config->get(configSection, "CharacterTag"_jrs, "{CHAR}"_jrs); + this->vehicleTag = Jupiter::IRC::Client::Config->get(configSection, "VehicleTag"_jrs, "{VEH}"_jrs); + this->adminTag = Jupiter::IRC::Client::Config->get(configSection, "AdminTag"_jrs, "{ADMIN}"_jrs); + this->prefixTag = Jupiter::IRC::Client::Config->get(configSection, "PrefixTag"_jrs, "{PREFIX}"_jrs); + this->gamePrefixTag = Jupiter::IRC::Client::Config->get(configSection, "GamePrefixTag"_jrs, "{GPREFIX}"_jrs); + this->teamColorTag = Jupiter::IRC::Client::Config->get(configSection, "TeamColorTag"_jrs, "{TCOLOR}"_jrs); + this->teamShortTag = Jupiter::IRC::Client::Config->get(configSection, "ShortTeamTag"_jrs, "{TEAMS}"_jrs); + this->teamLongTag = Jupiter::IRC::Client::Config->get(configSection, "LongTeamTag"_jrs, "{TEAML}"_jrs); + this->pingTag = Jupiter::IRC::Client::Config->get(configSection, "PingTag"_jrs, "{PING}"_jrs); + this->scoreTag = Jupiter::IRC::Client::Config->get(configSection, "ScoreTag"_jrs, "{SCORE}"_jrs); + this->scorePerMinuteTag = Jupiter::IRC::Client::Config->get(configSection, "ScorePerMinuteTag"_jrs, "{SPM}"_jrs); + this->creditsTag = Jupiter::IRC::Client::Config->get(configSection, "CreditsTag"_jrs, "{CREDITS}"_jrs); + this->killsTag = Jupiter::IRC::Client::Config->get(configSection, "KillsTag"_jrs, "{KILLS}"_jrs); + this->deathsTag = Jupiter::IRC::Client::Config->get(configSection, "DeathsTag"_jrs, "{DEATHS}"_jrs); + this->kdrTag = Jupiter::IRC::Client::Config->get(configSection, "KDRTag"_jrs, "{KDR}"_jrs); + this->suicidesTag = Jupiter::IRC::Client::Config->get(configSection, "SuicidesTag"_jrs, "{SUICIDES}"_jrs); + this->headshotsTag = Jupiter::IRC::Client::Config->get(configSection, "HeadshotsTag"_jrs, "{HEADSHOTS}"_jrs); + this->vehicleKillsTag = Jupiter::IRC::Client::Config->get(configSection, "VehicleKillsTag"_jrs, "{VEHICLEKILLS}"_jrs); + this->buildingKillsTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingKillsTag"_jrs, "{BUILDINGKILLS}"_jrs); + this->defenceKillsTag = Jupiter::IRC::Client::Config->get(configSection, "DefenceKillsTag"_jrs, "{DEFENCEKILLS}"_jrs); + this->gameTimeTag = Jupiter::IRC::Client::Config->get(configSection, "GameTimeTag"_jrs, "{GAMETIME}"_jrs); + this->gamesTag = Jupiter::IRC::Client::Config->get(configSection, "GamesTag"_jrs, "{GAMES}"_jrs); + this->GDIGamesTag = Jupiter::IRC::Client::Config->get(configSection, "GDIGamesTag"_jrs, "{GDIGAMES}"_jrs); + this->NodGamesTag = Jupiter::IRC::Client::Config->get(configSection, "NodGamesTag"_jrs, "{NODGAMES}"_jrs); + this->winsTag = Jupiter::IRC::Client::Config->get(configSection, "WinsTag"_jrs, "{WINS}"_jrs); + this->GDIWinsTag = Jupiter::IRC::Client::Config->get(configSection, "GDIWinsTag"_jrs, "{GDIWINS}"_jrs); + this->NodWinsTag = Jupiter::IRC::Client::Config->get(configSection, "NodWinsTag"_jrs, "{NODWINS}"_jrs); + this->tiesTag = Jupiter::IRC::Client::Config->get(configSection, "TiesTag"_jrs, "{TIES}"_jrs); + this->lossesTag = Jupiter::IRC::Client::Config->get(configSection, "LossesTag"_jrs, "{LOSSES}"_jrs); + this->GDILossesTag = Jupiter::IRC::Client::Config->get(configSection, "GDILossesTag"_jrs, "{GDILOSSES}"_jrs); + this->NodLossesTag = Jupiter::IRC::Client::Config->get(configSection, "NodLossesTag"_jrs, "{NODLOSSES}"_jrs); + this->winLossRatioTag = Jupiter::IRC::Client::Config->get(configSection, "WinLossRatioTag"_jrs, "{WLR}"_jrs); + this->GDIWinLossRatioTag = Jupiter::IRC::Client::Config->get(configSection, "GDIWinLossRatioTag"_jrs, "{GWLR}"_jrs); + this->NodWinLossRatioTag = Jupiter::IRC::Client::Config->get(configSection, "NodWinLossRatioTag"_jrs, "{NWLR}"_jrs); + this->beaconPlacementsTag = Jupiter::IRC::Client::Config->get(configSection, "BeaconPlacementsTag"_jrs, "{BEACONPLACEMENTS}"_jrs); + this->beaconDisarmsTag = Jupiter::IRC::Client::Config->get(configSection, "BeaconDisarmsTag"_jrs, "{BEACONDISARMS}"_jrs); + this->proxyPlacementsTag = Jupiter::IRC::Client::Config->get(configSection, "ProxyPlacementsTag"_jrs, "{PROXYPLACEMENTS}"_jrs); + this->proxyDisarmsTag = Jupiter::IRC::Client::Config->get(configSection, "ProxyDisarmsTag"_jrs, "{PROXYDISARMS}"_jrs); + this->capturesTag = Jupiter::IRC::Client::Config->get(configSection, "CapturesTag"_jrs, "{CAPTURES}"_jrs); + this->stealsTag = Jupiter::IRC::Client::Config->get(configSection, "StealsTag"_jrs, "{STEALS}"_jrs); + this->stolenTag = Jupiter::IRC::Client::Config->get(configSection, "StolenTag"_jrs, "{STOLEN}"_jrs); + this->accessTag = Jupiter::IRC::Client::Config->get(configSection, "AccessTag"_jrs, "{ACCESS}"_jrs); /** Victim player tags */ - this->victimNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimNameTag"), STRING_LITERAL_AS_REFERENCE("{VNAME}")); - this->victimRawNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimRawNameTag"), STRING_LITERAL_AS_REFERENCE("{VRNAME}")); - this->victimIPTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimIPTag"), STRING_LITERAL_AS_REFERENCE("{VIP}")); - this->victimRDNSTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimRDNSTag"), STRING_LITERAL_AS_REFERENCE("{VRDNS}")); - this->victimSteamTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimSteamTag"), STRING_LITERAL_AS_REFERENCE("{VSTEAM}")); - this->victimUUIDTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimUUIDTag"), STRING_LITERAL_AS_REFERENCE("{VUUID}")); - this->victimIDTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimIDTag"), STRING_LITERAL_AS_REFERENCE("{VID}")); - this->victimCharacterTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimCharacterTag"), STRING_LITERAL_AS_REFERENCE("{VCHAR}")); - this->victimVehicleTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimVehicleTag"), STRING_LITERAL_AS_REFERENCE("{VVEH}")); - this->victimAdminTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimAdminTag"), STRING_LITERAL_AS_REFERENCE("{VADMIN}")); - this->victimPrefixTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimPrefixTag"), STRING_LITERAL_AS_REFERENCE("{VPREFIX}")); - this->victimGamePrefixTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimGamePrefixTag"), STRING_LITERAL_AS_REFERENCE("{VGPREFIX}")); - this->victimTeamColorTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimTeamColorTag"), STRING_LITERAL_AS_REFERENCE("{VTCOLOR}")); - this->victimTeamShortTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimShortTeamTag"), STRING_LITERAL_AS_REFERENCE("{VTEAMS}")); - this->victimTeamLongTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimLongTeamTag"), STRING_LITERAL_AS_REFERENCE("{VTEAML}")); - this->victimPingTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimPingTag"), STRING_LITERAL_AS_REFERENCE("{VPING}")); - this->victimScoreTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimScoreTag"), STRING_LITERAL_AS_REFERENCE("{VSCORE}")); - this->victimCreditsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimCreditsTag"), STRING_LITERAL_AS_REFERENCE("{VCREDITS}")); - this->victimKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimKillsTag"), STRING_LITERAL_AS_REFERENCE("{VKILLS}")); - this->victimDeathsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimDeathsTag"), STRING_LITERAL_AS_REFERENCE("{VDEATHS}")); - this->victimKDRTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimKDRTag"), STRING_LITERAL_AS_REFERENCE("{VKDR}")); - this->victimSuicidesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimSuicidesTag"), STRING_LITERAL_AS_REFERENCE("{VSUICIDES}")); - this->victimHeadshotsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimHeadshotsTag"), STRING_LITERAL_AS_REFERENCE("{VHEADSHOTS}")); - this->victimVehicleKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimVehicleKillsTag"), STRING_LITERAL_AS_REFERENCE("{VVEHICLEKILLS}")); - this->victimBuildingKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimBuildingKillsTag"), STRING_LITERAL_AS_REFERENCE("{VBUILDINGKILLS}")); - this->victimDefenceKillsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimDefenceKillsTag"), STRING_LITERAL_AS_REFERENCE("{VDEFENCEKILLS}")); - this->victimWinsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimWinsTag"), STRING_LITERAL_AS_REFERENCE("{VWINS}")); - this->victimLosesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimLosesTag"), STRING_LITERAL_AS_REFERENCE("{VLOSES}")); - this->victimBeaconPlacementsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimBeaconPlacementsTag"), STRING_LITERAL_AS_REFERENCE("{VBEACONPLACEMENTS}")); - this->victimBeaconDisarmsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimBeaconDisarmsTag"), STRING_LITERAL_AS_REFERENCE("{VBEACONDISARMS}")); - this->victimCapturesTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimCapturesTag"), STRING_LITERAL_AS_REFERENCE("{VCAPTURES}")); - this->victimStealsTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimStealsTag"), STRING_LITERAL_AS_REFERENCE("{VSTEALS}")); - this->victimStolenTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimStolenTag"), STRING_LITERAL_AS_REFERENCE("{VSTOLEN}")); - this->victimAccessTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("VictimAccessTag"), STRING_LITERAL_AS_REFERENCE("{VACCESS}")); + this->victimNameTag = Jupiter::IRC::Client::Config->get(configSection, "VictimNameTag"_jrs, "{VNAME}"_jrs); + this->victimRawNameTag = Jupiter::IRC::Client::Config->get(configSection, "VictimRawNameTag"_jrs, "{VRNAME}"_jrs); + this->victimIPTag = Jupiter::IRC::Client::Config->get(configSection, "VictimIPTag"_jrs, "{VIP}"_jrs); + this->victimRDNSTag = Jupiter::IRC::Client::Config->get(configSection, "VictimRDNSTag"_jrs, "{VRDNS}"_jrs); + this->victimSteamTag = Jupiter::IRC::Client::Config->get(configSection, "VictimSteamTag"_jrs, "{VSTEAM}"_jrs); + this->victimUUIDTag = Jupiter::IRC::Client::Config->get(configSection, "VictimUUIDTag"_jrs, "{VUUID}"_jrs); + this->victimIDTag = Jupiter::IRC::Client::Config->get(configSection, "VictimIDTag"_jrs, "{VID}"_jrs); + this->victimCharacterTag = Jupiter::IRC::Client::Config->get(configSection, "VictimCharacterTag"_jrs, "{VCHAR}"_jrs); + this->victimVehicleTag = Jupiter::IRC::Client::Config->get(configSection, "VictimVehicleTag"_jrs, "{VVEH}"_jrs); + this->victimAdminTag = Jupiter::IRC::Client::Config->get(configSection, "VictimAdminTag"_jrs, "{VADMIN}"_jrs); + this->victimPrefixTag = Jupiter::IRC::Client::Config->get(configSection, "VictimPrefixTag"_jrs, "{VPREFIX}"_jrs); + this->victimGamePrefixTag = Jupiter::IRC::Client::Config->get(configSection, "VictimGamePrefixTag"_jrs, "{VGPREFIX}"_jrs); + this->victimTeamColorTag = Jupiter::IRC::Client::Config->get(configSection, "VictimTeamColorTag"_jrs, "{VTCOLOR}"_jrs); + this->victimTeamShortTag = Jupiter::IRC::Client::Config->get(configSection, "VictimShortTeamTag"_jrs, "{VTEAMS}"_jrs); + this->victimTeamLongTag = Jupiter::IRC::Client::Config->get(configSection, "VictimLongTeamTag"_jrs, "{VTEAML}"_jrs); + this->victimPingTag = Jupiter::IRC::Client::Config->get(configSection, "VictimPingTag"_jrs, "{VPING}"_jrs); + this->victimScoreTag = Jupiter::IRC::Client::Config->get(configSection, "VictimScoreTag"_jrs, "{VSCORE}"_jrs); + this->victimScorePerMinuteTag = Jupiter::IRC::Client::Config->get(configSection, "VictimScorePerMinuteTag"_jrs, "{VSPM}"_jrs); + this->victimCreditsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimCreditsTag"_jrs, "{VCREDITS}"_jrs); + this->victimKillsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimKillsTag"_jrs, "{VKILLS}"_jrs); + this->victimDeathsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimDeathsTag"_jrs, "{VDEATHS}"_jrs); + this->victimKDRTag = Jupiter::IRC::Client::Config->get(configSection, "VictimKDRTag"_jrs, "{VKDR}"_jrs); + this->victimSuicidesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimSuicidesTag"_jrs, "{VSUICIDES}"_jrs); + this->victimHeadshotsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimHeadshotsTag"_jrs, "{VHEADSHOTS}"_jrs); + this->victimVehicleKillsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimVehicleKillsTag"_jrs, "{VVEHICLEKILLS}"_jrs); + this->victimBuildingKillsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimBuildingKillsTag"_jrs, "{VBUILDINGKILLS}"_jrs); + this->victimDefenceKillsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimDefenceKillsTag"_jrs, "{VDEFENCEKILLS}"_jrs); + this->victimGameTimeTag = Jupiter::IRC::Client::Config->get(configSection, "VictimGameTimeTag"_jrs, "{VGAMETIME}"_jrs); + this->victimGamesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimGamesTag"_jrs, "{VGAMES}"_jrs); + this->victimGDIGamesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimGDIGamesTag"_jrs, "{VGDIGAMES}"_jrs); + this->victimNodGamesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimNodGamesTag"_jrs, "{VNODGAMES}"_jrs); + this->victimWinsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimWinsTag"_jrs, "{VWINS}"_jrs); + this->victimGDIWinsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimGDIWinsTag"_jrs, "{VGDIWINS}"_jrs); + this->victimNodWinsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimNodWinsTag"_jrs, "{VNODWINS}"_jrs); + this->victimTiesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimTiesTag"_jrs, "{VTIES}"_jrs); + this->victimLossesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimLossesTag"_jrs, "{VLOSSES}"_jrs); + this->victimGDILossesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimGDILossesTag"_jrs, "{VGDILOSSES}"_jrs); + this->victimNodLossesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimNodLossesTag"_jrs, "{VNODLOSSES}"_jrs); + this->victimWinLossRatioTag = Jupiter::IRC::Client::Config->get(configSection, "WinLossRatioTag"_jrs, "{WLR}"_jrs); + this->victimGDIWinLossRatioTag = Jupiter::IRC::Client::Config->get(configSection, "GDIWinLossRatioTag"_jrs, "{VGWLR}"_jrs); + this->victimNodWinLossRatioTag = Jupiter::IRC::Client::Config->get(configSection, "NodWinLossRatioTag"_jrs, "{VNWLR}"_jrs); + this->victimBeaconPlacementsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimBeaconPlacementsTag"_jrs, "{VBEACONPLACEMENTS}"_jrs); + this->victimBeaconDisarmsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimBeaconDisarmsTag"_jrs, "{VBEACONDISARMS}"_jrs); + this->victimProxyPlacementsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimProxyPlacementsTag"_jrs, "{VPROXYPLACEMENTS}"_jrs); + this->victimProxyDisarmsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimProxyDisarmsTag"_jrs, "{VPROXYDISARMS}"_jrs); + this->victimCapturesTag = Jupiter::IRC::Client::Config->get(configSection, "VictimCapturesTag"_jrs, "{VCAPTURES}"_jrs); + this->victimStealsTag = Jupiter::IRC::Client::Config->get(configSection, "VictimStealsTag"_jrs, "{VSTEALS}"_jrs); + this->victimStolenTag = Jupiter::IRC::Client::Config->get(configSection, "VictimStolenTag"_jrs, "{VSTOLEN}"_jrs); + this->victimAccessTag = Jupiter::IRC::Client::Config->get(configSection, "VictimAccessTag"_jrs, "{VACCESS}"_jrs); /** Building tags */ - this->buildingNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingNameTag"), STRING_LITERAL_AS_REFERENCE("{BNAME}")); - this->buildingRawNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingRawNameTag"), STRING_LITERAL_AS_REFERENCE("{BRNAME}")); - this->buildingHealthTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingHealthTag"), STRING_LITERAL_AS_REFERENCE("{BHEALTH}")); - this->buildingMaxHealthTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingMaxHealthTag"), STRING_LITERAL_AS_REFERENCE("{BMHEALTH}")); - this->buildingHealthPercentageTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingHealthPercentageTag"), STRING_LITERAL_AS_REFERENCE("{BHP}")); - this->buildingHealthBarTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingHealthBarTag"), STRING_LITERAL_AS_REFERENCE("{BHBAR}")); - this->buildingTeamColorTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingTeamColorTag"), STRING_LITERAL_AS_REFERENCE("{BCOLOR}")); - this->buildingTeamShortTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingShortTeamTag"), STRING_LITERAL_AS_REFERENCE("{BTEAMS}")); - this->buildingTeamLongTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("BuildingLongTeamTag"), STRING_LITERAL_AS_REFERENCE("{BTEAML}")); + this->buildingNameTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingNameTag"_jrs, "{BNAME}"_jrs); + this->buildingRawNameTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingRawNameTag"_jrs, "{BRNAME}"_jrs); + this->buildingHealthTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingHealthTag"_jrs, "{BHEALTH}"_jrs); + this->buildingMaxHealthTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingMaxHealthTag"_jrs, "{BMHEALTH}"_jrs); + this->buildingHealthPercentageTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingHealthPercentageTag"_jrs, "{BHP}"_jrs); + this->buildingHealthBarTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingHealthBarTag"_jrs, "{BHBAR}"_jrs); + this->buildingTeamColorTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingTeamColorTag"_jrs, "{BCOLOR}"_jrs); + this->buildingTeamShortTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingShortTeamTag"_jrs, "{BTEAMS}"_jrs); + this->buildingTeamLongTag = Jupiter::IRC::Client::Config->get(configSection, "BuildingLongTeamTag"_jrs, "{BTEAML}"_jrs); /** Other tags */ - this->weaponTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("WeaponTag"), STRING_LITERAL_AS_REFERENCE("{WEAPON}")); - this->objectTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("ObjectTag"), STRING_LITERAL_AS_REFERENCE("{OBJECT}")); - this->messageTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("MessageTag"), STRING_LITERAL_AS_REFERENCE("{MESSAGE}")); - this->newNameTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("NewNameTag"), STRING_LITERAL_AS_REFERENCE("{NNAME}")); - this->winScoreTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("WinScoreTag"), STRING_LITERAL_AS_REFERENCE("{WINSCORE}")); - this->loseScoreTag = Jupiter::IRC::Client::Config->get(configSection, STRING_LITERAL_AS_REFERENCE("LoseScoreTag"), STRING_LITERAL_AS_REFERENCE("{LOSESCORE}")); + this->weaponTag = Jupiter::IRC::Client::Config->get(configSection, "WeaponTag"_jrs, "{WEAPON}"_jrs); + this->objectTag = Jupiter::IRC::Client::Config->get(configSection, "ObjectTag"_jrs, "{OBJECT}"_jrs); + this->messageTag = Jupiter::IRC::Client::Config->get(configSection, "MessageTag"_jrs, "{MESSAGE}"_jrs); + this->newNameTag = Jupiter::IRC::Client::Config->get(configSection, "NewNameTag"_jrs, "{NNAME}"_jrs); + this->winScoreTag = Jupiter::IRC::Client::Config->get(configSection, "WinScoreTag"_jrs, "{WINSCORE}"_jrs); + this->loseScoreTag = Jupiter::IRC::Client::Config->get(configSection, "LoseScoreTag"_jrs, "{LOSESCORE}"_jrs); + this->lastGameTag = Jupiter::IRC::Client::Config->get(configSection, "LastScoreTag"_jrs, "{LOSESCORE}"_jrs); + this->rankTag = Jupiter::IRC::Client::Config->get(configSection, "RankTag"_jrs, "{RANK}"_jrs); } Jupiter::StringS TagsImp::get_building_health_bar(const RenX::BuildingInfo *building) @@ -320,11 +386,12 @@ Jupiter::StringS TagsImp::get_building_health_bar(const RenX::BuildingInfo *buil return r += IRCNORMAL; } -#define PROCESS_TAG(tag, value) \ -while(true) { \ -index = msg.find(tag); \ -if (index == Jupiter::INVALID_INDEX) break; \ -msg.replace(index, tag.size(), value); } +double get_ratio(double num, double denom) +{ + if (denom == 0.0f) + return num; + return num / denom; +} void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, const RenX::PlayerInfo *player, const RenX::PlayerInfo *victim, const RenX::BuildingInfo *building) { @@ -372,6 +439,7 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, PROCESS_TAG(this->INTERNAL_TEAM_LONG_TAG, RenX::getFullTeamName(player->team)); PROCESS_TAG(this->INTERNAL_PING_TAG, Jupiter::StringS::Format("%hu", player->ping)); PROCESS_TAG(this->INTERNAL_SCORE_TAG, Jupiter::StringS::Format("%.0f", player->score)); + PROCESS_TAG(this->INTERNAL_SCORE_PER_MINUTE_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(player->score), static_cast((std::chrono::steady_clock::now() - player->joinTime).count()) / 60.0))); PROCESS_TAG(this->INTERNAL_CREDITS_TAG, Jupiter::StringS::Format("%.0f", player->credits)); PROCESS_TAG(this->INTERNAL_KILLS_TAG, Jupiter::StringS::Format("%u", player->kills)); PROCESS_TAG(this->INTERNAL_DEATHS_TAG, Jupiter::StringS::Format("%u", player->deaths)); @@ -382,7 +450,7 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, PROCESS_TAG(this->INTERNAL_BUILDING_KILLS_TAG, Jupiter::StringS::Format("%u", player->buildingKills)); PROCESS_TAG(this->INTERNAL_DEFENCE_KILLS_TAG, Jupiter::StringS::Format("%u", player->defenceKills)); PROCESS_TAG(this->INTERNAL_WINS_TAG, Jupiter::StringS::Format("%u", player->wins)); - PROCESS_TAG(this->INTERNAL_LOSES_TAG, Jupiter::StringS::Format("%u", player->loses)); + PROCESS_TAG(this->INTERNAL_LOSSES_TAG, Jupiter::StringS::Format("%u", player->loses)); PROCESS_TAG(this->INTERNAL_BEACON_PLACEMENTS_TAG, Jupiter::StringS::Format("%u", player->beaconPlacements)); PROCESS_TAG(this->INTERNAL_BEACON_DISARMS_TAG, Jupiter::StringS::Format("%u", player->beaconDisarms)); PROCESS_TAG(this->INTERNAL_CAPTURES_TAG, Jupiter::StringS::Format("%u", player->captures)); @@ -408,6 +476,7 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, PROCESS_TAG(this->INTERNAL_VICTIM_TEAM_LONG_TAG, RenX::getFullTeamName(victim->team)); PROCESS_TAG(this->INTERNAL_VICTIM_PING_TAG, Jupiter::StringS::Format("%hu", victim->ping)); PROCESS_TAG(this->INTERNAL_VICTIM_SCORE_TAG, Jupiter::StringS::Format("%.0f", victim->score)); + PROCESS_TAG(this->INTERNAL_VICTIM_SCORE_PER_MINUTE_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(victim->score), static_cast((std::chrono::steady_clock::now() - victim->joinTime).count()) / 60.0))); PROCESS_TAG(this->INTERNAL_VICTIM_CREDITS_TAG, Jupiter::StringS::Format("%.0f", victim->credits)); PROCESS_TAG(this->INTERNAL_VICTIM_KILLS_TAG, Jupiter::StringS::Format("%u", victim->kills)); PROCESS_TAG(this->INTERNAL_VICTIM_DEATHS_TAG, Jupiter::StringS::Format("%u", victim->deaths)); @@ -418,7 +487,7 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, PROCESS_TAG(this->INTERNAL_VICTIM_BUILDING_KILLS_TAG, Jupiter::StringS::Format("%u", victim->buildingKills)); PROCESS_TAG(this->INTERNAL_VICTIM_DEFENCE_KILLS_TAG, Jupiter::StringS::Format("%u", victim->defenceKills)); PROCESS_TAG(this->INTERNAL_VICTIM_WINS_TAG, Jupiter::StringS::Format("%u", victim->wins)); - PROCESS_TAG(this->INTERNAL_VICTIM_LOSES_TAG, Jupiter::StringS::Format("%u", victim->loses)); + PROCESS_TAG(this->INTERNAL_VICTIM_LOSSES_TAG, Jupiter::StringS::Format("%u", victim->loses)); PROCESS_TAG(this->INTERNAL_VICTIM_BEACON_PLACEMENTS_TAG, Jupiter::StringS::Format("%u", victim->beaconPlacements)); PROCESS_TAG(this->INTERNAL_VICTIM_BEACON_DISARMS_TAG, Jupiter::StringS::Format("%u", victim->beaconDisarms)); PROCESS_TAG(this->INTERNAL_VICTIM_CAPTURES_TAG, Jupiter::StringS::Format("%u", victim->captures)); @@ -440,8 +509,66 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, } Jupiter::ArrayList &xPlugins = *RenX::getCore()->getPlugins(); - for (size_t i = 0; i < xPlugins.size(); i++) - xPlugins.get(i)->RenX_ProcessTags(msg, server, player, victim, building); + for (index = 0; index < xPlugins.size(); ++index) + xPlugins.get(index)->RenX_ProcessTags(msg, server, player, victim, building); +} + +void TagsImp::processTags(Jupiter::StringType &msg, const RenX::LadderDatabase::Entry &entry) +{ + size_t index; + uint32_t total_tied_games = entry.total_wins - entry.total_gdi_wins - entry.total_nod_wins; + uint32_t total_nontied_games = entry.total_games - total_tied_games; + + PROCESS_TAG(this->INTERNAL_NAME_TAG, entry.most_recent_name); + PROCESS_TAG(this->INTERNAL_STEAM_TAG, Jupiter::StringS::Format("%llu", entry.steam_id)); + PROCESS_TAG(this->INTERNAL_LAST_GAME_TAG, Jupiter::StringS::Format("XX Xuary 20XX at 00:00:00")); // TODO: format this! + PROCESS_TAG(this->INTERNAL_RANK_TAG, Jupiter::StringS::Format("%u", entry.rank)); + + /** Totals */ + PROCESS_TAG(this->INTERNAL_SCORE_TAG, Jupiter::StringS::Format("%llu", entry.total_score)); + PROCESS_TAG(this->INTERNAL_KILLS_TAG, Jupiter::StringS::Format("%u", entry.total_kills)); + PROCESS_TAG(this->INTERNAL_DEATHS_TAG, Jupiter::StringS::Format("%u", entry.total_deaths)); + PROCESS_TAG(this->INTERNAL_KDR_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(entry.total_kills), static_cast(entry.total_deaths)))); + PROCESS_TAG(this->INTERNAL_SCORE_PER_MINUTE_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(entry.total_score), static_cast(entry.total_game_time) / 60.0))); + PROCESS_TAG(this->INTERNAL_HEADSHOTS_TAG, Jupiter::StringS::Format("%u", entry.total_headshot_kills)); + PROCESS_TAG(this->INTERNAL_VEHICLE_KILLS_TAG, Jupiter::StringS::Format("%u", entry.total_vehicle_kills)); + PROCESS_TAG(this->INTERNAL_BUILDING_KILLS_TAG, Jupiter::StringS::Format("%u", entry.total_building_kills)); + PROCESS_TAG(this->INTERNAL_DEFENCE_KILLS_TAG, Jupiter::StringS::Format("%u", entry.total_defence_kills)); + PROCESS_TAG(this->INTERNAL_CAPTURES_TAG, Jupiter::StringS::Format("%u", entry.total_captures)); + PROCESS_TAG(this->INTERNAL_GAME_TIME_TAG, Jupiter::StringS::Format("%u", entry.total_game_time)); + PROCESS_TAG(this->INTERNAL_GAMES_TAG, Jupiter::StringS::Format("%u", entry.total_games)); + PROCESS_TAG(this->INTERNAL_GDI_GAMES_TAG, Jupiter::StringS::Format("%u", entry.total_gdi_games)); + PROCESS_TAG(this->INTERNAL_NOD_GAMES_TAG, Jupiter::StringS::Format("%u", entry.total_nod_games)); + PROCESS_TAG(this->INTERNAL_WINS_TAG, Jupiter::StringS::Format("%u", entry.total_wins)); + PROCESS_TAG(this->INTERNAL_GDI_WINS_TAG, Jupiter::StringS::Format("%u", entry.total_gdi_wins)); + PROCESS_TAG(this->INTERNAL_NOD_WINS_TAG, Jupiter::StringS::Format("%u", entry.total_nod_wins)); + PROCESS_TAG(this->INTERNAL_TIES_TAG, Jupiter::StringS::Format("%u", total_tied_games)); + PROCESS_TAG(this->INTERNAL_LOSSES_TAG, Jupiter::StringS::Format("%u", total_nontied_games - entry.total_wins)); + PROCESS_TAG(this->INTERNAL_GDI_LOSSES_TAG, Jupiter::StringS::Format("%u", total_nontied_games - entry.total_gdi_wins)); + PROCESS_TAG(this->INTERNAL_NOD_LOSSES_TAG, Jupiter::StringS::Format("%u", total_nontied_games - entry.total_nod_wins)); + + PROCESS_TAG(this->INTERNAL_WIN_LOSS_RATIO_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(entry.total_wins), static_cast(total_nontied_games - entry.total_wins)))); + PROCESS_TAG(this->INTERNAL_GDI_WIN_LOSS_RATIO_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(entry.total_gdi_wins), static_cast(total_nontied_games - entry.total_gdi_wins)))); + PROCESS_TAG(this->INTERNAL_NOD_WIN_LOSS_RATIO_TAG, Jupiter::StringS::Format("%.2f", get_ratio(static_cast(entry.total_nod_wins), static_cast(total_nontied_games - entry.total_nod_wins)))); + PROCESS_TAG(this->INTERNAL_BEACON_PLACEMENTS_TAG, Jupiter::StringS::Format("%u", entry.total_beacon_placements)); + PROCESS_TAG(this->INTERNAL_BEACON_DISARMS_TAG, Jupiter::StringS::Format("%u", entry.total_beacon_disarms)); + PROCESS_TAG(this->INTERNAL_PROXY_PLACEMENTS_TAG, Jupiter::StringS::Format("%u", entry.total_proxy_placements)); + PROCESS_TAG(this->INTERNAL_PROXY_DISARMS_TAG, Jupiter::StringS::Format("%u", entry.total_proxy_disarms)); + + /** Tops */ + PROCESS_TAG(this->INTERNAL_VICTIM_SCORE_TAG, Jupiter::StringS::Format("%llu", entry.top_score)); + PROCESS_TAG(this->INTERNAL_VICTIM_KILLS_TAG, Jupiter::StringS::Format("%u", entry.top_kills)); + PROCESS_TAG(this->INTERNAL_VICTIM_DEATHS_TAG, Jupiter::StringS::Format("%u", entry.most_deaths)); + PROCESS_TAG(this->INTERNAL_VICTIM_HEADSHOTS_TAG, Jupiter::StringS::Format("%u", entry.top_headshot_kills)); + PROCESS_TAG(this->INTERNAL_VICTIM_VEHICLE_KILLS_TAG, Jupiter::StringS::Format("%u", entry.top_vehicle_kills)); + PROCESS_TAG(this->INTERNAL_VICTIM_BUILDING_KILLS_TAG, Jupiter::StringS::Format("%u", entry.top_building_kills)); + PROCESS_TAG(this->INTERNAL_VICTIM_DEFENCE_KILLS_TAG, Jupiter::StringS::Format("%u", entry.top_defence_kills)); + PROCESS_TAG(this->INTERNAL_VICTIM_CAPTURES_TAG, Jupiter::StringS::Format("%u", entry.top_captures)); + PROCESS_TAG(this->INTERNAL_VICTIM_GAME_TIME_TAG, Jupiter::StringS::Format("%u", entry.top_game_time)); + PROCESS_TAG(this->INTERNAL_VICTIM_BEACON_PLACEMENTS_TAG, Jupiter::StringS::Format("%u", entry.top_beacon_placements)); + PROCESS_TAG(this->INTERNAL_VICTIM_BEACON_DISARMS_TAG, Jupiter::StringS::Format("%u", entry.top_beacon_disarms)); + PROCESS_TAG(this->INTERNAL_VICTIM_PROXY_PLACEMENTS_TAG, Jupiter::StringS::Format("%u", entry.top_proxy_placements)); + PROCESS_TAG(this->INTERNAL_VICTIM_PROXY_DISARMS_TAG, Jupiter::StringS::Format("%u", entry.top_proxy_disarms)); } void TagsImp::sanitizeTags(Jupiter::StringType &fmt) @@ -482,6 +609,7 @@ void TagsImp::sanitizeTags(Jupiter::StringType &fmt) fmt.replace(this->teamLongTag, this->INTERNAL_TEAM_LONG_TAG); fmt.replace(this->pingTag, this->INTERNAL_PING_TAG); fmt.replace(this->scoreTag, this->INTERNAL_SCORE_TAG); + fmt.replace(this->scorePerMinuteTag, this->INTERNAL_SCORE_PER_MINUTE_TAG); fmt.replace(this->creditsTag, this->INTERNAL_CREDITS_TAG); fmt.replace(this->killsTag, this->INTERNAL_KILLS_TAG); fmt.replace(this->deathsTag, this->INTERNAL_DEATHS_TAG); @@ -491,10 +619,24 @@ void TagsImp::sanitizeTags(Jupiter::StringType &fmt) fmt.replace(this->vehicleKillsTag, this->INTERNAL_VEHICLE_KILLS_TAG); fmt.replace(this->buildingKillsTag, this->INTERNAL_BUILDING_KILLS_TAG); fmt.replace(this->defenceKillsTag, this->INTERNAL_DEFENCE_KILLS_TAG); + fmt.replace(this->gameTimeTag, this->INTERNAL_GAME_TIME_TAG); + fmt.replace(this->gamesTag, this->INTERNAL_GAMES_TAG); + fmt.replace(this->GDIGamesTag, this->INTERNAL_GDI_GAMES_TAG); + fmt.replace(this->NodGamesTag, this->INTERNAL_NOD_GAMES_TAG); fmt.replace(this->winsTag, this->INTERNAL_WINS_TAG); - fmt.replace(this->losesTag, this->INTERNAL_LOSES_TAG); + fmt.replace(this->GDIWinsTag, this->INTERNAL_GDI_WINS_TAG); + fmt.replace(this->NodWinsTag, this->INTERNAL_NOD_WINS_TAG); + fmt.replace(this->tiesTag, this->INTERNAL_TIES_TAG); + fmt.replace(this->lossesTag, this->INTERNAL_LOSSES_TAG); + fmt.replace(this->GDILossesTag, this->INTERNAL_GDI_LOSSES_TAG); + fmt.replace(this->NodLossesTag, this->INTERNAL_NOD_LOSSES_TAG); + fmt.replace(this->winLossRatioTag, this->INTERNAL_WIN_LOSS_RATIO_TAG); + fmt.replace(this->GDIWinLossRatioTag, this->INTERNAL_GDI_WIN_LOSS_RATIO_TAG); + fmt.replace(this->NodWinLossRatioTag, this->INTERNAL_NOD_WIN_LOSS_RATIO_TAG); fmt.replace(this->beaconPlacementsTag, this->INTERNAL_BEACON_PLACEMENTS_TAG); fmt.replace(this->beaconDisarmsTag, this->INTERNAL_BEACON_DISARMS_TAG); + fmt.replace(this->proxyPlacementsTag, this->INTERNAL_PROXY_PLACEMENTS_TAG); + fmt.replace(this->proxyDisarmsTag, this->INTERNAL_PROXY_DISARMS_TAG); fmt.replace(this->capturesTag, this->INTERNAL_CAPTURES_TAG); fmt.replace(this->stealsTag, this->INTERNAL_STEALS_TAG); fmt.replace(this->stolenTag, this->INTERNAL_STOLEN_TAG); @@ -518,6 +660,7 @@ void TagsImp::sanitizeTags(Jupiter::StringType &fmt) fmt.replace(this->victimTeamLongTag, this->INTERNAL_VICTIM_TEAM_LONG_TAG); fmt.replace(this->victimPingTag, this->INTERNAL_VICTIM_PING_TAG); fmt.replace(this->victimScoreTag, this->INTERNAL_VICTIM_SCORE_TAG); + fmt.replace(this->victimScorePerMinuteTag, this->INTERNAL_SCORE_PER_MINUTE_TAG); fmt.replace(this->victimCreditsTag, this->INTERNAL_VICTIM_CREDITS_TAG); fmt.replace(this->victimKillsTag, this->INTERNAL_VICTIM_KILLS_TAG); fmt.replace(this->victimDeathsTag, this->INTERNAL_VICTIM_DEATHS_TAG); @@ -527,10 +670,24 @@ void TagsImp::sanitizeTags(Jupiter::StringType &fmt) fmt.replace(this->victimVehicleKillsTag, this->INTERNAL_VICTIM_VEHICLE_KILLS_TAG); fmt.replace(this->victimBuildingKillsTag, this->INTERNAL_VICTIM_BUILDING_KILLS_TAG); fmt.replace(this->victimDefenceKillsTag, this->INTERNAL_VICTIM_DEFENCE_KILLS_TAG); + fmt.replace(this->victimGameTimeTag, this->INTERNAL_VICTIM_GAME_TIME_TAG); + fmt.replace(this->victimGamesTag, this->INTERNAL_VICTIM_GAMES_TAG); + fmt.replace(this->victimGDIGamesTag, this->INTERNAL_VICTIM_GDI_GAMES_TAG); + fmt.replace(this->victimNodGamesTag, this->INTERNAL_VICTIM_NOD_GAMES_TAG); fmt.replace(this->victimWinsTag, this->INTERNAL_VICTIM_WINS_TAG); - fmt.replace(this->victimLosesTag, this->INTERNAL_VICTIM_LOSES_TAG); + fmt.replace(this->victimGDIWinsTag, this->INTERNAL_VICTIM_GDI_WINS_TAG); + fmt.replace(this->victimNodWinsTag, this->INTERNAL_VICTIM_NOD_WINS_TAG); + fmt.replace(this->victimTiesTag, this->INTERNAL_VICTIM_TIES_TAG); + fmt.replace(this->victimLossesTag, this->INTERNAL_VICTIM_LOSSES_TAG); + fmt.replace(this->victimGDILossesTag, this->INTERNAL_VICTIM_GDI_LOSSES_TAG); + fmt.replace(this->victimNodLossesTag, this->INTERNAL_VICTIM_NOD_LOSSES_TAG); + fmt.replace(this->victimWinLossRatioTag, this->INTERNAL_VICTIM_WIN_LOSS_RATIO_TAG); + fmt.replace(this->victimGDIWinLossRatioTag, this->INTERNAL_VICTIM_GDI_WIN_LOSS_RATIO_TAG); + fmt.replace(this->victimNodWinLossRatioTag, this->INTERNAL_VICTIM_NOD_WIN_LOSS_RATIO_TAG); fmt.replace(this->victimBeaconPlacementsTag, this->INTERNAL_VICTIM_BEACON_PLACEMENTS_TAG); fmt.replace(this->victimBeaconDisarmsTag, this->INTERNAL_VICTIM_BEACON_DISARMS_TAG); + fmt.replace(this->victimProxyPlacementsTag, this->INTERNAL_VICTIM_PROXY_PLACEMENTS_TAG); + fmt.replace(this->victimProxyDisarmsTag, this->INTERNAL_VICTIM_PROXY_DISARMS_TAG); fmt.replace(this->victimCapturesTag, this->INTERNAL_VICTIM_CAPTURES_TAG); fmt.replace(this->victimStealsTag, this->INTERNAL_VICTIM_STEALS_TAG); fmt.replace(this->victimStolenTag, this->INTERNAL_VICTIM_STOLEN_TAG); @@ -554,6 +711,8 @@ void TagsImp::sanitizeTags(Jupiter::StringType &fmt) fmt.replace(this->newNameTag, this->INTERNAL_NEW_NAME_TAG); fmt.replace(this->winScoreTag, this->INTERNAL_WIN_SCORE_TAG); fmt.replace(this->loseScoreTag, this->INTERNAL_LOSE_SCORE_TAG); + fmt.replace(this->lastGameTag, this->INTERNAL_LAST_GAME_TAG); + fmt.replace(this->rankTag, this->INTERNAL_RANK_TAG); Jupiter::ArrayList &xPlugins = *RenX::getCore()->getPlugins(); for (size_t i = 0; i < xPlugins.size(); i++) @@ -582,6 +741,11 @@ void RenX::processTags(Jupiter::StringType &msg, const RenX::Server *server, con _tags.processTags(msg, server, player, victim, building); } +void RenX::processTags(Jupiter::StringType &msg, const RenX::LadderDatabase::Entry &entry) +{ + _tags.processTags(msg, entry); +} + void RenX::sanitizeTags(Jupiter::StringType &fmt) { _tags.sanitizeTags(fmt); diff --git a/RenX.Core/RenX_Tags.h b/RenX.Core/RenX_Tags.h index 37bcded..a0eb0b7 100644 --- a/RenX.Core/RenX_Tags.h +++ b/RenX.Core/RenX_Tags.h @@ -27,6 +27,7 @@ #include "Jupiter/String.h" #include "Jupiter/CString.h" #include "RenX.h" +#include "RenX_LadderDatabase.h" /** DLL Linkage Nagging */ #if defined _MSC_VER @@ -39,8 +40,10 @@ namespace RenX /** Forward declarations */ struct PlayerInfo; class Server; + struct BuildingInfo; RENX_API void processTags(Jupiter::StringType &msg, const RenX::Server *server = nullptr, const RenX::PlayerInfo *player = nullptr, const RenX::PlayerInfo *victim = nullptr, const RenX::BuildingInfo *building = nullptr); + RENX_API void processTags(Jupiter::StringType &msg, const RenX::LadderDatabase::Entry &entry); RENX_API void sanitizeTags(Jupiter::StringType &fmt); RENX_API const Jupiter::ReadableString &getUniqueInternalTag(); @@ -86,6 +89,7 @@ namespace RenX Jupiter::StringS INTERNAL_TEAM_LONG_TAG; Jupiter::StringS INTERNAL_PING_TAG; Jupiter::StringS INTERNAL_SCORE_TAG; + Jupiter::StringS INTERNAL_SCORE_PER_MINUTE_TAG; Jupiter::StringS INTERNAL_CREDITS_TAG; Jupiter::StringS INTERNAL_KILLS_TAG; Jupiter::StringS INTERNAL_DEATHS_TAG; @@ -95,10 +99,24 @@ namespace RenX Jupiter::StringS INTERNAL_VEHICLE_KILLS_TAG; Jupiter::StringS INTERNAL_BUILDING_KILLS_TAG; Jupiter::StringS INTERNAL_DEFENCE_KILLS_TAG; + Jupiter::StringS INTERNAL_GAME_TIME_TAG; + Jupiter::StringS INTERNAL_GAMES_TAG; + Jupiter::StringS INTERNAL_GDI_GAMES_TAG; + Jupiter::StringS INTERNAL_NOD_GAMES_TAG; Jupiter::StringS INTERNAL_WINS_TAG; - Jupiter::StringS INTERNAL_LOSES_TAG; + Jupiter::StringS INTERNAL_GDI_WINS_TAG; + Jupiter::StringS INTERNAL_NOD_WINS_TAG; + Jupiter::StringS INTERNAL_TIES_TAG; + Jupiter::StringS INTERNAL_LOSSES_TAG; + Jupiter::StringS INTERNAL_GDI_LOSSES_TAG; + Jupiter::StringS INTERNAL_NOD_LOSSES_TAG; + Jupiter::StringS INTERNAL_WIN_LOSS_RATIO_TAG; + Jupiter::StringS INTERNAL_GDI_WIN_LOSS_RATIO_TAG; + Jupiter::StringS INTERNAL_NOD_WIN_LOSS_RATIO_TAG; Jupiter::StringS INTERNAL_BEACON_PLACEMENTS_TAG; Jupiter::StringS INTERNAL_BEACON_DISARMS_TAG; + Jupiter::StringS INTERNAL_PROXY_PLACEMENTS_TAG; + Jupiter::StringS INTERNAL_PROXY_DISARMS_TAG; Jupiter::StringS INTERNAL_CAPTURES_TAG; Jupiter::StringS INTERNAL_STEALS_TAG; Jupiter::StringS INTERNAL_STOLEN_TAG; @@ -122,6 +140,7 @@ namespace RenX Jupiter::StringS INTERNAL_VICTIM_TEAM_LONG_TAG; Jupiter::StringS INTERNAL_VICTIM_PING_TAG; Jupiter::StringS INTERNAL_VICTIM_SCORE_TAG; + Jupiter::StringS INTERNAL_VICTIM_SCORE_PER_MINUTE_TAG; Jupiter::StringS INTERNAL_VICTIM_CREDITS_TAG; Jupiter::StringS INTERNAL_VICTIM_KILLS_TAG; Jupiter::StringS INTERNAL_VICTIM_DEATHS_TAG; @@ -131,10 +150,24 @@ namespace RenX Jupiter::StringS INTERNAL_VICTIM_VEHICLE_KILLS_TAG; Jupiter::StringS INTERNAL_VICTIM_BUILDING_KILLS_TAG; Jupiter::StringS INTERNAL_VICTIM_DEFENCE_KILLS_TAG; + Jupiter::StringS INTERNAL_VICTIM_GAME_TIME_TAG; + Jupiter::StringS INTERNAL_VICTIM_GAMES_TAG; + Jupiter::StringS INTERNAL_VICTIM_GDI_GAMES_TAG; + Jupiter::StringS INTERNAL_VICTIM_NOD_GAMES_TAG; Jupiter::StringS INTERNAL_VICTIM_WINS_TAG; - Jupiter::StringS INTERNAL_VICTIM_LOSES_TAG; + Jupiter::StringS INTERNAL_VICTIM_GDI_WINS_TAG; + Jupiter::StringS INTERNAL_VICTIM_NOD_WINS_TAG; + Jupiter::StringS INTERNAL_VICTIM_TIES_TAG; + Jupiter::StringS INTERNAL_VICTIM_LOSSES_TAG; + Jupiter::StringS INTERNAL_VICTIM_GDI_LOSSES_TAG; + Jupiter::StringS INTERNAL_VICTIM_NOD_LOSSES_TAG; + Jupiter::StringS INTERNAL_VICTIM_WIN_LOSS_RATIO_TAG; + Jupiter::StringS INTERNAL_VICTIM_GDI_WIN_LOSS_RATIO_TAG; + Jupiter::StringS INTERNAL_VICTIM_NOD_WIN_LOSS_RATIO_TAG; Jupiter::StringS INTERNAL_VICTIM_BEACON_PLACEMENTS_TAG; Jupiter::StringS INTERNAL_VICTIM_BEACON_DISARMS_TAG; + Jupiter::StringS INTERNAL_VICTIM_PROXY_PLACEMENTS_TAG; + Jupiter::StringS INTERNAL_VICTIM_PROXY_DISARMS_TAG; Jupiter::StringS INTERNAL_VICTIM_CAPTURES_TAG; Jupiter::StringS INTERNAL_VICTIM_STEALS_TAG; Jupiter::StringS INTERNAL_VICTIM_STOLEN_TAG; @@ -158,6 +191,8 @@ namespace RenX Jupiter::StringS INTERNAL_NEW_NAME_TAG; Jupiter::StringS INTERNAL_WIN_SCORE_TAG; Jupiter::StringS INTERNAL_LOSE_SCORE_TAG; + Jupiter::StringS INTERNAL_LAST_GAME_TAG; + Jupiter::StringS INTERNAL_RANK_TAG; /** External message tags */ @@ -197,6 +232,7 @@ namespace RenX Jupiter::StringS teamLongTag; Jupiter::StringS pingTag; Jupiter::StringS scoreTag; + Jupiter::StringS scorePerMinuteTag; Jupiter::StringS creditsTag; Jupiter::StringS killsTag; Jupiter::StringS deathsTag; @@ -206,10 +242,24 @@ namespace RenX Jupiter::StringS vehicleKillsTag; Jupiter::StringS buildingKillsTag; Jupiter::StringS defenceKillsTag; + Jupiter::StringS gameTimeTag; + Jupiter::StringS gamesTag; + Jupiter::StringS GDIGamesTag; + Jupiter::StringS NodGamesTag; Jupiter::StringS winsTag; - Jupiter::StringS losesTag; + Jupiter::StringS GDIWinsTag; + Jupiter::StringS NodWinsTag; + Jupiter::StringS tiesTag; + Jupiter::StringS lossesTag; + Jupiter::StringS GDILossesTag; + Jupiter::StringS NodLossesTag; + Jupiter::StringS winLossRatioTag; + Jupiter::StringS GDIWinLossRatioTag; + Jupiter::StringS NodWinLossRatioTag; Jupiter::StringS beaconPlacementsTag; Jupiter::StringS beaconDisarmsTag; + Jupiter::StringS proxyPlacementsTag; + Jupiter::StringS proxyDisarmsTag; Jupiter::StringS capturesTag; Jupiter::StringS stealsTag; Jupiter::StringS stolenTag; @@ -233,6 +283,7 @@ namespace RenX Jupiter::StringS victimTeamLongTag; Jupiter::StringS victimPingTag; Jupiter::StringS victimScoreTag; + Jupiter::StringS victimScorePerMinuteTag; Jupiter::StringS victimCreditsTag; Jupiter::StringS victimKillsTag; Jupiter::StringS victimDeathsTag; @@ -242,10 +293,24 @@ namespace RenX Jupiter::StringS victimVehicleKillsTag; Jupiter::StringS victimBuildingKillsTag; Jupiter::StringS victimDefenceKillsTag; + Jupiter::StringS victimGameTimeTag; + Jupiter::StringS victimGamesTag; + Jupiter::StringS victimGDIGamesTag; + Jupiter::StringS victimNodGamesTag; Jupiter::StringS victimWinsTag; - Jupiter::StringS victimLosesTag; + Jupiter::StringS victimGDIWinsTag; + Jupiter::StringS victimNodWinsTag; + Jupiter::StringS victimTiesTag; + Jupiter::StringS victimLossesTag; + Jupiter::StringS victimGDILossesTag; + Jupiter::StringS victimNodLossesTag; + Jupiter::StringS victimWinLossRatioTag; + Jupiter::StringS victimGDIWinLossRatioTag; + Jupiter::StringS victimNodWinLossRatioTag; Jupiter::StringS victimBeaconPlacementsTag; Jupiter::StringS victimBeaconDisarmsTag; + Jupiter::StringS victimProxyPlacementsTag; + Jupiter::StringS victimProxyDisarmsTag; Jupiter::StringS victimCapturesTag; Jupiter::StringS victimStealsTag; Jupiter::StringS victimStolenTag; @@ -269,11 +334,20 @@ namespace RenX Jupiter::StringS newNameTag; Jupiter::StringS winScoreTag; Jupiter::StringS loseScoreTag; + Jupiter::StringS lastGameTag; + Jupiter::StringS rankTag; }; RENX_API extern Tags *tags; } +/** Helper macro for processing tags */ +#define PROCESS_TAG(tag, value) \ +while(true) { \ +index = msg.find(tag); \ +if (index == Jupiter::INVALID_INDEX) break; \ +msg.replace(index, tag.size(), value); } + /** Re-enable warnings */ #if defined _MSC_VER #pragma warning(pop) diff --git a/RenX.Ladder.Web/RenX.Ladder.Web.vcxproj b/RenX.Ladder.Web/RenX.Ladder.Web.vcxproj new file mode 100644 index 0000000..3bddbed --- /dev/null +++ b/RenX.Ladder.Web/RenX.Ladder.Web.vcxproj @@ -0,0 +1,86 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {57661A2A-EE94-4E9C-B792-AB756533DEFA} + RenX.Ladder.Web + + + + Application + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\Plugins\ + AllRules.ruleset + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + ../Bot;../Jupiter;../RenX.Core;../HTTPServer + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RenX.Ladder.Web/RenX.Ladder.Web.vcxproj.filters b/RenX.Ladder.Web/RenX.Ladder.Web.vcxproj.filters new file mode 100644 index 0000000..1bd8865 --- /dev/null +++ b/RenX.Ladder.Web/RenX.Ladder.Web.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/RenX.Ladder.Web/RenX_Ladder_Web.cpp b/RenX.Ladder.Web/RenX_Ladder_Web.cpp new file mode 100644 index 0000000..ee90699 --- /dev/null +++ b/RenX.Ladder.Web/RenX_Ladder_Web.cpp @@ -0,0 +1,339 @@ +/** + * Copyright (C) 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#include "Jupiter/IRC_Client.h" +#include "Jupiter/INIFile.h" +#include "Jupiter/HTTP.h" +#include "Jupiter/HTTP_QueryString.h" +#include "HTTPServer.h" +#include "RenX_Tags.h" +#include "RenX_Ladder_Web.h" + +using namespace Jupiter::literals; + +RenX_Ladder_WebPlugin::RenX_Ladder_WebPlugin() +{ + RenX_Ladder_WebPlugin::ladder_page_name = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "LadderPageName"_jrs, ""_jrs); + RenX_Ladder_WebPlugin::search_page_name = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "SearchPageName"_jrs, "search"_jrs); + RenX_Ladder_WebPlugin::profile_page_name = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "ProfilePageName"_jrs, "profile"_jrs); + RenX_Ladder_WebPlugin::web_hostname = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "Hostname"_jrs, ""_jrs); + RenX_Ladder_WebPlugin::web_path = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "Path"_jrs, "/"_jrs); + + this->OnRehash(); + + /** Initialize content */ + Jupiter::HTTP::Server &server = getHTTPServer(); + + Jupiter::HTTP::Server::Content *content = new Jupiter::HTTP::Server::Content(RenX_Ladder_WebPlugin::ladder_page_name, handle_ladder_page); + content->language = &Jupiter::HTTP::Content::Language::ENGLISH; + content->type = &Jupiter::HTTP::Content::Type::Text::HTML; + content->charset = &Jupiter::HTTP::Content::Type::Text::Charset::UTF8; + server.hook(RenX_Ladder_WebPlugin::web_hostname, RenX_Ladder_WebPlugin::web_path, content); + + content = new Jupiter::HTTP::Server::Content(RenX_Ladder_WebPlugin::search_page_name, handle_search_page); + content->language = &Jupiter::HTTP::Content::Language::ENGLISH; + content->type = &Jupiter::HTTP::Content::Type::Text::HTML; + content->charset = &Jupiter::HTTP::Content::Type::Text::Charset::UTF8; + server.hook(RenX_Ladder_WebPlugin::web_hostname, RenX_Ladder_WebPlugin::web_path, content); + + content = new Jupiter::HTTP::Server::Content(RenX_Ladder_WebPlugin::profile_page_name, handle_profile_page); + content->language = &Jupiter::HTTP::Content::Language::ENGLISH; + content->type = &Jupiter::HTTP::Content::Type::Text::HTML; + content->charset = &Jupiter::HTTP::Content::Type::Text::Charset::UTF8; + server.hook(RenX_Ladder_WebPlugin::web_hostname, RenX_Ladder_WebPlugin::web_path, content); +} + +RenX_Ladder_WebPlugin::~RenX_Ladder_WebPlugin() +{ + Jupiter::HTTP::Server &server = getHTTPServer(); + server.remove(RenX_Ladder_WebPlugin::web_hostname, RenX_Ladder_WebPlugin::web_path, RenX_Ladder_WebPlugin::ladder_page_name); + server.remove(RenX_Ladder_WebPlugin::web_hostname, RenX_Ladder_WebPlugin::web_path, RenX_Ladder_WebPlugin::search_page_name); + server.remove(RenX_Ladder_WebPlugin::web_hostname, RenX_Ladder_WebPlugin::web_path, RenX_Ladder_WebPlugin::profile_page_name); +} + +int RenX_Ladder_WebPlugin::OnRehash() +{ + FILE *file; + int chr; + + RenX_Ladder_WebPlugin::web_header_filename = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "HeaderFilename"_jrs, "RenX.Ladder.Web.Header.html"_jrs); + RenX_Ladder_WebPlugin::web_footer_filename = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "FooterFilename"_jrs, "RenX.Ladder.Web.Footer.html"_jrs); + RenX_Ladder_WebPlugin::web_profile_filename = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "ProfileFilename"_jrs, "RenX.Ladder.Web.Profile.html"_jrs); + RenX_Ladder_WebPlugin::web_ladder_table_header_filename = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "LadderTableHeaderFilename"_jrs, "RenX.Ladder.Web.Ladder.Table.Header.html"_jrs); + RenX_Ladder_WebPlugin::web_ladder_table_footer_filename = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "LadderTableFooterFilename"_jrs, "RenX.Ladder.Web.Ladder.Table.Footer.html"_jrs); + + RenX_Ladder_WebPlugin::entry_table_row = Jupiter::IRC::Client::Config->get(RenX_Ladder_WebPlugin::name, "EntryTableRow"_jrs, "{RANK}{NAME}{SCORE}{SPM}{KILLS}{DEATHS}{KDR}{NODGAMES}{NODWINS}{NODLOSSES}{NWLR}{GDIGAMES}{GDIWINS}{GDILOSSES}{GWLR}"_jrs); + RenX::sanitizeTags(RenX_Ladder_WebPlugin::entry_table_row); + + RenX_Ladder_WebPlugin::header.erase(); + RenX_Ladder_WebPlugin::footer.erase(); + RenX_Ladder_WebPlugin::entry_profile.erase(); + RenX_Ladder_WebPlugin::ladder_table_header.erase(); + RenX_Ladder_WebPlugin::ladder_table_footer.erase(); + + /** Load header */ + if (RenX_Ladder_WebPlugin::web_header_filename.isNotEmpty()) + { + file = fopen(RenX_Ladder_WebPlugin::web_header_filename.c_str(), "rb"); + if (file != nullptr) + { + while ((chr = fgetc(file)) != EOF) + RenX_Ladder_WebPlugin::header += chr; + fclose(file); + } + } + + /** Load footer */ + if (RenX_Ladder_WebPlugin::web_footer_filename.isNotEmpty()) + { + file = fopen(RenX_Ladder_WebPlugin::web_footer_filename.c_str(), "rb"); + if (file != nullptr) + { + while ((chr = fgetc(file)) != EOF) + RenX_Ladder_WebPlugin::footer += chr; + fclose(file); + } + } + + /** Load profile */ + if (RenX_Ladder_WebPlugin::web_profile_filename.isNotEmpty()) + { + file = fopen(RenX_Ladder_WebPlugin::web_profile_filename.c_str(), "rb"); + if (file != nullptr) + { + while ((chr = fgetc(file)) != EOF) + RenX_Ladder_WebPlugin::entry_profile += chr; + RenX::sanitizeTags(RenX_Ladder_WebPlugin::entry_profile); + fclose(file); + } + } + + /** Load table header */ + if (RenX_Ladder_WebPlugin::web_ladder_table_header_filename.isNotEmpty()) + { + file = fopen(RenX_Ladder_WebPlugin::web_ladder_table_header_filename.c_str(), "rb"); + if (file != nullptr) + { + while ((chr = fgetc(file)) != EOF) + RenX_Ladder_WebPlugin::ladder_table_header += chr; + fclose(file); + } + } + + /** Load table footer */ + if (RenX_Ladder_WebPlugin::web_ladder_table_footer_filename.isNotEmpty()) + { + file = fopen(RenX_Ladder_WebPlugin::web_ladder_table_footer_filename.c_str(), "rb"); + if (file != nullptr) + { + while ((chr = fgetc(file)) != EOF) + RenX_Ladder_WebPlugin::ladder_table_footer += chr; + fclose(file); + } + } + + return 0; +} + +/** Ladder page */ + +Jupiter::String RenX_Ladder_WebPlugin::generate_entry_table(size_t index, size_t count) +{ + if (RenX::ladder_databases.size() == 0) + return Jupiter::String("Error: No ladder databases loaded"_jrs); + + RenX::LadderDatabase *db = RenX::ladder_databases.get(0); + + if (db->getEntries() == 0) // No ladder data + return Jupiter::String("Error: No ladder data"_jrs); + + if (index >= db->getEntries() || count == 0) // Invalid entry range + return Jupiter::String("Error: Invalid range"_jrs); + + if (index + count > db->getEntries()) // Invalid entry range; use valid portion of range + count = db->getEntries() - index; + + RenX::LadderDatabase::Entry *node = db->getHead(); + + // iterate to requested index + while (index != 0) + { + node = node->next; + --index; + } + + // table header + Jupiter::String result(2048); + result = RenX_Ladder_WebPlugin::ladder_table_header; + + // append rows + Jupiter::String row(256); + while (count != 0) + { + row = RenX_Ladder_WebPlugin::entry_table_row; + RenX::processTags(row, *node); + result += row; + --count; + } + + // table footer + result += RenX_Ladder_WebPlugin::ladder_table_footer; + return result; +} + +Jupiter::String *RenX_Ladder_WebPlugin::generate_ladder_page(size_t index, size_t count) +{ + Jupiter::String *result = new Jupiter::String(RenX_Ladder_WebPlugin::header); + result->concat(this->generate_entry_table(index, count)); + result->concat(RenX_Ladder_WebPlugin::footer); + return result; +} + +/** Search page */ +Jupiter::String *RenX_Ladder_WebPlugin::generate_search_page(const Jupiter::ReadableString &name) +{ + Jupiter::String *result = new Jupiter::String(RenX_Ladder_WebPlugin::header); + + if (RenX::ladder_databases.size() == 0) + { + result->concat("Error: No ladder databases loaded"_jrs); + result->concat(RenX_Ladder_WebPlugin::footer); + return result; + } + + RenX::LadderDatabase *db = RenX::ladder_databases.get(0); + + if (db->getEntries() == 0) // No ladder data + { + result->concat("Error: No ladder data"_jrs); + result->concat(RenX_Ladder_WebPlugin::footer); + return result; + } + + result->concat(RenX_Ladder_WebPlugin::ladder_table_header); + + // append rows + Jupiter::String row(256); + RenX::LadderDatabase::Entry *node = db->getHead(); + while (node != nullptr) + { + if (node->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) // match found + { + row = RenX_Ladder_WebPlugin::entry_table_row; + RenX::processTags(row, *node); + result->concat(row); + } + node = node->next; + } + + result->concat(RenX_Ladder_WebPlugin::ladder_table_footer); + result->concat(RenX_Ladder_WebPlugin::footer); + return result; +} + +/** Profile page */ +Jupiter::String *RenX_Ladder_WebPlugin::generate_profile_page(uint64_t steam_id) +{ + Jupiter::String *result = new Jupiter::String(RenX_Ladder_WebPlugin::header); + + if (RenX::ladder_databases.size() == 0) + { + result->concat("Error: No ladder databases loaded"_jrs); + result->concat(RenX_Ladder_WebPlugin::footer); + return result; + } + + RenX::LadderDatabase *db = RenX::ladder_databases.get(0); + + if (db->getEntries() == 0) // No ladder data + { + result->concat("Error: No ladder data"_jrs); + result->concat(RenX_Ladder_WebPlugin::footer); + return result; + } + + RenX::LadderDatabase::Entry *entry = db->getHead(); + while (entry != nullptr) + { + if (entry->steam_id == steam_id) // match found + break; + entry = entry->next; + } + + if (entry == nullptr) + result->concat("Error: Player not found"_jrs); + else + { + Jupiter::String profile_data(RenX_Ladder_WebPlugin::entry_profile); + RenX::processTags(profile_data, *entry); + result->concat(profile_data); + } + + result->concat(RenX_Ladder_WebPlugin::footer); + return result; +} + +// Plugin instantiation and entry point. +RenX_Ladder_WebPlugin pluginInstance; + +/** Content functions */ + +Jupiter::ReadableString *handle_ladder_page(const Jupiter::ReadableString &query_string) +{ + size_t start_index = 0, count = 50; + + if (query_string.isNotEmpty()) + { + Jupiter::HTTP::HTMLFormResponse html_form_response(query_string); + start_index = static_cast(html_form_response.table.getInt("start"_jrs, 0)); + count = static_cast(html_form_response.table.getInt("count"_jrs, 50)); + } + return pluginInstance.generate_ladder_page(start_index, count); +} + +Jupiter::ReadableString *handle_search_page(const Jupiter::ReadableString &query_string) +{ + Jupiter::ReferenceString name; + if (query_string.isNotEmpty()) + { + Jupiter::HTTP::HTMLFormResponse html_form_response(query_string); + name = html_form_response.table.get("name"_jrs); + } + + if (name.isEmpty()) // Generate ladder page when no name specified + return handle_ladder_page(query_string); + + return pluginInstance.generate_search_page(name); +} + +Jupiter::ReadableString *handle_profile_page(const Jupiter::ReadableString &query_string) +{ + uint64_t steam_id = 0; + if (query_string.isNotEmpty()) + { + Jupiter::HTTP::HTMLFormResponse html_form_response(query_string); + steam_id = html_form_response.table.getLongLong("id"_jrs); + } + + return pluginInstance.generate_profile_page(steam_id); +} + +extern "C" __declspec(dllexport) Jupiter::Plugin *getPlugin() +{ + return &pluginInstance; +} diff --git a/RenX.Ladder.Web/RenX_Ladder_Web.h b/RenX.Ladder.Web/RenX_Ladder_Web.h new file mode 100644 index 0000000..c4478e3 --- /dev/null +++ b/RenX.Ladder.Web/RenX_Ladder_Web.h @@ -0,0 +1,66 @@ +/** + * Copyright (C) 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#if !defined _RENX_LADDER_WEB_H +#define _RENX_LADDER_WEB_H + +#include "Jupiter/Plugin.h" +#include "Jupiter/Reference_String.h" +#include "Jupiter/CString.h" +#include "RenX_Plugin.h" + +class RenX_Ladder_WebPlugin : public RenX::Plugin +{ +protected: + Jupiter::String generate_entry_table(size_t index, size_t count); + +public: + Jupiter::StringS header; + Jupiter::StringS footer; + Jupiter::String *generate_ladder_page(size_t start_index, size_t count); + Jupiter::String *generate_search_page(const Jupiter::ReadableString &name); + Jupiter::String *generate_profile_page(uint64_t steam_id); + + RenX_Ladder_WebPlugin(); + ~RenX_Ladder_WebPlugin(); + +public: // Jupiter::Plugin + const Jupiter::ReadableString &getName() override { return name; } + int OnRehash() override; + +private: + STRING_LITERAL_AS_NAMED_REFERENCE(name, "RenX.Ladder.Web"); + + /** Configuration variables */ + Jupiter::StringS ladder_page_name, search_page_name, profile_page_name, ladder_table_header, ladder_table_footer; + Jupiter::StringS web_hostname; + Jupiter::StringS web_path; + Jupiter::CStringS web_header_filename; + Jupiter::CStringS web_footer_filename; + Jupiter::CStringS web_profile_filename; + Jupiter::CStringS web_ladder_table_header_filename; + Jupiter::CStringS web_ladder_table_footer_filename; + + Jupiter::StringS entry_table_row, entry_profile; +}; + +Jupiter::ReadableString *handle_ladder_page(const Jupiter::ReadableString ¶meters); +Jupiter::ReadableString *handle_search_page(const Jupiter::ReadableString ¶meters); +Jupiter::ReadableString *handle_profile_page(const Jupiter::ReadableString ¶meters); + +#endif // _RENX_LADDER_WEB_H \ No newline at end of file diff --git a/RenX.Ladder/RenX.Ladder.vcxproj b/RenX.Ladder/RenX.Ladder.vcxproj index 1bebfbc..fcc3980 100644 --- a/RenX.Ladder/RenX.Ladder.vcxproj +++ b/RenX.Ladder/RenX.Ladder.vcxproj @@ -60,7 +60,7 @@ true true ../Bot;../Jupiter;../RenX.Core - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;RENX_LADDER_EXPORTS;%(PreprocessorDefinitions) true @@ -69,12 +69,10 @@ - - diff --git a/RenX.Ladder/RenX.Ladder.vcxproj.filters b/RenX.Ladder/RenX.Ladder.vcxproj.filters index e820651..a3835d6 100644 --- a/RenX.Ladder/RenX.Ladder.vcxproj.filters +++ b/RenX.Ladder/RenX.Ladder.vcxproj.filters @@ -29,16 +29,10 @@ Source Files - - Source Files - Header Files - - Header Files - \ No newline at end of file diff --git a/RenX.Ladder/RenX_Ladder.cpp b/RenX.Ladder/RenX_Ladder.cpp index 1af989e..0c4b41b 100644 --- a/RenX.Ladder/RenX_Ladder.cpp +++ b/RenX.Ladder/RenX_Ladder.cpp @@ -41,107 +41,6 @@ RenX_LadderPlugin::RenX_LadderPlugin() RenX_LadderPlugin::database.process_file(RenX_LadderPlugin::db_filename); } -void RenX_LadderPlugin::updateLadder(RenX::Server *server, const RenX::TeamType &team) -{ - if (server->players.size() != 0) - { - // update player stats in memory - RenX::PlayerInfo *player; - RenX_LadderDatabase::Entry *entry; - for (Jupiter::DLList::Node *node = server->players.getNode(0); node != nullptr; node = node->next) - { - player = node->data; - if (player->steamid != 0 && (player->ban_flags & RenX::BanDatabase::Entry::FLAG_TYPE_LADDER) == 0) - { - entry = RenX_LadderPlugin::database.getPlayerEntry(player->steamid); - if (entry == nullptr) - { - entry = new RenX_LadderDatabase::Entry(); - RenX_LadderPlugin::database.append(entry); - entry->steam_id = player->steamid; - } - - entry->total_score += static_cast(player->score); - - entry->total_kills += player->kills; - entry->total_deaths += player->deaths; - entry->total_headshot_kills += player->headshots; - entry->total_vehicle_kills += player->vehicleKills; - entry->total_building_kills += player->buildingKills; - entry->total_defence_kills += player->defenceKills; - entry->total_captures += player->captures; - entry->total_game_time += static_cast(std::chrono::duration_cast(server->getGameTime(player)).count()); - ++entry->total_games; - switch (player->team) - { - case RenX::TeamType::GDI: - ++entry->total_gdi_games; - if (player->team == team) - ++entry->total_wins, ++entry->total_gdi_wins; - break; - case RenX::TeamType::Nod: - ++entry->total_nod_games; - if (player->team == team) - ++entry->total_wins, ++entry->total_nod_wins; - break; - default: - if (player->team == team) - ++entry->total_wins; - break; - } - entry->total_beacon_placements += player->beaconPlacements; - entry->total_beacon_disarms += player->beaconDisarms; - entry->total_proxy_placements += player->proxy_placements; - entry->total_proxy_disarms += player->proxy_disarms; - - auto set_if_greater = [](uint32_t &src, const uint32_t &cmp) - { - if (cmp > src) - src = cmp; - }; - - set_if_greater(entry->top_score, static_cast(player->score)); - set_if_greater(entry->top_kills, player->kills); - set_if_greater(entry->most_deaths, player->deaths); - set_if_greater(entry->top_headshot_kills, player->headshots); - set_if_greater(entry->top_vehicle_kills, player->vehicleKills); - set_if_greater(entry->top_building_kills, player->buildingKills); - set_if_greater(entry->top_defence_kills, player->defenceKills); - set_if_greater(entry->top_captures, player->captures); - set_if_greater(entry->top_game_time, static_cast(std::chrono::duration_cast(server->getGameTime(player)).count())); - set_if_greater(entry->top_beacon_placements, player->beaconPlacements); - set_if_greater(entry->top_beacon_disarms, player->beaconDisarms); - set_if_greater(entry->top_proxy_placements, player->proxy_placements); - set_if_greater(entry->top_proxy_disarms, player->proxy_disarms); - - entry->most_recent_ip = player->ip32; - entry->last_game = time(nullptr); - entry->most_recent_name = player->name; - } - } - - // sort new stats - std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); - RenX_LadderPlugin::database.sort_entries(); - std::chrono::steady_clock::duration sort_duration = std::chrono::steady_clock::now() - start_time; - - // write new stats - start_time = std::chrono::steady_clock::now(); - RenX_LadderPlugin::database.write(RenX_LadderPlugin::db_filename); - std::chrono::steady_clock::duration write_duration = std::chrono::steady_clock::now() - start_time; - - if (RenX_LadderPlugin::output_times) - { - Jupiter::StringS str = Jupiter::StringS::Format("Ladder: %u entries sorted in %f seconds; Database written in %f seconds." ENDL, - RenX_LadderPlugin::database.getEntries(), - static_cast(sort_duration.count()) * (static_cast(std::chrono::steady_clock::duration::period::num / static_cast(std::chrono::steady_clock::duration::period::den) * static_cast(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num))), - static_cast(write_duration.count()) * (static_cast(std::chrono::steady_clock::duration::period::num) / static_cast(std::chrono::steady_clock::duration::period::den) * static_cast(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num))); - str.println(stdout); - server->sendLogChan(str); - } - } -} - /** Wait until the client list has been updated to update the ladder */ void RenX_LadderPlugin::RenX_OnGameOver(RenX::Server *server, RenX::WinType winType, const RenX::TeamType &team, int gScore, int nScore) @@ -163,7 +62,7 @@ void RenX_LadderPlugin::RenX_OnCommand(RenX::Server *server, const Jupiter::Read { server->varData.set(this->name, "w"_jrs, "0"_jrs); RenX::TeamType team = static_cast(server->varData.get(this->name, "t"_jrs, "\0"_jrs).get(0)); - RenX_LadderPlugin::updateLadder(server, team); + RenX_LadderPlugin::database.updateLadder(server, team, RenX_LadderPlugin::output_times); } } } @@ -178,7 +77,7 @@ RenX_LadderPlugin pluginInstance; /** Ladder Commands */ -Jupiter::StringS FormatLadderResponse(RenX_LadderDatabase::Entry *entry, size_t rank) +Jupiter::StringS FormatLadderResponse(RenX::LadderDatabase::Entry *entry, size_t rank) { return Jupiter::StringS::Format("#%" PRIuPTR ": \"%.*s\" - Score: %" PRIu64 " - Kills: %" PRIu32 " - Deaths: %" PRIu32 " - KDR: %.2f - SPM: %.2f", rank, entry->most_recent_name.size(), entry->most_recent_name.ptr(), entry->total_score, entry->total_kills, entry->total_deaths, static_cast(entry->total_kills) / (entry->total_deaths == 0 ? 1 : static_cast(entry->total_deaths)), static_cast(entry->total_score) / (entry->total_game_time == 0 ? 1.0 : static_cast(entry->total_game_time)) * 60.0); } @@ -196,7 +95,7 @@ GenericCommand::ResponseLine *LadderGenericCommand::trigger(const Jupiter::Reada if (parameters.isEmpty()) return new GenericCommand::ResponseLine("Error: Too few parameters. Syntax: ladder "_jrs, GenericCommand::DisplayType::PrivateError); - RenX_LadderDatabase::Entry *entry; + RenX::LadderDatabase::Entry *entry; size_t rank; if (parameters.span("0123456789"_jrs) == parameters.size()) { @@ -211,11 +110,11 @@ GenericCommand::ResponseLine *LadderGenericCommand::trigger(const Jupiter::Reada return new GenericCommand::ResponseLine(FormatLadderResponse(entry, rank), GenericCommand::DisplayType::PublicSuccess); } - Jupiter::SLList> list = pluginInstance.database.getPlayerEntriesAndIndexByPartName(parameters, pluginInstance.getMaxLadderCommandPartNameOutput()); + Jupiter::SLList> list = pluginInstance.database.getPlayerEntriesAndIndexByPartName(parameters, pluginInstance.getMaxLadderCommandPartNameOutput()); if (list.size() == 0) return new GenericCommand::ResponseLine("Error: Player not found"_jrs, GenericCommand::DisplayType::PrivateError); - std::pair *pair = list.remove(0); + std::pair *pair = list.remove(0); GenericCommand::ResponseLine *response_head = new GenericCommand::ResponseLine(FormatLadderResponse(std::addressof(pair->first), pair->second + 1), GenericCommand::DisplayType::PrivateSuccess); GenericCommand::ResponseLine *response_end = response_head; delete pair; @@ -253,7 +152,7 @@ void LadderGameCommand::trigger(RenX::Server *source, RenX::PlayerInfo *player, { if (player->steamid != 0) { - std::pair pair = pluginInstance.database.getPlayerEntryAndIndex(player->steamid); + std::pair pair = pluginInstance.database.getPlayerEntryAndIndex(player->steamid); if (pair.first != nullptr) source->sendMessage(FormatLadderResponse(pair.first, pair.second + 1)); else diff --git a/RenX.Ladder/RenX_Ladder.h b/RenX.Ladder/RenX_Ladder.h index d910e36..88b97a7 100644 --- a/RenX.Ladder/RenX_Ladder.h +++ b/RenX.Ladder/RenX_Ladder.h @@ -26,6 +26,12 @@ #include "RenX_LadderDatabase.h" #include "RenX_GameCommand.h" +/** DLL Linkage Nagging */ +#if defined _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4251) +#endif + class RenX_LadderPlugin : public RenX::Plugin { public: @@ -36,10 +42,8 @@ public: size_t getMaxLadderCommandPartNameOutput() const; RenX_LadderPlugin(); - RenX_LadderDatabase database; + RenX::LadderDatabase database; private: - void updateLadder(RenX::Server *server, const RenX::TeamType &team); - /** Configuration variables */ bool only_pure, output_times; size_t max_ladder_command_part_name_output; @@ -50,4 +54,9 @@ private: GENERIC_GENERIC_COMMAND(LadderGenericCommand) GENERIC_GAME_COMMAND(LadderGameCommand) +/** Re-enable warnings */ +#if defined _MSC_VER +#pragma warning(pop) +#endif + #endif // _RENX_LADDER_H_HEADER \ No newline at end of file diff --git a/RenX.Ladder/RenX_LadderDatabase.cpp b/RenX.Ladder/RenX_LadderDatabase.cpp deleted file mode 100644 index e4aa35a..0000000 --- a/RenX.Ladder/RenX_LadderDatabase.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/** - * Copyright (C) 2015 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Written by Jessica James - */ - -#include "RenX_LadderDatabase.h" - -RenX_LadderDatabase::~RenX_LadderDatabase() -{ - while (RenX_LadderDatabase::head != nullptr) - { - RenX_LadderDatabase::end = RenX_LadderDatabase::head; - RenX_LadderDatabase::head = RenX_LadderDatabase::head->next; - delete RenX_LadderDatabase::end; - } -} - -void RenX_LadderDatabase::process_data(Jupiter::DataBuffer &buffer, FILE *file, fpos_t pos) -{ - RenX_LadderDatabase::Entry *entry = new RenX_LadderDatabase::Entry(); - - // read data from buffer to entry - entry->steam_id = buffer.pop(); - entry->total_score = buffer.pop(); - - entry->total_kills = buffer.pop(); - entry->total_deaths = buffer.pop(); - entry->total_headshot_kills = buffer.pop(); - entry->total_vehicle_kills = buffer.pop(); - entry->total_building_kills = buffer.pop(); - entry->total_defence_kills = buffer.pop(); - entry->total_captures = buffer.pop(); - entry->total_game_time = buffer.pop(); - entry->total_games = buffer.pop(); - entry->total_gdi_games = buffer.pop(); - entry->total_nod_games = buffer.pop(); - entry->total_wins = buffer.pop(); - entry->total_gdi_wins = buffer.pop(); - entry->total_nod_wins = buffer.pop(); - entry->total_beacon_placements = buffer.pop(); - entry->total_beacon_disarms = buffer.pop(); - entry->total_proxy_placements = buffer.pop(); - entry->total_proxy_disarms = buffer.pop(); - - entry->top_score = buffer.pop(); - entry->top_kills = buffer.pop(); - entry->most_deaths = buffer.pop(); - entry->top_headshot_kills = buffer.pop(); - entry->top_vehicle_kills = buffer.pop(); - entry->top_building_kills = buffer.pop(); - entry->top_defence_kills = buffer.pop(); - entry->top_captures = buffer.pop(); - entry->top_game_time = buffer.pop(); - entry->top_beacon_placements = buffer.pop(); - entry->top_beacon_disarms = buffer.pop(); - entry->top_proxy_placements = buffer.pop(); - entry->top_proxy_disarms = buffer.pop(); - - entry->most_recent_ip = buffer.pop(); - entry->last_game = buffer.pop(); - entry->most_recent_name = buffer.pop(); - - // push data to list - if (RenX_LadderDatabase::head == nullptr) - { - RenX_LadderDatabase::head = entry; - RenX_LadderDatabase::end = RenX_LadderDatabase::head; - } - else - { - RenX_LadderDatabase::end->next = entry; - entry->prev = end; - end = entry; - } - - ++RenX_LadderDatabase::entries; -} - -void RenX_LadderDatabase::process_header(FILE *file) -{ - int chr = fgetc(file); - if (chr != EOF) - RenX_LadderDatabase::read_version = chr; -} - -void RenX_LadderDatabase::create_header(FILE *file) -{ - fputc(RenX_LadderDatabase::write_version, file); -} - -RenX_LadderDatabase::Entry *RenX_LadderDatabase::getHead() const -{ - return RenX_LadderDatabase::head; -} - -RenX_LadderDatabase::Entry *RenX_LadderDatabase::getPlayerEntry(uint64_t steamid) const -{ - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next) - if (itr->steam_id == steamid) - return itr; - return nullptr; -} - -std::pair RenX_LadderDatabase::getPlayerEntryAndIndex(uint64_t steamid) const -{ - size_t index = 0; - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) - if (itr->steam_id == steamid) - return std::pair(itr, index); - return std::pair(nullptr, Jupiter::INVALID_INDEX); -} - -RenX_LadderDatabase::Entry *RenX_LadderDatabase::getPlayerEntryByName(const Jupiter::ReadableString &name) const -{ - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next) - if (itr->most_recent_name.equalsi(name)) - return itr; - return nullptr; -} - -std::pair RenX_LadderDatabase::getPlayerEntryAndIndexByName(const Jupiter::ReadableString &name) const -{ - size_t index = 0; - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) - if (itr->most_recent_name.equalsi(name)) - return std::pair(itr, index); - return std::pair(nullptr, Jupiter::INVALID_INDEX); -} - -RenX_LadderDatabase::Entry *RenX_LadderDatabase::getPlayerEntryByPartName(const Jupiter::ReadableString &name) const -{ - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next) - if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) - return itr; - return nullptr; -} - -std::pair RenX_LadderDatabase::getPlayerEntryAndIndexByPartName(const Jupiter::ReadableString &name) const -{ - size_t index = 0; - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) - if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) - return std::pair(itr, index); - return std::pair(nullptr, Jupiter::INVALID_INDEX); -} - -Jupiter::SLList RenX_LadderDatabase::getPlayerEntriesByPartName(const Jupiter::ReadableString &name, size_t max) const -{ - Jupiter::SLList list; - if (max == 0) - { - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next) - if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) - list.add(new RenX_LadderDatabase::Entry(*itr)); - } - else - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next) - if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) - { - list.add(new RenX_LadderDatabase::Entry(*itr)); - if (--max == 0) - return list; - } - return list; -} - -Jupiter::SLList> RenX_LadderDatabase::getPlayerEntriesAndIndexByPartName(const Jupiter::ReadableString &name, size_t max) const -{ - Jupiter::SLList> list; - size_t index = 0; - if (max == 0) - { - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) - if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) - list.add(new std::pair(*itr, index)); - } - else - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next, ++index) - if (itr->most_recent_name.findi(name) != Jupiter::INVALID_INDEX) - { - list.add(new std::pair(*itr, index)); - if (--max) - return list; - } - return list; -} - -RenX_LadderDatabase::Entry *RenX_LadderDatabase::getPlayerEntryByIndex(size_t index) const -{ - for (RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; itr != nullptr; itr = itr->next, --index) - if (index == 0) - return itr; - return nullptr; -} - -size_t RenX_LadderDatabase::getEntries() const -{ - return RenX_LadderDatabase::entries; -} - -void RenX_LadderDatabase::append(RenX_LadderDatabase::Entry *entry) -{ - ++RenX_LadderDatabase::entries; - if (RenX_LadderDatabase::head == nullptr) - { - RenX_LadderDatabase::head = entry; - RenX_LadderDatabase::end = RenX_LadderDatabase::head; - return; - } - end->next = entry; - entry->prev = end; - end = entry; -} - -void RenX_LadderDatabase::write(const Jupiter::CStringType &filename) -{ - return RenX_LadderDatabase::write(filename.c_str()); -} - -void RenX_LadderDatabase::write(const char *filename) -{ - if (RenX_LadderDatabase::entries != 0) - { - FILE *file = fopen(filename, "wb"); - if (file != nullptr) - { - Jupiter::DataBuffer buffer; - RenX_LadderDatabase::create_header(file); - RenX_LadderDatabase::Entry *entry = RenX_LadderDatabase::head; - while (entry != nullptr) - { - // push data from entry to buffer - buffer.push(entry->steam_id); - buffer.push(entry->total_score); - - buffer.push(entry->total_kills); - buffer.push(entry->total_deaths); - buffer.push(entry->total_headshot_kills); - buffer.push(entry->total_vehicle_kills); - buffer.push(entry->total_building_kills); - buffer.push(entry->total_defence_kills); - buffer.push(entry->total_captures); - buffer.push(entry->total_game_time); - buffer.push(entry->total_games); - buffer.push(entry->total_gdi_games); - buffer.push(entry->total_nod_games); - buffer.push(entry->total_wins); - buffer.push(entry->total_gdi_wins); - buffer.push(entry->total_nod_wins); - buffer.push(entry->total_beacon_placements); - buffer.push(entry->total_beacon_disarms); - buffer.push(entry->total_proxy_placements); - buffer.push(entry->total_proxy_disarms); - - buffer.push(entry->top_score); - buffer.push(entry->top_kills); - buffer.push(entry->most_deaths); - buffer.push(entry->top_headshot_kills); - buffer.push(entry->top_vehicle_kills); - buffer.push(entry->top_building_kills); - buffer.push(entry->top_defence_kills); - buffer.push(entry->top_captures); - buffer.push(entry->top_game_time); - buffer.push(entry->top_beacon_placements); - buffer.push(entry->top_beacon_disarms); - buffer.push(entry->top_proxy_placements); - buffer.push(entry->top_proxy_disarms); - - buffer.push(entry->most_recent_ip); - buffer.push(entry->last_game); - buffer.push(entry->most_recent_name); - - // push buffer to file - buffer.push_to(file); - - // iterate - entry = entry->next; - } - fclose(file); - } - } -} - -void RenX_LadderDatabase::sort_entries() -{ - if (RenX_LadderDatabase::entries <= 1) - return; - - RenX_LadderDatabase::Entry *itr = RenX_LadderDatabase::head; - RenX_LadderDatabase::Entry *itr2, *ptr; - - // iterate forward (search for out-of-order content) - while (itr->next != nullptr) - { - // out-of-order content found - if (itr->next->total_score > itr->total_score) - { - // pull content out - ptr = itr->next; - itr->next = ptr->next; - if (itr->next != nullptr) - itr->next->prev = itr; - - // iterate backwards from our iterator, and insert - itr2 = itr; - while (true) - { - if (itr2->prev == nullptr) - { - // push ptr to head - ptr->next = itr2; - ptr->prev = nullptr; - itr2->prev = ptr; - RenX_LadderDatabase::head = ptr; - break; - } - itr2 = itr2->prev; - if (itr2->total_score > ptr->total_score) - { - // insert ptr after itr2 - ptr->next = itr2->next; - ptr->next->prev = ptr; - ptr->prev = itr2; - itr2->next = ptr; - break; - } - } - } - else // continue iterating - itr = itr->next; - } - - RenX_LadderDatabase::end = itr; -} \ No newline at end of file diff --git a/RenX.Ladder/RenX_LadderDatabase.h b/RenX.Ladder/RenX_LadderDatabase.h deleted file mode 100644 index e11c8a8..0000000 --- a/RenX.Ladder/RenX_LadderDatabase.h +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (C) 2015 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Written by Jessica James - */ - -#if !defined _RENX_LADDERDATABASE_H_HEADER -#define _RENX_LADDERDATABASE_H_HEADER - -#include "Jupiter/Database.h" -#include "Jupiter/String.h" -#include "Jupiter/SLList.h" - -class RenX_LadderDatabase : public Jupiter::Database -{ -public: // Jupiter::Database - /** - * @brief Processes a chunk of data in a database. - * - * @param buffer Buffer to process - * @param file File being processed - * @param pos position that the buffer starts at in the file - */ - void process_data(Jupiter::DataBuffer &buffer, FILE *file, fpos_t pos) override; - - /** - * @brief Processes the header for a database. - * - * @param file File being processed - */ - void process_header(FILE *file) override; - - /** - * @brief Generates a header for a database. - * - * @param file File being created - */ - void create_header(FILE *file) override; - -public: // RenX_LadderDatabase - struct Entry - { - uint64_t steam_id, total_score; - uint32_t total_kills, total_deaths, total_headshot_kills, total_vehicle_kills, total_building_kills, total_defence_kills, total_captures, total_game_time, total_games, total_gdi_games, total_nod_games, total_wins, total_gdi_wins, total_nod_wins, total_beacon_placements, total_beacon_disarms, total_proxy_placements, total_proxy_disarms, // totals (15) - top_score, top_kills, most_deaths, top_headshot_kills, top_vehicle_kills, top_building_kills, top_defence_kills, top_captures, top_game_time, top_beacon_placements, top_beacon_disarms, top_proxy_placements, top_proxy_disarms, // tops (12) - most_recent_ip; // other (1) - time_t last_game; - Jupiter::StringS most_recent_name; - Entry *next = nullptr; - Entry *prev = nullptr; - }; - - /** - * @brief Fetches the head of the entry list. - * - * @return Head of the ladder entry list. - */ - Entry *getHead() const; - - /** - * @brief Fetches a ladder entry by Steam ID. - * - * @param steamid Steam ID to search ladder for - * @return Ladder entry with a matching steamid if one exists, nullptr otherwise. - */ - Entry *getPlayerEntry(uint64_t steamid) const; - std::pair getPlayerEntryAndIndex(uint64_t steamid) const; - - /** - * @brief Searches for a ladder entry by name - * - * @param name Name to search ladder for - * @return Ladder entry with a matching name if one exists, nullptr otherwise. - */ - Entry *getPlayerEntryByName(const Jupiter::ReadableString &name) const; - std::pair getPlayerEntryAndIndexByName(const Jupiter::ReadableString &name) const; - - /** - * @brief Searches for a ladder entry by part name - * - * @param name Part of name to search ladder for - * @return Ladder entry with a matching name if one exists, nullptr otherwise. - */ - Entry *getPlayerEntryByPartName(const Jupiter::ReadableString &name) const; - std::pair getPlayerEntryAndIndexByPartName(const Jupiter::ReadableString &name) const; - - /** - * @brief Fetches all entries matching a part name. - * - * @param name Part of name to search for - * @param max Maximum number of entries to return - * @return List containing entries with matching names. - */ - Jupiter::SLList getPlayerEntriesByPartName(const Jupiter::ReadableString &name, size_t max) const; - Jupiter::SLList> getPlayerEntriesAndIndexByPartName(const Jupiter::ReadableString &name, size_t max) const; - - /** - * @brief Fetches a ladder entry at a specified index - * - * @param index Index of the element to fetch - * @return Ladder entry with a matching name if one exists, nullptr otherwise. - */ - Entry *getPlayerEntryByIndex(size_t index) const; - - /** - * @brief Fetches the total number of ladder entries in the list. - * - * @return Total number of entries. - */ - size_t getEntries() const; - - /** - * @brief Places a ladder entry at the end of the list, regardless of order - * Note: This does not copy data from the pointer -- the pointer is added to the list. - * - * @param entry Ladder entry to add - */ - void append(Entry *entry); - - /** - * @brief Writes the current ladder data to the disk. - */ - void write(const Jupiter::CStringType &filename); - void write(const char *filename); - - /** - * @brief Sorts the ladder data in memory. - */ - void sort_entries(); - - /** - * @brief Deconstructor for the RenX_LadderDatabase class - */ - ~RenX_LadderDatabase(); -private: - - /** Database version */ - const uint8_t write_version = 0; - uint8_t read_version = write_version; - - size_t entries = 0; - Entry *head = nullptr; - Entry *end; -}; - -#endif //_RENX_LADDERDATABASE_H_HEADER \ No newline at end of file diff --git a/RenX.Listen/RenX_Listen.cpp b/RenX.Listen/RenX_Listen.cpp index 758d3d6..de9fdf5 100644 --- a/RenX.Listen/RenX_Listen.cpp +++ b/RenX.Listen/RenX_Listen.cpp @@ -25,7 +25,7 @@ RenX_ListenPlugin::~RenX_ListenPlugin() { - RenX_ListenPlugin::socket.closeSocket(); + RenX_ListenPlugin::socket.close(); } bool RenX_ListenPlugin::init() @@ -59,7 +59,7 @@ int RenX_ListenPlugin::OnRehash() if (port != RenX_ListenPlugin::socket.getRemotePort() || address.equals(RenX_ListenPlugin::socket.getRemoteHostname()) == false) { puts("Notice: The Renegade-X listening socket has been changed!"); - RenX_ListenPlugin::socket.closeSocket(); + RenX_ListenPlugin::socket.close(); return RenX_ListenPlugin::socket.bind(Jupiter::CStringS(address).c_str(), port, true) == false || RenX_ListenPlugin::socket.setBlocking(false) == false; } return 0;