/** * Copyright (C) 2015 Justin 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 Justin 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; }