完善Replay fixedbug

This commit is contained in:
sin365 2025-01-16 18:31:34 +08:00
parent e31cd7174c
commit 9098ecb797
6 changed files with 336 additions and 148 deletions

11
IReplayReader.cs Normal file
View File

@ -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);
}
}

12
IReplayWriter.cs Normal file
View File

@ -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);
}
}

147
NetReplay.cs Normal file
View File

@ -0,0 +1,147 @@
using System.Collections.Generic;
namespace AxiReplay
{
public class NetReplay
{
/// <summary>
/// 客户端当前帧
/// </summary>
public int mCurrClientFrameIdx = 0;
/// <summary>
/// 服务器远端当前帧
/// </summary>
public int mRemoteFrameIdx { get; private set; }
/// <summary>
/// 服务器远端当前提前量
/// </summary>
public int mRemoteForwardCount { get; private set; }
/// <summary>
/// Remote 2 Client Frame Gap
/// </summary>
public int mDiffFrameCount => mRemoteFrameIdx - mCurrClientFrameIdx;
/// <summary>
/// 网络数据队列
/// </summary>
Queue<ReplayStep> mNetReplayQueue = new Queue<ReplayStep>();
/// <summary>
/// 当前数据
/// </summary>
ReplayStep mCurrReplay;
/// <summary>
/// 下一个数据数据
/// </summary>
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;
}
}
}

View File

