From 0b9af0e3f43c42dedd29c3d19371fbaacc762caa Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Sun, 20 Oct 2024 19:59:03 -0700 Subject: [PATCH] Update to Lumina 5 (new Excel parsing) (#2022) * Refactor and upgrade to new excel design * Obsolete ExcelResolver and use only RowRef * Better benchmarking for Lumina * Add custom game-supported RSV provider * Refactor and move Lazy and nullable/cached row objects to RowRefs * Convert IRSVProvider to delegate, resolve strings by default * Split IExcelRow into IExcelSubrow * Extra lumina documentation * Minor RSV CS fixes * Fix UIGlowPayload warning * Fix rebase * Update to Lumina 5 --- Dalamud.CorePlugin/Dalamud.CorePlugin.csproj | 4 +- Dalamud/Dalamud.csproj | 4 +- Dalamud/Data/DataManager.cs | 18 ++-- Dalamud/Data/LuminaUtils.cs | 22 +++++ Dalamud/Data/RsvResolver.cs | 51 +++++++++++ .../ClientState/Aetherytes/AetheryteEntry.cs | 9 +- Dalamud/Game/ClientState/Buddy/BuddyMember.cs | 16 ++-- Dalamud/Game/ClientState/ClientState.cs | 2 +- Dalamud/Game/ClientState/Fates/Fate.cs | 11 +-- .../ClientState/JobGauge/Types/SMNGauge.cs | 4 +- .../Objects/SubKinds/PlayerCharacter.cs | 22 ++--- .../ClientState/Objects/Types/Character.cs | 28 ++++--- Dalamud/Game/ClientState/Party/PartyMember.cs | 16 ++-- .../ClientState/Resolvers/ExcelResolver{T}.cs | 38 --------- Dalamud/Game/ClientState/Statuses/Status.cs | 6 +- Dalamud/Game/Gui/ContextMenu/MenuItem.cs | 2 +- .../Game/Gui/ContextMenu/MenuTargetDefault.cs | 7 +- .../PartyFinder/Types/JobFlagsExtensions.cs | 2 +- .../PartyFinder/Types/PartyFinderListing.cs | 36 ++++---- .../UniversalisMarketBoardUploader.cs | 6 +- .../Game/Network/Internal/NetworkHandlers.cs | 14 ++-- .../Structures/InfoProxy/CharacterData.cs | 22 ++--- Dalamud/Game/Text/SeStringHandling/Payload.cs | 7 -- .../Payloads/AutoTranslatePayload.cs | 84 +++++++++---------- .../SeStringHandling/Payloads/ItemPayload.cs | 34 +++----- .../Payloads/MapLinkPayload.cs | 34 +++----- .../Payloads/PlayerPayload.cs | 16 ++-- .../SeStringHandling/Payloads/QuestPayload.cs | 14 ++-- .../Payloads/StatusPayload.cs | 14 ++-- .../Payloads/UIForegroundPayload.cs | 22 ++--- .../Payloads/UIGlowPayload.cs | 17 ++-- .../Game/Text/SeStringHandling/SeString.cs | 19 ++--- .../Internal/SeStringColorStackSet.cs | 2 +- .../Internal/SeStringRenderer.cs | 2 +- .../Windows/Data/Widgets/AetherytesWidget.cs | 4 +- .../Windows/Data/Widgets/GaugeWidget.cs | 4 +- .../Windows/Data/Widgets/ObjectTableWidget.cs | 6 +- .../Widgets/SeStringRendererTestWidget.cs | 24 +++--- .../Windows/Data/Widgets/UIColorWidget.cs | 52 +++++++----- .../AgingSteps/ContextMenuAgingStep.cs | 41 +++++---- .../SelfTest/AgingSteps/LuminaAgingStep.cs | 38 ++++++--- .../Windows/SelfTest/SelfTestWindow.cs | 8 +- Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 2 +- Dalamud/Plugin/Services/IClientState.cs | 2 +- Dalamud/Plugin/Services/IDataManager.cs | 33 ++++++-- Dalamud/Utility/MapUtil.cs | 10 +-- Dalamud/Utility/SeStringExtensions.cs | 20 ++++- Dalamud/Utility/Util.cs | 12 +-- lib/FFXIVClientStructs | 2 +- 49 files changed, 460 insertions(+), 403 deletions(-) create mode 100644 Dalamud/Data/LuminaUtils.cs create mode 100644 Dalamud/Data/RsvResolver.cs delete mode 100644 Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj index 5f91a6ac8..6cc92cbb5 100644 --- a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj +++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj @@ -27,8 +27,8 @@ - - + + all diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 528145d59..a577f130b 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -71,8 +71,8 @@ - - + + all diff --git a/Dalamud/Data/DataManager.cs b/Dalamud/Data/DataManager.cs index 78fa83b00..d017bf85a 100644 --- a/Dalamud/Data/DataManager.cs +++ b/Dalamud/Data/DataManager.cs @@ -11,6 +11,7 @@ using Dalamud.Utility.Timing; using Lumina; using Lumina.Data; using Lumina.Excel; + using Newtonsoft.Json; using Serilog; @@ -28,12 +29,15 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager { private readonly Thread luminaResourceThread; private readonly CancellationTokenSource luminaCancellationTokenSource; + private readonly RsvResolver rsvResolver; [ServiceManager.ServiceConstructor] private DataManager(Dalamud dalamud) { this.Language = (ClientLanguage)dalamud.StartInfo.Language; + this.rsvResolver = new(); + try { Log.Verbose("Starting data load..."); @@ -44,11 +48,8 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager { LoadMultithreaded = true, CacheFileResources = true, -#if NEVER // Lumina bug PanicOnSheetChecksumMismatch = true, -#else - PanicOnSheetChecksumMismatch = false, -#endif + RsvResolver = this.rsvResolver.TryResolve, DefaultExcelLanguage = this.Language.ToLumina(), }; @@ -129,12 +130,12 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager #region Lumina Wrappers /// - public ExcelSheet? GetExcelSheet() where T : ExcelRow - => this.Excel.GetSheet(); + public ExcelSheet GetExcelSheet(ClientLanguage? language = null, string? name = null) where T : struct, IExcelRow + => this.Excel.GetSheet(language?.ToLumina(), name); /// - public ExcelSheet? GetExcelSheet(ClientLanguage language) where T : ExcelRow - => this.Excel.GetSheet(language.ToLumina()); + public SubrowExcelSheet GetSubrowExcelSheet(ClientLanguage? language = null, string? name = null) where T : struct, IExcelSubrow + => this.Excel.GetSubrowSheet(language?.ToLumina(), name); /// public FileResource? GetFile(string path) @@ -170,6 +171,7 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager { this.luminaCancellationTokenSource.Cancel(); this.GameData.Dispose(); + this.rsvResolver.Dispose(); } private class LauncherTroubleshootingInfo diff --git a/Dalamud/Data/LuminaUtils.cs b/Dalamud/Data/LuminaUtils.cs new file mode 100644 index 000000000..6da67f426 --- /dev/null +++ b/Dalamud/Data/LuminaUtils.cs @@ -0,0 +1,22 @@ +using Lumina.Excel; + +namespace Dalamud.Data; + +/// +/// A helper class to easily resolve Lumina data within Dalamud. +/// +internal static class LuminaUtils +{ + private static ExcelModule Module => Service.Get().Excel; + + /// + /// Initializes a new instance of the class using the default . + /// + /// The type of Lumina sheet to resolve. + /// The id of the row to resolve. + /// A new object. + public static RowRef CreateRef(uint rowId) where T : struct, IExcelRow + { + return new(Module, rowId); + } +} diff --git a/Dalamud/Data/RsvResolver.cs b/Dalamud/Data/RsvResolver.cs new file mode 100644 index 000000000..3f507ff1d --- /dev/null +++ b/Dalamud/Data/RsvResolver.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; + +using Dalamud.Hooking; +using Dalamud.Logging.Internal; +using Dalamud.Memory; +using FFXIVClientStructs.FFXIV.Client.LayoutEngine; +using Lumina.Text.ReadOnly; + +namespace Dalamud.Data; + +/// +/// Provides functionality for resolving RSV strings. +/// +internal sealed unsafe class RsvResolver : IDisposable +{ + private static readonly ModuleLog Log = new("RsvProvider"); + + private readonly Hook addRsvStringHook; + + /// + /// Initializes a new instance of the class. + /// + public RsvResolver() + { + this.addRsvStringHook = Hook.FromAddress((nint)LayoutWorld.MemberFunctionPointers.AddRsvString, this.AddRsvStringDetour); + + this.addRsvStringHook.Enable(); + } + + private Dictionary Lookup { get; } = []; + + /// Attemps to resolve an RSV string. + /// + public bool TryResolve(ReadOnlySeString rsvString, out ReadOnlySeString resolvedString) => + this.Lookup.TryGetValue(rsvString, out resolvedString); + + /// + public void Dispose() + { + this.addRsvStringHook.Dispose(); + } + + private bool AddRsvStringDetour(LayoutWorld* @this, byte* rsvString, byte* resolvedString, nuint resolvedStringSize) + { + var rsv = new ReadOnlySeString(MemoryHelper.ReadRawNullTerminated((nint)rsvString)); + var resolved = new ReadOnlySeString(new ReadOnlySpan(resolvedString, (int)resolvedStringSize).ToArray()); + Log.Debug($"Resolving RSV \"{rsv}\" to \"{resolved}\"."); + this.Lookup[rsv] = resolved; + return this.addRsvStringHook.Original(@this, rsvString, resolvedString, resolvedStringSize); + } +} diff --git a/Dalamud/Game/ClientState/Aetherytes/AetheryteEntry.cs b/Dalamud/Game/ClientState/Aetherytes/AetheryteEntry.cs index 058d6c0c2..244989476 100644 --- a/Dalamud/Game/ClientState/Aetherytes/AetheryteEntry.cs +++ b/Dalamud/Game/ClientState/Aetherytes/AetheryteEntry.cs @@ -1,6 +1,9 @@ -using Dalamud.Game.ClientState.Resolvers; +using Dalamud.Data; + using FFXIVClientStructs.FFXIV.Client.Game.UI; +using Lumina.Excel; + namespace Dalamud.Game.ClientState.Aetherytes; /// @@ -56,7 +59,7 @@ public interface IAetheryteEntry /// /// Gets the Aetheryte data related to this aetheryte. /// - ExcelResolver AetheryteData { get; } + RowRef AetheryteData { get; } } /// @@ -103,5 +106,5 @@ internal sealed class AetheryteEntry : IAetheryteEntry public bool IsApartment => this.data.IsApartment; /// - public ExcelResolver AetheryteData => new(this.AetheryteId); + public RowRef AetheryteData => LuminaUtils.CreateRef(this.AetheryteId); } diff --git a/Dalamud/Game/ClientState/Buddy/BuddyMember.cs b/Dalamud/Game/ClientState/Buddy/BuddyMember.cs index a650a7b44..025de611d 100644 --- a/Dalamud/Game/ClientState/Buddy/BuddyMember.cs +++ b/Dalamud/Game/ClientState/Buddy/BuddyMember.cs @@ -1,6 +1,8 @@ +using Dalamud.Data; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Game.ClientState.Resolvers; + +using Lumina.Excel; namespace Dalamud.Game.ClientState.Buddy; @@ -45,17 +47,17 @@ public interface IBuddyMember /// /// Gets the Mount data related to this buddy. It should only be used with companion buddies. /// - ExcelResolver MountData { get; } + RowRef MountData { get; } /// /// Gets the Pet data related to this buddy. It should only be used with pet buddies. /// - ExcelResolver PetData { get; } + RowRef PetData { get; } /// /// Gets the Trust data related to this buddy. It should only be used with battle buddies. /// - ExcelResolver TrustData { get; } + RowRef TrustData { get; } } /// @@ -94,13 +96,13 @@ internal unsafe class BuddyMember : IBuddyMember public uint DataID => this.Struct->DataId; /// - public ExcelResolver MountData => new(this.DataID); + public RowRef MountData => LuminaUtils.CreateRef(this.DataID); /// - public ExcelResolver PetData => new(this.DataID); + public RowRef PetData => LuminaUtils.CreateRef(this.DataID); /// - public ExcelResolver TrustData => new(this.DataID); + public RowRef TrustData => LuminaUtils.CreateRef(this.DataID); private FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember*)this.Address; } diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index 9dd999860..0fad33e15 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -19,7 +19,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Event; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI.Agent; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; using Action = System.Action; diff --git a/Dalamud/Game/ClientState/Fates/Fate.cs b/Dalamud/Game/ClientState/Fates/Fate.cs index 2d32cc04c..9b41ac758 100644 --- a/Dalamud/Game/ClientState/Fates/Fate.cs +++ b/Dalamud/Game/ClientState/Fates/Fate.cs @@ -1,10 +1,11 @@ using System.Numerics; using Dalamud.Data; -using Dalamud.Game.ClientState.Resolvers; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Memory; +using Lumina.Excel; + namespace Dalamud.Game.ClientState.Fates; /// @@ -20,7 +21,7 @@ public interface IFate : IEquatable /// /// Gets game data linked to this Fate. /// - Lumina.Excel.GeneratedSheets.Fate GameData { get; } + RowRef GameData { get; } /// /// Gets the time this started. @@ -105,7 +106,7 @@ public interface IFate : IEquatable /// /// Gets the territory this is located in. /// - ExcelResolver TerritoryType { get; } + RowRef TerritoryType { get; } /// /// Gets the address of this Fate in memory. @@ -185,7 +186,7 @@ internal unsafe partial class Fate : IFate public ushort FateId => this.Struct->FateId; /// - public Lumina.Excel.GeneratedSheets.Fate GameData => Service.Get().GetExcelSheet().GetRow(this.FateId); + public RowRef GameData => LuminaUtils.CreateRef(this.FateId); /// public int StartTimeEpoch => this.Struct->StartTimeEpoch; @@ -238,5 +239,5 @@ internal unsafe partial class Fate : IFate /// /// Gets the territory this is located in. /// - public ExcelResolver TerritoryType => new(this.Struct->TerritoryId); + public RowRef TerritoryType => LuminaUtils.CreateRef(this.Struct->TerritoryId); } diff --git a/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs b/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs index aa7e27fd2..81be0e762 100644 --- a/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs +++ b/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs @@ -29,13 +29,13 @@ public unsafe class SMNGauge : JobGaugeBase /// /// Gets the summon that will return after the current summon expires. - /// This maps to the sheet. + /// This maps to the sheet. /// public SummonPet ReturnSummon => (SummonPet)this.Struct->ReturnSummon; /// /// Gets the summon glam for the . - /// This maps to the sheet. + /// This maps to the sheet. /// public PetGlam ReturnSummonGlam => (PetGlam)this.Struct->ReturnSummonGlam; diff --git a/Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs b/Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs index 87fbf39c3..2fd723071 100644 --- a/Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs +++ b/Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs @@ -1,12 +1,8 @@ -using System.Numerics; - -using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Data; using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Game.ClientState.Resolvers; -using Dalamud.Game.ClientState.Statuses; -using Dalamud.Game.Text.SeStringHandling; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel; +using Lumina.Excel.Sheets; namespace Dalamud.Game.ClientState.Objects.SubKinds; @@ -16,14 +12,14 @@ namespace Dalamud.Game.ClientState.Objects.SubKinds; public interface IPlayerCharacter : IBattleChara { /// - /// Gets the current world of the character. + /// Gets the current world of the character. /// - ExcelResolver CurrentWorld { get; } + RowRef CurrentWorld { get; } /// - /// Gets the home world of the character. + /// Gets the home world of the character. /// - ExcelResolver HomeWorld { get; } + RowRef HomeWorld { get; } } /// @@ -42,10 +38,10 @@ internal unsafe class PlayerCharacter : BattleChara, IPlayerCharacter } /// - public ExcelResolver CurrentWorld => new(this.Struct->CurrentWorld); + public RowRef CurrentWorld => LuminaUtils.CreateRef(this.Struct->CurrentWorld); /// - public ExcelResolver HomeWorld => new(this.Struct->HomeWorld); + public RowRef HomeWorld => LuminaUtils.CreateRef(this.Struct->HomeWorld); /// /// Gets the target actor ID of the PlayerCharacter. diff --git a/Dalamud/Game/ClientState/Objects/Types/Character.cs b/Dalamud/Game/ClientState/Objects/Types/Character.cs index 72f6a9950..b04b54301 100644 --- a/Dalamud/Game/ClientState/Objects/Types/Character.cs +++ b/Dalamud/Game/ClientState/Objects/Types/Character.cs @@ -1,10 +1,12 @@ using System.Runtime.CompilerServices; +using Dalamud.Data; using Dalamud.Game.ClientState.Objects.Enums; -using Dalamud.Game.ClientState.Resolvers; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Memory; -using Lumina.Excel.GeneratedSheets; + +using Lumina.Excel; +using Lumina.Excel.Sheets; namespace Dalamud.Game.ClientState.Objects.Types; @@ -61,7 +63,7 @@ public interface ICharacter : IGameObject /// /// Gets the ClassJob of this Chara. /// - public ExcelResolver ClassJob { get; } + public RowRef ClassJob { get; } /// /// Gets the level of this Chara. @@ -87,7 +89,7 @@ public interface ICharacter : IGameObject /// /// Gets the current online status of the character. /// - public ExcelResolver OnlineStatus { get; } + public RowRef OnlineStatus { get; } /// /// Gets the status flags. @@ -97,14 +99,14 @@ public interface ICharacter : IGameObject /// /// Gets the current mount for this character. Will be null if the character doesn't have a mount. /// - public ExcelResolver? CurrentMount { get; } + public RowRef? CurrentMount { get; } /// /// Gets the current minion summoned for this character. Will be null if the character doesn't have a minion. /// This method *will* return information about a spawned (but invisible) minion, e.g. if the character is riding a /// mount. /// - public ExcelResolver? CurrentMinion { get; } + public RowRef? CurrentMinion { get; } } /// @@ -150,7 +152,7 @@ internal unsafe class Character : GameObject, ICharacter public byte ShieldPercentage => this.Struct->CharacterData.ShieldValue; /// - public ExcelResolver ClassJob => new(this.Struct->CharacterData.ClassJob); + public RowRef ClassJob => LuminaUtils.CreateRef(this.Struct->CharacterData.ClassJob); /// public byte Level => this.Struct->CharacterData.Level; @@ -170,7 +172,7 @@ internal unsafe class Character : GameObject, ICharacter public uint NameId => this.Struct->NameId; /// - public ExcelResolver OnlineStatus => new(this.Struct->CharacterData.OnlineStatus); + public RowRef OnlineStatus => LuminaUtils.CreateRef(this.Struct->CharacterData.OnlineStatus); /// /// Gets the status flags. @@ -186,28 +188,28 @@ internal unsafe class Character : GameObject, ICharacter (this.Struct->IsCasting ? StatusFlags.IsCasting : StatusFlags.None); /// - public ExcelResolver? CurrentMount + public RowRef? CurrentMount { get { if (this.Struct->IsNotMounted()) return null; // just for safety. var mountId = this.Struct->Mount.MountId; - return mountId == 0 ? null : new ExcelResolver(mountId); + return mountId == 0 ? null : LuminaUtils.CreateRef(mountId); } } /// - public ExcelResolver? CurrentMinion + public RowRef? CurrentMinion { get { if (this.Struct->CompanionObject != null) - return new ExcelResolver(this.Struct->CompanionObject->BaseId); + return LuminaUtils.CreateRef(this.Struct->CompanionObject->BaseId); // this is only present if a minion is summoned but hidden (e.g. the player's on a mount). var hiddenCompanionId = this.Struct->CompanionData.CompanionId; - return hiddenCompanionId == 0 ? null : new ExcelResolver(hiddenCompanionId); + return hiddenCompanionId == 0 ? null : LuminaUtils.CreateRef(hiddenCompanionId); } } diff --git a/Dalamud/Game/ClientState/Party/PartyMember.cs b/Dalamud/Game/ClientState/Party/PartyMember.cs index 34cd31dec..b764431f5 100644 --- a/Dalamud/Game/ClientState/Party/PartyMember.cs +++ b/Dalamud/Game/ClientState/Party/PartyMember.cs @@ -1,13 +1,15 @@ using System.Numerics; using System.Runtime.CompilerServices; +using Dalamud.Data; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Game.ClientState.Resolvers; using Dalamud.Game.ClientState.Statuses; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Memory; +using Lumina.Excel; + namespace Dalamud.Game.ClientState.Party; /// @@ -71,12 +73,12 @@ public interface IPartyMember /// /// Gets the territory this party member is located in. /// - ExcelResolver Territory { get; } + RowRef Territory { get; } /// /// Gets the World this party member resides in. /// - ExcelResolver World { get; } + RowRef World { get; } /// /// Gets the displayname of this party member. @@ -91,7 +93,7 @@ public interface IPartyMember /// /// Gets the classjob of this party member. /// - ExcelResolver ClassJob { get; } + RowRef ClassJob { get; } /// /// Gets the level of this party member. @@ -169,12 +171,12 @@ internal unsafe class PartyMember : IPartyMember /// /// Gets the territory this party member is located in. /// - public ExcelResolver Territory => new(this.Struct->TerritoryType); + public RowRef Territory => LuminaUtils.CreateRef(this.Struct->TerritoryType); /// /// Gets the World this party member resides in. /// - public ExcelResolver World => new(this.Struct->HomeWorld); + public RowRef World => LuminaUtils.CreateRef(this.Struct->HomeWorld); /// /// Gets the displayname of this party member. @@ -189,7 +191,7 @@ internal unsafe class PartyMember : IPartyMember /// /// Gets the classjob of this party member. /// - public ExcelResolver ClassJob => new(this.Struct->ClassJob); + public RowRef ClassJob => LuminaUtils.CreateRef(this.Struct->ClassJob); /// /// Gets the level of this party member. diff --git a/Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs b/Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs deleted file mode 100644 index 04003d9aa..000000000 --- a/Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Dalamud.Data; - -using Lumina.Excel; - -namespace Dalamud.Game.ClientState.Resolvers; - -/// -/// This object resolves a rowID within an Excel sheet. -/// -/// The type of Lumina sheet to resolve. -public class ExcelResolver where T : ExcelRow -{ - /// - /// Initializes a new instance of the class. - /// - /// The ID of the classJob. - internal ExcelResolver(uint id) - { - this.Id = id; - } - - /// - /// Gets the ID to be resolved. - /// - public uint Id { get; } - - /// - /// Gets GameData linked to this excel row. - /// - public T? GameData => Service.Get().GetExcelSheet()?.GetRow(this.Id); - - /// - /// Gets GameData linked to this excel row with the specified language. - /// - /// The language. - /// The ExcelRow in the specified language. - public T? GetWithLanguage(ClientLanguage language) => Service.Get().GetExcelSheet(language)?.GetRow(this.Id); -} diff --git a/Dalamud/Game/ClientState/Statuses/Status.cs b/Dalamud/Game/ClientState/Statuses/Status.cs index ad1a24b6a..f09d13fb3 100644 --- a/Dalamud/Game/ClientState/Statuses/Status.cs +++ b/Dalamud/Game/ClientState/Statuses/Status.cs @@ -1,6 +1,8 @@ +using Dalamud.Data; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Game.ClientState.Resolvers; + +using Lumina.Excel; namespace Dalamud.Game.ClientState.Statuses; @@ -31,7 +33,7 @@ public unsafe class Status /// /// Gets the GameData associated with this status. /// - public Lumina.Excel.GeneratedSheets.Status GameData => new ExcelResolver(this.Struct->StatusId).GameData; + public RowRef GameData => LuminaUtils.CreateRef(this.Struct->StatusId); /// /// Gets the parameter value of the status. diff --git a/Dalamud/Game/Gui/ContextMenu/MenuItem.cs b/Dalamud/Game/Gui/ContextMenu/MenuItem.cs index 9b7cc2bc1..df1cb54a7 100644 --- a/Dalamud/Game/Gui/ContextMenu/MenuItem.cs +++ b/Dalamud/Game/Gui/ContextMenu/MenuItem.cs @@ -1,7 +1,7 @@ using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; namespace Dalamud.Game.Gui.ContextMenu; diff --git a/Dalamud/Game/Gui/ContextMenu/MenuTargetDefault.cs b/Dalamud/Game/Gui/ContextMenu/MenuTargetDefault.cs index 26365ab14..f09b3e105 100644 --- a/Dalamud/Game/Gui/ContextMenu/MenuTargetDefault.cs +++ b/Dalamud/Game/Gui/ContextMenu/MenuTargetDefault.cs @@ -1,11 +1,12 @@ +using Dalamud.Data; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Game.ClientState.Resolvers; using Dalamud.Game.Network.Structures.InfoProxy; using FFXIVClientStructs.FFXIV.Client.UI.Agent; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel; +using Lumina.Excel.Sheets; namespace Dalamud.Game.Gui.ContextMenu; @@ -46,7 +47,7 @@ public sealed unsafe class MenuTargetDefault : MenuTarget /// /// Gets the home world id of the target. /// - public ExcelResolver TargetHomeWorld => new((uint)this.Context->TargetHomeWorldId); + public RowRef TargetHomeWorld => LuminaUtils.CreateRef((uint)this.Context->TargetHomeWorldId); /// /// Gets the currently targeted character. Only shows up for specific targets, like friends, party finder listings, or party members. diff --git a/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs b/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs index ba72021ba..1c78c871b 100644 --- a/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs +++ b/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs @@ -1,5 +1,5 @@ using Dalamud.Plugin.Services; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; namespace Dalamud.Game.Gui.PartyFinder.Types; diff --git a/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs index 3461841ab..09de07e0d 100644 --- a/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs +++ b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs @@ -5,7 +5,8 @@ using Dalamud.Data; using Dalamud.Game.Gui.PartyFinder.Internal; using Dalamud.Game.Text.SeStringHandling; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel; +using Lumina.Excel.Sheets; namespace Dalamud.Game.Gui.PartyFinder.Types; @@ -48,7 +49,7 @@ public interface IPartyFinderListing /// /// Gets a list of the classes/jobs that are currently present in the party. /// - IReadOnlyCollection> JobsPresent { get; } + IReadOnlyCollection> JobsPresent { get; } /// /// Gets the ID assigned to this listing by the game's server. @@ -73,17 +74,17 @@ public interface IPartyFinderListing /// /// Gets the world that this listing was created on. /// - Lazy World { get; } + RowRef World { get; } /// /// Gets the home world of the listing's host. /// - Lazy HomeWorld { get; } + RowRef HomeWorld { get; } /// /// Gets the current world of the listing's host. /// - Lazy CurrentWorld { get; } + RowRef CurrentWorld { get; } /// /// Gets the Party Finder category this listing is listed under. @@ -98,7 +99,7 @@ public interface IPartyFinderListing /// /// Gets the duty this listing is for. May be null for non-duty listings. /// - Lazy Duty { get; } + RowRef Duty { get; } /// /// Gets the type of duty this listing is for. @@ -216,12 +217,12 @@ internal class PartyFinderListing : IPartyFinderListing this.ContentId = listing.ContentId; this.Name = SeString.Parse(listing.Name.TakeWhile(b => b != 0).ToArray()); this.Description = SeString.Parse(listing.Description.TakeWhile(b => b != 0).ToArray()); - this.World = new Lazy(() => dataManager.GetExcelSheet().GetRow(listing.World)); - this.HomeWorld = new Lazy(() => dataManager.GetExcelSheet().GetRow(listing.HomeWorld)); - this.CurrentWorld = new Lazy(() => dataManager.GetExcelSheet().GetRow(listing.CurrentWorld)); + this.World = LuminaUtils.CreateRef(listing.World); + this.HomeWorld = LuminaUtils.CreateRef(listing.HomeWorld); + this.CurrentWorld = LuminaUtils.CreateRef(listing.CurrentWorld); this.Category = (DutyCategory)listing.Category; this.RawDuty = listing.Duty; - this.Duty = new Lazy(() => dataManager.GetExcelSheet().GetRow(listing.Duty)); + this.Duty = LuminaUtils.CreateRef(listing.Duty); this.DutyType = (DutyType)listing.DutyType; this.BeginnersWelcome = listing.BeginnersWelcome == 1; this.SecondsRemaining = listing.SecondsRemaining; @@ -231,10 +232,7 @@ internal class PartyFinderListing : IPartyFinderListing this.SlotsFilled = listing.NumSlotsFilled; this.LastPatchHotfixTimestamp = listing.LastPatchHotfixTimestamp; this.JobsPresent = listing.JobsPresent - .Select(id => new Lazy( - () => id == 0 - ? null - : dataManager.GetExcelSheet().GetRow(id))) + .Select(id => LuminaUtils.CreateRef(id)) .ToArray(); } @@ -251,13 +249,13 @@ internal class PartyFinderListing : IPartyFinderListing public SeString Description { get; } /// - public Lazy World { get; } + public RowRef World { get; } /// - public Lazy HomeWorld { get; } + public RowRef HomeWorld { get; } /// - public Lazy CurrentWorld { get; } + public RowRef CurrentWorld { get; } /// public DutyCategory Category { get; } @@ -266,7 +264,7 @@ internal class PartyFinderListing : IPartyFinderListing public ushort RawDuty { get; } /// - public Lazy Duty { get; } + public RowRef Duty { get; } /// public DutyType DutyType { get; } @@ -314,7 +312,7 @@ internal class PartyFinderListing : IPartyFinderListing public IReadOnlyCollection RawJobsPresent => this.jobsPresent; /// - public IReadOnlyCollection> JobsPresent { get; } + public IReadOnlyCollection> JobsPresent { get; } #region Indexers diff --git a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs index 7892e8a04..a62de369b 100644 --- a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs +++ b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs @@ -46,7 +46,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader var uploadObject = new UniversalisItemUploadRequest { - WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0, + WorldId = clientState.LocalPlayer?.CurrentWorld.RowId ?? 0, UploaderId = uploader.ToString(), ItemId = request.Listings.FirstOrDefault()?.CatalogId ?? 0, Listings = [], @@ -120,7 +120,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader var taxUploadObject = new UniversalisTaxUploadRequest { - WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0, + WorldId = clientState.LocalPlayer?.CurrentWorld.RowId ?? 0, UploaderId = clientState.LocalContentId.ToString(), TaxData = new UniversalisTaxData { @@ -158,7 +158,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader return; var itemId = purchaseHandler.CatalogId; - var worldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0; + var worldId = clientState.LocalPlayer?.CurrentWorld.RowId ?? 0; // ==================================================================================== diff --git a/Dalamud/Game/Network/Internal/NetworkHandlers.cs b/Dalamud/Game/Network/Internal/NetworkHandlers.cs index 0e87880ec..ad8dbb600 100644 --- a/Dalamud/Game/Network/Internal/NetworkHandlers.cs +++ b/Dalamud/Game/Network/Internal/NetworkHandlers.cs @@ -16,7 +16,7 @@ using Dalamud.Hooking; using Dalamud.Networking.Http; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.UI.Info; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; using Serilog; namespace Dalamud.Game.Network.Internal; @@ -282,21 +282,17 @@ internal unsafe class NetworkHandlers : IInternalDisposableService if (this.configuration.DutyFinderTaskbarFlash) Util.FlashWindow(); - var cfConditionSheet = Service.Get().GetExcelSheet()!; - var cfCondition = cfConditionSheet.GetRow(conditionId); + var cfCondition = LuminaUtils.CreateRef(conditionId); - if (cfCondition == null) + if (!cfCondition.IsValid) { Log.Error("CFC key {ConditionId} not in Lumina data", conditionId); return result; } - var cfcName = cfCondition.Name.ToDalamudString(); + var cfcName = cfCondition.Value.Name.ToDalamudString(); if (cfcName.Payloads.Count == 0) - { cfcName = "Duty Roulette"; - cfCondition.Image = 112324; - } Task.Run(() => { @@ -308,7 +304,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService Service.GetNullable()?.Print(b.Build()); } - this.CfPop.InvokeSafely(cfCondition); + this.CfPop.InvokeSafely(cfCondition.Value); }).ContinueWith( task => Log.Error(task.Exception, "CfPop.Invoke failed"), TaskContinuationOptions.OnlyOnFaulted); diff --git a/Dalamud/Game/Network/Structures/InfoProxy/CharacterData.cs b/Dalamud/Game/Network/Structures/InfoProxy/CharacterData.cs index 96de1c3b2..fcb46b0c3 100644 --- a/Dalamud/Game/Network/Structures/InfoProxy/CharacterData.cs +++ b/Dalamud/Game/Network/Structures/InfoProxy/CharacterData.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; -using Dalamud.Game.ClientState.Resolvers; -using Dalamud.Memory; +using Dalamud.Data; using FFXIVClientStructs.FFXIV.Client.UI.Info; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel; +using Lumina.Excel.Sheets; namespace Dalamud.Game.Network.Structures.InfoProxy; @@ -92,15 +92,15 @@ public unsafe class CharacterData /// /// Gets the applicable statues of the character. /// - public IReadOnlyList> Statuses + public IReadOnlyList> Statuses { get { - var statuses = new List>(); + var statuses = new List>(); for (var i = 0; i < 64; i++) { if ((this.StatusMask & (1UL << i)) != 0) - statuses.Add(new((uint)i)); + statuses.Add(LuminaUtils.CreateRef((uint)i)); } return statuses; @@ -125,22 +125,22 @@ public unsafe class CharacterData /// /// Gets the current world of the character. /// - public ExcelResolver CurrentWorld => new(this.Struct->CurrentWorld); + public RowRef CurrentWorld => LuminaUtils.CreateRef(this.Struct->CurrentWorld); /// /// Gets the home world of the character. /// - public ExcelResolver HomeWorld => new(this.Struct->HomeWorld); + public RowRef HomeWorld => LuminaUtils.CreateRef(this.Struct->HomeWorld); /// /// Gets the location of the character. /// - public ExcelResolver Location => new(this.Struct->Location); + public RowRef Location => LuminaUtils.CreateRef(this.Struct->Location); /// /// Gets the grand company of the character. /// - public ExcelResolver GrandCompany => new((uint)this.Struct->GrandCompany); + public RowRef GrandCompany => LuminaUtils.CreateRef((uint)this.Struct->GrandCompany); /// /// Gets the primary client language of the character. @@ -178,7 +178,7 @@ public unsafe class CharacterData /// /// Gets the job of the character. /// - public ExcelResolver ClassJob => new(this.Struct->Job); + public RowRef ClassJob => LuminaUtils.CreateRef(this.Struct->Job); /// /// Gets the name of the character. diff --git a/Dalamud/Game/Text/SeStringHandling/Payload.cs b/Dalamud/Game/Text/SeStringHandling/Payload.cs index b876598de..a38a8271d 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payload.cs @@ -38,13 +38,6 @@ public abstract partial class Payload /// public bool Dirty { get; protected set; } = true; - /// - /// Gets the Lumina instance to use for any necessary data lookups. - /// - [JsonIgnore] - // TODO: We should refactor this. It should not be possible to get IDataManager through here. - protected IDataManager DataResolver => Service.Get(); - /// /// Decodes a binary representation of a payload into its corresponding nice object payload. /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs index afc1cdc01..b038deb6f 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs @@ -2,7 +2,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel.Sheets; +using Lumina.Text.ReadOnly; + using Newtonsoft.Json; using Serilog; @@ -106,28 +110,28 @@ public class AutoTranslatePayload : Payload, ITextProvider this.Key = GetInteger(reader); } + private static ReadOnlySeString ResolveTextCommand(TextCommand command) + { + // TextCommands prioritize the `Alias` field, if it not empty + // Example for this is /rangerpose2l which becomes /blackrangerposeb in chat + return !command.Alias.IsEmpty ? command.Alias : command.Command; + } + private string Resolve() { string value = null; - var sheet = this.DataResolver.GetExcelSheet(); + var excelModule = Service.Get().Excel; + var completionSheet = excelModule.GetSheet(); - Completion row = null; - try - { - // try to get the row in the Completion table itself, because this is 'easiest' - // The row may not exist at all (if the Key is for another table), or it could be the wrong row - // (again, if it's meant for another table) - row = sheet.GetRow(this.Key); - } - catch - { - } // don't care, row will be null + // try to get the row in the Completion table itself, because this is 'easiest' + // The row may not exist at all (if the Key is for another table), or it could be the wrong row + // (again, if it's meant for another table) - if (row?.Group == this.Group) + if (completionSheet.GetRowOrDefault(this.Key) is { } completion && completion.Group == this.Group) { // if the row exists in this table and the group matches, this is actually the correct data - value = row.Text; + value = completion.Text.ExtractText(); } else { @@ -135,34 +139,34 @@ public class AutoTranslatePayload : Payload, ITextProvider { // we need to get the linked table and do the lookup there instead // in this case, there will only be one entry for this group id - row = sheet.First(r => r.Group == this.Group); + var row = completionSheet.First(r => r.Group == this.Group); // many of the names contain valid id ranges after the table name, but we don't need those - var actualTableName = row.LookupTable.RawString.Split('[')[0]; + var actualTableName = row.LookupTable.ExtractText().Split('[')[0]; var name = actualTableName switch { - "Action" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "ActionComboRoute" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "BuddyAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "ClassJob" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "Companion" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Singular, - "CraftAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "GeneralAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "GuardianDeity" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "MainCommand" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "Mount" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Singular, - "Pet" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "PetAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "PetMirage" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "PlaceName" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, - "Race" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Masculine, - "TextCommand" => this.ResolveTextCommand(), - "Tribe" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Masculine, - "Weather" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name, + "Action" => excelModule.GetSheet().GetRow(this.Key).Name, + "ActionComboRoute" => excelModule.GetSheet().GetRow(this.Key).Name, + "BuddyAction" => excelModule.GetSheet().GetRow(this.Key).Name, + "ClassJob" => excelModule.GetSheet().GetRow(this.Key).Name, + "Companion" => excelModule.GetSheet().GetRow(this.Key).Singular, + "CraftAction" => excelModule.GetSheet().GetRow(this.Key).Name, + "GeneralAction" => excelModule.GetSheet().GetRow(this.Key).Name, + "GuardianDeity" => excelModule.GetSheet().GetRow(this.Key).Name, + "MainCommand" => excelModule.GetSheet().GetRow(this.Key).Name, + "Mount" => excelModule.GetSheet().GetRow(this.Key).Singular, + "Pet" => excelModule.GetSheet().GetRow(this.Key).Name, + "PetAction" => excelModule.GetSheet().GetRow(this.Key).Name, + "PetMirage" => excelModule.GetSheet().GetRow(this.Key).Name, + "PlaceName" => excelModule.GetSheet().GetRow(this.Key).Name, + "Race" => excelModule.GetSheet().GetRow(this.Key).Masculine, + "TextCommand" => AutoTranslatePayload.ResolveTextCommand(excelModule.GetSheet().GetRow(this.Key)), + "Tribe" => excelModule.GetSheet().GetRow(this.Key).Masculine, + "Weather" => excelModule.GetSheet().GetRow(this.Key).Name, _ => throw new Exception(actualTableName), }; - value = name; + value = name.ExtractText(); } catch (Exception e) { @@ -172,12 +176,4 @@ public class AutoTranslatePayload : Payload, ITextProvider return value; } - - private Lumina.Text.SeString ResolveTextCommand() - { - // TextCommands prioritize the `Alias` field, if it not empty - // Example for this is /rangerpose2l which becomes /blackrangerposeb in chat - var result = this.DataResolver.GetExcelSheet().GetRow(this.Key); - return result.Alias.Payloads.Count > 0 ? result.Alias : result.Command; - } } diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs index e3415b2dc..c31707ff2 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs @@ -3,9 +3,10 @@ using System.IO; using System.Linq; using System.Text; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; -using Serilog; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -14,8 +15,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class ItemPayload : Payload { - private Item? item; - // mainly to allow overriding the name (for things like owo) // TODO: even though this is present in some item links, it may not really have a use at all // For things like owo, changing the text payload is probably correct, whereas changing the @@ -131,27 +130,13 @@ public class ItemPayload : Payload public uint RawItemId => this.rawItemId; /// - /// Gets the underlying Lumina Item represented by this payload. + /// Gets the underlying Lumina data represented by this payload. This is either a Item or EventItem . /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public Item? Item - { - get - { - // TODO(goat): This should be revamped/removed on an API level change. - if (this.Kind == ItemKind.EventItem) - { - Log.Warning("Event items cannot be fetched from the ItemPayload"); - return null; - } - - this.item ??= this.DataResolver.GetExcelSheet()!.GetRow(this.ItemId); - return this.item; - } - } + public RowRef Item => + this.Kind == ItemKind.EventItem + ? (RowRef)LuminaUtils.CreateRef(this.ItemId) + : (RowRef)LuminaUtils.CreateRef(this.ItemId); /// /// Gets a value indicating whether or not this item link is for a high-quality version of the item. @@ -183,7 +168,8 @@ public class ItemPayload : Payload /// public override string ToString() { - return $"{this.Type} - ItemId: {this.ItemId}, Kind: {this.Kind}, Name: {this.displayName ?? this.Item?.Name}"; + var name = this.displayName ?? (this.Item.GetValueOrDefault()?.Name ?? this.Item.GetValueOrDefault()?.Name)?.ExtractText(); + return $"{this.Type} - ItemId: {this.ItemId}, Kind: {this.Kind}, Name: {name}"; } /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs index 7d975b347..7b672d07a 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs @@ -1,7 +1,10 @@ using System.Collections.Generic; using System.IO; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -11,11 +14,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class MapLinkPayload : Payload { - private Map map; - private TerritoryType territoryType; - private string placeNameRegion; - private string placeName; - [JsonProperty] private uint territoryTypeId; @@ -38,8 +36,8 @@ public class MapLinkPayload : Payload // this fudge is necessary basically to ensure we don't shift down a full tenth // because essentially values are truncated instead of rounded, so 3.09999f will become // 3.0f and not 3.1f - this.RawX = this.ConvertMapCoordinateToRawPosition(niceXCoord + fudgeFactor, this.Map.SizeFactor, this.Map.OffsetX); - this.RawY = this.ConvertMapCoordinateToRawPosition(niceYCoord + fudgeFactor, this.Map.SizeFactor, this.Map.OffsetY); + this.RawX = this.ConvertMapCoordinateToRawPosition(niceXCoord + fudgeFactor, this.Map.Value.SizeFactor, this.Map.Value.OffsetX); + this.RawY = this.ConvertMapCoordinateToRawPosition(niceYCoord + fudgeFactor, this.Map.Value.SizeFactor, this.Map.Value.OffsetY); } /// @@ -72,20 +70,14 @@ public class MapLinkPayload : Payload /// /// Gets the Map specified for this map link. /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public Map Map => this.map ??= this.DataResolver.GetExcelSheet().GetRow(this.mapId); + public RowRef Map => LuminaUtils.CreateRef(this.mapId); /// /// Gets the TerritoryType specified for this map link. /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public TerritoryType TerritoryType => this.territoryType ??= this.DataResolver.GetExcelSheet().GetRow(this.territoryTypeId); + public RowRef TerritoryType => LuminaUtils.CreateRef(this.territoryTypeId); /// /// Gets the internal x-coordinate for this map position. @@ -102,13 +94,13 @@ public class MapLinkPayload : Payload /// /// Gets the readable x-coordinate position for this map link. This value is approximate and unrounded. /// - public float XCoord => this.ConvertRawPositionToMapCoordinate(this.RawX, this.Map.SizeFactor, this.Map.OffsetX); + public float XCoord => this.ConvertRawPositionToMapCoordinate(this.RawX, this.Map.Value.SizeFactor, this.Map.Value.OffsetX); /// /// Gets the readable y-coordinate position for this map link. This value is approximate and unrounded. /// [JsonIgnore] - public float YCoord => this.ConvertRawPositionToMapCoordinate(this.RawY, this.Map.SizeFactor, this.Map.OffsetY); + public float YCoord => this.ConvertRawPositionToMapCoordinate(this.RawY, this.Map.Value.SizeFactor, this.Map.Value.OffsetY); // there is no Z; it's purely in the text payload where applicable @@ -143,18 +135,18 @@ public class MapLinkPayload : Payload /// Gets the region name for this map link. This corresponds to the upper zone name found in the actual in-game map UI. eg, "La Noscea". /// [JsonIgnore] - public string PlaceNameRegion => this.placeNameRegion ??= this.TerritoryType.PlaceNameRegion.Value?.Name; + public string PlaceNameRegion => this.TerritoryType.Value.PlaceNameRegion.Value.Name.ExtractText(); /// /// Gets the place name for this map link. This corresponds to the lower zone name found in the actual in-game map UI. eg, "Limsa Lominsa Upper Decks". /// [JsonIgnore] - public string PlaceName => this.placeName ??= this.TerritoryType.PlaceName.Value?.Name; + public string PlaceName => this.TerritoryType.Value.PlaceName.Value.Name.ExtractText(); /// /// Gets the data string for this map link, for use by internal game functions that take a string variant and not a binary payload. /// - public string DataString => $"m:{this.TerritoryType.RowId},{this.Map.RowId},{this.RawX},{this.RawY}"; + public string DataString => $"m:{this.territoryTypeId},{this.mapId},{this.RawX},{this.RawY}"; /// public override string ToString() diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/PlayerPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/PlayerPayload.cs index b9d6bc896..07a13e5a3 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/PlayerPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/PlayerPayload.cs @@ -2,7 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Text; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -12,8 +15,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class PlayerPayload : Payload { - private World world; - [JsonProperty] private uint serverId; @@ -43,11 +44,8 @@ public class PlayerPayload : Payload /// /// Gets the Lumina object representing the player's home server. /// - /// - /// Value is evaluated lazily and cached. - /// [JsonIgnore] - public World World => this.world ??= this.DataResolver.GetExcelSheet().GetRow(this.serverId); + public RowRef World => LuminaUtils.CreateRef(this.serverId); /// /// Gets or sets the player's displayed name. This does not contain the server name. @@ -72,7 +70,7 @@ public class PlayerPayload : Payload /// The world name will always be present. /// [JsonIgnore] - public string DisplayedName => $"{this.PlayerName}{(char)SeIconChar.CrossWorld}{this.World.Name}"; + public string DisplayedName => $"{this.PlayerName}{(char)SeIconChar.CrossWorld}{this.World.ValueNullable?.Name}"; /// public override PayloadType Type => PayloadType.Player; @@ -80,7 +78,7 @@ public class PlayerPayload : Payload /// public override string ToString() { - return $"{this.Type} - PlayerName: {this.PlayerName}, ServerId: {this.serverId}, ServerName: {this.World.Name}"; + return $"{this.Type} - PlayerName: {this.PlayerName}, ServerId: {this.serverId}, ServerName: {this.World.ValueNullable?.Name}"; } /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs index e5b9e635e..19d494d8a 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs @@ -1,7 +1,10 @@ using System.Collections.Generic; using System.IO; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -11,8 +14,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class QuestPayload : Payload { - private Quest quest; - [JsonProperty] private uint questId; @@ -40,16 +41,13 @@ public class QuestPayload : Payload /// /// Gets the underlying Lumina Quest represented by this payload. /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public Quest Quest => this.quest ??= this.DataResolver.GetExcelSheet().GetRow(this.questId); + public RowRef Quest => LuminaUtils.CreateRef(this.questId); /// public override string ToString() { - return $"{this.Type} - QuestId: {this.questId}, Name: {this.Quest?.Name ?? "QUEST NOT FOUND"}"; + return $"{this.Type} - QuestId: {this.questId}, Name: {this.Quest.ValueNullable?.Name.ExtractText() ?? "QUEST NOT FOUND"}"; } /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs index 3e10f7659..d102dfab6 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs @@ -1,7 +1,10 @@ using System.Collections.Generic; using System.IO; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -11,8 +14,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class StatusPayload : Payload { - private Status status; - [JsonProperty] private uint statusId; @@ -40,16 +41,13 @@ public class StatusPayload : Payload /// /// Gets the Lumina Status object represented by this payload. /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public Status Status => this.status ??= this.DataResolver.GetExcelSheet().GetRow(this.statusId); + public RowRef Status => LuminaUtils.CreateRef(this.statusId); /// public override string ToString() { - return $"{this.Type} - StatusId: {this.statusId}, Name: {this.Status.Name}"; + return $"{this.Type} - StatusId: {this.statusId}, Name: {this.Status.ValueNullable?.Name}"; } /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs index 1cd96a81a..995c20211 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs @@ -1,7 +1,10 @@ using System.Collections.Generic; using System.IO; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -11,8 +14,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class UIForegroundPayload : Payload { - private UIColor color; - [JsonProperty] private ushort colorKey; @@ -51,11 +52,8 @@ public class UIForegroundPayload : Payload /// /// Gets a Lumina UIColor object representing this payload. The actual color data is at UIColor.UIForeground. /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public UIColor UIColor => this.color ??= this.DataResolver.GetExcelSheet().GetRow(this.colorKey); + public RowRef UIColor => LuminaUtils.CreateRef(this.colorKey); /// /// Gets or sets the color key used as a lookup in the UIColor table for this foreground color. @@ -63,15 +61,11 @@ public class UIForegroundPayload : Payload [JsonIgnore] public ushort ColorKey { - get - { - return this.colorKey; - } + get => this.colorKey; set { this.colorKey = value; - this.color = null; this.Dirty = true; } } @@ -80,13 +74,13 @@ public class UIForegroundPayload : Payload /// Gets the Red/Green/Blue/Alpha values for this foreground color, encoded as a typical hex color. /// [JsonIgnore] - public uint RGBA => this.UIColor.UIForeground; + public uint RGBA => this.UIColor.Value.UIForeground; /// /// Gets the ABGR value for this foreground color, as ImGui requires it in PushColor. /// [JsonIgnore] - public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.UIForeground); + public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.Value.UIForeground); /// public override string ToString() diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs index 68ed983ff..3049ccac3 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs @@ -1,7 +1,10 @@ using System.Collections.Generic; using System.IO; -using Lumina.Excel.GeneratedSheets; +using Dalamud.Data; + +using Lumina.Excel; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -11,8 +14,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class UIGlowPayload : Payload { - private UIColor color; - [JsonProperty] private ushort colorKey; @@ -57,7 +58,6 @@ public class UIGlowPayload : Payload set { this.colorKey = value; - this.color = null; this.Dirty = true; } } @@ -71,22 +71,19 @@ public class UIGlowPayload : Payload /// Gets the Red/Green/Blue/Alpha values for this glow color, encoded as a typical hex color. /// [JsonIgnore] - public uint RGBA => this.UIColor.UIGlow; + public uint RGBA => this.UIColor.Value.UIGlow; /// /// Gets the ABGR value for this glow color, as ImGui requires it in PushColor. /// [JsonIgnore] - public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.UIGlow); + public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.Value.UIGlow); /// /// Gets a Lumina UIColor object representing this payload. The actual color data is at UIColor.UIGlow. /// - /// - /// The value is evaluated lazily and cached. - /// [JsonIgnore] - public UIColor UIColor => this.color ??= this.DataResolver.GetExcelSheet().GetRow(this.colorKey); + public RowRef UIColor => LuminaUtils.CreateRef(this.colorKey); /// public override string ToString() diff --git a/Dalamud/Game/Text/SeStringHandling/SeString.cs b/Dalamud/Game/Text/SeStringHandling/SeString.cs index 3b83aed0c..baae181e3 100644 --- a/Dalamud/Game/Text/SeStringHandling/SeString.cs +++ b/Dalamud/Game/Text/SeStringHandling/SeString.cs @@ -7,7 +7,7 @@ using System.Text; using Dalamud.Data; using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Utility; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling; @@ -200,12 +200,12 @@ public class SeString case ItemPayload.ItemKind.Normal: case ItemPayload.ItemKind.Collectible: case ItemPayload.ItemKind.Hq: - var item = data.GetExcelSheet()?.GetRow(itemId); - displayName = item?.Name; + var item = data.GetExcelSheet()?.GetRowOrDefault(itemId); + displayName = item?.Name.ExtractText(); rarity = item?.Rarity ?? 1; break; case ItemPayload.ItemKind.EventItem: - displayName = data.GetExcelSheet()?.GetRow(itemId)?.Name; + displayName = data.GetExcelSheet()?.GetRowOrDefault(itemId)?.Name.ExtractText(); break; default: throw new ArgumentOutOfRangeException(nameof(kind), kind, null); @@ -251,7 +251,7 @@ public class SeString /// An SeString containing all the payloads necessary to display an item link in the chat log. public static SeString CreateItemLink(Item item, bool isHq, string? displayNameOverride = null) { - return CreateItemLink(item.RowId, isHq, displayNameOverride ?? item.Name); + return CreateItemLink(item.RowId, isHq, displayNameOverride ?? item.Name.ExtractText()); } /// @@ -360,15 +360,14 @@ public class SeString var mapSheet = data.GetExcelSheet(); var matches = data.GetExcelSheet() - .Where(row => row.Name.ToString().ToLowerInvariant() == placeName.ToLowerInvariant()) - .ToArray(); + .Where(row => row.Name.ExtractText().Equals(placeName, StringComparison.InvariantCultureIgnoreCase)); foreach (var place in matches) { - var map = mapSheet.FirstOrDefault(row => row.PlaceName.Row == place.RowId); - if (map != null && map.TerritoryType.Row != 0) + var map = mapSheet.Cast().FirstOrDefault(row => row!.Value.PlaceName.RowId == place.RowId); + if (map.HasValue && map.Value.TerritoryType.RowId != 0) { - return CreateMapLinkWithInstance(map.TerritoryType.Row, map.RowId, instance, xCoord, yCoord, fudgeFactor); + return CreateMapLinkWithInstance(map.Value.TerritoryType.RowId, map.Value.RowId, instance, xCoord, yCoord, fudgeFactor); } } diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs index 5a7e87e1b..ddff55923 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs @@ -5,7 +5,7 @@ using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Component.Text; using Lumina.Excel; -using Lumina.Excel.GeneratedSheets2; +using Lumina.Excel.Sheets; using Lumina.Text.Expressions; using Lumina.Text.Payloads; using Lumina.Text.ReadOnly; diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs index 8afc1b473..9d62de193 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs @@ -18,7 +18,7 @@ using FFXIVClientStructs.FFXIV.Client.UI; using ImGuiNET; -using Lumina.Excel.GeneratedSheets2; +using Lumina.Excel.Sheets; using Lumina.Text.Parse; using Lumina.Text.Payloads; using Lumina.Text.ReadOnly; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs index 606c49c49..9a3b231e5 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Game.ClientState.Aetherytes; +using Dalamud.Game.ClientState.Aetherytes; using ImGuiNET; @@ -56,7 +56,7 @@ internal class AetherytesWidget : IDataWindowWidget ImGui.TextUnformatted($"{i}"); ImGui.TableNextColumn(); // Name - ImGui.TextUnformatted($"{info.AetheryteData.GameData?.PlaceName.Value?.Name}"); + ImGui.TextUnformatted($"{info.AetheryteData.ValueNullable?.PlaceName.ValueNullable?.Name}"); ImGui.TableNextColumn(); // ID ImGui.TextUnformatted($"{info.AetheryteId}"); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs index c16cc34e1..f30585406 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.JobGauge; using Dalamud.Game.ClientState.JobGauge.Types; using Dalamud.Utility; @@ -39,7 +39,7 @@ internal class GaugeWidget : IDataWindowWidget return; } - var jobID = player.ClassJob.Id; + var jobID = player.ClassJob.RowId; JobGaugeBase? gauge = jobID switch { 19 => jobGauges.Get(), diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs index 963138bec..761dc49a8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.Objects; @@ -56,8 +56,8 @@ internal class ObjectTableWidget : IDataWindowWidget { stateString += $"ObjectTableLen: {objectTable.Length}\n"; stateString += $"LocalPlayerName: {clientState.LocalPlayer.Name}\n"; - stateString += $"CurrentWorldName: {(this.resolveGameData ? clientState.LocalPlayer.CurrentWorld.GameData?.Name : clientState.LocalPlayer.CurrentWorld.Id.ToString())}\n"; - stateString += $"HomeWorldName: {(this.resolveGameData ? clientState.LocalPlayer.HomeWorld.GameData?.Name : clientState.LocalPlayer.HomeWorld.Id.ToString())}\n"; + stateString += $"CurrentWorldName: {(this.resolveGameData ? clientState.LocalPlayer.CurrentWorld.ValueNullable?.Name : clientState.LocalPlayer.CurrentWorld.RowId.ToString())}\n"; + stateString += $"HomeWorldName: {(this.resolveGameData ? clientState.LocalPlayer.HomeWorld.ValueNullable?.Name : clientState.LocalPlayer.HomeWorld.RowId.ToString())}\n"; stateString += $"LocalCID: {clientState.LocalContentId:X}\n"; stateString += $"LastLinkedItem: {chatGui.LastLinkedItemId}\n"; stateString += $"TerritoryType: {clientState.TerritoryType}\n\n"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs index 17aba0c71..f4b76942f 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Numerics; using System.Text; @@ -16,7 +16,8 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using ImGuiNET; -using Lumina.Excel.GeneratedSheets2; +using Lumina.Excel; +using Lumina.Excel.Sheets; using Lumina.Text; using Lumina.Text.Payloads; using Lumina.Text.ReadOnly; @@ -33,7 +34,7 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget private static readonly string[] ThemeNames = ["Dark", "Light", "Classic FF", "Clear Blue"]; private ImVectorWrapper testStringBuffer; private string testString = string.Empty; - private Addon[]? addons; + private ExcelSheet addons; private ReadOnlySeString? logkind; private SeStringDrawParams style; private bool interactable; @@ -53,7 +54,7 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget public void Load() { this.style = new() { GetEntity = this.GetEntity }; - this.addons = null; + this.addons = Service.Get().GetExcelSheet(); this.logkind = null; this.testString = string.Empty; this.interactable = this.useEntity = true; @@ -155,9 +156,9 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget if (this.logkind is null) { var tt = new SeStringBuilder(); - foreach (var uc in Service.Get().GetExcelSheet()!) + foreach (var uc in Service.Get().GetExcelSheet()) { - var ucsp = uc.Format.AsReadOnly().AsSpan(); + var ucsp = uc.Format.AsSpan(); if (ucsp.IsEmpty) continue; @@ -184,7 +185,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget if (ImGui.CollapsingHeader("Addon Table")) { - this.addons ??= Service.Get().GetExcelSheet()!.ToArray(); if (ImGui.BeginTable("Addon Sheet", 3)) { ImGui.TableSetupScrollFreeze(0, 1); @@ -197,25 +197,27 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget ImGui.TableHeadersRow(); var clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper()); - clipper.Begin(this.addons.Length); + clipper.Begin(this.addons.Count); while (clipper.Step()) { for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + var row = this.addons.GetRowAt(i); + ImGui.TableNextRow(); ImGui.PushID(i); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted($"{this.addons[i].RowId}"); + ImGui.TextUnformatted($"{row.RowId}"); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGuiHelpers.SeStringWrapped(this.addons[i].Text.AsReadOnly(), this.style); + ImGuiHelpers.SeStringWrapped(row.Text, this.style); ImGui.TableNextColumn(); if (ImGui.Button("Print to Chat")) - Service.Get().Print(this.addons[i].Text.ToDalamudString()); + Service.Get().Print(row.Text.ToDalamudString()); ImGui.PopID(); } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index 575bce23c..6b57f7a6a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -1,4 +1,4 @@ -using System.Buffers.Binary; +using System.Buffers.Binary; using System.Linq; using System.Numerics; using System.Text; @@ -12,7 +12,8 @@ using Dalamud.Storage.Assets; using ImGuiNET; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel; +using Lumina.Excel.Sheets; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -21,7 +22,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class UiColorWidget : IDataWindowWidget { - private UIColor[]? colors; + private ExcelSheet colors; /// public string[]? CommandShortcuts { get; init; } = ["uicolor"]; @@ -36,15 +37,12 @@ internal class UiColorWidget : IDataWindowWidget public void Load() { this.Ready = true; - this.colors = null; + this.colors = Service.Get().GetExcelSheet(); } /// public unsafe void Draw() { - this.colors ??= Service.Get().GetExcelSheet()?.ToArray(); - if (this.colors is null) return; - Service.Get().CompileAndDrawWrapped( "· Color notation is #" + "RR" + @@ -73,12 +71,24 @@ internal class UiColorWidget : IDataWindowWidget ImGui.TableHeadersRow(); var clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper()); - clipper.Begin(this.colors.Length, ImGui.GetFrameHeightWithSpacing()); + clipper.Begin(this.colors.Count, ImGui.GetFrameHeightWithSpacing()); while (clipper.Step()) { for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - var id = this.colors[i].RowId; + var row = this.colors.GetRowAt(i); + UIColor? adjacentRow = null; + if (i + 1 < this.colors.Count) + { + var adjRow = this.colors.GetRowAt(i + 1); + if (adjRow.RowId == row.RowId + 1) + { + adjacentRow = adjRow; + } + } + + var id = row.RowId; + ImGui.TableNextRow(); ImGui.TableNextColumn(); @@ -88,33 +98,33 @@ internal class UiColorWidget : IDataWindowWidget ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.PushID($"row{id}_col1"); - if (this.DrawColorColumn(this.colors[i].UIForeground) && - i + 1 < this.colors.Length && this.colors[i + 1].RowId == id + 1) - DrawEdgePreview(id, this.colors[i].UIForeground, this.colors[i + 1].UIForeground); + if (this.DrawColorColumn(row.UIForeground) && + adjacentRow.HasValue) + DrawEdgePreview(id, row.UIForeground, adjacentRow.Value.UIForeground); ImGui.PopID(); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.PushID($"row{id}_col2"); - if (this.DrawColorColumn(this.colors[i].UIGlow) && - i + 1 < this.colors.Length && this.colors[i + 1].RowId == id + 1) - DrawEdgePreview(id, this.colors[i].UIGlow, this.colors[i + 1].UIGlow); + if (this.DrawColorColumn(row.UIGlow) && + adjacentRow.HasValue) + DrawEdgePreview(id, row.UIGlow, adjacentRow.Value.UIGlow); ImGui.PopID(); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.PushID($"row{id}_col3"); - if (this.DrawColorColumn(this.colors[i].Unknown2) && - i + 1 < this.colors.Length && this.colors[i + 1].RowId == id + 1) - DrawEdgePreview(id, this.colors[i].Unknown2, this.colors[i + 1].Unknown2); + if (this.DrawColorColumn(row.Unknown0) && + adjacentRow.HasValue) + DrawEdgePreview(id, row.Unknown0, adjacentRow.Value.Unknown0); ImGui.PopID(); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.PushID($"row{id}_col4"); - if (this.DrawColorColumn(this.colors[i].Unknown3) && - i + 1 < this.colors.Length && this.colors[i + 1].RowId == id + 1) - DrawEdgePreview(id, this.colors[i].Unknown3, this.colors[i + 1].Unknown3); + if (this.DrawColorColumn(row.Unknown1) && + adjacentRow.HasValue) + DrawEdgePreview(id, row.Unknown1, adjacentRow.Value.Unknown1); ImGui.PopID(); } } diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ContextMenuAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ContextMenuAgingStep.cs index 3bc91088d..5bcd1845c 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ContextMenuAgingStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/ContextMenuAgingStep.cs @@ -7,10 +7,9 @@ using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.Gui.ContextMenu; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; -using Dalamud.Utility; using ImGuiNET; using Lumina.Excel; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; using Serilog; namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps; @@ -45,9 +44,9 @@ internal class ContextMenuAgingStep : IAgingStep { var contextMenu = Service.Get(); var dataMgr = Service.Get(); - this.itemSheet = dataMgr.GetExcelSheet()!; - this.materiaSheet = dataMgr.GetExcelSheet()!; - this.stainSheet = dataMgr.GetExcelSheet()!; + this.itemSheet = dataMgr.GetExcelSheet(); + this.materiaSheet = dataMgr.GetExcelSheet(); + this.stainSheet = dataMgr.GetExcelSheet(); ImGui.Text(this.currentSubStep.ToString()); @@ -83,7 +82,7 @@ internal class ContextMenuAgingStep : IAgingStep case SubStep.TestDefault: if (this.targetCharacter is { } character) { - ImGui.Text($"Did you click \"{character.Name}\" ({character.ClassJob.GameData!.Abbreviation.ToDalamudString()})?"); + ImGui.Text($"Did you click \"{character.Name}\" ({character.ClassJob.Value.Abbreviation.ExtractText()})?"); if (ImGui.Button("Yes")) this.currentSubStep++; @@ -146,7 +145,7 @@ internal class ContextMenuAgingStep : IAgingStep var targetItem = (a.Target as MenuTargetInventory)!.TargetItem; if (targetItem is { } item) { - name = (this.itemSheet.GetRow(item.ItemId)?.Name.ToDalamudString() ?? $"Unknown ({item.ItemId})") + (item.IsHq ? $" {SeIconChar.HighQuality.ToIconString()}" : string.Empty); + name = (this.itemSheet.GetRowOrDefault(item.ItemId)?.Name.ExtractText() ?? $"Unknown ({item.ItemId})") + (item.IsHq ? $" {SeIconChar.HighQuality.ToIconString()}" : string.Empty); count = item.Quantity; } else @@ -194,7 +193,7 @@ internal class ContextMenuAgingStep : IAgingStep { var b = new StringBuilder(); b.AppendLine($"Target: {targetDefault.TargetName}"); - b.AppendLine($"Home World: {targetDefault.TargetHomeWorld.GameData?.Name.ToDalamudString() ?? "Unknown"} ({targetDefault.TargetHomeWorld.Id})"); + b.AppendLine($"Home World: {targetDefault.TargetHomeWorld.ValueNullable?.Name.ExtractText() ?? "Unknown"} ({targetDefault.TargetHomeWorld.RowId})"); b.AppendLine($"Content Id: 0x{targetDefault.TargetContentId:X8}"); b.AppendLine($"Object Id: 0x{targetDefault.TargetObjectId:X8}"); Log.Verbose(b.ToString()); @@ -209,20 +208,20 @@ internal class ContextMenuAgingStep : IAgingStep b.AppendLine($"Content Id: 0x{character.ContentId:X8}"); b.AppendLine($"FC Tag: {character.FCTag}"); - b.AppendLine($"Job: {character.ClassJob.GameData?.Abbreviation.ToDalamudString() ?? "Unknown"} ({character.ClassJob.Id})"); - b.AppendLine($"Statuses: {string.Join(", ", character.Statuses.Select(s => s.GameData?.Name.ToDalamudString() ?? s.Id.ToString()))}"); - b.AppendLine($"Home World: {character.HomeWorld.GameData?.Name.ToDalamudString() ?? "Unknown"} ({character.HomeWorld.Id})"); - b.AppendLine($"Current World: {character.CurrentWorld.GameData?.Name.ToDalamudString() ?? "Unknown"} ({character.CurrentWorld.Id})"); + b.AppendLine($"Job: {character.ClassJob.ValueNullable?.Abbreviation.ExtractText() ?? "Unknown"} ({character.ClassJob.RowId})"); + b.AppendLine($"Statuses: {string.Join(", ", character.Statuses.Select(s => s.ValueNullable?.Name.ExtractText() ?? s.RowId.ToString()))}"); + b.AppendLine($"Home World: {character.HomeWorld.ValueNullable?.Name.ExtractText() ?? "Unknown"} ({character.HomeWorld.RowId})"); + b.AppendLine($"Current World: {character.CurrentWorld.ValueNullable?.Name.ExtractText() ?? "Unknown"} ({character.CurrentWorld.RowId})"); b.AppendLine($"Is From Other Server: {character.IsFromOtherServer}"); b.Append("Location: "); - if (character.Location.GameData is { } location) - b.Append($"{location.PlaceNameRegion.Value?.Name.ToDalamudString() ?? "Unknown"}/{location.PlaceNameZone.Value?.Name.ToDalamudString() ?? "Unknown"}/{location.PlaceName.Value?.Name.ToDalamudString() ?? "Unknown"}"); + if (character.Location.ValueNullable is { } location) + b.Append($"{location.PlaceNameRegion.ValueNullable?.Name.ExtractText() ?? "Unknown"}/{location.PlaceNameZone.ValueNullable?.Name.ExtractText() ?? "Unknown"}/{location.PlaceName.ValueNullable?.Name.ExtractText() ?? "Unknown"}"); else b.Append("Unknown"); - b.AppendLine($" ({character.Location.Id})"); + b.AppendLine($" ({character.Location.RowId})"); - b.AppendLine($"Grand Company: {character.GrandCompany.GameData?.Name.ToDalamudString() ?? "Unknown"} ({character.GrandCompany.Id})"); + b.AppendLine($"Grand Company: {character.GrandCompany.ValueNullable?.Name.ExtractText() ?? "Unknown"} ({character.GrandCompany.RowId})"); b.AppendLine($"Client Language: {character.ClientLanguage}"); b.AppendLine($"Languages: {string.Join(", ", character.Languages)}"); b.AppendLine($"Gender: {character.Gender}"); @@ -241,7 +240,7 @@ internal class ContextMenuAgingStep : IAgingStep if (targetInventory.TargetItem is { } item) { var b = new StringBuilder(); - b.AppendLine($"Item: {(item.IsEmpty ? "None" : this.itemSheet.GetRow(item.ItemId)?.Name.ToDalamudString())} ({item.ItemId})"); + b.AppendLine($"Item: {(item.IsEmpty ? "None" : this.itemSheet.GetRowOrDefault(item.ItemId)?.Name.ExtractText())} ({item.ItemId})"); b.AppendLine($"Container: {item.ContainerType}"); b.AppendLine($"Slot: {item.InventorySlot}"); b.AppendLine($"Quantity: {item.Quantity}"); @@ -259,7 +258,7 @@ internal class ContextMenuAgingStep : IAgingStep Log.Verbose($"{materiaId} {materiaGrade}"); if (this.materiaSheet.GetRow(materiaId) is { } materia && materia.Item[materiaGrade].Value is { } materiaItem) - materias.Add($"{materiaItem.Name.ToDalamudString()}"); + materias.Add($"{materiaItem.Name.ExtractText()}"); else materias.Add($"Unknown (Id: {materiaId}, Grade: {materiaGrade})"); } @@ -275,7 +274,7 @@ internal class ContextMenuAgingStep : IAgingStep var stainId = item.Stains[i]; if (stainId != 0) { - var stainName = this.stainSheet.GetRow(stainId)?.Name.ToDalamudString().ToString() ?? "Unknown"; + var stainName = this.stainSheet.GetRowOrDefault(stainId)?.Name.ExtractText() ?? "Unknown"; b.AppendLine($" Stain {i + 1}: {stainName} ({stainId})"); } else @@ -285,13 +284,13 @@ internal class ContextMenuAgingStep : IAgingStep } if (item.Stains[0] != 0) - b.AppendLine($"{this.stainSheet.GetRow(item.Stains[0])?.Name.ToDalamudString() ?? "Unknown"} ({item.Stains[0]})"); + b.AppendLine($"{this.stainSheet.GetRowOrDefault(item.Stains[0])?.Name.ExtractText() ?? "Unknown"} ({item.Stains[0]})"); else b.AppendLine("None"); b.Append("Glamoured Item: "); if (item.GlamourId != 0) - b.AppendLine($"{this.itemSheet.GetRow(item.GlamourId)?.Name.ToDalamudString() ?? "Unknown"} ({item.GlamourId})"); + b.AppendLine($"{this.itemSheet.GetRowOrDefault(item.GlamourId)?.Name.ExtractText() ?? "Unknown"} ({item.GlamourId})"); else b.AppendLine("None"); diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs index a07b21e54..0f411b8f1 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/LuminaAgingStep.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - using Dalamud.Data; using Dalamud.Utility; using Lumina.Excel; @@ -11,31 +8,46 @@ namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps; /// Test setup for Lumina. /// /// ExcelRow to run test on. -internal class LuminaAgingStep : IAgingStep - where T : ExcelRow +/// Whether or not the sheet is large. If it is large, the self test will iterate through the full sheet in one frame and benchmark the time taken. +internal class LuminaAgingStep(bool isLargeSheet) : IAgingStep + where T : struct, IExcelRow { private int step = 0; - private List rows; + private ExcelSheet rows; /// - public string Name => "Test Lumina"; + public string Name => $"Test Lumina ({typeof(T).Name})"; /// public SelfTestStepResult RunStep() { - var dataManager = Service.Get(); + this.rows ??= Service.Get().GetExcelSheet(); - this.rows ??= dataManager.GetExcelSheet().ToList(); + if (isLargeSheet) + { + var i = 0; + T currentRow = default; + foreach (var row in this.rows) + { + i++; + currentRow = row; + } - Util.ShowObject(this.rows[this.step]); + Util.ShowObject(currentRow); + return SelfTestStepResult.Pass; + } + else + { + Util.ShowObject(this.rows.GetRowAt(this.step)); - this.step++; - return this.step >= this.rows.Count ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting; + this.step++; + return this.step >= this.rows.Count ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting; + } } /// public void CleanUp() { - // ignored + this.step = 0; } } diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs index 51c9b35f6..3b3670228 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs @@ -9,7 +9,7 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; using Dalamud.Logging.Internal; using ImGuiNET; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; namespace Dalamud.Interface.Internal.Windows.SelfTest; @@ -39,7 +39,11 @@ internal class SelfTestWindow : Window new GamepadStateAgingStep(), new ChatAgingStep(), new HoverAgingStep(), - new LuminaAgingStep(), + new LuminaAgingStep(true), + new LuminaAgingStep(true), + new LuminaAgingStep(true), + new LuminaAgingStep(true), + new LuminaAgingStep(false), new AddonLifecycleAgingStep(), new PartyFinderAgingStep(), new HandledExceptionAgingStep(), diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index 34641fe4b..59f6b23c1 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -599,7 +599,7 @@ internal class LocalPlugin : IAsyncDisposable // Changes to Lumina should be upstreamed if feasible, and if there is a desire to re-add unpinned Lumina we // will need to put this behind some kind of feature flag somewhere. config.SharedAssemblies.Add((typeof(Lumina.GameData).Assembly.GetName(), true)); - config.SharedAssemblies.Add((typeof(Lumina.Excel.ExcelSheetImpl).Assembly.GetName(), true)); + config.SharedAssemblies.Add((typeof(Lumina.Excel.Sheets.Addon).Assembly.GetName(), true)); } private void EnsureLoader() diff --git a/Dalamud/Plugin/Services/IClientState.cs b/Dalamud/Plugin/Services/IClientState.cs index 6b0555f23..f7c462d09 100644 --- a/Dalamud/Plugin/Services/IClientState.cs +++ b/Dalamud/Plugin/Services/IClientState.cs @@ -61,7 +61,7 @@ public interface IClientState /// /// Event that gets fired when a duty is ready. /// - public event Action CfPop; + public event Action CfPop; /// /// Gets the language of the client. diff --git a/Dalamud/Plugin/Services/IDataManager.cs b/Dalamud/Plugin/Services/IDataManager.cs index cead130aa..65c51a9fb 100644 --- a/Dalamud/Plugin/Services/IDataManager.cs +++ b/Dalamud/Plugin/Services/IDataManager.cs @@ -5,7 +5,9 @@ using Dalamud.Game; using Lumina; using Lumina.Data; +using Lumina.Data.Structs.Excel; using Lumina.Excel; +using Lumina.Excel.Exceptions; namespace Dalamud.Plugin.Services; @@ -37,17 +39,38 @@ public interface IDataManager /// /// Get an with the given Excel sheet row type. /// + /// Language of the sheet to get. Leave or empty to use the default language. + /// Explicitly provide the name of the sheet to get. Leave to use 's sheet name. Explicit names are necessary for quest/dungeon/cutscene sheets. /// The excel sheet type to get. /// The , giving access to game rows. - public ExcelSheet? GetExcelSheet() where T : ExcelRow; + /// + /// If the sheet type you want has subrows, use instead. + /// + /// Sheet name was not specified neither via 's nor . + /// does not have a valid . + /// Sheet does not exist. + /// Sheet had a mismatched column hash. + /// Sheet does not support nor . + /// Sheet was not a . + public ExcelSheet GetExcelSheet(ClientLanguage? language = null, string? name = null) where T : struct, IExcelRow; /// - /// Get an with the given Excel sheet row type with a specified language. + /// Get a with the given Excel sheet row type. /// - /// Language of the sheet to get. + /// Language of the sheet to get. Leave or empty to use the default language. + /// Explicitly provide the name of the sheet to get. Leave to use 's sheet name. Explicit names are necessary for quest/dungeon/cutscene sheets. /// The excel sheet type to get. - /// The , giving access to game rows. - public ExcelSheet? GetExcelSheet(ClientLanguage language) where T : ExcelRow; + /// The , giving access to game rows. + /// + /// If the sheet type you want has only rows, use instead. + /// + /// Sheet name was not specified neither via 's nor . + /// does not have a valid . + /// Sheet does not exist. + /// Sheet had a mismatched column hash. + /// Sheet does not support nor . + /// Sheet was not a . + public SubrowExcelSheet GetSubrowExcelSheet(ClientLanguage? language = null, string? name = null) where T : struct, IExcelSubrow; /// /// Get a with the given path. diff --git a/Dalamud/Utility/MapUtil.cs b/Dalamud/Utility/MapUtil.cs index 221f9cb55..3e72add9c 100644 --- a/Dalamud/Utility/MapUtil.cs +++ b/Dalamud/Utility/MapUtil.cs @@ -1,11 +1,11 @@ -using System.Numerics; +using System.Numerics; using Dalamud.Data; using Dalamud.Game.ClientState.Objects.Types; using FFXIVClientStructs.FFXIV.Client.UI.Agent; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; namespace Dalamud.Utility; @@ -149,9 +149,7 @@ public static class MapUtil if (agentMap == null || agentMap->CurrentMapId == 0) throw new InvalidOperationException("Could not determine active map - data may not be loaded yet?"); - var territoryTransient = Service.Get() - .GetExcelSheet()! - .GetRow(agentMap->CurrentTerritoryId); + var territoryTransient = LuminaUtils.CreateRef(agentMap->CurrentTerritoryId); return WorldToMap( go.Position, @@ -161,7 +159,7 @@ public static class MapUtil */ -agentMap->CurrentOffsetX, -agentMap->CurrentOffsetY, - territoryTransient?.OffsetZ ?? 0, + territoryTransient.ValueNullable?.OffsetZ ?? 0, (uint)agentMap->CurrentMapSizeFactor, correctZOffset); } diff --git a/Dalamud/Utility/SeStringExtensions.cs b/Dalamud/Utility/SeStringExtensions.cs index b89f815bc..34ebb1450 100644 --- a/Dalamud/Utility/SeStringExtensions.cs +++ b/Dalamud/Utility/SeStringExtensions.cs @@ -1,4 +1,6 @@ -using Lumina.Text.Parse; +using Lumina.Text.Parse; + +using Lumina.Text.ReadOnly; using DSeString = Dalamud.Game.Text.SeStringHandling.SeString; using DSeStringBuilder = Dalamud.Game.Text.SeStringHandling.SeStringBuilder; @@ -20,6 +22,22 @@ public static class SeStringExtensions /// The re-parsed Dalamud SeString. public static DSeString ToDalamudString(this LSeString originalString) => DSeString.Parse(originalString.RawData); + /// + /// Convert a Lumina ReadOnlySeString into a Dalamud SeString. + /// This conversion re-parses the string. + /// + /// The original Lumina ReadOnlySeString. + /// The re-parsed Dalamud SeString. + public static DSeString ToDalamudString(this ReadOnlySeString originalString) => DSeString.Parse(originalString.Data.Span); + + /// + /// Convert a Lumina ReadOnlySeStringSpan into a Dalamud SeString. + /// This conversion re-parses the string. + /// + /// The original Lumina ReadOnlySeStringSpan. + /// The re-parsed Dalamud SeString. + public static DSeString ToDalamudString(this ReadOnlySeStringSpan originalString) => DSeString.Parse(originalString.Data); + /// Compiles and appends a macro string. /// Target SeString builder. /// Macro string in UTF-8 to compile and append to . diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs index d8e05716e..e37afb765 100644 --- a/Dalamud/Utility/Util.cs +++ b/Dalamud/Utility/Util.cs @@ -21,7 +21,7 @@ using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; using Dalamud.Support; using ImGuiNET; -using Lumina.Excel.GeneratedSheets; +using Lumina.Excel.Sheets; using Serilog; using TerraFX.Interop.Windows; using Windows.Win32.Storage.FileSystem; @@ -813,7 +813,7 @@ public static class Util var names = data.GetExcelSheet(ClientLanguage.English)!; var rng = new Random(); - return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString; + return names.GetRowAt(rng.Next(0, names.Count - 1)).Singular.ExtractText(); } /// @@ -891,13 +891,13 @@ public static class Util if (actor is ICharacter chara) { actorString += - $" Level: {chara.Level} ClassJob: {(resolveGameData ? chara.ClassJob.GameData?.Name : chara.ClassJob.Id.ToString())} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}\n Customize: {BitConverter.ToString(chara.Customize).Replace("-", " ")} StatusFlags: {chara.StatusFlags}\n"; + $" Level: {chara.Level} ClassJob: {(resolveGameData ? chara.ClassJob.ValueNullable?.Name : chara.ClassJob.RowId.ToString())} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}\n Customize: {BitConverter.ToString(chara.Customize).Replace("-", " ")} StatusFlags: {chara.StatusFlags}\n"; } if (actor is IPlayerCharacter pc) { actorString += - $" HomeWorld: {(resolveGameData ? pc.HomeWorld.GameData?.Name : pc.HomeWorld.Id.ToString())} CurrentWorld: {(resolveGameData ? pc.CurrentWorld.GameData?.Name : pc.CurrentWorld.Id.ToString())} FC: {pc.CompanyTag}\n"; + $" HomeWorld: {(resolveGameData ? pc.HomeWorld.ValueNullable?.Name : pc.HomeWorld.RowId.ToString())} CurrentWorld: {(resolveGameData ? pc.CurrentWorld.ValueNullable?.Name : pc.CurrentWorld.RowId.ToString())} FC: {pc.CompanyTag}\n"; } ImGui.TextUnformatted(actorString); @@ -925,13 +925,13 @@ public static class Util if (actor is Character chara) { actorString += - $" Level: {chara.Level} ClassJob: {(resolveGameData ? chara.ClassJob.GameData?.Name : chara.ClassJob.Id.ToString())} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}\n Customize: {BitConverter.ToString(chara.Customize).Replace("-", " ")} StatusFlags: {chara.StatusFlags}\n"; + $" Level: {chara.Level} ClassJob: {(resolveGameData ? chara.ClassJob.ValueNullable?.Name : chara.ClassJob.RowId.ToString())} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}\n Customize: {BitConverter.ToString(chara.Customize).Replace("-", " ")} StatusFlags: {chara.StatusFlags}\n"; } if (actor is PlayerCharacter pc) { actorString += - $" HomeWorld: {(resolveGameData ? pc.HomeWorld.GameData?.Name : pc.HomeWorld.Id.ToString())} CurrentWorld: {(resolveGameData ? pc.CurrentWorld.GameData?.Name : pc.CurrentWorld.Id.ToString())} FC: {pc.CompanyTag}\n"; + $" HomeWorld: {(resolveGameData ? pc.HomeWorld.ValueNullable?.Name : pc.HomeWorld.RowId.ToString())} CurrentWorld: {(resolveGameData ? pc.CurrentWorld.ValueNullable?.Name : pc.CurrentWorld.RowId.ToString())} FC: {pc.CompanyTag}\n"; } ImGui.TextUnformatted(actorString); diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 81fb80190..7c5f04e34 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 81fb801905b7fe8e02aa40dcf9942e0f707dcc21 +Subproject commit 7c5f04e346067f7a316ad9072fb8260122ba80f0