基础归档
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