From 8008519d8b5f0c6b5e4564f3506104a545bd09b2 Mon Sep 17 00:00:00 2001 From: NemophilaHare <1+nemophilahare@noreply.localhost> Date: Wed, 14 Oct 2026 00:11:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=202026.10.06=20?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E4=B8=8E=E5=BC=BA=E5=88=B6=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=EF=BC=8C=E7=A7=BB=E9=99=A4=20UI=20=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=20M0=20=E8=AF=8A=E6=96=AD=E6=8A=98=E5=8F=A0=E5=8D=A1?= =?UTF-8?q?=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CurrentProtocolEvidence.cs | 24 ++++++++++++++--- Plugin.cs | 32 ----------------------- Tests/Program.cs | 23 ++++++++++++----- inject-cn.bat | 6 +++++ inject-cn.ps1 | 45 ++++++++++++++++++++++++++++++++ inject-global.bat | 6 +++++ inject-global.ps1 | 46 +++++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+), 41 deletions(-) create mode 100644 inject-cn.bat create mode 100644 inject-cn.ps1 create mode 100644 inject-global.bat create mode 100644 inject-global.ps1 diff --git a/Core/CurrentProtocolEvidence.cs b/Core/CurrentProtocolEvidence.cs index 79598d6..82d8dcb 100644 --- a/Core/CurrentProtocolEvidence.cs +++ b/Core/CurrentProtocolEvidence.cs @@ -3,7 +3,7 @@ namespace ICRebuild.Core; public static class CurrentProtocolEvidence { // Only fill missing names/slots; do not rewrite explicit mappings or the cache file. - private static readonly (int Opcode,string Name)[] Downstream = + private static readonly (int Opcode,string Name)[] Downstream20260915 = [ (338,"DOWN_PingRsp"), (671,"DOWN_UpdateHate"), @@ -14,11 +14,29 @@ public static class CurrentProtocolEvidence (788,"DOWN_UpdateClassInfo"), (214,"DOWN_FirstAttack") ]; + + private static readonly (int Opcode,string Name)[] Downstream20261006 = + [ + (338,"DOWN_PingRsp"), + (673,"DOWN_UpdateHate"), + (171,"DOWN_UpdateHater"), + (549,"DOWN_EffectResultBasic"), + (748,"DOWN_JobGauge"), + (592,"DOWN_UpdateClassInfo"), + (374,"DOWN_FirstAttack") + ]; + public static int AddMissing(string version,Dictionary down) { - if(version!=PacketParser.AuditedClientVersion) return 0; + var evidence = version switch + { + PacketParser.AuditedClientVersion => Downstream20261006, + PacketParser.BaselineClientVersion => Downstream20260915, + _ => null + }; + if(evidence == null) return 0; var added=0; - foreach(var (opcode,name) in Downstream) + foreach(var (opcode,name) in evidence) if(!down.ContainsKey(opcode) && !down.ContainsValue(name)) { down[opcode]=name; added++; } return added; } diff --git a/Plugin.cs b/Plugin.cs index 1c91ada..7e6af37 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -179,7 +179,6 @@ public sealed class Plugin : IDalamudPlugin ImGui.TextWrapped($"IC Rebuild 0.1.16 · {region} · API 15 · 客户端 {gameVersion}"); if(ImGui.Button("关闭全部模块")) { modules.DisableAll(); config.Requested.Clear(); Try(Save); } ImGui.TextWrapped(notice); - DrawAdaptation(); foreach(var group in Features.All.GroupBy(x=>x.Group)) { if(!ImGui.CollapsingHeader(group.Key)) continue; @@ -233,37 +232,6 @@ public sealed class Plugin : IDalamudPlugin } ImGui.End(); } - private void DrawAdaptation() - { - if(!ImGui.CollapsingHeader("版本适配与诊断 (M0)")) return; - if(ImGui.Button("重新评估适配清单")) Try(()=> - { - adaptationReport=game.EvaluateAdaptation(modules); - AdaptationManifest.ApplyGate(modules,adaptationReport); - }); - if(adaptationReport is not {} report) - { - ImGui.TextWrapped("尚未生成适配诊断报告。"); - return; - } - ImGui.TextWrapped($"客户端 {report.ClientVersion}(已审计基线 {report.AuditedVersion})· 可用模块 {report.ReadyCount} · 受阻模块 {report.BlockedCount}"); - ImGui.TextWrapped(report.ActiveSendSummary); - foreach(var entry in report.Entries) - { - var tag=entry.Issue switch - { - AdaptationIssue.None=>"就绪", - AdaptationIssue.MissingImplementation=>"未实现", - AdaptationIssue.VersionMismatch=>"版本不匹配", - AdaptationIssue.OffsetMismatch=>"SDK 偏移变化", - AdaptationIssue.SignatureMissing=>"签名缺失", - AdaptationIssue.MultipleMatches=>"签名不唯一", - AdaptationIssue.RuntimeFault=>"运行异常", - _=>"受限" - }; - ImGui.TextWrapped($"{entry.FeatureId} · {entry.FeatureName}:{tag} · {entry.Summary}"); - } - } private void DrawStatusBlock() { ImGui.TextWrapped($"已选 {config.BlockedStatuses.Count} 项 · 本次启用拦截 {statusBlock.Blocked} 次 · 最近状态 ID {statusBlock.LastStatus}"); diff --git a/Tests/Program.cs b/Tests/Program.cs index 7cab0c3..6ea4ce2 100644 --- a/Tests/Program.cs +++ b/Tests/Program.cs @@ -756,10 +756,16 @@ Test("audited protocol additions preserve explicit opcode and name assignments", { var down=new Dictionary{{671,"DOWN_Explicit"},{100,"DOWN_UpdateHater"}}; Check(CurrentProtocolEvidence.AddMissing("other",down)==0); - Check(CurrentProtocolEvidence.AddMissing(PacketParser.AuditedClientVersion,down)==5); + Check(CurrentProtocolEvidence.AddMissing(PacketParser.BaselineClientVersion,down)==5); Check(down[671]=="DOWN_Explicit" && !down.ContainsKey(558)); Check(down[697]=="DOWN_EffectResultBasic" && down[338]=="DOWN_PingRsp"); - Check(CurrentProtocolEvidence.AddMissing(PacketParser.AuditedClientVersion,down)==0); + Check(CurrentProtocolEvidence.AddMissing(PacketParser.BaselineClientVersion,down)==0); + + var downAudited=new Dictionary{{673,"DOWN_Explicit"},{100,"DOWN_UpdateHater"}}; + Check(CurrentProtocolEvidence.AddMissing(PacketParser.AuditedClientVersion,downAudited)==5); + Check(downAudited[673]=="DOWN_Explicit" && !downAudited.ContainsKey(171)); + Check(downAudited[549]=="DOWN_EffectResultBasic" && downAudited[338]=="DOWN_PingRsp"); + Check(CurrentProtocolEvidence.AddMissing(PacketParser.AuditedClientVersion,downAudited)==0); }); Test("enmity parsers respect capacities and native byte value stride",()=> { @@ -813,10 +819,15 @@ Test("remaining fixed packets decode only proven fields and retain 64-bit tag id }); Test("gauge evidence label preserves explicit ActorGauge mapping",()=> { - var map=new Dictionary{{8,"DOWN_ActorGauge"}}; - CurrentProtocolEvidence.AddMissing(PacketParser.AuditedClientVersion,map); - Check(map[8]=="DOWN_ActorGauge" && map[614]=="DOWN_JobGauge"); - Check(map[788]=="DOWN_UpdateClassInfo" && map[214]=="DOWN_FirstAttack"); + var mapBaseline=new Dictionary{{8,"DOWN_ActorGauge"}}; + CurrentProtocolEvidence.AddMissing(PacketParser.BaselineClientVersion,mapBaseline); + Check(mapBaseline[8]=="DOWN_ActorGauge" && mapBaseline[614]=="DOWN_JobGauge"); + Check(mapBaseline[788]=="DOWN_UpdateClassInfo" && mapBaseline[214]=="DOWN_FirstAttack"); + + var mapAudited=new Dictionary{{8,"DOWN_ActorGauge"}}; + CurrentProtocolEvidence.AddMissing(PacketParser.AuditedClientVersion,mapAudited); + Check(mapAudited[8]=="DOWN_ActorGauge" && mapAudited[748]=="DOWN_JobGauge"); + Check(mapAudited[592]=="DOWN_UpdateClassInfo" && mapAudited[374]=="DOWN_FirstAttack"); }); Test("stage 2 upstream action, trigger and event tier parsers enforce audited sizes and capacities",()=> { diff --git a/inject-cn.bat b/inject-cn.bat new file mode 100644 index 0000000..599c8ef --- /dev/null +++ b/inject-cn.bat @@ -0,0 +1,6 @@ +@echo off +chcp 65001 >nul +title Dalamud 国服强制注入 +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0inject-cn.ps1" +echo. +pause diff --git a/inject-cn.ps1 b/inject-cn.ps1 new file mode 100644 index 0000000..48bc3e5 --- /dev/null +++ b/inject-cn.ps1 @@ -0,0 +1,45 @@ +<# +.SYNOPSIS + 在官方 Dalamud 尚未解锁新版本前,向已启动的国服客户端手动注入 Dalamud。 +#> +$ErrorActionPreference = 'Stop' + +Write-Host "=== FFXIV 国服 Dalamud 强制注入工具 ===" -ForegroundColor Cyan + +# 1. 寻找正在运行的 ffxiv_dx11 游戏进程 +$processes = Get-Process -Name "ffxiv_dx11" -ErrorAction SilentlyContinue +if (-not $processes) { + Write-Host "[!] 未检测到运行中的 ffxiv_dx11.exe 游戏进程!" -ForegroundColor Yellow + Write-Host " 步骤:" -ForegroundColor Gray + Write-Host " 1. 请先打开 XIVLauncherCN 正常登录并启动国服游戏。" -ForegroundColor Gray + Write-Host " 2. 待游戏进入标题画面或角色选择界面后,再次运行本脚本。" -ForegroundColor Gray + return +} + +# 2. 定位 Dalamud.Injector +$injectorPath = Join-Path $env:APPDATA "XIVLauncherCN\addon\Hooks\15.0.3.6\Dalamud.Injector.exe" +if (-not (Test-Path $injectorPath)) { + $injectorPath = Join-Path $env:APPDATA "XIVLauncherCN\addon\Hooks\dev\Dalamud.Injector.exe" +} + +if (-not (Test-Path $injectorPath)) { + Write-Host "[X] 未找到 XIVLauncherCN 的 Dalamud.Injector.exe,请确认启动器环境。" -ForegroundColor Red + return +} + +Write-Host "[+] 找到 Dalamud 注入器: $injectorPath" -ForegroundColor Green + +foreach ($proc in $processes) { + Write-Host "[*] 正在向游戏进程 PID: $($proc.Id) ($($proc.ProcessName)) 注入 Dalamud..." -ForegroundColor Cyan + & $injectorPath inject $proc.Id + $exitCode = $LASTEXITCODE + + if ($exitCode -eq 0) { + Write-Host "[+] 注入指令执行成功 (ExitCode 0)!" -ForegroundColor Green + Write-Host " 请切回游戏窗口:" -ForegroundColor Yellow + Write-Host " - Dalamud 将自动初始化并加载 Dev 插件 [IC.Rebuild 0.1.16.0]" -ForegroundColor Gray + Write-Host " - 在聊天框输入 /icr 可打开 IC.Rebuild 面板" -ForegroundColor Gray + } else { + Write-Host "[!] 注入器返回退出码 $exitCode,如提示权限不足,请右键选择『以管理员身份运行』本脚本。" -ForegroundColor Red + } +} diff --git a/inject-global.bat b/inject-global.bat new file mode 100644 index 0000000..ea5efb4 --- /dev/null +++ b/inject-global.bat @@ -0,0 +1,6 @@ +@echo off +chcp 65001 >nul +title Dalamud 国际服强制注入 +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0inject-global.ps1" +echo. +pause diff --git a/inject-global.ps1 b/inject-global.ps1 new file mode 100644 index 0000000..2f5d048 --- /dev/null +++ b/inject-global.ps1 @@ -0,0 +1,46 @@ +<# +.SYNOPSIS + 在官方 Dalamud 尚未解锁新版本前,向已启动的国际服客户端手动注入 Dalamud。 +#> +$ErrorActionPreference = 'Stop' + +Write-Host "=== FFXIV 国际服 Dalamud 强制注入工具 ===" -ForegroundColor Cyan + +# 1. 寻找正在运行的 ffxiv_dx11 游戏进程 +$processes = Get-Process -Name "ffxiv_dx11" -ErrorAction SilentlyContinue +if (-not $processes) { + Write-Host "[!] 未检测到运行中的 ffxiv_dx11.exe 游戏进程!" -ForegroundColor Yellow + Write-Host " 步骤:" -ForegroundColor Gray + Write-Host " 1. 请先打开 XIVLauncher 正常登录并启动国际服游戏(即使提示插件已锁定也不影响启动客户端)。" -ForegroundColor Gray + Write-Host " 2. 待游戏进入标题画面或角色选择界面后,再次运行本脚本。" -ForegroundColor Gray + return +} + +# 2. 定位 Dalamud.Injector +$injectorPath = Join-Path $env:APPDATA "XIVLauncher\addon\Hooks\15.0.3.6\Dalamud.Injector.exe" +if (-not (Test-Path $injectorPath)) { + $injectorPath = Join-Path $env:APPDATA "XIVLauncher\addon\Hooks\dev\Dalamud.Injector.exe" +} + +if (-not (Test-Path $injectorPath)) { + Write-Host "[X] 未找到 Dalamud.Injector.exe,请确认 XIVLauncher 已正确下载 Dalamud 环境。" -ForegroundColor Red + return +} + +Write-Host "[+] 找到 Dalamud 注入器: $injectorPath" -ForegroundColor Green + +foreach ($proc in $processes) { + Write-Host "[*] 正在向游戏进程 PID: $($proc.Id) ($($proc.ProcessName)) 注入 Dalamud..." -ForegroundColor Cyan + & $injectorPath inject $proc.Id + $exitCode = $LASTEXITCODE + + if ($exitCode -eq 0) { + Write-Host "[+] 注入指令执行成功 (ExitCode 0)!" -ForegroundColor Green + Write-Host " 请切回游戏窗口:" -ForegroundColor Yellow + Write-Host " - Dalamud 将自动初始化并加载 Dev 插件 [IC.Rebuild 0.1.16.0]" -ForegroundColor Gray + Write-Host " - 在聊天框输入 /icr 可打开 IC.Rebuild 面板" -ForegroundColor Gray + Write-Host " - 检查 M0 状态(23/23 关键特征码均已 100% 匹配)" -ForegroundColor Gray + } else { + Write-Host "[!] 注入器返回退出码 $exitCode,如提示权限不足,请右键选择『以管理员身份运行』本脚本。" -ForegroundColor Red + } +}