API 4 updates

This commit is contained in:
Ottermandias 2021-08-27 15:06:58 +02:00
parent 86417ed74f
commit f10280d15d
31 changed files with 359 additions and 367 deletions

View file

@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Enums;
namespace Glamourer.Customization
@ -150,10 +150,10 @@ namespace Glamourer.Customization
}
}
public void Read(Actor actor)
public void Read(Character actor)
=> Read(actor.Address + CustomizationOffset);
public ActorCustomization(Actor actor)
public ActorCustomization(Character actor)
: this()
{
Read(actor.Address + CustomizationOffset);

View file

@ -1,4 +1,5 @@
using Dalamud.Plugin;
using Dalamud.Data;
using Dalamud.Plugin;
namespace Glamourer
{
@ -7,9 +8,9 @@ namespace Glamourer
public readonly Lumina.Data.FileResource File;
public readonly uint[] RgbaColors;
public CmpFile(DalamudPluginInterface pi)
public CmpFile(DataManager gameData)
{
File = pi.Data.GetFile("chara/xls/charamake/human.cmp");
File = gameData.GetFile("chara/xls/charamake/human.cmp")!;
RgbaColors = new uint[File.Data.Length >> 2];
for (var i = 0; i < File.Data.Length; i += 4)
{

View file

@ -1,4 +1,6 @@
using System.Collections.Generic;
using Dalamud;
using Dalamud.Data;
using Dalamud.Plugin;
using Penumbra.GameData.Enums;
@ -11,9 +13,9 @@ namespace Glamourer.Customization
private CustomizationManager()
{ }
public static ICustomizationManager Create(DalamudPluginInterface pi)
public static ICustomizationManager Create(DalamudPluginInterface pi, DataManager gameData, ClientLanguage language)
{
_options ??= new CustomizationOptions(pi);
_options ??= new CustomizationOptions(pi, gameData, language);
return new CustomizationManager();
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Dalamud;
using Dalamud.Data;
using Dalamud.Plugin;
using Glamourer.Util;
using Lumina.Data;
@ -50,7 +51,7 @@ namespace Glamourer.Customization
private Customization[] GetHairStyles(SubRace race, Gender gender)
{
var row = _hairSheet.GetRow(((uint) race - 1) * 2 - 1 + (uint) gender);
var row = _hairSheet.GetRow(((uint) race - 1) * 2 - 1 + (uint) gender)!;
var hairList = new List<Customization>(row.Unknown30);
for (var i = 0; i < row.Unknown30; ++i)
{
@ -129,7 +130,7 @@ namespace Glamourer.Customization
private CustomizationSet GetSet(SubRace race, Gender gender)
{
var (skin, hair) = GetColors(race, gender);
var row = _listSheet.GetRow(((uint) race - 1) * 2 - 1 + (uint) gender);
var row = _listSheet.GetRow(((uint) race - 1) * 2 - 1 + (uint) gender)!;
var set = new CustomizationSet(race, gender)
{
HairStyles = race.ToRace() == Race.Hrothgar ? HrothgarFaces(row) : GetHairStyles(race, gender),
@ -211,7 +212,7 @@ namespace Glamourer.Customization
return textRow?.Text.ToString() ?? c.ToDefaultName();
}).ToArray();
set._types = ((CustomizationId[]) Enum.GetValues(typeof(CustomizationId))).Select(c =>
set.Types = ((CustomizationId[]) Enum.GetValues(typeof(CustomizationId))).Select(c =>
{
if (c == CustomizationId.HighlightColor)
return CharaMakeParams.MenuType.ColorPicker;
@ -255,21 +256,21 @@ namespace Glamourer.Customization
_ => Language.English,
};
internal CustomizationOptions(DalamudPluginInterface pi)
internal CustomizationOptions(DalamudPluginInterface pi, DataManager gameData, ClientLanguage language)
{
_cmpFile = new CmpFile(pi);
_customizeSheet = pi.Data.GetExcelSheet<CharaMakeCustomize>();
_lobby = pi.Data.GetExcelSheet<Lobby>();
var tmp = pi.Data.Excel.GetType()!.GetMethod("GetSheet", BindingFlags.Instance | BindingFlags.NonPublic)!
.MakeGenericMethod(typeof(CharaMakeParams))!.Invoke(pi.Data.Excel, new object?[]
_cmpFile = new CmpFile(gameData);
_customizeSheet = gameData.GetExcelSheet<CharaMakeCustomize>()!;
_lobby = gameData.GetExcelSheet<Lobby>()!;
var tmp = gameData.Excel.GetType()!.GetMethod("GetSheet", BindingFlags.Instance | BindingFlags.NonPublic)!
.MakeGenericMethod(typeof(CharaMakeParams))!.Invoke(gameData.Excel, new object?[]
{
"charamaketype",
FromClientLanguage(pi.ClientState.ClientLanguage),
FromClientLanguage(language),
null,
}) as ExcelSheet<CharaMakeParams>;
_listSheet = tmp!;
_hairSheet = pi.Data.GetExcelSheet<HairMakeType>();
SetNames(pi);
_hairSheet = gameData.GetExcelSheet<HairMakeType>()!;
SetNames(gameData);
_highlightPicker = CreateColorPicker(CustomizationId.HighlightColor, 256, 192);
_lipColorPickerDark = CreateColorPicker(CustomizationId.LipColor, 512, 96);
@ -279,7 +280,7 @@ namespace Glamourer.Customization
_facePaintColorPickerLight = CreateColorPicker(CustomizationId.FacePaintColor, 1152, 96, true);
_tattooColorPicker = CreateColorPicker(CustomizationId.TattooColor, 0, 192);
_icons = new IconStorage(pi, _list.Length * 50);
_icons = new IconStorage(pi, gameData, _list.Length * 50);
foreach (var race in Clans)
{
foreach (var gender in Genders)
@ -287,9 +288,9 @@ namespace Glamourer.Customization
}
}
public void SetNames(DalamudPluginInterface pi)
private void SetNames(DataManager gameData)
{
var subRace = pi.Data.GetExcelSheet<Tribe>();
var subRace = gameData.GetExcelSheet<Tribe>()!;
_names[(int) CustomName.Clan] = _lobby.GetRow(102)?.Text ?? "Clan";
_names[(int) CustomName.Gender] = _lobby.GetRow(103)?.Text ?? "Gender";
_names[(int) CustomName.Reverse] = _lobby.GetRow(2135)?.Text ?? "Reverse";

View file

@ -69,7 +69,7 @@ namespace Glamourer.Customization
public IReadOnlyList<Customization> LipColorsLight { get; internal set; } = null!;
public IReadOnlyList<Customization> LipColorsDark { get; internal set; } = null!;
public IReadOnlyList<CharaMakeParams.MenuType> _types { get; internal set; } = null!;
public IReadOnlyList<CharaMakeParams.MenuType> Types { get; internal set; } = null!;
public string Option(CustomizationId id)
=> OptionName[(int) id];
@ -154,7 +154,7 @@ namespace Glamourer.Customization
}
public CharaMakeParams.MenuType Type(CustomizationId id)
=> _types[(int) id];
=> Types[(int) id];
public int Count(CustomizationId id)

View file

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Plugin;
using Dalamud.Data;
using Penumbra.GameData.Enums;
namespace Glamourer
@ -11,22 +11,22 @@ namespace Glamourer
private static Dictionary<byte, Stain>? _stains;
private static Dictionary<EquipSlot, List<Item>>? _itemsBySlot;
public static IReadOnlyDictionary<byte, Stain> Stains(DalamudPluginInterface pi)
public static IReadOnlyDictionary<byte, Stain> Stains(DataManager dataManager)
{
if (_stains != null)
return _stains;
var sheet = pi.Data.GetExcelSheet<Lumina.Excel.GeneratedSheets.Stain>();
var sheet = dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Stain>()!;
_stains = sheet.Where(s => s.Color != 0).ToDictionary(s => (byte) s.RowId, s => new Stain((byte) s.RowId, s));
return _stains;
}
public static IReadOnlyDictionary<EquipSlot, List<Item>> ItemsBySlot(DalamudPluginInterface pi)
public static IReadOnlyDictionary<EquipSlot, List<Item>> ItemsBySlot(DataManager dataManager)
{
if (_itemsBySlot != null)
return _itemsBySlot;
var sheet = pi.Data.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>();
var sheet = dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>()!;
Item EmptySlot(EquipSlot slot)
=> new(sheet.First(), "Nothing", slot);

View file

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<TargetFramework>net5.0-windows</TargetFramework>
<LangVersion>preview</LangVersion>
<PlatformTarget>x64</PlatformTarget>
<RootNamespace>Glamourer</RootNamespace>
<AssemblyName>Glamourer.GameData</AssemblyName>
<FileVersion>1.0.0.0</FileVersion>

View file

@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using Dalamud.Data.LuminaExtensions;
using Dalamud.Data;
using Dalamud.Plugin;
using Dalamud.Utility;
using ImGuiScene;
using Lumina.Data.Files;
@ -10,32 +11,34 @@ namespace Glamourer.Util
public class IconStorage : IDisposable
{
private readonly DalamudPluginInterface _pi;
private readonly Dictionary<int, TextureWrap> _icons;
private readonly DataManager _gameData;
private readonly Dictionary<uint, TextureWrap> _icons;
public IconStorage(DalamudPluginInterface pi, int size = 0)
public IconStorage(DalamudPluginInterface pi, DataManager gameData, int size = 0)
{
_pi = pi;
_icons = new Dictionary<int, TextureWrap>(size);
_gameData = gameData;
_icons = new Dictionary<uint, TextureWrap>(size);
}
public TextureWrap this[int id]
=> LoadIcon(id);
private TexFile? LoadIconHq(int id)
private TexFile? LoadIconHq(uint id)
{
var path = $"ui/icon/{id / 1000 * 1000:000000}/{id:000000}_hr1.tex";
return _pi.Data.GetFile<TexFile>(path);
return _gameData.GetFile<TexFile>(path);
}
public TextureWrap LoadIcon(uint id)
=> LoadIcon((int) id);
public TextureWrap LoadIcon(int id)
=> LoadIcon((uint) id);
public TextureWrap LoadIcon(uint id)
{
if (_icons.TryGetValue(id, out var ret))
return ret;
var icon = LoadIconHq(id) ?? _pi.Data.GetIcon(id);
var icon = LoadIconHq(id) ?? _gameData.GetIcon(id)!;
var iconData = icon.GetRgbaImageData();
ret = _pi.UiBuilder.LoadImageRaw(iconData, icon.Header.Width, icon.Header.Height, 4);

View file

@ -1,8 +1,8 @@
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Objects.Types;
namespace Glamourer
{
public static class ActorExtensions
public static class CharacterExtensions
{
public const int WetnessOffset = 0x19A5;
public const byte WetnessFlag = 0x10;
@ -13,10 +13,10 @@ namespace Glamourer
public const int WeaponHiddenOffset = 0xF64;
public const byte WeaponHiddenFlag = 0x02;
public static unsafe bool IsWet(this Actor a)
public static unsafe bool IsWet(this Character a)
=> (*((byte*) a.Address + WetnessOffset) & WetnessFlag) != 0;
public static unsafe bool SetWetness(this Actor a, bool value)
public static unsafe bool SetWetness(this Character a, bool value)
{
var current = a.IsWet();
if (current == value)
@ -29,10 +29,10 @@ namespace Glamourer
return true;
}
public static unsafe ref byte StateFlags(this Actor a)
public static unsafe ref byte StateFlags(this Character a)
=> ref *((byte*) a.Address + StateFlagsOffset);
public static bool SetStateFlag(this Actor a, bool value, byte flag)
public static bool SetStateFlag(this Character a, bool value, byte flag)
{
var current = a.StateFlags();
var previousValue = (current & flag) != 0;
@ -46,20 +46,20 @@ namespace Glamourer
return true;
}
public static bool IsHatHidden(this Actor a)
public static bool IsHatHidden(this Character a)
=> (a.StateFlags() & HatHiddenFlag) != 0;
public static unsafe bool IsWeaponHidden(this Actor a)
public static unsafe bool IsWeaponHidden(this Character a)
=> (a.StateFlags() & WeaponHiddenFlag) != 0
&& (*((byte*) a.Address + WeaponHiddenOffset) & WeaponHiddenFlag) != 0;
public static bool IsVisorToggled(this Actor a)
public static bool IsVisorToggled(this Character a)
=> (a.StateFlags() & VisorToggledFlag) != 0;
public static bool SetHatHidden(this Actor a, bool value)
public static bool SetHatHidden(this Character a, bool value)
=> SetStateFlag(a, value, HatHiddenFlag);
public static unsafe bool SetWeaponHidden(this Actor a, bool value)
public static unsafe bool SetWeaponHidden(this Character a, bool value)
{
var ret = SetStateFlag(a, value, WeaponHiddenFlag);
var val = *((byte*) a.Address + WeaponHiddenOffset);
@ -70,10 +70,10 @@ namespace Glamourer
return ret || (val & WeaponHiddenFlag) != 0 != value;
}
public static bool SetVisorToggled(this Actor a, bool value)
public static bool SetVisorToggled(this Character a, bool value)
=> SetStateFlag(a, value, VisorToggledFlag);
public static unsafe ref float Alpha(this Actor a)
public static unsafe ref float Alpha(this Character a)
=> ref *(float*) ((byte*) a.Address + AlphaOffset);
}
}

View file

@ -1,5 +1,5 @@
using System;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Objects.Types;
using Glamourer.Customization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@ -121,7 +121,7 @@ namespace Glamourer
public ActorEquipMask WriteEquipment
{
get => (ActorEquipMask) ((ushort) _bytes[2] | ((ushort) _bytes[3] << 8));
get => (ActorEquipMask) (_bytes[2] | (_bytes[3] << 8));
set
{
_bytes[2] = (byte) ((ushort) value & 0xFF);
@ -181,17 +181,17 @@ namespace Glamourer
private static void CheckActorMask(byte val1, byte val2)
{
var mask = (ActorEquipMask) ((ushort) val1 | ((ushort) val2 << 8));
var mask = (ActorEquipMask) (val1 | (val2 << 8));
if (mask > ActorEquipMask.All)
throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid value {mask} in byte 3 and 4.");
}
public void LoadActor(Actor a)
public void LoadActor(Character a)
{
WriteCustomizations = true;
Load(new ActorCustomization(a));
Load(new ActorEquipment(a), ActorEquipMask.All);
Load(new ActorEquipment(a));
SetHatState = true;
SetVisorState = true;
@ -202,7 +202,7 @@ namespace Glamourer
Alpha = a.Alpha();
}
public void Apply(Actor a)
public void Apply(Character a)
{
if (WriteCustomizations)
Customizations.Write(a.Address);

View file

@ -1,23 +0,0 @@
using Dalamud.Plugin;
namespace Glamourer
{
public class CmpFile
{
public readonly Lumina.Data.FileResource File;
public readonly uint[] RgbaColors;
public CmpFile(DalamudPluginInterface pi)
{
File = pi.Data.GetFile("chara/xls/charamake/human.cmp");
RgbaColors = new uint[File.Data.Length >> 2];
for (var i = 0; i < File.Data.Length; i += 4)
{
RgbaColors[i >> 2] = File.Data[i]
| (uint) (File.Data[i + 1] << 8)
| (uint) (File.Data[i + 2] << 16)
| (uint) (File.Data[i + 3] << 24);
}
}
}
}

56
Glamourer/Dalamud.cs Normal file
View file

@ -0,0 +1,56 @@
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Buddy;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Fates;
using Dalamud.Game.ClientState.JobGauge;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Party;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.PartyFinder;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Libc;
using Dalamud.Game.Network;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.IoC;
using Dalamud.Plugin;
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
namespace Glamourer
{
public class Dalamud
{
public static void Initialize(DalamudPluginInterface pluginInterface)
=> pluginInterface.Create<Dalamud>();
// @formatter:off
[PluginService][RequiredVersion("1.0")] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static CommandManager Commands { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static SigScanner SigScanner { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static DataManager GameData { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static ClientState ClientState { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static ChatGui Chat { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static SeStringManager SeStrings { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static ChatHandlers ChatHandlers { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static Framework Framework { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static GameNetwork Network { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static Condition Conditions { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static KeyState Keys { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static GameGui GameGui { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static FlyTextGui FlyTexts { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static ToastGui Toasts { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static JobGauges Gauges { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static PartyFinderGui PartyFinder { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static BuddyList Buddies { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static PartyList Party { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static TargetManager Targets { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static ObjectTable Objects { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static FateTable Fates { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static LibcFunction LibC { get; private set; } = null!;
// @formatter:on
}
}

View file

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dalamud.Plugin;
using Dalamud.Logging;
using Glamourer.FileSystem;
using Newtonsoft.Json;
@ -16,9 +16,9 @@ namespace Glamourer.Designs
public SortedList<string, CharacterSave> Designs = null!;
public FileSystem.FileSystem FileSystem { get; } = new();
public DesignManager(DalamudPluginInterface pi)
public DesignManager()
{
var saveFolder = new DirectoryInfo(pi.GetPluginConfigDirectory());
var saveFolder = new DirectoryInfo(Dalamud.PluginInterface.GetPluginConfigDirectory());
if (!saveFolder.Exists)
Directory.CreateDirectory(saveFolder.FullName);
@ -31,25 +31,22 @@ namespace Glamourer.Designs
{
FileSystem.Clear();
var anyChanges = false;
foreach (var kvp in Designs.ToArray())
foreach (var (path, save) in Designs.ToArray())
{
var path = kvp.Key;
var save = kvp.Value;
try
{
var (folder, name) = FileSystem.CreateAllFolders(path);
var design = new Design(folder, name) { Data = save };
folder.FindOrAddChild(design);
var fixedPath = design.FullName();
if (!string.Equals(fixedPath, path, StringComparison.InvariantCultureIgnoreCase))
{
if (string.Equals(fixedPath, path, StringComparison.InvariantCultureIgnoreCase))
continue;
Designs.Remove(path);
Designs[fixedPath] = save;
anyChanges = true;
PluginLog.Debug($"Problem loading saved designs, {path} was renamed to {fixedPath}.");
}
}
catch (Exception e)
{
PluginLog.Error($"Problem loading saved designs, {path} was removed because:\n{e}");

View file

@ -1,6 +1,5 @@
using System;
using System.Linq;
using Dalamud.Plugin;
using Dalamud.Logging;
using ImGuiNET;
namespace Glamourer.FileSystem
@ -12,7 +11,7 @@ namespace Glamourer.FileSystem
private static unsafe bool IsDropping(string name)
=> ImGui.AcceptDragDropPayload(name).NativePtr != null;
private static IFileSystemBase? _draggedObject = null;
private static IFileSystemBase? _draggedObject;
public static bool DragDropTarget(FileSystem fs, IFileSystemBase child, out string oldPath, out IFileSystemBase? draggedChild)
{

View file

@ -1,17 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Glamourer.Designs;
namespace Glamourer.FileSystem
{
internal class FolderStructureComparer : IComparer<IFileSystemBase>
{
// Compare only the direct folder names since this is only used inside an enumeration of children of one folder.
public static int Cmp(IFileSystemBase x, IFileSystemBase y)
=> ReferenceEquals(x, y) ? 0 : string.Compare(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase);
public static int Cmp(IFileSystemBase? x, IFileSystemBase? y)
=> ReferenceEquals(x, y) ? 0 : string.Compare(x?.Name, y?.Name, StringComparison.InvariantCultureIgnoreCase);
public int Compare(IFileSystemBase x, IFileSystemBase y)
public int Compare(IFileSystemBase? x, IFileSystemBase? y)
=> Cmp(x, y);
internal static readonly FolderStructureComparer Default = new();

View file

@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<TargetFramework>net5.0-windows</TargetFramework>
<LangVersion>preview</LangVersion>
<PlatformTarget>x64</PlatformTarget>
<RootNamespace>Glamourer</RootNamespace>
<AssemblyName>Glamourer</AssemblyName>
<FileVersion>0.0.3.0</FileVersion>
<AssemblyVersion>0.0.3.0</AssemblyVersion>
<FileVersion>0.0.4.0</FileVersion>
<AssemblyVersion>0.0.4.0</AssemblyVersion>
<Company>SoftOtter</Company>
<Product>Glamourer</Product>
<Copyright>Copyright © 2020</Copyright>
@ -63,24 +64,14 @@
<HintPath>$(appdata)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
</Reference>
<Reference Include="Penumbra.GameData">
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\net472\Penumbra.GameData.dll</HintPath>
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.GameData.dll</HintPath>
</Reference>
<Reference Include="Penumbra.Api">
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\net472\Penumbra.Api.dll</HintPath>
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.Api.dll</HintPath>
</Reference>
<Reference Include="Penumbra.PlayerWatch">
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\net472\Penumbra.PlayerWatch.dll</HintPath>
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.PlayerWatch.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>

View file

@ -6,6 +6,6 @@
"AssemblyVersion": "0.0.3.0",
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
"ApplicableVersion": "any",
"DalamudApiLevel": 3,
"DalamudApiLevel": 4,
"LoadPriority": -100
}

View file

@ -20,17 +20,15 @@ namespace Glamourer
public uint EquipmentColor { get; set; } = DefaultEquipmentColor;
public void Save()
=> Glamourer.PluginInterface.SavePluginConfig(this);
=> Dalamud.PluginInterface.SavePluginConfig(this);
public static GlamourerConfig Create()
{
var config = Glamourer.PluginInterface.GetPluginConfig() as GlamourerConfig;
if (config == null)
public static GlamourerConfig Load()
{
if (Dalamud.PluginInterface.GetPluginConfig() is GlamourerConfig config)
return config;
config = new GlamourerConfig();
Glamourer.PluginInterface.SavePluginConfig(config);
}
config.Save();
return config;
}
}

View file

@ -20,12 +20,12 @@ namespace Glamourer.Gui
private readonly IReadOnlyList<string> _itemNamesLower;
private readonly Func<T, string> _itemToName;
public Action? PrePreview = null;
public Action? PostPreview = null;
public Func<T, bool>? CreateSelectable = null;
public Action? PreList = null;
public Action? PostList = null;
public float? HeightPerItem = null;
public Action? PrePreview;
public Action? PostPreview;
public Func<T, bool>? CreateSelectable;
public Action? PreList;
public Action? PostList;
public float? HeightPerItem;
private float _heightPerItem;
@ -99,7 +99,7 @@ namespace Glamourer.Gui
{
nodeIdx = i;
var item = _items[i]!;
var success = false;
bool success;
if (CreateSelectable != null)
{
success = CreateSelectable(item);
@ -151,7 +151,7 @@ namespace Glamourer.Gui
_heightPerItem = HeightPerItem ?? ImGui.GetTextLineHeightWithSpacing();
var ret = false;
bool ret;
try
{
ImGui.SetNextItemWidth(-1);

View file

@ -7,15 +7,12 @@ namespace Glamourer.Gui
{
public sealed class ImGuiRaii : IDisposable
{
private int _colorStack = 0;
private int _fontStack = 0;
private int _styleStack = 0;
private float _indentation = 0f;
private int _colorStack;
private int _fontStack;
private int _styleStack;
private float _indentation;
private Stack<Action>? _onDispose = null;
public ImGuiRaii()
{ }
private Stack<Action>? _onDispose;
public static ImGuiRaii NewGroup()
=> new ImGuiRaii().Group();
@ -51,6 +48,7 @@ namespace Glamourer.Gui
ImGui.PopStyleColor(actualN);
_colorStack -= actualN;
}
return this;
}
@ -76,6 +74,7 @@ namespace Glamourer.Gui
ImGui.PopStyleVar(actualN);
_styleStack -= actualN;
}
return this;
}
@ -95,6 +94,7 @@ namespace Glamourer.Gui
ImGui.PopFont();
--_fontStack;
}
return this;
}
@ -105,6 +105,7 @@ namespace Glamourer.Gui
ImGui.Indent(width);
_indentation += width;
}
return this;
}
@ -134,7 +135,7 @@ namespace Glamourer.Gui
public void End(int n = 1)
{
var actualN = Math.Min(n, _onDispose?.Count ?? 0);
while(actualN-- > 0)
while (actualN-- > 0)
_onDispose!.Pop()();
}

View file

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Actors;
using Glamourer.Designs;
using ImGuiNET;
using Penumbra.GameData;
@ -19,7 +18,6 @@ namespace Glamourer.Gui
private readonly string _glamourerHeader;
private readonly IReadOnlyDictionary<byte, Stain> _stains;
private readonly ActorTable _actors;
private readonly IObjectIdentifier _identifier;
private readonly Dictionary<EquipSlot, (ComboWithFilter<Item>, ComboWithFilter<Stain>)> _combos;
private readonly ImGuiScene.TextureWrap? _legacyTattooIcon;
@ -27,8 +25,8 @@ namespace Glamourer.Gui
private readonly DesignManager _designs;
private readonly Glamourer _plugin;
private bool _visible = false;
private bool _inGPose = false;
private bool _visible;
private bool _inGPose;
public Interface(Glamourer plugin)
{
@ -37,31 +35,30 @@ namespace Glamourer.Gui
_glamourerHeader = Glamourer.Version.Length > 0
? $"{PluginName} v{Glamourer.Version}###{PluginName}Main"
: $"{PluginName}###{PluginName}Main";
Glamourer.PluginInterface.UiBuilder.DisableGposeUiHide = true;
Glamourer.PluginInterface.UiBuilder.OnBuildUi += Draw;
Glamourer.PluginInterface.UiBuilder.OnOpenConfigUi += ToggleVisibility;
Dalamud.PluginInterface.UiBuilder.DisableGposeUiHide = true;
Dalamud.PluginInterface.UiBuilder.Draw += Draw;
Dalamud.PluginInterface.UiBuilder.OpenConfigUi += ToggleVisibility;
_equipSlotNames = GetEquipSlotNames();
_stains = GameData.Stains(Glamourer.PluginInterface);
_identifier = Penumbra.GameData.GameData.GetIdentifier(Glamourer.PluginInterface);
_actors = Glamourer.PluginInterface.ClientState.Actors;
_stains = GameData.Stains(Dalamud.GameData);
_identifier = Penumbra.GameData.GameData.GetIdentifier(Dalamud.GameData, Dalamud.ClientState.ClientLanguage);
var stainCombo = CreateDefaultStainCombo(_stains.Values.ToArray());
var equip = GameData.ItemsBySlot(Glamourer.PluginInterface);
var equip = GameData.ItemsBySlot(Dalamud.GameData);
_combos = equip.ToDictionary(kvp => kvp.Key, kvp => CreateCombos(kvp.Key, kvp.Value, stainCombo));
_legacyTattooIcon = GetLegacyTattooIcon();
}
public void ToggleVisibility(object _, object _2)
public void ToggleVisibility()
=> _visible = !_visible;
public void Dispose()
{
_legacyTattooIcon?.Dispose();
Glamourer.PluginInterface.UiBuilder.OnBuildUi -= Draw;
Glamourer.PluginInterface.UiBuilder.OnOpenConfigUi -= ToggleVisibility;
Dalamud.PluginInterface.UiBuilder.Draw -= Draw;
Dalamud.PluginInterface.UiBuilder.OpenConfigUi -= ToggleVisibility;
}
private void Draw()
@ -80,7 +77,7 @@ namespace Glamourer.Gui
if (!raii.Begin(() => ImGui.BeginTabBar("##tabBar"), ImGui.EndTabBar))
return;
_inGPose = _actors[GPoseActorId] != null;
_inGPose = Dalamud.Objects[GPoseActorId] != null;
_iconSize = Vector2.One * ImGui.GetTextLineHeightWithSpacing() * 2;
_actualIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding;
_comboSelectorSize = 4 * _actualIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X;

View file

@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Numerics;
using System.Windows.Forms;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using Dalamud.Plugin;
using Dalamud.Logging;
using Glamourer.Designs;
using Glamourer.FileSystem;
using ImGuiNET;
@ -14,7 +14,7 @@ namespace Glamourer.Gui
{
private readonly CharacterSave _currentSave = new();
private string _newDesignName = string.Empty;
private bool _keyboardFocus = false;
private bool _keyboardFocus;
private const string DesignNamePopupLabel = "Save Design As...";
private const uint RedHeaderColor = 0xFF1818C0;
private const uint GreenHeaderColor = 0xFF18C018;
@ -37,7 +37,7 @@ namespace Glamourer.Gui
{
ImGui.PushFont(UiBuilder.IconFont);
if (ImGui.Button(FontAwesomeIcon.Clipboard.ToIconString()))
Clipboard.SetText(save.ToBase64());
ImGui.SetClipboardText(save.ToBase64());
ImGui.PopFont();
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Copy customization code to clipboard.");
@ -54,7 +54,7 @@ namespace Glamourer.Gui
if (!applyButton)
return false;
var text = Clipboard.GetText();
var text = ImGui.GetClipboardText();
if (!text.Any())
return false;
@ -88,56 +88,56 @@ namespace Glamourer.Gui
private void DrawTargetPlayerButton()
{
if (ImGui.Button("Target Player"))
Glamourer.PluginInterface.ClientState.Targets.SetCurrentTarget(_player);
Dalamud.Targets.SetTarget(_player);
}
private void DrawApplyToPlayerButton(CharacterSave save)
{
if (ImGui.Button("Apply to Self"))
{
if (!ImGui.Button("Apply to Self"))
return;
var player = _inGPose
? Glamourer.PluginInterface.ClientState.Actors[GPoseActorId]
: Glamourer.PluginInterface.ClientState.LocalPlayer;
var fallback = _inGPose ? Glamourer.PluginInterface.ClientState.LocalPlayer : null;
if (player != null)
{
? (Character?) Dalamud.Objects[GPoseActorId]
: Dalamud.ClientState.LocalPlayer;
var fallback = _inGPose ? Dalamud.ClientState.LocalPlayer : null;
if (player == null)
return;
save.Apply(player);
if (_inGPose)
save.Apply(fallback!);
_plugin.UpdateActors(player, fallback);
}
}
}
private void DrawApplyToTargetButton(CharacterSave save)
{
if (ImGui.Button("Apply to Target"))
{
var player = Glamourer.PluginInterface.ClientState.Targets.CurrentTarget;
if (player != null)
{
var fallBackActor = _playerNames[player.Name];
if (!ImGui.Button("Apply to Target"))
return;
var player = Dalamud.Targets.Target as Character;
if (player == null)
return;
var fallBackActor = _playerNames[player.Name.ToString()];
save.Apply(player);
if (fallBackActor != null)
save.Apply(fallBackActor);
_plugin.UpdateActors(player, fallBackActor);
}
}
}
private void SaveNewDesign(CharacterSave save)
{
try
{
var (folder, name) = _designs.FileSystem.CreateAllFolders(_newDesignName);
if (name.Any())
{
if (!name.Any())
return;
var newDesign = new Design(folder, name) { Data = save };
folder.AddChild(newDesign);
_designs.Designs[newDesign.FullName()] = save;
_designs.SaveToFile();
}
}
catch (Exception e)
{
PluginLog.Error($"Could not save new design {_newDesignName}:\n{e}");

View file

@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Actors;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using ImGuiNET;
@ -10,11 +10,11 @@ namespace Glamourer.Gui
{
internal partial class Interface
{
private Actor? _player;
private Character? _player;
private string _currentActorName = string.Empty;
private string _actorFilter = string.Empty;
private string _actorFilterLower = string.Empty;
private readonly Dictionary<string, Actor?> _playerNames = new(400);
private readonly Dictionary<string, Character?> _playerNames = new(400);
private void DrawActorFilter()
{
@ -26,9 +26,9 @@ namespace Glamourer.Gui
_actorFilterLower = _actorFilter.ToLowerInvariant();
}
private void DrawActorSelectable(Actor actor, bool gPose)
private void DrawActorSelectable(Character actor, bool gPose)
{
var actorName = actor.Name;
var actorName = actor.Name.ToString();
if (!actorName.Any())
return;
@ -50,7 +50,7 @@ namespace Glamourer.Gui
return;
}
if (_currentActorName == actor.Name)
if (_currentActorName == actorName)
{
_currentSave.LoadActor(actor);
_player = actor;
@ -63,10 +63,10 @@ namespace Glamourer.Gui
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.FrameRounding, 0)
.PushFont(UiBuilder.IconFont);
Actor? select = null;
Character? select = null;
var buttonWidth = Vector2.UnitX * SelectorWidth / 2;
if (ImGui.Button(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth))
select = Glamourer.PluginInterface.ClientState.LocalPlayer;
select = Dalamud.ClientState.LocalPlayer;
raii.PopFonts();
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Select the local player character.");
@ -81,7 +81,7 @@ namespace Glamourer.Gui
else
{
if (ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth))
select = Glamourer.PluginInterface.ClientState.Targets.CurrentTarget;
select = Dalamud.Targets.Target as Character;
}
raii.PopFonts();
@ -92,7 +92,7 @@ namespace Glamourer.Gui
return;
_player = select;
_currentActorName = _player.Name;
_currentActorName = _player.Name.ToString();
_currentSave.LoadActor(_player);
}
@ -107,7 +107,7 @@ namespace Glamourer.Gui
_playerNames.Clear();
for (var i = GPoseActorId; i < GPoseActorId + 48; ++i)
{
var actor = _actors[i];
var actor = Dalamud.Objects[i] as Character;
if (actor == null)
break;
@ -117,13 +117,13 @@ namespace Glamourer.Gui
for (var i = 0; i < GPoseActorId; i += 2)
{
var actor = _actors[i];
var actor = Dalamud.Objects[i] as Character;
if (actor != null && actor.ObjectKind == ObjectKind.Player)
DrawActorSelectable(actor, false);
}
using (var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
using (var _ = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
{
ImGui.EndChild();
}

View file

@ -53,7 +53,7 @@ namespace Glamourer.Gui
return;
}
if (ImGui.Button(buttonLabel) && _plugin.GetPenumbra())
if (ImGui.Button(buttonLabel) && Glamourer.GetPenumbra())
{
_plugin.UnregisterFunctions();
_plugin.RegisterFunctions();
@ -88,7 +88,7 @@ namespace Glamourer.Gui
cfg.AttachToPenumbra = v;
if (v)
{
if (_plugin.GetPenumbra())
if (Glamourer.GetPenumbra())
_plugin.RegisterFunctions();
}
else

View file

@ -2,7 +2,7 @@
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Plugin;
using Dalamud.Logging;
using Glamourer.Customization;
using ImGuiNET;
using Penumbra.GameData.Enums;
@ -41,11 +41,11 @@ namespace Glamourer.Gui
private Vector2 _iconSize = Vector2.Zero;
private Vector2 _actualIconSize = Vector2.Zero;
private float _raceSelectorWidth = 0;
private float _inputIntSize = 0;
private float _comboSelectorSize = 0;
private float _percentageSize = 0;
private float _itemComboWidth = 0;
private float _raceSelectorWidth;
private float _inputIntSize;
private float _comboSelectorSize;
private float _percentageSize;
private float _itemComboWidth;
private bool InputInt(string label, ref int value, int minValue, int maxValue)
{
@ -93,7 +93,7 @@ namespace Glamourer.Gui
ImGui.SameLine();
using (var group = ImGuiRaii.NewGroup())
using (var _ = ImGuiRaii.NewGroup())
{
if (InputInt($"##text_{id}", ref current, 1, count))
{

View file

@ -1,9 +1,8 @@
using System;
using System.Linq;
using System.Numerics;
using System.Windows.Forms;
using Dalamud.Interface;
using Dalamud.Plugin;
using Dalamud.Logging;
using Glamourer.Designs;
using Glamourer.FileSystem;
using ImGuiNET;
@ -12,9 +11,9 @@ namespace Glamourer.Gui
{
internal partial class Interface
{
private int _totalObject = 0;
private int _totalObject;
private Design? _selection = null;
private Design? _selection;
private string _newChildName = string.Empty;
private void DrawDesignSelector()
@ -50,7 +49,7 @@ namespace Glamourer.Gui
if (_selection!.Data.WriteProtected || !applyButton)
return;
var text = Clipboard.GetText();
var text = ImGui.GetClipboardText();
if (!text.Any())
return;
@ -280,7 +279,6 @@ namespace Glamourer.Gui
private void ContextMenu(IFileSystemBase child)
{
var label = $"##fsPopup{child.FullName()}";
var renameLabel = $"{label}_rename";
if (ImGui.BeginPopup(label))
{
if (ImGui.MenuItem("Delete"))
@ -289,7 +287,7 @@ namespace Glamourer.Gui
RenameChildInput(child);
if (child is Design d && ImGui.MenuItem("Copy to Clipboard"))
Clipboard.SetText(d.Data.ToBase64());
ImGui.SetClipboardText(d.Data.ToBase64());
ImGui.EndPopup();
}

View file

@ -1,11 +1,8 @@
using System;
using System.Linq;
using System.Windows.Forms;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Plugin;
using Dalamud.Logging;
using Glamourer.Customization;
using ImGuiNET;
using Penumbra.Api;
using Penumbra.GameData.Enums;
namespace Glamourer.Gui
@ -46,7 +43,7 @@ namespace Glamourer.Gui
break;
default:
var count = set.Count(id);
if (set.DataByValue(id, customization[id], out var value) < 0)
if (set.DataByValue(id, customization[id], out _) < 0)
if (count == 0)
customization[id] = 0;
else
@ -173,7 +170,7 @@ namespace Glamourer.Gui
case DesignNameUse.FromClipboard:
try
{
var text = Clipboard.GetText();
var text = ImGui.GetClipboardText();
var save = CharacterSave.FromString(text);
SaveNewDesign(save);
}

View file

@ -53,7 +53,7 @@ namespace Glamourer.Gui
{
var rawImage = new byte[resource.Length];
resource.Read(rawImage, 0, (int) resource.Length);
return Glamourer.PluginInterface.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4);
return Dalamud.PluginInterface.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4);
}
return null;
@ -61,7 +61,7 @@ namespace Glamourer.Gui
private static Dictionary<EquipSlot, string> GetEquipSlotNames()
{
var sheet = Glamourer.PluginInterface.Data.GetExcelSheet<Addon>();
var sheet = Dalamud.GameData.GetExcelSheet<Addon>()!;
var ret = new Dictionary<EquipSlot, string>(12)
{
[EquipSlot.MainHand] = sheet.GetRow(738)?.Text.ToString() ?? "Main Hand",

View file

@ -1,5 +1,5 @@
using System;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Objects.Types;
using ImGuiNET;
namespace Glamourer.Gui
@ -18,7 +18,7 @@ namespace Glamourer.Gui
return false;
}
private static bool DrawMiscellaneous(CharacterSave save, Actor? player)
private static bool DrawMiscellaneous(CharacterSave save, Character? player)
{
var ret = false;
if (!ImGui.CollapsingHeader("Miscellaneous"))

View file

@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Command;
using Dalamud.Logging;
using Dalamud.Plugin;
using Glamourer.Customization;
using Glamourer.Designs;
@ -18,14 +17,13 @@ namespace Glamourer
{
public class Glamourer : IDalamudPlugin
{
public const int RequiredPenumbraShareVersion = 1;
public const int RequiredPenumbraShareVersion = 3;
private const string HelpString = "[Copy|Apply|Save],[Name or PlaceHolder],<Name for Save>";
public string Name
=> "Glamourer";
public static DalamudPluginInterface PluginInterface = null!;
public static GlamourerConfig Config = null!;
private Interface _interface = null!;
public static ICustomizationManager Customization = null!;
@ -36,18 +34,6 @@ namespace Glamourer
public static IPenumbraApi? Penumbra;
private Dalamud.Dalamud _dalamud = null!;
private List<(IDalamudPlugin Plugin, PluginDefinition Definition, DalamudPluginInterface PluginInterface, bool IsRaw)> _plugins = null!;
private void SetDalamud(DalamudPluginInterface pi)
{
var dalamud = (Dalamud.Dalamud?) pi.GetType()
?.GetField("dalamud", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(pi);
_dalamud = dalamud ?? throw new Exception("Could not obtain Dalamud.");
}
private static void PenumbraTooltip(object? it)
{
if (it is Lumina.Excel.GeneratedSheets.Item)
@ -56,11 +42,11 @@ namespace Glamourer
private void PenumbraRightClick(MouseButton button, object? it)
{
if (button == MouseButton.Right && it is Lumina.Excel.GeneratedSheets.Item item)
{
var actors = PluginInterface.ClientState.Actors;
var gPose = actors[Interface.GPoseActorId];
var player = actors[0];
if (button != MouseButton.Right || it is not Lumina.Excel.GeneratedSheets.Item item)
return;
var gPose = Dalamud.Objects[Interface.GPoseActorId] as Character;
var player = Dalamud.Objects[0] as Character;
var writeItem = new Item(item, string.Empty);
if (gPose != null)
{
@ -73,7 +59,6 @@ namespace Glamourer
UpdateActors(player);
}
}
}
public void RegisterFunctions()
{
@ -93,61 +78,51 @@ namespace Glamourer
Penumbra!.ChangedItemClicked -= PenumbraRightClick;
}
private void SetPlugins(DalamudPluginInterface pi)
internal static bool GetPenumbra()
{
var pluginManager = _dalamud?.GetType()
?.GetProperty("PluginManager", BindingFlags.Instance | BindingFlags.NonPublic)
?.GetValue(_dalamud);
if (pluginManager == null)
throw new Exception("Could not obtain plugin manager.");
var pluginsList =
(List<(IDalamudPlugin Plugin, PluginDefinition Definition, DalamudPluginInterface PluginInterface, bool IsRaw)>?) pluginManager
?.GetType()
?.GetProperty("Plugins", BindingFlags.Instance | BindingFlags.Public)
?.GetValue(pluginManager);
_plugins = pluginsList ?? throw new Exception("Could not obtain Dalamud.");
try
{
var subscriber = Dalamud.PluginInterface.GetIpcSubscriber<IPenumbraApiBase>("Penumbra.Api");
var penumbraApiBase = subscriber.InvokeFunc();
if (penumbraApiBase.ApiVersion != RequiredPenumbraShareVersion)
{
PluginLog.Debug("Could not get Penumbra because API version {penumbraApiBase.ApiVersion} does not equal the required version {RequiredPenumbraShareVersion}.");
Penumbra = null;
return false;
}
public bool GetPenumbra()
Penumbra = penumbraApiBase as IPenumbraApi;
}
catch (IpcNotReadyError ipc)
{
if (Penumbra?.Valid ?? false)
return true;
var plugin = _plugins.Find(p
=> p.Definition.InternalName == "Penumbra"
&& string.Compare(p.Definition.AssemblyVersion, "0.4.0.3", StringComparison.Ordinal) >= 0).Plugin;
var penumbra = (IPenumbraApiBase?) plugin?.GetType().GetProperty("Api", BindingFlags.Instance | BindingFlags.Public)
?.GetValue(plugin);
if (penumbra != null && penumbra.Valid && penumbra.ApiVersion >= RequiredPenumbraShareVersion)
Penumbra = (IPenumbraApi) penumbra!;
else
Penumbra = null;
PluginLog.Debug($"Could not get Penumbra because IPC not registered:\n{ipc}");
}
catch (Exception e)
{
Penumbra = null;
PluginLog.Debug($"Could not get Penumbra for unknown reason:\n{e}");
}
return Penumbra != null;
}
public void Initialize(DalamudPluginInterface pluginInterface)
public Glamourer(DalamudPluginInterface pluginInterface)
{
Version = Assembly.GetExecutingAssembly()?.GetName().Version.ToString() ?? "";
PluginInterface = pluginInterface;
Config = GlamourerConfig.Create();
Customization = CustomizationManager.Create(PluginInterface);
SetDalamud(PluginInterface);
SetPlugins(PluginInterface);
Designs = new DesignManager(PluginInterface);
Dalamud.Initialize(pluginInterface);
Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "";
Config = GlamourerConfig.Load();
Customization = CustomizationManager.Create(Dalamud.PluginInterface, Dalamud.GameData, Dalamud.ClientState.ClientLanguage);
Designs = new DesignManager();
if (GetPenumbra() && Config.AttachToPenumbra)
RegisterFunctions();
PlayerWatcher = PlayerWatchFactory.Create(PluginInterface);
PlayerWatcher = PlayerWatchFactory.Create(Dalamud.Framework, Dalamud.ClientState, Dalamud.Objects);
PluginInterface.CommandManager.AddHandler("/glamourer", new CommandInfo(OnGlamourer)
Dalamud.Commands.AddHandler("/glamourer", new CommandInfo(OnGlamourer)
{
HelpMessage = "Open or close the Glamourer window.",
});
PluginInterface.CommandManager.AddHandler("/glamour", new CommandInfo(OnGlamour)
Dalamud.Commands.AddHandler("/glamour", new CommandInfo(OnGlamour)
{
HelpMessage = $"Use Glamourer Functions: {HelpString}",
});
@ -156,48 +131,48 @@ namespace Glamourer
}
public void OnGlamourer(string command, string arguments)
=> _interface?.ToggleVisibility(null!, null!);
=> _interface.ToggleVisibility();
private Actor? GetActor(string name)
private static GameObject? GetActor(string name)
{
var lowerName = name.ToLowerInvariant();
return lowerName switch
{
"" => null,
"<me>" => PluginInterface.ClientState.Actors[Interface.GPoseActorId] ?? PluginInterface.ClientState.LocalPlayer,
"self" => PluginInterface.ClientState.Actors[Interface.GPoseActorId] ?? PluginInterface.ClientState.LocalPlayer,
"<t>" => PluginInterface.ClientState.Targets.CurrentTarget,
"target" => PluginInterface.ClientState.Targets.CurrentTarget,
"<f>" => PluginInterface.ClientState.Targets.FocusTarget,
"focus" => PluginInterface.ClientState.Targets.FocusTarget,
"<mo>" => PluginInterface.ClientState.Targets.MouseOverTarget,
"mouseover" => PluginInterface.ClientState.Targets.MouseOverTarget,
_ => PluginInterface.ClientState.Actors.LastOrDefault(
a => string.Equals(a.Name, lowerName, StringComparison.InvariantCultureIgnoreCase)),
"<me>" => Dalamud.Objects[Interface.GPoseActorId] ?? Dalamud.ClientState.LocalPlayer,
"self" => Dalamud.Objects[Interface.GPoseActorId] ?? Dalamud.ClientState.LocalPlayer,
"<t>" => Dalamud.Targets.Target,
"target" => Dalamud.Targets.Target,
"<f>" => Dalamud.Targets.FocusTarget,
"focus" => Dalamud.Targets.FocusTarget,
"<mo>" => Dalamud.Targets.MouseOverTarget,
"mouseover" => Dalamud.Targets.MouseOverTarget,
_ => Dalamud.Objects.LastOrDefault(
a => string.Equals(a.Name.ToString(), lowerName, StringComparison.InvariantCultureIgnoreCase)),
};
}
public void CopyToClipboard(Actor actor)
public void CopyToClipboard(Character actor)
{
var save = new CharacterSave();
save.LoadActor(actor);
Clipboard.SetText(save.ToBase64());
ImGui.SetClipboardText(save.ToBase64());
}
public void ApplyCommand(Actor actor, string target)
public void ApplyCommand(Character actor, string target)
{
CharacterSave? save = null;
if (target.ToLowerInvariant() == "clipboard")
try
{
save = CharacterSave.FromString(Clipboard.GetText());
save = CharacterSave.FromString(ImGui.GetClipboardText());
}
catch (Exception)
{
PluginInterface.Framework.Gui.Chat.PrintError("Clipboard does not contain a valid customization string.");
Dalamud.Chat.PrintError("Clipboard does not contain a valid customization string.");
}
else if (!Designs.FileSystem.Find(target, out var child) || child is not Design d)
PluginInterface.Framework.Gui.Chat.PrintError("The given path to a saved design does not exist or does not point to a design.");
Dalamud.Chat.PrintError("The given path to a saved design does not exist or does not point to a design.");
else
save = d.Data;
@ -205,7 +180,7 @@ namespace Glamourer
UpdateActors(actor);
}
public void SaveCommand(Actor actor, string path)
public void SaveCommand(Character actor, string path)
{
var save = new CharacterSave();
save.LoadActor(actor);
@ -219,8 +194,8 @@ namespace Glamourer
}
catch (Exception e)
{
PluginInterface.Framework.Gui.Chat.PrintError("Could not save file:");
PluginInterface.Framework.Gui.Chat.PrintError($" {e.Message}");
Dalamud.Chat.PrintError("Could not save file:");
Dalamud.Chat.PrintError($" {e.Message}");
}
}
@ -228,8 +203,8 @@ namespace Glamourer
{
static void PrintHelp()
{
PluginInterface.Framework.Gui.Chat.Print("Usage:");
PluginInterface.Framework.Gui.Chat.Print($" {HelpString}");
Dalamud.Chat.Print("Usage:");
Dalamud.Chat.Print($" {HelpString}");
}
arguments = arguments.Trim();
@ -250,10 +225,10 @@ namespace Glamourer
return;
}
var actor = GetActor(split[1]);
var actor = GetActor(split[1]) as Character;
if (actor == null)
{
PluginInterface.Framework.Gui.Chat.Print($"Could not find actor for {split[1]}.");
Dalamud.Chat.Print($"Could not find actor for {split[1]} or it was not a Character.");
return;
}
@ -266,7 +241,7 @@ namespace Glamourer
{
if (split.Length < 3)
{
PluginInterface.Framework.Gui.Chat.Print("Applying requires a name for the save to be applied or 'clipboard'.");
Dalamud.Chat.Print("Applying requires a name for the save to be applied or 'clipboard'.");
return;
}
@ -278,7 +253,7 @@ namespace Glamourer
{
if (split.Length < 3)
{
PluginInterface.Framework.Gui.Chat.Print("Saving requires a name for the save.");
Dalamud.Chat.Print("Saving requires a name for the save.");
return;
}
@ -296,25 +271,24 @@ namespace Glamourer
PlayerWatcher?.Dispose();
UnregisterFunctions();
_interface?.Dispose();
PluginInterface.CommandManager.RemoveHandler("/glamour");
PluginInterface.CommandManager.RemoveHandler("/glamourer");
PluginInterface.Dispose();
Dalamud.Commands.RemoveHandler("/glamour");
Dalamud.Commands.RemoveHandler("/glamourer");
}
// Update actors without triggering PlayerWatcher Events,
// then manually redraw using Penumbra.
public void UpdateActors(Actor actor, Actor? gPoseOriginalActor = null)
public void UpdateActors(Character actor, Character? gPoseOriginalActor = null)
{
var newEquip = PlayerWatcher.UpdateActorWithoutEvent(actor);
Penumbra?.RedrawActor(actor, RedrawType.WithSettings);
Penumbra?.RedrawObject(actor, RedrawType.WithSettings);
// Special case for carrying over changes to the gPose actor to the regular player actor, too.
if (gPoseOriginalActor != null)
{
if (gPoseOriginalActor == null)
return;
newEquip.Write(gPoseOriginalActor.Address);
PlayerWatcher.UpdateActorWithoutEvent(gPoseOriginalActor);
Penumbra?.RedrawActor(gPoseOriginalActor, RedrawType.AfterGPoseWithSettings);
}
Penumbra?.RedrawObject(gPoseOriginalActor, RedrawType.AfterGPoseWithSettings);
}
}
}

View file

@ -4,11 +4,11 @@
"Name": "Glamourer",
"Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.",
"InternalName": "Glamourer",
"AssemblyVersion": "0.0.3.0",
"TestingAssemblyVersion": "0.0.3.0",
"AssemblyVersion": "0.0.4.0",
"TestingAssemblyVersion": "0.0.4.0",
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
"ApplicableVersion": "any",
"DalamudApiLevel": 3,
"DalamudApiLevel": 4,
"IsHide": "False",
"IsTestingExclusive": "false",
"DownloadCount": 1,