mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Fix crashes on custom faces.
This commit is contained in:
parent
31cbff497f
commit
68552cb48f
2 changed files with 197 additions and 179 deletions
|
|
@ -1,208 +1,223 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Logging;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Penumbra.PlayerWatch;
|
using Penumbra.PlayerWatch;
|
||||||
|
|
||||||
namespace Glamourer.Gui
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
|
internal partial class Interface
|
||||||
{
|
{
|
||||||
internal partial class Interface
|
public const int CharacterScreenIndex = 240;
|
||||||
|
public const int ExamineScreenIndex = 241;
|
||||||
|
public const int FittingRoomIndex = 242;
|
||||||
|
public const int DyePreviewIndex = 243;
|
||||||
|
|
||||||
|
private Character? _player;
|
||||||
|
private string _currentLabel = string.Empty;
|
||||||
|
private string _playerFilter = string.Empty;
|
||||||
|
private string _playerFilterLower = string.Empty;
|
||||||
|
private readonly Dictionary<string, int> _playerNames = new(100);
|
||||||
|
private readonly Dictionary<string, Character?> _gPoseActors = new(CharacterScreenIndex - GPoseObjectId);
|
||||||
|
|
||||||
|
private void DrawPlayerFilter()
|
||||||
{
|
{
|
||||||
public const int CharacterScreenIndex = 240;
|
using var raii = new ImGuiRaii()
|
||||||
public const int ExamineScreenIndex = 241;
|
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||||
public const int FittingRoomIndex = 242;
|
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
|
||||||
public const int DyePreviewIndex = 243;
|
ImGui.SetNextItemWidth(SelectorWidth * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.InputTextWithHint("##playerFilter", "Filter Players...", ref _playerFilter, 32))
|
||||||
|
_playerFilterLower = _playerFilter.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
private Character? _player;
|
private void DrawGPoseSelectable(Character player)
|
||||||
private string _currentLabel = string.Empty;
|
{
|
||||||
private string _playerFilter = string.Empty;
|
var playerName = player.Name.ToString();
|
||||||
private string _playerFilterLower = string.Empty;
|
if (!playerName.Any())
|
||||||
private readonly Dictionary<string, int> _playerNames = new(100);
|
return;
|
||||||
private readonly Dictionary<string, Character?> _gPoseActors = new(CharacterScreenIndex - GPoseObjectId);
|
|
||||||
|
|
||||||
private void DrawPlayerFilter()
|
_gPoseActors[playerName] = null;
|
||||||
|
|
||||||
|
DrawSelectable(player, $"{playerName} (GPose)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLabel(Character player, string playerName, int num)
|
||||||
|
{
|
||||||
|
if (player.ObjectKind == ObjectKind.Player)
|
||||||
|
return num == 1 ? playerName : $"{playerName} #{num}";
|
||||||
|
|
||||||
|
if (player.ModelType() == 0)
|
||||||
|
return num == 1 ? $"{playerName} (NPC)" : $"{playerName} #{num} (NPC)";
|
||||||
|
|
||||||
|
return num == 1 ? $"{playerName} (Monster)" : $"{playerName} #{num} (Monster)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPlayerSelectable(Character player, int idx = 0)
|
||||||
|
{
|
||||||
|
var (playerName, modifiable) = idx switch
|
||||||
{
|
{
|
||||||
using var raii = new ImGuiRaii()
|
CharacterScreenIndex => ("Character Screen Actor", false),
|
||||||
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
ExamineScreenIndex => ("Examine Screen Actor", false),
|
||||||
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
|
FittingRoomIndex => ("Fitting Room Actor", false),
|
||||||
ImGui.SetNextItemWidth(SelectorWidth * ImGui.GetIO().FontGlobalScale);
|
DyePreviewIndex => ("Dye Preview Actor", false),
|
||||||
if (ImGui.InputTextWithHint("##playerFilter", "Filter Players...", ref _playerFilter, 32))
|
_ => (player.Name.ToString(), true),
|
||||||
_playerFilterLower = _playerFilter.ToLowerInvariant();
|
};
|
||||||
|
if (!playerName.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_playerNames.TryGetValue(playerName, out var num))
|
||||||
|
_playerNames[playerName] = ++num;
|
||||||
|
else
|
||||||
|
_playerNames[playerName] = num = 1;
|
||||||
|
|
||||||
|
if (_gPoseActors.ContainsKey(playerName))
|
||||||
|
{
|
||||||
|
_gPoseActors[playerName] = player;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawGPoseSelectable(Character player)
|
var label = GetLabel(player, playerName, num);
|
||||||
{
|
DrawSelectable(player, label, modifiable);
|
||||||
var playerName = player.Name.ToString();
|
}
|
||||||
if (!playerName.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
_gPoseActors[playerName] = null;
|
|
||||||
|
|
||||||
DrawSelectable(player, $"{playerName} (GPose)", true);
|
private void DrawSelectable(Character player, string label, bool modifiable)
|
||||||
}
|
{
|
||||||
|
if (!_playerFilterLower.Any() || label.ToLowerInvariant().Contains(_playerFilterLower))
|
||||||
private static string GetLabel(Character player, string playerName, int num)
|
if (ImGui.Selectable(label, _currentLabel == label))
|
||||||
{
|
|
||||||
if (player.ObjectKind == ObjectKind.Player)
|
|
||||||
return num == 1 ? playerName : $"{playerName} #{num}";
|
|
||||||
|
|
||||||
if (player.ModelType() == 0)
|
|
||||||
return num == 1 ? $"{playerName} (NPC)" : $"{playerName} #{num} (NPC)";
|
|
||||||
|
|
||||||
return num == 1 ? $"{playerName} (Monster)" : $"{playerName} #{num} (Monster)";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawPlayerSelectable(Character player, int idx = 0)
|
|
||||||
{
|
|
||||||
var (playerName, modifiable) = idx switch
|
|
||||||
{
|
{
|
||||||
CharacterScreenIndex => ("Character Screen Actor", false),
|
_currentLabel = label;
|
||||||
ExamineScreenIndex => ("Examine Screen Actor", false),
|
_currentSave.LoadCharacter(player);
|
||||||
FittingRoomIndex => ("Fitting Room Actor", false),
|
_player = player;
|
||||||
DyePreviewIndex => ("Dye Preview Actor", false),
|
_currentSave.WriteProtected = !modifiable;
|
||||||
_ => (player.Name.ToString(), true),
|
|
||||||
};
|
|
||||||
if (!playerName.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_playerNames.TryGetValue(playerName, out var num))
|
|
||||||
_playerNames[playerName] = ++num;
|
|
||||||
else
|
|
||||||
_playerNames[playerName] = num = 1;
|
|
||||||
|
|
||||||
if (_gPoseActors.ContainsKey(playerName))
|
|
||||||
{
|
|
||||||
_gPoseActors[playerName] = player;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var label = GetLabel(player, playerName, num);
|
if (_currentLabel != label)
|
||||||
DrawSelectable(player, label, modifiable);
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
try
|
||||||
private void DrawSelectable(Character player, string label, bool modifiable)
|
|
||||||
{
|
{
|
||||||
if (!_playerFilterLower.Any() || label.ToLowerInvariant().Contains(_playerFilterLower))
|
|
||||||
if (ImGui.Selectable(label, _currentLabel == label))
|
|
||||||
{
|
|
||||||
_currentLabel = label;
|
|
||||||
_currentSave.LoadCharacter(player);
|
|
||||||
_player = player;
|
|
||||||
_currentSave.WriteProtected = !modifiable;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_currentLabel != label)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_currentSave.LoadCharacter(player);
|
_currentSave.LoadCharacter(player);
|
||||||
_player = player;
|
_player = player;
|
||||||
_currentSave.WriteProtected = !modifiable;
|
_currentSave.WriteProtected = !modifiable;
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
private void DrawSelectionButtons()
|
|
||||||
{
|
{
|
||||||
using var raii = new ImGuiRaii()
|
PluginLog.Error($"Could not load character {player.Name}s information:\n{e}");
|
||||||
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
|
||||||
.PushStyle(ImGuiStyleVar.FrameRounding, 0)
|
|
||||||
.PushFont(UiBuilder.IconFont);
|
|
||||||
Character? select = null;
|
|
||||||
var buttonWidth = Vector2.UnitX * SelectorWidth / 2;
|
|
||||||
if (ImGui.Button(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth))
|
|
||||||
select = Dalamud.ClientState.LocalPlayer;
|
|
||||||
raii.PopFonts();
|
|
||||||
ImGuiCustom.HoverTooltip("Select the local player character.");
|
|
||||||
ImGui.SameLine();
|
|
||||||
raii.PushFont(UiBuilder.IconFont);
|
|
||||||
if (_inGPose)
|
|
||||||
{
|
|
||||||
raii.PushStyle(ImGuiStyleVar.Alpha, 0.5f);
|
|
||||||
ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth);
|
|
||||||
raii.PopStyles();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth))
|
|
||||||
select = CharacterFactory.Convert(Dalamud.Targets.Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
raii.PopFonts();
|
|
||||||
ImGuiCustom.HoverTooltip("Select the current target, if it is in the list.");
|
|
||||||
|
|
||||||
if (select == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_player = select;
|
|
||||||
_currentLabel = _player.Name.ToString();
|
|
||||||
_currentSave.LoadCharacter(_player);
|
|
||||||
_currentSave.WriteProtected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawPlayerSelector()
|
|
||||||
{
|
|
||||||
ImGui.BeginGroup();
|
|
||||||
DrawPlayerFilter();
|
|
||||||
if (!ImGui.BeginChild("##playerSelector",
|
|
||||||
new Vector2(SelectorWidth * ImGui.GetIO().FontGlobalScale, -ImGui.GetFrameHeight() - 1), true))
|
|
||||||
{
|
|
||||||
ImGui.EndChild();
|
|
||||||
ImGui.EndGroup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_playerNames.Clear();
|
|
||||||
_gPoseActors.Clear();
|
|
||||||
for (var i = GPoseObjectId; i < GPoseObjectId + 48; ++i)
|
|
||||||
{
|
|
||||||
var player = CharacterFactory.Convert(Dalamud.Objects[i]);
|
|
||||||
if (player == null)
|
|
||||||
break;
|
|
||||||
|
|
||||||
DrawGPoseSelectable(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < GPoseObjectId; ++i)
|
|
||||||
{
|
|
||||||
var player = CharacterFactory.Convert(Dalamud.Objects[i]);
|
|
||||||
if (player != null)
|
|
||||||
DrawPlayerSelectable(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = CharacterScreenIndex; i < Dalamud.Objects.Length; ++i)
|
|
||||||
{
|
|
||||||
var player = CharacterFactory.Convert(Dalamud.Objects[i]);
|
|
||||||
if (player != null)
|
|
||||||
DrawPlayerSelectable(player, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
using (var _ = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
|
|
||||||
{
|
|
||||||
ImGui.EndChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawSelectionButtons();
|
|
||||||
ImGui.EndGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawPlayerTab()
|
|
||||||
{
|
|
||||||
using var raii = new ImGuiRaii();
|
|
||||||
_player = null;
|
|
||||||
if (!raii.Begin(() => ImGui.BeginTabItem("Current Players"), ImGui.EndTabItem))
|
|
||||||
return;
|
|
||||||
|
|
||||||
DrawPlayerSelector();
|
|
||||||
|
|
||||||
if (!_currentLabel.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
DrawActorPanel();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawSelectionButtons()
|
||||||
|
{
|
||||||
|
using var raii = new ImGuiRaii()
|
||||||
|
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||||
|
.PushStyle(ImGuiStyleVar.FrameRounding, 0)
|
||||||
|
.PushFont(UiBuilder.IconFont);
|
||||||
|
Character? select = null;
|
||||||
|
var buttonWidth = Vector2.UnitX * SelectorWidth / 2;
|
||||||
|
if (ImGui.Button(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth))
|
||||||
|
select = Dalamud.ClientState.LocalPlayer;
|
||||||
|
raii.PopFonts();
|
||||||
|
ImGuiCustom.HoverTooltip("Select the local player character.");
|
||||||
|
ImGui.SameLine();
|
||||||
|
raii.PushFont(UiBuilder.IconFont);
|
||||||
|
if (_inGPose)
|
||||||
|
{
|
||||||
|
raii.PushStyle(ImGuiStyleVar.Alpha, 0.5f);
|
||||||
|
ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth);
|
||||||
|
raii.PopStyles();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth))
|
||||||
|
select = CharacterFactory.Convert(Dalamud.Targets.Target);
|
||||||
|
}
|
||||||
|
|
||||||
|
raii.PopFonts();
|
||||||
|
ImGuiCustom.HoverTooltip("Select the current target, if it is in the list.");
|
||||||
|
|
||||||
|
if (select == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_currentSave.LoadCharacter(select);
|
||||||
|
_player = select;
|
||||||
|
_currentLabel = _player.Name.ToString();
|
||||||
|
_currentSave.WriteProtected = false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
PluginLog.Error($"Could not load character {select.Name}s information:\n{e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPlayerSelector()
|
||||||
|
{
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
DrawPlayerFilter();
|
||||||
|
if (!ImGui.BeginChild("##playerSelector",
|
||||||
|
new Vector2(SelectorWidth * ImGui.GetIO().FontGlobalScale, -ImGui.GetFrameHeight() - 1), true))
|
||||||
|
{
|
||||||
|
ImGui.EndChild();
|
||||||
|
ImGui.EndGroup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_playerNames.Clear();
|
||||||
|
_gPoseActors.Clear();
|
||||||
|
for (var i = GPoseObjectId; i < GPoseObjectId + 48; ++i)
|
||||||
|
{
|
||||||
|
var player = CharacterFactory.Convert(Dalamud.Objects[i]);
|
||||||
|
if (player == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DrawGPoseSelectable(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < GPoseObjectId; ++i)
|
||||||
|
{
|
||||||
|
var player = CharacterFactory.Convert(Dalamud.Objects[i]);
|
||||||
|
if (player != null)
|
||||||
|
DrawPlayerSelectable(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = CharacterScreenIndex; i < Dalamud.Objects.Length; ++i)
|
||||||
|
{
|
||||||
|
var player = CharacterFactory.Convert(Dalamud.Objects[i]);
|
||||||
|
if (player != null)
|
||||||
|
DrawPlayerSelectable(player, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using (var _ = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
|
||||||
|
{
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawSelectionButtons();
|
||||||
|
ImGui.EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPlayerTab()
|
||||||
|
{
|
||||||
|
using var raii = new ImGuiRaii();
|
||||||
|
_player = null;
|
||||||
|
if (!raii.Begin(() => ImGui.BeginTabItem("Current Players"), ImGui.EndTabItem))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DrawPlayerSelector();
|
||||||
|
|
||||||
|
if (!_currentLabel.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawActorPanel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,10 +162,13 @@ namespace Glamourer.Gui
|
||||||
var count = set.Count(CustomizationId.FacialFeaturesTattoos);
|
var count = set.Count(CustomizationId.FacialFeaturesTattoos);
|
||||||
using (var _ = ImGuiRaii.NewGroup())
|
using (var _ = ImGuiRaii.NewGroup())
|
||||||
{
|
{
|
||||||
|
var face = set.Race == Race.Hrothgar ? customization.Hairstyle : customization.Face;
|
||||||
|
if (set.Faces.Count <= face)
|
||||||
|
face = 1;
|
||||||
for (var i = 0; i < count; ++i)
|
for (var i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
var enabled = customization.FacialFeature(i);
|
var enabled = customization.FacialFeature(i);
|
||||||
var feature = set.FacialFeature(set.Race == Race.Hrothgar ? customization.Hairstyle : customization.Face, i);
|
var feature = set.FacialFeature(face, i);
|
||||||
var icon = i == count - 1
|
var icon = i == count - 1
|
||||||
? _legacyTattooIcon ?? Glamourer.Customization.GetIcon(feature.IconId)
|
? _legacyTattooIcon ?? Glamourer.Customization.GetIcon(feature.IconId)
|
||||||
: Glamourer.Customization.GetIcon(feature.IconId);
|
: Glamourer.Customization.GetIcon(feature.IconId);
|
||||||
|
|
@ -249,7 +252,7 @@ namespace Glamourer.Gui
|
||||||
var current = set.DataByValue(id, customization[id], out var custom);
|
var current = set.DataByValue(id, customization[id], out var custom);
|
||||||
if (current < 0)
|
if (current < 0)
|
||||||
{
|
{
|
||||||
PluginLog.Warning($"Read invalid customization value {customization[id]} for {id}.");
|
label = $"{label} (Custom #{customization[id]})";
|
||||||
current = 0;
|
current = 0;
|
||||||
custom = set.Data(id, 0);
|
custom = set.Data(id, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue