feat: add in-game social test lab
This commit is contained in:
@@ -34,6 +34,13 @@ import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/commo
|
||||
import * as WebSocket from 'ws';
|
||||
import { ChatService } from '../../business/chat/chat.service';
|
||||
import { SocialService } from '../../business/social/social.service';
|
||||
import {
|
||||
getTestLabPresence,
|
||||
getTestLabPresences,
|
||||
removeTestLabPresence,
|
||||
TestLabPresence,
|
||||
upsertTestLabPresence,
|
||||
} from '../../business/admin/test_lab_presence.registry';
|
||||
|
||||
/** WebSocket 服务器默认端口 */
|
||||
const DEFAULT_WEBSOCKET_PORT = 3001;
|
||||
@@ -911,6 +918,58 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
|
||||
return players;
|
||||
}
|
||||
|
||||
/** 管理端测试实验室使用:返回真实在线玩家,绝不包含合成假人。 */
|
||||
public getOnlineWorldPlayers(): Array<{ userId: string; username: string; mapId: string }> {
|
||||
return [...this.clients.values()]
|
||||
.filter((client) => client.authenticated && client.worldReady && client.userId && client.currentMap)
|
||||
.map((client) => ({ userId: String(client.userId), username: String(client.username || ''), mapId: String(client.currentMap) }));
|
||||
}
|
||||
|
||||
public setTestLabPresence(presence: TestLabPresence): void {
|
||||
const previous = getTestLabPresence(presence.userId);
|
||||
const current = upsertTestLabPresence(presence);
|
||||
if (previous?.online && (!current.online || previous.mapId !== current.mapId)) {
|
||||
this.broadcastToMap(previous.mapId, { t: 'player_left', userId: previous.userId, username: previous.nickname, mapId: previous.mapId });
|
||||
}
|
||||
if (!current.online) return;
|
||||
const payload = {
|
||||
t: previous?.online && previous.mapId === current.mapId ? 'position_update' : 'player_joined',
|
||||
userId: current.userId,
|
||||
username: current.nickname,
|
||||
mapId: current.mapId,
|
||||
x: current.x,
|
||||
y: current.y,
|
||||
skinId: current.skinId,
|
||||
avatarId: current.avatarId,
|
||||
appearance: { skinId: current.skinId, avatarId: current.avatarId },
|
||||
};
|
||||
this.broadcastToMap(current.mapId, payload);
|
||||
}
|
||||
|
||||
public removeTestLabActor(userId: string): void {
|
||||
const previous = removeTestLabPresence(userId);
|
||||
if (previous?.online) {
|
||||
this.broadcastToMap(previous.mapId, { t: 'player_left', userId: previous.userId, username: previous.nickname, mapId: previous.mapId });
|
||||
}
|
||||
}
|
||||
|
||||
public broadcastTestLabChat(actor: TestLabPresence, content: string, scope: 'local' | 'global' = 'local'): void {
|
||||
const payload = {
|
||||
t: 'chat_render',
|
||||
from: actor.nickname,
|
||||
fromUserId: actor.userId,
|
||||
txt: content,
|
||||
bubble: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
messageId: `test_${Date.now()}_${actor.userId}`,
|
||||
mapId: actor.mapId,
|
||||
scope,
|
||||
testLab: true,
|
||||
};
|
||||
if (scope === 'global') this.broadcastToAll(payload);
|
||||
else this.broadcastToMap(actor.mapId, payload);
|
||||
}
|
||||
|
||||
// ========== 私有辅助方法 ==========
|
||||
|
||||
private sendMessage(ws: ExtendedWebSocket, data: any) {
|
||||
@@ -976,10 +1035,22 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
|
||||
});
|
||||
const players = (await this.chatService.getMapPlayerSnapshot(normalizedMapId, ws.id))
|
||||
.filter((player) => activeUserIds.has(String(player.userId)));
|
||||
const testPlayers = getTestLabPresences(normalizedMapId).map((player) => ({
|
||||
userId: player.userId,
|
||||
username: player.nickname,
|
||||
mapId: player.mapId,
|
||||
x: player.x,
|
||||
y: player.y,
|
||||
skinId: player.skinId,
|
||||
avatarId: player.avatarId,
|
||||
appearance: { skinId: player.skinId, avatarId: player.avatarId },
|
||||
cafeCompanion: null,
|
||||
movementLocked: false,
|
||||
}));
|
||||
this.sendMessage(ws, {
|
||||
t: 'map_players_snapshot',
|
||||
mapId: normalizedMapId,
|
||||
players,
|
||||
players: [...players, ...testPlayers].filter((player) => String(player.userId) !== String(ws.userId)),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user