From 71e11c5b45e4419e06c27fef7ca93e4742cca1fb Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Thu, 27 Oct 2022 12:49:18 +0200 Subject: [PATCH] add customizeplus support --- .../Factories/CharacterDataFactory.cs | 3 +- MareSynchronos/Managers/CachedPlayer.cs | 10 +++ MareSynchronos/Managers/IpcManager.cs | 73 ++++++++++++++++++- MareSynchronos/Managers/PlayerManager.cs | 17 ++++- MareSynchronos/Models/CharacterData.cs | 6 +- MareSynchronos/UI/UIShared.cs | 14 +++- 6 files changed, 114 insertions(+), 9 deletions(-) diff --git a/MareSynchronos/Factories/CharacterDataFactory.cs b/MareSynchronos/Factories/CharacterDataFactory.cs index a1c85c0..172cd90 100644 --- a/MareSynchronos/Factories/CharacterDataFactory.cs +++ b/MareSynchronos/Factories/CharacterDataFactory.cs @@ -263,7 +263,7 @@ public class CharacterDataFactory Thread.Sleep(50); } - _dalamudUtil.WaitWhileCharacterIsDrawing(objectKind.ToString(), charaPointer, 15000); + _dalamudUtil.WaitWhileCharacterIsDrawing(objectKind.ToString(), charaPointer, objectKind == ObjectKind.MinionOrMount ? 1000 : 15000); var human = (Human*)((Character*)charaPointer)->GameObject.GetDrawObject(); for (var mdlIdx = 0; mdlIdx < human->CharacterBase.SlotCount; ++mdlIdx) @@ -303,6 +303,7 @@ public class CharacterDataFactory previousData.ManipulationString = _ipcManager.PenumbraGetMetaManipulations(); previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(charaPointer); previousData.HeelsOffset = _ipcManager.GetHeelsOffset(); + previousData.CustomizePlusScale = _ipcManager.GetCustomizePlusScale(); Logger.Debug("Handling transient update for " + objectKind); ManageSemiTransientData(previousData, objectKind, charaPointer); diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index 70318a4..a409a7f 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -126,6 +126,14 @@ public class CachedPlayer charaDataToUpdate.Add(objectKind); continue; } + + bool customizeDataDifferent = _cachedData.CustomizePlusData != characterData.CustomizePlusData; + if (customizeDataDifferent) + { + Logger.Debug("Updating " + objectKind); + charaDataToUpdate.Add(objectKind); + continue; + } } } @@ -248,6 +256,7 @@ public class CachedPlayer _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName!, PlayerCharacter, 10000, ct); ct.ThrowIfCancellationRequested(); _ipcManager.HeelsSetOffsetForPlayer(_cachedData.HeelsOffset, PlayerCharacter); + _ipcManager.CustomizePlusSetBodyScale(PlayerCharacter, _cachedData.CustomizePlusData); RequestedPenumbraRedraw = true; Logger.Debug( $"Request Redraw for {PlayerName}"); @@ -337,6 +346,7 @@ public class CachedPlayer _ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter); _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter); _ipcManager.HeelsRestoreOffsetForPlayer(PlayerCharacter); + _ipcManager.CustomizePlusRevert(PlayerCharacter); } else { diff --git a/MareSynchronos/Managers/IpcManager.cs b/MareSynchronos/Managers/IpcManager.cs index cdd351c..e6df56c 100644 --- a/MareSynchronos/Managers/IpcManager.cs +++ b/MareSynchronos/Managers/IpcManager.cs @@ -4,15 +4,16 @@ using System; using System.Collections.Generic; using Dalamud.Game.ClientState.Objects.Types; using MareSynchronos.Utils; -using MareSynchronos.WebAPI; using Action = System.Action; using System.Collections.Concurrent; +using System.Text; namespace MareSynchronos.Managers; public delegate void PenumbraRedrawEvent(IntPtr address, int objTblIdx); public delegate void HeelsOffsetChange(float change); public delegate void PenumbraResourceLoadEvent(IntPtr drawObject, string gamePath, string filePath); +public delegate void CustomizePlusScaleChange(string? scale); public class IpcManager : IDisposable { private readonly ICallGateSubscriber _glamourerApiVersion; @@ -43,6 +44,12 @@ public class IpcManager : IDisposable private readonly ICallGateSubscriber _heelsRegisterPlayer; private readonly ICallGateSubscriber _heelsUnregisterPlayer; + private readonly ICallGateSubscriber _customizePlusApiVersion; + private readonly ICallGateSubscriber _customizePlusGetBodyScale; + private readonly ICallGateSubscriber _customizePlusSetBodyScaleToCharacter; + private readonly ICallGateSubscriber _customizePlusRevert; + private readonly ICallGateSubscriber _customizePlusOnScaleUpdate; + private readonly DalamudUtil _dalamudUtil; private readonly ConcurrentQueue actionQueue = new(); @@ -89,6 +96,14 @@ public class IpcManager : IDisposable _heelsOffsetUpdate.Subscribe(HeelsOffsetChange); + _customizePlusApiVersion = pi.GetIpcSubscriber("CustomizePlus.GetApiVersion"); + _customizePlusGetBodyScale = pi.GetIpcSubscriber("CustomizePlus.GetBodyScale"); + _customizePlusRevert = pi.GetIpcSubscriber("CustomizePlus.RevertCharacter"); + _customizePlusSetBodyScaleToCharacter = pi.GetIpcSubscriber("CustomizePlus.SetBodyScaleToCharacter"); + _customizePlusOnScaleUpdate = pi.GetIpcSubscriber("CustomizePlus.OnScaleUpdate"); + + _customizePlusOnScaleUpdate.Subscribe(OnCustomizePlusScaleChange); + if (Initialized) { PenumbraInitialized?.Invoke(); @@ -128,6 +143,7 @@ public class IpcManager : IDisposable public event PenumbraRedrawEvent? PenumbraRedrawEvent; public event HeelsOffsetChange? HeelsOffsetChangeEvent; public event PenumbraResourceLoadEvent? PenumbraResourceLoadEvent; + public event CustomizePlusScaleChange? CustomizePlusScaleChange; public bool Initialized => CheckPenumbraApi(); public bool CheckGlamourerApi() @@ -166,6 +182,18 @@ public class IpcManager : IDisposable } } + public bool CheckCustomizePlusApi() + { + try + { + return string.Equals(_customizePlusApiVersion.InvokeFunc(), "1.0", StringComparison.Ordinal); + } + catch + { + return false; + } + } + public void Dispose() { Logger.Verbose("Disposing " + nameof(IpcManager)); @@ -229,6 +257,43 @@ public class IpcManager : IDisposable }); } + public string GetCustomizePlusScale() + { + if (!CheckCustomizePlusApi()) return string.Empty; + var scale = _customizePlusGetBodyScale.InvokeFunc(_dalamudUtil.PlayerName); + if(string.IsNullOrEmpty(scale)) return string.Empty; + return Convert.ToBase64String(Encoding.UTF8.GetBytes(scale)); + } + + public void CustomizePlusSetBodyScale(IntPtr character, string scale) + { + if (!CheckCustomizePlusApi() || string.IsNullOrEmpty(scale)) return; + actionQueue.Enqueue(() => + { + var gameObj = _dalamudUtil.CreateGameObject(character); + if (gameObj is Character c) + { + string decodedScale = Encoding.UTF8.GetString(Convert.FromBase64String(scale)); + Logger.Verbose("CustomizePlus applying for " + c.Address.ToString("X")); + _customizePlusSetBodyScaleToCharacter!.InvokeAction(decodedScale, c); + } + }); + } + + public void CustomizePlusRevert(IntPtr character) + { + if (!CheckCustomizePlusApi()) return; + actionQueue.Enqueue(() => + { + var gameObj = _dalamudUtil.CreateGameObject(character); + if (gameObj is Character c) + { + Logger.Verbose("CustomizePlus reverting for " + c.Address.ToString("X")); + _customizePlusRevert!.InvokeAction(c); + } + }); + } + public void GlamourerApplyAll(string? customization, IntPtr obj) { if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return; @@ -392,6 +457,12 @@ public class IpcManager : IDisposable HeelsOffsetChangeEvent?.Invoke(offset); } + private void OnCustomizePlusScaleChange(string? scale) + { + if (scale != null) scale = Convert.ToBase64String(Encoding.UTF8.GetBytes(scale)); + CustomizePlusScaleChange?.Invoke(scale); + } + private void PenumbraDispose() { PenumbraDisposed?.Invoke(); diff --git a/MareSynchronos/Managers/PlayerManager.cs b/MareSynchronos/Managers/PlayerManager.cs index accfd0c..4b222f6 100644 --- a/MareSynchronos/Managers/PlayerManager.cs +++ b/MareSynchronos/Managers/PlayerManager.cs @@ -53,6 +53,7 @@ public class PlayerManager : IDisposable _transientResourceManager.TransientResourceLoaded += HandleTransientResourceLoad; _dalamudUtil.DelayedFrameworkUpdate += DalamudUtilOnDelayedFrameworkUpdate; _ipcManager.HeelsOffsetChangeEvent += HeelsOffsetChanged; + _ipcManager.CustomizePlusScaleChange += CustomizePlusChanged; _dalamudUtil.FrameworkUpdate += DalamudUtilOnFrameworkUpdate; @@ -105,7 +106,18 @@ public class PlayerManager : IDisposable if (LastCreatedCharacterData != null && LastCreatedCharacterData.HeelsOffset != change && !player.IsProcessing) { Logger.Debug("Heels offset changed to " + change); - playerRelatedObjects.First(f => f.ObjectKind == ObjectKind.Player).HasTransientsUpdate = true; + player.HasTransientsUpdate = true; + } + } + + private void CustomizePlusChanged(string? change) + { + change ??= string.Empty; + var player = playerRelatedObjects.First(f => f.ObjectKind == ObjectKind.Player); + if (LastCreatedCharacterData != null && LastCreatedCharacterData.CustomizePlusData != change && !player.IsProcessing) + { + Logger.Debug("CustomizePlus data changed to " + change); + player.HasTransientsUpdate = true; } } @@ -124,6 +136,7 @@ public class PlayerManager : IDisposable _playerChangedCts?.Cancel(); _ipcManager.HeelsOffsetChangeEvent -= HeelsOffsetChanged; + _ipcManager.CustomizePlusScaleChange -= CustomizePlusChanged; } private unsafe void DalamudUtilOnDelayedFrameworkUpdate() @@ -241,7 +254,7 @@ public class PlayerManager : IDisposable _periodicFileScanner.HaltScan("Character creation"); foreach (var item in unprocessedObjects) { - _dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, 10000, token); + _dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, item.ObjectKind == ObjectKind.MinionOrMount ? 1000 : 10000, token); } cacheDto = (await CreateFullCharacterCacheDto(token).ConfigureAwait(false)); diff --git a/MareSynchronos/Models/CharacterData.cs b/MareSynchronos/Models/CharacterData.cs index 0724ef8..31b1c40 100644 --- a/MareSynchronos/Models/CharacterData.cs +++ b/MareSynchronos/Models/CharacterData.cs @@ -25,6 +25,9 @@ public class CharacterData [JsonProperty] public float HeelsOffset { get; set; } = 0f; + [JsonProperty] + public string CustomizePlusScale { get; set; } = string.Empty; + public void AddFileReplacement(ObjectKind objectKind, FileReplacement fileReplacement) { if (!fileReplacement.HasFileReplacement) return; @@ -71,7 +74,8 @@ public class CharacterData FileReplacements = fileReplacements, GlamourerData = GlamourerString.ToDictionary(d => d.Key, d => d.Value), ManipulationData = ManipulationString, - HeelsOffset = HeelsOffset + HeelsOffset = HeelsOffset, + CustomizePlusData = CustomizePlusScale }; } diff --git a/MareSynchronos/UI/UIShared.cs b/MareSynchronos/UI/UIShared.cs index 1080a36..f86c75c 100644 --- a/MareSynchronos/UI/UIShared.cs +++ b/MareSynchronos/UI/UIShared.cs @@ -41,7 +41,7 @@ public class UiShared : IDisposable public bool UidFontBuilt { get; private set; } public static bool CtrlPressed() => (GetKeyState(0xA2) & 0x8000) != 0 || (GetKeyState(0xA3) & 0x8000) != 0; public static bool ShiftPressed() => (GetKeyState(0xA1) & 0x8000) != 0 || (GetKeyState(0xA0) & 0x8000) != 0; - + public static ImGuiWindowFlags PopupWindowFlags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; @@ -115,10 +115,10 @@ public class UiShared : IDisposable var center = ImGui.GetMainViewport().GetCenter(); ImGui.SetWindowPos(new Vector2(center.X - x / 2, center.Y - y / 2)); } - + ImGui.SetWindowSize(new Vector2(x, y)); } - + public static void SetScaledWindowSize(float width, float height, bool centerWindow = true) { ImGui.SameLine(); @@ -130,7 +130,7 @@ public class UiShared : IDisposable var center = ImGui.GetMainViewport().GetCenter(); ImGui.SetWindowPos(new Vector2(center.X - x / 2, center.Y - y / 2)); } - + ImGui.SetWindowSize(new Vector2(x, y)); } @@ -154,10 +154,12 @@ public class UiShared : IDisposable var penumbraExists = _ipcManager.CheckPenumbraApi(); var glamourerExists = _ipcManager.CheckGlamourerApi(); var heelsExists = _ipcManager.CheckHeelsApi(); + var customizeExists = _ipcManager.CheckCustomizePlusApi(); var penumbraColor = penumbraExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; var glamourerColor = glamourerExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; var heelsColor = heelsExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; + var customizeColor = customizeExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; ImGui.Text("Penumbra:"); ImGui.SameLine(); ImGui.TextColored(penumbraColor, penumbraExists ? "Available" : "Unavailable"); @@ -170,6 +172,10 @@ public class UiShared : IDisposable ImGui.Text("Heels:"); ImGui.SameLine(); ImGui.TextColored(heelsColor, heelsExists ? "Available" : "Unavailable"); + ImGui.SameLine(); + ImGui.Text("Customize+:"); + ImGui.SameLine(); + ImGui.TextColored(customizeColor, customizeExists ? "Available" : "Unavailable"); if (!penumbraExists || !glamourerExists) {