using System.Collections.Concurrent; using ProtoCSStruct; using Sog; using Sog.Gate; namespace FrameSync; public class Room { public readonly int MatchTickInterval = 33; public readonly ConcurrentQueue playerOpInfos = new(); public uint currFrameIndex = 0; public List<(uint, long)> playerSessionIDs = new(20); public Dictionary playerInfos = new(); public CSMultFrapBootInfo cacheInfos = new CSMultFrapBootInfo(); public uint gateServerID; public int refCount = 0; public bool isFull = false; public long matchTimeAcc = -1; public RoomMode mode; public bool isMatch = false; public bool AddPlayer(ref CSJoinRoomRes joinRoom, uint gateId, long sessionID) { gateServerID = gateId; playerSessionIDs.Add((gateId, sessionID)); playerInfos.Add(sessionID, joinRoom); refCount++; if (mode == RoomMode.None) { isFull = true; } else if (mode == RoomMode.Mode1v1) { isFull = refCount >= 2; } return isFull; } public void RemovePlayer(uint gateId, long sessionID) { for (int i = 0; i < playerSessionIDs.Count; i++) { if (playerSessionIDs[i].Item1 == gateId && playerSessionIDs[i].Item2 == sessionID) { playerSessionIDs.RemoveAt(i); refCount--; break; } } if (refCount == 0) { isMatch = false; } } public void BeginMatch(ServerApp app) { matchTimeAcc = -1; isMatch = true; // sync to all clients CSRoomInfoSync infos = new CSRoomInfoSync(); infos.Mode = mode; for (int i = 0; i < playerSessionIDs.Count; i++) { if (playerInfos.TryGetValue(playerSessionIDs[i].Item2, out CSJoinRoomRes joinRoom) == false) { TraceLog.Error("Room.BeginMatch playerInfos.TryGetValue failed"); continue; } infos.Poses.Add(joinRoom.Pos); infos.Eids.Add(joinRoom.Eid); } for (int i = 0; i < playerSessionIDs.Count; i++) { uint gateServerID = playerSessionIDs[i].Item1; long sessionID = playerSessionIDs[i].Item2; infos.LocalEid = playerInfos[playerSessionIDs[i].Item2].Eid; GateService.SendToGate(0, app.GetCluster(), gateServerID, sessionID, (int)CSGameMsgID.RoomInfoSync, ref infos); } } public void AddPlayerOpInfo(ref CSPlayerOpInfo playerOpInfo) { playerOpInfos.Enqueue(playerOpInfo); } public void Tick(long nowMs, ServerApp app) { if (isMatch == false) return; if (matchTimeAcc == -1) { matchTimeAcc = nowMs; return; } if (nowMs - matchTimeAcc < MatchTickInterval * (currFrameIndex + 1)) return; Broadcast(app); } public void Broadcast(ServerApp app) { CSFrapBootInfo frapBootInfo = new CSFrapBootInfo(); currFrameIndex++; frapBootInfo.DwKFrapsNo = currFrameIndex; var count = playerOpInfos.Count; while (count > 0 && playerOpInfos.TryDequeue(out CSPlayerOpInfo playerOpInfo)) { count--; frapBootInfo.Ops.Add(playerOpInfo); } // 冗余4帧 // cacheInfos.SpareNum = currFrameIndex; // if (cacheInfos.SpareNum >= 4) { // cacheInfos.SpareNum = 4; // } // cacheInfos.SpareFraps.Add(frapBootInfo); for (int i = 0; i < playerSessionIDs.Count; i++) { TraceLog.TraceDetail("MatchSystem.Tick send to gateServerID {0}, sessionID {1} frapBootInfo {2}", playerSessionIDs[i].Item1, playerSessionIDs[i].Item2, cacheInfos.SpareFraps[0].DwKFrapsNo); GateService.SendToGate(0, app.GetCluster(), playerSessionIDs[i].Item1, playerSessionIDs[i].Item2, (int)CSGameMsgID.CsMultFrapBootInfoSync, ref cacheInfos); } // 满了 if (cacheInfos.SpareNum == 4) { for(int i = 1; i < 4; i++) { cacheInfos.SpareFraps[i - 1] = cacheInfos.SpareFraps[i]; } cacheInfos.SpareFraps.RemoveAt(3); } } } public static class MatchSystem { private static ServerApp m_app; public static long MatchTickInterval = 33; private static long lastMatchTickTime = 0; public static List s_Rooms = new List(20); private static Dictionary s_Player2Rooms = new Dictionary(); // private static List playerOpInfos = new List(20); // private static List<(uint, long)> playerSessionIDs = new List<(uint, long)>(20); // private static CSMultFrapBootInfo cacheInfos = new CSMultFrapBootInfo(); public static void JoinOrCreateRoom(ref CSJoinRoomReq joinRoom, uint gateServerID, long sessionID) { // 获取房间 if (s_Player2Rooms.TryGetValue(sessionID, out Room room)) { CSJoinRoomRes joinRoomRes = new CSJoinRoomRes(); joinRoomRes.Mode = room.mode; joinRoomRes.Pos = room.refCount; joinRoomRes.Eid = 10 + room.refCount; GateService.SendToGate(0, m_app.GetCluster(), gateServerID, sessionID, (int)CSGameMsgID.JoinRoomRes, ref joinRoomRes); } else { if (s_Rooms.Count > 0) { // 找没满的 Room targetRoom = null; foreach (var r in s_Rooms) { if (r.mode == joinRoom.Mode && r.isFull == false) { targetRoom = r; break; } } if (targetRoom != null) { s_Player2Rooms.Add(sessionID, targetRoom); CSJoinRoomRes joinRoomRes = new CSJoinRoomRes(); joinRoomRes.Mode = targetRoom.mode; joinRoomRes.Pos = targetRoom.refCount; joinRoomRes.Eid = 10 + targetRoom.refCount; targetRoom.AddPlayer(ref joinRoomRes, gateServerID, sessionID); GateService.SendToGate(0, m_app.GetCluster(), gateServerID, sessionID, (int)CSGameMsgID.JoinRoomRes, ref joinRoomRes); if (targetRoom.isFull) { targetRoom.BeginMatch(m_app); } return; } } room = new Room(); room.mode = joinRoom.Mode; // room.AddPlayer(ref joinRoom, gateServerID, sessionID); s_Rooms.Add(room); s_Player2Rooms.Add(sessionID, room); CSJoinRoomRes joinRoomRes2 = new CSJoinRoomRes(); joinRoomRes2.Mode = room.mode; joinRoomRes2.Pos = room.refCount; joinRoomRes2.Eid = 10 + room.refCount; room.AddPlayer(ref joinRoomRes2, gateServerID, sessionID); GateService.SendToGate(0, m_app.GetCluster(), gateServerID, sessionID, (int)CSGameMsgID.JoinRoomRes, ref joinRoomRes2); if (room.isFull) { room.BeginMatch(m_app); } } } public static void LeaveRoom(uint gateServerID, long sessionID) { if (s_Player2Rooms.TryGetValue(sessionID, out Room room)) { room.RemovePlayer(gateServerID, sessionID); if (room.refCount == 0) { s_Rooms.Remove(room); s_Player2Rooms.Remove(sessionID); } } } public static void Init(ServerApp app) { m_app = app; s_Player2Rooms.Clear(); s_Rooms.Clear(); } public static void AddPlayerOpInfo(ref CSPlayerOpInfo playerOpInfo, uint gateServerID, long sessionID) { if (s_Player2Rooms.TryGetValue(sessionID, out Room room)) { if (room.isMatch) room.AddPlayerOpInfo(ref playerOpInfo); } } public static void Tick(long nowMs, ServerApp app) { for (int i = 0; i < s_Rooms.Count; i++) { if (s_Rooms[i].refCount == 0) { s_Rooms.RemoveAt(i); i--; } } for (int i = 0; i < s_Rooms.Count; i++) { s_Rooms[i].Tick(nowMs, app); } } }