Skip to content

Commit

Permalink
Added all pets without a preset size.sizeMap.
Browse files Browse the repository at this point in the history
Each ComboBox now has its own filter.
If HomeWorld or ContentId is know for any given data, it's also matched alongside name in OldParse.
Sort combo options only if there's a minimum of 2 entries.
Center only custom size text in DisplayEntries.
Add Tab state awareness, all praise stateless ImGui.

Ritualistic sacrifice backfired, partial brain damage acquired.
  • Loading branch information
Kurochi51 committed Jul 23, 2024
1 parent 7b8ab80 commit face599
Show file tree
Hide file tree
Showing 8 changed files with 509 additions and 162 deletions.
2 changes: 1 addition & 1 deletion PetScale/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Configuration : IPluginConfiguration
{
public int Version { get; set; } = 0;
public IList<PetStruct> PetData { get; set; } = [];
public int FairySize { get; set; } = 0;
public PetState FairyState { get; set; } = PetState.Off;
public ushort HomeWorld { get; set; } = 0;
public bool UpdateNeeded { get; internal set; }

Expand Down
16 changes: 16 additions & 0 deletions PetScale/Enums/PetEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ public enum PetRow : uint
AutomatonQueen = 18,
// DRK Emo Clone
Esteem = 17,
// Custom SMN pets
Carbuncle = 23,
RubyCarbuncle = 24,
TopazCarbuncle = 25,
EmeraldCarbuncle = 26,
IfritEgi = 27,
TitanEgi = 28,
GarudaEgi = 29,
}

/// <summary>
Expand All @@ -44,6 +52,14 @@ public enum PetModel
AutomatonQueen = 2618,
// DRK Emo Clone
Esteem = 2621,
// Custom SMN pets
Carbuncle = 411,
RubyCarbuncle = 410,
TopazCarbuncle = 412,
EmeraldCarbuncle = 409,
IfritEgi = 415,
TitanEgi = 416,
GarudaEgi = 417,
}

public enum PetSize
Expand Down
7 changes: 5 additions & 2 deletions PetScale/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
[assembly: SuppressMessage("Design", "MA0049:Type name should not match containing namespace", Justification = "...and I took that personally.", Scope = "type", Target = "~T:PetScale.PetScale")]
[assembly: SuppressMessage("Design", "MA0038:Make method static (deprecated, use CA1822 instead)", Justification = "Obsolete", Scope = "member", Target = "~M:PetScale.Helpers.Utilities.SetScale(FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara*,System.Single)")]
[assembly: SuppressMessage("Design", "MA0041:Make property static (deprecated, use CA1822 instead)", Justification = "Obsolete", Scope = "member", Target = "~P:PetScale.PetScale.BattleCharaSpan")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "Not meant for public consumption", Scope = "member", Target = "~P:PetScale.Windows.ConfigWindow.petMap")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "No", Scope = "member", Target = "~P:PetScale.Windows.ConfigWindow.otherPetMap")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "Not meant for public consumption", Scope = "member", Target = "~P:PetScale.Windows.ConfigWindow.presetPetMap")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "No", Scope = "member", Target = "~P:PetScale.Windows.ConfigWindow.customPetMap")]
[assembly: SuppressMessage("Performance", "MA0066:Hash table unfriendly type is used in a hash table", Justification = "None", Scope = "member", Target = "~F:PetScale.PetScale.activePetDictionary")]
[assembly: SuppressMessage("Design", "MA0038:Make method static (deprecated, use CA1822 instead)", Justification = "Obsolete", Scope = "member", Target = "~M:PetScale.Helpers.Utilities.PetVisible(FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara*)~System.Boolean")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "No", Scope = "member", Target = "~P:PetScale.Windows.ConfigWindow.worldMap")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "No", Scope = "member", Target = "~P:PetScale.PetScale.presetPetModelMap")]
[assembly: SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "No", Scope = "member", Target = "~P:PetScale.PetScale.customPetModelMap")]
83 changes: 83 additions & 0 deletions PetScale/Helpers/ImGuiUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Numerics;

using ImGuiNET;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Windowing;
using Dalamud.Interface.ManagedFontAtlas;

namespace PetScale.Helpers;

public static class ImGuiUtils
{
private static bool IsDrawSafe => PetScale.DrawAvailable;

public static float GetStyleWidth()
{
if (!IsDrawSafe)
{
throw new InvalidOperationException($"{nameof(GetStyleWidth)} called outside {nameof(WindowSystem.Draw)} instance");
}
return (ImGui.GetStyle().FramePadding.X * 2) + (ImGui.GetStyle().ItemSpacing.X * 2) + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().ItemInnerSpacing.X;
}

public static void CenterText(string text, float horizontalSpace, int magicNumber = 4)
{
if (!IsDrawSafe)
{
throw new InvalidOperationException($"{nameof(CenterText)} called outside {nameof(WindowSystem.Draw)} instance");
}
// Right now magicNumber is setup to match the amount of columns in the given table that this is used for
// Whether that's actually the apropriate way of getting an accurate center, or I just stumbled upon it
// is between god and me, and I forgot
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ((horizontalSpace - ImGui.CalcTextSize(text).X - (GetStyleWidth() / magicNumber)) / 2));
ImGui.TextUnformatted(text);
}

