mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Services here, too!
This commit is contained in:
parent
1eb16b98a8
commit
85adc3626e
47 changed files with 1015 additions and 562 deletions
|
|
@ -95,4 +95,14 @@ public static class CustomizeFlagExtensions
|
||||||
CustomizeFlag.FacePaintColor => CustomizeIndex.FacePaintColor,
|
CustomizeFlag.FacePaintColor => CustomizeIndex.FacePaintColor,
|
||||||
_ => (CustomizeIndex)byte.MaxValue,
|
_ => (CustomizeIndex)byte.MaxValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static bool SetIfDifferent(ref this CustomizeFlag flags, CustomizeFlag flag, bool value)
|
||||||
|
{
|
||||||
|
var newValue = value ? flags | flag : flags & ~flag;
|
||||||
|
if (newValue == flags)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
flags = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ public partial class Glamourer
|
||||||
|
|
||||||
private readonly ObjectTable _objectTable;
|
private readonly ObjectTable _objectTable;
|
||||||
private readonly DalamudPluginInterface _pluginInterface;
|
private readonly DalamudPluginInterface _pluginInterface;
|
||||||
private readonly Glamourer _glamourer;
|
|
||||||
|
|
||||||
internal ICallGateProvider<string, string?>? ProviderGetAllCustomization;
|
internal ICallGateProvider<string, string?>? ProviderGetAllCustomization;
|
||||||
internal ICallGateProvider<Character?, string?>? ProviderGetAllCustomizationFromCharacter;
|
internal ICallGateProvider<Character?, string?>? ProviderGetAllCustomizationFromCharacter;
|
||||||
|
|
@ -44,10 +43,8 @@ public partial class Glamourer
|
||||||
internal ICallGateProvider<Character?, object>? ProviderRevertCharacter;
|
internal ICallGateProvider<Character?, object>? ProviderRevertCharacter;
|
||||||
internal ICallGateProvider<int>? ProviderGetApiVersion;
|
internal ICallGateProvider<int>? ProviderGetApiVersion;
|
||||||
|
|
||||||
public GlamourerIpc(Glamourer glamourer, ClientState clientState, ObjectTable objectTable,
|
public GlamourerIpc(ObjectTable objectTable, DalamudPluginInterface pluginInterface)
|
||||||
DalamudPluginInterface pluginInterface)
|
|
||||||
{
|
{
|
||||||
_glamourer = glamourer;
|
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
|
|
||||||
|
|
@ -214,9 +211,9 @@ public partial class Glamourer
|
||||||
if (character == null)
|
if (character == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var design = Design.CreateTemporaryFromBase64(customization, true, true);
|
//var design = Design.CreateTemporaryFromBase64(customization, true, true);
|
||||||
var active = _glamourer._stateManager.GetOrCreateSave(character.Address);
|
//var active = _glamourer._stateManager.GetOrCreateSave(character.Address);
|
||||||
_glamourer._stateManager.ApplyDesign(active, design, false);
|
//_glamourer._stateManager.ApplyDesign(active, design, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyOnlyCustomization(string customization, string characterName)
|
private void ApplyOnlyCustomization(string customization, string characterName)
|
||||||
|
|
@ -235,9 +232,9 @@ public partial class Glamourer
|
||||||
{
|
{
|
||||||
if (character == null)
|
if (character == null)
|
||||||
return;
|
return;
|
||||||
var design = Design.CreateTemporaryFromBase64(customization, true, false);
|
//var design = Design.CreateTemporaryFromBase64(customization, true, false);
|
||||||
var active = _glamourer._stateManager.GetOrCreateSave(character.Address);
|
//var active = _glamourer._stateManager.GetOrCreateSave(character.Address);
|
||||||
_glamourer._stateManager.ApplyDesign(active, design, false);
|
//_glamourer._stateManager.ApplyDesign(active, design, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyOnlyEquipment(string customization, string characterName)
|
private void ApplyOnlyEquipment(string customization, string characterName)
|
||||||
|
|
@ -256,9 +253,9 @@ public partial class Glamourer
|
||||||
{
|
{
|
||||||
if (character == null)
|
if (character == null)
|
||||||
return;
|
return;
|
||||||
var design = Design.CreateTemporaryFromBase64(customization, false, true);
|
//var design = Design.CreateTemporaryFromBase64(customization, false, true);
|
||||||
var active = _glamourer._stateManager.GetOrCreateSave(character.Address);
|
//var active = _glamourer._stateManager.GetOrCreateSave(character.Address);
|
||||||
_glamourer._stateManager.ApplyDesign(active, design, false);
|
//_glamourer._stateManager.ApplyDesign(active, design, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Revert(string characterName)
|
private void Revert(string characterName)
|
||||||
|
|
@ -277,9 +274,9 @@ public partial class Glamourer
|
||||||
if (character == null)
|
if (character == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var ident = Actors.FromObject(character, true, false, false);
|
//var ident = Actors.FromObject(character, true, false, false);
|
||||||
_glamourer._stateManager.DeleteSave(ident);
|
//_glamourer._stateManager.DeleteSave(ident);
|
||||||
_glamourer._penumbra.RedrawObject(character.Address, RedrawType.Redraw);
|
//_glamourer._penumbra.RedrawObject(character.Address, RedrawType.Redraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string? GetAllCustomization(Character? character)
|
private string? GetAllCustomization(Character? character)
|
||||||
|
|
@ -287,11 +284,12 @@ public partial class Glamourer
|
||||||
if (character == null)
|
if (character == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var ident = Actors.FromObject(character, true, false, false);
|
//var ident = Actors.FromObject(character, true, false, false);
|
||||||
if (!_glamourer._stateManager.TryGetValue(ident, out var design))
|
//if (!_glamourer._stateManager.TryGetValue(ident, out var design))
|
||||||
design = new ActiveDesign(ident, character.Address);
|
// design = new ActiveDesign(ident, character.Address);
|
||||||
|
//
|
||||||
return design.CreateOldBase64();
|
//return design.CreateOldBase64();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string? GetAllCustomization(string characterName)
|
private string? GetAllCustomization(string characterName)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
|
using Dalamud.Plugin;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
|
|
@ -8,11 +9,17 @@ using Penumbra.Api.Helpers;
|
||||||
|
|
||||||
namespace Glamourer.Api;
|
namespace Glamourer.Api;
|
||||||
|
|
||||||
|
public class CommunicatorService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe class PenumbraAttach : IDisposable
|
public unsafe class PenumbraAttach : IDisposable
|
||||||
{
|
{
|
||||||
public const int RequiredPenumbraBreakingVersion = 4;
|
public const int RequiredPenumbraBreakingVersion = 4;
|
||||||
public const int RequiredPenumbraFeatureVersion = 15;
|
public const int RequiredPenumbraFeatureVersion = 15;
|
||||||
|
|
||||||
|
private readonly DalamudPluginInterface _pluginInterface;
|
||||||
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
|
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
|
||||||
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
|
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
|
||||||
private readonly EventSubscriber<nint, string, nint, nint, nint> _creatingCharacterBase;
|
private readonly EventSubscriber<nint, string, nint, nint, nint> _creatingCharacterBase;
|
||||||
|
|
@ -25,14 +32,15 @@ public unsafe class PenumbraAttach : IDisposable
|
||||||
private readonly EventSubscriber _disposedEvent;
|
private readonly EventSubscriber _disposedEvent;
|
||||||
public bool Available { get; private set; }
|
public bool Available { get; private set; }
|
||||||
|
|
||||||
public PenumbraAttach()
|
public PenumbraAttach(DalamudPluginInterface pi)
|
||||||
{
|
{
|
||||||
_initializedEvent = Ipc.Initialized.Subscriber(Dalamud.PluginInterface, Reattach);
|
_pluginInterface = pi;
|
||||||
_disposedEvent = Ipc.Disposed.Subscriber(Dalamud.PluginInterface, Unattach);
|
_initializedEvent = Ipc.Initialized.Subscriber(pi, Reattach);
|
||||||
_tooltipSubscriber = Ipc.ChangedItemTooltip.Subscriber(Dalamud.PluginInterface);
|
_disposedEvent = Ipc.Disposed.Subscriber(pi, Unattach);
|
||||||
_clickSubscriber = Ipc.ChangedItemClick.Subscriber(Dalamud.PluginInterface);
|
_tooltipSubscriber = Ipc.ChangedItemTooltip.Subscriber(pi);
|
||||||
_createdCharacterBase = Ipc.CreatedCharacterBase.Subscriber(Dalamud.PluginInterface);
|
_clickSubscriber = Ipc.ChangedItemClick.Subscriber(pi);
|
||||||
_creatingCharacterBase = Ipc.CreatingCharacterBase.Subscriber(Dalamud.PluginInterface);
|
_createdCharacterBase = Ipc.CreatedCharacterBase.Subscriber(pi);
|
||||||
|
_creatingCharacterBase = Ipc.CreatingCharacterBase.Subscriber(pi);
|
||||||
Reattach();
|
Reattach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,7 +96,7 @@ public unsafe class PenumbraAttach : IDisposable
|
||||||
{
|
{
|
||||||
Unattach();
|
Unattach();
|
||||||
|
|
||||||
var (breaking, feature) = Ipc.ApiVersions.Subscriber(Dalamud.PluginInterface).Invoke();
|
var (breaking, feature) = Ipc.ApiVersions.Subscriber(_pluginInterface).Invoke();
|
||||||
if (breaking != RequiredPenumbraBreakingVersion || feature < RequiredPenumbraFeatureVersion)
|
if (breaking != RequiredPenumbraBreakingVersion || feature < RequiredPenumbraFeatureVersion)
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
$"Invalid Version {breaking}.{feature:D4}, required major Version {RequiredPenumbraBreakingVersion} with feature greater or equal to {RequiredPenumbraFeatureVersion}.");
|
$"Invalid Version {breaking}.{feature:D4}, required major Version {RequiredPenumbraBreakingVersion} with feature greater or equal to {RequiredPenumbraFeatureVersion}.");
|
||||||
|
|
@ -97,9 +105,9 @@ public unsafe class PenumbraAttach : IDisposable
|
||||||
_clickSubscriber.Enable();
|
_clickSubscriber.Enable();
|
||||||
_creatingCharacterBase.Enable();
|
_creatingCharacterBase.Enable();
|
||||||
_createdCharacterBase.Enable();
|
_createdCharacterBase.Enable();
|
||||||
_drawObjectInfo = Ipc.GetDrawObjectInfo.Subscriber(Dalamud.PluginInterface);
|
_drawObjectInfo = Ipc.GetDrawObjectInfo.Subscriber(_pluginInterface);
|
||||||
_cutsceneParent = Ipc.GetCutsceneParentIndex.Subscriber(Dalamud.PluginInterface);
|
_cutsceneParent = Ipc.GetCutsceneParentIndex.Subscriber(_pluginInterface);
|
||||||
_redrawSubscriber = Ipc.RedrawObjectByIndex.Subscriber(Dalamud.PluginInterface);
|
_redrawSubscriber = Ipc.RedrawObjectByIndex.Subscriber(_pluginInterface);
|
||||||
Available = true;
|
Available = true;
|
||||||
Glamourer.Log.Debug("Glamourer attached to Penumbra.");
|
Glamourer.Log.Debug("Glamourer attached to Penumbra.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
79
Glamourer/Configuration.cs
Normal file
79
Glamourer/Configuration.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Dalamud.Configuration;
|
||||||
|
using Glamourer.Services;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||||
|
|
||||||
|
namespace Glamourer;
|
||||||
|
|
||||||
|
public class Configuration : IPluginConfiguration, ISavable
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
private readonly SaveService _saveService;
|
||||||
|
|
||||||
|
public class FixedDesign
|
||||||
|
{
|
||||||
|
public string Name = string.Empty;
|
||||||
|
public string Path = string.Empty;
|
||||||
|
public uint JobGroups;
|
||||||
|
public bool Enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Version { get; set; } = 1;
|
||||||
|
|
||||||
|
public const uint DefaultCustomizationColor = 0xFFC000C0;
|
||||||
|
public const uint DefaultStateColor = 0xFF00C0C0;
|
||||||
|
public const uint DefaultEquipmentColor = 0xFF00C000;
|
||||||
|
|
||||||
|
public bool UseRestrictedGearProtection { get; set; } = true;
|
||||||
|
|
||||||
|
public bool FoldersFirst { get; set; } = false;
|
||||||
|
public bool ColorDesigns { get; set; } = true;
|
||||||
|
public bool ShowLocks { get; set; } = true;
|
||||||
|
public bool ApplyFixedDesigns { get; set; } = true;
|
||||||
|
|
||||||
|
public uint CustomizationColor { get; set; } = DefaultCustomizationColor;
|
||||||
|
public uint StateColor { get; set; } = DefaultStateColor;
|
||||||
|
public uint EquipmentColor { get; set; } = DefaultEquipmentColor;
|
||||||
|
|
||||||
|
public List<FixedDesign> FixedDesigns { get; set; } = new();
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
=> _saveService.QueueSave(this);
|
||||||
|
|
||||||
|
public Configuration(SaveService saveService)
|
||||||
|
{
|
||||||
|
_saveService = saveService;
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load()
|
||||||
|
{
|
||||||
|
static void HandleDeserializationError(object? sender, ErrorEventArgs errorArgs)
|
||||||
|
{
|
||||||
|
Glamourer.Log.Error(
|
||||||
|
$"Error parsing Configuration at {errorArgs.ErrorContext.Path}, using default or migrating:\n{errorArgs.ErrorContext.Error}");
|
||||||
|
errorArgs.ErrorContext.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(_saveService.FileNames.ConfigFile))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var text = File.ReadAllText(_saveService.FileNames.ConfigFile);
|
||||||
|
JsonConvert.PopulateObject(text, this, new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
Error = HandleDeserializationError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToFilename(FilenameService fileNames)
|
||||||
|
=> fileNames.ConfigFile;
|
||||||
|
|
||||||
|
public void Save(StreamWriter writer)
|
||||||
|
{
|
||||||
|
using var jWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented };
|
||||||
|
var serializer = new JsonSerializer { Formatting = Formatting.Indented };
|
||||||
|
serializer.Serialize(jWriter, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,26 +7,43 @@ using Dalamud.Game.Command;
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
|
|
||||||
|
|
||||||
namespace Glamourer;
|
namespace Glamourer;
|
||||||
|
|
||||||
public class Dalamud
|
public class DalamudServices
|
||||||
{
|
{
|
||||||
public static void Initialize(DalamudPluginInterface pluginInterface)
|
public DalamudServices(DalamudPluginInterface pi)
|
||||||
=> pluginInterface.Create<Dalamud>();
|
{
|
||||||
|
pi.Inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton(PluginInterface);
|
||||||
|
services.AddSingleton(Commands);
|
||||||
|
services.AddSingleton(GameData);
|
||||||
|
services.AddSingleton(ClientState);
|
||||||
|
services.AddSingleton(GameGui);
|
||||||
|
services.AddSingleton(Chat);
|
||||||
|
services.AddSingleton(Framework);
|
||||||
|
services.AddSingleton(Targets);
|
||||||
|
services.AddSingleton(Objects);
|
||||||
|
services.AddSingleton(KeyState);
|
||||||
|
services.AddSingleton(this);
|
||||||
|
services.AddSingleton(PluginInterface.UiBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
[PluginService][RequiredVersion("1.0")] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public DalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static CommandManager Commands { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public CommandManager Commands { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static DataManager GameData { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public DataManager GameData { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static ClientState ClientState { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public ClientState ClientState { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static GameGui GameGui { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public GameGui GameGui { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static ChatGui Chat { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public ChatGui Chat { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static Framework Framework { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public Framework Framework { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static TargetManager Targets { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public TargetManager Targets { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static ObjectTable Objects { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public ObjectTable Objects { get; private set; } = null!;
|
||||||
[PluginService][RequiredVersion("1.0")] public static KeyState KeyState { get; private set; } = null!;
|
[PluginService][RequiredVersion("1.0")] public KeyState KeyState { get; private set; } = null!;
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Services;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -21,8 +22,9 @@ public partial class Design
|
||||||
public const string DesignFolderName = "designs";
|
public const string DesignFolderName = "designs";
|
||||||
public readonly string DesignFolder;
|
public readonly string DesignFolder;
|
||||||
|
|
||||||
private readonly FrameworkManager _framework;
|
private readonly ItemManager _items;
|
||||||
private readonly List<Design> _designs = new();
|
private readonly SaveService _saveService;
|
||||||
|
private readonly List<Design> _designs = new();
|
||||||
|
|
||||||
public enum DesignChangeType
|
public enum DesignChangeType
|
||||||
{
|
{
|
||||||
|
|
@ -50,9 +52,10 @@ public partial class Design
|
||||||
public IReadOnlyList<Design> Designs
|
public IReadOnlyList<Design> Designs
|
||||||
=> _designs;
|
=> _designs;
|
||||||
|
|
||||||
public Manager(DalamudPluginInterface pi, FrameworkManager framework)
|
public Manager(DalamudPluginInterface pi, SaveService saveService, ItemManager items)
|
||||||
{
|
{
|
||||||
_framework = framework;
|
_saveService = saveService;
|
||||||
|
_items = items;
|
||||||
DesignFolder = SetDesignFolder(pi);
|
DesignFolder = SetDesignFolder(pi);
|
||||||
DesignChange += OnChange;
|
DesignChange += OnChange;
|
||||||
LoadDesigns();
|
LoadDesigns();
|
||||||
|
|
@ -105,7 +108,7 @@ public partial class Design
|
||||||
=> Path.Combine(DesignFolder, $"{design.Identifier}.json");
|
=> Path.Combine(DesignFolder, $"{design.Identifier}.json");
|
||||||
|
|
||||||
public void SaveDesign(Design design)
|
public void SaveDesign(Design design)
|
||||||
=> _framework.RegisterDelayed($"{nameof(SaveDesign)}_{design.Identifier}", () => SaveDesignInternal(design));
|
=> _saveService.QueueSave(design);
|
||||||
|
|
||||||
private void SaveDesignInternal(Design design)
|
private void SaveDesignInternal(Design design)
|
||||||
{
|
{
|
||||||
|
|
@ -133,7 +136,7 @@ public partial class Design
|
||||||
{
|
{
|
||||||
var text = File.ReadAllText(file.FullName);
|
var text = File.ReadAllText(file.FullName);
|
||||||
var data = JObject.Parse(text);
|
var data = JObject.Parse(text);
|
||||||
var design = LoadDesign(data, out var changes);
|
var design = LoadDesign(_items, data, out var changes);
|
||||||
if (design.Identifier.ToString() != Path.GetFileNameWithoutExtension(file.Name))
|
if (design.Identifier.ToString() != Path.GetFileNameWithoutExtension(file.Name))
|
||||||
invalidNames.Add((design, file.FullName));
|
invalidNames.Add((design, file.FullName));
|
||||||
if (_designs.Any(f => f.Identifier == design.Identifier))
|
if (_designs.Any(f => f.Identifier == design.Identifier))
|
||||||
|
|
@ -177,7 +180,7 @@ public partial class Design
|
||||||
|
|
||||||
public Design Create(string name)
|
public Design Create(string name)
|
||||||
{
|
{
|
||||||
var design = new Design()
|
var design = new Design(_items)
|
||||||
{
|
{
|
||||||
CreationDate = DateTimeOffset.UtcNow,
|
CreationDate = DateTimeOffset.UtcNow,
|
||||||
Identifier = CreateNewGuid(),
|
Identifier = CreateNewGuid(),
|
||||||
|
|
@ -297,7 +300,7 @@ public partial class Design
|
||||||
public void ChangeEquip(Design design, EquipSlot slot, uint itemId, Lumina.Excel.GeneratedSheets.Item? item = null)
|
public void ChangeEquip(Design design, EquipSlot slot, uint itemId, Lumina.Excel.GeneratedSheets.Item? item = null)
|
||||||
{
|
{
|
||||||
var old = design.Armor(slot);
|
var old = design.Armor(slot);
|
||||||
if (design.SetArmor(slot, itemId, item))
|
if (design.SetArmor(_items, slot, itemId, item))
|
||||||
{
|
{
|
||||||
var n = design.Armor(slot);
|
var n = design.Armor(slot);
|
||||||
Glamourer.Log.Debug(
|
Glamourer.Log.Debug(
|
||||||
|
|
@ -309,8 +312,8 @@ public partial class Design
|
||||||
public void ChangeWeapon(Design design, uint itemId, EquipSlot offhand, Lumina.Excel.GeneratedSheets.Item? item = null)
|
public void ChangeWeapon(Design design, uint itemId, EquipSlot offhand, Lumina.Excel.GeneratedSheets.Item? item = null)
|
||||||
{
|
{
|
||||||
var (old, change, n) = offhand == EquipSlot.OffHand
|
var (old, change, n) = offhand == EquipSlot.OffHand
|
||||||
? (design.WeaponOff, design.SetOffhand(itemId, item), design.WeaponOff)
|
? (design.WeaponOff, design.SetOffhand(_items, itemId, item), design.WeaponOff)
|
||||||
: (design.WeaponMain, design.SetMainhand(itemId, item), design.WeaponMain);
|
: (design.WeaponMain, design.SetMainhand(_items, itemId, item), design.WeaponMain);
|
||||||
if (change)
|
if (change)
|
||||||
{
|
{
|
||||||
Glamourer.Log.Debug(
|
Glamourer.Log.Debug(
|
||||||
|
|
@ -386,13 +389,13 @@ public partial class Design
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var actualName = Path.GetFileName(name);
|
var actualName = Path.GetFileName(name);
|
||||||
var design = new Design()
|
var design = new Design(_items)
|
||||||
{
|
{
|
||||||
CreationDate = DateTimeOffset.UtcNow,
|
CreationDate = DateTimeOffset.UtcNow,
|
||||||
Identifier = CreateNewGuid(),
|
Identifier = CreateNewGuid(),
|
||||||
Name = actualName,
|
Name = actualName,
|
||||||
};
|
};
|
||||||
design.MigrateBase64(base64);
|
design.MigrateBase64(_items, base64);
|
||||||
Add(design, $"Migrated old design to {design.Identifier}.");
|
Add(design, $"Migrated old design to {design.Identifier}.");
|
||||||
migratedFileSystemPaths.Add(design.Identifier.ToString(), name);
|
migratedFileSystemPaths.Add(design.Identifier.ToString(), name);
|
||||||
++successes;
|
++successes;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Util;
|
using Glamourer.Services;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui;
|
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public partial class Design : DesignBase
|
public partial class Design : DesignBase, ISavable
|
||||||
{
|
{
|
||||||
public const int FileVersion = 1;
|
public const int FileVersion = 1;
|
||||||
|
|
||||||
|
|
@ -69,7 +70,8 @@ public partial class Design : DesignBase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Design()
|
private Design(ItemManager items)
|
||||||
|
: base(items)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public JObject JsonSerialize()
|
public JObject JsonSerialize()
|
||||||
|
|
@ -142,17 +144,17 @@ public partial class Design : DesignBase
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Design LoadDesign(JObject json, out bool changes)
|
public static Design LoadDesign(ItemManager items, JObject json, out bool changes)
|
||||||
{
|
{
|
||||||
var version = json[nameof(FileVersion)]?.ToObject<int>() ?? 0;
|
var version = json[nameof(FileVersion)]?.ToObject<int>() ?? 0;
|
||||||
return version switch
|
return version switch
|
||||||
{
|
{
|
||||||
1 => LoadDesignV1(json, out changes),
|
1 => LoadDesignV1(items, json, out changes),
|
||||||
_ => throw new Exception("The design to be loaded has no valid Version."),
|
_ => throw new Exception("The design to be loaded has no valid Version."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Design LoadDesignV1(JObject json, out bool changes)
|
private static Design LoadDesignV1(ItemManager items, JObject json, out bool changes)
|
||||||
{
|
{
|
||||||
static string[] ParseTags(JObject json)
|
static string[] ParseTags(JObject json)
|
||||||
{
|
{
|
||||||
|
|
@ -160,7 +162,7 @@ public partial class Design : DesignBase
|
||||||
return tags.OrderBy(t => t).Distinct().ToArray();
|
return tags.OrderBy(t => t).Distinct().ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var design = new Design()
|
var design = new Design(items)
|
||||||
{
|
{
|
||||||
CreationDate = json["CreationDate"]?.ToObject<DateTimeOffset>() ?? throw new ArgumentNullException("CreationDate"),
|
CreationDate = json["CreationDate"]?.ToObject<DateTimeOffset>() ?? throw new ArgumentNullException("CreationDate"),
|
||||||
Identifier = json["Identifier"]?.ToObject<Guid>() ?? throw new ArgumentNullException("Identifier"),
|
Identifier = json["Identifier"]?.ToObject<Guid>() ?? throw new ArgumentNullException("Identifier"),
|
||||||
|
|
@ -169,12 +171,12 @@ public partial class Design : DesignBase
|
||||||
Tags = ParseTags(json),
|
Tags = ParseTags(json),
|
||||||
};
|
};
|
||||||
|
|
||||||
changes = LoadEquip(json["Equipment"], design);
|
changes = LoadEquip(items, json["Equipment"], design);
|
||||||
changes |= LoadCustomize(json["Customize"], design);
|
changes |= LoadCustomize(json["Customize"], design);
|
||||||
return design;
|
return design;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool LoadEquip(JToken? equip, Design design)
|
private static bool LoadEquip(ItemManager items, JToken? equip, Design design)
|
||||||
{
|
{
|
||||||
if (equip == null)
|
if (equip == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -192,7 +194,7 @@ public partial class Design : DesignBase
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
{
|
{
|
||||||
var (id, stain, apply, applyStain) = ParseItem(slot, equip[slot.ToString()]);
|
var (id, stain, apply, applyStain) = ParseItem(slot, equip[slot.ToString()]);
|
||||||
changes |= !design.SetArmor(slot, id);
|
changes |= !design.SetArmor(items, slot, id);
|
||||||
changes |= !design.SetStain(slot, stain);
|
changes |= !design.SetStain(slot, stain);
|
||||||
design.SetApplyEquip(slot, apply);
|
design.SetApplyEquip(slot, apply);
|
||||||
design.SetApplyStain(slot, applyStain);
|
design.SetApplyStain(slot, applyStain);
|
||||||
|
|
@ -205,11 +207,11 @@ public partial class Design : DesignBase
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var id = main["ItemId"]?.ToObject<uint>() ?? Glamourer.Items.DefaultSword.RowId;
|
var id = main["ItemId"]?.ToObject<uint>() ?? items.DefaultSword.RowId;
|
||||||
var stain = (StainId)(main["Stain"]?.ToObject<byte>() ?? 0);
|
var stain = (StainId)(main["Stain"]?.ToObject<byte>() ?? 0);
|
||||||
var apply = main["Apply"]?.ToObject<bool>() ?? false;
|
var apply = main["Apply"]?.ToObject<bool>() ?? false;
|
||||||
var applyStain = main["ApplyStain"]?.ToObject<bool>() ?? false;
|
var applyStain = main["ApplyStain"]?.ToObject<bool>() ?? false;
|
||||||
changes |= !design.SetMainhand(id);
|
changes |= !design.SetMainhand(items, id);
|
||||||
changes |= !design.SetStain(EquipSlot.MainHand, stain);
|
changes |= !design.SetStain(EquipSlot.MainHand, stain);
|
||||||
design.SetApplyEquip(EquipSlot.MainHand, apply);
|
design.SetApplyEquip(EquipSlot.MainHand, apply);
|
||||||
design.SetApplyStain(EquipSlot.MainHand, applyStain);
|
design.SetApplyStain(EquipSlot.MainHand, applyStain);
|
||||||
|
|
@ -226,7 +228,7 @@ public partial class Design : DesignBase
|
||||||
var stain = (StainId)(off["Stain"]?.ToObject<byte>() ?? 0);
|
var stain = (StainId)(off["Stain"]?.ToObject<byte>() ?? 0);
|
||||||
var apply = off["Apply"]?.ToObject<bool>() ?? false;
|
var apply = off["Apply"]?.ToObject<bool>() ?? false;
|
||||||
var applyStain = off["ApplyStain"]?.ToObject<bool>() ?? false;
|
var applyStain = off["ApplyStain"]?.ToObject<bool>() ?? false;
|
||||||
changes |= !design.SetOffhand(id);
|
changes |= !design.SetOffhand(items, id);
|
||||||
changes |= !design.SetStain(EquipSlot.OffHand, stain);
|
changes |= !design.SetStain(EquipSlot.OffHand, stain);
|
||||||
design.SetApplyEquip(EquipSlot.OffHand, apply);
|
design.SetApplyEquip(EquipSlot.OffHand, apply);
|
||||||
design.SetApplyStain(EquipSlot.OffHand, applyStain);
|
design.SetApplyStain(EquipSlot.OffHand, applyStain);
|
||||||
|
|
@ -259,14 +261,14 @@ public partial class Design : DesignBase
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MigrateBase64(string base64)
|
public void MigrateBase64(ItemManager items, string base64)
|
||||||
{
|
{
|
||||||
var data = MigrateBase64(base64, out var applyEquip, out var applyCustomize, out var writeProtected, out var wet, out var hat,
|
var data = MigrateBase64(base64, out var applyEquip, out var applyCustomize, out var writeProtected, out var wet, out var hat,
|
||||||
out var visor, out var weapon);
|
out var visor, out var weapon);
|
||||||
UpdateMainhand(data.MainHand);
|
UpdateMainhand(items, data.MainHand);
|
||||||
UpdateMainhand(data.OffHand);
|
UpdateOffhand(items, data.OffHand);
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
UpdateArmor(slot, data.Equipment[slot], true);
|
UpdateArmor(items, slot, data.Equipment[slot], true);
|
||||||
CharacterData.CustomizeData = data.CustomizeData;
|
CharacterData.CustomizeData = data.CustomizeData;
|
||||||
ApplyEquip = applyEquip;
|
ApplyEquip = applyEquip;
|
||||||
ApplyCustomize = applyCustomize;
|
ApplyCustomize = applyCustomize;
|
||||||
|
|
@ -277,10 +279,10 @@ public partial class Design : DesignBase
|
||||||
Weapon = weapon;
|
Weapon = weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Design CreateTemporaryFromBase64(string base64, bool customize, bool equip)
|
public static Design CreateTemporaryFromBase64(ItemManager items, string base64, bool customize, bool equip)
|
||||||
{
|
{
|
||||||
var ret = new Design();
|
var ret = new Design(items);
|
||||||
ret.MigrateBase64(base64);
|
ret.MigrateBase64(items, base64);
|
||||||
if (!customize)
|
if (!customize)
|
||||||
ret.ApplyCustomize = 0;
|
ret.ApplyCustomize = 0;
|
||||||
if (!equip)
|
if (!equip)
|
||||||
|
|
@ -296,4 +298,20 @@ public partial class Design : DesignBase
|
||||||
public string CreateOldBase64()
|
public string CreateOldBase64()
|
||||||
=> CreateOldBase64(in CharacterData, ApplyEquip, ApplyCustomize, Wetness == QuadBool.True, Hat.ForcedValue, Hat.Enabled,
|
=> CreateOldBase64(in CharacterData, ApplyEquip, ApplyCustomize, Wetness == QuadBool.True, Hat.ForcedValue, Hat.Enabled,
|
||||||
Visor.ForcedValue, Visor.Enabled, Weapon.ForcedValue, Weapon.Enabled, WriteProtected, 1f);
|
Visor.ForcedValue, Visor.Enabled, Weapon.ForcedValue, Weapon.Enabled, WriteProtected, 1f);
|
||||||
|
|
||||||
|
public string ToFilename(FilenameService fileNames)
|
||||||
|
=> fileNames.DesignFile(this);
|
||||||
|
|
||||||
|
public void Save(StreamWriter writer)
|
||||||
|
{
|
||||||
|
using var j = new JsonTextWriter(writer)
|
||||||
|
{
|
||||||
|
Formatting = Formatting.Indented,
|
||||||
|
};
|
||||||
|
var obj = JsonSerialize();
|
||||||
|
obj.WriteTo(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LogName(string fileName)
|
||||||
|
=> Path.GetFileNameWithoutExtension(fileName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.Util;
|
using Glamourer.Util;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -45,14 +46,14 @@ public class DesignBase
|
||||||
public CharacterEquip Equipment()
|
public CharacterEquip Equipment()
|
||||||
=> CharacterData.Equipment;
|
=> CharacterData.Equipment;
|
||||||
|
|
||||||
public DesignBase()
|
public DesignBase(ItemManager items)
|
||||||
{
|
{
|
||||||
MainHand = Glamourer.Items.DefaultSword.RowId;
|
MainHand = items.DefaultSword.RowId;
|
||||||
(_, CharacterData.MainHand.Set, CharacterData.MainHand.Type, CharacterData.MainHand.Variant, MainhandName, MainhandType) =
|
(_, CharacterData.MainHand.Set, CharacterData.MainHand.Type, CharacterData.MainHand.Variant, MainhandName, MainhandType) =
|
||||||
Glamourer.Items.Resolve(MainHand, Glamourer.Items.DefaultSword);
|
items.Resolve(MainHand, items.DefaultSword);
|
||||||
OffHand = ItemManager.NothingId(MainhandType.Offhand());
|
OffHand = ItemManager.NothingId(MainhandType.Offhand());
|
||||||
(_, CharacterData.OffHand.Set, CharacterData.OffHand.Type, CharacterData.OffHand.Variant, OffhandName, _) =
|
(_, CharacterData.OffHand.Set, CharacterData.OffHand.Type, CharacterData.OffHand.Variant, OffhandName, _) =
|
||||||
Glamourer.Items.Resolve(OffHand, MainhandType);
|
items.Resolve(OffHand, MainhandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint ModelId
|
public uint ModelId
|
||||||
|
|
@ -96,9 +97,9 @@ public class DesignBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool SetArmor(EquipSlot slot, uint itemId, Lumina.Excel.GeneratedSheets.Item? item = null)
|
protected bool SetArmor(ItemManager items, EquipSlot slot, uint itemId, Lumina.Excel.GeneratedSheets.Item? item = null)
|
||||||
{
|
{
|
||||||
var (valid, set, variant, name) = Glamourer.Items.Resolve(slot, itemId, item);
|
var (valid, set, variant, name) = items.Resolve(slot, itemId, item);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -108,7 +109,7 @@ public class DesignBase
|
||||||
protected bool SetArmor(EquipSlot slot, Item item)
|
protected bool SetArmor(EquipSlot slot, Item item)
|
||||||
=> SetArmor(slot, item.ModelBase, item.Variant, item.Name, item.ItemId);
|
=> SetArmor(slot, item.ModelBase, item.Variant, item.Name, item.ItemId);
|
||||||
|
|
||||||
protected bool UpdateArmor(EquipSlot slot, CharacterArmor armor, bool force)
|
protected bool UpdateArmor(ItemManager items, EquipSlot slot, CharacterArmor armor, bool force)
|
||||||
{
|
{
|
||||||
if (!force)
|
if (!force)
|
||||||
switch (slot)
|
switch (slot)
|
||||||
|
|
@ -125,19 +126,19 @@ public class DesignBase
|
||||||
case EquipSlot.LFinger when CharacterData.LFinger.Value == armor.Value: return false;
|
case EquipSlot.LFinger when CharacterData.LFinger.Value == armor.Value: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (valid, id, name) = Glamourer.Items.Identify(slot, armor.Set, armor.Variant);
|
var (valid, id, name) = items.Identify(slot, armor.Set, armor.Variant);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return SetArmor(slot, armor.Set, armor.Variant, name, id);
|
return SetArmor(slot, armor.Set, armor.Variant, name, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool SetMainhand(uint mainId, Lumina.Excel.GeneratedSheets.Item? main = null)
|
protected bool SetMainhand(ItemManager items, uint mainId, Lumina.Excel.GeneratedSheets.Item? main = null)
|
||||||
{
|
{
|
||||||
if (mainId == MainHand)
|
if (mainId == MainHand)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var (valid, set, weapon, variant, name, type) = Glamourer.Items.Resolve(mainId, main);
|
var (valid, set, weapon, variant, name, type) = items.Resolve(mainId, main);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -150,16 +151,16 @@ public class DesignBase
|
||||||
CharacterData.MainHand.Type = weapon;
|
CharacterData.MainHand.Type = weapon;
|
||||||
CharacterData.MainHand.Variant = variant;
|
CharacterData.MainHand.Variant = variant;
|
||||||
if (fixOffhand)
|
if (fixOffhand)
|
||||||
SetOffhand(ItemManager.NothingId(type.Offhand()));
|
SetOffhand(items, ItemManager.NothingId(type.Offhand()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool SetOffhand(uint offId, Lumina.Excel.GeneratedSheets.Item? off = null)
|
protected bool SetOffhand(ItemManager items, uint offId, Lumina.Excel.GeneratedSheets.Item? off = null)
|
||||||
{
|
{
|
||||||
if (offId == OffHand)
|
if (offId == OffHand)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var (valid, set, weapon, variant, name, type) = Glamourer.Items.Resolve(offId, MainhandType, off);
|
var (valid, set, weapon, variant, name, type) = items.Resolve(offId, MainhandType, off);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -171,12 +172,12 @@ public class DesignBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool UpdateMainhand(CharacterWeapon weapon)
|
protected bool UpdateMainhand(ItemManager items, CharacterWeapon weapon)
|
||||||
{
|
{
|
||||||
if (weapon.Value == CharacterData.MainHand.Value)
|
if (weapon.Value == CharacterData.MainHand.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var (valid, id, name, type) = Glamourer.Items.Identify(EquipSlot.MainHand, weapon.Set, weapon.Type, (byte)weapon.Variant);
|
var (valid, id, name, type) = items.Identify(EquipSlot.MainHand, weapon.Set, weapon.Type, (byte)weapon.Variant);
|
||||||
if (!valid || id == MainHand)
|
if (!valid || id == MainHand)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -190,16 +191,16 @@ public class DesignBase
|
||||||
CharacterData.MainHand.Variant = weapon.Variant;
|
CharacterData.MainHand.Variant = weapon.Variant;
|
||||||
CharacterData.MainHand.Stain = weapon.Stain;
|
CharacterData.MainHand.Stain = weapon.Stain;
|
||||||
if (fixOffhand)
|
if (fixOffhand)
|
||||||
SetOffhand(ItemManager.NothingId(type.Offhand()));
|
SetOffhand(items, ItemManager.NothingId(type.Offhand()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool UpdateOffhand(CharacterWeapon weapon)
|
protected bool UpdateOffhand(ItemManager items, CharacterWeapon weapon)
|
||||||
{
|
{
|
||||||
if (weapon.Value == CharacterData.OffHand.Value)
|
if (weapon.Value == CharacterData.OffHand.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var (valid, id, name, _) = Glamourer.Items.Identify(EquipSlot.OffHand, weapon.Set, weapon.Type, (byte)weapon.Variant, MainhandType);
|
var (valid, id, name, _) = items.Identify(EquipSlot.OffHand, weapon.Set, weapon.Type, (byte)weapon.Variant, MainhandType);
|
||||||
if (!valid || id == OffHand)
|
if (!valid || id == OffHand)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using Glamourer.Services;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
|
|
@ -12,20 +13,20 @@ using OtterGui.Filesystem;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public sealed class DesignFileSystem : FileSystem<Design>, IDisposable
|
public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
||||||
{
|
{
|
||||||
public static string GetDesignFileSystemFile(DalamudPluginInterface pi)
|
public static string GetDesignFileSystemFile(DalamudPluginInterface pi)
|
||||||
=> Path.Combine(pi.GetPluginConfigDirectory(), "sort_order.json");
|
=> Path.Combine(pi.GetPluginConfigDirectory(), "sort_order.json");
|
||||||
|
|
||||||
public readonly string DesignFileSystemFile;
|
public readonly string DesignFileSystemFile;
|
||||||
private readonly FrameworkManager _framework;
|
private readonly SaveService _saveService;
|
||||||
private readonly Design.Manager _designManager;
|
private readonly Design.Manager _designManager;
|
||||||
|
|
||||||
public DesignFileSystem(Design.Manager designManager, DalamudPluginInterface pi, FrameworkManager framework)
|
public DesignFileSystem(Design.Manager designManager, DalamudPluginInterface pi, SaveService saveService)
|
||||||
{
|
{
|
||||||
DesignFileSystemFile = GetDesignFileSystemFile(pi);
|
DesignFileSystemFile = GetDesignFileSystemFile(pi);
|
||||||
_designManager = designManager;
|
_designManager = designManager;
|
||||||
_framework = framework;
|
_saveService = saveService;
|
||||||
_designManager.DesignChange += OnDataChange;
|
_designManager.DesignChange += OnDataChange;
|
||||||
Changed += OnChange;
|
Changed += OnChange;
|
||||||
Reload();
|
Reload();
|
||||||
|
|
@ -34,7 +35,7 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable
|
||||||
private void Reload()
|
private void Reload()
|
||||||
{
|
{
|
||||||
if (Load(new FileInfo(DesignFileSystemFile), _designManager.Designs, DesignToIdentifier, DesignToName))
|
if (Load(new FileInfo(DesignFileSystemFile), _designManager.Designs, DesignToIdentifier, DesignToName))
|
||||||
SaveFilesystem();
|
_saveService.ImmediateSave(this);
|
||||||
|
|
||||||
Glamourer.Log.Debug("Reloaded design filesystem.");
|
Glamourer.Log.Debug("Reloaded design filesystem.");
|
||||||
}
|
}
|
||||||
|
|
@ -71,18 +72,9 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable
|
||||||
private void OnChange(FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3)
|
private void OnChange(FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3)
|
||||||
{
|
{
|
||||||
if (type != FileSystemChangeType.Reload)
|
if (type != FileSystemChangeType.Reload)
|
||||||
SaveFilesystem();
|
_saveService.QueueSave(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveFilesystem()
|
|
||||||
{
|
|
||||||
SaveToFile(new FileInfo(DesignFileSystemFile), SaveDesign, true);
|
|
||||||
Glamourer.Log.Verbose("Saved design filesystem.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save()
|
|
||||||
=> _framework.RegisterDelayed(nameof(SaveFilesystem), SaveFilesystem);
|
|
||||||
|
|
||||||
private void OnDataChange(Design.Manager.DesignChangeType type, Design design, object? data)
|
private void OnDataChange(Design.Manager.DesignChangeType type, Design design, object? data)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|
@ -176,4 +168,12 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable
|
||||||
Glamourer.Log.Error($"Could not migrate old folder paths to new version:\n{ex}");
|
Glamourer.Log.Error($"Could not migrate old folder paths to new version:\n{ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ToFilename(FilenameService fileNames)
|
||||||
|
=> fileNames.DesignFileSystem;
|
||||||
|
|
||||||
|
public void Save(StreamWriter writer)
|
||||||
|
{
|
||||||
|
SaveToFile(writer, SaveDesign, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using Glamourer.Api;
|
using Glamourer.Api;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Glamourer.Util;
|
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||||
|
|
@ -15,12 +14,12 @@ namespace Glamourer;
|
||||||
public class DrawObjectManager : IDisposable
|
public class DrawObjectManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly ItemManager _items;
|
private readonly ItemManager _items;
|
||||||
private readonly ActorManager _actors;
|
private readonly ActorService _actors;
|
||||||
private readonly ActiveDesign.Manager _manager;
|
private readonly ActiveDesign.Manager _manager;
|
||||||
private readonly Interop.Interop _interop;
|
private readonly Interop.Interop _interop;
|
||||||
private readonly PenumbraAttach _penumbra;
|
private readonly PenumbraAttach _penumbra;
|
||||||
|
|
||||||
public DrawObjectManager(ItemManager items, ActorManager actors, ActiveDesign.Manager manager, Interop.Interop interop,
|
public DrawObjectManager(ItemManager items, ActorService actors, ActiveDesign.Manager manager, Interop.Interop interop,
|
||||||
PenumbraAttach penumbra)
|
PenumbraAttach penumbra)
|
||||||
{
|
{
|
||||||
_items = items;
|
_items = items;
|
||||||
|
|
@ -54,7 +53,7 @@ public class DrawObjectManager : IDisposable
|
||||||
if (gameObject.ModelId != modelId)
|
if (gameObject.ModelId != modelId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var identifier = _actors.FromObject((GameObject*)gameObjectPtr, out _, true, true, false);
|
var identifier = _actors.AwaitedService.FromObject((GameObject*)gameObjectPtr, out _, true, true, false);
|
||||||
if (!identifier.IsValid || !_manager.TryGetValue(identifier, out var design))
|
if (!identifier.IsValid || !_manager.TryGetValue(identifier, out var design))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -75,7 +74,7 @@ public class DrawObjectManager : IDisposable
|
||||||
foreach (var slot in EquipSlotExtensions.EquipmentSlots)
|
foreach (var slot in EquipSlotExtensions.EquipmentSlots)
|
||||||
{
|
{
|
||||||
(_, equip[slot]) =
|
(_, equip[slot]) =
|
||||||
Glamourer.Items.ResolveRestrictedGear(saveEquip[slot], slot, customize.Race, customize.Gender);
|
_items.ResolveRestrictedGear(saveEquip[slot], slot, customize.Race, customize.Gender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,15 @@ public struct FixedCondition
|
||||||
|
|
||||||
public bool Check(Actor actor)
|
public bool Check(Actor actor)
|
||||||
{
|
{
|
||||||
if ((_data & (_territoryFlag | _jobFlag)) == 0)
|
//if ((_data & (_territoryFlag | _jobFlag)) == 0)
|
||||||
return true;
|
// return true;
|
||||||
|
//
|
||||||
if ((_data & _territoryFlag) != 0)
|
//if ((_data & _territoryFlag) != 0)
|
||||||
return Dalamud.ClientState.TerritoryType == (ushort)_data;
|
// return Dalamud.ClientState.TerritoryType == (ushort)_data;
|
||||||
|
//
|
||||||
if (actor && GameData.JobGroups(Dalamud.GameData).TryGetValue((ushort)_data, out var group) && group.Fits(actor.Job))
|
//if (actor && GameData.JobGroups(Dalamud.GameData).TryGetValue((ushort)_data, out var group) && group.Fits(actor.Job))
|
||||||
return true;
|
// return true;
|
||||||
|
//
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,15 @@
|
||||||
using System.Collections.Generic;
|
using System.Reflection;
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using Dalamud.Game.Command;
|
|
||||||
using Dalamud.Interface.Windowing;
|
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Glamourer.Api;
|
|
||||||
using Glamourer.Customization;
|
|
||||||
using Glamourer.Designs;
|
|
||||||
using Glamourer.Gui;
|
using Glamourer.Gui;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Glamourer.Util;
|
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Log;
|
using OtterGui.Log;
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
using FixedDesigns = Glamourer.State.FixedDesigns;
|
|
||||||
|
|
||||||
namespace Glamourer;
|
namespace Glamourer;
|
||||||
|
|
||||||
public partial class Glamourer : IDalamudPlugin
|
public partial class Glamourer : IDalamudPlugin
|
||||||
{
|
{
|
||||||
private const string HelpString = "[Copy|Apply|Save],[Name or PlaceHolder],<Name for Save>";
|
|
||||||
private const string MainCommandString = "/glamourer";
|
|
||||||
private const string ApplyCommandString = "/glamour";
|
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
=> "Glamourer";
|
=> "Glamourer";
|
||||||
|
|
||||||
|
|
@ -33,73 +19,20 @@ public partial class Glamourer : IDalamudPlugin
|
||||||
Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "Unknown";
|
Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "Unknown";
|
||||||
|
|
||||||
|
|
||||||
public static GlamourerConfig Config = null!;
|
public static readonly Logger Log = new();
|
||||||
public static Logger Log = null!;
|
public static ChatService ChatService { get; private set; } = null!;
|
||||||
public static ActorManager Actors = null!;
|
private readonly ServiceProvider _services;
|
||||||
public static ICustomizationManager Customization = null!;
|
|
||||||
public static RedrawManager RedrawManager = null!;
|
|
||||||
public static ItemManager Items = null!;
|
|
||||||
public readonly FixedDesigns FixedDesigns;
|
|
||||||
|
|
||||||
private readonly Interop.Interop _interop;
|
|
||||||
private readonly PenumbraAttach _penumbra;
|
|
||||||
private readonly ObjectManager _objectManager;
|
|
||||||
private readonly Design.Manager _designManager;
|
|
||||||
private readonly ActiveDesign.Manager _stateManager;
|
|
||||||
private readonly DrawObjectManager _drawObjectManager;
|
|
||||||
private readonly DesignFileSystem _fileSystem;
|
|
||||||
private readonly FrameworkManager _framework;
|
|
||||||
private readonly WindowSystem _windowSystem = new("Glamourer");
|
|
||||||
private readonly Interface _interface;
|
|
||||||
|
|
||||||
//public readonly DesignManager Designs;
|
|
||||||
|
|
||||||
//public static RevertableDesigns RevertableDesigns = new();
|
|
||||||
public readonly GlamourerIpc Ipc;
|
|
||||||
|
|
||||||
public Glamourer(DalamudPluginInterface pluginInterface)
|
public Glamourer(DalamudPluginInterface pluginInterface)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Dalamud.Initialize(pluginInterface);
|
_services = ServiceManager.CreateProvider(pluginInterface, Log);
|
||||||
Log = new Logger();
|
ChatService = _services.GetRequiredService<ChatService>();
|
||||||
_framework = new FrameworkManager(Dalamud.Framework, Log);
|
_services.GetRequiredService<BackupService>();
|
||||||
_interop = new Interop.Interop();
|
_services.GetRequiredService<GlamourerWindowSystem>();
|
||||||
_penumbra = new PenumbraAttach();
|
_services.GetRequiredService<CommandService>();
|
||||||
|
_services.GetRequiredService<GlamourerIpc>();
|
||||||
Items = new ItemManager(Dalamud.PluginInterface, Dalamud.GameData);
|
|
||||||
Customization = CustomizationManager.Create(Dalamud.PluginInterface, Dalamud.GameData);
|
|
||||||
|
|
||||||
Backup.CreateBackup(pluginInterface.ConfigDirectory, BackupFiles(Dalamud.PluginInterface));
|
|
||||||
Config = GlamourerConfig.Load();
|
|
||||||
|
|
||||||
_objectManager = new ObjectManager(Dalamud.Framework, Dalamud.ClientState, Dalamud.Objects);
|
|
||||||
Actors = new ActorManager(Dalamud.PluginInterface, Dalamud.Objects, Dalamud.ClientState, Dalamud.Framework, Dalamud.GameData,
|
|
||||||
Dalamud.GameGui, i => (short)_penumbra.CutsceneParent(i));
|
|
||||||
|
|
||||||
|
|
||||||
_designManager = new Design.Manager(Dalamud.PluginInterface, _framework);
|
|
||||||
_fileSystem = new DesignFileSystem(_designManager, Dalamud.PluginInterface, _framework);
|
|
||||||
FixedDesigns = new FixedDesigns();
|
|
||||||
_stateManager = new ActiveDesign.Manager(Actors, _objectManager, _interop, _penumbra);
|
|
||||||
|
|
||||||
//GlamourerIpc = new GlamourerIpc(Dalamud.ClientState, Dalamud.Objects, Dalamud.PluginInterface);
|
|
||||||
RedrawManager = new RedrawManager(FixedDesigns, _stateManager);
|
|
||||||
_drawObjectManager = new DrawObjectManager(Items, Actors, _stateManager, _interop, _penumbra);
|
|
||||||
|
|
||||||
Dalamud.Commands.AddHandler(MainCommandString, new CommandInfo(OnGlamourer)
|
|
||||||
{
|
|
||||||
HelpMessage = "Open or close the Glamourer window.",
|
|
||||||
});
|
|
||||||
Dalamud.Commands.AddHandler(ApplyCommandString, new CommandInfo(OnGlamour)
|
|
||||||
{
|
|
||||||
HelpMessage = $"Use Glamourer Functions: {HelpString}",
|
|
||||||
});
|
|
||||||
|
|
||||||
_interface = new Interface(Dalamud.PluginInterface, Items, _stateManager, _designManager, _fileSystem, _objectManager);
|
|
||||||
_windowSystem.AddWindow(_interface);
|
|
||||||
Dalamud.PluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
|
||||||
Ipc = new GlamourerIpc(this, Dalamud.ClientState, Dalamud.Objects, Dalamud.PluginInterface);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
@ -111,25 +44,9 @@ public partial class Glamourer : IDalamudPlugin
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Ipc?.Dispose();
|
_services?.Dispose();
|
||||||
_drawObjectManager?.Dispose();
|
|
||||||
RedrawManager?.Dispose();
|
|
||||||
if (_windowSystem != null)
|
|
||||||
Dalamud.PluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
|
||||||
_interface?.Dispose();
|
|
||||||
_fileSystem?.Dispose();
|
|
||||||
//GlamourerIpc.Dispose();
|
|
||||||
_interop?.Dispose();
|
|
||||||
_penumbra?.Dispose();
|
|
||||||
_framework?.Dispose();
|
|
||||||
Items?.Dispose();
|
|
||||||
Dalamud.Commands.RemoveHandler(ApplyCommandString);
|
|
||||||
Dalamud.Commands.RemoveHandler(MainCommandString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGlamourer(string command, string arguments)
|
|
||||||
=> _interface.Toggle();
|
|
||||||
|
|
||||||
//private static GameObject? GetPlayer(string name)
|
//private static GameObject? GetPlayer(string name)
|
||||||
//{
|
//{
|
||||||
// var lowerName = name.ToLowerInvariant();
|
// var lowerName = name.ToLowerInvariant();
|
||||||
|
|
@ -262,25 +179,4 @@ public partial class Glamourer : IDalamudPlugin
|
||||||
// return;
|
// return;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all relevant files for glamourer configuration.
|
|
||||||
private static IReadOnlyList<FileInfo> BackupFiles(DalamudPluginInterface pi)
|
|
||||||
{
|
|
||||||
var list = new List<FileInfo>(16)
|
|
||||||
{
|
|
||||||
pi.ConfigFile,
|
|
||||||
new(DesignFileSystem.GetDesignFileSystemFile(pi)),
|
|
||||||
};
|
|
||||||
|
|
||||||
var configDir = Dalamud.PluginInterface.ConfigDirectory;
|
|
||||||
if (Directory.Exists(configDir.FullName))
|
|
||||||
{
|
|
||||||
list.Add(new FileInfo(Path.Combine(configDir.FullName, "Designs.json"))); // migration
|
|
||||||
var designDir = new DirectoryInfo(Path.Combine(configDir.FullName, Design.Manager.DesignFolderName));
|
|
||||||
if (designDir.Exists)
|
|
||||||
list.AddRange(designDir.EnumerateFiles("*.json", SearchOption.TopDirectoryOnly));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@
|
||||||
<ProjectReference Include="..\Glamourer.GameData\Glamourer.GameData.csproj" />
|
<ProjectReference Include="..\Glamourer.GameData\Glamourer.GameData.csproj" />
|
||||||
<ProjectReference Include="..\..\Penumbra\Penumbra.Api\Penumbra.Api.csproj" />
|
<ProjectReference Include="..\..\Penumbra\Penumbra.Api\Penumbra.Api.csproj" />
|
||||||
<ProjectReference Include="..\..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj" />
|
<ProjectReference Include="..\..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ public partial class CustomizationDrawer
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
using var group = ImRaii.Group();
|
using var group = ImRaii.Group();
|
||||||
DrawRaceCombo();
|
DrawRaceCombo();
|
||||||
var gender = Glamourer.Customization.GetName(CustomName.Gender);
|
var gender = _service.AwaitedService.GetName(CustomName.Gender);
|
||||||
var clan = Glamourer.Customization.GetName(CustomName.Clan);
|
var clan = _service.AwaitedService.GetName(CustomName.Clan);
|
||||||
ImGui.TextUnformatted($"{gender} & {clan}");
|
ImGui.TextUnformatted($"{gender} & {clan}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,20 +39,20 @@ public partial class CustomizationDrawer
|
||||||
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty, icon == FontAwesomeIcon.MarsDouble, true))
|
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty, icon == FontAwesomeIcon.MarsDouble, true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Changed |= _customize.ChangeGender(CharacterEquip.Null, _customize.Gender is Gender.Male ? Gender.Female : Gender.Male);
|
Changed |= _customize.ChangeGender(CharacterEquip.Null, _customize.Gender is Gender.Male ? Gender.Female : Gender.Male, _items, _service.AwaitedService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawRaceCombo()
|
private void DrawRaceCombo()
|
||||||
{
|
{
|
||||||
ImGui.SetNextItemWidth(_raceSelectorWidth);
|
ImGui.SetNextItemWidth(_raceSelectorWidth);
|
||||||
using var combo = ImRaii.Combo("##subRaceCombo", _customize.ClanName());
|
using var combo = ImRaii.Combo("##subRaceCombo", _customize.ClanName(_service.AwaitedService));
|
||||||
if (!combo)
|
if (!combo)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var subRace in Enum.GetValues<SubRace>().Skip(1)) // Skip Unknown
|
foreach (var subRace in Enum.GetValues<SubRace>().Skip(1)) // Skip Unknown
|
||||||
{
|
{
|
||||||
if (ImGui.Selectable(CustomizeExtensions.ClanName(subRace, _customize.Gender), subRace == _customize.Clan))
|
if (ImGui.Selectable(CustomizeExtensions.ClanName(_service.AwaitedService, subRace, _customize.Gender), subRace == _customize.Clan))
|
||||||
Changed |= _customize.ChangeRace(CharacterEquip.Null, subRace);
|
Changed |= _customize.ChangeRace(CharacterEquip.Null, subRace, _items, _service.AwaitedService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public partial class CustomizationDrawer
|
||||||
custom = _set.Data(index, 0);
|
custom = _set.Data(index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var icon = Glamourer.Customization.GetIcon(custom!.Value.IconId);
|
var icon = _service.AwaitedService.GetIcon(custom!.Value.IconId);
|
||||||
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
|
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
|
||||||
ImGui.OpenPopup(IconSelectorPopup);
|
ImGui.OpenPopup(IconSelectorPopup);
|
||||||
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
|
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
|
||||||
|
|
@ -77,13 +77,12 @@ public partial class CustomizationDrawer
|
||||||
if (!popup)
|
if (!popup)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var ret = false;
|
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||||
.Push(ImGuiStyleVar.FrameRounding, 0);
|
.Push(ImGuiStyleVar.FrameRounding, 0);
|
||||||
for (var i = 0; i < _currentCount; ++i)
|
for (var i = 0; i < _currentCount; ++i)
|
||||||
{
|
{
|
||||||
var custom = _set.Data(_currentIndex, i, _customize.Face);
|
var custom = _set.Data(_currentIndex, i, _customize.Face);
|
||||||
var icon = Glamourer.Customization.GetIcon(custom.IconId);
|
var icon = _service.AwaitedService.GetIcon(custom.IconId);
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
|
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
|
||||||
|
|
@ -134,8 +133,8 @@ public partial class CustomizationDrawer
|
||||||
var enabled = _customize.Get(featureIdx) != CustomizeValue.Zero;
|
var enabled = _customize.Get(featureIdx) != CustomizeValue.Zero;
|
||||||
var feature = _set.Data(featureIdx, 0, _customize.Face);
|
var feature = _set.Data(featureIdx, 0, _customize.Face);
|
||||||
var icon = featureIdx == CustomizeIndex.LegacyTattoo
|
var icon = featureIdx == CustomizeIndex.LegacyTattoo
|
||||||
? _legacyTattoo ?? Glamourer.Customization.GetIcon(feature.IconId)
|
? _legacyTattoo ?? _service.AwaitedService.GetIcon(feature.IconId)
|
||||||
: Glamourer.Customization.GetIcon(feature.IconId);
|
: _service.AwaitedService.GetIcon(feature.IconId);
|
||||||
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int)ImGui.GetStyle().FramePadding.X,
|
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int)ImGui.GetStyle().FramePadding.X,
|
||||||
Vector4.Zero, enabled ? Vector4.One : _redTint))
|
Vector4.Zero, enabled ? Vector4.One : _redTint))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Services;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
|
|
@ -40,8 +41,13 @@ public partial class CustomizationDrawer : IDisposable
|
||||||
private float _comboSelectorSize;
|
private float _comboSelectorSize;
|
||||||
private float _raceSelectorWidth;
|
private float _raceSelectorWidth;
|
||||||
|
|
||||||
public CustomizationDrawer(DalamudPluginInterface pi)
|
private readonly CustomizationService _service;
|
||||||
|
private readonly ItemManager _items;
|
||||||
|
|
||||||
|
public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service, ItemManager items)
|
||||||
{
|
{
|
||||||
|
_service = service;
|
||||||
|
_items = items;
|
||||||
_legacyTattoo = GetLegacyTattooIcon(pi);
|
_legacyTattoo = GetLegacyTattooIcon(pi);
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
|
@ -120,7 +126,7 @@ public partial class CustomizationDrawer : IDisposable
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DrawRaceGenderSelector();
|
DrawRaceGenderSelector();
|
||||||
_set = Glamourer.Customization.GetList(_customize.Clan, _customize.Gender);
|
_set = _service.AwaitedService.GetList(_customize.Clan, _customize.Gender);
|
||||||
|
|
||||||
foreach (var id in _set.Order[CharaMakeParams.MenuType.Percentage])
|
foreach (var id in _set.Order[CharaMakeParams.MenuType.Percentage])
|
||||||
PercentageSelector(id);
|
PercentageSelector(id);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using Glamourer.Designs;
|
using System.Numerics;
|
||||||
|
using Dalamud.Game.ClientState.Keys;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Glamourer.Designs;
|
||||||
|
using OtterGui;
|
||||||
using OtterGui.FileSystem.Selector;
|
using OtterGui.FileSystem.Selector;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Designs;
|
namespace Glamourer.Gui.Designs;
|
||||||
|
|
@ -10,11 +14,12 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
|
||||||
public struct DesignState
|
public struct DesignState
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public DesignFileSystemSelector(Design.Manager manager, DesignFileSystem fileSystem)
|
public DesignFileSystemSelector(Design.Manager manager, DesignFileSystem fileSystem, KeyState keyState)
|
||||||
: base(fileSystem, Dalamud.KeyState)
|
: base(fileSystem, keyState)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_manager.DesignChange += OnDesignChange;
|
_manager.DesignChange += OnDesignChange;
|
||||||
|
AddButton(DeleteButton, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
|
|
@ -36,4 +41,19 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DeleteButton(Vector2 size)
|
||||||
|
{
|
||||||
|
var keys = true;
|
||||||
|
var tt = SelectedLeaf == null
|
||||||
|
? "No design selected."
|
||||||
|
: "Delete the currently selected design entirely from your drive.\n"
|
||||||
|
+ "This can not be undone.";
|
||||||
|
//if (!keys)
|
||||||
|
// tt += $"\nHold {_config.DeleteModModifier} while clicking to delete the mod.";
|
||||||
|
|
||||||
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, tt, SelectedLeaf == null || !keys, true)
|
||||||
|
&& Selected != null)
|
||||||
|
_manager.Delete(Selected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Dalamud.Data;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Glamourer.Util;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
|
|
@ -23,27 +24,27 @@ public class EquipmentDrawer
|
||||||
private readonly ItemCombo[] _itemCombo;
|
private readonly ItemCombo[] _itemCombo;
|
||||||
private readonly Dictionary<(FullEquipType, EquipSlot), WeaponCombo> _weaponCombo;
|
private readonly Dictionary<(FullEquipType, EquipSlot), WeaponCombo> _weaponCombo;
|
||||||
|
|
||||||
public EquipmentDrawer(ItemManager items)
|
public EquipmentDrawer(DataManager gameData, ItemManager items)
|
||||||
{
|
{
|
||||||
_items = items;
|
_items = items;
|
||||||
_stainData = items.Stains;
|
_stainData = items.Stains;
|
||||||
_stainCombo = new FilterComboColors(140,
|
_stainCombo = new FilterComboColors(140,
|
||||||
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
|
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
|
||||||
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(items, e)).ToArray();
|
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e)).ToArray();
|
||||||
_weaponCombo = new Dictionary<(FullEquipType, EquipSlot), WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
|
_weaponCombo = new Dictionary<(FullEquipType, EquipSlot), WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
|
||||||
foreach (var type in Enum.GetValues<FullEquipType>())
|
foreach (var type in Enum.GetValues<FullEquipType>())
|
||||||
{
|
{
|
||||||
if (type.ToSlot() is EquipSlot.MainHand)
|
if (type.ToSlot() is EquipSlot.MainHand)
|
||||||
_weaponCombo.TryAdd((type, EquipSlot.MainHand), new WeaponCombo(items, type, EquipSlot.MainHand));
|
_weaponCombo.TryAdd((type, EquipSlot.MainHand), new WeaponCombo(gameData, items, type, EquipSlot.MainHand));
|
||||||
else if (type.ToSlot() is EquipSlot.OffHand)
|
else if (type.ToSlot() is EquipSlot.OffHand)
|
||||||
_weaponCombo.TryAdd((type, EquipSlot.OffHand), new WeaponCombo(items, type, EquipSlot.OffHand));
|
_weaponCombo.TryAdd((type, EquipSlot.OffHand), new WeaponCombo(gameData, items, type, EquipSlot.OffHand));
|
||||||
|
|
||||||
var offhand = type.Offhand();
|
var offhand = type.Offhand();
|
||||||
if (offhand is not FullEquipType.Unknown && !_weaponCombo.ContainsKey((offhand, EquipSlot.OffHand)))
|
if (offhand is not FullEquipType.Unknown && !_weaponCombo.ContainsKey((offhand, EquipSlot.OffHand)))
|
||||||
_weaponCombo.TryAdd((offhand, EquipSlot.OffHand), new WeaponCombo(items, type, EquipSlot.OffHand));
|
_weaponCombo.TryAdd((offhand, EquipSlot.OffHand), new WeaponCombo(gameData, items, type, EquipSlot.OffHand));
|
||||||
}
|
}
|
||||||
|
|
||||||
_weaponCombo.Add((FullEquipType.Unknown, EquipSlot.MainHand), new WeaponCombo(items, FullEquipType.Unknown, EquipSlot.MainHand));
|
_weaponCombo.Add((FullEquipType.Unknown, EquipSlot.MainHand), new WeaponCombo(gameData, items, FullEquipType.Unknown, EquipSlot.MainHand));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string VerifyRestrictedGear(Item gear, EquipSlot slot, Gender gender, Race race)
|
private string VerifyRestrictedGear(Item gear, EquipSlot slot, Gender gender, Race race)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Glamourer.Util;
|
using Dalamud.Data;
|
||||||
|
using Glamourer.Designs;
|
||||||
|
using Glamourer.Services;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -17,10 +19,10 @@ public sealed class ItemCombo : FilterComboCache<Item>
|
||||||
public readonly string Label;
|
public readonly string Label;
|
||||||
private uint _currentItem;
|
private uint _currentItem;
|
||||||
|
|
||||||
public ItemCombo(ItemManager items, EquipSlot slot)
|
public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot)
|
||||||
: base(() => GetItems(items, slot))
|
: base(() => GetItems(items, slot))
|
||||||
{
|
{
|
||||||
Label = GetLabel(slot);
|
Label = GetLabel(gameData, slot);
|
||||||
_currentItem = ItemManager.NothingId(slot);
|
_currentItem = ItemManager.NothingId(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,9 +68,9 @@ public sealed class ItemCombo : FilterComboCache<Item>
|
||||||
protected override string ToString(Item obj)
|
protected override string ToString(Item obj)
|
||||||
=> obj.Name;
|
=> obj.Name;
|
||||||
|
|
||||||
private static string GetLabel(EquipSlot slot)
|
private static string GetLabel(DataManager gameData, EquipSlot slot)
|
||||||
{
|
{
|
||||||
var sheet = Dalamud.GameData.GetExcelSheet<Addon>()!;
|
var sheet = gameData.GetExcelSheet<Addon>()!;
|
||||||
|
|
||||||
return slot switch
|
return slot switch
|
||||||
{
|
{
|
||||||
|
|
@ -89,7 +91,7 @@ public sealed class ItemCombo : FilterComboCache<Item>
|
||||||
private static IReadOnlyList<Item> GetItems(ItemManager items, EquipSlot slot)
|
private static IReadOnlyList<Item> GetItems(ItemManager items, EquipSlot slot)
|
||||||
{
|
{
|
||||||
var nothing = ItemManager.NothingItem(slot);
|
var nothing = ItemManager.NothingItem(slot);
|
||||||
if (!items.Items.TryGetValue(slot.ToEquipType(), out var list))
|
if (!items.ItemService.AwaitedService.TryGetValue(slot.ToEquipType(), out var list))
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
nothing,
|
nothing,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Dalamud.Data;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Util;
|
using Glamourer.Services;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -18,9 +19,9 @@ public sealed class WeaponCombo : FilterComboCache<Weapon>
|
||||||
public readonly string Label;
|
public readonly string Label;
|
||||||
private uint _currentItem;
|
private uint _currentItem;
|
||||||
|
|
||||||
public WeaponCombo(ItemManager items, FullEquipType type, EquipSlot offhand)
|
public WeaponCombo(DataManager gameData, ItemManager items, FullEquipType type, EquipSlot offhand)
|
||||||
: base(offhand is EquipSlot.OffHand ? () => GetOff(items, type) : () => GetMain(items, type))
|
: base(offhand is EquipSlot.OffHand ? () => GetOff(items, type) : () => GetMain(items, type))
|
||||||
=> Label = GetLabel(offhand);
|
=> Label = GetLabel(gameData, offhand);
|
||||||
|
|
||||||
protected override void DrawList(float width, float itemHeight)
|
protected override void DrawList(float width, float itemHeight)
|
||||||
{
|
{
|
||||||
|
|
@ -64,9 +65,9 @@ public sealed class WeaponCombo : FilterComboCache<Weapon>
|
||||||
protected override string ToString(Weapon obj)
|
protected override string ToString(Weapon obj)
|
||||||
=> obj.Name;
|
=> obj.Name;
|
||||||
|
|
||||||
private static string GetLabel(EquipSlot offhand)
|
private static string GetLabel(DataManager gameData, EquipSlot offhand)
|
||||||
{
|
{
|
||||||
var sheet = Dalamud.GameData.GetExcelSheet<Addon>()!;
|
var sheet = gameData.GetExcelSheet<Addon>()!;
|
||||||
return offhand is EquipSlot.OffHand
|
return offhand is EquipSlot.OffHand
|
||||||
? sheet.GetRow(739)?.Text.ToString() ?? "Off Hand"
|
? sheet.GetRow(739)?.Text.ToString() ?? "Off Hand"
|
||||||
: sheet.GetRow(738)?.Text.ToString() ?? "Main Hand";
|
: sheet.GetRow(738)?.Text.ToString() ?? "Main Hand";
|
||||||
|
|
@ -77,9 +78,9 @@ public sealed class WeaponCombo : FilterComboCache<Weapon>
|
||||||
var list = new List<Weapon>();
|
var list = new List<Weapon>();
|
||||||
if (type is FullEquipType.Unknown)
|
if (type is FullEquipType.Unknown)
|
||||||
foreach (var t in Enum.GetValues<FullEquipType>().Where(t => t.ToSlot() == EquipSlot.MainHand))
|
foreach (var t in Enum.GetValues<FullEquipType>().Where(t => t.ToSlot() == EquipSlot.MainHand))
|
||||||
list.AddRange(items.Items[t].Select(w => new Weapon(w, false)));
|
list.AddRange(items.ItemService.AwaitedService[t].Select(w => new Weapon(w, false)));
|
||||||
else if (type.ToSlot() is EquipSlot.MainHand)
|
else if (type.ToSlot() is EquipSlot.MainHand)
|
||||||
list.AddRange(items.Items[type].Select(w => new Weapon(w, false)));
|
list.AddRange(items.ItemService.AwaitedService[type].Select(w => new Weapon(w, false)));
|
||||||
list.Sort((w1, w2) => string.CompareOrdinal(w1.Name, w2.Name));
|
list.Sort((w1, w2) => string.CompareOrdinal(w1.Name, w2.Name));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +90,7 @@ public sealed class WeaponCombo : FilterComboCache<Weapon>
|
||||||
if (type.ToSlot() == EquipSlot.OffHand)
|
if (type.ToSlot() == EquipSlot.OffHand)
|
||||||
{
|
{
|
||||||
var nothing = ItemManager.NothingItem(type);
|
var nothing = ItemManager.NothingItem(type);
|
||||||
if (!items.Items.TryGetValue(type, out var list))
|
if (!items.ItemService.AwaitedService.TryGetValue(type, out var list))
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
nothing,
|
nothing,
|
||||||
|
|
@ -97,7 +98,7 @@ public sealed class WeaponCombo : FilterComboCache<Weapon>
|
||||||
|
|
||||||
return list.Select(w => new Weapon(w, true)).OrderBy(w => w.Name).Prepend(nothing).ToList();
|
return list.Select(w => new Weapon(w, true)).OrderBy(w => w.Name).Prepend(nothing).ToList();
|
||||||
}
|
}
|
||||||
else if (items.Items.TryGetValue(type, out var list))
|
else if (items.ItemService.AwaitedService.TryGetValue(type, out var list))
|
||||||
{
|
{
|
||||||
return list.Select(w => new Weapon(w, true)).OrderBy(w => w.Name).ToList();
|
return list.Select(w => new Weapon(w, true)).OrderBy(w => w.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
Glamourer/Gui/GlamourerWindowSystem.cs
Normal file
30
Glamourer/Gui/GlamourerWindowSystem.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
|
||||||
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
|
public class GlamourerWindowSystem : IDisposable
|
||||||
|
{
|
||||||
|
private readonly WindowSystem _windowSystem = new("Glamourer");
|
||||||
|
private readonly UiBuilder _uiBuilder;
|
||||||
|
private readonly Interface _ui;
|
||||||
|
|
||||||
|
public GlamourerWindowSystem(UiBuilder uiBuilder, Interface ui)
|
||||||
|
{
|
||||||
|
_uiBuilder = uiBuilder;
|
||||||
|
_ui = ui;
|
||||||
|
_windowSystem.AddWindow(ui);
|
||||||
|
_uiBuilder.Draw += _windowSystem.Draw;
|
||||||
|
_uiBuilder.OpenConfigUi += _ui.Toggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_uiBuilder.Draw -= _windowSystem.Draw;
|
||||||
|
_uiBuilder.OpenConfigUi -= _ui.Toggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Toggle()
|
||||||
|
=> _ui.Toggle();
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -14,25 +16,32 @@ using ImGui = ImGuiNET.ImGui;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
private class ActorTab
|
private class ActorTab
|
||||||
{
|
{
|
||||||
private readonly Interface _main;
|
private readonly Interface _main;
|
||||||
private readonly ActiveDesign.Manager _activeDesigns;
|
private readonly ActiveDesign.Manager _activeDesigns;
|
||||||
private readonly ObjectManager _objects;
|
private readonly ObjectManager _objects;
|
||||||
|
private readonly TargetManager _targets;
|
||||||
|
private readonly ActorService _actors;
|
||||||
|
private readonly ItemManager _items;
|
||||||
|
|
||||||
public ActorTab(Interface main, ActiveDesign.Manager activeDesigns, ObjectManager objects)
|
public ActorTab(Interface main, ActiveDesign.Manager activeDesigns, ObjectManager objects, TargetManager targets, ActorService actors,
|
||||||
|
ItemManager items)
|
||||||
{
|
{
|
||||||
_main = main;
|
_main = main;
|
||||||
_activeDesigns = activeDesigns;
|
_activeDesigns = activeDesigns;
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
|
_targets = targets;
|
||||||
|
_actors = actors;
|
||||||
|
_items = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
|
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
|
||||||
private ObjectManager.ActorData _currentData = ObjectManager.ActorData.Invalid;
|
private ActorData _currentData = ActorData.Invalid;
|
||||||
private string _currentLabel = string.Empty;
|
private string _currentLabel = string.Empty;
|
||||||
private ActiveDesign? _currentSave;
|
private ActiveDesign? _currentSave;
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
|
|
@ -42,7 +51,7 @@ internal partial class Interface
|
||||||
|
|
||||||
DrawActorSelector();
|
DrawActorSelector();
|
||||||
if (!_objects.TryGetValue(_identifier, out _currentData))
|
if (!_objects.TryGetValue(_identifier, out _currentData))
|
||||||
_currentData = ObjectManager.ActorData.Invalid;
|
_currentData = ActorData.Invalid;
|
||||||
else
|
else
|
||||||
_currentLabel = _currentData.Label;
|
_currentLabel = _currentData.Label;
|
||||||
|
|
||||||
|
|
@ -64,11 +73,12 @@ internal partial class Interface
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_currentData.Valid)
|
if (_currentData.Valid)
|
||||||
_currentSave.Initialize(_currentData.Objects[0]);
|
_currentSave.Initialize(_items, _currentData.Objects[0]);
|
||||||
|
|
||||||
RevertButton();
|
RevertButton();
|
||||||
if (_main._customizationDrawer.Draw(_currentSave.Customize(), _identifier.Type == IdentifierType.Special))
|
if (_main._customizationDrawer.Draw(_currentSave.Customize(), _identifier.Type == IdentifierType.Special))
|
||||||
_activeDesigns.ChangeCustomize(_currentSave, _main._customizationDrawer.Changed, _main._customizationDrawer.CustomizeData, false);
|
_activeDesigns.ChangeCustomize(_currentSave, _main._customizationDrawer.Changed, _main._customizationDrawer.CustomizeData,
|
||||||
|
false);
|
||||||
|
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
{
|
{
|
||||||
|
|
@ -76,7 +86,8 @@ internal partial class Interface
|
||||||
if (_main._equipmentDrawer.DrawStain(current.Stain, slot, out var stain))
|
if (_main._equipmentDrawer.DrawStain(current.Stain, slot, out var stain))
|
||||||
_activeDesigns.ChangeStain(_currentSave, slot, stain.RowIndex, false);
|
_activeDesigns.ChangeStain(_currentSave, slot, stain.RowIndex, false);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (_main._equipmentDrawer.DrawArmor(current, slot, out var armor, _currentSave.Customize().Gender, _currentSave.Customize().Race))
|
if (_main._equipmentDrawer.DrawArmor(current, slot, out var armor, _currentSave.Customize().Gender,
|
||||||
|
_currentSave.Customize().Race))
|
||||||
_activeDesigns.ChangeEquipment(_currentSave, slot, armor, false);
|
_activeDesigns.ChangeEquipment(_currentSave, slot, armor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,9 +106,7 @@ internal partial class Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_main._equipmentDrawer.DrawVisor(_currentSave, out var value))
|
if (_main._equipmentDrawer.DrawVisor(_currentSave, out var value))
|
||||||
{
|
|
||||||
_activeDesigns.ChangeVisor(_currentSave, value, false);
|
_activeDesigns.ChangeVisor(_currentSave, value, false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const uint RedHeaderColor = 0xFF1818C0;
|
private const uint RedHeaderColor = 0xFF1818C0;
|
||||||
|
|
@ -241,10 +250,10 @@ internal partial class Interface
|
||||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckFilter(KeyValuePair<ActorIdentifier, ObjectManager.ActorData> pair)
|
private bool CheckFilter(KeyValuePair<ActorIdentifier, ActorData> pair)
|
||||||
=> _actorFilter.IsEmpty || pair.Value.Label.Contains(_actorFilter.Lower, StringComparison.OrdinalIgnoreCase);
|
=> _actorFilter.IsEmpty || pair.Value.Label.Contains(_actorFilter.Lower, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
private void DrawSelectable(KeyValuePair<ActorIdentifier, ObjectManager.ActorData> pair)
|
private void DrawSelectable(KeyValuePair<ActorIdentifier, ActorData> pair)
|
||||||
{
|
{
|
||||||
var equal = pair.Key.Equals(_identifier);
|
var equal = pair.Key.Equals(_identifier);
|
||||||
if (ImGui.Selectable(pair.Value.Label, equal) && !equal)
|
if (ImGui.Selectable(pair.Value.Label, equal) && !equal)
|
||||||
|
|
@ -263,13 +272,13 @@ internal partial class Interface
|
||||||
|
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
|
||||||
, "Select the local player character.", !_objects.Player, true))
|
, "Select the local player character.", !_objects.Player, true))
|
||||||
_identifier = _objects.Player.GetIdentifier();
|
_identifier = _objects.Player.GetIdentifier(_actors.AwaitedService);
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
Actor targetActor = Dalamud.Targets.Target?.Address;
|
Actor targetActor = _targets.Target?.Address;
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth,
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth,
|
||||||
"Select the current target, if it is in the list.", _objects.IsInGPose || !targetActor, true))
|
"Select the current target, if it is in the list.", _objects.IsInGPose || !targetActor, true))
|
||||||
_identifier = targetActor.GetIdentifier();
|
_identifier = targetActor.GetIdentifier(_actors.AwaitedService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.Util;
|
using Glamourer.Util;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -7,31 +8,34 @@ using OtterGui.Raii;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
private class DebugDataTab
|
private class DebugDataTab
|
||||||
{
|
{
|
||||||
private readonly ICustomizationManager _mg;
|
private readonly CustomizationService _service;
|
||||||
|
|
||||||
public DebugDataTab(ICustomizationManager manager)
|
public DebugDataTab(CustomizationService service)
|
||||||
=> _mg = manager;
|
=> _service = service;
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
|
if (!_service.Valid)
|
||||||
|
return;
|
||||||
|
|
||||||
using var tab = ImRaii.TabItem("Debug");
|
using var tab = ImRaii.TabItem("Debug");
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var clan in _mg.Clans)
|
foreach (var clan in _service.AwaitedService.Clans)
|
||||||
{
|
{
|
||||||
foreach (var gender in _mg.Genders)
|
foreach (var gender in _service.AwaitedService.Genders)
|
||||||
DrawCustomizationInfo(_mg.GetList(clan, gender));
|
DrawCustomizationInfo(_service.AwaitedService.GetList(clan, gender));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DrawCustomizationInfo(CustomizationSet set)
|
public void DrawCustomizationInfo(CustomizationSet set)
|
||||||
{
|
{
|
||||||
if (!ImGui.CollapsingHeader($"{CustomizeExtensions.ClanName(set.Clan, set.Gender)} {set.Gender}"))
|
if (!ImGui.CollapsingHeader($"{CustomizeExtensions.ClanName(_service.AwaitedService, set.Clan, set.Gender)} {set.Gender}"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var table = ImRaii.Table("data", 5);
|
using var table = ImRaii.Table("data", 5);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ using Penumbra.GameData.Actors;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
private class DebugStateTab
|
private class DebugStateTab
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,31 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Dalamud.Game.ClientState.Keys;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Gui.Customization;
|
|
||||||
using Glamourer.Gui.Designs;
|
using Glamourer.Gui.Designs;
|
||||||
using Glamourer.Gui.Equipment;
|
|
||||||
using Glamourer.Interop;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
private class DesignTab : IDisposable
|
private class DesignTab : IDisposable
|
||||||
{
|
{
|
||||||
public readonly DesignFileSystemSelector Selector;
|
public readonly DesignFileSystemSelector Selector;
|
||||||
private readonly Interface _main;
|
private readonly Interface _main;
|
||||||
private readonly DesignFileSystem _fileSystem;
|
private readonly DesignFileSystem _fileSystem;
|
||||||
private readonly Design.Manager _manager;
|
private readonly Design.Manager _manager;
|
||||||
|
|
||||||
public DesignTab(Interface main, Design.Manager manager, DesignFileSystem fileSystem)
|
public DesignTab(Interface main, Design.Manager manager, DesignFileSystem fileSystem, KeyState keyState)
|
||||||
{
|
{
|
||||||
_main = main;
|
_main = main;
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
Selector = new DesignFileSystemSelector(manager, fileSystem);
|
Selector = new DesignFileSystemSelector(manager, fileSystem, keyState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,28 @@
|
||||||
using System;
|
using System;
|
||||||
using Glamourer.State;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
private static void Checkmark(string label, string tooltip, bool value, Action<bool> setter)
|
private void Checkmark(string label, string tooltip, bool value, Action<bool> setter)
|
||||||
{
|
{
|
||||||
if (ImGuiUtil.Checkbox(label, tooltip, value, setter))
|
if (ImGuiUtil.Checkbox(label, tooltip, value, setter))
|
||||||
Glamourer.Config.Save();
|
_config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ChangeAndSave<T>(T value, T currentValue, Action<T> setter) where T : IEquatable<T>
|
private void ChangeAndSave<T>(T value, T currentValue, Action<T> setter) where T : IEquatable<T>
|
||||||
{
|
{
|
||||||
if (value.Equals(currentValue))
|
if (value.Equals(currentValue))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setter(value);
|
setter(value);
|
||||||
Glamourer.Config.Save();
|
_config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawColorPicker(string name, string tooltip, uint value, uint defaultValue, Action<uint> setter)
|
private void DrawColorPicker(string name, string tooltip, uint value, uint defaultValue, Action<uint> setter)
|
||||||
{
|
{
|
||||||
const ImGuiColorEditFlags flags = ImGuiColorEditFlags.AlphaPreviewHalf | ImGuiColorEditFlags.NoInputs;
|
const ImGuiColorEditFlags flags = ImGuiColorEditFlags.AlphaPreviewHalf | ImGuiColorEditFlags.NoInputs;
|
||||||
|
|
||||||
|
|
@ -42,7 +41,7 @@ internal partial class Interface
|
||||||
|
|
||||||
private static void DrawRestorePenumbraButton()
|
private static void DrawRestorePenumbraButton()
|
||||||
{
|
{
|
||||||
const string buttonLabel = "Re-Register Penumbra";
|
//const string buttonLabel = "Re-Register Penumbra";
|
||||||
// TODO
|
// TODO
|
||||||
//if (ImGui.Button(buttonLabel))
|
//if (ImGui.Button(buttonLabel))
|
||||||
// Glamourer.Penumbra.Reattach(true);
|
// Glamourer.Penumbra.Reattach(true);
|
||||||
|
|
@ -51,36 +50,35 @@ internal partial class Interface
|
||||||
// "If Penumbra did not register the functions for some reason, pressing this button might help restore functionality.");
|
// "If Penumbra did not register the functions for some reason, pressing this button might help restore functionality.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawSettingsTab()
|
private void DrawSettingsTab()
|
||||||
{
|
{
|
||||||
using var tab = ImRaii.TabItem("Settings");
|
using var tab = ImRaii.TabItem("Settings");
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var cfg = Glamourer.Config;
|
|
||||||
ImGui.Dummy(_spacing);
|
ImGui.Dummy(_spacing);
|
||||||
|
|
||||||
Checkmark("Folders First", "Sort Folders before all designs instead of lexicographically.", cfg.FoldersFirst,
|
Checkmark("Folders First", "Sort Folders before all designs instead of lexicographically.", _config.FoldersFirst,
|
||||||
v => cfg.FoldersFirst = v);
|
v => _config.FoldersFirst = v);
|
||||||
Checkmark("Color Designs", "Color the names of designs in the selector using the colors from below for the given cases.",
|
Checkmark("Color Designs", "Color the names of designs in the selector using the colors from below for the given cases.",
|
||||||
cfg.ColorDesigns,
|
_config.ColorDesigns,
|
||||||
v => cfg.ColorDesigns = v);
|
v => _config.ColorDesigns = v);
|
||||||
Checkmark("Show Locks", "Write-protected Designs show a lock besides their name in the selector.", cfg.ShowLocks,
|
Checkmark("Show Locks", "Write-protected Designs show a lock besides their name in the selector.", _config.ShowLocks,
|
||||||
v => cfg.ShowLocks = v);
|
v => _config.ShowLocks = v);
|
||||||
DrawRestorePenumbraButton();
|
DrawRestorePenumbraButton();
|
||||||
|
|
||||||
Checkmark("Apply Fixed Designs",
|
Checkmark("Apply Fixed Designs",
|
||||||
"Automatically apply fixed designs to characters and redraw them when anything changes.",
|
"Automatically apply fixed designs to characters and redraw them when anything changes.",
|
||||||
cfg.ApplyFixedDesigns,
|
_config.ApplyFixedDesigns,
|
||||||
v => { cfg.ApplyFixedDesigns = v; });
|
v => { _config.ApplyFixedDesigns = v; });
|
||||||
|
|
||||||
ImGui.Dummy(_spacing);
|
ImGui.Dummy(_spacing);
|
||||||
|
|
||||||
DrawColorPicker("Customization Color", "The color for designs that only apply their character customization.",
|
DrawColorPicker("Customization Color", "The color for designs that only apply their character customization.",
|
||||||
cfg.CustomizationColor, GlamourerConfig.DefaultCustomizationColor, c => cfg.CustomizationColor = c);
|
_config.CustomizationColor, Configuration.DefaultCustomizationColor, c => _config.CustomizationColor = c);
|
||||||
DrawColorPicker("Equipment Color", "The color for designs that only apply some or all of their equipment slots and stains.",
|
DrawColorPicker("Equipment Color", "The color for designs that only apply some or all of their equipment slots and stains.",
|
||||||
cfg.EquipmentColor, GlamourerConfig.DefaultEquipmentColor, c => cfg.EquipmentColor = c);
|
_config.EquipmentColor, Configuration.DefaultEquipmentColor, c => _config.EquipmentColor = c);
|
||||||
DrawColorPicker("State Color", "The color for designs that only apply some state modification.",
|
DrawColorPicker("State Color", "The color for designs that only apply some state modification.",
|
||||||
cfg.StateColor, GlamourerConfig.DefaultStateColor, c => cfg.StateColor = c);
|
_config.StateColor, Configuration.DefaultStateColor, c => _config.StateColor = c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ using ImGuiNET;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
private static Vector2 _spacing = Vector2.Zero;
|
private static Vector2 _spacing = Vector2.Zero;
|
||||||
private static float _actorSelectorWidth;
|
private static float _actorSelectorWidth;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Dalamud.Data;
|
||||||
|
using Dalamud.Game.ClientState.Keys;
|
||||||
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
|
@ -7,43 +10,43 @@ using Glamourer.Designs;
|
||||||
using Glamourer.Gui.Customization;
|
using Glamourer.Gui.Customization;
|
||||||
using Glamourer.Gui.Equipment;
|
using Glamourer.Gui.Equipment;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Glamourer.Util;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface : Window, IDisposable
|
public partial class Interface : Window, IDisposable
|
||||||
{
|
{
|
||||||
private readonly DalamudPluginInterface _pi;
|
private readonly DalamudPluginInterface _pi;
|
||||||
|
|
||||||
private readonly EquipmentDrawer _equipmentDrawer;
|
private readonly EquipmentDrawer _equipmentDrawer;
|
||||||
private readonly CustomizationDrawer _customizationDrawer;
|
private readonly CustomizationDrawer _customizationDrawer;
|
||||||
|
private readonly Configuration _config;
|
||||||
private readonly ActorTab _actorTab;
|
private readonly ActorTab _actorTab;
|
||||||
private readonly DesignTab _designTab;
|
private readonly DesignTab _designTab;
|
||||||
private readonly DebugStateTab _debugStateTab;
|
private readonly DebugStateTab _debugStateTab;
|
||||||
private readonly DebugDataTab _debugDataTab;
|
private readonly DebugDataTab _debugDataTab;
|
||||||
|
|
||||||
public Interface(DalamudPluginInterface pi, ItemManager items, ActiveDesign.Manager activeDesigns, Design.Manager manager,
|
public Interface(DalamudPluginInterface pi, ItemManager items, ActiveDesign.Manager activeDesigns, Design.Manager manager,
|
||||||
DesignFileSystem fileSystem, ObjectManager objects)
|
DesignFileSystem fileSystem, ObjectManager objects, CustomizationService customization, Configuration config, DataManager gameData, TargetManager targets, ActorService actors, KeyState keyState)
|
||||||
: base(GetLabel())
|
: base(GetLabel())
|
||||||
{
|
{
|
||||||
_pi = pi;
|
_pi = pi;
|
||||||
_equipmentDrawer = new EquipmentDrawer(items);
|
_config = config;
|
||||||
_customizationDrawer = new CustomizationDrawer(pi);
|
_equipmentDrawer = new EquipmentDrawer(gameData, items);
|
||||||
Dalamud.PluginInterface.UiBuilder.DisableGposeUiHide = true;
|
_customizationDrawer = new CustomizationDrawer(pi, customization, items);
|
||||||
Dalamud.PluginInterface.UiBuilder.OpenConfigUi += Toggle;
|
pi.UiBuilder.DisableGposeUiHide = true;
|
||||||
SizeConstraints = new WindowSizeConstraints()
|
SizeConstraints = new WindowSizeConstraints()
|
||||||
{
|
{
|
||||||
MinimumSize = new Vector2(675, 675),
|
MinimumSize = new Vector2(675, 675),
|
||||||
MaximumSize = ImGui.GetIO().DisplaySize,
|
MaximumSize = ImGui.GetIO().DisplaySize,
|
||||||
};
|
};
|
||||||
_actorTab = new ActorTab(this, activeDesigns, objects);
|
_actorTab = new ActorTab(this, activeDesigns, objects, targets, actors, items);
|
||||||
_debugStateTab = new DebugStateTab(activeDesigns);
|
_debugStateTab = new DebugStateTab(activeDesigns);
|
||||||
_debugDataTab = new DebugDataTab(Glamourer.Customization);
|
_debugDataTab = new DebugDataTab(customization);
|
||||||
_designTab = new DesignTab(this, manager, fileSystem);
|
_designTab = new DesignTab(this, manager, fileSystem, keyState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
internal partial class Interface
|
public partial class Interface
|
||||||
{
|
{
|
||||||
//private readonly CharacterSave _currentSave = new();
|
//private readonly CharacterSave _currentSave = new();
|
||||||
//private string _newDesignName = string.Empty;
|
//private string _newDesignName = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,14 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
||||||
public static implicit operator IntPtr(Actor actor)
|
public static implicit operator IntPtr(Actor actor)
|
||||||
=> actor.Pointer == null ? IntPtr.Zero : (IntPtr)actor.Pointer;
|
=> actor.Pointer == null ? IntPtr.Zero : (IntPtr)actor.Pointer;
|
||||||
|
|
||||||
public ActorIdentifier GetIdentifier()
|
public ActorIdentifier GetIdentifier(ActorManager actors)
|
||||||
=> Glamourer.Actors.FromObject((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)Pointer, out _, true, true, false);
|
=> actors.FromObject((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)Pointer, out _, true, true, false);
|
||||||
|
|
||||||
public bool Identifier(out ActorIdentifier ident)
|
public bool Identifier(ActorManager actors, out ActorIdentifier ident)
|
||||||
{
|
{
|
||||||
if (Valid)
|
if (Valid)
|
||||||
{
|
{
|
||||||
ident = GetIdentifier();
|
ident = GetIdentifier(actors);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,9 +39,6 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Character? Character
|
|
||||||
=> Pointer == null ? null : Dalamud.Objects[Pointer->GameObject.ObjectIndex] as Character;
|
|
||||||
|
|
||||||
public bool IsAvailable
|
public bool IsAvailable
|
||||||
=> Pointer->GameObject.GetIsTargetable();
|
=> Pointer->GameObject.GetIsTargetable();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,35 +4,50 @@ using System.Collections.Generic;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
using Dalamud.Game.ClientState.Objects;
|
using Dalamud.Game.ClientState.Objects;
|
||||||
|
using Glamourer.Services;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
|
||||||
namespace Glamourer.Interop;
|
namespace Glamourer.Interop;
|
||||||
|
|
||||||
public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ObjectManager.ActorData>
|
public readonly struct ActorData
|
||||||
{
|
{
|
||||||
public readonly struct ActorData
|
public readonly List<Actor> Objects;
|
||||||
|
public readonly string Label;
|
||||||
|
|
||||||
|
public bool Valid
|
||||||
|
=> Objects.Count > 0;
|
||||||
|
|
||||||
|
public ActorData(Actor actor, string label)
|
||||||
{
|
{
|
||||||
public readonly List<Actor> Objects;
|
Objects = new List<Actor> { actor };
|
||||||
public readonly string Label;
|
Label = label;
|
||||||
|
|
||||||
public bool Valid
|
|
||||||
=> Objects.Count > 0;
|
|
||||||
|
|
||||||
public ActorData(Actor actor, string label)
|
|
||||||
{
|
|
||||||
Objects = new List<Actor> { actor };
|
|
||||||
Label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly ActorData Invalid = new(false);
|
|
||||||
|
|
||||||
private ActorData(bool _)
|
|
||||||
{
|
|
||||||
Objects = new List<Actor>(0);
|
|
||||||
Label = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly ActorData Invalid = new(false);
|
||||||
|
|
||||||
|
private ActorData(bool _)
|
||||||
|
{
|
||||||
|
Objects = new List<Actor>(0);
|
||||||
|
Label = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
|
||||||
|
{
|
||||||
|
private readonly Framework _framework;
|
||||||
|
private readonly ClientState _clientState;
|
||||||
|
private readonly ObjectTable _objects;
|
||||||
|
private readonly ActorService _actors;
|
||||||
|
|
||||||
|
public ObjectManager(Framework framework, ClientState clientState, ObjectTable objects, ActorService actors)
|
||||||
|
{
|
||||||
|
_framework = framework;
|
||||||
|
_clientState = clientState;
|
||||||
|
_objects = objects;
|
||||||
|
_actors = actors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public DateTime LastUpdate { get; private set; }
|
public DateTime LastUpdate { get; private set; }
|
||||||
|
|
||||||
public bool IsInGPose { get; private set; }
|
public bool IsInGPose { get; private set; }
|
||||||
|
|
@ -56,16 +71,6 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ObjectManager.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Framework _framework;
|
|
||||||
private readonly ClientState _clientState;
|
|
||||||
private readonly ObjectTable _objects;
|
|
||||||
|
|
||||||
public ObjectManager(Framework framework, ClientState clientState, ObjectTable objects)
|
|
||||||
{
|
|
||||||
_framework = framework;
|
|
||||||
_clientState = clientState;
|
|
||||||
_objects = objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
|
|
@ -80,14 +85,14 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ObjectManager.
|
||||||
for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i)
|
for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i)
|
||||||
{
|
{
|
||||||
Actor character = _objects.GetObjectAddress(i);
|
Actor character = _objects.GetObjectAddress(i);
|
||||||
if (character.Identifier(out var identifier))
|
if (character.Identifier(_actors.AwaitedService, out var identifier))
|
||||||
HandleIdentifier(identifier, character);
|
HandleIdentifier(identifier, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i)
|
for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i)
|
||||||
{
|
{
|
||||||
Actor character = _objects.GetObjectAddress(i);
|
Actor character = _objects.GetObjectAddress(i);
|
||||||
if (!character.Identifier(out var identifier))
|
if (!character.Identifier(_actors.AwaitedService, out var identifier))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
HandleIdentifier(identifier, character);
|
HandleIdentifier(identifier, character);
|
||||||
|
|
@ -96,7 +101,7 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ObjectManager.
|
||||||
void AddSpecial(ScreenActor idx, string label)
|
void AddSpecial(ScreenActor idx, string label)
|
||||||
{
|
{
|
||||||
Actor actor = _objects.GetObjectAddress((int)idx);
|
Actor actor = _objects.GetObjectAddress((int)idx);
|
||||||
if (actor.Identifier(out var ident))
|
if (actor.Identifier(_actors.AwaitedService, out var ident))
|
||||||
{
|
{
|
||||||
var data = new ActorData(actor, label);
|
var data = new ActorData(actor, label);
|
||||||
_identifiers.Add(ident, data);
|
_identifiers.Add(ident, data);
|
||||||
|
|
@ -112,10 +117,10 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ObjectManager.
|
||||||
AddSpecial(ScreenActor.Card7, "Card Actor 7");
|
AddSpecial(ScreenActor.Card7, "Card Actor 7");
|
||||||
AddSpecial(ScreenActor.Card8, "Card Actor 8");
|
AddSpecial(ScreenActor.Card8, "Card Actor 8");
|
||||||
|
|
||||||
for (var i = (int)ScreenActor.ScreenEnd; i < Dalamud.Objects.Length; ++i)
|
for (var i = (int)ScreenActor.ScreenEnd; i < _objects.Length; ++i)
|
||||||
{
|
{
|
||||||
Actor character = _objects.GetObjectAddress(i);
|
Actor character = _objects.GetObjectAddress(i);
|
||||||
if (character.Identifier(out var identifier))
|
if (character.Identifier(_actors.AwaitedService, out var identifier))
|
||||||
HandleIdentifier(identifier, character);
|
HandleIdentifier(identifier, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ public unsafe partial class RedrawManager
|
||||||
var character = (Actor)(characterOffset - CharacterWeaponOffset);
|
var character = (Actor)(characterOffset - CharacterWeaponOffset);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var identifier = character.GetIdentifier();
|
var identifier = character.GetIdentifier(_actors.AwaitedService);
|
||||||
if (_fixedDesigns.TryGetDesign(identifier, out var save))
|
if (_fixedDesignManager.TryGetDesign(identifier, out var save))
|
||||||
{
|
{
|
||||||
PluginLog.Information($"Loaded weapon from fixed design for {identifier}.");
|
PluginLog.Information($"Loaded weapon from fixed design for {identifier}.");
|
||||||
weapon = slot switch
|
weapon = slot switch
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using Dalamud.Logging;
|
||||||
using Dalamud.Utility.Signatures;
|
using Dalamud.Utility.Signatures;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Glamourer.Structs;
|
using Glamourer.Structs;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -16,8 +17,11 @@ namespace Glamourer.Interop;
|
||||||
|
|
||||||
public partial class Interop : IDisposable
|
public partial class Interop : IDisposable
|
||||||
{
|
{
|
||||||
public Interop()
|
private readonly JobService _jobService;
|
||||||
|
|
||||||
|
public Interop(JobService jobService)
|
||||||
{
|
{
|
||||||
|
_jobService = jobService;
|
||||||
SignatureHelper.Initialise(this);
|
SignatureHelper.Initialise(this);
|
||||||
_changeJobHook.Enable();
|
_changeJobHook.Enable();
|
||||||
_flagSlotForUpdateHook.Enable();
|
_flagSlotForUpdateHook.Enable();
|
||||||
|
|
@ -187,7 +191,7 @@ public partial class Interop
|
||||||
private void ChangeJobDetour(IntPtr data, uint job)
|
private void ChangeJobDetour(IntPtr data, uint job)
|
||||||
{
|
{
|
||||||
_changeJobHook.Original(data, job);
|
_changeJobHook.Original(data, job);
|
||||||
JobChanged?.Invoke(data - Offsets.Character.ClassJobContainer, GameData.Jobs(Dalamud.GameData)[(byte)job]);
|
JobChanged?.Invoke(data - Offsets.Character.ClassJobContainer, _jobService.Jobs[(byte)job]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public event Action<Actor, Job>? JobChanged;
|
public event Action<Actor, Job>? JobChanged;
|
||||||
|
|
@ -195,14 +199,18 @@ public partial class Interop
|
||||||
|
|
||||||
public unsafe partial class RedrawManager : IDisposable
|
public unsafe partial class RedrawManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly FixedDesigns _fixedDesigns;
|
private readonly ItemManager _items;
|
||||||
|
private readonly ActorService _actors;
|
||||||
|
private readonly FixedDesignManager _fixedDesignManager;
|
||||||
private readonly ActiveDesign.Manager _stateManager;
|
private readonly ActiveDesign.Manager _stateManager;
|
||||||
|
|
||||||
public RedrawManager(FixedDesigns fixedDesigns, ActiveDesign.Manager stateManager)
|
public RedrawManager(FixedDesignManager fixedDesignManager, ActiveDesign.Manager stateManager, ItemManager items, ActorService actors)
|
||||||
{
|
{
|
||||||
SignatureHelper.Initialise(this);
|
SignatureHelper.Initialise(this);
|
||||||
_fixedDesigns = fixedDesigns;
|
_fixedDesignManager = fixedDesignManager;
|
||||||
_stateManager = stateManager;
|
_stateManager = stateManager;
|
||||||
|
_items = items;
|
||||||
|
_actors = actors;
|
||||||
_flagSlotForUpdateHook.Enable();
|
_flagSlotForUpdateHook.Enable();
|
||||||
_loadWeaponHook.Enable();
|
_loadWeaponHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
@ -221,8 +229,8 @@ public unsafe partial class RedrawManager : IDisposable
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check if we have a current design in use, or if not if the actor has a fixed design.
|
// Check if we have a current design in use, or if not if the actor has a fixed design.
|
||||||
var identifier = actor.GetIdentifier();
|
var identifier = actor.GetIdentifier(_actors.AwaitedService);
|
||||||
if (!(_stateManager.TryGetValue(identifier, out var save) || _fixedDesigns.TryGetDesign(identifier, out var save2)))
|
if (!(_stateManager.TryGetValue(identifier, out var save) || _fixedDesignManager.TryGetDesign(identifier, out var save2)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Compare game object customize data against draw object customize data for transformations.
|
// Compare game object customize data against draw object customize data for transformations.
|
||||||
|
|
@ -240,7 +248,7 @@ public unsafe partial class RedrawManager : IDisposable
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
{
|
{
|
||||||
(_, equip[slot]) =
|
(_, equip[slot]) =
|
||||||
Glamourer.Items.ResolveRestrictedGear(saveEquip[slot], slot, customize.Race, customize.Gender);
|
_items.ResolveRestrictedGear(saveEquip[slot], slot, customize.Race, customize.Gender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
Glamourer/Services/BackupService.cs
Normal file
30
Glamourer/Services/BackupService.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using OtterGui.Log;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
public class BackupService
|
||||||
|
{
|
||||||
|
public BackupService(Logger logger, FilenameService fileNames)
|
||||||
|
{
|
||||||
|
var files = GlamourerFiles(fileNames);
|
||||||
|
Backup.CreateBackup(logger, new DirectoryInfo(fileNames.ConfigDirectory), files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Collect all relevant files for glamourer configuration. </summary>
|
||||||
|
private static IReadOnlyList<FileInfo> GlamourerFiles(FilenameService fileNames)
|
||||||
|
{
|
||||||
|
var list = new List<FileInfo>(16)
|
||||||
|
{
|
||||||
|
new(fileNames.ConfigFile),
|
||||||
|
new(fileNames.DesignFileSystem),
|
||||||
|
new(fileNames.MigrationDesignFile),
|
||||||
|
};
|
||||||
|
|
||||||
|
list.AddRange(fileNames.Designs());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Glamourer/Services/CommandService.cs
Normal file
36
Glamourer/Services/CommandService.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using Dalamud.Game.Command;
|
||||||
|
using Glamourer.Gui;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
public class CommandService : IDisposable
|
||||||
|
{
|
||||||
|
private const string HelpString = "[Copy|Apply|Save],[Name or PlaceHolder],<Name for Save>";
|
||||||
|
private const string MainCommandString = "/glamourer";
|
||||||
|
private const string ApplyCommandString = "/glamour";
|
||||||
|
|
||||||
|
private readonly CommandManager _commands;
|
||||||
|
private readonly Interface _interface;
|
||||||
|
|
||||||
|
public CommandService(CommandManager commands, Interface ui)
|
||||||
|
{
|
||||||
|
_commands = commands;
|
||||||
|
_interface = ui;
|
||||||
|
|
||||||
|
_commands.AddHandler(MainCommandString, new CommandInfo(OnGlamourer) { HelpMessage = "Open or close the Glamourer window." });
|
||||||
|
_commands.AddHandler(ApplyCommandString, new CommandInfo(OnGlamour) { HelpMessage = $"Use Glamourer Functions: {HelpString}" });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_commands.RemoveHandler(MainCommandString);
|
||||||
|
_commands.RemoveHandler(ApplyCommandString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGlamourer(string command, string arguments)
|
||||||
|
=> _interface.Toggle();
|
||||||
|
|
||||||
|
private void OnGlamour(string command, string arguments)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
40
Glamourer/Services/FilenameService.cs
Normal file
40
Glamourer/Services/FilenameService.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Glamourer.Designs;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
public class FilenameService
|
||||||
|
{
|
||||||
|
public readonly string ConfigDirectory;
|
||||||
|
public readonly string ConfigFile;
|
||||||
|
public readonly string DesignFileSystem;
|
||||||
|
public readonly string MigrationDesignFile;
|
||||||
|
public readonly string DesignDirectory;
|
||||||
|
|
||||||
|
public FilenameService(DalamudPluginInterface pi)
|
||||||
|
{
|
||||||
|
ConfigDirectory = pi.ConfigDirectory.FullName;
|
||||||
|
ConfigFile = pi.ConfigFile.FullName;
|
||||||
|
DesignFileSystem = Path.Combine(ConfigDirectory, "sort_order.json");
|
||||||
|
MigrationDesignFile = Path.Combine(ConfigDirectory, "Designs.json");
|
||||||
|
DesignDirectory = Path.Combine(ConfigDirectory, "designs");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<FileInfo> Designs()
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(DesignDirectory))
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
foreach (var file in Directory.EnumerateFiles(DesignDirectory, "*.json", SearchOption.TopDirectoryOnly))
|
||||||
|
yield return new FileInfo(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DesignFile(Design design)
|
||||||
|
=> DesignFile(design.Identifier.ToString());
|
||||||
|
|
||||||
|
public string DesignFile(string identifier)
|
||||||
|
=> Path.Combine(DesignDirectory, $"{identifier}.json");
|
||||||
|
}
|
||||||
|
|
@ -6,13 +6,13 @@ using Dalamud.Plugin;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using Lumina.Excel;
|
using Lumina.Excel;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Penumbra.GameData;
|
using Lumina.Text;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Race = Penumbra.GameData.Enums.Race;
|
using Race = Penumbra.GameData.Enums.Race;
|
||||||
|
|
||||||
namespace Glamourer.Util;
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
public class ItemManager : IDisposable
|
public class ItemManager : IDisposable
|
||||||
{
|
{
|
||||||
|
|
@ -20,33 +20,33 @@ public class ItemManager : IDisposable
|
||||||
public const string SmallClothesNpc = "Smallclothes (NPC)";
|
public const string SmallClothesNpc = "Smallclothes (NPC)";
|
||||||
public const ushort SmallClothesNpcModel = 9903;
|
public const ushort SmallClothesNpcModel = 9903;
|
||||||
|
|
||||||
public readonly IObjectIdentifier Identifier;
|
private readonly Configuration _config;
|
||||||
public readonly ExcelSheet<Item> ItemSheet;
|
public readonly IdentifierService IdentifierService;
|
||||||
public readonly StainData Stains;
|
public readonly ExcelSheet<Item> ItemSheet;
|
||||||
public readonly ItemData Items;
|
public readonly StainData Stains;
|
||||||
public readonly RestrictedGear RestrictedGear;
|
public readonly ItemService ItemService;
|
||||||
|
public readonly RestrictedGear RestrictedGear;
|
||||||
|
|
||||||
public ItemManager(DalamudPluginInterface pi, DataManager gameData)
|
public ItemManager(DalamudPluginInterface pi, DataManager gameData, IdentifierService identifierService, ItemService itemService, Configuration config)
|
||||||
{
|
{
|
||||||
ItemSheet = gameData.GetExcelSheet<Item>()!;
|
_config = config;
|
||||||
Identifier = Penumbra.GameData.GameData.GetIdentifier(pi, gameData, gameData.Language);
|
ItemSheet = gameData.GetExcelSheet<Item>()!;
|
||||||
Stains = new StainData(pi, gameData, gameData.Language);
|
IdentifierService = identifierService;
|
||||||
Items = new ItemData(pi, gameData, gameData.Language);
|
Stains = new StainData(pi, gameData, gameData.Language);
|
||||||
RestrictedGear = new RestrictedGear(pi, gameData.Language, gameData);
|
ItemService = itemService;
|
||||||
DefaultSword = ItemSheet.GetRow(1601)!; // Weathered Shortsword
|
RestrictedGear = new RestrictedGear(pi, gameData.Language, gameData);
|
||||||
|
DefaultSword = ItemSheet.GetRow(1601)!; // Weathered Shortsword
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Stains.Dispose();
|
Stains.Dispose();
|
||||||
Items.Dispose();
|
|
||||||
Identifier.Dispose();
|
|
||||||
RestrictedGear.Dispose();
|
RestrictedGear.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public (bool, CharacterArmor) ResolveRestrictedGear(CharacterArmor armor, EquipSlot slot, Race race, Gender gender)
|
public (bool, CharacterArmor) ResolveRestrictedGear(CharacterArmor armor, EquipSlot slot, Race race, Gender gender)
|
||||||
{
|
{
|
||||||
if (Glamourer.Config.UseRestrictedGearProtection)
|
if (_config.UseRestrictedGearProtection)
|
||||||
return RestrictedGear.ResolveRestricted(armor, slot, race, gender);
|
return RestrictedGear.ResolveRestricted(armor, slot, race, gender);
|
||||||
|
|
||||||
return (false, armor);
|
return (false, armor);
|
||||||
|
|
@ -152,7 +152,7 @@ public class ItemManager : IDisposable
|
||||||
case 0: return (true, NothingId(slot), Nothing);
|
case 0: return (true, NothingId(slot), Nothing);
|
||||||
case SmallClothesNpcModel: return (true, SmallclothesId(slot), SmallClothesNpc);
|
case SmallClothesNpcModel: return (true, SmallclothesId(slot), SmallClothesNpc);
|
||||||
default:
|
default:
|
||||||
var item = Identifier.Identify(id, variant, slot).FirstOrDefault();
|
var item = IdentifierService.AwaitedService.Identify(id, variant, slot).FirstOrDefault();
|
||||||
return item == null
|
return item == null
|
||||||
? (false, 0, string.Intern($"Unknown ({id.Value}-{variant})"))
|
? (false, 0, string.Intern($"Unknown ({id.Value}-{variant})"))
|
||||||
: (true, item.RowId, string.Intern(item.Name.ToDalamudString().TextValue));
|
: (true, item.RowId, string.Intern(item.Name.ToDalamudString().TextValue));
|
||||||
|
|
@ -166,7 +166,7 @@ public class ItemManager : IDisposable
|
||||||
{
|
{
|
||||||
case EquipSlot.MainHand:
|
case EquipSlot.MainHand:
|
||||||
{
|
{
|
||||||
var item = Identifier.Identify(id, type, variant, slot).FirstOrDefault();
|
var item = IdentifierService.AwaitedService.Identify(id, type, variant, slot).FirstOrDefault();
|
||||||
return item != null
|
return item != null
|
||||||
? (true, item.RowId, string.Intern(item.Name.ToDalamudString().TextValue), item.ToEquipType())
|
? (true, item.RowId, string.Intern(item.Name.ToDalamudString().TextValue), item.ToEquipType())
|
||||||
: (false, 0, string.Intern($"Unknown ({id.Value}-{type.Value}-{variant})"), mainhandType);
|
: (false, 0, string.Intern($"Unknown ({id.Value}-{type.Value}-{variant})"), mainhandType);
|
||||||
|
|
@ -177,7 +177,7 @@ public class ItemManager : IDisposable
|
||||||
if (id.Value == 0)
|
if (id.Value == 0)
|
||||||
return (true, NothingId(weaponType), Nothing, weaponType);
|
return (true, NothingId(weaponType), Nothing, weaponType);
|
||||||
|
|
||||||
var item = Identifier.Identify(id, type, variant, slot).FirstOrDefault();
|
var item = IdentifierService.AwaitedService.Identify(id, type, variant, slot).FirstOrDefault();
|
||||||
return item != null
|
return item != null
|
||||||
? (true, item.RowId, string.Intern(item.Name.ToDalamudString().TextValue), item.ToEquipType())
|
? (true, item.RowId, string.Intern(item.Name.ToDalamudString().TextValue), item.ToEquipType())
|
||||||
: (false, 0, string.Intern($"Unknown ({id.Value}-{type.Value}-{variant})"),
|
: (false, 0, string.Intern($"Unknown ({id.Value}-{type.Value}-{variant})"),
|
||||||
16
Glamourer/Services/JobService.cs
Normal file
16
Glamourer/Services/JobService.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Dalamud.Data;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
public class JobService
|
||||||
|
{
|
||||||
|
public readonly IReadOnlyDictionary<byte, Structs.Job> Jobs;
|
||||||
|
public readonly IReadOnlyDictionary<ushort, Structs.JobGroup> JobGroups;
|
||||||
|
|
||||||
|
public JobService(DataManager gameData)
|
||||||
|
{
|
||||||
|
Jobs = GameData.Jobs(gameData);
|
||||||
|
JobGroups = GameData.JobGroups(gameData);
|
||||||
|
}
|
||||||
|
}
|
||||||
97
Glamourer/Services/SaveService.cs
Normal file
97
Glamourer/Services/SaveService.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using OtterGui.Log;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Any file type that we want to save via SaveService.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISavable
|
||||||
|
{
|
||||||
|
/// <summary> The full file name of a given object. </summary>
|
||||||
|
public string ToFilename(FilenameService fileNames);
|
||||||
|
|
||||||
|
/// <summary> Write the objects data to the given stream writer. </summary>
|
||||||
|
public void Save(StreamWriter writer);
|
||||||
|
|
||||||
|
/// <summary> An arbitrary message printed to Debug before saving. </summary>
|
||||||
|
public string LogName(string fileName)
|
||||||
|
=> fileName;
|
||||||
|
|
||||||
|
public string TypeName
|
||||||
|
=> GetType().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SaveService
|
||||||
|
{
|
||||||
|
private readonly Logger _log;
|
||||||
|
private readonly FrameworkManager _framework;
|
||||||
|
|
||||||
|
public readonly FilenameService FileNames;
|
||||||
|
|
||||||
|
public SaveService(Logger log, FrameworkManager framework, FilenameService fileNames)
|
||||||
|
{
|
||||||
|
_log = log;
|
||||||
|
_framework = framework;
|
||||||
|
FileNames = fileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Queue a save for the next framework tick. </summary>
|
||||||
|
public void QueueSave(ISavable value)
|
||||||
|
{
|
||||||
|
var file = value.ToFilename(FileNames);
|
||||||
|
_framework.RegisterDelayed(value.GetType().Name + file, () =>
|
||||||
|
{
|
||||||
|
ImmediateSave(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Immediately trigger a save. </summary>
|
||||||
|
public void ImmediateSave(ISavable value)
|
||||||
|
{
|
||||||
|
var name = value.ToFilename(FileNames);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (name.Length == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid object returned empty filename.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.Debug($"Saving {value.TypeName} {value.LogName(name)}...");
|
||||||
|
var file = new FileInfo(name);
|
||||||
|
file.Directory?.Create();
|
||||||
|
using var s = file.Exists ? file.Open(FileMode.Truncate) : file.Open(FileMode.CreateNew);
|
||||||
|
using var w = new StreamWriter(s, Encoding.UTF8);
|
||||||
|
value.Save(w);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error($"Could not save {value.GetType().Name} {value.LogName(name)}:\n{ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ImmediateDelete(ISavable value)
|
||||||
|
{
|
||||||
|
var name = value.ToFilename(FileNames);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (name.Length == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid object returned empty filename.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_log.Information($"Deleting {value.GetType().Name} {value.LogName(name)}...");
|
||||||
|
File.Delete(name);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error($"Could not delete {value.GetType().Name} {value.LogName(name)}:\n{ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
76
Glamourer/Services/ServiceManager.cs
Normal file
76
Glamourer/Services/ServiceManager.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Glamourer.Api;
|
||||||
|
using Glamourer.Designs;
|
||||||
|
using Glamourer.Gui;
|
||||||
|
using Glamourer.Interop;
|
||||||
|
using Glamourer.State;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using OtterGui.Log;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
public static class ServiceManager
|
||||||
|
{
|
||||||
|
public static ServiceProvider CreateProvider(DalamudPluginInterface pi, Logger log)
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection()
|
||||||
|
.AddSingleton(log)
|
||||||
|
.AddDalamud(pi)
|
||||||
|
.AddMeta()
|
||||||
|
.AddConfig()
|
||||||
|
.AddPenumbra()
|
||||||
|
.AddInterop()
|
||||||
|
.AddGameData()
|
||||||
|
.AddDesigns()
|
||||||
|
.AddInterface()
|
||||||
|
.AddApi();
|
||||||
|
|
||||||
|
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddDalamud(this IServiceCollection services, DalamudPluginInterface pi)
|
||||||
|
{
|
||||||
|
new DalamudServices(pi).AddServices(services);
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddMeta(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<FilenameService>()
|
||||||
|
.AddSingleton<SaveService>()
|
||||||
|
.AddSingleton<FrameworkManager>()
|
||||||
|
.AddSingleton<ChatService>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddConfig(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<Configuration>()
|
||||||
|
.AddSingleton<BackupService>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddPenumbra(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<PenumbraAttach>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddGameData(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<IdentifierService>()
|
||||||
|
.AddSingleton<ActorService>()
|
||||||
|
.AddSingleton<ItemService>()
|
||||||
|
.AddSingleton<ItemManager>()
|
||||||
|
.AddSingleton<CustomizationService>()
|
||||||
|
.AddSingleton<JobService>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddInterop(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<Interop.Interop>()
|
||||||
|
.AddSingleton<ObjectManager>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddDesigns(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<Design.Manager>()
|
||||||
|
.AddSingleton<DesignFileSystem>()
|
||||||
|
.AddSingleton<ActiveDesign.Manager>()
|
||||||
|
.AddSingleton<FixedDesignManager>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddInterface(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<Interface>()
|
||||||
|
.AddSingleton<GlamourerWindowSystem>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddApi(this IServiceCollection services)
|
||||||
|
=> services.AddSingleton<CommandService>()
|
||||||
|
.AddSingleton<Glamourer.GlamourerIpc>();
|
||||||
|
}
|
||||||
105
Glamourer/Services/ServiceWrapper.cs
Normal file
105
Glamourer/Services/ServiceWrapper.cs
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
using Dalamud.Data;
|
||||||
|
using Dalamud.Game.ClientState.Objects;
|
||||||
|
using Dalamud.Game.ClientState;
|
||||||
|
using Dalamud.Game.Gui;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Glamourer.Api;
|
||||||
|
using Glamourer.Customization;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
|
using Penumbra.GameData;
|
||||||
|
|
||||||
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
|
public abstract class AsyncServiceWrapper<T>
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public T? Service { get; private set; }
|
||||||
|
|
||||||
|
public T AwaitedService
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_task?.Wait();
|
||||||
|
return Service!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Valid
|
||||||
|
=> Service != null && !_isDisposed;
|
||||||
|
|
||||||
|
public event Action? FinishedCreation;
|
||||||
|
private Task? _task;
|
||||||
|
|
||||||
|
private bool _isDisposed;
|
||||||
|
|
||||||
|
protected AsyncServiceWrapper(string name, Func<T> factory)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
_task = Task.Run(() =>
|
||||||
|
{
|
||||||
|
var service = factory();
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
if (service is IDisposable d)
|
||||||
|
d.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Service = service;
|
||||||
|
Glamourer.Log.Verbose($"[{Name}] Created.");
|
||||||
|
_task = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_task.ContinueWith((t, x) =>
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
FinishedCreation?.Invoke();
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isDisposed = true;
|
||||||
|
_task = null;
|
||||||
|
if (Service is IDisposable d)
|
||||||
|
d.Dispose();
|
||||||
|
Glamourer.Log.Verbose($"[{Name}] Disposed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
|
||||||
|
{
|
||||||
|
public IdentifierService(DalamudPluginInterface pi, DataManager data)
|
||||||
|
: base(nameof(IdentifierService), () => Penumbra.GameData.GameData.GetIdentifier(pi, data))
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ItemService : AsyncServiceWrapper<ItemData>
|
||||||
|
{
|
||||||
|
public ItemService(DalamudPluginInterface pi, DataManager gameData)
|
||||||
|
: base(nameof(ItemService), () => new ItemData(pi, gameData, gameData.Language))
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ActorService : AsyncServiceWrapper<ActorManager>
|
||||||
|
{
|
||||||
|
public ActorService(DalamudPluginInterface pi, ObjectTable objects, ClientState clientState, Framework framework, DataManager gameData,
|
||||||
|
GameGui gui, PenumbraAttach penumbra)
|
||||||
|
: base(nameof(ActorService),
|
||||||
|
() => new ActorManager(pi, objects, clientState, framework, gameData, gui, idx => (short)penumbra.CutsceneParent(idx)))
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationManager>
|
||||||
|
{
|
||||||
|
public CustomizationService(DalamudPluginInterface pi, DataManager gameData)
|
||||||
|
: base(nameof(CustomizationService), () => CustomizationManager.Create(pi, gameData))
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
@ -6,16 +6,14 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
|
||||||
using Glamourer.Api;
|
using Glamourer.Api;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
|
using Glamourer.Services;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||||
using Item = Glamourer.Designs.Item;
|
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
|
|
||||||
namespace Glamourer.State;
|
namespace Glamourer.State;
|
||||||
|
|
||||||
|
|
@ -23,19 +21,21 @@ public sealed partial class ActiveDesign
|
||||||
{
|
{
|
||||||
public partial class Manager : IReadOnlyDictionary<ActorIdentifier, ActiveDesign>
|
public partial class Manager : IReadOnlyDictionary<ActorIdentifier, ActiveDesign>
|
||||||
{
|
{
|
||||||
private readonly ActorManager _actors;
|
private readonly ActorService _actors;
|
||||||
private readonly ObjectManager _objects;
|
private readonly ObjectManager _objects;
|
||||||
private readonly Interop.Interop _interop;
|
private readonly Interop.Interop _interop;
|
||||||
private readonly PenumbraAttach _penumbra;
|
private readonly PenumbraAttach _penumbra;
|
||||||
|
private readonly ItemManager _items;
|
||||||
|
|
||||||
private readonly Dictionary<ActorIdentifier, ActiveDesign> _characterSaves = new();
|
private readonly Dictionary<ActorIdentifier, ActiveDesign> _characterSaves = new();
|
||||||
|
|
||||||
public Manager(ActorManager actors, ObjectManager objects, Interop.Interop interop, PenumbraAttach penumbra)
|
public Manager(ActorService actors, ObjectManager objects, Interop.Interop interop, PenumbraAttach penumbra, ItemManager items)
|
||||||
{
|
{
|
||||||
_actors = actors;
|
_actors = actors;
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
_interop = interop;
|
_interop = interop;
|
||||||
_penumbra = penumbra;
|
_penumbra = penumbra;
|
||||||
|
_items = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<ActorIdentifier, ActiveDesign>> GetEnumerator()
|
public IEnumerator<KeyValuePair<ActorIdentifier, ActiveDesign>> GetEnumerator()
|
||||||
|
|
@ -67,16 +67,16 @@ public sealed partial class ActiveDesign
|
||||||
|
|
||||||
public unsafe ActiveDesign GetOrCreateSave(Actor actor)
|
public unsafe ActiveDesign GetOrCreateSave(Actor actor)
|
||||||
{
|
{
|
||||||
var id = _actors.FromObject((GameObject*)actor.Pointer, out _, false, false, false);
|
var id = _actors.AwaitedService.FromObject((GameObject*)actor.Pointer, out _, false, false, false);
|
||||||
if (_characterSaves.TryGetValue(id, out var save))
|
if (_characterSaves.TryGetValue(id, out var save))
|
||||||
{
|
{
|
||||||
save.Initialize(actor);
|
save.Initialize(_items, actor);
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
||||||
id = id.CreatePermanent();
|
id = id.CreatePermanent();
|
||||||
save = new ActiveDesign(id, actor);
|
save = new ActiveDesign(_items, id, actor);
|
||||||
save.Initialize(actor);
|
save.Initialize(_items, actor);
|
||||||
_characterSaves.Add(id, save);
|
_characterSaves.Add(id, save);
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +100,7 @@ public sealed partial class ActiveDesign
|
||||||
|
|
||||||
if (from.DoApplyEquip(EquipSlot.MainHand))
|
if (from.DoApplyEquip(EquipSlot.MainHand))
|
||||||
ChangeMainHand(to, from.MainHand, fromFixed);
|
ChangeMainHand(to, from.MainHand, fromFixed);
|
||||||
|
|
||||||
if (from.DoApplyEquip(EquipSlot.OffHand))
|
if (from.DoApplyEquip(EquipSlot.OffHand))
|
||||||
ChangeOffHand(to, from.OffHand, fromFixed);
|
ChangeOffHand(to, from.OffHand, fromFixed);
|
||||||
|
|
||||||
|
|
@ -130,10 +130,10 @@ public sealed partial class ActiveDesign
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeMainHand(ActiveDesign design, uint itemId, bool fromFixed)
|
public void ChangeMainHand(ActiveDesign design, uint itemId, bool fromFixed)
|
||||||
=> design.SetMainhand(itemId);
|
=> design.SetMainhand(_items, itemId);
|
||||||
|
|
||||||
public void ChangeOffHand(ActiveDesign design, uint itemId, bool fromFixed)
|
public void ChangeOffHand(ActiveDesign design, uint itemId, bool fromFixed)
|
||||||
=> design.SetOffhand(itemId);
|
=> design.SetOffhand(_items, itemId);
|
||||||
|
|
||||||
public void RevertMainHand(ActiveDesign design)
|
public void RevertMainHand(ActiveDesign design)
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -187,7 +187,7 @@ public sealed partial class ActiveDesign
|
||||||
if (equip)
|
if (equip)
|
||||||
{
|
{
|
||||||
var flag = slot.ToFlag();
|
var flag = slot.ToFlag();
|
||||||
design.UpdateArmor(slot, item, true);
|
design.UpdateArmor(_items, slot, item, true);
|
||||||
design.ChangedEquip &= ~flag;
|
design.ChangedEquip &= ~flag;
|
||||||
design.FixedEquip &= ~flag;
|
design.FixedEquip &= ~flag;
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +265,7 @@ public sealed partial class ActiveDesign
|
||||||
if (!_objects.TryGetValue(design.Identifier, out var data))
|
if (!_objects.TryGetValue(design.Identifier, out var data))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var obj in data.Objects)
|
foreach (var obj in data.Objects)
|
||||||
Interop.Interop.SetVisorState(obj.DrawObject, on);
|
Interop.Interop.SetVisorState(obj.DrawObject, on);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
using System;
|
using Glamourer.Customization;
|
||||||
using System.Linq;
|
|
||||||
using Glamourer.Customization;
|
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Penumbra.Api.Enums;
|
using Glamourer.Services;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
|
|
@ -26,13 +24,15 @@ public sealed partial class ActiveDesign : DesignBase
|
||||||
public bool IsVisorToggled { get; private set; } = false;
|
public bool IsVisorToggled { get; private set; } = false;
|
||||||
public bool IsWet { get; private set; } = false;
|
public bool IsWet { get; private set; } = false;
|
||||||
|
|
||||||
private ActiveDesign(ActorIdentifier identifier)
|
private ActiveDesign(ItemManager items, ActorIdentifier identifier)
|
||||||
|
: base(items)
|
||||||
=> Identifier = identifier;
|
=> Identifier = identifier;
|
||||||
|
|
||||||
public ActiveDesign(ActorIdentifier identifier, Actor actor)
|
public ActiveDesign(ItemManager items, ActorIdentifier identifier, Actor actor)
|
||||||
|
: base(items)
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
Initialize(actor);
|
Initialize(items, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void ApplyToActor(Actor actor)
|
//public void ApplyToActor(Actor actor)
|
||||||
|
|
@ -65,7 +65,7 @@ public sealed partial class ActiveDesign : DesignBase
|
||||||
// RedrawManager.SetVisor(actor.DrawObject.Pointer, actor.VisorEnabled);
|
// RedrawManager.SetVisor(actor.DrawObject.Pointer, actor.VisorEnabled);
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
public void Initialize(Actor actor)
|
public void Initialize(ItemManager items, Actor actor)
|
||||||
{
|
{
|
||||||
if (!actor)
|
if (!actor)
|
||||||
return;
|
return;
|
||||||
|
|
@ -84,7 +84,7 @@ public sealed partial class ActiveDesign : DesignBase
|
||||||
if (initialEquip[slot] != current)
|
if (initialEquip[slot] != current)
|
||||||
{
|
{
|
||||||
initialEquip[slot] = current;
|
initialEquip[slot] = current;
|
||||||
UpdateArmor(slot, current, true);
|
UpdateArmor(items, slot, current, true);
|
||||||
SetStain(slot, current.Stain);
|
SetStain(slot, current.Stain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,14 +92,14 @@ public sealed partial class ActiveDesign : DesignBase
|
||||||
if (_initialData.MainHand != actor.MainHand)
|
if (_initialData.MainHand != actor.MainHand)
|
||||||
{
|
{
|
||||||
_initialData.MainHand = actor.MainHand;
|
_initialData.MainHand = actor.MainHand;
|
||||||
UpdateMainhand(actor.MainHand);
|
UpdateMainhand(items, actor.MainHand);
|
||||||
SetStain(EquipSlot.MainHand, actor.MainHand.Stain);
|
SetStain(EquipSlot.MainHand, actor.MainHand.Stain);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_initialData.OffHand != actor.OffHand)
|
if (_initialData.OffHand != actor.OffHand)
|
||||||
{
|
{
|
||||||
_initialData.OffHand = actor.OffHand;
|
_initialData.OffHand = actor.OffHand;
|
||||||
UpdateOffhand(actor.OffHand);
|
UpdateOffhand(items, actor.OffHand);
|
||||||
SetStain(EquipSlot.OffHand, actor.OffHand.Stain);
|
SetStain(EquipSlot.OffHand, actor.OffHand.Stain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@ using Penumbra.GameData.Actors;
|
||||||
|
|
||||||
namespace Glamourer.State;
|
namespace Glamourer.State;
|
||||||
|
|
||||||
public class FixedDesigns
|
public class FixedDesignManager
|
||||||
{
|
{
|
||||||
public bool TryGetDesign(ActorIdentifier actor, [NotNullWhen(true)] out Design? save)
|
public bool TryGetDesign(ActorIdentifier actor, [NotNullWhen(true)] out Design? save)
|
||||||
{
|
{
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using Dalamud.Configuration;
|
|
||||||
|
|
||||||
namespace Glamourer.State;
|
|
||||||
|
|
||||||
public class GlamourerConfig : IPluginConfiguration
|
|
||||||
{
|
|
||||||
public class FixedDesign
|
|
||||||
{
|
|
||||||
public string Name = string.Empty;
|
|
||||||
public string Path = string.Empty;
|
|
||||||
public uint JobGroups;
|
|
||||||
public bool Enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Version { get; set; } = 1;
|
|
||||||
|
|
||||||
public const uint DefaultCustomizationColor = 0xFFC000C0;
|
|
||||||
public const uint DefaultStateColor = 0xFF00C0C0;
|
|
||||||
public const uint DefaultEquipmentColor = 0xFF00C000;
|
|
||||||
|
|
||||||
public bool UseRestrictedGearProtection { get; set; } = true;
|
|
||||||
|
|
||||||
public bool FoldersFirst { get; set; } = false;
|
|
||||||
public bool ColorDesigns { get; set; } = true;
|
|
||||||
public bool ShowLocks { get; set; } = true;
|
|
||||||
public bool ApplyFixedDesigns { get; set; } = true;
|
|
||||||
|
|
||||||
public uint CustomizationColor { get; set; } = DefaultCustomizationColor;
|
|
||||||
public uint StateColor { get; set; } = DefaultStateColor;
|
|
||||||
public uint EquipmentColor { get; set; } = DefaultEquipmentColor;
|
|
||||||
|
|
||||||
public List<FixedDesign> FixedDesigns { get; set; } = new();
|
|
||||||
|
|
||||||
public void Save()
|
|
||||||
=> Dalamud.PluginInterface.SavePluginConfig(this);
|
|
||||||
|
|
||||||
public static GlamourerConfig Load()
|
|
||||||
{
|
|
||||||
if (Dalamud.PluginInterface.GetPluginConfig() is GlamourerConfig config)
|
|
||||||
return config;
|
|
||||||
|
|
||||||
config = new GlamourerConfig();
|
|
||||||
config.Save();
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
using Glamourer.Designs;
|
|
||||||
using Glamourer.Interop;
|
|
||||||
|
|
||||||
namespace Glamourer.State;
|
|
||||||
|
|
||||||
public interface IDesign
|
|
||||||
{
|
|
||||||
public ref CharacterData Data { get; }
|
|
||||||
|
|
||||||
public void ApplyToActor(Actor a);
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Services;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
|
@ -8,7 +9,7 @@ namespace Glamourer.Util;
|
||||||
public static class CustomizeExtensions
|
public static class CustomizeExtensions
|
||||||
{
|
{
|
||||||
// In languages other than english the actual clan name may depend on gender.
|
// In languages other than english the actual clan name may depend on gender.
|
||||||
public static string ClanName(SubRace race, Gender gender)
|
public static string ClanName(ICustomizationManager customization, SubRace race, Gender gender)
|
||||||
{
|
{
|
||||||
if (gender == Gender.FemaleNpc)
|
if (gender == Gender.FemaleNpc)
|
||||||
gender = Gender.Female;
|
gender = Gender.Female;
|
||||||
|
|
@ -16,79 +17,79 @@ public static class CustomizeExtensions
|
||||||
gender = Gender.Male;
|
gender = Gender.Male;
|
||||||
return (gender, race) switch
|
return (gender, race) switch
|
||||||
{
|
{
|
||||||
(Gender.Male, SubRace.Midlander) => Glamourer.Customization.GetName(CustomName.MidlanderM),
|
(Gender.Male, SubRace.Midlander) => customization.GetName(CustomName.MidlanderM),
|
||||||
(Gender.Male, SubRace.Highlander) => Glamourer.Customization.GetName(CustomName.HighlanderM),
|
(Gender.Male, SubRace.Highlander) => customization.GetName(CustomName.HighlanderM),
|
||||||
(Gender.Male, SubRace.Wildwood) => Glamourer.Customization.GetName(CustomName.WildwoodM),
|
(Gender.Male, SubRace.Wildwood) => customization.GetName(CustomName.WildwoodM),
|
||||||
(Gender.Male, SubRace.Duskwight) => Glamourer.Customization.GetName(CustomName.DuskwightM),
|
(Gender.Male, SubRace.Duskwight) => customization.GetName(CustomName.DuskwightM),
|
||||||
(Gender.Male, SubRace.Plainsfolk) => Glamourer.Customization.GetName(CustomName.PlainsfolkM),
|
(Gender.Male, SubRace.Plainsfolk) => customization.GetName(CustomName.PlainsfolkM),
|
||||||
(Gender.Male, SubRace.Dunesfolk) => Glamourer.Customization.GetName(CustomName.DunesfolkM),
|
(Gender.Male, SubRace.Dunesfolk) => customization.GetName(CustomName.DunesfolkM),
|
||||||
(Gender.Male, SubRace.SeekerOfTheSun) => Glamourer.Customization.GetName(CustomName.SeekerOfTheSunM),
|
(Gender.Male, SubRace.SeekerOfTheSun) => customization.GetName(CustomName.SeekerOfTheSunM),
|
||||||
(Gender.Male, SubRace.KeeperOfTheMoon) => Glamourer.Customization.GetName(CustomName.KeeperOfTheMoonM),
|
(Gender.Male, SubRace.KeeperOfTheMoon) => customization.GetName(CustomName.KeeperOfTheMoonM),
|
||||||
(Gender.Male, SubRace.Seawolf) => Glamourer.Customization.GetName(CustomName.SeawolfM),
|
(Gender.Male, SubRace.Seawolf) => customization.GetName(CustomName.SeawolfM),
|
||||||
(Gender.Male, SubRace.Hellsguard) => Glamourer.Customization.GetName(CustomName.HellsguardM),
|
(Gender.Male, SubRace.Hellsguard) => customization.GetName(CustomName.HellsguardM),
|
||||||
(Gender.Male, SubRace.Raen) => Glamourer.Customization.GetName(CustomName.RaenM),
|
(Gender.Male, SubRace.Raen) => customization.GetName(CustomName.RaenM),
|
||||||
(Gender.Male, SubRace.Xaela) => Glamourer.Customization.GetName(CustomName.XaelaM),
|
(Gender.Male, SubRace.Xaela) => customization.GetName(CustomName.XaelaM),
|
||||||
(Gender.Male, SubRace.Helion) => Glamourer.Customization.GetName(CustomName.HelionM),
|
(Gender.Male, SubRace.Helion) => customization.GetName(CustomName.HelionM),
|
||||||
(Gender.Male, SubRace.Lost) => Glamourer.Customization.GetName(CustomName.LostM),
|
(Gender.Male, SubRace.Lost) => customization.GetName(CustomName.LostM),
|
||||||
(Gender.Male, SubRace.Rava) => Glamourer.Customization.GetName(CustomName.RavaM),
|
(Gender.Male, SubRace.Rava) => customization.GetName(CustomName.RavaM),
|
||||||
(Gender.Male, SubRace.Veena) => Glamourer.Customization.GetName(CustomName.VeenaM),
|
(Gender.Male, SubRace.Veena) => customization.GetName(CustomName.VeenaM),
|
||||||
(Gender.Female, SubRace.Midlander) => Glamourer.Customization.GetName(CustomName.MidlanderF),
|
(Gender.Female, SubRace.Midlander) => customization.GetName(CustomName.MidlanderF),
|
||||||
(Gender.Female, SubRace.Highlander) => Glamourer.Customization.GetName(CustomName.HighlanderF),
|
(Gender.Female, SubRace.Highlander) => customization.GetName(CustomName.HighlanderF),
|
||||||
(Gender.Female, SubRace.Wildwood) => Glamourer.Customization.GetName(CustomName.WildwoodF),
|
(Gender.Female, SubRace.Wildwood) => customization.GetName(CustomName.WildwoodF),
|
||||||
(Gender.Female, SubRace.Duskwight) => Glamourer.Customization.GetName(CustomName.DuskwightF),
|
(Gender.Female, SubRace.Duskwight) => customization.GetName(CustomName.DuskwightF),
|
||||||
(Gender.Female, SubRace.Plainsfolk) => Glamourer.Customization.GetName(CustomName.PlainsfolkF),
|
(Gender.Female, SubRace.Plainsfolk) => customization.GetName(CustomName.PlainsfolkF),
|
||||||
(Gender.Female, SubRace.Dunesfolk) => Glamourer.Customization.GetName(CustomName.DunesfolkF),
|
(Gender.Female, SubRace.Dunesfolk) => customization.GetName(CustomName.DunesfolkF),
|
||||||
(Gender.Female, SubRace.SeekerOfTheSun) => Glamourer.Customization.GetName(CustomName.SeekerOfTheSunF),
|
(Gender.Female, SubRace.SeekerOfTheSun) => customization.GetName(CustomName.SeekerOfTheSunF),
|
||||||
(Gender.Female, SubRace.KeeperOfTheMoon) => Glamourer.Customization.GetName(CustomName.KeeperOfTheMoonF),
|
(Gender.Female, SubRace.KeeperOfTheMoon) => customization.GetName(CustomName.KeeperOfTheMoonF),
|
||||||
(Gender.Female, SubRace.Seawolf) => Glamourer.Customization.GetName(CustomName.SeawolfF),
|
(Gender.Female, SubRace.Seawolf) => customization.GetName(CustomName.SeawolfF),
|
||||||
(Gender.Female, SubRace.Hellsguard) => Glamourer.Customization.GetName(CustomName.HellsguardF),
|
(Gender.Female, SubRace.Hellsguard) => customization.GetName(CustomName.HellsguardF),
|
||||||
(Gender.Female, SubRace.Raen) => Glamourer.Customization.GetName(CustomName.RaenF),
|
(Gender.Female, SubRace.Raen) => customization.GetName(CustomName.RaenF),
|
||||||
(Gender.Female, SubRace.Xaela) => Glamourer.Customization.GetName(CustomName.XaelaF),
|
(Gender.Female, SubRace.Xaela) => customization.GetName(CustomName.XaelaF),
|
||||||
(Gender.Female, SubRace.Helion) => Glamourer.Customization.GetName(CustomName.HelionM),
|
(Gender.Female, SubRace.Helion) => customization.GetName(CustomName.HelionM),
|
||||||
(Gender.Female, SubRace.Lost) => Glamourer.Customization.GetName(CustomName.LostM),
|
(Gender.Female, SubRace.Lost) => customization.GetName(CustomName.LostM),
|
||||||
(Gender.Female, SubRace.Rava) => Glamourer.Customization.GetName(CustomName.RavaF),
|
(Gender.Female, SubRace.Rava) => customization.GetName(CustomName.RavaF),
|
||||||
(Gender.Female, SubRace.Veena) => Glamourer.Customization.GetName(CustomName.VeenaF),
|
(Gender.Female, SubRace.Veena) => customization.GetName(CustomName.VeenaF),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(race), race, null),
|
_ => throw new ArgumentOutOfRangeException(nameof(race), race, null),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ClanName(this Customize customize)
|
public static string ClanName(this Customize customize, ICustomizationManager customization)
|
||||||
=> ClanName(customize.Clan, customize.Gender);
|
=> ClanName(customization, customize.Clan, customize.Gender);
|
||||||
|
|
||||||
|
|
||||||
// Change a gender and fix up all required customizations afterwards.
|
// Change a gender and fix up all required customizations afterwards.
|
||||||
public static CustomizeFlag ChangeGender(this Customize customize, CharacterEquip equip, Gender gender)
|
public static CustomizeFlag ChangeGender(this Customize customize, CharacterEquip equip, Gender gender, ItemManager items, ICustomizationManager customization)
|
||||||
{
|
{
|
||||||
if (customize.Gender == gender)
|
if (customize.Gender == gender)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
FixRestrictedGear(customize, equip, gender, customize.Race);
|
FixRestrictedGear(items, customize, equip, gender, customize.Race);
|
||||||
customize.Gender = gender;
|
customize.Gender = gender;
|
||||||
return CustomizeFlag.Gender | FixUpAttributes(customize);
|
return CustomizeFlag.Gender | FixUpAttributes(customization, customize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change a race and fix up all required customizations afterwards.
|
// Change a race and fix up all required customizations afterwards.
|
||||||
public static CustomizeFlag ChangeRace(this Customize customize, CharacterEquip equip, SubRace clan)
|
public static CustomizeFlag ChangeRace(this Customize customize, CharacterEquip equip, SubRace clan, ItemManager items, ICustomizationManager customization)
|
||||||
{
|
{
|
||||||
if (customize.Clan == clan)
|
if (customize.Clan == clan)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var race = clan.ToRace();
|
var race = clan.ToRace();
|
||||||
var gender = race == Race.Hrothgar ? Gender.Male : customize.Gender; // TODO Female Hrothgar
|
var gender = race == Race.Hrothgar ? Gender.Male : customize.Gender; // TODO Female Hrothgar
|
||||||
FixRestrictedGear(customize, equip, gender, race);
|
FixRestrictedGear(items, customize, equip, gender, race);
|
||||||
var flags = CustomizeFlag.Race | CustomizeFlag.Clan;
|
var flags = CustomizeFlag.Race | CustomizeFlag.Clan;
|
||||||
if (gender != customize.Gender)
|
if (gender != customize.Gender)
|
||||||
flags |= CustomizeFlag.Gender;
|
flags |= CustomizeFlag.Gender;
|
||||||
customize.Gender = gender;
|
customize.Gender = gender;
|
||||||
customize.Race = race;
|
customize.Race = race;
|
||||||
customize.Clan = clan;
|
customize.Clan = clan;
|
||||||
return flags | FixUpAttributes(customize);
|
return flags | FixUpAttributes(customization, customize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go through a whole customization struct and fix up all settings that need fixing.
|
// Go through a whole customization struct and fix up all settings that need fixing.
|
||||||
private static CustomizeFlag FixUpAttributes(Customize customize)
|
private static CustomizeFlag FixUpAttributes(ICustomizationManager customization, Customize customize)
|
||||||
{
|
{
|
||||||
var set = Glamourer.Customization.GetList(customize.Clan, customize.Gender);
|
var set = customization.GetList(customize.Clan, customize.Gender);
|
||||||
CustomizeFlag flags = 0;
|
CustomizeFlag flags = 0;
|
||||||
foreach (CustomizeIndex id in Enum.GetValues(typeof(CustomizeIndex)))
|
foreach (CustomizeIndex id in Enum.GetValues(typeof(CustomizeIndex)))
|
||||||
{
|
{
|
||||||
|
|
@ -115,12 +116,12 @@ public static class CustomizeExtensions
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FixRestrictedGear(Customize customize, CharacterEquip equip, Gender gender, Race race)
|
private static void FixRestrictedGear(ItemManager items, Customize customize, CharacterEquip equip, Gender gender, Race race)
|
||||||
{
|
{
|
||||||
if (!equip || race == customize.Race && gender == customize.Gender)
|
if (!equip || race == customize.Race && gender == customize.Gender)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
(_, equip[slot]) = Glamourer.Items.ResolveRestrictedGear(equip[slot], slot, race, gender);
|
(_, equip[slot]) = items.ResolveRestrictedGear(equip[slot], slot, race, gender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue