feat(squad): in-memory squad/lobby state + wire squad functions
Build & Deploy / build (push) Successful in 31s

Adds SquadService (singleton, process-local) tracking squads by the
squadId the client shares across party members, plus a user->squad index
so TryGetCompleteSquadInfo (no squadId in request) can resolve the
caller's squad. Members are lazily registered on any squad call.

- TryGetCompleteSquadInfo: returns the caller's real squad.
- SquadMemberReadyForMatch: joins the squad, records readiness/map,
  returns the squad + whether everyone is ready.
- SquadMemberSelectedMap: records the member's selected map.
- DbUserService.FindByIdAsync: resolve display name for squad members.

Groundwork for the station lobby; assumes the client drives squads via
these calls with a shared squadId (to confirm with a 2-client session).
Real-time SignalR push (unknown event names) deferred; the squad is
carried in responses + TryGetCompleteSquadInfo for now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 15:34:43 +02:00
co-authored by Claude Opus 4.8
parent 922deb8397
commit 0588849e4c
6 changed files with 166 additions and 33 deletions
@@ -13,11 +13,17 @@ public class DbUserService : BaseDbService<PlayFabUser>
public async Task<PlayFabUser> FindAsync(PlayFabUserAuthType type, string key)
{
return await Collection.Find(user => user.Auth.Any(auth =>
auth.Type == type &&
return await Collection.Find(user => user.Auth.Any(auth =>
auth.Type == type &&
auth.Key == key)).FirstOrDefaultAsync();
}
// Resolve a player by its PlayFab id (used to display squad member names).
public async Task<PlayFabUser> FindByIdAsync(string id)
{
return await Collection.Find(user => user.Id == id).FirstOrDefaultAsync();
}
private async Task<PlayFabUser> CreateAsync(PlayFabUserAuthType type, string key)
{
var user = new PlayFabUser