Share online membership and game setup with the server

Profile, member join/leave and building a fresh game move into the sim library,
and the packet reader and writer into protocol.h, so the server can run lobbies
exactly as clients do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shweetandClaude Opus 5.5 committed 2026-11-08 01:54:27 -05:00
1 parent 465f75f6d7
commit 9613e85706
7 files changed
+181 -105

No files matched your search

+78
View File
@@ -1,6 +1,7 @@
#include "match.h"
#include "sim.h"
#include <algorithm>
#include <cstring>
constexpr Burst FINISH_BURST = {.gravity = 200, .life = 1, .size = 3, .speed = 240, .count = 40};
constexpr float RACE_GRACE = 15;
@@ -746,3 +747,80 @@ void Match::leaves_take(Sim& sim)
std::fill(std::begin(isReady), std::end(isReady), false);
sim.cues->sound_play(SOUND_FINISH);
}
// A fighter's loadout, slots and levels as a profile, to bring it back as it was (a name and colour are added by whoever
// knows them).
Profile profile_get(Fighter& fighter)
{
Profile profile;
profile.weaponSlots = fighter.weaponSlots;
profile.trinketSlots = fighter.trinketSlots;
std::copy(std::begin(fighter.weaponLoadout), std::end(fighter.weaponLoadout), profile.weaponLoadout);
std::copy(std::begin(fighter.trinketLoadout), std::end(fighter.trinketLoadout), profile.trinketLoadout);
std::copy(std::begin(fighter.weaponSlotLevels), std::end(fighter.weaponSlotLevels), profile.weaponSlotLevels);
std::copy(std::begin(fighter.trinketSlotLevels), std::end(fighter.trinketSlotLevels), profile.trinketSlotLevels);
std::copy(std::begin(fighter.weaponItemLevels), std::end(fighter.weaponItemLevels), profile.weaponItemLevels);
std::copy(std::begin(fighter.trinketItemLevels), std::end(fighter.trinketItemLevels), profile.trinketItemLevels);
return profile;
}
// Online, a member's fighter appears, set up from their profile, in the colour they asked for if it's free. Returns
// it, or -1 when the game is full.
int Match::member_join(Sim& sim, int member, const Profile& profile)
{
if (sim.fighterCount >= MAX_FIGHTERS)
return -1;
int index = sim.fighterCount++;
Fighter& fighter = sim.fighters[index];
fighter = Fighter{};
fighter.init(sim, index);
fighter.slots_set(std::clamp(profile.weaponSlots, 1, SLOT_MAX), std::clamp(profile.trinketSlots, 1, SLOT_MAX));
std::copy(std::begin(profile.weaponLoadout), std::end(profile.weaponLoadout), fighter.weaponLoadout);
std::copy(std::begin(profile.trinketLoadout), std::end(profile.trinketLoadout), fighter.trinketLoadout);
std::copy(std::begin(profile.weaponSlotLevels), std::end(profile.weaponSlotLevels), fighter.weaponSlotLevels);
std::copy(std::begin(profile.trinketSlotLevels), std::end(profile.trinketSlotLevels), fighter.trinketSlotLevels);
std::copy(std::begin(profile.weaponItemLevels), std::end(profile.weaponItemLevels), fighter.weaponItemLevels);
std::copy(std::begin(profile.trinketItemLevels), std::end(profile.trinketItemLevels), fighter.trinketItemLevels);
owners[index] = member;
std::memcpy(names[index], profile.name, sizeof(names[index]));
names[index][PLAYER_NAME_MAX] = '\0';
bool isTaken[COLOR_COUNT] = {};
for (int i = 0; i < index; i++)
isTaken[colors[i]] = true;
bool isFree = profile.color >= 0 && profile.color < COLOR_COUNT && !isTaken[profile.color];
colors[index] = isFree ? profile.color : (std::find(isTaken, isTaken + COLOR_COUNT, false) - isTaken) % COLOR_COUNT;
return index;
}
// Online, a member's fighter goes with its attacks, and the fighters after it move down a place.
void Match::member_leave(Sim& sim, int member)
{
int index = fighter_find(sim, member);
if (index < 0)
return;
std::vector<Attack>& attacks = sim.weapons.attacks;
std::erase_if(attacks, [&](Attack& attack) { return attack.owner == index; });
for (Attack& attack : attacks)
attack.owner -= attack.owner > index;
for (int i = index; i + 1 < sim.fighterCount; i++)
{
sim.fighters[i] = sim.fighters[i + 1];
sim.fighters[i].index = i;
sim.bot.states[i] = sim.bot.states[i + 1];
owners[i] = owners[i + 1];
colors[i] = colors[i + 1];
std::memcpy(names[i], names[i + 1], sizeof(names[i]));
}
queue_slots_shift(index, sim.fighterCount);
sim.fighterCount--;
owners[sim.fighterCount] = -1;
}
// Which fighter a member plays, or -1 for none.
int Match::fighter_find(Sim& sim, int member)
{
for (int i = 0; i < sim.fighterCount; i++)
if (owners[i] == member)
return i;
return -1;
}