Unity中使用Photon离开房间后无法通过名称加入房间
Unity Photon 多人房间加入问题排查
问题现象
在Unity中使用Photon开发多人游戏时,初始流程(连接大厅、创建/按名称加入房间)均正常。但用户离开房间回到大厅后,创建房间功能正常,却无法通过名称加入已有房间,会提示**"There is no room with such name"**;注释掉房间存在性验证逻辑后,用户即可正常连接,问题出在房间存在性验证相关逻辑中。
相关代码
用户连接大厅代码
private void Start() { PhotonNetwork.ConnectUsingSettings(); } public override void OnConnectedToMaster() { PhotonNetwork.JoinLobby(); SceneManager.LoadScene("Lobby"); }
创建/加入房间代码
private Dictionary<string, RoomInfo> _roomList = new Dictionary<string, RoomInfo>(); private bool CheckNullOrEmpty(string name) { return !string.IsNullOrEmpty(name); } private bool CheckServerAvaliable(string qwe) { bool isAvaliable = true; foreach (var item in _roomList) { RoomInfo info = item.Value; if (info.Name == qwe) { isAvaliable = false; } } return isAvaliable; } private void SetNickname() { PhotonNetwork.NickName = _nickname.text; PlayerPrefs.SetString("name", _nickname.text); } private void CreateRoom() { RoomOptions roomOptions = new() { MaxPlayers = _maximumPlayers }; PhotonNetwork.CreateRoom(_createServer.text, roomOptions); } public void TryCreateRoom() { if (CheckNullOrEmpty(_createServer.text) && CheckServerAvaliable(_createServer.text) && CheckNullOrEmpty(_nickname.text)) { SetNickname(); CreateRoom(); } else if (!CheckNullOrEmpty(_nickname.text)) { _errorText.SetText("Nickname cannot contain only spaces or be empty"); } else if (!CheckServerAvaliable(_createServer.text)) { _errorText.SetText("The name of the room is occupied"); } } public void TryJoinRoom() { if (!CheckServerAvaliable(_joinServer.text)) { SetNickname(); PhotonNetwork.JoinRoom(_joinServer.text); } else if (!CheckNullOrEmpty(_nickname.text)) { _errorText.SetText("Nickname cannot contain only spaces or be empty"); } else if (CheckServerAvaliable(_joinServer.text)) { _errorText.SetText("There is no room with such name"); } } private void UpdateCachedRoomList(List<RoomInfo> roomList) { for (int i = 0; i < roomList.Count; i++) { RoomInfo info = roomList[i]; if (info.RemovedFromList) { _roomList.Remove(info.Name); } else { _roomList[info.Name] = info; } } } public override void OnRoomListUpdate(List<RoomInfo> roomList) { UpdateCachedRoomList(roomList); }
离开房间代码
public void Leave() { PhotonNetwork.LeaveRoom(); SceneManager.LoadScene("Lobby"); }
问题根源分析
- 异步操作未等待:离开房间时直接调用
SceneManager.LoadScene("Lobby"),但PhotonNetwork.LeaveRoom()是异步操作,此时可能还未真正回到大厅状态,导致新场景中的Lobby脚本无法正确订阅房间列表更新。 - 房间列表缓存未刷新:场景重新加载后,新的Lobby脚本实例的
_roomList是空的,而Photon的OnRoomListUpdate默认只发送增量更新(而非全量房间列表),导致本地缓存没有已有房间的信息,CheckServerAvaliable会错误判断房间不存在。 - 验证逻辑冗余遍历:
CheckServerAvaliable方法遍历整个字典时,找到匹配房间名后未提前终止循环,虽然不影响功能,但效率较低。
修复方案
1. 修复离开房间的异步逻辑
等待Photon完成离开房间操作后再加载场景,通过重写OnLeftRoom回调实现:
public void Leave() { PhotonNetwork.LeaveRoom(); } public override void OnLeftRoom() { // 确认离开房间后再加载大厅场景 SceneManager.LoadScene("Lobby"); }
2. 确保大厅场景订阅全量房间列表
在Lobby脚本中重写OnJoinedLobby回调,确保进入大厅后能获取到全量房间列表(Photon会在调用JoinLobby后自动发送全量列表):
public override void OnConnectedToMaster() { PhotonNetwork.JoinLobby(); } public override void OnJoinedLobby() { // 进入大厅后再加载场景,确保后续能接收房间列表更新 SceneManager.LoadScene("Lobby"); }
3. 优化房间存在性验证逻辑
找到匹配房间名后立即返回结果,避免无效遍历:
private bool CheckServerAvaliable(string roomName) { // 直接检查字典中是否存在该房间名,更高效 return !_roomList.ContainsKey(roomName); }
4. 补充空值与空格校验
原CheckNullOrEmpty方法未处理纯空格的情况,补充校验:
private bool CheckNullOrEmpty(string name) { return !string.IsNullOrWhiteSpace(name); }
修复逻辑说明
- 等待
OnLeftRoom回调再加载场景,确保客户端完全回到大厅状态,此时Photon会正常推送房间列表更新。 - 使用
_roomList.ContainsKey替代遍历字典,既简化代码又提升效率。 - 替换
string.IsNullOrEmpty为string.IsNullOrWhiteSpace,覆盖纯空格的非法输入场景。
内容的提问来源于stack exchange,提问作者user21403547
相关产品推荐
相关产品推荐

