namespace ICRebuild.Core; public enum AdaptationIssue { None, MissingImplementation, VersionMismatch, OffsetMismatch, SignatureMissing, MultipleMatches, RuntimeFault } public sealed record SignatureRequirement(string Name, string Signature, string AuditedRva, bool RequireUnique = true); public sealed record ModuleAdaptationSpec( int FeatureId, string FeatureName, bool VersionLocked, bool RequiresSdkOffsets, string Evidence, SignatureRequirement[] Signatures); public sealed record ModuleAdaptationEntry( int FeatureId, string FeatureName, bool VersionLocked, AdaptationIssue Issue, Adaptation AdaptationState, string Summary, string Evidence, string[] FailedSignatures); public sealed record AdaptationReport( string ClientVersion, string AuditedVersion, bool VersionMatches, bool ActiveSendReady, string ActiveSendSummary, ModuleAdaptationEntry[] Entries) { public int ReadyCount => Entries.Count(e => e.Issue == AdaptationIssue.None); public int BlockedCount => Entries.Count(e => e.Issue != AdaptationIssue.None); } public static class AdaptationManifest { public const string AuditedVersion = PacketParser.AuditedClientVersion; public const string BaselineVersion = PacketParser.BaselineClientVersion; public static bool IsAuditedVersion(string? version) => PacketParser.IsAuditedVersion(version); public const string ActiveSendReceiverSignature = "48 83 EC 38 48 8B 89 70 0A 00 00 48 85 C9 74 0F C6 44 24 20 00 E8 ?? ?? ?? ?? 48 83 C4 38 C3 32 C0 48 83 C4 38 C3 CC CC CC CC CC CC CC CC CC CC 48 83 EC 38 48 8B 89 70 0A 00 00"; public const string ActiveSendZoneSignature = "48 83 EC 28 48 8B 89 98 00 00 00 48 85 C9 74 1F 44 89 44 24 30 4C 8D 44 24 30"; public static readonly SignatureRequirement[] ActiveSendSignatures = [ new("ReceiverSendPacket", ActiveSendReceiverSignature, "0x1CFD140"), new("ZoneClientSendPacket", ActiveSendZoneSignature, "0x1D03040") ]; public static readonly ModuleAdaptationSpec[] Specs = [ new(1, "移速调整", false, false, "RVA 0x8D6E40 + 40 项减速状态保护", [new("SpeedHook", "40 57 48 83 EC ?? 48 8B F9 48 8B 49 ?? 48 8B 01 FF 90 ?? ?? ?? ?? 48 85 C0 75", "0x8D6E40")]), new(2, "最大加速度", true, false, "RVA 0x182BB20,偏移 +0x20/+0x3C/+0x44 与 owner +0x3E0 已核对", [new("AccelerationHook", "40 ?? 48 ?? ?? ?? 80 79 ?? ?? 48 ?? ?? 0f 84 ?? ?? ?? ?? 48 89 7c 24 ?? 48 ?? ?? ??", "0x182BB20")]), new(3, "强制移动", false, false, "RVA 0xE16130,Permission ID 14/96/97 已核对", [new("MovePermissionHook", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 54 41 56 41 57 48 83 EC ?? 33 DB 41 8B E9 48 39 1D", "0xE16130")]), new(4, "击退距离调整", false, false, "RVA 0x90BC90,按本地角色地址过滤", [new("AntiKnockHook", "48 ?? ?? 57 48 ?? ?? ?? ?? ?? ?? 0f 29 70 ?? 0f ?? ??", "0x90BC90")]), new(5, "掉落无伤", false, false, "RVA 0x62AF60,移动标志位掩码处理", [new("OnSendFlagHook", "48 89 5c 24 ?? 57 48 ?? ?? ?? 8b ?? 48 ?? ?? 33 ?? e8 ?? ?? ?? ?? 84 ??", "0x62AF60")]), new(6, "无掉落", false, false, "调用点 RVA 0x182F9E4", [new("FallCheckHook", "e8 ?? ?? ?? ?? 8b ?? 85 ?? 0f 88 ?? ?? ?? ?? 48 ?? ?? ?? f3 ?? ?? ?? ?? ?? ?? ??", "0x182F9E4")]), new(7, "魅惑与恐惧移动处理", true, false, "调用点 RVA 0x194AEC3,第 5 参数核实为 float", [new("ForcedWalkHook", "e8 ?? ?? ?? ?? b0 ?? c7 43 ?? ?? ?? ?? ?? eb ??", "0x194AEC3")]), new(8, "状态屏蔽", true, true, "SetStatus RVA 0x8A6BF0 + 本地角色 RVA 0xB37D7A + 偏移 0x23B0/0x78", [ new("StatusSetter", "40 53 56 41 56 48 83 EC 70 45 32 F6 0F 29 74 24 50 41 0F B7 F0 0F 28 F3 48 8B D9 83 FA 3C", "0x8A6BF0"), new("LocalPlayerPtr", "48 8B 1D ?? ?? ?? ?? 48 8B FA 48 85 DB 74 28 48 8B 03 48 8B CB FF 90 78 02 00 00", "0xB37D7A") ]), new(9, "飞天遁地", false, false, "普通移动 RVA 0x62B680 + 战斗移动 RVA 0x62B730", [ new("OnSendNormalMove", "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B F9 41 8B D8", "0x62B680"), new("OnSendCombatMove", "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B F9 41 8B F0", "0x62B730") ]), new(10, "深层迷宫专用模式", false, false, "依赖模块 9 与 EventFramework 深层迷宫实例", []), new(11, "迷宫状态显示", false, false, "EventFramework.GetInstanceContentDeepDungeon", []), new(13, "技能距离调整", false, false, "ActionManager.GetActionRange SDK 入口", []), new(14, "目标圈半径调整", true, false, "ActorRadius RVA 0x175728F + 原生圈 RVA 0x7B5430 + ActionManager 距离入口", [ new("ActorRadius", "e8 ?? ?? ?? ?? f3 ?? ?? ?? 48 ?? ?? ?? ?? f3 ?? ?? ?? ?? f3 ?? ?? ?? f3 ?? ?? ?? ?? f3 0f 11 74 24 ?? ", "0x175728F"), new("NativeTargetRingUpdate", "4C 8B DC 55 57 41 57 49 8D AB ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 85 ?? ?? ?? ?? 80 B9 ?? ?? ?? ?? ?? 4C 8B FA 48 8B F9 0F 85 ?? ?? ?? ?? 48 8B 41 30", "0x7B5430") ]), new(15, "后摇期间可移动", false, false, "RVA 0x8D6F30(首匹配包装入口)", [new("NoBackswing", "48 ?? ?? ?? 48 ?? ?? ?? 45 ?? ?? 33 ?? e8 ?? ?? ?? ?? 84 ?? 74 ?? ", "0x8D6F30", RequireUnique: false)]), new(16, "突进无位移", true, false, "公共位移初始化 RVA 0x1822510,owner +0x3E0 与 ushort Timeline", [new("ActionMovementStart", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 48 8B D9 0F B6 FA 48 81 C1 ?? ?? ?? ?? 4D 8B F1 4D 8B F8 E8 ?? ?? ?? ?? 48 8B B3 ?? ?? ?? ??", "0x1822510")]), new(17, "复唱缩减秒数", false, false, "GetAdjustedRecastTime + 同步 RVA 0x8EF260(GCD 组 57)", [new("SyncRecast", "40 ?? 48 ?? ?? ?? 0f 29 74 24 ?? 41 ?? ?? 0f ?? ?? e8 ?? ?? ?? ??", "0x8EF260")]), new(18, "快速结印", false, false, "依赖模块 17,结印 ActionId 2259/2261/2263/18805..18807", []), new(19, "咏唱缩减秒数", false, false, "GetAdjustedCastTime + 静态地址 RVA 0x104F17 + 更新 RVA 0x8E00A0", [ new("CastStaticAddress", "F3 44 0F 2C C0 BA ?? ?? ?? ?? 48 8B CB E8 ?? ?? ?? ?? F3 44 0F 10 1D", "0x104F17"), new("CastUpdate", "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B F9 0F 29 74 24 ?? 0F B6 49", "0x8E00A0") ]), new(20, "PVP 动画锁上限", false, false, "ActionManager.AnimationLock 帧更新", []), new(27, "坐标移动", false, false, "GameObject.SetPosition", []), new(28, "面向调整", false, false, "GameObject.SetRotation", []), new(29, "目标缩放", false, false, "RVA 0x899720,含原缩放恢复表", [new("SetScale", "F3 0F 11 89 ?? ?? ?? ?? E9 ?? ?? ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC", "0x899720")]), new(36, "网络记录", true, false, "ZoneUp RVA 0x1D718C0 + ZoneDown RVA 0x1D71440 + 共享观察管线", [ new("ZoneUp", "48 89 5C 24 ?? 48 89 74 24 ?? 4C 89 64 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 70", "0x1D718C0"), new("ZoneDown", "48 89 5C 24 18 57 48 83 EC 20 48 83 B9 88 00 00 00 00 48 8B FA 48 8B D9", "0x1D71440") ]), new(37, "包解析与 Opcode 管理", false, false, "离线/实时解析与请求响应关联,不挂接原生 Hook", []) ]; public static AdaptationReport Evaluate( ModuleManager modules, string clientVersion, Func countMatches, bool sdkOffsetsValid = true) { ArgumentNullException.ThrowIfNull(modules); ArgumentNullException.ThrowIfNull(countMatches); var versionMatches = IsAuditedVersion(clientVersion); var entries = new List(Specs.Length); foreach (var spec in Specs) { var status = modules.Status[spec.FeatureId]; if (!status.HasImplementation) { entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.MissingImplementation, status.Adaptation, "缺实现,保持禁用", spec.Evidence, [])); continue; } if (spec.VersionLocked && !versionMatches) { entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.VersionMismatch, Adaptation.Unadapted, $"版本不符:仅核对 {AuditedVersion}(兼容 {BaselineVersion}),当前为 {clientVersion}", spec.Evidence, [])); continue; } if (spec.RequiresSdkOffsets && !sdkOffsetsValid) { entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.OffsetMismatch, Adaptation.Unadapted, "SDK 角色/状态偏移与已核对入口不一致", spec.Evidence, [])); continue; } List missing = []; List multiple = []; foreach (var sig in spec.Signatures) { var matches = countMatches(sig.Signature); if (matches <= 0) missing.Add($"{sig.Name} ({sig.AuditedRva})"); else if (sig.RequireUnique && matches > 1) multiple.Add($"{sig.Name} ({matches} 处匹配)"); } if (missing.Count > 0) { entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.SignatureMissing, Adaptation.Unadapted, $"签名未匹配:{string.Join(", ", missing)}", spec.Evidence, [.. missing])); continue; } if (multiple.Count > 0) { entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.MultipleMatches, Adaptation.Unadapted, $"签名多重匹配,拒绝盲挂:{string.Join(", ", multiple)}", spec.Evidence, [.. multiple])); continue; } if (status.State == ModuleState.Failed) { entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.RuntimeFault, status.Adaptation, $"运行异常:{status.Detail}", spec.Evidence, [])); continue; } var adapt = versionMatches && ValidationCatalog.UserConfirmed.Contains(spec.FeatureId) ? Adaptation.Verified : Adaptation.Testable; var label = adapt == Adaptation.Verified ? "已核对且用户实测有效" : "签名与版本核对通过,待实测"; entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked, AdaptationIssue.None, adapt, label, spec.Evidence, [])); } var (activeSendReady, activeSendSummary) = EvaluateActiveSend(clientVersion, countMatches); return new(clientVersion, AuditedVersion, versionMatches, activeSendReady, activeSendSummary, [.. entries]); } public static (bool Ready, string Summary) EvaluateActiveSend(string clientVersion, Func countMatches) { if (!IsAuditedVersion(clientVersion)) return (false, $"主动发送(M4)已禁用:仅核对已审计版本({AuditedVersion} / {BaselineVersion}),当前为 {clientVersion}"); foreach (var sig in ActiveSendSignatures) { var matches = countMatches(sig.Signature); if (matches <= 0) return (false, $"主动发送(M4)已禁用:签名未匹配 {sig.Name} ({sig.AuditedRva})"); if (sig.RequireUnique && matches > 1) return (false, $"主动发送(M4)已禁用:签名多重匹配 {sig.Name} ({matches})"); } return (true, "主动发送(M4)入口核对通过:ReceiverSendPacket → ZoneClientSendPacket"); } // Applies diagnostic gating without breaking unaffected modules or offline analysis. public static void ApplyGate(ModuleManager modules, AdaptationReport report) { ArgumentNullException.ThrowIfNull(modules); ArgumentNullException.ThrowIfNull(report); foreach (var entry in report.Entries) { if (!modules.Status.TryGetValue(entry.FeatureId, out var status)) continue; status.Adaptation = entry.AdaptationState; if (entry.Issue is AdaptationIssue.VersionMismatch or AdaptationIssue.OffsetMismatch or AdaptationIssue.SignatureMissing or AdaptationIssue.MultipleMatches) { if (modules.IsEnabled(entry.FeatureId)) modules.Disable(entry.FeatureId); modules.Unavailable(entry.FeatureId, entry.Summary); } else if (entry.Issue == AdaptationIssue.None) { modules.ClearUnavailable(entry.FeatureId); } } } }