mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-18 08:05:15 +02:00
- Read Dev / Creator / Homie Steam IDs from api.reskate.dev instead of the hardcoded list
- Creator (red) and Homie (gold) tags and hoodie/board colours; Admin tag is now pink
- Global bans: lobby hosts and dedicated servers turn banned players away
("global_bans": false in ReSkateServer.json opts a server out)
- SPECIAL menu page for listed players to hide their own tag and items
- Fix hoodie and board keeping the animated colour after the animation turns off
- Multiplayer protocol 39 -> 40
63 lines
2.8 KiB
C++
63 lines
2.8 KiB
C++
#include "developer_identity.h"
|
|
#include "Engine/Core/Json/json.h"
|
|
#include <algorithm>
|
|
#include <atomic>
|
|
#include <charconv>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
|
|
// The lists themselves, shared by the game and the dedicated server. Each reads
|
|
// them from the backend its own way: developer_identity_fetch.cpp, Server/global_bans.cpp.
|
|
namespace dingosdk::multiplayer {
|
|
namespace {
|
|
// The API's name for each category, in IdentityList order; the ban list follows them.
|
|
constexpr std::array<std::string_view, 3> categories{"dev", "homie", "content_creator"};
|
|
constexpr auto banned = static_cast<std::size_t>(IdentityList::banned);
|
|
|
|
std::atomic<std::shared_ptr<const IdentityLists>> current;
|
|
|
|
// A player's SteamID64 is 76561197960265728 plus a 32-bit account number, and
|
|
// nobody has account 0. The API sends them as strings.
|
|
std::uint64_t steam_id(const Json &entry) {
|
|
constexpr std::uint64_t base = 76561197960265728ULL, last = base + 0xffffffffULL;
|
|
std::uint64_t id{};
|
|
if (entry.is_string()) {
|
|
const auto &text = entry.string();
|
|
const auto parsed = std::from_chars(text.data(), text.data() + text.size(), id);
|
|
if (parsed.ec == std::errc{} && parsed.ptr == text.data() + text.size() && id > base && id <= last) return id;
|
|
}
|
|
throw std::runtime_error("an entry is not a player's SteamID64");
|
|
}
|
|
} // namespace
|
|
|
|
IdentityLists parse_identity_lists(std::string_view json) {
|
|
const auto answer = Json::parse(json);
|
|
if (!answer.is_object() || !answer.contains("categories") || !answer.at("categories").is_object())
|
|
throw std::runtime_error("the answer has no categories");
|
|
const auto &listed = answer.at("categories");
|
|
IdentityLists lists;
|
|
const auto read = [](const Json &entries, std::vector<std::uint64_t> &ids) {
|
|
if (!entries.is_array()) throw std::runtime_error("a list of players is not a list");
|
|
for (const auto &entry : entries) ids.push_back(steam_id(entry));
|
|
std::sort(ids.begin(), ids.end());
|
|
ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
|
|
};
|
|
for (std::size_t index = 0; index < categories.size(); ++index)
|
|
if (listed.contains(categories[index])) read(listed.at(categories[index]), lists[index]);
|
|
if (answer.contains("banned")) read(answer.at("banned"), lists[banned]);
|
|
return lists;
|
|
}
|
|
bool publish_identity_lists(IdentityLists lists) {
|
|
const auto previous = current.load();
|
|
if (previous && *previous == lists) return false;
|
|
current.store(std::make_shared<const IdentityLists>(std::move(lists)));
|
|
return true;
|
|
}
|
|
bool identity_listed(std::uint64_t id, IdentityList list) noexcept {
|
|
const auto lists = current.load();
|
|
if (!id || !lists || list >= IdentityList::count) return false;
|
|
const auto &ids = (*lists)[static_cast<std::size_t>(list)];
|
|
return std::binary_search(ids.begin(), ids.end(), id);
|
|
}
|
|
} // namespace dingosdk::multiplayer
|