using AnotherReplayReader.ReplayFile; using System; using System.Collections.Generic; using System.Linq; namespace AnotherReplayReader.Apm { internal class DataRow { public const string AverageApmRow = "APM(整局游戏)"; public const string PartialApmRow = "APM(当前时间段)"; public string Name { get; } public bool IsDisabled { get; } public DataValue Player1Value => _values[0]; public DataValue Player2Value => _values[1]; public DataValue Player3Value => _values[2]; public DataValue Player4Value => _values[3]; public DataValue Player5Value => _values[4]; public DataValue Player6Value => _values[5]; private readonly IReadOnlyList _values; public DataRow(string name, IEnumerable values, bool isDisabled = false) { Name = name; IsDisabled = isDisabled; if (values.Count() < 6) { values = values.Concat(new string[6 - values.Count()]); } _values = values.Select(x => new DataValue(x)).ToArray(); } public static List GetList(ApmPlotter plotter, ApmPlotterFilterOptions options, PlayerIdentity identity, TimeSpan begin, TimeSpan end, out int apmRowIndex) { // these commands should appear in this order by default var orderedCommands = new List(); orderedCommands.AddRange(RA3Commands.UnknownCommands); orderedCommands.AddRange(RA3Commands.AutoCommands); orderedCommands.AddRange(new byte[] { 0xF5, 0xF8, 0x2A, 0xFA, 0xFB, 0x07, 0x08, 0x05, 0x06, 0x09, 0x00, 0x0A, 0x03, 0x04, 0x28, 0x29, 0x0D, 0x0E, 0x15, 0x14, 0x36, 0x16, 0x2C, 0x1A, 0x4E, 0xFE, 0xFF, 0x32, 0x2E, 0x2F, 0x4B, 0x4C, 0x02, 0x0C, 0x10, }); var dataList = new List { new("ID", plotter.Players.Select(x => x.PlayerName)) }; var isPartial = begin > TimeSpan.Zero || end <= plotter.ReplayLength; if (isPartial) { string GetStatus(Player player, int i) { if (player.IsComputer) { return "这是 AI"; } if (begin < plotter.StricterPlayerLifes[i]) { return "存活"; } return begin < plotter.PlayerLifes[i] ? "变身天眼帝国,或双手离开键盘" : "可能已离开房间"; } dataList.Add(new("存活状态(推测)", plotter.Players.Select(GetStatus))); } if (plotter.Replay.Type is ReplayType.Lan && identity.IsUsable) { string GetIpAndName(Player player) => player.IsComputer ? "这是 AI" : identity.QueryRealNameAndIP(player.PlayerIp) ?? string.Empty; dataList.Add(new("局域网 IP", plotter.Players.Select(GetIpAndName))); } apmRowIndex = dataList.Count; // kill-death ratio if (plotter.Replay.Footer?.TryGetKillDeathRatios() is { } kdRatios) { var texts = kdRatios .Take(plotter.Players.Length) .Select(x => $"{x:0.##}"); dataList.Add(new("击杀阵亡比(存疑)", texts)); } // get commands var commandCounts = plotter.GetCommandCounts(begin, end); // add commands in the order specified by the list foreach (var command in orderedCommands) { var counts = commandCounts.TryGetValue(command, out var stored) ? stored : new int[plotter.Players.Length]; if (!isPartial || counts.Any(x => x > 0)) { dataList.Add(new(RA3Commands.GetCommandName(command), counts.Select(x => $"{x}"), options.ShouldSkip(command))); } commandCounts.Remove(command); } // add other commands foreach (var commandCount in commandCounts) { dataList.Add(new(RA3Commands.GetCommandName(commandCount.Key), commandCount.Value.Select(x => $"{x}"), options.ShouldSkip(commandCount.Key))); } return dataList; } } }