2 Commits

Author SHA1 Message Date
moyin
963e6ca90f refactor(auth): 移除登录注册时的Zulip内存关联逻辑
范围: src/business/auth/
涉及文件:
- src/business/auth/login.service.ts
- src/business/auth/register.service.ts

主要改进:
- 移除登录时建立Zulip内存关联的代码
- 移除注册时建立Zulip内存关联的代码
- 改为在WebSocket连接时由Zulip客户端创建内存关联
- 优化了内存关联的时机,避免不必要的提前创建

技术说明:
- 原逻辑在登录/注册时就建立内存关联,但用户可能不会立即使用Zulip
- 新逻辑延迟到WebSocket连接时创建,更加合理和高效
- 减少了登录/注册流程的复杂度和耦合度
2026-01-19 17:59:58 +08:00
moyin
cd2a197288 feat(chat): 添加地图切换功能
范围: src/gateway/chat/
- 新增 change_map 事件处理
- 实现 handleChangeMap() 方法
- 支持玩家在不同地图间切换
- 自动更新房间成员和广播通知
- 完善地图切换的错误处理

功能说明:
- 玩家可以通过 WebSocket 发送 change_map 事件切换地图
- 自动处理房间加入/离开逻辑
- 向旧地图广播玩家离开,向新地图广播玩家加入
- 支持携带初始位置坐标,默认使用 (400, 300)
2026-01-19 17:43:59 +08:00
3 changed files with 84 additions and 18 deletions

View File

@@ -714,13 +714,7 @@ export class LoginService {
apiKeyResult.apiKey! apiKeyResult.apiKey!
); );
// 4. 更新内存关联 // 注意不在登录时建立内存关联Zulip客户端将在WebSocket连接时创建
await this.zulipAccountService.linkGameAccount(
user.id.toString(),
zulipAccount.zulipUserId,
zulipAccount.zulipEmail,
apiKeyResult.apiKey!
);
const duration = Date.now() - startTime; const duration = Date.now() - startTime;

View File

@@ -533,15 +533,7 @@ export class RegisterService {
status: 'active', status: 'active',
}); });
// 6. 建立游戏账号与Zulip账号的内存关联用于当前会话 // 注意不在注册时建立内存关联Zulip客户端将在WebSocket连接时创建
if (finalApiKey) {
await this.zulipAccountService.linkGameAccount(
gameUser.id.toString(),
createResult.userId, // 已在上面验证不为 undefined
createResult.email!,
finalApiKey
);
}
const duration = Date.now() - startTime; const duration = Date.now() - startTime;

View File

@@ -169,6 +169,9 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
case 'position': case 'position':
await this.handlePosition(ws, message); await this.handlePosition(ws, message);
break; break;
case 'change_map':
await this.handleChangeMap(ws, message);
break;
default: default:
this.logger.warn(`未知消息类型: ${messageType}`); this.logger.warn(`未知消息类型: ${messageType}`);
this.sendError(ws, `未知消息类型: ${messageType}`); this.sendError(ws, `未知消息类型: ${messageType}`);
@@ -254,7 +257,7 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
* 处理聊天消息 * 处理聊天消息
* *
* @param ws WebSocket 连接实例 * @param ws WebSocket 连接实例
* @param message 聊天消息(包含 content, scope * @param message 聊天消息(包含 content, scope, mapId
*/ */
private async handleChat(ws: ExtendedWebSocket, message: any) { private async handleChat(ws: ExtendedWebSocket, message: any) {
if (!ws.authenticated) { if (!ws.authenticated) {
@@ -271,7 +274,8 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
const result = await this.chatService.sendChatMessage({ const result = await this.chatService.sendChatMessage({
socketId: ws.id, socketId: ws.id,
content: message.content, content: message.content,
scope: message.scope || 'local' scope: message.scope || 'local',
mapId: message.mapId || ws.currentMap, // 支持指定目标地图
}); });
if (result.success) { if (result.success) {
@@ -335,6 +339,82 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
} }
} }
/**
* 处理切换地图
*
* @param ws WebSocket 连接实例
* @param message 切换地图消息(包含 mapId
*/
private async handleChangeMap(ws: ExtendedWebSocket, message: any) {
if (!ws.authenticated) {
this.sendError(ws, '请先登录');
return;
}
if (!message.mapId) {
this.sendError(ws, '地图ID不能为空');
return;
}
try {
const oldMapId = ws.currentMap;
const newMapId = message.mapId;
// 如果地图相同,直接返回成功
if (oldMapId === newMapId) {
this.sendMessage(ws, {
t: 'map_changed',
mapId: newMapId,
message: '已在当前地图'
});
return;
}
// 更新房间
this.leaveMapRoom(ws.id, oldMapId);
this.joinMapRoom(ws.id, newMapId);
ws.currentMap = newMapId;
// 更新会话中的地图信息(使用默认位置)
await this.chatService.updatePlayerPosition({
socketId: ws.id,
x: message.x || 400,
y: message.y || 300,
mapId: newMapId
});
// 通知客户端切换成功
this.sendMessage(ws, {
t: 'map_changed',
mapId: newMapId,
oldMapId: oldMapId,
message: '地图切换成功'
});
// 向旧地图广播玩家离开
this.broadcastToMap(oldMapId, {
t: 'player_left',
userId: ws.userId,
username: ws.username,
mapId: oldMapId
});
// 向新地图广播玩家加入
this.broadcastToMap(newMapId, {
t: 'player_joined',
userId: ws.userId,
username: ws.username,
mapId: newMapId
}, ws.id);
this.logger.log(`用户切换地图: ${ws.username} (${oldMapId} -> ${newMapId})`);
} catch (error) {
this.logger.error('切换地图处理失败', error);
this.sendError(ws, '切换地图处理失败');
}
}
/** /**
* 处理连接关闭 * 处理连接关闭
* *