Skip to content

Commit

Permalink
Initial ranking stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
alicealys committed Jun 30, 2024
1 parent 524261f commit 545d8de
Show file tree
Hide file tree
Showing 19 changed files with 570 additions and 41 deletions.
261 changes: 261 additions & 0 deletions src/server/database/models/event_rankings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
#include <std_include.hpp>

#include "event_rankings.hpp"
#include "player_records.hpp"
#include "players.hpp"

#include <utils/cryptography.hpp>
#include <utils/string.hpp>
#include <utils/nt.hpp>

#define TABLE_DEF R"(
create table if not exists `event_rankings`
(
id bigint unsigned not null auto_increment,
player_id bigint unsigned not null,
event_id int unsigned not null,
player_rank bigint unsigned not null default 0,
value int unsigned not null default 0,
primary key (`id`),
foreign key (`player_id`) references players(`id`),
unique key `unique_player_event_rankings_type` (`player_id`, `event_id`)
))"

namespace database::event_rankings
{
namespace
{
std::unordered_map<std::string, event_ranking_lookup_type> lookup_type_map =
{
{"BEST", lookup_best},
{"AROUND", lookup_around},
};

std::unordered_map<std::string, event_class> event_class_map =
{
{"SNEAK", class_fob},
{"SNEAK_EVENT", class_fob_event},
{"LEAGUE", class_league},
{"LEAGUE_EVENT", class_league_event},
};
}

std::optional<event_type> get_event_type_from_id(const std::uint32_t id, const std::string& type)
{
const auto upper = utils::string::to_upper(type);
const auto iter = event_class_map.find(upper);
if (iter == event_class_map.end())
{
return {};
}

if ((iter->second == class_fob || iter->second == class_fob_event) && id <= fob_event_end)
{
return static_cast<event_type>(id);
}
else if ((iter->second == class_league || iter->second == class_league_event) && id <= (league_event_end - fob_event_end))
{
return static_cast<event_type>(id + league_event_start);
}

return {};
}

std::optional<event_ranking_lookup_type> get_lookup_type_from_name(const std::string& name)
{
const auto upper = utils::string::to_upper(name);
const auto iter = lookup_type_map.find(upper);
if (iter == lookup_type_map.end())
{
return {};
}

return {iter->second};
}

GET_FIELD_C(event_ranking, std::uint64_t, id);
GET_FIELD_C(event_ranking, std::uint64_t, player_id);
GET_FIELD_C(event_ranking, std::uint32_t, event_id);
GET_FIELD_C(event_ranking, std::uint64_t, rank);
GET_FIELD_C(event_ranking, std::uint32_t, value);
GET_FIELD_C(event_ranking, std::uint32_t, fob_grade);
GET_FIELD_C(event_ranking, std::uint32_t, league_grade);
GET_FIELD_C(event_ranking, std::uint64_t, account_id);

void create_entries(const std::uint64_t player_id)
{
database::access([&](database_t& db)
{
for (auto i = 0; i < event_count; i++)
{
db->operator()(
sqlpp::insert_into(event_ranking::table)
.set(event_ranking::table.player_id = player_id,
event_ranking::table.event_id = i)
);
}
});
}

bool set_event_value(const std::uint64_t player_id, const event_type event_id, const std::uint32_t value)
{
return database::access<bool>([&](database_t& db)
{
const auto result = db->operator()(
sqlpp::update(event_ranking::table)
.set(event_ranking::table.value = value)
.where(event_ranking::table.player_id == player_id && event_ranking::table.event_id == static_cast<std::uint32_t>(event_id))
);

return result != 0;
});
}

bool increment_event_value(const std::uint64_t player_id, const event_type event_id, const std::uint32_t count)
{
return database::access<bool>([&](database_t& db)
{
const auto result = db->operator()(
sqlpp::update(event_ranking::table)
.set(event_ranking::table.value = event_ranking::table.value + count)
.where(event_ranking::table.player_id == player_id && event_ranking::table.event_id == static_cast<std::uint32_t>(event_id))
);

return result != 0;
});
}

bool set_value_if_bigger(const std::uint64_t player_id, const event_type event_id, const std::uint32_t value)
{
return database::access<bool>([&](database_t& db)
{
const auto result = db->operator()(
sqlpp::update(event_ranking::table)
.set(event_ranking::table.value = value)
.where(event_ranking::table.player_id == player_id &&
event_ranking::table.event_id == static_cast<std::uint32_t>(event_id) && event_ranking::table.value < value)
);

return result != 0;
});
}

bool reset_periodic_values()
{
return database::access<bool>([&](database_t& db)
{
const auto result = db->operator()(
sqlpp::update(event_ranking::table)
.set(event_ranking::table.value = 0, event_ranking::table.player_rank = 0)
.where(event_ranking::table.event_id != static_cast<std::uint32_t>(ep_earned))
);

return result != 0;
});
}

std::optional<std::uint64_t> get_player_rank(const std::uint64_t player_id, const event_type event_id)
{
return database::access<std::optional<std::uint64_t>>([&](database_t& db)
-> std::optional<std::uint64_t>
{
auto results = db->operator()(
sqlpp::select(event_ranking::table.player_rank)
.from(event_ranking::table)
.where(event_ranking::table.event_id == static_cast<std::uint32_t>(event_id) &&
event_ranking::table.player_id == player_id)
);

if (results.empty())
{
return {};
}

return {results.front().player_rank};
});
}

std::vector<event_ranking> get_entries(const event_type event_id, const std::uint64_t offset, const std::uint32_t num)
{
return database::access<std::vector<event_ranking>>([&](database_t& db)
-> std::vector<event_ranking>
{
std::vector<event_ranking> list;

auto joined_tables = event_ranking::table
.join(player_records::player_record::table)
.on(event_ranking::table.player_id == player_records::player_record::table.player_id)
.join(players::player::table)
.on(event_ranking::table.player_id == player_records::player_record::table.player_id && event_ranking::table.player_id == players::player::table.id);

auto results = db->operator()(
sqlpp::select(sqlpp::all_of(event_ranking::table), player_records::player_record::table.fob_grade, player_records::player_record::table.league_grade,
players::player::table.account_id)
.from(joined_tables)
.where(event_ranking::table.player_rank != 0 && event_ranking::table.event_id == static_cast<std::uint32_t>(event_id))
.order_by(event_ranking::table.player_rank.asc())
.limit(num)
.offset(offset)
);

for (auto& row : results)
{
event_ranking entry{row};
entry.set_fob_grade(static_cast<std::uint32_t>(row.fob_grade));
entry.set_league_grade(static_cast<std::uint32_t>(row.league_grade));
entry.set_account_id(row.account_id);
list.emplace_back(entry);
}

return list;
});
}

std::chrono::system_clock::time_point last_update{};

void update_entries(database_t& db)
{
const auto now = std::chrono::system_clock::now();
if (now - last_update < 10min)
{
return;
}

last_update = now;

db->execute(R"(
with ranked_players as (
select player_id, value,
(select count(distinct value) + 1
from event_rankings pr2
where pr2.value > pr1.value) as new_rank
from event_rankings pr1
)
update event_rankings record
join ranked_players ranked_player on record.player_id = ranked_player.player_id
set record.player_rank = ranked_player.new_rank where record.value > 0;
)");
}

std::chrono::seconds get_last_update()
{
auto a = last_update.time_since_epoch();
return std::chrono::duration_cast<std::chrono::seconds>(last_update.time_since_epoch());
}

class table final : public table_interface
{
public:
void create(database_t& database) override
{
database->execute(TABLE_DEF);
}

void run_tasks(database_t& database)
{
update_entries(database);
}
};
}

