Fix some things in item unlocks. Add unlock cheatcodes to default configuration.

This commit is contained in:
Ottermandias 2023-07-13 19:33:28 +02:00
parent 51bfcd1136
commit 9910b17ab0
8 changed files with 115 additions and 37 deletions

View file

@ -34,7 +34,11 @@ public class Configuration : IPluginConfiguration, ISavable
[JsonProperty(Order = int.MaxValue)] [JsonProperty(Order = int.MaxValue)]
public ISortMode<Design> SortMode { get; set; } = ISortMode<Design>.FoldersFirst; public ISortMode<Design> SortMode { get; set; } = ISortMode<Design>.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 #if DEBUG
public bool DebugMode { get; set; } = true; public bool DebugMode { get; set; } = true;

View file

@ -121,7 +121,6 @@
</None> </None>
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="if $(Configuration) == Release powershell Compress-Archive -Force $(TargetPath), $(TargetDir)$(SolutionName).json, $(TargetDir)$(SolutionName).GameData.dll, $(TargetDir)Penumbra.GameData.dll, $(TargetDir)Penumbra.Api.dll, $(TargetDir)Penumbra.String.dll $(SolutionDir)$(SolutionName).zip" />
<Exec Command="if $(Configuration) == Release powershell Copy-Item -Force $(TargetDir)$(SolutionName).json -Destination $(SolutionDir)" /> <Exec Command="if $(Configuration) == Release powershell Copy-Item -Force $(TargetDir)$(SolutionName).json -Destination $(SolutionDir)" />
</Target> </Target>
</Project> </Project>

View file

@ -31,6 +31,7 @@ public class SetPanel
private readonly DesignCombo _designCombo; private readonly DesignCombo _designCombo;
private readonly JobGroupCombo _jobGroupCombo; private readonly JobGroupCombo _jobGroupCombo;
private readonly IdentifierDrawer _identifierDrawer; private readonly IdentifierDrawer _identifierDrawer;
private readonly CodeService _codeService;
private string? _tempName; private string? _tempName;
private int _dragIndex = -1; private int _dragIndex = -1;
@ -38,7 +39,8 @@ public class SetPanel
private Action? _endAction; private Action? _endAction;
public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs, ItemUnlockManager itemUnlocks, 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; _selector = selector;
_manager = manager; _manager = manager;
@ -46,6 +48,7 @@ public class SetPanel
_customizeUnlocks = customizeUnlocks; _customizeUnlocks = customizeUnlocks;
_customizations = customizations; _customizations = customizations;
_identifierDrawer = identifierDrawer; _identifierDrawer = identifierDrawer;
_codeService = codeService;
_designCombo = new DesignCombo(_manager, designs); _designCombo = new DesignCombo(_manager, designs);
_jobGroupCombo = new JobGroupCombo(manager, jobs); _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", var tt = _codeService.EnabledInventory
"All equipment to be applied is unlocked."); // TODO ? "\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(); sb.Clear();
var sb2 = new StringBuilder(); var sb2 = new StringBuilder();
@ -199,7 +204,7 @@ public class SetPanel
continue; continue;
if (flag.RequiresRedraw()) 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 else if (type is CustomizeIndex.Hairstyle or CustomizeIndex.FacePaint
&& set.DataByValue(type, customize[type], out var data, customize.Face) >= 0 && set.DataByValue(type, customize[type], out var data, customize.Face) >= 0
&& !_customizeUnlocks.IsUnlocked(data!.Value, out _)) && !_customizeUnlocks.IsUnlocked(data!.Value, out _))
@ -208,10 +213,16 @@ public class SetPanel
} }
ImGui.SameLine(); ImGui.SameLine();
DrawWarning(sb2, 0xA03030F0, size, "\nThese customizations will be skipped when applied automatically. To change this, see", tt = _codeService.EnabledInventory
"All customizations to be applied are unlocked."); // TODO ? "\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(); 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 "No customizations unable to be applied automatically are set to be applied."); // TODO
} }

View file

