mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-23 00:15:23 +00:00
feat(kick-system): add translated kick reasons with error codes
- Add kickReason field to ServerErrorMessage schema with enum values - Display translated kick messages instead of generic "Kicked from game" - Include error codes (KICK_ADMIN, KICK_MULTI_TAB, KICK_LOBBY_CREATOR) for debugging - Update kick handlers in GameServer, PostJoinHandler, and Worker to pass reasons - Modify showErrorModal to handle kick-specific formatting without duplication
This commit is contained in:
@@ -545,7 +545,11 @@
|
||||
"copy_clipboard": "Copy to clipboard",
|
||||
"copied": "Copied!",
|
||||
"failed_copy": "Failed to copy",
|
||||
"desync_notice": "You are desynced from other players. What you see might differ from other players."
|
||||
"desync_notice": "You are desynced from other players. What you see might differ from other players.",
|
||||
"kicked_message": "You have been kicked from the game.",
|
||||
"kicked_reason_admin": "An administrator removed you from the game.",
|
||||
"kicked_reason_lobby_creator": "The lobby host removed you from the game.",
|
||||
"kicked_reason_multi_tab": "You may be playing on another tab or browser window."
|
||||
},
|
||||
"heads_up_message": {
|
||||
"choose_spawn": "Choose a starting location"
|
||||
|
||||
@@ -105,15 +105,31 @@ export function joinLobby(
|
||||
).then((r) => r.start());
|
||||
}
|
||||
if (message.type === "error") {
|
||||
showErrorModal(
|
||||
message.error,
|
||||
message.message,
|
||||
lobbyConfig.gameID,
|
||||
lobbyConfig.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
if (message.kickReason) {
|
||||
const kickMessage = translateText("error_modal.kicked_message");
|
||||
const reasonKey = `error_modal.kicked_reason_${message.kickReason.replace("kick_", "")}`;
|
||||
const reasonMessage = translateText(reasonKey);
|
||||
|
||||
showErrorModal(
|
||||
kickMessage,
|
||||
`${reasonMessage}\nError Code: ${message.kickReason.toUpperCase()}`,
|
||||
lobbyConfig.gameID,
|
||||
lobbyConfig.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
} else {
|
||||
showErrorModal(
|
||||
message.error,
|
||||
message.message,
|
||||
lobbyConfig.gameID,
|
||||
lobbyConfig.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
transport.connect(onconnect, onmessage);
|
||||
@@ -336,15 +352,31 @@ export class ClientGameRunner {
|
||||
);
|
||||
}
|
||||
if (message.type === "error") {
|
||||
showErrorModal(
|
||||
message.error,
|
||||
message.message,
|
||||
this.lobby.gameID,
|
||||
this.lobby.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
if (message.kickReason) {
|
||||
const kickMessage = translateText("error_modal.kicked_message");
|
||||
const reasonKey = `error_modal.kicked_reason_${message.kickReason.replace("kick_", "")}`;
|
||||
const reasonMessage = translateText(reasonKey);
|
||||
|
||||
showErrorModal(
|
||||
kickMessage,
|
||||
`${reasonMessage}\nError Code: ${message.kickReason.toUpperCase()}`,
|
||||
this.lobby.gameID,
|
||||
this.lobby.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
} else {
|
||||
showErrorModal(
|
||||
message.error,
|
||||
message.message,
|
||||
this.lobby.gameID,
|
||||
this.lobby.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
}
|
||||
}
|
||||
if (message.type === "turn") {
|
||||
if (!this.hasJoined) {
|
||||
|
||||
@@ -465,6 +465,7 @@ export const ServerDesyncSchema = z.object({
|
||||
|
||||
export const ServerErrorSchema = z.object({
|
||||
error: z.string(),
|
||||
kickReason: z.enum(["kick_admin", "kick_multi_tab", "kick_lobby_creator"]).optional(),
|
||||
message: z.string().optional(),
|
||||
type: z.literal("error"),
|
||||
});
|
||||
|
||||
@@ -175,7 +175,7 @@ export class GameServer {
|
||||
});
|
||||
// Kick the existing client instead of the new one, because this was causing issues when
|
||||
// a client wanted to replay the game afterwards.
|
||||
this.kickClient(conflicting.clientID);
|
||||
this.kickClient(conflicting.clientID, "kick_multi_tab");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +502,8 @@ export class GameServer {
|
||||
return this.gameConfig.gameType === GameType.Public;
|
||||
}
|
||||
|
||||
public kickClient(clientID: ClientID): void {
|
||||
|
||||
public kickClient(clientID: ClientID, kickReason?: "kick_admin" | "kick_multi_tab" | "kick_lobby_creator"): void {
|
||||
if (this.kickedClients.has(clientID)) {
|
||||
this.log.warn(`cannot kick client, already kicked`, {
|
||||
clientID,
|
||||
@@ -513,11 +514,13 @@ export class GameServer {
|
||||
if (client) {
|
||||
this.log.info("Kicking client from game", {
|
||||
clientID: client.clientID,
|
||||
kickReason,
|
||||
persistentID: client.persistentID,
|
||||
});
|
||||
client.ws.send(
|
||||
JSON.stringify({
|
||||
error: "Kicked from game (you may have been playing on another tab)",
|
||||
error: "Kicked from game",
|
||||
kickReason,
|
||||
type: "error",
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
|
||||
@@ -294,7 +294,7 @@ export async function startWorker() {
|
||||
return;
|
||||
}
|
||||
|
||||
game.kickClient(clientID);
|
||||
game.kickClient(clientID, "kick_admin");
|
||||
res.status(200).send("Player kicked successfully");
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -77,7 +77,7 @@ export async function postJoinMessageHandler(
|
||||
target: clientMsg.intent.target,
|
||||
});
|
||||
|
||||
gs.kickClient(clientMsg.intent.target);
|
||||
gs.kickClient(clientMsg.intent.target, "kick_lobby_creator");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user