REGISTER_TABLE(database::event_rankings::table, -1)
134 changes: 134 additions & 0 deletions src/server/database/models/event_rankings.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#pragma once

#include "../database.hpp"

#include "player_data.hpp"

#include "utils/tpp.hpp"

namespace database::event_rankings
{
enum event_class
{
class_fob,
class_fob_event,
class_league,
class_league_event
};

enum event_type
{
fob_event_start = 0,
ep_earned = 0,
most_ep_in_mission = 1,
cores_reached_defender = 2,
cores_reached_no_defender = 3,
damage_defender = 4,
materials_stolen = 5,
total_stealth = 6,
unknown = 7,
defense_deployments = 8,
defense_deployments_support = 9,
defense_deployments_support_received = 10,
defender_neutralized_intruder = 11,
successful_defenses = 12,
times_neutralized_by_intruder = 13,
fob_event_ranking = 14,
fob_event_end = 14,

league_event_start = 15,
league_1 = 15,
league_2 = 16,
league_3 = 17,
league_4 = 18,
league_5 = 19,
league_6 = 20,
league_7 = 21,
league_8 = 22,
league_9 = 23,
league_10 = 24,
league_11 = 25,
league_event_end = 25,

event_count
};

enum event_ranking_lookup_type
{
lookup_best, // best global
lookup_around // around your placement
};

enum event_ranking_type
{
event_type_sneak, // all time
event_type_sneak_event // within period
};

std::optional<event_ranking_lookup_type> get_lookup_type_from_name(const std::string& name);
std::optional<event_type> get_event_type_from_id(const std::uint32_t id, const std::string& type);

class event_ranking
{
public:
DEFINE_FIELD(id, sqlpp::integer_unsigned);
DEFINE_FIELD(player_id, sqlpp::integer_unsigned);
DEFINE_FIELD(event_id, sqlpp::integer_unsigned);
DEFINE_FIELD(player_rank, sqlpp::integer_unsigned);
DEFINE_FIELD(value, sqlpp::integer_unsigned);
DEFINE_TABLE(event_rankings, id_field_t, player_id_field_t, event_id_field_t, player_rank_field_t, value_field_t);

inline static table_t table;

template <typename ...Args>
event_ranking(const sqlpp::result_row_t<Args...>& row)
{
this->id_ = row.id;
this->player_id_ = row.player_id;
this->event_id_ = static_cast<std::uint32_t>(row.event_id);
this->rank_ = row.player_rank;
this->value_ = static_cast<std::uint32_t>(row.value);
}

void set_league_grade(const std::uint32_t grade)
{
this->league_grade_ = grade;
}

void set_fob_grade(const std::uint32_t grade)
{
this->fob_grade_ = grade;
}

void set_account_id(const std::uint64_t account_id)
{
this->account_id_ = account_id;
}

GET_FIELD_H(std::uint64_t, id);
GET_FIELD_H(std::uint64_t, player_id);
GET_FIELD_H(std::uint32_t, event_id);
GET_FIELD_H(std::uint64_t, rank);
GET_FIELD_H(std::uint32_t, value);
GET_FIELD_H(std::uint32_t, fob_grade);
GET_FIELD_H(std::uint32_t, league_grade);
GET_FIELD_H(std::uint64_t, account_id);

private:

};

void create_entries(const std::uint64_t player_id);

bool set_event_value(const std::uint64_t player_id, const event_type event_id, const std::uint32_t value);
bool increment_event_value(const std::uint64_t player_id, const event_type event_id, const std::uint32_t count);
bool set_value_if_bigger(const std::uint64_t player_id, const event_type event_id, const std::uint32_t value);

std::optional<std::uint64_t> get_player_rank(const std::uint64_t player_id, const event_type event_id);

std::vector<event_ranking> get_entries(const event_type event_id, const std::uint64_t offset, const std::uint32_t num);

bool reset_periodic_values();

std::chrono::seconds get_last_update();
}
Loading

0 comments on commit 545d8de

Please sign in to comment.