From 9098ecb79793c4260c5686a389324bbf3de5788d Mon Sep 17 00:00:00 2001
From: sin365 <353374337@qq.com>
Date: Thu, 16 Jan 2025 18:31:34 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84Replay=20fixedbug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
IReplayReader.cs | 11 ++
IReplayWriter.cs | 12 +++
NetReplay.cs | 147 ++++++++++++++++++++++++++
ReplayData.cs | 4 +-
ReplayReader.cs | 49 ++++++---
ReplayWriter.cs | 261 ++++++++++++++++++++++++-----------------------
6 files changed, 336 insertions(+), 148 deletions(-)
create mode 100644 IReplayReader.cs
create mode 100644 IReplayWriter.cs
create mode 100644 NetReplay.cs
diff --git a/IReplayReader.cs b/IReplayReader.cs
new file mode 100644
index 0000000..c0761a5
--- /dev/null
+++ b/IReplayReader.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace AxiReplay
+{
+ internal interface IReplayReader : IDisposable
+ {
+ bool NextFrame(out ReplayStep data);
+ bool TakeFrame(int addFrame, out ReplayStep data);
+ bool NextFramebyFrameIdx(int FrameID, out ReplayStep data);
+ }
+}
diff --git a/IReplayWriter.cs b/IReplayWriter.cs
new file mode 100644
index 0000000..8f11a28
--- /dev/null
+++ b/IReplayWriter.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace AxiReplay
+{
+ internal interface IReplayWriter : IDisposable
+ {
+ void NextFrame(UInt64 frameInput);
+ void NextFramebyFrameIdx(int FrameID, UInt64 frameInput);
+ void TakeFrame(int addFrame, UInt64 frameInput);
+ void SaveData(string path, bool bNeedDump = false, string dumpFilePath = null);
+ }
+}
diff --git a/NetReplay.cs b/NetReplay.cs
new file mode 100644
index 0000000..5b7d26e
--- /dev/null
+++ b/NetReplay.cs
@@ -0,0 +1,147 @@
+using System.Collections.Generic;
+
+namespace AxiReplay
+{
+ public class NetReplay
+ {
+ ///
+ /// 客户端当前帧
+ ///
+ public int mCurrClientFrameIdx = 0;
+ ///
+ /// 服务器远端当前帧
+ ///
+ public int mRemoteFrameIdx { get; private set; }
+ ///
+ /// 服务器远端当前提前量
+ ///
+ public int mRemoteForwardCount { get; private set; }
+ ///
+ /// Remote 2 Client Frame Gap
+ ///
+ public int mDiffFrameCount => mRemoteFrameIdx - mCurrClientFrameIdx;
+ ///
+ /// 网络数据队列
+ ///
+ Queue mNetReplayQueue = new Queue();
+ ///
+ /// 当前数据
+ ///
+ ReplayStep mCurrReplay;
+ ///
+ /// 下一个数据数据
+ ///
+ ReplayStep mNextReplay;
+
+ bool bNetInit = false;
+ public NetReplay()
+ {
+ ResetData();
+ }
+ public void ResetData()
+ {
+ mNetReplayQueue.Clear();
+ mCurrReplay = default(ReplayStep);
+ mCurrReplay.FrameStartID = int.MinValue;
+ bNetInit = false;
+ }
+ public void InData(ReplayStep inputData, int ServerFrameIdx)
+ {
+ mNetReplayQueue.Enqueue(inputData);
+ mRemoteFrameIdx = inputData.FrameStartID;
+ if (!bNetInit)
+ {
+ bNetInit = true;
+ mNextReplay = mNetReplayQueue.Dequeue();
+ }
+ }
+ public bool TryGetNextFrame(out ReplayStep data, out int frameDiff, out bool inputDiff)
+ {
+ if (!bNetInit)
+ {
+ data = default(ReplayStep);
+ frameDiff = default(int);
+ inputDiff = false;
+ return false;
+ }
+ TakeFrame(1, out data, out frameDiff, out inputDiff);
+ return frameDiff > 0;
+ }
+
+ public bool TryGetNextFrame(int targetFrame, out ReplayStep data, out int frameDiff, out bool inputDiff)
+ {
+ if (!bNetInit)
+ {
+ data = default(ReplayStep);
+ frameDiff = default(int);
+ inputDiff = false;
+ return false;
+ }
+ return TakeFrameToTargetFrame(targetFrame, out data, out frameDiff, out inputDiff);
+ }
+
+ void TakeFrame(int addFrame, out ReplayStep data, out int bFrameDiff, out bool inputDiff)
+ {
+ int targetFrame = mCurrClientFrameIdx + addFrame;
+ TakeFrameToTargetFrame(targetFrame, out data, out bFrameDiff, out inputDiff);
+ }
+
+ bool TakeFrameToTargetFrame(int targetFrame, out ReplayStep data, out int bFrameDiff, out bool inputDiff)
+ {
+ bool result;
+ inputDiff = false;
+ if (targetFrame == mNextReplay.FrameStartID && targetFrame <= mRemoteFrameIdx && mNetReplayQueue.Count > 0)
+ {
+ //当前帧追加
+ mCurrClientFrameIdx = targetFrame;
+ ulong oldInput = mCurrReplay.InPut;
+ mCurrReplay = mNextReplay;
+ if (oldInput != mCurrReplay.InPut)
+ inputDiff = true;
+ mNextReplay = mNetReplayQueue.Dequeue();
+ result = true;
+ }
+ else
+ result = false;
+
+ bFrameDiff = mRemoteFrameIdx - mCurrClientFrameIdx;
+ data = mCurrReplay;
+
+ return result;
+ }
+
+ public int GetSkipFrameCount()
+ {
+ if(!bNetInit)
+ return 0;
+ //本地队列差异高于服务器提前量的值
+ int moreNum = mDiffFrameCount - mRemoteForwardCount;
+ //if (mDiffFrameCount < 0 || mDiffFrameCount > 10000)
+ // return 0;
+
+ ////游戏刚开始的一小段时间,直接追满
+ //if (mCurrClientFrameIdx < 60)
+ // return moreNum;
+
+ int skip = 0;
+ if (mDiffFrameCount > short.MaxValue) skip = 0;
+ else if (moreNum <= 1) skip = 0;
+ else if (moreNum <= 3) skip = 2;
+ else if (moreNum <= 6) skip = 2;
+ else if (moreNum <= 20) skip = moreNum / 2; //20帧以内,平滑跳帧数
+ else skip = moreNum;//完全追上
+ return skip;
+
+ //var frameGap = mDiffFrameCount;
+ //if (frameGap > 10000) return 0;
+ //if (frameGap <= 2) skip = 0;
+ //if (frameGap > 2 && frameGap < 6) skip = 1 + 1;
+ //else if (frameGap > 7 && frameGap < 12) skip = 2 + 1;
+ //else if (frameGap > 13 && frameGap < 20) skip = 3 + 1;
+ //else skip = frameGap - 2;
+
+
+ //return skip;
+ }
+ }
+}
diff --git a/ReplayData.cs b/ReplayData.cs
index ab3dd58..c958f2d 100644
--- a/ReplayData.cs
+++ b/ReplayData.cs
@@ -4,7 +4,7 @@ using System.Text;
namespace AxiReplay
{
- [StructLayout(LayoutKind.Explicit,Size = 44)]
+ [StructLayout(LayoutKind.Explicit, Size = 44)]
public struct ReplayHandler
{
[FieldOffset(0)]
@@ -51,7 +51,7 @@ namespace AxiReplay
FM32IP32,
FM32IP64,
}
- public static void GetStringByteData(string str,out byte[] data,out int lenghtWithEnd,Encoding encoding)
+ public static void GetStringByteData(string str, out byte[] data, out int lenghtWithEnd, Encoding encoding)
{
data = encoding.GetBytes(str);
lenghtWithEnd = data.Length + 1;
diff --git a/ReplayReader.cs b/ReplayReader.cs
index 7410eb7..e7d3c99 100644
--- a/ReplayReader.cs
+++ b/ReplayReader.cs
@@ -6,7 +6,7 @@ using static AxiReplay.ReplayData;
namespace AxiReplay
{
- public class ReplayReader : IDisposable
+ public class ReplayReader : IReplayReader
{
public ReplayData.ReplayFormat mFormat { get; private set; }
public Encoding TexEncoding { get; private set; }
@@ -21,10 +21,10 @@ namespace AxiReplay
FileStream mStream;
BinaryReader mBinaryReader;
- int mCurrFrame = -1;
+ int mCurrFrame = 0;
byte[] mNextOutbytes;
- ReplayStep currStep;
- ReplayStep nextStep;
+ public ReplayStep currStep;
+ public ReplayStep nextStep;
bool bEnd;
List dbgList = new List();
@@ -79,11 +79,12 @@ namespace AxiReplay
}
}
-
+
void UpdateNextFrame(int targetFrame)
{
+ int LastNextFrameStartID = nextStep.FrameStartID;
//如果已经超过
- while (targetFrame > nextStep.FrameStartID)
+ while (targetFrame >= nextStep.FrameStartID)
{
if (nextStep.FrameStartID >= handler.AllFrame)
{
@@ -117,34 +118,31 @@ namespace AxiReplay
}
dbgList.Add($"{nextStep.FrameStartID} | {nextStep.InPut}");
+ //如果这次的NextStep1只推进了1帧,则跳过,交给下一帧判断
+ if (nextStep.FrameStartID - LastNextFrameStartID == 1)
+ {
+ break;
+ }
+
targetFrame++;
}
}
int byFrameIdx = 0;
- ///
- /// 往前推进帧的,指定帧下标
- ///
- public bool NextFramebyFrameIdx(int FrameID,out ReplayStep data)
- {
- bool res = TakeFrame(FrameID - byFrameIdx, out data);
- byFrameIdx = FrameID;
- return res;
- }
///
/// 往前推进1帧的Input(返回是否变化)
///
public bool NextFrame(out ReplayStep data)
{
- return TakeFrame(1,out data);
+ return TakeFrame(1, out data);
}
///
/// 往前推进指定帧数量的Input (返回是否变化)
///
///
- public bool TakeFrame(int addFrame,out ReplayStep data)
+ public bool TakeFrame(int addFrame, out ReplayStep data)
{
bool Changed = false;
mCurrFrame += addFrame;
@@ -162,6 +160,23 @@ namespace AxiReplay
return Changed;
}
+ int lastTest = 0;
+ ///
+ /// 往前推进帧的,指定帧下标
+ ///
+ public bool NextFramebyFrameIdx(int FrameID, out ReplayStep data)
+ {
+ lastTest = FrameID;
+
+ if (FrameID == 3360)
+ {
+
+ }
+ bool res = TakeFrame(FrameID - byFrameIdx, out data);
+ byFrameIdx = FrameID;
+ return res;
+ }
+
public void Dispose()
{
mStream.Dispose();
diff --git a/ReplayWriter.cs b/ReplayWriter.cs
index 3d0f516..144c889 100644
--- a/ReplayWriter.cs
+++ b/ReplayWriter.cs
@@ -5,152 +5,155 @@ using System.Text;
namespace AxiReplay
{
- public class ReplayWriter : IDisposable
- {
- public ReplayData.ReplayFormat mFormat { get; private set; }
- public Encoding TexEncoding { get; private set; }
- ReplayHandler handler;
- string mTitle;
- string mNote;
- int mAllFrame;
- int mAllTime;
- long mData;
- int mSingleInputLenght;
- int mSingleDataLenght;
- MemoryStream mStream;
- BinaryWriter mBinaryWriter;
+ public class ReplayWriter : IReplayWriter
+ {
+ public ReplayData.ReplayFormat mFormat { get; private set; }
+ public Encoding TexEncoding { get; private set; }
+ ReplayHandler handler;
+ string mTitle;
+ string mNote;
+ int mAllFrame;
+ int mAllTime;
+ long mData;
+ int mSingleInputLenght;
+ int mSingleDataLenght;
+ MemoryStream mStream;
+ BinaryWriter mBinaryWriter;
- int mCurrFrame;
- UInt64 mCurrInput;
- ReplayStep wirteStep;
+ int mCurrFrame;
+ UInt64 mCurrInput;
+ ReplayStep wirteStep;
- List dbgList = new List();
+ List dbgList = new List();
- public ReplayWriter(string Title, string Note, ReplayData.ReplayFormat format, Encoding encoding)
- {
- mTitle = Title;
- mNote = Note;
- TexEncoding = encoding;
- mFormat = format;
- switch (mFormat)
- {
- case ReplayData.ReplayFormat.FM32IP64: mSingleInputLenght = sizeof(UInt64); break;
- case ReplayData.ReplayFormat.FM32IP32: mSingleInputLenght = sizeof(UInt32); break;
- case ReplayData.ReplayFormat.FM32IP16: mSingleInputLenght = sizeof(UInt16); break;
- case ReplayData.ReplayFormat.FM32IPBYTE: mSingleInputLenght = sizeof(byte); break;
- }
- mSingleDataLenght = (sizeof(UInt32)) + mSingleInputLenght;
+ public ReplayWriter(string Title, string Note, ReplayData.ReplayFormat format, Encoding encoding)
+ {
+ mTitle = Title;
+ mNote = Note;
+ TexEncoding = encoding;
+ mFormat = format;
+ switch (mFormat)
+ {
+ case ReplayData.ReplayFormat.FM32IP64: mSingleInputLenght = sizeof(UInt64); break;
+ case ReplayData.ReplayFormat.FM32IP32: mSingleInputLenght = sizeof(UInt32); break;
+ case ReplayData.ReplayFormat.FM32IP16: mSingleInputLenght = sizeof(UInt16); break;
+ case ReplayData.ReplayFormat.FM32IPBYTE: mSingleInputLenght = sizeof(byte); break;
+ }
+ mSingleDataLenght = (sizeof(UInt32)) + mSingleInputLenght;
- mStream = new MemoryStream();
- mBinaryWriter = new BinaryWriter(mStream);
+ mStream = new MemoryStream();
+ mBinaryWriter = new BinaryWriter(mStream);
- mCurrFrame = -1;
+ //mCurrFrame = -1;
+ mCurrFrame = 0;
mCurrInput = int.MaxValue;
- wirteStep = new ReplayStep();
+ wirteStep = new ReplayStep();
- dbgList.Clear();
+ dbgList.Clear();
- }
+ }
- int byFrameIdx = 0;
- ///
- /// 往前推进帧的,指定帧下标
- ///
- ///
- public void NextFramebyFrameIdx(int FrameID,UInt64 frameInput)
- {
- TakeFrame(FrameID - byFrameIdx, frameInput);
- byFrameIdx = FrameID;
- }
+ int byFrameIdx = 0;
+ ///
+ /// 往前推进帧的,指定帧下标
+ ///
+ ///
+ public void NextFramebyFrameIdx(int FrameID, UInt64 frameInput)
+ {
+ TakeFrame(FrameID - byFrameIdx, frameInput);
+ byFrameIdx = FrameID;
+ }
- ///
- /// 往前推进1帧的Input
- ///
- ///
- public void NextFrame(UInt64 frameInput)
- {
- TakeFrame(1, frameInput);
- }
+ ///
+ /// 往前推进1帧的Input
+ ///
+ ///
+ public void NextFrame(UInt64 frameInput)
+ {
+ TakeFrame(1, frameInput);
+ }
- ///
- /// 往前推进指定帧数量的Input
- ///
- ///
- public void TakeFrame(int addFrame, UInt64 frameInput)
- {
- if (addFrame < 0)
- {
-
- }
- mCurrFrame += addFrame;
- if (mCurrInput == frameInput)
- return;
- mCurrInput = frameInput;
+ ///
+ /// 往前推进指定帧数量的Input
+ ///
+ ///
+ public void TakeFrame(int addFrame, UInt64 frameInput)
+ {
+ if (addFrame < 0)
+ {
- wirteStep.FrameStartID = mCurrFrame;
- wirteStep.InPut = mCurrInput;
- dbgList.Add($"{mCurrFrame} | {mCurrInput}");
+ }
+ mCurrFrame += addFrame;
+ if (mCurrInput == frameInput)
+ return;
+ mCurrInput = frameInput;
- switch (mFormat)
- {
- case ReplayData.ReplayFormat.FM32IP64:
- mBinaryWriter.Write(wirteStep.FrameStartID);
- mBinaryWriter.Write(wirteStep.InPut);
- break;
- case ReplayData.ReplayFormat.FM32IP32:
- mBinaryWriter.Write(BitConverter.GetBytes(wirteStep.All64Data), 0, 4 + 4);
- break;
- case ReplayData.ReplayFormat.FM32IP16:
- mBinaryWriter.Write(BitConverter.GetBytes(wirteStep.All64Data), 0, 4 + 2);
- break;
- case ReplayData.ReplayFormat.FM32IPBYTE:
- mBinaryWriter.Write(BitConverter.GetBytes(wirteStep.All64Data), 0, 4 + 1);
- break;
- }
- }
+ wirteStep.FrameStartID = mCurrFrame;
+ wirteStep.InPut = mCurrInput;
+ dbgList.Add($"{mCurrFrame} | {mCurrInput}");
- public void SaveData(string path, bool bWithDump = false, string dumppath = null)
- {
- ReplayData.GetStringByteData(mTitle, out byte[] titleData, out int titleLenghtWithEnd, TexEncoding);
- ReplayData.GetStringByteData(mNote, out byte[] noteData, out int noteLenghtWithEnd, TexEncoding);
+ switch (mFormat)
+ {
+ case ReplayData.ReplayFormat.FM32IP64:
+ mBinaryWriter.Write(wirteStep.FrameStartID);
+ mBinaryWriter.Write(wirteStep.InPut);
+ break;
+ case ReplayData.ReplayFormat.FM32IP32:
+ mBinaryWriter.Write(BitConverter.GetBytes(wirteStep.All64Data), 0, 4 + 4);
+ break;
+ case ReplayData.ReplayFormat.FM32IP16:
+ mBinaryWriter.Write(BitConverter.GetBytes(wirteStep.All64Data), 0, 4 + 2);
+ break;
+ case ReplayData.ReplayFormat.FM32IPBYTE:
+ mBinaryWriter.Write(BitConverter.GetBytes(wirteStep.All64Data), 0, 4 + 1);
+ break;
+ }
+ }
- ReplayHandler handler = new ReplayHandler();
- handler.Format = (int)this.mFormat;
- handler.DataOffset = ReplayData.HandlerLenght;
- handler.CreateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
- handler.AllFrame = wirteStep.FrameStartID;
- handler.SingleLenght = mSingleDataLenght;
+ public void SaveData(string path, bool bWithDump = false, string dumppath = null)
+ {
+ byte[] titleData; int titleLenghtWithEnd;
+ ReplayData.GetStringByteData(mTitle, out titleData, out titleLenghtWithEnd, TexEncoding);
+ byte[] noteData; int noteLenghtWithEnd;
+ ReplayData.GetStringByteData(mNote, out noteData, out noteLenghtWithEnd, TexEncoding);
- using (FileStream fs = new FileStream(path, FileMode.Create))
- {
- using (BinaryWriter bw = new BinaryWriter(fs))
- {
- //写入Handler
- bw.Write(ReplayData.GetHandlerData(handler));
- //写入Data
- bw.Write(mStream.ToArray());
- }
- }
+ ReplayHandler handler = new ReplayHandler();
+ handler.Format = (int)this.mFormat;
+ handler.DataOffset = ReplayData.HandlerLenght;
+ handler.CreateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+ handler.AllFrame = wirteStep.FrameStartID;
+ handler.SingleLenght = mSingleDataLenght;
- if (bWithDump)
- {
- List temp = new List();
- temp.Add($"Format => {handler.Format}");
- temp.Add($"DataOffset => {handler.DataOffset}");
- temp.Add($"CreateTime => {handler.CreateTime}");
- temp.Add($"AllFrame => {handler.AllFrame}");
- temp.Add($"SingleLenght => {handler.SingleLenght}");
- dbgList.InsertRange(0,temp);
- File.WriteAllLines(dumppath, dbgList);
- }
- }
+ using (FileStream fs = new FileStream(path, FileMode.Create))
+ {
+ using (BinaryWriter bw = new BinaryWriter(fs))
+ {
+ //写入Handler
+ bw.Write(ReplayData.GetHandlerData(handler));
+ //写入Data
+ bw.Write(mStream.ToArray());
+ }
+ }
- public void Dispose()
- {
- mStream.Dispose();
- mBinaryWriter.Dispose();
- //TODO
- }
+ if (bWithDump)
+ {
+ List temp = new List();
+ temp.Add($"Format => {handler.Format}");
+ temp.Add($"DataOffset => {handler.DataOffset}");
+ temp.Add($"CreateTime => {handler.CreateTime}");
+ temp.Add($"AllFrame => {handler.AllFrame}");
+ temp.Add($"SingleLenght => {handler.SingleLenght}");
+ dbgList.InsertRange(0, temp);
+ File.WriteAllLines(dumppath, dbgList);
+ }
+ }
- }
+ public void Dispose()
+ {
+ mStream.Dispose();
+ mBinaryWriter.Dispose();
+ //TODO
+ }
+
+ }
}