You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单例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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 07:45:56