You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
8.6 KiB

1 month ago
using System.Collections.Concurrent;
using ProtoCSStruct;
using Sog;
using Sog.Gate;
namespace FrameSync;
public class Room
{
public readonly int MatchTickInterval = 33;
public readonly ConcurrentQueue<CSPlayerOpInfo> playerOpInfos = new();
public uint currFrameIndex = 0;
public List<(uint, long)> playerSessionIDs = new(20);
public Dictionary<long, CSJoinRoomRes> 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<Room> s_Rooms = new List<Room>(20);
private static Dictionary<long, Room> s_Player2Rooms = new Dictionary<long, Room>();
// private static List<CSPlayerOpInfo> playerOpInfos = new List<CSPlayerOpInfo>(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);
}
}
}