From e8c1a7d3a069c947b90ece6457c4a1667de4189e Mon Sep 17 00:00:00 2001 From: sin365 <353374337@qq.com> Date: Mon, 18 Nov 2024 23:46:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E8=A2=AB=E5=8A=A8?= =?UTF-8?q?=E8=BF=BD=E5=B8=A7+=E4=BC=98=E5=8C=96=E5=B9=BF=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AxibugEmuOnline.Server.csproj | 4 + AxibugEmuOnline.Server/Manager/RoomManager.cs | 158 +++++++++++------- AxibugEmuOnline.Server/Program.cs | 2 +- 3 files changed, 105 insertions(+), 59 deletions(-) diff --git a/AxibugEmuOnline.Server/AxibugEmuOnline.Server.csproj b/AxibugEmuOnline.Server/AxibugEmuOnline.Server.csproj index 7bd51e11..57a78f95 100644 --- a/AxibugEmuOnline.Server/AxibugEmuOnline.Server.csproj +++ b/AxibugEmuOnline.Server/AxibugEmuOnline.Server.csproj @@ -7,6 +7,10 @@ enable + + + + ..\Lib\Google.Protobuf.dll diff --git a/AxibugEmuOnline.Server/Manager/RoomManager.cs b/AxibugEmuOnline.Server/Manager/RoomManager.cs index 1fd03ddc..b70098b3 100644 --- a/AxibugEmuOnline.Server/Manager/RoomManager.cs +++ b/AxibugEmuOnline.Server/Manager/RoomManager.cs @@ -28,18 +28,17 @@ namespace AxibugEmuOnline.Server NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomPlayerReady, OnRoomPlayerReady); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomSingelPlayerInput, OnSingelPlayerInput); - NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdScreen, OnCmdScreen); - //roomTickARE = AppSrv.g_Tick.AddNewARE(TickManager.TickType.Interval_16MS); - //threadRoomTick = new Thread(UpdateLoopTick); - //threadRoomTick.Start(); + roomTickARE = AppSrv.g_Tick.AddNewARE(TickManager.TickType.Interval_16MS); + threadRoomTick = new Thread(UpdateLoopTick); + threadRoomTick.Start(); - System.Timers.Timer mTimer16ms = new System.Timers.Timer(16);//实例化Timer类 - mTimer16ms.Elapsed += new System.Timers.ElapsedEventHandler((source, e) => { UpdateAllRoomLogic(); });//到达时间的时候执行事件; - mTimer16ms.AutoReset = true;//设置是执行一次(false)还是一直执行(true); - mTimer16ms.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件; - mTimer16ms.Start(); + //System.Timers.Timer mTimer16ms = new System.Timers.Timer(16);//实例化Timer类 + //mTimer16ms.Elapsed += new System.Timers.ElapsedEventHandler((source, e) => { UpdateAllRoomLogic(); });//到达时间的时候执行事件; + //mTimer16ms.AutoReset = true;//设置是执行一次(false)还是一直执行(true); + //mTimer16ms.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件; + //mTimer16ms.Start(); } #region 房间管理 @@ -153,7 +152,7 @@ namespace AxibugEmuOnline.Server Errcode = ErrorCode.ErrorRoomNotFound; else { - resp.FrameID = (int)room.mCurrFrameId; + resp.FrameID = (int)room.mCurrServerFrameId; resp.RoomID = room.RoomID; resp.RawBitmap = room.ScreenRaw; } @@ -201,7 +200,7 @@ namespace AxibugEmuOnline.Server AppSrv.g_ClientMgr.ClientSend(_c, (int)CommandID.CmdRoomCreate, (int)joinErrcode, ProtoBufHelper.Serizlize(resp)); if (joinErrcode == ErrorCode.ErrorOk && bHadRoomStateChange) - SendRoomStateChange(newRoom); + SendRoomStepChange(newRoom); SendRoomUpdateToAll(newRoom.RoomID, 0); } @@ -235,7 +234,7 @@ namespace AxibugEmuOnline.Server Protobuf_Room_MyRoom_State_Change(msg.RoomID); if (joinErrcode == ErrorCode.ErrorOk && bHadRoomStateChange) - SendRoomStateChange(room); + SendRoomStepChange(room); if (room != null) { @@ -266,7 +265,7 @@ namespace AxibugEmuOnline.Server //Protobuf_Room_MyRoom_State_Change(msg.RoomID); //if (errcode == ErrorCode.ErrorOk && bHadRoomStateChange) - // SendRoomStateChange(room); + // SendRoomStepChange(room); //SendRoomUpdateToAll(room.RoomID, 1); //if (room.GetPlayerCount() < 1) @@ -283,7 +282,7 @@ namespace AxibugEmuOnline.Server Data_RoomData room = GetRoomData(_c.RoomState.RoomID); bool bHadRoomStateChange = false; if (room == null) - { + { errcode = ErrorCode.ErrorRoomNotFound; AppSrv.g_ClientMgr.ClientSend(_c, (int)CommandID.CmdRoomLeave, (int)errcode, ProtoBufHelper.Serizlize(resp)); return; @@ -297,7 +296,7 @@ namespace AxibugEmuOnline.Server Protobuf_Room_MyRoom_State_Change(RoomID); if (errcode == ErrorCode.ErrorOk && bHadRoomStateChange) - SendRoomStateChange(room); + SendRoomStepChange(room); if (room.GetPlayerCount() < 1) { @@ -327,7 +326,7 @@ namespace AxibugEmuOnline.Server { room.SetLoadRaw(msg.LoadStateRaw, out bool bHadRoomStateChange); if (bHadRoomStateChange) - SendRoomStateChange(room); + SendRoomStepChange(room); } } @@ -346,17 +345,15 @@ namespace AxibugEmuOnline.Server room.SetRePlayerReady(_c.RoomState.PlayerIdx, out errcode, out bool bHadRoomStateChange); if (bHadRoomStateChange) { - SendRoomStateChange(room); + SendRoomStepChange(room); } } } - ulong LastTestRecv = 0; public void OnSingelPlayerInput(Socket sk, byte[] reqData) { ClientInfo _c = AppSrv.g_ClientMgr.GetClientForSocket(sk); Protobuf_Room_SinglePlayerInputData msg = ProtoBufHelper.DeSerizlize(reqData); - Data_RoomData room = GetRoomData(_c.RoomState.RoomID); if (room == null) return; @@ -364,14 +361,37 @@ namespace AxibugEmuOnline.Server //取玩家操作数据中的第一个 ServerInputSnapShot temp = new ServerInputSnapShot(); temp.all = msg.InputData; - room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp); + //room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp); - if (LastTestRecv != room.mCurrInputData.all) + //是否需要推帧 + if (room.GetNeedForwardTick(msg.FrameID, out long forwaFrame)) { - LastTestRecv = room.mCurrInputData.all; - AppSrv.g_Log.Debug($" {DateTime.Now.ToString("hh:mm:ss.fff")} SynTestRecv=> UID->{_c.UID} roomId->{room.mCurrFrameId} input->{msg.InputData}"); + for (int i = 0; i < forwaFrame; i++) + { + if (i + 1 == forwaFrame)//最后一帧 + { + //写入操作前、将网络波动堆积,可能造成瞬时多个连续推帧结果(最后一帧除外)立即广播,不等16msTick + if (forwaFrame > 1) + room.SynInputData(); + + //推帧过程中,最后一帧才写入操作 + room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp); + } + //推帧 + room.TakeFrame(); + } + } + else//不需要推帧 + { + //虽然不推帧,但是存入Input + room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp); } + if (room.LastTestRecv != room.mCurrInputData.all) + { + room.LastTestRecv = room.mCurrInputData.all; + AppSrv.g_Log.Debug($" {DateTime.Now.ToString("hh:mm:ss.fff")} SynTestRecv=> UID->{_c.UID} roomId->{room.mCurrServerFrameId} input->{msg.InputData}"); + } } public void OnCmdScreen(Socket sk, byte[] reqData) @@ -406,7 +426,11 @@ namespace AxibugEmuOnline.Server } } - public void SendRoomStateChange(Data_RoomData room) + /// + /// 广播联机Step + /// + /// + public void SendRoomStepChange(Data_RoomData room) { List roomClient = room.GetAllPlayerClientList(); switch (room.GameState) @@ -417,7 +441,7 @@ namespace AxibugEmuOnline.Server { WaitStep = 0 }; - AppSrv.g_Log.Debug($"Step=>{0} WaitRawUpdate 广播等待主机上报即时存档"); + AppSrv.g_Log.DebugCmd($"Step:0 WaitRawUpdate 广播等待主机上报即时存档"); AppSrv.g_ClientMgr.ClientSend(roomClient, (int)CommandID.CmdRoomWaitStep, (int)ErrorCode.ErrorOk, ProtoBufHelper.Serizlize(resp)); } break; @@ -428,8 +452,7 @@ namespace AxibugEmuOnline.Server WaitStep = 1, LoadStateRaw = room.NextStateRaw }; - AppSrv.g_Log.Debug($"Step=>{1} WaitReady 广播即时存档"); - + AppSrv.g_Log.DebugCmd($"Step:1 WaitReady 广播即时存档"); AppSrv.g_ClientMgr.ClientSend(roomClient, (int)CommandID.CmdRoomWaitStep, (int)ErrorCode.ErrorOk, ProtoBufHelper.Serizlize(resp)); } break; @@ -439,16 +462,13 @@ namespace AxibugEmuOnline.Server { WaitStep = 2, }; - AppSrv.g_Log.Debug($"Step=>{2} 广播开始游戏"); - + AppSrv.g_Log.DebugCmd($"Step:2 InOnlineGame 广播开始游戏"); AppSrv.g_ClientMgr.ClientSend(roomClient, (int)CommandID.CmdRoomWaitStep, (int)ErrorCode.ErrorOk, ProtoBufHelper.Serizlize(resp)); } break; } } - - #region 房间帧循环 void UpdateLoopTick() { @@ -468,7 +488,7 @@ namespace AxibugEmuOnline.Server if (!mDictRoom.TryGetValue(roomid, out Data_RoomData room) || room.GameState < RoomGameState.InOnlineGame) continue; //更新帧 - room.TakeFrame(); + //room.TakeFrame(); //广播 room.SynInputData(); } @@ -494,9 +514,10 @@ namespace AxibugEmuOnline.Server public List SynUIDs; //public RoomPlayerState PlayerState => getPlayerState(); private RoomGameState mGameState; - public uint mCurrFrameId = 0; + public uint mCurrServerFrameId = 0; public ServerInputSnapShot mCurrInputData; public Queue<(uint, ServerInputSnapShot)> mInputQueue; + object synInputLock = new object(); //TODO public Dictionary> mDictPlayerIdx2SendQueue; public RoomGameState GameState @@ -520,6 +541,12 @@ namespace AxibugEmuOnline.Server } } + /// + /// 服务器提前帧数 + /// + public int SrvForwardFrames { get; set; } + + bool IsAllReady() { bool Ready = true; @@ -652,9 +679,9 @@ namespace AxibugEmuOnline.Server switch (PlayerIdx) { case 0: mCurrInputData.p1_byte = allinput.p1_byte; break; - case 1: mCurrInputData.p2_byte = allinput.p2_byte; break; - case 2: mCurrInputData.p3_byte = allinput.p3_byte; break; - case 3: mCurrInputData.p4_byte = allinput.p4_byte; break; + case 1: mCurrInputData.p2_byte = allinput.p1_byte; break; + case 2: mCurrInputData.p3_byte = allinput.p1_byte; break; + case 3: mCurrInputData.p4_byte = allinput.p1_byte; break; } } @@ -692,47 +719,52 @@ namespace AxibugEmuOnline.Server maxNetDelay = Math.Max(maxNetDelay, player.AveNetDelay); } - mCurrFrameId = 0; + mCurrServerFrameId = 0; mCurrInputData.all = 1; - int TaskFrameCount = (int)((maxNetDelay / 0.016f) + 5f); + float MustTaskFrame = 3; - AppSrv.g_Log.Debug($"服务器提前跑帧数:({maxNetDelay} / {0.016f}) + {5f} = {TaskFrameCount}"); - TaskFrameCount = 0; - for (int i = 0; i < TaskFrameCount; i++) - { + SrvForwardFrames = (int)((maxNetDelay / 0.016f) + MustTaskFrame); + AppSrv.g_Log.Debug($"服务器提前跑帧数:({maxNetDelay} / {0.016f}) + {MustTaskFrame} = {SrvForwardFrames}"); + + //服务器提前跑帧数 + for (int i = 0; i < SrvForwardFrames; i++) TakeFrame(); - } } public void TakeFrame() { - mInputQueue.Enqueue((mCurrFrameId, mCurrInputData)); - mCurrFrameId++; + mInputQueue.Enqueue((mCurrServerFrameId, mCurrInputData)); + mCurrServerFrameId++; } ulong LastTestSend = 0; + internal ulong LastTestRecv; + /// /// 广播数据 /// public void SynInputData() { - while (mInputQueue.Count > 0) + lock (synInputLock) { - (uint frameId, ServerInputSnapShot inputdata) data = mInputQueue.Dequeue(); - Protobuf_Room_Syn_RoomFrameAllInputData resp = new Protobuf_Room_Syn_RoomFrameAllInputData() + while (mInputQueue.Count > 0) { - FrameID = data.frameId, - InputData = data.inputdata.all, - ServerFrameID = mCurrFrameId - }; - - if (LastTestSend != data.inputdata.all) - { - LastTestSend = data.inputdata.all; - AppSrv.g_Log.Debug($" {DateTime.Now.ToString("hh:mm:ss.fff")} SynInput=> RoomID->{RoomID} ServerFrameID->{mCurrFrameId} SynUIDs=>{string.Join(",", SynUIDs)} "); + (uint frameId, ServerInputSnapShot inputdata) data = mInputQueue.Dequeue(); + Protobuf_Room_Syn_RoomFrameAllInputData resp = new Protobuf_Room_Syn_RoomFrameAllInputData() + { + FrameID = data.frameId, + InputData = data.inputdata.all, + ServerFrameID = mCurrServerFrameId + }; + //if (LastTestSend != data.inputdata.all) + //{ + // LastTestSend = data.inputdata.all; + // AppSrv.g_Log.Debug($" {DateTime.Now.ToString("hh:mm:ss.fff")} SynInput=> RoomID->{RoomID} ServerFrameID->{mCurrServerFrameId} SynUIDs=>{string.Join(",", SynUIDs)} "); + //} + AppSrv.g_ClientMgr.ClientSend(SynUIDs, (int)CommandID.CmdRoomSynPlayerInput, (int)ErrorCode.ErrorOk, ProtoBufHelper.Serizlize(resp)); + //AppSrv.g_Log.Debug($" {DateTime.Now.ToString("hh:mm:ss.fff")} SynInput=> RoomID->{RoomID} ServerFrameID->{mCurrServerFrameId} SynUIDs=>{string.Join(",", SynUIDs)} "); } - AppSrv.g_ClientMgr.ClientSend(SynUIDs, (int)CommandID.CmdRoomSynPlayerInput, (int)ErrorCode.ErrorOk, ProtoBufHelper.Serizlize(resp)); } } @@ -878,6 +910,16 @@ namespace AxibugEmuOnline.Server { this.ScreenRaw = NextStateRaw; } + + public bool GetNeedForwardTick(uint clientFrame,out long forwaFrame) + { + forwaFrame = 0; + //目标帧,客户端+服务器提前量 + long targetFrame = clientFrame + SrvForwardFrames; + if (targetFrame > mCurrServerFrameId)//更靠前 + forwaFrame = targetFrame - mCurrServerFrameId; + return forwaFrame > 0; + } } [StructLayout(LayoutKind.Explicit, Size = 8)] diff --git a/AxibugEmuOnline.Server/Program.cs b/AxibugEmuOnline.Server/Program.cs index 39fb88d9..f18dee6f 100644 --- a/AxibugEmuOnline.Server/Program.cs +++ b/AxibugEmuOnline.Server/Program.cs @@ -29,7 +29,7 @@ namespace AxibugEmuOnline.Server AppSrv.g_Log.Info($"GameRomID:{room.GameRomID}"); AppSrv.g_Log.Info($"GameState:{room.GameState}"); AppSrv.g_Log.Info($"HostUID:{room.HostUID}"); - AppSrv.g_Log.Info($"mCurrFrameId:{room.mCurrFrameId}"); + AppSrv.g_Log.Info($"mCurrFrameId:{room.mCurrServerFrameId}"); AppSrv.g_Log.Info($"input all:{room.mCurrInputData.all}"); AppSrv.g_Log.Info($"input p1:{room.mCurrInputData.p1_byte}"); AppSrv.g_Log.Info($"input p2:{room.mCurrInputData.p2_byte}");