Add docker setup and switch voice chat backend to use livekit

This commit is contained in:
2026-03-11 16:06:41 +01:00
parent b051a0a851
commit ae301db3bb
24 changed files with 1362 additions and 232 deletions

View File

@@ -32,8 +32,7 @@ type MessageHandlerDeps = {
};
signalingSend: (message: unknown) => void;
peerManager: {
createOrGetPeer: (id: string, initiator: boolean, user: { id: string; nickname: string; x: number; y: number }) => Promise<unknown>;
handleSignal: (message: IncomingMessage) => Promise<{ id: string; nickname: string; x: number; y: number }>;
ensurePeer: (id: string, user: { id: string; nickname: string; x: number; y: number }) => { id: string; nickname: string; x: number; y: number };
setPeerPosition: (id: string, x: number, y: number) => void;
setPeerNickname: (id: string, nickname: string) => void;
removePeer: (id: string) => void;
@@ -77,8 +76,7 @@ type MessageHandlerDeps = {
handleAdminUsersList: (message: Extract<IncomingMessage, { type: 'admin_users_list' }>) => void;
handleAdminActionResult: (message: Extract<IncomingMessage, { type: 'admin_action_result' }>) => void;
handleItemTransferTargets: (message: Extract<IncomingMessage, { type: 'item_transfer_targets' }>) => void;
isPeerNegotiationReady: () => boolean;
enqueuePendingSignal: (message: Extract<IncomingMessage, { type: 'signal' }>) => void;
connectToLiveKit: (url: string, token: string) => void;
};
/**
@@ -153,30 +151,8 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
deps.gameLoop();
break;
case 'signal': {
if (!deps.isPeerNegotiationReady()) {
deps.enqueuePendingSignal(message);
if (!deps.state.peers.has(message.senderId)) {
deps.state.peers.set(message.senderId, {
id: message.senderId,
userId: null,
nickname: deps.sanitizeName(message.senderNickname || 'user...') || 'user...',
x: Number.isFinite(message.x) ? message.x : 20,
y: Number.isFinite(message.y) ? message.y : 20,
});
}
break;
}
const peer = await deps.peerManager.handleSignal(message);
if (!deps.state.peers.has(peer.id)) {
deps.state.peers.set(peer.id, {
id: peer.id,
userId: null,
nickname: deps.sanitizeName(peer.nickname) || 'user...',
x: peer.x,
y: peer.y,
});
}
case 'livekit_token': {
deps.connectToLiveKit(message.url, message.token);
break;
}

View File

@@ -175,15 +175,10 @@ export const authResultSchema = z.object({
.optional(),
});
export const signalMessageSchema = z.object({
type: z.literal('signal'),
senderId: z.string(),
senderNickname: z.string().optional(),
x: z.number().int().optional(),
y: z.number().int().optional(),
targetId: z.string().optional(),
sdp: z.any().optional(),
ice: z.any().optional(),
export const livekitTokenSchema = z.object({
type: z.literal('livekit_token'),
token: z.string(),
url: z.string(),
});
export const updatePositionSchema = z.object({
@@ -368,7 +363,7 @@ export const incomingMessageSchema = z.discriminatedUnion('type', [
authRequiredSchema,
authResultSchema,
welcomeMessageSchema,
signalMessageSchema,
livekitTokenSchema,
updatePositionSchema,
teleportCompleteSchema,
updateNicknameSchema,
@@ -407,7 +402,6 @@ export type OutgoingMessage =
| { type: 'admin_user_ban'; username: string }
| { type: 'admin_user_unban'; username: string }
| { type: 'admin_user_delete'; username: string }
| { type: 'signal'; targetId: string; sdp?: RTCSessionDescriptionInit; ice?: RTCIceCandidateInit }
| { type: 'update_position'; x: number; y: number }
| { type: 'teleport_complete'; x: number; y: number }
| { type: 'update_nickname'; nickname: string }