基础归档
This commit is contained in:
parent
e758a59ea9
commit
e31cd7174c
7
AxiReplay.csproj
Normal file
7
AxiReplay.csproj
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
101
ReplayData.cs
Normal file
101
ReplayData.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AxiReplay
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Explicit,Size = 44)]
|
||||||
|
public struct ReplayHandler
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public int Format;
|
||||||
|
[FieldOffset(sizeof(int) * 1)]
|
||||||
|
public int RomID;
|
||||||
|
[FieldOffset(sizeof(int) * 2)]
|
||||||
|
public int RomType;
|
||||||
|
[FieldOffset(sizeof(int) * 3)]
|
||||||
|
public int DataOffset;
|
||||||
|
[FieldOffset(sizeof(int) * 4)]
|
||||||
|
public int TitleOffset;
|
||||||
|
[FieldOffset(sizeof(int) * 5)]
|
||||||
|
public int NoteOffset;
|
||||||
|
[FieldOffset(sizeof(int) * 6)]
|
||||||
|
public int AllFrame;
|
||||||
|
[FieldOffset(sizeof(int) * 7)]
|
||||||
|
public int AllTime;
|
||||||
|
[FieldOffset(sizeof(int) * 8)]
|
||||||
|
public int SingleLenght;
|
||||||
|
[FieldOffset(sizeof(int) * 9)]
|
||||||
|
public long CreateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct ReplayStep
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public UInt64 All64Data;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public Int32 FrameStartID;
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public UInt64 InPut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ReplayData
|
||||||
|
{
|
||||||
|
public static int HandlerLenght = sizeof(int) * 9 + sizeof(long);
|
||||||
|
public enum ReplayFormat : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
FM32IPBYTE,
|
||||||
|
FM32IP16,
|
||||||
|
FM32IP32,
|
||||||
|
FM32IP64,
|
||||||
|
}
|
||||||
|
public static void GetStringByteData(string str,out byte[] data,out int lenghtWithEnd,Encoding encoding)
|
||||||
|
{
|
||||||
|
data = encoding.GetBytes(str);
|
||||||
|
lenghtWithEnd = data.Length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetHandlerData(ReplayHandler replayhandler)
|
||||||
|
{
|
||||||
|
int size = Marshal.SizeOf(typeof(ReplayHandler));
|
||||||
|
byte[] arr = new byte[size];
|
||||||
|
|
||||||
|
IntPtr ptr = Marshal.AllocHGlobal(size);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Marshal.StructureToPtr(replayhandler, ptr, false);
|
||||||
|
Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReplayHandler GetReplayHandlerFromData(byte[] data)
|
||||||
|
{
|
||||||
|
if (data == null || data.Length < ReplayData.HandlerLenght)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid data length or null data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr ptr = Marshal.AllocHGlobal(ReplayData.HandlerLenght);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 将byte数组的内容复制到非托管内存中
|
||||||
|
Marshal.Copy(data, 0, ptr, ReplayData.HandlerLenght);
|
||||||
|
// 从非托管内存将内容转换回ReplayHandler结构体
|
||||||
|
return (ReplayHandler)Marshal.PtrToStructure(ptr, typeof(ReplayHandler));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 释放非托管内存
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
ReplayReader.cs
Normal file
173
ReplayReader.cs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using static AxiReplay.ReplayData;
|
||||||
|
|
||||||
|
namespace AxiReplay
|
||||||
|
{
|
||||||
|
public class ReplayReader : 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;
|
||||||
|
FileStream mStream;
|
||||||
|
BinaryReader mBinaryReader;
|
||||||
|
|
||||||
|
int mCurrFrame = -1;
|
||||||
|
byte[] mNextOutbytes;
|
||||||
|
ReplayStep currStep;
|
||||||
|
ReplayStep nextStep;
|
||||||
|
bool bEnd;
|
||||||
|
|
||||||
|
List<string> dbgList = new List<string>();
|
||||||
|
bool bdbg = false;
|
||||||
|
string dumpPath;
|
||||||
|
|
||||||
|
public ReplayReader(string path, bool bWithDump = false, string dumppath = null)
|
||||||
|
{
|
||||||
|
dbgList.Clear();
|
||||||
|
bdbg = bWithDump;
|
||||||
|
dumpPath = dumppath;
|
||||||
|
mStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
|
mBinaryReader = new BinaryReader(mStream);
|
||||||
|
byte[] Outbytes;
|
||||||
|
Outbytes = mBinaryReader.ReadBytes(ReplayData.HandlerLenght);
|
||||||
|
handler = ReplayData.GetReplayHandlerFromData(Outbytes);
|
||||||
|
mFormat = (ReplayFormat)handler.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;
|
||||||
|
}
|
||||||
|
//Frame+Lenght
|
||||||
|
mSingleDataLenght = (sizeof(UInt32)) + mSingleInputLenght;
|
||||||
|
nextStep = new ReplayStep();
|
||||||
|
nextStep.FrameStartID = -1;
|
||||||
|
bEnd = false;
|
||||||
|
|
||||||
|
dbgList.Add($"Format => {handler.Format}");
|
||||||
|
dbgList.Add($"DataOffset => {handler.DataOffset}");
|
||||||
|
dbgList.Add($"CreateTime => {handler.CreateTime}");
|
||||||
|
dbgList.Add($"AllFrame => {handler.AllFrame}");
|
||||||
|
dbgList.Add($"SingleLenght => {handler.SingleLenght}");
|
||||||
|
|
||||||
|
|
||||||
|
mNextOutbytes = new byte[mSingleDataLenght];
|
||||||
|
|
||||||
|
if (bWithDump)
|
||||||
|
{
|
||||||
|
int TestFrameIdx = -1;
|
||||||
|
while (!bEnd)
|
||||||
|
{
|
||||||
|
UpdateNextFrame(TestFrameIdx++);
|
||||||
|
}
|
||||||
|
File.WriteAllLines(dumppath, dbgList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateNextFrame(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateNextFrame(int targetFrame)
|
||||||
|
{
|
||||||
|
//如果已经超过
|
||||||
|
while (targetFrame > nextStep.FrameStartID)
|
||||||
|
{
|
||||||
|
if (nextStep.FrameStartID >= handler.AllFrame)
|
||||||
|
{
|
||||||
|
bEnd = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mBinaryReader.Read(mNextOutbytes, 0, mSingleDataLenght);
|
||||||
|
switch (mFormat)
|
||||||
|
{
|
||||||
|
case ReplayFormat.FM32IP64:
|
||||||
|
{
|
||||||
|
nextStep.FrameStartID = BitConverter.ToInt32(mNextOutbytes, 0);
|
||||||
|
nextStep.InPut = BitConverter.ToUInt64(mNextOutbytes, sizeof(UInt32));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ReplayFormat.FM32IP32:
|
||||||
|
{
|
||||||
|
nextStep.All64Data = BitConverter.ToUInt64(mNextOutbytes, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ReplayFormat.FM32IP16:
|
||||||
|
{
|
||||||
|
nextStep.All64Data = BitConverter.ToUInt64(mNextOutbytes, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ReplayFormat.FM32IPBYTE:
|
||||||
|
{
|
||||||
|
nextStep.All64Data = BitConverter.ToUInt64(mNextOutbytes, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dbgList.Add($"{nextStep.FrameStartID} | {nextStep.InPut}");
|
||||||
|
|
||||||
|
targetFrame++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
/// 往前推进1帧的Input(返回是否变化)
|
||||||
|
/// </summary>
|
||||||
|
public bool NextFrame(out ReplayStep data)
|
||||||
|
{
|
||||||
|
return TakeFrame(1,out data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 往前推进指定帧数量的Input (返回是否变化)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="addFrame"></param>
|
||||||
|
public bool TakeFrame(int addFrame,out ReplayStep data)
|
||||||
|
{
|
||||||
|
bool Changed = false;
|
||||||
|
mCurrFrame += addFrame;
|
||||||
|
if (mCurrFrame >= nextStep.FrameStartID)
|
||||||
|
{
|
||||||
|
Changed = currStep.InPut != nextStep.InPut;
|
||||||
|
currStep = nextStep;
|
||||||
|
data = currStep;
|
||||||
|
UpdateNextFrame(mCurrFrame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = currStep;
|
||||||
|
}
|
||||||
|
return Changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
mStream.Dispose();
|
||||||
|
mBinaryReader.Dispose();
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
156
ReplayWriter.cs
Normal file
156
ReplayWriter.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
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;
|
||||||
|
|
||||||
|
int mCurrFrame;
|
||||||
|
UInt64 mCurrInput;
|
||||||
|
ReplayStep wirteStep;
|
||||||
|
|
||||||
|
List<string> dbgList = new List<string>();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
mCurrFrame = -1;
|
||||||
|
mCurrInput = int.MaxValue;
|
||||||
|
wirteStep = new ReplayStep();
|
||||||
|
|
||||||
|
dbgList.Clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int byFrameIdx = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// 往前推进帧的,指定帧下标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frameInput"></param>
|
||||||
|
public void NextFramebyFrameIdx(int FrameID,UInt64 frameInput)
|
||||||
|
{
|
||||||
|
TakeFrame(FrameID - byFrameIdx, frameInput);
|
||||||
|
byFrameIdx = FrameID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 往前推进1帧的Input
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frameInput"></param>
|
||||||
|
public void NextFrame(UInt64 frameInput)
|
||||||
|
{
|
||||||
|
TakeFrame(1, frameInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 往前推进指定帧数量的Input
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frameInput"></param>
|
||||||
|
public void TakeFrame(int addFrame, UInt64 frameInput)
|
||||||
|
{
|
||||||
|
if (addFrame < 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
mCurrFrame += addFrame;
|
||||||
|
if (mCurrInput == frameInput)
|
||||||
|
return;
|
||||||
|
mCurrInput = frameInput;
|
||||||
|
|
||||||
|
wirteStep.FrameStartID = mCurrFrame;
|
||||||
|
wirteStep.InPut = mCurrInput;
|
||||||
|
dbgList.Add($"{mCurrFrame} | {mCurrInput}");
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bWithDump)
|
||||||
|
{
|
||||||
|
List<string> temp = new List<string>();
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user