Add support for Palette+ (#40)
This commit is contained in:
		| @@ -11,6 +11,7 @@ public record MareCharaFileData | |||||||
|     public string Description { get; set; } = string.Empty; |     public string Description { get; set; } = string.Empty; | ||||||
|     public string GlamourerData { get; set; } = string.Empty; |     public string GlamourerData { get; set; } = string.Empty; | ||||||
|     public string CustomizePlusData { get; set; } = string.Empty; |     public string CustomizePlusData { get; set; } = string.Empty; | ||||||
|  |     public string PalettePlusData { get; set; } = string.Empty; | ||||||
|     public string ManipulationData { get; set; } = string.Empty; |     public string ManipulationData { get; set; } = string.Empty; | ||||||
|     public List<FileData> Files { get; set; } = new(); |     public List<FileData> Files { get; set; } = new(); | ||||||
|     public List<FileSwap> FileSwaps { get; set; } = new(); |     public List<FileSwap> FileSwaps { get; set; } = new(); | ||||||
| @@ -26,6 +27,7 @@ public record MareCharaFileData | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         CustomizePlusData = dto.CustomizePlusData; |         CustomizePlusData = dto.CustomizePlusData; | ||||||
|  |         PalettePlusData = dto.PalettePlusData; | ||||||
|         ManipulationData = dto.ManipulationData; |         ManipulationData = dto.ManipulationData; | ||||||
|  |  | ||||||
|         if (dto.FileReplacements.TryGetValue(ObjectKind.Player, out var fileReplacements)) |         if (dto.FileReplacements.TryGetValue(ObjectKind.Player, out var fileReplacements)) | ||||||
|   | |||||||
| @@ -326,6 +326,7 @@ public class CharacterDataFactory | |||||||
|         previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(charaPointer); |         previousData.GlamourerString[objectKind] = _ipcManager.GlamourerGetCharacterCustomization(charaPointer); | ||||||
|         previousData.HeelsOffset = _ipcManager.GetHeelsOffset(); |         previousData.HeelsOffset = _ipcManager.GetHeelsOffset(); | ||||||
|         previousData.CustomizePlusScale = _ipcManager.GetCustomizePlusScale(); |         previousData.CustomizePlusScale = _ipcManager.GetCustomizePlusScale(); | ||||||
|  |         previousData.PalettePlusPalette = _ipcManager.PalettePlusGetPalette(); | ||||||
|  |  | ||||||
|         Logger.Debug("Handling transient update for " + objectKind); |         Logger.Debug("Handling transient update for " + objectKind); | ||||||
|         ManageSemiTransientData(previousData, objectKind, charaPointer); |         ManageSemiTransientData(previousData, objectKind, charaPointer); | ||||||
|   | |||||||
| @@ -129,6 +129,14 @@ public class CachedPlayer : IDisposable | |||||||
|                     charaDataToUpdate.Add(objectKind); |                     charaDataToUpdate.Add(objectKind); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 bool palettePlusDataDifferent = !string.Equals(_cachedData.PalettePlusData, characterData.PalettePlusData, StringComparison.Ordinal); | ||||||
|  |                 if (palettePlusDataDifferent) | ||||||
|  |                 { | ||||||
|  |                     Logger.Debug("Updating " + objectKind); | ||||||
|  |                     charaDataToUpdate.Add(objectKind); | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -149,6 +157,15 @@ public class CachedPlayer : IDisposable | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (!string.IsNullOrEmpty(characterData.PalettePlusData)) | ||||||
|  |         { | ||||||
|  |             if (!warning.ShownPalettePlusWarning && !_ipcManager.CheckPalettePlusApi()) | ||||||
|  |             { | ||||||
|  |                 _dalamudUtil.PrintWarnChat("Received Palette+ data for player " + PlayerName + ", but Palette+ is not installed. Install Palette+ to experience their character fully."); | ||||||
|  |                 warning.ShownPalettePlusWarning = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         _cachedData = characterData; |         _cachedData = characterData; | ||||||
|  |  | ||||||
|         DownloadAndApplyCharacter(charaDataToUpdate, updateModdedPaths); |         DownloadAndApplyCharacter(charaDataToUpdate, updateModdedPaths); | ||||||
| @@ -244,6 +261,7 @@ public class CachedPlayer : IDisposable | |||||||
|                 ct.ThrowIfCancellationRequested(); |                 ct.ThrowIfCancellationRequested(); | ||||||
|                 _ipcManager.HeelsSetOffsetForPlayer(_cachedData.HeelsOffset, PlayerCharacter); |                 _ipcManager.HeelsSetOffsetForPlayer(_cachedData.HeelsOffset, PlayerCharacter); | ||||||
|                 _ipcManager.CustomizePlusSetBodyScale(PlayerCharacter, _cachedData.CustomizePlusData); |                 _ipcManager.CustomizePlusSetBodyScale(PlayerCharacter, _cachedData.CustomizePlusData); | ||||||
|  |                 _ipcManager.PalettePlusSetPalette(PlayerCharacter, _cachedData.PalettePlusData); | ||||||
|                 RequestedPenumbraRedraw = true; |                 RequestedPenumbraRedraw = true; | ||||||
|                 Logger.Debug( |                 Logger.Debug( | ||||||
|                     $"Request Redraw for {PlayerName}"); |                     $"Request Redraw for {PlayerName}"); | ||||||
| @@ -449,6 +467,7 @@ public class CachedPlayer : IDisposable | |||||||
|                 _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter); |                 _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter); | ||||||
|                 _ipcManager.HeelsRestoreOffsetForPlayer(PlayerCharacter); |                 _ipcManager.HeelsRestoreOffsetForPlayer(PlayerCharacter); | ||||||
|                 _ipcManager.CustomizePlusRevert(PlayerCharacter); |                 _ipcManager.CustomizePlusRevert(PlayerCharacter); | ||||||
|  |                 _ipcManager.PalettePlusRemovePalette(PlayerCharacter); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -51,6 +51,12 @@ public class IpcManager : IDisposable | |||||||
|     private readonly ICallGateSubscriber<Character?, object> _customizePlusRevert; |     private readonly ICallGateSubscriber<Character?, object> _customizePlusRevert; | ||||||
|     private readonly ICallGateSubscriber<string?, object> _customizePlusOnScaleUpdate; |     private readonly ICallGateSubscriber<string?, object> _customizePlusOnScaleUpdate; | ||||||
|      |      | ||||||
|  |     private readonly ICallGateSubscriber<string> _palettePlusApiVersion; | ||||||
|  |     private readonly ICallGateSubscriber<Character, string> _palettePlusGetCharaPalette; | ||||||
|  |     private readonly ICallGateSubscriber<Character, string, object> _palettePlusSetCharaPalette; | ||||||
|  |     private readonly ICallGateSubscriber<Character, object> _palettePlusRemoveCharaPalette; | ||||||
|  |     private readonly ICallGateSubscriber<Character, string, object> _palettePlusPaletteChanged; | ||||||
|  |  | ||||||
|     private readonly DalamudUtil _dalamudUtil; |     private readonly DalamudUtil _dalamudUtil; | ||||||
|     private bool _inGposeQueueMode = false; |     private bool _inGposeQueueMode = false; | ||||||
|     private ConcurrentQueue<Action> ActionQueue => _inGposeQueueMode ? _gposeActionQueue : _normalQueue; |     private ConcurrentQueue<Action> ActionQueue => _inGposeQueueMode ? _gposeActionQueue : _normalQueue; | ||||||
| @@ -103,6 +109,14 @@ public class IpcManager : IDisposable | |||||||
|  |  | ||||||
|         _customizePlusOnScaleUpdate.Subscribe(OnCustomizePlusScaleChange); |         _customizePlusOnScaleUpdate.Subscribe(OnCustomizePlusScaleChange); | ||||||
|          |          | ||||||
|  |         _palettePlusApiVersion = pi.GetIpcSubscriber<string>("PalettePlus.ApiVersion"); | ||||||
|  |         _palettePlusGetCharaPalette = pi.GetIpcSubscriber<Character, string>("PalettePlus.GetCharaPalette"); | ||||||
|  |         _palettePlusSetCharaPalette = pi.GetIpcSubscriber<Character, string, object>("PalettePlus.SetCharaPalette"); | ||||||
|  |         _palettePlusRemoveCharaPalette = pi.GetIpcSubscriber<Character, object>("PalettePlus.RemoveCharaPalette"); | ||||||
|  |         _palettePlusPaletteChanged = pi.GetIpcSubscriber<Character, string, object>("PalettePlus.PaletteChanged"); | ||||||
|  |  | ||||||
|  |         _palettePlusPaletteChanged.Subscribe(OnPalettePlusPaletteChange); | ||||||
|  |  | ||||||
|         if (Initialized) |         if (Initialized) | ||||||
|         { |         { | ||||||
|             PenumbraInitialized?.Invoke(); |             PenumbraInitialized?.Invoke(); | ||||||
| @@ -168,6 +182,7 @@ public class IpcManager : IDisposable | |||||||
|     public event FloatDelegate? HeelsOffsetChangeEvent; |     public event FloatDelegate? HeelsOffsetChangeEvent; | ||||||
|     public event PenumbraFileResourceDelegate? PenumbraResourceLoadEvent; |     public event PenumbraFileResourceDelegate? PenumbraResourceLoadEvent; | ||||||
|     public event StringDelegate? CustomizePlusScaleChange; |     public event StringDelegate? CustomizePlusScaleChange; | ||||||
|  |     public event StringDelegate? PalettePlusPaletteChange; | ||||||
|  |  | ||||||
|     public bool Initialized => CheckPenumbraApi(); |     public bool Initialized => CheckPenumbraApi(); | ||||||
|     public bool CheckGlamourerApi() |     public bool CheckGlamourerApi() | ||||||
| @@ -218,6 +233,18 @@ public class IpcManager : IDisposable | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public bool CheckPalettePlusApi() | ||||||
|  |     { | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             return string.Equals(_palettePlusApiVersion.InvokeFunc(), "1.0.0", StringComparison.Ordinal); | ||||||
|  |         } | ||||||
|  |         catch | ||||||
|  |         { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public void Dispose() |     public void Dispose() | ||||||
|     { |     { | ||||||
|         Logger.Verbose("Disposing " + nameof(IpcManager)); |         Logger.Verbose("Disposing " + nameof(IpcManager)); | ||||||
| @@ -503,6 +530,59 @@ public class IpcManager : IDisposable | |||||||
|         CustomizePlusScaleChange?.Invoke(scale); |         CustomizePlusScaleChange?.Invoke(scale); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void OnPalettePlusPaletteChange(Character character, string palette) | ||||||
|  |     { | ||||||
|  |         if (character.Address == 0 || character.Address != _dalamudUtil.PlayerPointer) return; | ||||||
|  |         if (palette != null) palette = Convert.ToBase64String(Encoding.UTF8.GetBytes(palette)); | ||||||
|  |         PalettePlusPaletteChange?.Invoke(palette); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void PalettePlusSetPalette(IntPtr character, string palette) | ||||||
|  |     { | ||||||
|  |         if (!CheckPalettePlusApi()) return; | ||||||
|  |         ActionQueue.Enqueue(() => | ||||||
|  |         { | ||||||
|  |             var gameObj = _dalamudUtil.CreateGameObject(character); | ||||||
|  |             if (gameObj is Character c) | ||||||
|  |             { | ||||||
|  |                 string decodedPalette = Encoding.UTF8.GetString(Convert.FromBase64String(palette)); | ||||||
|  |                  | ||||||
|  |                 if (string.IsNullOrEmpty(decodedPalette)) | ||||||
|  |                 { | ||||||
|  |                     Logger.Verbose("PalettePlus removing for " + c.Address.ToString("X")); | ||||||
|  |                     _palettePlusRemoveCharaPalette!.InvokeAction(c); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     Logger.Verbose("PalettePlus applying for " + c.Address.ToString("X")); | ||||||
|  |                     _palettePlusSetCharaPalette!.InvokeAction(c, decodedPalette); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public string PalettePlusGetPalette() | ||||||
|  |     { | ||||||
|  |         if (!CheckPalettePlusApi()) return string.Empty; | ||||||
|  |         var palette = _palettePlusGetCharaPalette.InvokeFunc(_dalamudUtil.PlayerCharacter); | ||||||
|  |         if (string.IsNullOrEmpty(palette)) return string.Empty; | ||||||
|  |         return Convert.ToBase64String(Encoding.UTF8.GetBytes(palette)); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     public void PalettePlusRemovePalette(IntPtr character) | ||||||
|  |     { | ||||||
|  |         if (!CheckPalettePlusApi()) return; | ||||||
|  |         ActionQueue.Enqueue(() => | ||||||
|  |         { | ||||||
|  |             var gameObj = _dalamudUtil.CreateGameObject(character); | ||||||
|  |             if (gameObj is Character c) | ||||||
|  |             { | ||||||
|  |                 Logger.Verbose("PalettePlus removing for " + c.Address.ToString("X")); | ||||||
|  |                 _palettePlusRemoveCharaPalette!.InvokeAction(c); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void PenumbraDispose() |     private void PenumbraDispose() | ||||||
|     { |     { | ||||||
|         PenumbraDisposed?.Invoke(); |         PenumbraDisposed?.Invoke(); | ||||||
|   | |||||||
| @@ -51,6 +51,7 @@ public class PlayerManager : IDisposable | |||||||
|         _dalamudUtil.DelayedFrameworkUpdate += DalamudUtilOnDelayedFrameworkUpdate; |         _dalamudUtil.DelayedFrameworkUpdate += DalamudUtilOnDelayedFrameworkUpdate; | ||||||
|         _ipcManager.HeelsOffsetChangeEvent += HeelsOffsetChanged; |         _ipcManager.HeelsOffsetChangeEvent += HeelsOffsetChanged; | ||||||
|         _ipcManager.CustomizePlusScaleChange += CustomizePlusChanged; |         _ipcManager.CustomizePlusScaleChange += CustomizePlusChanged; | ||||||
|  |         _ipcManager.PalettePlusPaletteChange += PalettePlusChanged; | ||||||
|         _dalamudUtil.FrameworkUpdate += DalamudUtilOnFrameworkUpdate; |         _dalamudUtil.FrameworkUpdate += DalamudUtilOnFrameworkUpdate; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -118,6 +119,17 @@ public class PlayerManager : IDisposable | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void PalettePlusChanged(string? change) | ||||||
|  |     { | ||||||
|  |         change ??= string.Empty; | ||||||
|  |         var player = _playerRelatedObjects.First(f => f.ObjectKind == ObjectKind.Player); | ||||||
|  |         if (LastCreatedCharacterData != null && !string.Equals(LastCreatedCharacterData.PalettePlusData, change, StringComparison.Ordinal) && !player.IsProcessing) | ||||||
|  |         { | ||||||
|  |             Logger.Debug("PalettePlus data changed to " + change); | ||||||
|  |             player.HasTransientsUpdate = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public void Dispose() |     public void Dispose() | ||||||
|     { |     { | ||||||
|         Logger.Verbose("Disposing " + nameof(PlayerManager)); |         Logger.Verbose("Disposing " + nameof(PlayerManager)); | ||||||
| @@ -134,6 +146,7 @@ public class PlayerManager : IDisposable | |||||||
|         _playerChangedCts?.Cancel(); |         _playerChangedCts?.Cancel(); | ||||||
|         _ipcManager.HeelsOffsetChangeEvent -= HeelsOffsetChanged; |         _ipcManager.HeelsOffsetChangeEvent -= HeelsOffsetChanged; | ||||||
|         _ipcManager.CustomizePlusScaleChange -= CustomizePlusChanged; |         _ipcManager.CustomizePlusScaleChange -= CustomizePlusChanged; | ||||||
|  |         _ipcManager.PalettePlusPaletteChange -= PalettePlusChanged; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private unsafe void DalamudUtilOnDelayedFrameworkUpdate() |     private unsafe void DalamudUtilOnDelayedFrameworkUpdate() | ||||||
|   | |||||||
| @@ -26,6 +26,9 @@ public class CharacterData | |||||||
|     [JsonProperty] |     [JsonProperty] | ||||||
|     public string CustomizePlusScale { get; set; } = string.Empty; |     public string CustomizePlusScale { get; set; } = string.Empty; | ||||||
|      |      | ||||||
|  |     [JsonProperty] | ||||||
|  |     public string PalettePlusPalette { get; set; } = string.Empty; | ||||||
|  |  | ||||||
|     public void AddFileReplacement(ObjectKind objectKind, FileReplacement fileReplacement) |     public void AddFileReplacement(ObjectKind objectKind, FileReplacement fileReplacement) | ||||||
|     { |     { | ||||||
|         if (!fileReplacement.HasFileReplacement) return; |         if (!fileReplacement.HasFileReplacement) return; | ||||||
| @@ -74,6 +77,7 @@ public class CharacterData | |||||||
|             ManipulationData = ManipulationString, |             ManipulationData = ManipulationString, | ||||||
|             HeelsOffset = HeelsOffset, |             HeelsOffset = HeelsOffset, | ||||||
|             CustomizePlusData = CustomizePlusScale, |             CustomizePlusData = CustomizePlusScale, | ||||||
|  |             PalettePlusData = PalettePlusPalette, | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,4 +4,5 @@ public record OptionalPluginWarning | |||||||
| { | { | ||||||
|     public bool ShownHeelsWarning { get; set; } = false; |     public bool ShownHeelsWarning { get; set; } = false; | ||||||
|     public bool ShownCustomizePlusWarning { get; set; } = false; |     public bool ShownCustomizePlusWarning { get; set; } = false; | ||||||
|  |     public bool ShownPalettePlusWarning { get; set; } = false; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -64,6 +64,7 @@ public class Pair | |||||||
|         { |         { | ||||||
|             ShownCustomizePlusWarning = _configService.Current.DisableOptionalPluginWarnings, |             ShownCustomizePlusWarning = _configService.Current.DisableOptionalPluginWarnings, | ||||||
|             ShownHeelsWarning = _configService.Current.DisableOptionalPluginWarnings, |             ShownHeelsWarning = _configService.Current.DisableOptionalPluginWarnings, | ||||||
|  |             ShownPalettePlusWarning = _configService.Current.DisableOptionalPluginWarnings, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         CachedPlayer.Initialize(address, name); |         CachedPlayer.Initialize(address, name); | ||||||
| @@ -91,6 +92,7 @@ public class Pair | |||||||
|         { |         { | ||||||
|             ShownCustomizePlusWarning = _configService.Current.DisableOptionalPluginWarnings, |             ShownCustomizePlusWarning = _configService.Current.DisableOptionalPluginWarnings, | ||||||
|             ShownHeelsWarning = _configService.Current.DisableOptionalPluginWarnings, |             ShownHeelsWarning = _configService.Current.DisableOptionalPluginWarnings, | ||||||
|  |             ShownPalettePlusWarning = _configService.Current.DisableOptionalPluginWarnings, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         CachedPlayer.ApplyCharacterData(RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, _pluginWarnings); |         CachedPlayer.ApplyCharacterData(RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, _pluginWarnings); | ||||||
|   | |||||||
| @@ -181,11 +181,13 @@ public partial class UiShared : IDisposable | |||||||
|         var glamourerExists = _ipcManager.CheckGlamourerApi(); |         var glamourerExists = _ipcManager.CheckGlamourerApi(); | ||||||
|         var heelsExists = _ipcManager.CheckHeelsApi(); |         var heelsExists = _ipcManager.CheckHeelsApi(); | ||||||
|         var customizeExists = _ipcManager.CheckCustomizePlusApi(); |         var customizeExists = _ipcManager.CheckCustomizePlusApi(); | ||||||
|  |         var paletteExists = _ipcManager.CheckPalettePlusApi(); | ||||||
|  |  | ||||||
|         var penumbraColor = penumbraExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; |         var penumbraColor = penumbraExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; | ||||||
|         var glamourerColor = glamourerExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; |         var glamourerColor = glamourerExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; | ||||||
|         var heelsColor = heelsExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; |         var heelsColor = heelsExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; | ||||||
|         var customizeColor = customizeExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; |         var customizeColor = customizeExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; | ||||||
|  |         var paletteColor = paletteExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; | ||||||
|         ImGui.Text("Penumbra:"); |         ImGui.Text("Penumbra:"); | ||||||
|         ImGui.SameLine(); |         ImGui.SameLine(); | ||||||
|         ImGui.TextColored(penumbraColor, penumbraExists ? "Available" : "Unavailable"); |         ImGui.TextColored(penumbraColor, penumbraExists ? "Available" : "Unavailable"); | ||||||
| @@ -202,6 +204,10 @@ public partial class UiShared : IDisposable | |||||||
|         ImGui.Text("Customize+:"); |         ImGui.Text("Customize+:"); | ||||||
|         ImGui.SameLine(); |         ImGui.SameLine(); | ||||||
|         ImGui.TextColored(customizeColor, customizeExists ? "Available" : "Unavailable"); |         ImGui.TextColored(customizeColor, customizeExists ? "Available" : "Unavailable"); | ||||||
|  |         ImGui.SameLine(); | ||||||
|  |         ImGui.Text("PalettePlus+:"); | ||||||
|  |         ImGui.SameLine(); | ||||||
|  |         ImGui.TextColored(paletteColor, paletteExists ? "Available" : "Unavailable"); | ||||||
|  |  | ||||||
|         if (!penumbraExists || !glamourerExists) |         if (!penumbraExists || !glamourerExists) | ||||||
|         { |         { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Cara
					Cara