84 lines
2.5 KiB
C#
84 lines
2.5 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.Immutable;
|
||
using System.IO;
|
||
|
||
namespace AnotherReplayReader.ReplayFile
|
||
{
|
||
public enum CommandArgumentType
|
||
{
|
||
Int32 = 0,
|
||
Float32 = 1,
|
||
Bool = 2,
|
||
AssetId = 3,
|
||
ObjectId = 4,
|
||
ObjectId_2 = 5,
|
||
UInt32 = 6,
|
||
Vector3 = 7,
|
||
UInt32_2 = 8,
|
||
UInt16 = 9,
|
||
AsciiString = 10,
|
||
UnicodeString = 11,
|
||
}
|
||
|
||
public record struct CommandArgumentEntry(CommandArgumentType Type, object Value, int Count);
|
||
public record struct Vector3(float X, float Y, float Z)
|
||
{
|
||
public override readonly string ToString() => $"(X={Math.Round(X)},Y={Math.Round(Y)},Z={Math.Round(Z)})";
|
||
}
|
||
public record struct AssetId(uint TypeId, uint InstanceId)
|
||
{
|
||
public override readonly string ToString() => $"(TypeId={TypeId:X},InstanceId={InstanceId:X})";
|
||
}
|
||
|
||
public sealed class CommandChunk
|
||
{
|
||
public int CommandId { get; private set; }
|
||
public int PlayerIndex { get; private set; }
|
||
public ImmutableArray<CommandArgumentEntry> Data { get; private set; }
|
||
|
||
public static List<CommandChunk> Parse(ReplayChunk chunk)
|
||
{
|
||
if (chunk.Type != 1)
|
||
{
|
||
throw new NotImplementedException();
|
||
}
|
||
|
||
using var reader = chunk.GetReader();
|
||
if (reader.ReadByte() != 1)
|
||
{
|
||
throw new InvalidDataException("Payload first byte not 1");
|
||
}
|
||
|
||
var list = new List<CommandChunk>();
|
||
var numberOfCommands = reader.ReadInt32();
|
||
for (var i = 0; i < numberOfCommands; ++i)
|
||
{
|
||
var commandIdAndPlayerId = reader.ReadUInt16();
|
||
var commandId = commandIdAndPlayerId & 0x7FF;
|
||
var playerId = commandIdAndPlayerId >> 11;
|
||
var data = reader.ReadCommandData();
|
||
list.Add(new CommandChunk
|
||
{
|
||
CommandId = commandId,
|
||
PlayerIndex = playerId,
|
||
Data = data.ToImmutableArray(),
|
||
});
|
||
}
|
||
|
||
if (reader.BaseStream.Position != reader.BaseStream.Length)
|
||
{
|
||
throw new InvalidDataException("Payload not fully parsed");
|
||
}
|
||
|
||
return list;
|
||
}
|
||
|
||
public override string ToString()
|
||
{
|
||
return $"[玩家 {PlayerIndex},{RA3Commands.GetCommandName(CommandId)}]";
|
||
}
|
||
}
|
||
|
||
}
|