mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-18 00:27:06 +02:00
166 lines
6.5 KiB
C++
166 lines
6.5 KiB
C++
#include "party_book.h"
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
namespace dingosdk::multiplayer {
|
|
std::uint32_t PartyBook::party_of(std::uint64_t player) const {
|
|
const auto found = member_of_.find(player);
|
|
return found == member_of_.end() ? 0 : found->second;
|
|
}
|
|
const PartyBook::Party *PartyBook::party(std::uint32_t id) const {
|
|
const auto found = parties_.find(id);
|
|
return found == parties_.end() ? nullptr : &found->second;
|
|
}
|
|
PartyBook::Party *PartyBook::find(std::uint32_t id) {
|
|
const auto found = parties_.find(id);
|
|
return found == parties_.end() ? nullptr : &found->second;
|
|
}
|
|
bool PartyBook::invited(std::uint64_t to, std::uint64_t from) const {
|
|
return std::any_of(invites_.begin(), invites_.end(), [&](const Invite &i) { return i.to == to && i.from == from; });
|
|
}
|
|
void PartyBook::add(std::uint32_t id, std::uint64_t player) {
|
|
parties_[id].members.push_back(player);
|
|
member_of_[player] = id;
|
|
}
|
|
void PartyBook::take_out(std::uint64_t player) {
|
|
const auto id = party_of(player);
|
|
auto *p = find(id);
|
|
if (!p) return;
|
|
member_of_.erase(player);
|
|
std::erase(p->members, player);
|
|
if (p->members.size() < 2) {
|
|
for (const auto member : p->members) member_of_.erase(member);
|
|
parties_.erase(id);
|
|
} else if (p->leader == player) {
|
|
p->leader = p->members.front(); // the longest-standing member leads next
|
|
}
|
|
changed();
|
|
}
|
|
void PartyBook::prune_invites() {
|
|
const auto stale = [&](const Invite &i) {
|
|
const auto party = party_of(i.from);
|
|
const auto *p = this->party(party);
|
|
// Accepting would do nothing (already together) or could not fit.
|
|
return (party && party == party_of(i.to)) || (p && p->members.size() >= limit_);
|
|
};
|
|
for (const auto &i : invites_) if (stale(i)) withdrawn_.push_back(i);
|
|
std::erase_if(invites_, stale);
|
|
}
|
|
PartyBook::Result PartyBook::invite(std::uint64_t from, std::uint64_t to, std::uint64_t now) {
|
|
if (from == to) return Result::self;
|
|
const auto party = party_of(from);
|
|
if (party && party == party_of(to)) return Result::same_party;
|
|
if (const auto *p = this->party(party); p && p->members.size() >= limit_) return Result::full;
|
|
const auto found = std::find_if(invites_.begin(), invites_.end(), [&](const Invite &i) { return i.to == to && i.from == from; });
|
|
if (found != invites_.end()) {
|
|
found->expires = now + invite_lifetime_us;
|
|
return Result::renewed;
|
|
}
|
|
if (std::count_if(invites_.begin(), invites_.end(), [&](const Invite &i) { return i.to == to; }) >=
|
|
static_cast<std::ptrdiff_t>(max_invites))
|
|
return Result::busy;
|
|
invites_.push_back({from, to, now + invite_lifetime_us});
|
|
return Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::accept(std::uint64_t to, std::uint64_t from, std::uint64_t now) {
|
|
const auto found = std::find_if(invites_.begin(), invites_.end(), [&](const Invite &i) {
|
|
return i.to == to && i.from == from && now < i.expires;
|
|
});
|
|
if (found == invites_.end()) return Result::no_invite;
|
|
invites_.erase(found);
|
|
auto party = party_of(from);
|
|
if (party && party == party_of(to)) return Result::same_party;
|
|
if (const auto *p = this->party(party); p && p->members.size() >= limit_) return Result::full;
|
|
take_out(to);
|
|
if (!party) {
|
|
party = next_++;
|
|
if (!next_) next_ = 1;
|
|
parties_[party] = {from, {}, false};
|
|
add(party, from);
|
|
}
|
|
add(party, to);
|
|
changed();
|
|
prune_invites();
|
|
return Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::decline(std::uint64_t to, std::uint64_t from) {
|
|
const auto before = invites_.size();
|
|
std::erase_if(invites_, [&](const Invite &i) { return i.to == to && i.from == from; });
|
|
return invites_.size() == before ? Result::no_invite : Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::join(std::uint64_t who, std::uint64_t target, std::uint64_t now) {
|
|
if (who == target) return Result::self;
|
|
const auto party = party_of(target);
|
|
if (!party) return Result::no_party;
|
|
if (party == party_of(who)) return Result::same_party;
|
|
const auto *p = this->party(party);
|
|
// An invite from anyone in that party lets the player in, as does an open party.
|
|
const auto invite = std::find_if(invites_.begin(), invites_.end(), [&](const Invite &i) {
|
|
return i.to == who && party_of(i.from) == party && now < i.expires;
|
|
});
|
|
if (invite != invites_.end()) return accept(who, invite->from, now);
|
|
if (!p->open) return Result::closed;
|
|
if (p->members.size() >= limit_) return Result::full;
|
|
take_out(who);
|
|
add(party, who);
|
|
changed();
|
|
prune_invites();
|
|
return Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::leave(std::uint64_t who) {
|
|
if (!party_of(who)) return Result::not_member;
|
|
take_out(who);
|
|
return Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::kick(std::uint64_t leader, std::uint64_t target) {
|
|
const auto party = party_of(leader);
|
|
const auto *p = this->party(party);
|
|
if (!p) return Result::not_member;
|
|
if (p->leader != leader) return Result::not_leader;
|
|
if (target == leader) return Result::self;
|
|
if (party_of(target) != party) return Result::not_member;
|
|
take_out(target);
|
|
return Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::promote(std::uint64_t leader, std::uint64_t target) {
|
|
const auto party = party_of(leader);
|
|
auto *p = find(party);
|
|
if (!p) return Result::not_member;
|
|
if (p->leader != leader) return Result::not_leader;
|
|
if (target == leader) return Result::self;
|
|
if (party_of(target) != party) return Result::not_member;
|
|
p->leader = target;
|
|
changed();
|
|
return Result::ok;
|
|
}
|
|
PartyBook::Result PartyBook::set_open(std::uint64_t leader, bool open) {
|
|
auto *p = find(party_of(leader));
|
|
if (!p) return Result::not_member;
|
|
if (p->leader != leader) return Result::not_leader;
|
|
if (p->open != open) {
|
|
p->open = open;
|
|
changed();
|
|
}
|
|
return Result::ok;
|
|
}
|
|
void PartyBook::remove(std::uint64_t player) {
|
|
take_out(player);
|
|
std::erase_if(invites_, [&](const Invite &i) {
|
|
if (i.to == player) return true;
|
|
if (i.from != player) return false;
|
|
withdrawn_.push_back(i);
|
|
return true;
|
|
});
|
|
}
|
|
std::vector<PartyBook::Invite> PartyBook::expire(std::uint64_t now) {
|
|
std::vector<Invite> lapsed;
|
|
for (const auto &i : invites_) if (now >= i.expires) lapsed.push_back(i);
|
|
std::erase_if(invites_, [&](const Invite &i) { return now >= i.expires; });
|
|
return lapsed;
|
|
}
|
|
std::vector<PartyBook::Invite> PartyBook::take_withdrawn() {
|
|
prune_invites();
|
|
return std::exchange(withdrawn_, {});
|
|
}
|
|
} // namespace dingosdk::multiplayer
|