fix(ui): bounds-guard out-of-range list access in pop-out and tabs UI
Two pre-existing upstream defects fixed in v1.0.0: - Ui/Popout.cs PopOutDocked[Idx] now bounds-checks Idx against ChatLogWindow.PopOutDocked.Count before reading or writing. A popout instance can outlive a list resize when AddPopOutsToDraw() rebuilds the docked-state list while a draw frame is in flight, which previously produced an out-of-range crash on tab drop - Ui/SettingsTabs/Tabs.cs guards against an empty worlds list before indexing worlds[selectedWorld]. Empty lists can occur briefly when switching characters or before the datacenter sheet finishes loading — the previous code would crash with an ArgumentOutOfRangeException
This commit is contained in:
@@ -80,7 +80,10 @@ internal class Popout : Window
|
|||||||
if (!Tab.CanResize)
|
if (!Tab.CanResize)
|
||||||
Flags |= ImGuiWindowFlags.NoResize;
|
Flags |= ImGuiWindowFlags.NoResize;
|
||||||
|
|
||||||
if (!ChatLogWindow.PopOutDocked[Idx])
|
// Idx may point past the end if PopOutDocked was resized (e.g., a tab
|
||||||
|
// dropped) between the AddPopOutsToDraw() snapshot and this frame.
|
||||||
|
// Guard the read so we don't index into stale state.
|
||||||
|
if (Idx >= 0 && Idx < ChatLogWindow.PopOutDocked.Count && !ChatLogWindow.PopOutDocked[Idx])
|
||||||
{
|
{
|
||||||
if (Tab.IndependentOpacity)
|
if (Tab.IndependentOpacity)
|
||||||
{
|
{
|
||||||
@@ -195,6 +198,7 @@ internal class Popout : Window
|
|||||||
|
|
||||||
public override void PostDraw()
|
public override void PostDraw()
|
||||||
{
|
{
|
||||||
|
if (Idx >= 0 && Idx < ChatLogWindow.PopOutDocked.Count)
|
||||||
ChatLogWindow.PopOutDocked[Idx] = ImGui.IsWindowDocked();
|
ChatLogWindow.PopOutDocked[Idx] = ImGui.IsWindowDocked();
|
||||||
|
|
||||||
if (Plugin.Config is { OverrideStyle: true, ChosenStyle: not null })
|
if (Plugin.Config is { OverrideStyle: true, ChosenStyle: not null })
|
||||||
|
|||||||
@@ -181,6 +181,16 @@ internal sealed class Tabs : ISettingsTab
|
|||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
// Guard against an empty worlds list — can happen briefly
|
||||||
|
// when switching characters or if the datacenter sheet
|
||||||
|
// has not yet populated. Without the guard the indexed
|
||||||
|
// access into worlds[selectedWorld] would crash.
|
||||||
|
if (worlds.Count == 0)
|
||||||
|
{
|
||||||
|
ImGui.TextDisabled("(no worlds available)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
var selectedWorld = worlds.FindIndex(world => world.RowId == tab.TellTarget.World);
|
var selectedWorld = worlds.FindIndex(world => world.RowId == tab.TellTarget.World);
|
||||||
if (selectedWorld == -1)
|
if (selectedWorld == -1)
|
||||||
selectedWorld = 0;
|
selectedWorld = 0;
|
||||||
@@ -207,6 +217,7 @@ internal sealed class Tabs : ISettingsTab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var target = (Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target) as IPlayerCharacter;
|
var target = (Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target) as IPlayerCharacter;
|
||||||
using (ImRaii.Disabled(target == null))
|
using (ImRaii.Disabled(target == null))
|
||||||
|
|||||||
Reference in New Issue
Block a user