@ -77,14 +77,14 @@ public class SettingsTab : ITab
private void DrawCodes() private void DrawCodes()
{ {
if (!ImGui.CollapsingHeader("Codes")) if (!ImGui.CollapsingHeader("Cheat Codes"))
return; return;
using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, _currentCode.Length > 0)) using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, _currentCode.Length > 0))
{ {
var color = _codeService.CheckCode(_currentCode) != null ? ColorId.ActorAvailable : ColorId.ActorUnavailable; var color = _codeService.CheckCode(_currentCode) != null ? ColorId.ActorAvailable : ColorId.ActorUnavailable;
using var c = ImRaii.PushColor(ImGuiCol.Border, color.Value(), _currentCode.Length > 0); 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)) if (_codeService.AddCode(_currentCode))
_currentCode = string.Empty; _currentCode = string.Empty;
} }

View file

@ -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 // @formatter:off
private static ReadOnlySpan<byte> 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<byte> 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<byte> 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 }; private static ReadOnlySpan<byte> 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 };

View file

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using Glamourer.Automation; using Glamourer.Automation;
using Glamourer.Gui; using Glamourer.Gui;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -52,6 +53,18 @@ public class ConfigMigrationService
_config.Colors[ColorId.EquipmentDesign] = equipmentColor; _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) private static void AddColors(Configuration config, bool forceSave)
{ {
var save = false; var save = false;

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Game; using Dalamud.Game;
using Dalamud.Game.ClientState; using Dalamud.Game.ClientState;
@ -10,17 +11,22 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI;
using Glamourer.Events; using Glamourer.Events;
using Glamourer.Services; using Glamourer.Services;
using Lumina.Excel.GeneratedSheets; 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 Cabinet = Lumina.Excel.GeneratedSheets.Cabinet;
using Item = Lumina.Excel.GeneratedSheets.Item;
namespace Glamourer.Unlocks; namespace Glamourer.Unlocks;
public class ItemUnlockManager : ISavable, IDisposable public class ItemUnlockManager : ISavable, IDisposable
{ {
private readonly SaveService _saveService; private readonly SaveService _saveService;
private readonly ItemManager _items; private readonly ItemManager _items;
private readonly ClientState _clientState; private readonly ClientState _clientState;
private readonly Framework _framework; private readonly Framework _framework;
private readonly ObjectUnlocked _event; private readonly ObjectUnlocked _event;
private readonly IdentifierService _identifier;
private readonly Dictionary<uint, long> _unlocked = new(); private readonly Dictionary<uint, long> _unlocked = new();
@ -46,7 +52,7 @@ public class ItemUnlockManager : ISavable, IDisposable
=> _unlocked; => _unlocked;
public ItemUnlockManager(SaveService saveService, ItemManager items, ClientState clientState, DataManager gameData, Framework framework, public ItemUnlockManager(SaveService saveService, ItemManager items, ClientState clientState, DataManager gameData, Framework framework,
ObjectUnlocked @event) ObjectUnlocked @event, IdentifierService identifier)
{ {
SignatureHelper.Initialise(this); SignatureHelper.Initialise(this);
_saveService = saveService; _saveService = saveService;
@ -54,6 +60,7 @@ public class ItemUnlockManager : ISavable, IDisposable
_clientState = clientState; _clientState = clientState;
_framework = framework; _framework = framework;
_event = @event; _event = @event;
_identifier = identifier;
Unlockable = CreateUnlockData(gameData, items); Unlockable = CreateUnlockData(gameData, items);
Load(); Load();
_clientState.Login += OnLogin; _clientState.Login += OnLogin;
@ -97,6 +104,23 @@ public class ItemUnlockManager : ISavable, IDisposable
InventoryType.RetainerMarket, 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 _) private unsafe void OnFramework(Framework _)
{ {
var uiState = UIState.Instance(); var uiState = UIState.Instance();
@ -122,16 +146,6 @@ public class ItemUnlockManager : ISavable, IDisposable
Scan(); Scan();
var time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); 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 mirageManager = MirageManager.Instance();
var changes = false; var changes = false;
if (mirageManager != null) if (mirageManager != null)
@ -143,7 +157,7 @@ public class ItemUnlockManager : ISavable, IDisposable
// TODO: Make independent from hardcoded value // TODO: Make independent from hardcoded value
var span = new ReadOnlySpan<uint>(mirageManager->PrismBoxItemIds, 800); var span = new ReadOnlySpan<uint>(mirageManager->PrismBoxItemIds, 800);
foreach (var item in span) foreach (var item in span)
changes |= AddItem(item); changes |= AddItem(item, time);
} }
var newPlateState = mirageManager->GlamourPlatesLoaded; var newPlateState = mirageManager->GlamourPlatesLoaded;
@ -155,7 +169,7 @@ public class ItemUnlockManager : ISavable, IDisposable
// TODO: Make independent from hardcoded value // TODO: Make independent from hardcoded value
var span = new ReadOnlySpan<uint>(plate.ItemIds, 12); var span = new ReadOnlySpan<uint>(plate.ItemIds, 12);
foreach (var item in span) 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++); var item = container->GetInventorySlot(_currentInventoryIndex++);
if (item != null) if (item != null)
{ {
changes |= AddItem(item->ItemID); changes |= AddItem(item->ItemID, time);
changes |= AddItem(item->GlamourID); changes |= AddItem(item->GlamourID, time);
} }
} }
else else
@ -262,8 +276,11 @@ public class ItemUnlockManager : ISavable, IDisposable
=> UnlockDictionaryHelpers.Save(writer, Unlocked); => UnlockDictionaryHelpers.Save(writer, Unlocked);
private void Load() 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"); id => _items.ItemService.AwaitedService.TryGetValue(id, out _), "item");
UpdateModels(version);
}
private void OnLogin(object? _, EventArgs _2) private void OnLogin(object? _, EventArgs _2)
=> Scan(); => Scan();
@ -296,4 +313,31 @@ public class ItemUnlockManager : ISavable, IDisposable
return ret; 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,
};
} }

