mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-09 10:18:05 +00:00
Put friends on the same team (#3994)
Fixes #3911 ## Description: - Server captures `publicId` and `friends` from `getUserMe()` and includes each player's in-game friend `clientID`s in `PlayerSchema` on game start - Team assignment treats friends as a **soft preference** (best-effort): a non-clan player goes to the team where the most of their friends already are; if that team is full they spill to the next-emptiest team rather than getting kicked - Clans remain strict (kick overflow) since clan membership is an explicit opt-in; friends are implicit, so a friend-of-friend chain that doesn't fit shouldn't bench anyone - Friendship is symmetric — an edge from either direction counts, which keeps things working when one side's `getUserMe` is stale - Lobby preview unchanged — friend grouping only takes effect once the game actually starts (avoids exposing friend lists in the lobby payload) ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
@@ -21,5 +21,7 @@ export class Client {
|
||||
public clanTag: string | null,
|
||||
public ws: WebSocket,
|
||||
public readonly cosmetics: PlayerCosmetics | undefined,
|
||||
public readonly publicId: string | undefined,
|
||||
public readonly friends: string[],
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -731,18 +731,29 @@ export class GameServer {
|
||||
// if no client connects/pings.
|
||||
this.lastPingUpdate = Date.now();
|
||||
|
||||
const publicIdToClientID = new Map<string, ClientID>();
|
||||
for (const c of this.activeClients) {
|
||||
if (c.publicId) publicIdToClientID.set(c.publicId, c.clientID);
|
||||
}
|
||||
|
||||
const result = GameStartInfoSchema.safeParse({
|
||||
gameID: this.id,
|
||||
lobbyCreatedAt: this.createdAt,
|
||||
visibleAt: this.visibleAt,
|
||||
config: this.gameConfig,
|
||||
players: this.activeClients.map((c) => ({
|
||||
username: c.username,
|
||||
clanTag: c.clanTag ?? null,
|
||||
clientID: c.clientID,
|
||||
cosmetics: c.cosmetics,
|
||||
isLobbyCreator: this.lobbyCreatorID === c.clientID,
|
||||
})),
|
||||
players: this.activeClients.map((c) => {
|
||||
const friendClientIDs = c.friends
|
||||
.map((pid) => publicIdToClientID.get(pid))
|
||||
.filter((id): id is ClientID => id !== undefined);
|
||||
return {
|
||||
username: c.username,
|
||||
clanTag: c.clanTag ?? null,
|
||||
clientID: c.clientID,
|
||||
cosmetics: c.cosmetics,
|
||||
isLobbyCreator: this.lobbyCreatorID === c.clientID,
|
||||
friends: friendClientIDs.length > 0 ? friendClientIDs : undefined,
|
||||
};
|
||||
}),
|
||||
});
|
||||
if (!result.success) {
|
||||
const error = z.prettifyError(result.error);
|
||||
|
||||
@@ -376,6 +376,8 @@ export async function startWorker() {
|
||||
}
|
||||
|
||||
let flares: string[] | undefined;
|
||||
let publicId: string | undefined;
|
||||
let friends: string[] = [];
|
||||
|
||||
const allowedFlares = ServerEnv.allowedFlares();
|
||||
if (claims === null) {
|
||||
@@ -396,6 +398,8 @@ export async function startWorker() {
|
||||
return;
|
||||
}
|
||||
flares = result.response.player.flares;
|
||||
publicId = result.response.player.publicId;
|
||||
friends = result.response.player.friends;
|
||||
|
||||
if (allowedFlares !== undefined) {
|
||||
const allowed =
|
||||
@@ -462,6 +466,8 @@ export async function startWorker() {
|
||||
censoredClanTag,
|
||||
ws,
|
||||
cosmeticResult.cosmetics,
|
||||
publicId,
|
||||
friends,
|
||||
);
|
||||
|
||||
const joinResult = gm.joinClient(client, clientMsg.gameID);
|
||||
|
||||
Reference in New Issue
Block a user