mirror of
https://github.com/waynebian01/Shigure.git
synced 2026-09-02 22:39:01 +08:00
216 lines
7.6 KiB
C#
216 lines
7.6 KiB
C#
using System.Text.Json.Nodes;
|
||
|
||
namespace Shigure;
|
||
|
||
public sealed class StateBuilder : IRuntimeStateBuilder
|
||
{
|
||
private readonly ConfigService _config;
|
||
|
||
public StateBuilder(ConfigService config)
|
||
{
|
||
_config = config;
|
||
}
|
||
|
||
public GameState Build(
|
||
IReadOnlyDictionary<int, int> rowData,
|
||
IReadOnlyDictionary<int, int> barData,
|
||
IReadOnlyDictionary<int, int>? healAbsorbData = null)
|
||
{
|
||
var classId = rowData.TryGetValue(2, out var cid) ? cid : 0;
|
||
var specId = rowData.TryGetValue(3, out var sid) ? sid : 0;
|
||
var stateConfig = _config.BuildStateConfig(classId, specId);
|
||
var result = new Dictionary<string, object?>();
|
||
healAbsorbData ??= new Dictionary<int, int>();
|
||
|
||
var itemIds = new Dictionary<string, long>(StringComparer.Ordinal);
|
||
foreach (var (key, node) in stateConfig)
|
||
{
|
||
if (key is "group" or "spells" or "auras" || node is not JsonObject field || !field.ContainsKey("step"))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
result[key] = ConvertRawValue(ResolveRaw(field, rowData, barData), JsonHelpers.GetString(JsonHelpers.Get(field, "type")));
|
||
var itemId = JsonHelpers.GetLong(JsonHelpers.Get(field, "itemId"));
|
||
if (itemId is > 0)
|
||
{
|
||
itemIds[key] = itemId.Value;
|
||
}
|
||
}
|
||
|
||
if (itemIds.Count > 0)
|
||
{
|
||
result["$itemIds"] = itemIds;
|
||
}
|
||
|
||
if (JsonHelpers.Get(stateConfig, "spells") is JsonObject spellsConfig)
|
||
{
|
||
result["spells"] = BuildFieldMap(spellsConfig, rowData, barData);
|
||
result["$spellDisplayTypes"] = BuildSpellDisplayTypes(spellsConfig);
|
||
}
|
||
|
||
if (JsonHelpers.Get(stateConfig, "auras") is JsonObject aurasConfig)
|
||
{
|
||
result["auras"] = BuildFieldMap(aurasConfig, rowData, barData);
|
||
}
|
||
|
||
if (JsonHelpers.Get(stateConfig, "group") is JsonObject groupConfig)
|
||
{
|
||
var group = BuildGroup(groupConfig, rowData, barData, healAbsorbData);
|
||
result["group"] = group;
|
||
}
|
||
|
||
return new GameState(result);
|
||
}
|
||
|
||
private static Dictionary<string, object?> BuildFieldMap(
|
||
JsonObject fieldsConfig,
|
||
IReadOnlyDictionary<int, int> rowData,
|
||
IReadOnlyDictionary<int, int> barData)
|
||
{
|
||
var values = new Dictionary<string, object?>();
|
||
foreach (var (fieldName, node) in fieldsConfig)
|
||
{
|
||
if (node is not JsonObject field || !field.ContainsKey("step"))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var value = ConvertRawValue(ResolveRaw(field, rowData, barData), JsonHelpers.GetString(JsonHelpers.Get(field, "type")));
|
||
values[fieldName] = value;
|
||
AddAuraAliases(values, field, value, includeScope: true);
|
||
}
|
||
|
||
return values;
|
||
}
|
||
|
||
private static Dictionary<string, string> BuildSpellDisplayTypes(JsonObject fieldsConfig)
|
||
{
|
||
var values = new Dictionary<string, string>();
|
||
foreach (var (fieldName, node) in fieldsConfig)
|
||
{
|
||
if (node is not JsonObject field)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var displayType = JsonHelpers.GetString(JsonHelpers.Get(field, "displayType"));
|
||
if (!string.IsNullOrWhiteSpace(displayType))
|
||
{
|
||
values[fieldName] = displayType;
|
||
}
|
||
}
|
||
|
||
return values;
|
||
}
|
||
|
||
private static Dictionary<string, IReadOnlyDictionary<string, object?>> BuildGroup(
|
||
JsonObject groupConfig,
|
||
IReadOnlyDictionary<int, int> rowData,
|
||
IReadOnlyDictionary<int, int> barData,
|
||
IReadOnlyDictionary<int, int> healAbsorbData)
|
||
{
|
||
var start = JsonHelpers.GetInt(JsonHelpers.Get(groupConfig, "start")) ?? 26;
|
||
var numParams = JsonHelpers.GetInt(JsonHelpers.Get(groupConfig, "num")) ?? 5;
|
||
var group = new Dictionary<string, IReadOnlyDictionary<string, object?>>();
|
||
|
||
for (var i = 1; i <= 30; i++)
|
||
{
|
||
var baseStep = start + (i - 1) * numParams;
|
||
var sub = new Dictionary<string, object?>();
|
||
foreach (var (fieldName, node) in groupConfig)
|
||
{
|
||
if (fieldName is "start" or "num" || node is not JsonObject field || !field.ContainsKey("step"))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
int? raw;
|
||
var stepNode = JsonHelpers.Get(field, "step");
|
||
if (JsonHelpers.GetString(stepNode) == "bar")
|
||
{
|
||
raw = ResolveRaw(field, rowData, barData);
|
||
}
|
||
else
|
||
{
|
||
var relStep = JsonHelpers.GetInt(stepNode);
|
||
raw = relStep is null
|
||
? null
|
||
: rowData.TryGetValue(baseStep + relStep.Value, out var rawValue) ? rawValue : null;
|
||
}
|
||
|
||
var value = ConvertRawValue(raw, JsonHelpers.GetString(JsonHelpers.Get(field, "type")));
|
||
sub[fieldName] = value;
|
||
AddAuraAliases(sub, field, value, includeScope: false);
|
||
}
|
||
|
||
// 治疗吸收来自网格扫描:白块右侧像素的 B=单位编号,G-1=吸收值。
|
||
// 插件像素里的生命值含吸收盾,这里折算为真实生命:生命值 -= 治疗吸收。
|
||
// 保留 0 和负数,供最低生命值选择器比较治疗吸收后的有效生命值。
|
||
var absorb = healAbsorbData.TryGetValue(i, out var absorbValue) ? absorbValue : 0;
|
||
sub["治疗吸收"] = absorb;
|
||
if (absorb != 0 && sub.TryGetValue("生命值", out var healthObj) && healthObj is int health)
|
||
{
|
||
sub["生命值"] = health - absorb;
|
||
}
|
||
|
||
group[i.ToString()] = sub;
|
||
}
|
||
|
||
return group;
|
||
}
|
||
|
||
private static void AddAuraAliases(
|
||
IDictionary<string, object?> target,
|
||
JsonObject field,
|
||
object? value,
|
||
bool includeScope)
|
||
{
|
||
var canonicalId = JsonHelpers.GetLong(JsonHelpers.Get(field, "spellId"));
|
||
var metric = JsonHelpers.GetString(JsonHelpers.Get(field, "metric"));
|
||
var scope = JsonHelpers.GetString(JsonHelpers.Get(field, "scope"));
|
||
if (canonicalId is null || string.IsNullOrWhiteSpace(metric)
|
||
|| JsonHelpers.Get(field, "spellIds") is not JsonArray aliases)
|
||
{
|
||
return;
|
||
}
|
||
|
||
foreach (var node in aliases)
|
||
{
|
||
var alias = JsonHelpers.GetLong(node);
|
||
if (alias is null || alias == canonicalId)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var key = includeScope
|
||
? $"{scope}.{alias}.{metric}"
|
||
: $"auras.{alias}.{metric}";
|
||
target[key] = value;
|
||
}
|
||
}
|
||
|
||
private static int? ResolveRaw(JsonObject field, IReadOnlyDictionary<int, int> rowData, IReadOnlyDictionary<int, int> barData)
|
||
{
|
||
var stepNode = JsonHelpers.Get(field, "step");
|
||
if (JsonHelpers.GetString(stepNode) == "bar")
|
||
{
|
||
var barIndex = JsonHelpers.GetInt(JsonHelpers.Get(field, "bar"));
|
||
return barIndex is not null && barData.TryGetValue(barIndex.Value, out var barValue) ? barValue : null;
|
||
}
|
||
|
||
var step = JsonHelpers.GetInt(stepNode);
|
||
return step is not null && rowData.TryGetValue(step.Value, out var value) ? value : null;
|
||
}
|
||
|
||
private static object ConvertRawValue(int? raw, string? type)
|
||
{
|
||
return type switch
|
||
{
|
||
"bool" => raw.GetValueOrDefault() != 0,
|
||
"string" => raw?.ToString() ?? string.Empty,
|
||
_ => raw.GetValueOrDefault()
|
||
};
|
||
}
|
||
}
|