单例GameManager成员列表修改未同步问题排查
单例GameManager玩家移除同步异常问题
当前使用单例GameManager作为数据源(后续将迁移至数据库),遇到成员列表修改未正常同步的问题:
- 在
Handle函数中,从GameManager正确获取到玩家数为2的房间,调用room.RemovePlayer()后,该房间的玩家数变为1; - 但调用
HandleRoomUpdate函数再次从GameManager获取该房间时,玩家数又变回了2; - 直接在
Handle中修改room的属性(如room.Status = ROOM_STATUS.GAME_OVER)可正常同步,说明问题大概率出在RemovePlayer函数中。
相关代码
Handle函数
public static void Handle(RequestModel request) { var room = GameManager.Instance.Rooms.Find(r => r.RoomId == request.RoomId); var player = room.TryGetPlayer(request.ClientId); if (player == null) return; if (room.isOwner(request.ClientId)) { var kickPlayerRequest = (KickPlayerRequest)request.Data; var kickedClient = GameManager.Instance.ClientsInRoom[room.RoomId] .Find(p => p.ConnectionInfo.Id == kickPlayerRequest.playerId); if (kickedClient == null || kickedClient.ConnectionInfo.Id == request.ClientId) return; room.RemovePlayer(kickPlayerRequest.playerId); GameManager.Instance.ClientsInRoom[room.RoomId].Remove(kickedClient); GameManager.Instance.ClientsAwaitingRoom.Add(kickedClient); ResponseHandler.HandleKickedUpdate(kickedClient); ResponseHandler.HandleRoomUpdate(request.RoomId); } }
RemovePlayer方法
public void RemovePlayer(Guid playerId) { var team = GetPlayerTeam(playerId); var player = Teams[team].Players.Find(p => p.id == playerId); if (player != null) { Teams[team].Players.Remove(player); } }
HandleRoomUpdate函数
public static void HandleRoomUpdate(string RoomId) { var room = GameManager.Instance.Rooms.Find(r => r.RoomId == RoomId); JObject response = new JObject(); response["responseType"] = "update_room"; response["room"] = JsonConvert.SerializeObject(room, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var clients = GameManager.Instance.ClientsInRoom[RoomId]; foreach (var c in clients) { response["playerId"] = c.ConnectionInfo.Id; c.Send(response.ToString()); } }
补充说明
Handle函数通过反射调用:
public static void HandleMessage(RequestModel request) { Type requestType = request.Data.GetType(); requestType.GetMethod("Handle").Invoke(null, new object?[]{request}); }
- 调试中确认操作的是同一个房间实例,但
RemovePlayer的修改未同步; - 尝试编写测试代码复现问题,但测试代码中修改可正常同步:
Room room = new Room(); room.teams[0].players.Add(new Player(0)); room.teams[0].players.Add(new Player(1)); GameManager.Instance.Rooms.Add(room); // 为了保持一致性,用这种方式调用方法 new RequestHandler().GetType().GetMethod("Handle").Invoke(null, new object?[]{room.id}); public class GameManager { public List<Room> Rooms; private GameManager() { Rooms = new List<Room>(); } private static GameManager m_instance; public static GameManager Instance { get { if (m_instance == null) { m_instance = new GameManager(); } return m_instance; } } } public class RequestHandler { public RequestHandler() {} public static void Handle(int id) { Room room = GameManager.Instance.Rooms.Find(r => r.id == id); // 输出2 Console.WriteLine(room.teams[0].players.Count); room.RemovePlayer(0); // 输出1 Console.WriteLine(room.teams[0].players.Count); ResponseHandler.HandleResponse(id); } } public class ResponseHandler { public static void HandleResponse(int id) { Room room = GameManager.Instance.Rooms.Find(r => r.id == id); // 这个例子里输出1,但实际场景中输出2 Console.WriteLine(room.teams[0].players.Count); } } public class Player { public int id; public Player(int id) { this.id = id; } } public class Team { public List<Player> players; public Team() { players = new List<Player>(); } } public class Room { public int id; public List<Team> teams; public Room() { id = 0; teams = new List<Team>(); teams.Add(new Team()); } public void RemovePlayer(int player) { var team = GetPlayersList(); var playa = teams[team].players.Find(p => p.id == player); teams[team].players.Remove(playa); } public int GetPlayersList() { return 0; } }
内容的提问来源于stack exchange,提问作者Peter Bou Saada
相关产品推荐
相关产品推荐

