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 Data { get; private set; } public static List 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(); 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)}]"; } } }