Fix crashes on custom faces.

This commit is contained in:
Ottermandias 2021-11-16 14:36:39 +01:00
parent 31cbff497f
commit 68552cb48f
2 changed files with 197 additions and 179 deletions

View file

@ -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();
}
} }

View file

@ -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);
} }