Files
AnotherReplayReader/Apm/DataRow.cs
T
2026-06-21 14:42:04 +02:00

169 lines
5.7 KiB
C#

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<DataValue> _values;
public DataRow(string name,
IEnumerable<string> 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<DataRow> GetList(ApmPlotter plotter,
ApmPlotterFilterOptions options,
TimeSpan begin,
TimeSpan end,
out int apmRowIndex)
{
// these commands should appear in this order by default
var orderedCommands = new List<int>();
orderedCommands.AddRange(
[
0x1F5, // 选择
0x1F6,
0x1F8,
0x1F9,
0x22A,
0x1FA, // 编队
0x1FB,
0x1FC,
0x207, // 生产/建造
0x208,
0x205,
0x206,
0x209, // 摆放
0x20A, // 出售
0x203, // 升级
0x204,
0x20D, // 右键攻击
0x20E, // 强A
0x20F, // 强A
0x215, // 移动攻击
0x214, // 移动
0x236, // 倒车
0x216, // 碾压
0x22C, // 队形
0x21A, // 停止
0x21B, // 散开
0x24E, // 选择协议
0x1FE, // 释放特殊能力
0x1FF,
0x200,
0x201,
0x232,
0x22E, // 姿态
0x22F, // 计划模式
0x228, // 维修
0x229,
0x202, // 集结点
0x210, // 进驻建筑
0x20C, // 从建筑中撤出
0x248, // 采矿交矿
0x212,
0x24B, // 信标
0x24C,
0x24D,
0x1, // 退出地图
]);
orderedCommands.AddRange(RA3Commands.AutoCommands);
orderedCommands.AddRange(RA3Commands.UnknownCommands);
var dataList = new List<DataRow>
{
new("ID", plotter.PlayersArray.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.PlayersArray.Select(GetStatus)));
}
apmRowIndex = dataList.Count;
// kill-death ratio
if (plotter.Replay.Footer?.TryGetKillDeathRatios() is { } kdRatios)
{
var texts = kdRatios
.Take(plotter.PlayersArray.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.PlayersArray.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;
}
}
}