JustinAJ
9 years ago
6 changed files with 973 additions and 0 deletions
@ -0,0 +1,87 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup Label="ProjectConfigurations"> |
|||
<ProjectConfiguration Include="Debug|Win32"> |
|||
<Configuration>Debug</Configuration> |
|||
<Platform>Win32</Platform> |
|||
</ProjectConfiguration> |
|||
<ProjectConfiguration Include="Release|Win32"> |
|||
<Configuration>Release</Configuration> |
|||
<Platform>Win32</Platform> |
|||
</ProjectConfiguration> |
|||
</ItemGroup> |
|||
<PropertyGroup Label="Globals"> |
|||
<ProjectGuid>{B2846BD6-2332-4DA6-A13B-113318F76D5E}</ProjectGuid> |
|||
<RootNamespace>RenX.Ladder</RootNamespace> |
|||
</PropertyGroup> |
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
|||
<ConfigurationType>Application</ConfigurationType> |
|||
<UseDebugLibraries>true</UseDebugLibraries> |
|||
<PlatformToolset>v140</PlatformToolset> |
|||
<CharacterSet>MultiByte</CharacterSet> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
|||
<ConfigurationType>DynamicLibrary</ConfigurationType> |
|||
<UseDebugLibraries>false</UseDebugLibraries> |
|||
<PlatformToolset>v140</PlatformToolset> |
|||
<WholeProgramOptimization>true</WholeProgramOptimization> |
|||
<CharacterSet>Unicode</CharacterSet> |
|||
</PropertyGroup> |
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
|||
<ImportGroup Label="ExtensionSettings"> |
|||
</ImportGroup> |
|||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
|||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
|||
</ImportGroup> |
|||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
|||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
|||
</ImportGroup> |
|||
<PropertyGroup Label="UserMacros" /> |
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
|||
<OutDir>$(SolutionDir)$(Configuration)\Plugins\</OutDir> |
|||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> |
|||
</PropertyGroup> |
|||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
|||
<ClCompile> |
|||
<WarningLevel>Level3</WarningLevel> |
|||
<Optimization>Disabled</Optimization> |
|||
<SDLCheck>true</SDLCheck> |
|||
</ClCompile> |
|||
<Link> |
|||
<GenerateDebugInformation>true</GenerateDebugInformation> |
|||
</Link> |
|||
</ItemDefinitionGroup> |
|||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
|||
<ClCompile> |
|||
<WarningLevel>Level3</WarningLevel> |
|||
<Optimization>MaxSpeed</Optimization> |
|||
<FunctionLevelLinking>true</FunctionLevelLinking> |
|||
<IntrinsicFunctions>true</IntrinsicFunctions> |
|||
<SDLCheck>true</SDLCheck> |
|||
<AdditionalIncludeDirectories>../Bot;../Jupiter;../RenX.Core</AdditionalIncludeDirectories> |
|||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
|||
</ClCompile> |
|||
<Link> |
|||
<GenerateDebugInformation>true</GenerateDebugInformation> |
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
|||
<OptimizeReferences>true</OptimizeReferences> |
|||
</Link> |
|||
</ItemDefinitionGroup> |
|||
<ItemGroup> |
|||
<ClInclude Include="RenX_LadderDatabase.h" /> |
|||
<ClInclude Include="RenX_Ladder.h" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ClCompile Include="RenX_Ladder.cpp" /> |
|||
<ClCompile Include="RenX_LadderDatabase.cpp" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Library Include="..\Jupiter\Release\Jupiter.lib" /> |
|||
<Library Include="..\Release\Bot.lib" /> |
|||
<Library Include="..\Release\Plugins\RenX.Core.lib" /> |
|||
</ItemGroup> |
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
|||
<ImportGroup Label="ExtensionTargets"> |
|||
</ImportGroup> |
|||
</Project> |
@ -0,0 +1,44 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<Filter Include="Source Files"> |
|||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> |
|||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> |
|||
</Filter> |
|||
<Filter Include="Header Files"> |
|||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> |
|||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> |
|||
</Filter> |
|||
<Filter Include="Resource Files"> |
|||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> |
|||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> |
|||
</Filter> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Library Include="..\Release\Plugins\RenX.Core.lib"> |
|||
<Filter>Resource Files</Filter> |
|||
</Library> |
|||
<Library Include="..\Release\Bot.lib"> |
|||
<Filter>Resource Files</Filter> |
|||
</Library> |
|||
<Library Include="..\Jupiter\Release\Jupiter.lib"> |
|||
<Filter>Resource Files</Filter> |
|||
</Library> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ClCompile Include="RenX_Ladder.cpp"> |
|||
<Filter>Source Files</Filter> |
|||
</ClCompile> |
|||
<ClCompile Include="RenX_LadderDatabase.cpp"> |
|||
<Filter>Source Files</Filter> |
|||
</ClCompile> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ClInclude Include="RenX_Ladder.h"> |
|||
<Filter>Header Files</Filter> |
|||
</ClInclude> |
|||
<ClInclude Include="RenX_LadderDatabase.h"> |
|||
<Filter>Header Files</Filter> |
|||
</ClInclude> |
|||
</ItemGroup> |
|||
</Project> |
@ -0,0 +1,287 @@ |
|||
/**
|
|||
* Copyright (C) 2015 Justin James. |
|||
* |
|||
* This license must be preserved. |
|||
* Any applications, libraries, or code which make any use of any |
|||
* component of this program must not be commercial, unless explicit |
|||
* permission is granted from the original author. The use of this |
|||
* program for non-profit purposes is permitted. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|||
* |
|||
* In the event that this license restricts you from making desired use of this program, contact the original author. |
|||
* Written by Justin James <justin.aj@hotmail.com> |
|||
*/ |
|||
|
|||
#include "Console_Command.h" |
|||
#include "Jupiter/INIFile.h" |
|||
#include "RenX_Ladder.h" |
|||
#include "RenX_Server.h" |
|||
#include "RenX_PlayerInfo.h" |
|||
|
|||
using namespace Jupiter::literals; |
|||
|
|||
RenX_LadderPlugin::RenX_LadderPlugin() |
|||
{ |
|||
RenX_LadderPlugin::only_pure = Jupiter::IRC::Client::Config->getBool(this->getName(), "OnlyPure"_jrs, false); |
|||
RenX_LadderPlugin::output_times = Jupiter::IRC::Client::Config->getBool(this->getName(), "OutputTimes"_jrs, true); |
|||
int mlcpno = Jupiter::IRC::Client::Config->getInt(this->getName(), "MaxLadderCommandPartNameOutput"_jrs, 5); |
|||
if (mlcpno < 0) |
|||
RenX_LadderPlugin::max_ladder_command_part_name_output = 0; |
|||
else |
|||
RenX_LadderPlugin::max_ladder_command_part_name_output = mlcpno; |
|||
RenX_LadderPlugin::db_filename = Jupiter::IRC::Client::Config->get(this->getName(), "LadderDatabase"_jrs, "Ladder.db"_jrs); |
|||
|
|||
// load database
|
|||
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<RenX::PlayerInfo>::Node *node = server->players.getNode(0); node != nullptr; node = node->next) |
|||
{ |
|||
player = node->data; |
|||
if (player->steamid != 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<uint64_t>(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<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(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<uint32_t>(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<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(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<double>(sort_duration.count()) * (static_cast<double>(std::chrono::steady_clock::duration::period::num / static_cast<double>(std::chrono::steady_clock::duration::period::den) * static_cast<double>(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num))), |
|||
static_cast<double>(write_duration.count()) * (static_cast<double>(std::chrono::steady_clock::duration::period::num) / static_cast<double>(std::chrono::steady_clock::duration::period::den) * static_cast<double>(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) |
|||
{ |
|||
if (server->hasSeenStart() && server->players.size() != 0) // the first game doesn't count!
|
|||
{ |
|||
char chr = static_cast<char>(team); |
|||
server->varData.set(this->name, "t"_jrs, Jupiter::ReferenceString(chr)); |
|||
server->varData.set(this->name, "w"_jrs, "1"_jrs); |
|||
server->updateClientList(); |
|||
} |
|||
} |
|||
|
|||
void RenX_LadderPlugin::RenX_OnCommand(RenX::Server *server, const Jupiter::ReadableString &) |
|||
{ |
|||
if (server->getCurrentRCONCommand().equalsi("clientvarlist"_jrs)) |
|||
{ |
|||
if (server->varData.get(this->name, "w"_jrs, "0"_jrs).equals("1")) |
|||
{ |
|||
server->varData.set(this->name, "w"_jrs, "0"_jrs); |
|||
RenX::TeamType team = static_cast<RenX::TeamType>(server->varData.get(this->name, "t"_jrs, "\0"_jrs).get(0)); |
|||
RenX_LadderPlugin::updateLadder(server, team); |
|||
} |
|||
} |
|||
} |
|||
|
|||
size_t RenX_LadderPlugin::getMaxLadderCommandPartNameOutput() const |
|||
{ |
|||
return RenX_LadderPlugin::max_ladder_command_part_name_output; |
|||
} |
|||
|
|||
// Plugin instantiation and entry point.
|
|||
RenX_LadderPlugin pluginInstance; |
|||
|
|||
/** Ladder Commands */ |
|||
#include <cinttypes> |
|||
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<double>(entry->total_kills) / (entry->total_deaths == 0 ? 1 : static_cast<double>(entry->total_deaths)), static_cast<double>(entry->total_score) / (entry->total_game_time == 0 ? 1.0 : static_cast<double>(entry->total_game_time)) * 60.0); |
|||
} |
|||
|
|||
// Ladder Command
|
|||
|
|||
LadderGenericCommand::LadderGenericCommand() |
|||
{ |
|||
this->addTrigger("ladder"_jrs); |
|||
this->addTrigger("rank"_jrs); |
|||
} |
|||
|
|||
GenericCommand::ResponseLine *LadderGenericCommand::trigger(const Jupiter::ReadableString ¶meters) |
|||
{ |
|||
if (parameters.isEmpty()) |
|||
return new GenericCommand::ResponseLine("Error: Too few parameters. Syntax: ladder <name | rank>"_jrs, GenericCommand::DisplayType::PrivateError); |
|||
|
|||
RenX_LadderDatabase::Entry *entry; |
|||
size_t rank; |
|||
if (parameters.span("0123456789"_jrs) == parameters.size()) |
|||
{ |
|||
rank = parameters.asUnsignedInt(10); |
|||
if (rank == 0) |
|||
return new GenericCommand::ResponseLine("Error: Invalid parameters"_jrs, GenericCommand::DisplayType::PrivateError); |
|||
|
|||
entry = pluginInstance.database.getPlayerEntryByIndex(rank - 1); |
|||
if (entry == nullptr) |
|||
return new GenericCommand::ResponseLine("Error: Player not found"_jrs, GenericCommand::DisplayType::PrivateError); |
|||
|
|||
return new GenericCommand::ResponseLine(FormatLadderResponse(entry, rank), GenericCommand::DisplayType::PublicSuccess); |
|||
} |
|||
|
|||
Jupiter::SLList<std::pair<RenX_LadderDatabase::Entry, size_t>> 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<RenX_LadderDatabase::Entry, size_t> *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; |
|||
while (list.size() != 0) |
|||
{ |
|||
pair = list.remove(0); |
|||
response_end->next = new GenericCommand::ResponseLine(FormatLadderResponse(std::addressof(pair->first), pair->second + 1), GenericCommand::DisplayType::PrivateSuccess); |
|||
response_end = response_end->next; |
|||
delete pair; |
|||
} |
|||
return response_head; |
|||
} |
|||
|
|||
const Jupiter::ReadableString &LadderGenericCommand::getHelp(const Jupiter::ReadableString &) |
|||
{ |
|||
static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Fetches ladder information about a player. Syntax: ladder <name | rank>"); |
|||
return defaultHelp; |
|||
} |
|||
|
|||
GENERIC_COMMAND_INIT(LadderGenericCommand) |
|||
GENERIC_COMMAND_AS_CONSOLE_COMMAND(LadderGenericCommand) |
|||
GENERIC_COMMAND_AS_IRC_COMMAND_NO_CREATE(LadderGenericCommand) |
|||
|
|||
// Ladder Game Command
|
|||
|
|||
void LadderGameCommand::create() |
|||
{ |
|||
this->addTrigger("ladder"_jrs); |
|||
this->addTrigger("rank"_jrs); |
|||
} |
|||
|
|||
void LadderGameCommand::trigger(RenX::Server *source, RenX::PlayerInfo *player, const Jupiter::ReadableString ¶meters) |
|||
{ |
|||
if (parameters.isEmpty()) |
|||
{ |
|||
if (player->steamid != 0) |
|||
{ |
|||
std::pair<RenX_LadderDatabase::Entry *, size_t> pair = pluginInstance.database.getPlayerEntryAndIndex(player->steamid); |
|||
if (pair.first != nullptr) |
|||
source->sendMessage(FormatLadderResponse(pair.first, pair.second + 1)); |
|||
else |
|||
source->sendMessage(player, "Error: You have no ladder data. Get started by sticking around until the end of the match!"_jrs); |
|||
} |
|||
else |
|||
source->sendMessage(player, "Error: You have no ladder data, because you're not using Steam."_jrs); |
|||
} |
|||
else |
|||
{ |
|||
GenericCommand::ResponseLine *response = LadderGenericCommand_instance.trigger(parameters); |
|||
GenericCommand::ResponseLine *ptr; |
|||
while (response != nullptr) |
|||
{ |
|||
source->sendMessage(player, response->response); |
|||
ptr = response; |
|||
response = response->next; |
|||
delete ptr; |
|||
} |
|||
} |
|||
} |
|||
|
|||
const Jupiter::ReadableString &LadderGameCommand::getHelp(const Jupiter::ReadableString &) |
|||
{ |
|||
static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Displays ladder information about yourself, or another player. Syntax: ladder [name / rank]"); |
|||
return defaultHelp; |
|||
} |
|||
|
|||
GAME_COMMAND_INIT(LadderGameCommand) |
|||
|
|||
extern "C" __declspec(dllexport) Jupiter::Plugin *getPlugin() |
|||
{ |
|||
return &pluginInstance; |
|||
} |
@ -0,0 +1,52 @@ |
|||
/**
|
|||
* Copyright (C) 2015 Justin James. |
|||
* |
|||
* This license must be preserved. |
|||
* Any applications, libraries, or code which make any use of any |
|||
* component of this program must not be commercial, unless explicit |
|||
* permission is granted from the original author. The use of this |
|||
* program for non-profit purposes is permitted. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|||
* |
|||
* In the event that this license restricts you from making desired use of this program, contact the original author. |
|||
* Written by Justin James <justin.aj@hotmail.com> |
|||
*/ |
|||
|
|||
#if !defined _RENX_LADDER_H_HEADER |
|||
#define _RENX_LADDER_H_HEADER |
|||
|
|||
#include "Jupiter/Plugin.h" |
|||
#include "Jupiter/Reference_String.h" |
|||
#include "IRC_Command.h" |
|||
#include "RenX_Plugin.h" |
|||
#include "RenX_LadderDatabase.h" |
|||
#include "RenX_GameCommand.h" |
|||
|
|||
class RenX_LadderPlugin : public RenX::Plugin |
|||
{ |
|||
public: |
|||
const Jupiter::ReadableString &getName() override { return name; } |
|||
void RenX_OnGameOver(RenX::Server *server, RenX::WinType winType, const RenX::TeamType &team, int gScore, int nScore) override; |
|||
void RenX_OnCommand(RenX::Server *server, const Jupiter::ReadableString &) override; |
|||
|
|||
size_t getMaxLadderCommandPartNameOutput() const; |
|||
RenX_LadderPlugin(); |
|||
|
|||
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; |
|||
Jupiter::CStringS db_filename; |
|||
STRING_LITERAL_AS_NAMED_REFERENCE(name, "RenX.Ladder"); |
|||
}; |
|||
|
|||
GENERIC_GENERIC_COMMAND(LadderGenericCommand) |
|||
GENERIC_GAME_COMMAND(LadderGameCommand) |
|||
|
|||
#endif // _RENX_LADDER_H_HEADER
|
@ -0,0 +1,346 @@ |
|||
/**
|
|||
* Copyright (C) 2015 Justin James. |
|||
* |
|||
* This license must be preserved. |
|||
* Any applications, libraries, or code which make any use of any |
|||
* component of this program must not be commercial, unless explicit |
|||
* permission is granted from the original author. The use of this |
|||
* program for non-profit purposes is permitted. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|||
* |
|||
* In the event that this license restricts you from making desired use of this program, contact the original author. |
|||
* Written by Justin James <justin.aj@hotmail.com> |
|||
*/ |
|||
|
|||
#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<uint64_t>(); |
|||
entry->total_score = buffer.pop<uint64_t>(); |
|||
|
|||
entry->total_kills = buffer.pop<uint32_t>(); |
|||
entry->total_deaths = buffer.pop<uint32_t>(); |
|||
entry->total_headshot_kills = buffer.pop<uint32_t>(); |
|||
entry->total_vehicle_kills = buffer.pop<uint32_t>(); |
|||
entry->total_building_kills = buffer.pop<uint32_t>(); |
|||
entry->total_defence_kills = buffer.pop<uint32_t>(); |
|||
entry->total_captures = buffer.pop<uint32_t>(); |
|||
entry->total_game_time = buffer.pop<uint32_t>(); |
|||
entry->total_games = buffer.pop<uint32_t>(); |
|||
entry->total_gdi_games = buffer.pop<uint32_t>(); |
|||
entry->total_nod_games = buffer.pop<uint32_t>(); |
|||
entry->total_wins = buffer.pop<uint32_t>(); |
|||
entry->total_gdi_wins = buffer.pop<uint32_t>(); |
|||
entry->total_nod_wins = buffer.pop<uint32_t>(); |
|||
entry->total_beacon_placements = buffer.pop<uint32_t>(); |
|||
entry->total_beacon_disarms = buffer.pop<uint32_t>(); |
|||
entry->total_proxy_placements = buffer.pop<uint32_t>(); |
|||
entry->total_proxy_disarms = buffer.pop<uint32_t>(); |
|||
|
|||
entry->top_score = buffer.pop<uint32_t>(); |
|||
entry->top_kills = buffer.pop<uint32_t>(); |
|||
entry->most_deaths = buffer.pop<uint32_t>(); |
|||
entry->top_headshot_kills = buffer.pop<uint32_t>(); |
|||
entry->top_vehicle_kills = buffer.pop<uint32_t>(); |
|||
entry->top_building_kills = buffer.pop<uint32_t>(); |
|||
entry->top_defence_kills = buffer.pop<uint32_t>(); |
|||
entry->top_captures = buffer.pop<uint32_t>(); |
|||
entry->top_game_time = buffer.pop<uint32_t>(); |
|||
entry->top_beacon_placements = buffer.pop<uint32_t>(); |
|||
entry->top_beacon_disarms = buffer.pop<uint32_t>(); |
|||
entry->top_proxy_placements = buffer.pop<uint32_t>(); |
|||
entry->top_proxy_disarms = buffer.pop<uint32_t>(); |
|||
|
|||
entry->most_recent_ip = buffer.pop<uint32_t>(); |
|||
entry->last_game = buffer.pop<time_t>(); |
|||
entry->most_recent_name = buffer.pop<Jupiter::String_Strict, char>(); |
|||
|
|||
// 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::Entry *, size_t> 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<RenX_LadderDatabase::Entry *, size_t>(itr, index); |
|||
return std::pair<RenX_LadderDatabase::Entry *, size_t>(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::Entry *, size_t> 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<RenX_LadderDatabase::Entry *, size_t>(itr, index); |
|||
return std::pair<RenX_LadderDatabase::Entry *, size_t>(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::Entry *, size_t> 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<RenX_LadderDatabase::Entry *, size_t>(itr, index); |
|||
return std::pair<RenX_LadderDatabase::Entry *, size_t>(nullptr, Jupiter::INVALID_INDEX); |
|||
} |
|||
|
|||
Jupiter::SLList<RenX_LadderDatabase::Entry> RenX_LadderDatabase::getPlayerEntriesByPartName(const Jupiter::ReadableString &name, size_t max) const |
|||
{ |
|||
Jupiter::SLList<RenX_LadderDatabase::Entry> 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<std::pair<RenX_LadderDatabase::Entry, size_t>> RenX_LadderDatabase::getPlayerEntriesAndIndexByPartName(const Jupiter::ReadableString &name, size_t max) const |
|||
{ |
|||
Jupiter::SLList<std::pair<RenX_LadderDatabase::Entry, size_t>> 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<RenX_LadderDatabase::Entry, size_t>(*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<RenX_LadderDatabase::Entry, size_t>(*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; |
|||
} |
@ -0,0 +1,157 @@ |
|||
/**
|
|||
* Copyright (C) 2015 Justin James. |
|||
* |
|||
* This license must be preserved. |
|||
* Any applications, libraries, or code which make any use of any |
|||
* component of this program must not be commercial, unless explicit |
|||
* permission is granted from the original author. The use of this |
|||
* program for non-profit purposes is permitted. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|||
* |
|||
* In the event that this license restricts you from making desired use of this program, contact the original author. |
|||
* Written by Justin James <justin.aj@hotmail.com> |
|||
*/ |
|||
|
|||
#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<Entry *, size_t> 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<Entry *, size_t> 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<Entry *, size_t> 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<Entry> getPlayerEntriesByPartName(const Jupiter::ReadableString &name, size_t max) const; |
|||
Jupiter::SLList<std::pair<Entry, size_t>> 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
|
Loading…
Reference in new issue