feat: kick_player can target a publicId (admin bot) (#4403)

## Description:

Add an optional `targetPublicId` to KickPlayerIntent; the server
resolves it against the connected clients to the live clientID, then
kicks as before. Existing clientID targeting (lobby / in-game kick) is
unchanged. That way you can kick player with both the clientID and
playerID

## 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

## Please put your Discord username so you can be contacted if a bug or
regression is found:

zixer._
This commit is contained in:
Zixer1
2026-06-24 17:34:17 -04:00
committed by GitHub
parent 82efcecb80
commit 8ce5f3439c
5 changed files with 49 additions and 8 deletions
+1 -1
View File
@@ -640,7 +640,7 @@ export class Transport {
private onSendKickPlayerIntent(event: SendKickPlayerIntentEvent) {
this.sendIntent({
type: "kick_player",
target: event.target,
targetClientID: event.target,
});
}
+5 -1
View File
@@ -477,7 +477,11 @@ export const MarkDisconnectedIntentSchema = z.object({
export const KickPlayerIntentSchema = z.object({
type: z.literal("kick_player"),
target: ID,
// Either a live clientID (lobby / in-game kick) OR an account publicID, for
// callers that identify a player by account rather than per-session clientID;
// the server resolves the publicID to the live clientID. Exactly one is set.
targetClientID: ID.optional(),
targetPublicID: ID.optional(),
});
export const TogglePauseIntentSchema = z.object({
+15 -3
View File
@@ -265,7 +265,19 @@ export class GameServer {
error: "only the lobby creator or an admin can kick players",
};
}
if (stamped.clientID === stamped.target) {
// Resolve the target to a live clientID: an explicit clientID, or an
// account publicId matched against the connected clients (for callers
// that know the account but not the per-session clientID).
let target = stamped.targetClientID;
if (target === undefined && stamped.targetPublicID !== undefined) {
target = this.activeClients.find(
(c) => c.publicId === stamped.targetPublicID,
)?.clientID;
}
if (target === undefined) {
return { status: 404, error: "no matching player to kick" };
}
if (stamped.clientID === target) {
return { status: 400, error: "cannot kick yourself" };
}
const reason =
@@ -274,12 +286,12 @@ export class GameServer {
: KICK_REASON_LOBBY_CREATOR;
this.log.info("player kicked", {
kicker: stamped.clientID,
target: stamped.target,
target,
isAdmin: actor.isAdmin,
isAdminBot: actor.isAdminBot,
gameID: this.id,
});
this.kickClient(stamped.target, reason);
this.kickClient(target, reason);
return { status: 200 };
}