From 9910b17ab0c4866925387f2aa1a53e11f2e39f97 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 13 Jul 2023 19:33:28 +0200 Subject: [PATCH] Fix some things in item unlocks. Add unlock cheatcodes to default configuration. --- Glamourer/Configuration.cs | 6 +- Glamourer/Glamourer.csproj | 1 - Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs | 25 ++++-- Glamourer/Gui/Tabs/SettingsTab.cs | 4 +- Glamourer/Services/CodeService.cs | 3 + Glamourer/Services/ConfigMigrationService.cs | 13 +++ Glamourer/Unlocks/ItemUnlockManager.cs | 86 +++++++++++++++----- Glamourer/Unlocks/UnlockDictionaryHelpers.cs | 14 ++-- 8 files changed, 115 insertions(+), 37 deletions(-) diff --git a/Glamourer/Configuration.cs b/Glamourer/Configuration.cs index 889bc89..0885297 100644 --- a/Glamourer/Configuration.cs +++ b/Glamourer/Configuration.cs @@ -34,7 +34,11 @@ public class Configuration : IPluginConfiguration, ISavable [JsonProperty(Order = int.MaxValue)] public ISortMode SortMode { get; set; } = ISortMode.FoldersFirst; - public List<(string Code, bool Enabled)> Codes { get; set; } = new List<(string Code, bool Enabled)>(); + public List<(string Code, bool Enabled)> Codes { get; set; } = new List<(string Code, bool Enabled)>() + { + (CodeService.CodeInventoryString, false), + (CodeService.CodeMesmerString, false), + }; #if DEBUG public bool DebugMode { get; set; } = true; diff --git a/Glamourer/Glamourer.csproj b/Glamourer/Glamourer.csproj index 63eaf6b..1ee77c5 100644 --- a/Glamourer/Glamourer.csproj +++ b/Glamourer/Glamourer.csproj @@ -121,7 +121,6 @@ - \ No newline at end of file diff --git a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs index b680a8a..a6f7265 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs @@ -31,6 +31,7 @@ public class SetPanel private readonly DesignCombo _designCombo; private readonly JobGroupCombo _jobGroupCombo; private readonly IdentifierDrawer _identifierDrawer; + private readonly CodeService _codeService; private string? _tempName; private int _dragIndex = -1; @@ -38,7 +39,8 @@ public class SetPanel private Action? _endAction; public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs, ItemUnlockManager itemUnlocks, - CustomizeUnlockManager customizeUnlocks, CustomizationService customizations, IdentifierDrawer identifierDrawer) + CustomizeUnlockManager customizeUnlocks, CustomizationService customizations, IdentifierDrawer identifierDrawer, + CodeService codeService) { _selector = selector; _manager = manager; @@ -46,6 +48,7 @@ public class SetPanel _customizeUnlocks = customizeUnlocks; _customizations = customizations; _identifierDrawer = identifierDrawer; + _codeService = codeService; _designCombo = new DesignCombo(_manager, designs); _jobGroupCombo = new JobGroupCombo(manager, jobs); } @@ -182,8 +185,10 @@ public class SetPanel } } - DrawWarning(sb, 0xA03030F0, size, "\nThese items will be skipped when applied automatically. To change this, see", - "All equipment to be applied is unlocked."); // TODO + var tt = _codeService.EnabledInventory + ? "\nThese items will still be applied, because you have enabled a cheat code." + : $"\nThese items will be skipped when applied automatically.\n\nTo change this, enable the \"{CodeService.CodeInventoryString}\" Cheat Code in Settings."; + DrawWarning(sb, !_codeService.EnabledInventory ? 0xA03030F0 : 0x0, size, tt, "All equipment to be applied is unlocked."); sb.Clear(); var sb2 = new StringBuilder(); @@ -199,7 +204,7 @@ public class SetPanel continue; if (flag.RequiresRedraw()) - sb.AppendLine($"{type.ToDefaultName()} Customization can not be changed automatically."); // TODO + sb.AppendLine($"{type.ToDefaultName()} Customization should not be changed automatically."); else if (type is CustomizeIndex.Hairstyle or CustomizeIndex.FacePaint && set.DataByValue(type, customize[type], out var data, customize.Face) >= 0 && !_customizeUnlocks.IsUnlocked(data!.Value, out _)) @@ -208,10 +213,16 @@ public class SetPanel } ImGui.SameLine(); - DrawWarning(sb2, 0xA03030F0, size, "\nThese customizations will be skipped when applied automatically. To change this, see", - "All customizations to be applied are unlocked."); // TODO + tt = _codeService.EnabledInventory + ? "\nThese customizations will still be applied, because you have enabled a cheat code." + : $"\nThese customizations will be skipped when applied automatically.\n\nTo change this, enable the \"{CodeService.CodeInventoryString}\" Cheat Code in Settings."; + DrawWarning(sb2, !_codeService.EnabledInventory ? 0xA03030F0 : 0x0, size, tt, "All customizations to be applied are unlocked."); ImGui.SameLine(); - DrawWarning(sb, 0xA030F0F0, size, "\nThese customizations will be skipped when applied automatically.", + + tt = _codeService.EnabledMesmer + ? "\nThese customizations will still be applied, because you have enabled a cheat code." + : $"\nThese customizations will be skipped when applied automatically.\n\nTo change this, enable the \"{CodeService.CodeMesmerString}\" Cheat Code in Settings."; + DrawWarning(sb, !_codeService.EnabledMesmer ? 0xA03030F0 : 0x0, size, tt, "No customizations unable to be applied automatically are set to be applied."); // TODO } diff --git a/Glamourer/Gui/Tabs/SettingsTab.cs b/Glamourer/Gui/Tabs/SettingsTab.cs index 6bd0a11..e2542e1 100644 --- a/Glamourer/Gui/Tabs/SettingsTab.cs +++ b/Glamourer/Gui/Tabs/SettingsTab.cs @@ -77,14 +77,14 @@ public class SettingsTab : ITab private void DrawCodes() { - if (!ImGui.CollapsingHeader("Codes")) + if (!ImGui.CollapsingHeader("Cheat Codes")) return; using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, _currentCode.Length > 0)) { var color = _codeService.CheckCode(_currentCode) != null ? ColorId.ActorAvailable : ColorId.ActorUnavailable; using var c = ImRaii.PushColor(ImGuiCol.Border, color.Value(), _currentCode.Length > 0); - if (ImGui.InputTextWithHint("##Code", "Enter Code...", ref _currentCode, 512, ImGuiInputTextFlags.EnterReturnsTrue)) + if (ImGui.InputTextWithHint("##Code", "Enter Cheat Code...", ref _currentCode, 512, ImGuiInputTextFlags.EnterReturnsTrue)) if (_codeService.AddCode(_currentCode)) _currentCode = string.Empty; } diff --git a/Glamourer/Services/CodeService.cs b/Glamourer/Services/CodeService.cs index f9646dc..49c1531 100644 --- a/Glamourer/Services/CodeService.cs +++ b/Glamourer/Services/CodeService.cs @@ -93,6 +93,9 @@ public class CodeService }; } + public const string CodeInventoryString = "I found this secret cheat code and all I got was all the lousy t-shirts."; + public const string CodeMesmerString = "With the power of cheats, you can be anything you want!"; + // @formatter:off private static ReadOnlySpan CodeClown => new byte[] { 0xC4, 0xEE, 0x1D, 0x6F, 0xC5, 0x5D, 0x47, 0xBE, 0x78, 0x63, 0x66, 0x86, 0x81, 0x15, 0xEB, 0xFA, 0xF6, 0x4A, 0x90, 0xEA, 0xC0, 0xE4, 0xEE, 0x86, 0x69, 0x01, 0x8E, 0xDB, 0xCC, 0x69, 0xD1, 0xBD }; private static ReadOnlySpan CodeEmperor => new byte[] { 0xE2, 0x2D, 0x3E, 0x57, 0x16, 0x82, 0x65, 0x98, 0x7E, 0xE6, 0x8F, 0x45, 0x14, 0x7D, 0x65, 0x31, 0xE9, 0xD8, 0xDB, 0xEA, 0xDC, 0xBF, 0xEE, 0x2A, 0xBA, 0xD5, 0x69, 0x96, 0x78, 0x34, 0x3B, 0x57 }; diff --git a/Glamourer/Services/ConfigMigrationService.cs b/Glamourer/Services/ConfigMigrationService.cs index bb3dbcc..689a40e 100644 --- a/Glamourer/Services/ConfigMigrationService.cs +++ b/Glamourer/Services/ConfigMigrationService.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using Glamourer.Automation; using Glamourer.Gui; using Newtonsoft.Json.Linq; @@ -52,6 +53,18 @@ public class ConfigMigrationService _config.Colors[ColorId.EquipmentDesign] = equipmentColor; } + private void MigrateV2To3() + { + if (_config.Version > 2) + return; + + _config.Version = 3; + if (_config.Codes.All(s => s.Code != CodeService.CodeInventoryString)) + _config.Codes.Add((CodeService.CodeInventoryString, false)); + if (_config.Codes.All(s => s.Code != CodeService.CodeMesmerString)) + _config.Codes.Add((CodeService.CodeMesmerString, false)); + } + private static void AddColors(Configuration config, bool forceSave) { var save = false; diff --git a/Glamourer/Unlocks/ItemUnlockManager.cs b/Glamourer/Unlocks/ItemUnlockManager.cs index 7aa6909..b387e63 100644 --- a/Glamourer/Unlocks/ItemUnlockManager.cs +++ b/Glamourer/Unlocks/ItemUnlockManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Dalamud.Data; using Dalamud.Game; using Dalamud.Game.ClientState; @@ -10,17 +11,22 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI; using Glamourer.Events; using Glamourer.Services; using Lumina.Excel.GeneratedSheets; +using Penumbra.GameData.Enums; +using static OtterGui.Raii.ImRaii; +using static Penumbra.GameData.Files.ShpkFile; using Cabinet = Lumina.Excel.GeneratedSheets.Cabinet; +using Item = Lumina.Excel.GeneratedSheets.Item; namespace Glamourer.Unlocks; public class ItemUnlockManager : ISavable, IDisposable { - private readonly SaveService _saveService; - private readonly ItemManager _items; - private readonly ClientState _clientState; - private readonly Framework _framework; - private readonly ObjectUnlocked _event; + private readonly SaveService _saveService; + private readonly ItemManager _items; + private readonly ClientState _clientState; + private readonly Framework _framework; + private readonly ObjectUnlocked _event; + private readonly IdentifierService _identifier; private readonly Dictionary _unlocked = new(); @@ -46,7 +52,7 @@ public class ItemUnlockManager : ISavable, IDisposable => _unlocked; public ItemUnlockManager(SaveService saveService, ItemManager items, ClientState clientState, DataManager gameData, Framework framework, - ObjectUnlocked @event) + ObjectUnlocked @event, IdentifierService identifier) { SignatureHelper.Initialise(this); _saveService = saveService; @@ -54,6 +60,7 @@ public class ItemUnlockManager : ISavable, IDisposable _clientState = clientState; _framework = framework; _event = @event; + _identifier = identifier; Unlockable = CreateUnlockData(gameData, items); Load(); _clientState.Login += OnLogin; @@ -97,6 +104,23 @@ public class ItemUnlockManager : ISavable, IDisposable InventoryType.RetainerMarket, }; + bool AddItem(uint itemId, long time) + { + itemId = HandleHq(itemId); + if (!_items.ItemService.AwaitedService.TryGetValue(itemId, out var equip) || !_unlocked.TryAdd(equip.ItemId, time)) + return false; + + _event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time)); + var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot()); + foreach (var item in ident) + { + if (_unlocked.TryAdd(item.ItemId, time)) + _event.Invoke(ObjectUnlocked.Type.Item, item.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time)); + } + + return true; + } + private unsafe void OnFramework(Framework _) { var uiState = UIState.Instance(); @@ -122,16 +146,6 @@ public class ItemUnlockManager : ISavable, IDisposable Scan(); var time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - - bool AddItem(uint itemId) - { - if (!_items.ItemService.AwaitedService.TryGetValue(itemId, out var equip) || !_unlocked.TryAdd(equip.ItemId, time)) - return false; - - _event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time)); - return true; - } - var mirageManager = MirageManager.Instance(); var changes = false; if (mirageManager != null) @@ -143,7 +157,7 @@ public class ItemUnlockManager : ISavable, IDisposable // TODO: Make independent from hardcoded value var span = new ReadOnlySpan(mirageManager->PrismBoxItemIds, 800); foreach (var item in span) - changes |= AddItem(item); + changes |= AddItem(item, time); } var newPlateState = mirageManager->GlamourPlatesLoaded; @@ -155,7 +169,7 @@ public class ItemUnlockManager : ISavable, IDisposable // TODO: Make independent from hardcoded value var span = new ReadOnlySpan(plate.ItemIds, 12); foreach (var item in span) - changes |= AddItem(item); + changes |= AddItem(item, time); } } } @@ -172,8 +186,8 @@ public class ItemUnlockManager : ISavable, IDisposable var item = container->GetInventorySlot(_currentInventoryIndex++); if (item != null) { - changes |= AddItem(item->ItemID); - changes |= AddItem(item->GlamourID); + changes |= AddItem(item->ItemID, time); + changes |= AddItem(item->GlamourID, time); } } else @@ -262,8 +276,11 @@ public class ItemUnlockManager : ISavable, IDisposable => UnlockDictionaryHelpers.Save(writer, Unlocked); private void Load() - => UnlockDictionaryHelpers.Load(ToFilename(_saveService.FileNames), _unlocked, + { + var version = UnlockDictionaryHelpers.Load(ToFilename(_saveService.FileNames), _unlocked, id => _items.ItemService.AwaitedService.TryGetValue(id, out _), "item"); + UpdateModels(version); + } private void OnLogin(object? _, EventArgs _2) => Scan(); @@ -296,4 +313,31 @@ public class ItemUnlockManager : ISavable, IDisposable return ret; } + + private void UpdateModels(int version) + { + if (version > 1) + return; + + foreach (var (item, time) in _unlocked.ToArray()) + { + if (!_items.ItemService.AwaitedService.TryGetValue(item, out var equip)) + continue; + + var ident = _identifier.AwaitedService.Identify(equip.ModelId, equip.WeaponType, equip.Variant, equip.Type.ToSlot()); + foreach (var item2 in ident) + { + if (_unlocked.TryAdd(item2.ItemId, time)) + _event.Invoke(ObjectUnlocked.Type.Item, item2.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time)); + } + } + } + + private uint HandleHq(uint itemId) + => itemId switch + { + > 1000000 => itemId - 1000000, + > 500000 => itemId - 500000, + _ => itemId, + }; } diff --git a/Glamourer/Unlocks/UnlockDictionaryHelpers.cs b/Glamourer/Unlocks/UnlockDictionaryHelpers.cs index a8bee5e..e9a31bf 100644 --- a/Glamourer/Unlocks/UnlockDictionaryHelpers.cs +++ b/Glamourer/Unlocks/UnlockDictionaryHelpers.cs @@ -8,7 +8,7 @@ namespace Glamourer.Unlocks; public static class UnlockDictionaryHelpers { public const int Magic = 0x00C0FFEE; - public const int Version = 1; + public const int Version = 2; public static void Save(StreamWriter writer, IReadOnlyDictionary data) { @@ -26,11 +26,11 @@ public static class UnlockDictionaryHelpers b.Flush(); } - public static void Load(string filePath, Dictionary data, Func validate, string type) + public static int Load(string filePath, Dictionary data, Func validate, string type) { data.Clear(); if (!File.Exists(filePath)) - return; + return -1; try { @@ -49,7 +49,7 @@ public static class UnlockDictionaryHelpers default: Glamourer.Chat.NotificationMessage($"Loading unlocked {type}s failed: Invalid magic number.", "Warning", NotificationType.Warning); - return; + return -1; } var version = b.ReadInt32(); @@ -57,6 +57,7 @@ public static class UnlockDictionaryHelpers var now = DateTimeOffset.UtcNow; switch (version) { + case 1: case Version: var count = b.ReadInt32(); data.EnsureCapacity(count); @@ -86,15 +87,18 @@ public static class UnlockDictionaryHelpers default: Glamourer.Chat.NotificationMessage($"Loading unlocked {type}s failed: Version {version} is unknown.", "Warning", NotificationType.Warning); - return; + return version; } Glamourer.Log.Debug($"[UnlockManager] Loaded {data.Count} unlocked {type}s."); + return version; } catch (Exception ex) { Glamourer.Chat.NotificationMessage(ex, $"Loading unlocked {type}s failed: Unknown Error.", $"Loading unlocked {type}s failed:\n", "Error", NotificationType.Error); + + return -1; } }