public static Vector2 IconButtonSize(IFontHandle fontHandle, string icon)
{
if (!IsDrawSafe)
{
throw new InvalidOperationException($"{nameof(IconButtonSize)} called outside {nameof(WindowSystem.Draw)} instance");
}
using (fontHandle.Push())
{
return new Vector2(ImGuiHelpers.GetButtonSize(icon).X, ImGui.GetFrameHeight());
}
}

// widthOffset is a pain in the ass, at 100% you want 0, <100% you want 1 or more, >100% it entirely depends on whether you get a non-repeating divison or not... maybe?
// also this entirely varies for each icon, so good luck aligning everything
public static bool IconButton(IFontHandle fontHandle, string icon, string buttonIDLabel, float widthOffset = 0f)
{
if (!IsDrawSafe)
{
throw new InvalidOperationException($"{nameof(IconButton)} called outside {nameof(WindowSystem.Draw)} instance");
}
using (fontHandle.Push())
{
var cursorScreenPos = ImGui.GetCursorScreenPos();
var frameHeight = ImGui.GetFrameHeight();
var result = ImGui.Button("##" + buttonIDLabel, new Vector2(ImGuiHelpers.GetButtonSize(icon).X, frameHeight));
var pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X + widthOffset,
cursorScreenPos.Y + (frameHeight / 2f) - (ImGui.CalcTextSize(icon).Y / 2f));
ImGui.GetWindowDrawList().AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), icon);

return result;
}
}

public static void CenterCursor(Vector2 windowSize, Vector2? offset = null)
{
if (!IsDrawSafe)
{
throw new InvalidOperationException($"{nameof(CenterCursor)} called outside {nameof(WindowSystem.Draw)} instance");
}
var center = windowSize / 2;
if (offset.HasValue)
{
center -= offset.Value / 2;
}
ImGui.SetCursorPos(center);
}
}
61 changes: 54 additions & 7 deletions PetScale/Helpers/Utilities.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;

using Lumina.Excel;
Expand All @@ -20,6 +21,14 @@ public class Utilities(IDataManager _dataManager, IPluginLog _pluginLog, ClientL
private readonly IPluginLog log = _pluginLog;
private readonly ClientLanguage language = _language;
private ExcelSheet<World>? worldSheet = null;
private ExcelSheet<World>? WorldSheet
{
get
{
worldSheet??= GetSheet<World>(language);
return worldSheet;
}
}

/// <summary>
/// Attempt to retrieve an <see cref="ExcelSheet{T}"/>, optionally in a specific <paramref name="language"/>.
Expand Down Expand Up @@ -59,6 +68,7 @@ public unsafe void SetScale(BattleChara* pet, float scale)
drawObject->Object.Scale.Y = scale;
drawObject->Object.Scale.Z = scale;
}
//log.Debug("Set {a} to size {b}", pet->NameString, scale);
}

private static unsafe DrawState* ActorDrawState(IGameObject actor)
Expand All @@ -73,7 +83,7 @@ public static unsafe void ToggleVisibility(IGameObject actor)
*ActorDrawState(actor) ^= DrawState.Invisibility;
}

public unsafe void CachePlayerList(uint playerEntityId, ushort homeWorld, Queue<(string, ulong)> queue, Span<Pointer<BattleChara>> CharacterSpan)
public unsafe void CachePlayerList(uint playerEntityId, ushort homeWorld, Queue<(string Name, ulong ContentId, ushort HomeWorld)> queue, Span<Pointer<BattleChara>> CharacterSpan)
{
foreach (var chara in CharacterSpan)
{
Expand All @@ -92,7 +102,7 @@ public unsafe void CachePlayerList(uint playerEntityId, ushort homeWorld, Queue<
{
world = "@" + GetHomeWorldName(chara.Value->Character.HomeWorld);
}
queue.Enqueue((chara.Value->Character.NameString + world, chara.Value->ContentId));
queue.Enqueue((chara.Value->Character.NameString + world, chara.Value->ContentId, chara.Value->HomeWorld));
}
}
}
Expand All @@ -116,14 +126,51 @@ public static float GetMinSize(PetModel pet)
};
}

public ushort GetHomeWorldId(string name)
{
ushort id = 0;
if (WorldSheet is null)
{
return id;
}
foreach (var world in WorldSheet.Where(item => item.IsPublic))
{
if (!world.Name.ToDalamudString().TextValue.Equals(name, StringComparison.Ordinal))
{
continue;
}
id = (ushort)world.RowId;
break;
}
return id;
}

public string GetHomeWorldName(ushort id)
{
worldSheet ??= GetSheet<World>(language);
if (worldSheet is not null)
if (WorldSheet is null)
{
var world = worldSheet.GetRow(id);
return world?.Name ?? string.Empty;
return string.Empty;
}
return WorldSheet.GetRow(id)?.Name ?? string.Empty;
}

public void InitWorldMap(IDictionary<string, string> worldDictionary)
{
if (WorldSheet is null)
{
return;
}
foreach (var currentWorld in WorldSheet)
{
if (!currentWorld.IsPublic)
{
continue;
}
if (currentWorld.Name.ToDalamudString().TextValue.Contains("test", StringComparison.Ordinal))
{
continue;
}
worldDictionary.Add(currentWorld.Name, currentWorld.DataCenter.Value!.Name.ToDalamudString().TextValue);
}
return string.Empty;
}
}
Loading

0 comments on commit face599

Please sign in to comment.