View file

@ -8,7 +8,7 @@ namespace Glamourer.Unlocks;
public static class UnlockDictionaryHelpers public static class UnlockDictionaryHelpers
{ {
public const int Magic = 0x00C0FFEE; public const int Magic = 0x00C0FFEE;
public const int Version = 1; public const int Version = 2;
public static void Save(StreamWriter writer, IReadOnlyDictionary<uint, long> data) public static void Save(StreamWriter writer, IReadOnlyDictionary<uint, long> data)
{ {
@ -26,11 +26,11 @@ public static class UnlockDictionaryHelpers
b.Flush(); b.Flush();
} }
public static void Load(string filePath, Dictionary<uint, long> data, Func<uint, bool> validate, string type) public static int Load(string filePath, Dictionary<uint, long> data, Func<uint, bool> validate, string type)
{ {
data.Clear(); data.Clear();
if (!File.Exists(filePath)) if (!File.Exists(filePath))
return; return -1;
try try
{ {
@ -49,7 +49,7 @@ public static class UnlockDictionaryHelpers
default: default:
Glamourer.Chat.NotificationMessage($"Loading unlocked {type}s failed: Invalid magic number.", "Warning", Glamourer.Chat.NotificationMessage($"Loading unlocked {type}s failed: Invalid magic number.", "Warning",
NotificationType.Warning); NotificationType.Warning);
return; return -1;
} }
var version = b.ReadInt32(); var version = b.ReadInt32();
@ -57,6 +57,7 @@ public static class UnlockDictionaryHelpers
var now = DateTimeOffset.UtcNow; var now = DateTimeOffset.UtcNow;
switch (version) switch (version)
{ {
case 1:
case Version: case Version:
var count = b.ReadInt32(); var count = b.ReadInt32();
data.EnsureCapacity(count); data.EnsureCapacity(count);
@ -86,15 +87,18 @@ public static class UnlockDictionaryHelpers
default: default:
Glamourer.Chat.NotificationMessage($"Loading unlocked {type}s failed: Version {version} is unknown.", "Warning", Glamourer.Chat.NotificationMessage($"Loading unlocked {type}s failed: Version {version} is unknown.", "Warning",
NotificationType.Warning); NotificationType.Warning);
return; return version;
} }
Glamourer.Log.Debug($"[UnlockManager] Loaded {data.Count} unlocked {type}s."); Glamourer.Log.Debug($"[UnlockManager] Loaded {data.Count} unlocked {type}s.");
return version;
} }
catch (Exception ex) catch (Exception ex)
{ {
Glamourer.Chat.NotificationMessage(ex, $"Loading unlocked {type}s failed: Unknown Error.", $"Loading unlocked {type}s failed:\n", Glamourer.Chat.NotificationMessage(ex, $"Loading unlocked {type}s failed: Unknown Error.", $"Loading unlocked {type}s failed:\n",
"Error", NotificationType.Error); "Error", NotificationType.Error);
return -1;
} }
} }