From 7eaa536efbce3be1afb384276cc85f038c34d7f1 Mon Sep 17 00:00:00 2001 From: NemophilaHare <1+nemophilahare@noreply.localhost> Date: Wed, 14 Oct 2026 01:23:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=BF=AB=E6=8D=B7=E9=80=89=E6=8B=A9=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=E4=B8=8EPVP=E5=8A=A8=E7=94=BB=E9=94=81=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E7=8A=B6=E6=80=81=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plugin.cs | 37 +++++++++++++++++++++++++++++++++--- Runtime/StatusBlockModule.cs | 2 +- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Plugin.cs b/Plugin.cs index 52e0297..d5f7144 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -103,7 +103,7 @@ public sealed class Plugin : IDalamudPlugin serviceBar=dtrBar.Get("IC Rebuild · 高度与迷宫"); serviceBar.Shown=false; serviceBar.OnClick=_=>Open(); - commands.AddHandler("/icr",new CommandInfo(Command) { HelpMessage="IC Rebuild 设置。on/off 编号;stop;pos X Y Z;ground 技能ID [target|self];finish [事件ID];retainer;face 弧度;scale 倍率;export [文件名]。" }); + commands.AddHandler("/icr",new CommandInfo(Command) { HelpMessage="IC Rebuild 设置。on/off 编号;stop;pos X Y Z;ground 技能ID [target|self];finish [事件ID];retainer;yes;no;select 索引;face 弧度;scale 倍率;export [文件名]。" }); pi.UiBuilder.Draw+=Draw; pi.UiBuilder.OpenConfigUi+=Open; pi.UiBuilder.OpenMainUi+=Open; framework.Update+=Update; } @@ -212,11 +212,14 @@ public sealed class Plugin : IDalamudPlugin ConfirmYesno(true); break; case "no": ConfirmYesno(false); break; - default: Open(); notice="用法:/icr on|off 编号;stop;pos X Y Z;ground 技能ID [target|self];finish [事件ID];retainer;yes;no"; break; + case "select" or "choose" when args.Length==2: + var optIndex=int.Parse(args[1],CultureInfo.InvariantCulture); + SelectDialogOption(optIndex); break; + default: Open(); notice="用法:/icr on|off 编号;stop;pos X Y Z;ground 技能ID [target|self];finish [事件ID];retainer;yes;no;select 索引"; break; } }); } - private void Draw() + private unsafe void Draw() { if(!open) return; ImGui.SetNextWindowSize(new(790,650),ImGuiCond.FirstUseEver); @@ -273,6 +276,10 @@ public sealed class Plugin : IDalamudPlugin } if(feature.Id==20) { + var pvpState=game.IsPvP ? "是 (生效中)" : "否 (仅PvP区域生效)"; + var mgr=FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance(); + var currentLock=mgr!=null ? mgr->AnimationLock : 0f; + ImGui.Text($"PvP 区域:【{pvpState}】 · 当前动画锁:{currentLock:F3}s"); ImGui.Text("快速预设:"); ImGui.SameLine(); if(ImGui.SmallButton("极限 0.5s")) { config.Values[20]=0.5f; Try(Save); } ImGui.SameLine(); @@ -695,6 +702,30 @@ public sealed class Plugin : IDalamudPlugin } else chat.Print("[IC Rebuild] 当前无可见的 Yes/No 提示框"); } + private unsafe void SelectDialogOption(int index) + { + var mgr=FFXIVClientStructs.FFXIV.Client.UI.RaptureAtkUnitManager.Instance(); + if(mgr==null) return; + var selectString=mgr->GetAddonByName("SelectString",1); + if(selectString!=null && selectString->IsVisible && selectString->IsReady) + { + var val=stackalloc FFXIVClientStructs.FFXIV.Component.GUI.AtkValue[1]; + val[0].SetInt(index); + selectString->FireCallback(1,val,true); + chat.Print($"[IC Rebuild] 已选择【SelectString】第 {index + 1} 项 (索引 {index})"); + return; + } + var selectIconString=mgr->GetAddonByName("SelectIconString",1); + if(selectIconString!=null && selectIconString->IsVisible && selectIconString->IsReady) + { + var val=stackalloc FFXIVClientStructs.FFXIV.Component.GUI.AtkValue[1]; + val[0].SetInt(index); + selectIconString->FireCallback(1,val,true); + chat.Print($"[IC Rebuild] 已选择【SelectIconString】第 {index + 1} 项 (索引 {index})"); + return; + } + chat.Print("[IC Rebuild] 当前无可见的选择列表 (SelectString / SelectIconString)"); + } private unsafe void ProcessRetainerAutomation() { var mgr=FFXIVClientStructs.FFXIV.Client.UI.RaptureAtkUnitManager.Instance(); diff --git a/Runtime/StatusBlockModule.cs b/Runtime/StatusBlockModule.cs index 8e3b2c4..4247ad4 100644 --- a/Runtime/StatusBlockModule.cs +++ b/Runtime/StatusBlockModule.cs @@ -21,7 +21,7 @@ public sealed class StatusBlockModule(GameContext game, Configuration config, Mo public void Register() => modules.Register(8, scope => { if(!StatusBlockPolicy.IsAuditedVersion(game.GameVersion)) - throw new InvalidOperationException($"状态屏蔽仅适配国际服已审计版本,当前为 {game.GameVersion}。"); + throw new InvalidOperationException($"状态屏蔽仅适配已核对客户端(国服/国际服),当前为 {game.GameVersion}。"); if(Marshal.OffsetOf(nameof(BattleChara.StatusManager)).ToInt32() != StatusBlockPolicy.ManagerOffset || Marshal.OffsetOf(nameof(GameObject.EntityId)).ToInt32() != StatusBlockPolicy.EntityIdOffset) throw new InvalidOperationException("当前 SDK 的角色布局与已核对的状态入口不一致。");