@ -4,7 +4,7 @@ using System.Text;
namespace AxiReplay namespace AxiReplay
{ {
[StructLayout(LayoutKind.Explicit,Size = 44)] [StructLayout(LayoutKind.Explicit, Size = 44)]
public struct ReplayHandler public struct ReplayHandler
{ {
[FieldOffset(0)] [FieldOffset(0)]
@ -51,7 +51,7 @@ namespace AxiReplay
FM32IP32, FM32IP32,
FM32IP64, 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); data = encoding.GetBytes(str);
lenghtWithEnd = data.Length + 1; lenghtWithEnd = data.Length + 1;

View File

@ -6,7 +6,7 @@ using static AxiReplay.ReplayData;
namespace AxiReplay namespace AxiReplay
{ {
public class ReplayReader : IDisposable public class ReplayReader : IReplayReader
{ {
public ReplayData.ReplayFormat mFormat { get; private set; } public ReplayData.ReplayFormat mFormat { get; private set; }
public Encoding TexEncoding { get; private set; } public Encoding TexEncoding { get; private set; }
@ -21,10 +21,10 @@ namespace AxiReplay
FileStream mStream; FileStream mStream;
BinaryReader mBinaryReader; BinaryReader mBinaryReader;
int mCurrFrame = -1; int mCurrFrame = 0;
byte[] mNextOutbytes; byte[] mNextOutbytes;
ReplayStep currStep; public ReplayStep currStep;
ReplayStep nextStep; public ReplayStep nextStep;
bool bEnd; bool bEnd;
List<string> dbgList = new List<string>(); List<string> dbgList = new List<string>();
@ -79,11 +79,12 @@ namespace AxiReplay
} }
} }
void UpdateNextFrame(int targetFrame) void UpdateNextFrame(int targetFrame)
{ {
int LastNextFrameStartID = nextStep.FrameStartID;
//如果已经超过 //如果已经超过
while (targetFrame > nextStep.FrameStartID) while (targetFrame >= nextStep.FrameStartID)
{ {
if (nextStep.FrameStartID >= handler.AllFrame) if (nextStep.FrameStartID >= handler.AllFrame)
{ {
@ -117,34 +118,31 @@ namespace AxiReplay
} }
dbgList.Add($"{nextStep.FrameStartID} | {nextStep.InPut}"); dbgList.Add($"{nextStep.FrameStartID} | {nextStep.InPut}");
//如果这次的NextStep1只推进了1帧则跳过交给下一帧判断
if (nextStep.FrameStartID - LastNextFrameStartID == 1)
{
break;
}
targetFrame++; targetFrame++;
} }
} }
int byFrameIdx = 0; int byFrameIdx = 0;
/// <summary>
/// 往前推进帧的,指定帧下标
/// </summary>
public bool NextFramebyFrameIdx(int FrameID,out ReplayStep data)
{
bool res = TakeFrame(FrameID - byFrameIdx, out data);
byFrameIdx = FrameID;
return res;
}
/// <summary> /// <summary>
/// 往前推进1帧的Input(返回是否变化) /// 往前推进1帧的Input(返回是否变化)
/// </summary> /// </summary>
public bool NextFrame(out ReplayStep data) public bool NextFrame(out ReplayStep data)
{ {
return TakeFrame(1,out data); return TakeFrame(1, out data);
} }
/// <summary> /// <summary>
/// 往前推进指定帧数量的Input (返回是否变化) /// 往前推进指定帧数量的Input (返回是否变化)
/// </summary> /// </summary>
/// <param name="addFrame"></param> /// <param name="addFrame"></param>
public bool TakeFrame(int addFrame,out ReplayStep data) public bool TakeFrame(int addFrame, out ReplayStep data)
{ {
bool Changed = false; bool Changed = false;
mCurrFrame += addFrame; mCurrFrame += addFrame;
@ -162,6 +160,23 @@ namespace AxiReplay
return Changed; return Changed;
} }
int lastTest = 0;
/// <summary>
/// 往前推进帧的,指定帧下标
/// </summary>
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() public void Dispose()
{ {
mStream.Dispose(); mStream.Dispose();

View File

@ -5,152 +5,155 @@ using System.Text;
namespace AxiReplay namespace AxiReplay
{ {
public class ReplayWriter : IDisposable public class ReplayWriter : IReplayWriter
{ {
public ReplayData.ReplayFormat mFormat { get; private set; } public ReplayData.ReplayFormat mFormat { get; private set; }
public Encoding TexEncoding { get; private set; } public Encoding TexEncoding { get; private set; }
ReplayHandler handler; ReplayHandler handler;
string mTitle; string mTitle;
string mNote; string mNote;
int mAllFrame; int mAllFrame;
int mAllTime; int mAllTime;
long mData; long mData;
int mSingleInputLenght; int mSingleInputLenght;
int mSingleDataLenght; int mSingleDataLenght;
MemoryStream mStream; MemoryStream mStream;
BinaryWriter mBinaryWriter; BinaryWriter mBinaryWriter;
int mCurrFrame; int mCurrFrame;
UInt64 mCurrInput; UInt64 mCurrInput;
ReplayStep wirteStep; ReplayStep wirteStep;
List<string> dbgList = new List<string>(); List<string> dbgList = new List<string>();
public ReplayWriter(string Title, string Note, ReplayData.ReplayFormat format, Encoding encoding) public ReplayWriter(string Title, string Note, ReplayData.ReplayFormat format, Encoding encoding)
{ {
mTitle = Title; mTitle = Title;
mNote = Note; mNote = Note;
TexEncoding = encoding; TexEncoding = encoding;
mFormat = format; mFormat = format;
switch (mFormat) switch (mFormat)
{ {
case ReplayData.ReplayFormat.FM32IP64: mSingleInputLenght = sizeof(UInt64); break; case ReplayData.ReplayFormat.FM32IP64: mSingleInputLenght = sizeof(UInt64); break;
case ReplayData.ReplayFormat.FM32IP32: mSingleInputLenght = sizeof(UInt32); break; case ReplayData.ReplayFormat.FM32IP32: mSingleInputLenght = sizeof(UInt32); break;
case ReplayData.ReplayFormat.FM32IP16: mSingleInputLenght = sizeof(UInt16); break; case ReplayData.ReplayFormat.FM32IP16: mSingleInputLenght = sizeof(UInt16); break;
case ReplayData.ReplayFormat.FM32IPBYTE: mSingleInputLenght = sizeof(byte); break; case ReplayData.ReplayFormat.FM32IPBYTE: mSingleInputLenght = sizeof(byte); break;
} }
mSingleDataLenght = (sizeof(UInt32)) + mSingleInputLenght; mSingleDataLenght = (sizeof(UInt32)) + mSingleInputLenght;
mStream = new MemoryStream(); mStream = new MemoryStream();
mBinaryWriter = new BinaryWriter(mStream); mBinaryWriter = new BinaryWriter(mStream);
mCurrFrame = -1; //mCurrFrame = -1;
mCurrFrame = 0;
mCurrInput = int.MaxValue; mCurrInput = int.MaxValue;
wirteStep = new ReplayStep(); wirteStep = new ReplayStep();
dbgList.Clear(); dbgList.Clear();
} }
int byFrameIdx = 0; int byFrameIdx = 0;
/// <summary> /// <summary>
/// 往前推进帧的,指定帧下标 /// 往前推进帧的,指定帧下标
/// </summary> /// </summary>
/// <param name="frameInput"></param> /// <param name="frameInput"></param>
public void NextFramebyFrameIdx(int FrameID,UInt64 frameInput) public void NextFramebyFrameIdx(int FrameID, UInt64 frameInput)
{ {
TakeFrame(FrameID - byFrameIdx, frameInput); TakeFrame(FrameID - byFrameIdx, frameInput);
byFrameIdx = FrameID; byFrameIdx = FrameID;
} }
/// <summary> /// <summary>
/// 往前推进1帧的Input /// 往前推进1帧的Input
/// </summary> /// </summary>
/// <param name="frameInput"></param> /// <param name="frameInput"></param>
public void NextFrame(UInt64 frameInput) public void NextFrame(UInt64 frameInput)
{ {
TakeFrame(1, frameInput); TakeFrame(1, frameInput);
} }
/// <summary> /// <summary>
/// 往前推进指定帧数量的Input /// 往前推进指定帧数量的Input
/// </summary> /// </summary>
/// <param name="frameInput"></param> /// <param name="frameInput"></param>
public void TakeFrame(int addFrame, UInt64 frameInput) public void TakeFrame(int addFrame, UInt64 frameInput)
{ {
if (addFrame < 0) if (addFrame < 0)
{ {
}
mCurrFrame += addFrame;
if (mCurrInput == frameInput)
return;
mCurrInput = frameInput;
wirteStep.FrameStartID = mCurrFrame; }
wirteStep.InPut = mCurrInput; mCurrFrame += addFrame;
dbgList.Add($"{mCurrFrame} | {mCurrInput}"); if (mCurrInput == frameInput)
return;
mCurrInput = frameInput;
switch (mFormat) wirteStep.FrameStartID = mCurrFrame;
{ wirteStep.InPut = mCurrInput;
case ReplayData.ReplayFormat.FM32IP64: dbgList.Add($"{mCurrFrame} | {mCurrInput}");
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;
}
}
public void SaveData(string path, bool bWithDump = false, string dumppath = null) switch (mFormat)
{ {
ReplayData.GetStringByteData(mTitle, out byte[] titleData, out int titleLenghtWithEnd, TexEncoding); case ReplayData.ReplayFormat.FM32IP64:
ReplayData.GetStringByteData(mNote, out byte[] noteData, out int noteLenghtWithEnd, TexEncoding); 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(); public void SaveData(string path, bool bWithDump = false, string dumppath = null)
handler.Format = (int)this.mFormat; {
handler.DataOffset = ReplayData.HandlerLenght; byte[] titleData; int titleLenghtWithEnd;
handler.CreateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); ReplayData.GetStringByteData(mTitle, out titleData, out titleLenghtWithEnd, TexEncoding);
handler.AllFrame = wirteStep.FrameStartID; byte[] noteData; int noteLenghtWithEnd;
handler.SingleLenght = mSingleDataLenght; ReplayData.GetStringByteData(mNote, out noteData, out noteLenghtWithEnd, TexEncoding);
using (FileStream fs = new FileStream(path, FileMode.Create)) ReplayHandler handler = new ReplayHandler();
{ handler.Format = (int)this.mFormat;
using (BinaryWriter bw = new BinaryWriter(fs)) handler.DataOffset = ReplayData.HandlerLenght;
{ handler.CreateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
//写入Handler handler.AllFrame = wirteStep.FrameStartID;
bw.Write(ReplayData.GetHandlerData(handler)); handler.SingleLenght = mSingleDataLenght;
//写入Data
bw.Write(mStream.ToArray());
}
}
if (bWithDump) using (FileStream fs = new FileStream(path, FileMode.Create))
{ {
List<string> temp = new List<string>(); using (BinaryWriter bw = new BinaryWriter(fs))
temp.Add($"Format => {handler.Format}"); {
temp.Add($"DataOffset => {handler.DataOffset}"); //写入Handler
temp.Add($"CreateTime => {handler.CreateTime}"); bw.Write(ReplayData.GetHandlerData(handler));
temp.Add($"AllFrame => {handler.AllFrame}"); //写入Data
temp.Add($"SingleLenght => {handler.SingleLenght}"); bw.Write(mStream.ToArray());
dbgList.InsertRange(0,temp); }
File.WriteAllLines(dumppath, dbgList); }
}
}
public void Dispose() if (bWithDump)
{ {
mStream.Dispose(); List<string> temp = new List<string>();
mBinaryWriter.Dispose(); temp.Add($"Format => {handler.Format}");
//TODO 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
}
}
} }