diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 65ec356a7..9be9d59cd 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -33,16 +33,23 @@ "GitHubActions", "GitLab", "Jenkins", + "Rider", "SpaceAutomation", "TeamCity", "Terminal", - "TravisCI" + "TravisCI", + "VisualStudio", + "VSCode" ] }, "NoLogo": { "type": "boolean", "description": "Disables displaying the NUKE logo" }, + "Partition": { + "type": "string", + "description": "Partition to use on CI" + }, "Plan": { "type": "boolean", "description": "Shows the execution plan (HTML)" diff --git a/Dalamud/ClientLanguageExtensions.cs b/Dalamud/ClientLanguageExtensions.cs new file mode 100644 index 000000000..dccefb93f --- /dev/null +++ b/Dalamud/ClientLanguageExtensions.cs @@ -0,0 +1,27 @@ +using System; + +namespace Dalamud +{ + /// + /// Extension methods for the class. + /// + public static class ClientLanguageExtensions + { + /// + /// Converts a Dalamud ClientLanguage to the corresponding Lumina variant. + /// + /// Langauge to convert. + /// Converted langauge. + public static Lumina.Data.Language ToLumina(this ClientLanguage language) + { + return language switch + { + ClientLanguage.Japanese => Lumina.Data.Language.Japanese, + ClientLanguage.English => Lumina.Data.Language.English, + ClientLanguage.German => Lumina.Data.Language.German, + ClientLanguage.French => Lumina.Data.Language.French, + _ => throw new ArgumentOutOfRangeException(nameof(language)), + }; + } + } +} diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs index 4eb6e3b03..33933d98f 100644 --- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs +++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs @@ -92,6 +92,13 @@ namespace Dalamud.Configuration.Internal /// public Dictionary DevPluginSettings { get; set; } = new(); + /// + /// Gets or sets a list of additional locations that dev plugins should be loaded from. This can + /// be either a DLL or folder, but should be the absolute path, or a path relative to the currently + /// injected Dalamud instance. + /// + public List DevPluginLoadLocations { get; set; } = new(); + /// /// Gets or sets the global UI scale. /// diff --git a/Dalamud/Configuration/Internal/DevPluginLocationSettings.cs b/Dalamud/Configuration/Internal/DevPluginLocationSettings.cs new file mode 100644 index 000000000..995fb1a23 --- /dev/null +++ b/Dalamud/Configuration/Internal/DevPluginLocationSettings.cs @@ -0,0 +1,24 @@ +namespace Dalamud.Configuration +{ + /// + /// Additional locations to load dev plugins from. + /// + internal sealed class DevPluginLocationSettings + { + /// + /// Gets or sets the dev pluign path. + /// + public string Path { get; set; } + + /// + /// Gets or sets a value indicating whether the third party repo is enabled. + /// + public bool IsEnabled { get; set; } + + /// + /// Clone this object. + /// + /// A shallow copy of this object. + public DevPluginLocationSettings Clone() => this.MemberwiseClone() as DevPluginLocationSettings; + } +} diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index e9357c4a6..be4278ec5 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -7,11 +7,9 @@ using System.Threading; using Dalamud.Configuration.Internal; using Dalamud.Data; using Dalamud.Game; -using Dalamud.Game.Addon; using Dalamud.Game.ClientState; using Dalamud.Game.Command; using Dalamud.Game.Internal; -using Dalamud.Game.Network; using Dalamud.Game.Network.Internal; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Hooking.Internal; diff --git a/Dalamud/Data/DataManager.cs b/Dalamud/Data/DataManager.cs index ebdf24c57..093c8bb1a 100644 --- a/Dalamud/Data/DataManager.cs +++ b/Dalamud/Data/DataManager.cs @@ -5,9 +5,8 @@ using System.Diagnostics; using System.IO; using System.Threading; -using Dalamud.Data.LuminaExtensions; -using Dalamud.Interface; using Dalamud.Interface.Internal; +using Dalamud.Utility; using ImGuiScene; using JetBrains.Annotations; using Lumina; @@ -96,15 +95,7 @@ namespace Dalamud.Data /// The , giving access to game rows. public ExcelSheet GetExcelSheet(ClientLanguage language) where T : ExcelRow { - var lang = language switch - { - ClientLanguage.Japanese => Lumina.Data.Language.Japanese, - ClientLanguage.English => Lumina.Data.Language.English, - ClientLanguage.German => Lumina.Data.Language.German, - ClientLanguage.French => Lumina.Data.Language.French, - _ => throw new ArgumentOutOfRangeException(nameof(language), $"Unknown Language: {language}"), - }; - return this.Excel.GetSheet(lang); + return this.Excel.GetSheet(language.ToLumina()); } /// @@ -146,18 +137,30 @@ namespace Dalamud.Data /// /// The icon ID. /// The containing the icon. - public TexFile GetIcon(int iconId) + public TexFile GetIcon(uint iconId) { return this.GetIcon(this.Language, iconId); } + /// + /// Get a containing the icon with the given ID, of the given quality. + /// + /// A value indicating whether the icon should be HQ. + /// The icon ID. + /// The containing the icon. + public TexFile GetIcon(bool isHq, uint iconId) + { + var type = isHq ? "hq/" : string.Empty; + return this.GetIcon(type, iconId); + } + /// /// Get a containing the icon with the given ID, of the given language. /// /// The requested language. /// The icon ID. /// The containing the icon. - public TexFile GetIcon(ClientLanguage iconLanguage, int iconId) + public TexFile GetIcon(ClientLanguage iconLanguage, uint iconId) { var type = iconLanguage switch { @@ -177,7 +180,7 @@ namespace Dalamud.Data /// The type of the icon (e.g. 'hq' to get the HQ variant of an item icon). /// The icon ID. /// The containing the icon. - public TexFile GetIcon(string type, int iconId) + public TexFile GetIcon(string type, uint iconId) { type ??= string.Empty; if (type.Length > 0 && !type.EndsWith("/")) @@ -186,7 +189,8 @@ namespace Dalamud.Data var filePath = string.Format(IconFileFormat, iconId / 1000, type, iconId); var file = this.GetFile(filePath); - if (file != default(TexFile) || type.Length <= 0) return file; + if (type == string.Empty || file != default) + return file; // Couldn't get specific type, try for generic version. filePath = string.Format(IconFileFormat, iconId / 1000, string.Empty, iconId); @@ -194,6 +198,14 @@ namespace Dalamud.Data return file; } + /// + /// Get a containing the HQ icon with the given ID. + /// + /// The icon ID. + /// The containing the icon. + public TexFile GetHqIcon(uint iconId) + => this.GetIcon(true, iconId); + /// /// Get the passed as a drawable ImGui TextureWrap. /// @@ -210,13 +222,30 @@ namespace Dalamud.Data public TextureWrap GetImGuiTexture(string path) => this.GetImGuiTexture(this.GetFile(path)); + /// + /// Get a containing the icon with the given ID. + /// + /// The icon ID. + /// The containing the icon. + public TextureWrap GetImGuiTextureIcon(uint iconId) + => this.GetImGuiTexture(this.GetIcon(iconId)); + + /// + /// Get a containing the icon with the given ID, of the given quality. + /// + /// A value indicating whether the icon should be HQ. + /// The icon ID. + /// The containing the icon. + public TextureWrap GetImGuiTextureIcon(bool isHq, uint iconId) + => this.GetImGuiTexture(this.GetIcon(isHq, iconId)); + /// /// Get a containing the icon with the given ID, of the given language. /// /// The requested language. /// The icon ID. /// The containing the icon. - public TextureWrap GetImGuiTextureIcon(ClientLanguage iconLanguage, int iconId) + public TextureWrap GetImGuiTextureIcon(ClientLanguage iconLanguage, uint iconId) => this.GetImGuiTexture(this.GetIcon(iconLanguage, iconId)); /// @@ -225,9 +254,17 @@ namespace Dalamud.Data /// The type of the icon (e.g. 'hq' to get the HQ variant of an item icon). /// The icon ID. /// The containing the icon. - public TextureWrap GetImGuiTextureIcon(string type, int iconId) + public TextureWrap GetImGuiTextureIcon(string type, uint iconId) => this.GetImGuiTexture(this.GetIcon(type, iconId)); + /// + /// Get a containing the HQ icon with the given ID. + /// + /// The icon ID. + /// The containing the icon. + public TextureWrap GetImGuiTextureHqIcon(uint iconId) + => this.GetImGuiTexture(this.GetHqIcon(iconId)); + #endregion /// @@ -263,21 +300,12 @@ namespace Dalamud.Data var luminaOptions = new LuminaOptions { CacheFileResources = true, - #if DEBUG PanicOnSheetChecksumMismatch = true, #else PanicOnSheetChecksumMismatch = false, #endif - - DefaultExcelLanguage = this.Language switch - { - ClientLanguage.Japanese => Lumina.Data.Language.Japanese, - ClientLanguage.English => Lumina.Data.Language.English, - ClientLanguage.German => Lumina.Data.Language.German, - ClientLanguage.French => Lumina.Data.Language.French, - _ => throw new ArgumentOutOfRangeException(nameof(this.Language), $"Unknown Language: {this.Language}"), - }, + DefaultExcelLanguage = this.Language.ToLumina(), }; var processModule = Process.GetCurrentProcess().MainModule; diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs index 378f841fd..6ce1cdc4b 100644 --- a/Dalamud/EntryPoint.cs +++ b/Dalamud/EntryPoint.cs @@ -142,7 +142,7 @@ namespace Dalamud var oldFile = new FileInfo(oldPath); if (!oldFile.Exists) - oldFile.Create(); + oldFile.Create().Close(); using var reader = new BinaryReader(logFile.Open(FileMode.Open, FileAccess.Read)); using var writer = new BinaryWriter(oldFile.Open(FileMode.Append, FileAccess.Write)); diff --git a/Dalamud/Game/Internal/BaseAddressResolver.cs b/Dalamud/Game/BaseAddressResolver.cs similarity index 94% rename from Dalamud/Game/Internal/BaseAddressResolver.cs rename to Dalamud/Game/BaseAddressResolver.cs index 287bacaaa..b1873b0d7 100644 --- a/Dalamud/Game/Internal/BaseAddressResolver.cs +++ b/Dalamud/Game/BaseAddressResolver.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; -namespace Dalamud.Game.Internal +namespace Dalamud.Game { /// /// Base memory address resolver. @@ -11,9 +11,9 @@ namespace Dalamud.Game.Internal public abstract class BaseAddressResolver { /// - /// A list of memory addresses that were found, to list in /xldata. + /// Gets a list of memory addresses that were found, to list in /xldata. /// - public static Dictionary> DebugScannedValues = new(); + public static Dictionary> DebugScannedValues { get; } = new(); /// /// Gets or sets a value indicating whether the resolver has successfully run or . diff --git a/Dalamud/Game/ClientState/Actors/Types/Chara.cs b/Dalamud/Game/ClientState/Actors/Types/Chara.cs index 792ca17c0..5c8dca228 100644 --- a/Dalamud/Game/ClientState/Actors/Types/Chara.cs +++ b/Dalamud/Game/ClientState/Actors/Types/Chara.cs @@ -65,7 +65,7 @@ namespace Dalamud.Game.ClientState.Actors.Types /// /// Gets the ClassJob of this Chara. /// - public ClassJobResolver ClassJob => new(*(byte*)(this.Address + ActorOffsets.ClassJob), this.Dalamud); + public ExcelResolver ClassJob => new(*(byte*)(this.Address + ActorOffsets.ClassJob), this.Dalamud); /// /// Gets the level of this Chara. diff --git a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs b/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs index a1ebe1ab0..e04c36d32 100644 --- a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs +++ b/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs @@ -23,14 +23,14 @@ namespace Dalamud.Game.ClientState.Actors.Types } /// - /// Gets the current world of the character. + /// Gets the current world of the character. /// - public WorldResolver CurrentWorld => new(*(ushort*)(this.Address + ActorOffsets.CurrentWorld), this.Dalamud); + public ExcelResolver CurrentWorld => new(*(ushort*)(this.Address + ActorOffsets.CurrentWorld), this.Dalamud); /// - /// Gets the home world of the character. + /// Gets the home world of the character. /// - public WorldResolver HomeWorld => new(*(ushort*)(this.Address + ActorOffsets.HomeWorld), this.Dalamud); + public ExcelResolver HomeWorld => new(*(ushort*)(this.Address + ActorOffsets.HomeWorld), this.Dalamud); /// /// Gets the Free Company tag of this player. diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index b9e40ccd7..0df4c1f69 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -1,14 +1,16 @@ using System; using System.ComponentModel; +using System.Linq; using System.Runtime.InteropServices; using Dalamud.Game.ClientState.Actors; using Dalamud.Game.ClientState.Actors.Types; +using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Fates; -using Dalamud.Game.Internal; +using Dalamud.Game.ClientState.GamePad; +using Dalamud.Game.ClientState.Keys; using Dalamud.Hooking; using JetBrains.Annotations; -using Lumina.Excel.GeneratedSheets; using Serilog; namespace Dalamud.Game.ClientState @@ -93,7 +95,7 @@ namespace Dalamud.Game.ClientState /// /// Event that gets fired when a duty is ready. /// - public event EventHandler CfPop; + public event EventHandler CfPop; /// /// Gets the table of all present actors. @@ -194,7 +196,7 @@ namespace Dalamud.Game.ClientState return this.setupTerritoryTypeHook.Original(manager, terriType); } - private void NetworkHandlersOnCfPop(object sender, ContentFinderCondition e) + private void NetworkHandlersOnCfPop(object sender, Lumina.Excel.GeneratedSheets.ContentFinderCondition e) { this.CfPop?.Invoke(this, e); } diff --git a/Dalamud/Game/ClientState/Condition.cs b/Dalamud/Game/ClientState/Conditions/Condition.cs similarity index 94% rename from Dalamud/Game/ClientState/Condition.cs rename to Dalamud/Game/ClientState/Conditions/Condition.cs index b416c4df4..5a4322532 100644 --- a/Dalamud/Game/ClientState/Condition.cs +++ b/Dalamud/Game/ClientState/Conditions/Condition.cs @@ -1,6 +1,6 @@ using System; -namespace Dalamud.Game.ClientState +namespace Dalamud.Game.ClientState.Conditions { /// /// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc. @@ -37,7 +37,7 @@ namespace Dalamud.Game.ClientState { var idx = (int)flag; - if (idx > MaxConditionEntries || idx < 0) + if (idx < 0 || idx >= MaxConditionEntries) return false; return *(bool*)(this.ConditionArrayBase + idx); diff --git a/Dalamud/Game/ClientState/ConditionFlag.cs b/Dalamud/Game/ClientState/Conditions/ConditionFlag.cs similarity index 99% rename from Dalamud/Game/ClientState/ConditionFlag.cs rename to Dalamud/Game/ClientState/Conditions/ConditionFlag.cs index dc3d72d61..75c295ed0 100644 --- a/Dalamud/Game/ClientState/ConditionFlag.cs +++ b/Dalamud/Game/ClientState/Conditions/ConditionFlag.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.ClientState +namespace Dalamud.Game.ClientState.Conditions { /// /// Possible state flags (or conditions as they're called internally) that can be set on the local client. diff --git a/Dalamud/Game/ClientState/Fates/Types/Fate.cs b/Dalamud/Game/ClientState/Fates/Fate.cs similarity index 75% rename from Dalamud/Game/ClientState/Fates/Types/Fate.cs rename to Dalamud/Game/ClientState/Fates/Fate.cs index a42e3f925..2b284b6a5 100644 --- a/Dalamud/Game/ClientState/Fates/Types/Fate.cs +++ b/Dalamud/Game/ClientState/Fates/Fate.cs @@ -1,17 +1,19 @@ using System; +using System.Numerics; using Dalamud.Game.ClientState.Resolvers; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Memory; -using FFXIVClientStructs.FFXIV.Client.System.String; -namespace Dalamud.Game.ClientState.Fates.Types +namespace Dalamud.Game.ClientState.Fates { /// /// This class represents an FFXIV Fate. /// public unsafe partial class Fate : IEquatable { + private Dalamud dalamud; + /// /// Initializes a new instance of the class. /// @@ -20,7 +22,7 @@ namespace Dalamud.Game.ClientState.Fates.Types internal Fate(IntPtr address, Dalamud dalamud) { this.Address = address; - this.Dalamud = dalamud; + this.dalamud = dalamud; } /// @@ -28,10 +30,7 @@ namespace Dalamud.Game.ClientState.Fates.Types /// public IntPtr Address { get; } - /// - /// Gets Dalamud itself. - /// - private protected Dalamud Dalamud { get; } + private FFXIVClientStructs.FFXIV.Client.Game.Fate.FateContext* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Fate.FateContext*)this.Address; public static bool operator ==(Fate fate1, Fate fate2) { @@ -53,7 +52,7 @@ namespace Dalamud.Game.ClientState.Fates.Types if (fate == null) return false; - if (fate.Dalamud.ClientState.LocalContentId == 0) + if (fate.dalamud.ClientState.LocalContentId == 0) return false; return true; @@ -83,22 +82,22 @@ namespace Dalamud.Game.ClientState.Fates.Types /// /// Gets the Fate ID of this . /// - public ushort FateId => *(ushort*)(this.Address + FateOffsets.FateId); + public ushort FateId => this.Struct->FateId; /// /// Gets game data linked to this Fate. /// - public Lumina.Excel.GeneratedSheets.Fate GameData => this.Dalamud.Data.GetExcelSheet().GetRow(this.FateId); + public Lumina.Excel.GeneratedSheets.Fate GameData => this.dalamud.Data.GetExcelSheet().GetRow(this.FateId); /// /// Gets the time this started. /// - public int StartTimeEpoch => *(int*)(this.Address + FateOffsets.StartTimeEpoch); + public int StartTimeEpoch => this.Struct->StartTimeEpoch; /// /// Gets how long this will run. /// - public short Duration => *(short*)(this.Address + FateOffsets.Duration); + public short Duration => this.Struct->Duration; /// /// Gets the remaining time in seconds for this . @@ -108,31 +107,31 @@ namespace Dalamud.Game.ClientState.Fates.Types /// /// Gets the displayname of this . /// - public SeString Name => MemoryHelper.ReadSeString((Utf8String*)(this.Address + FateOffsets.Name)); + public SeString Name => MemoryHelper.ReadSeString(&this.Struct->Name); /// /// Gets the state of this (Running, Ended, Failed, Preparation, WaitingForEnd). /// - public FateState State => *(FateState*)(this.Address + FateOffsets.State); + public FateState State => (FateState)this.Struct->State; /// /// Gets the progress amount of this . /// - public byte Progress => *(byte*)(this.Address + FateOffsets.Progress); + public byte Progress => this.Struct->Progress; /// /// Gets the level of this . /// - public byte Level => *(byte*)(this.Address + FateOffsets.Level); + public byte Level => this.Struct->Level; /// /// Gets the position of this . /// - public Position3 Position => *(Position3*)(this.Address + FateOffsets.Position); + public Vector3 Position => new(this.Struct->X, this.Struct->Y, this.Struct->Z); /// /// Gets the territory this is located in. /// - public TerritoryTypeResolver TerritoryType => new(*(ushort*)(this.Address + FateOffsets.Territory), this.Dalamud); + public ExcelResolver TerritoryType => new(this.Struct->TerritoryID, this.dalamud); } } diff --git a/Dalamud/Game/ClientState/Fates/Types/FateState.cs b/Dalamud/Game/ClientState/Fates/FateState.cs similarity index 93% rename from Dalamud/Game/ClientState/Fates/Types/FateState.cs rename to Dalamud/Game/ClientState/Fates/FateState.cs index 94eb00717..c7a789231 100644 --- a/Dalamud/Game/ClientState/Fates/Types/FateState.cs +++ b/Dalamud/Game/ClientState/Fates/FateState.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.ClientState.Fates.Types +namespace Dalamud.Game.ClientState.Fates { /// /// This represents the state of a single Fate. diff --git a/Dalamud/Game/ClientState/Fates/FateTable.cs b/Dalamud/Game/ClientState/Fates/FateTable.cs index 07158820e..cd6e58ada 100644 --- a/Dalamud/Game/ClientState/Fates/FateTable.cs +++ b/Dalamud/Game/ClientState/Fates/FateTable.cs @@ -2,7 +2,6 @@ using System; using System.Collections; using System.Collections.Generic; -using Dalamud.Game.ClientState.Fates.Types; using JetBrains.Annotations; using Serilog; @@ -13,11 +12,6 @@ namespace Dalamud.Game.ClientState.Fates /// public sealed partial class FateTable { - // If the pointer at this offset is 0, do not scan the table - private const int CheckPtrOffset = 0x80; - private const int FirstPtrOffset = 0x90; - private const int LastPtrOffset = 0x98; - private readonly Dalamud dalamud; private readonly ClientStateAddressResolver address; @@ -45,12 +39,13 @@ namespace Dalamud.Game.ClientState.Fates if (fateTable == IntPtr.Zero) return 0; - var check = *(long*)(fateTable + CheckPtrOffset); + // Sonar used this to check if the table was safe to read + var check = Struct->Unk80.ToInt64(); if (check == 0) return 0; - var start = *(long*)(fateTable + FirstPtrOffset); - var end = *(long*)(fateTable + LastPtrOffset); + var start = Struct->FirstFatePtr.ToInt64(); + var end = Struct->LastFatePtr.ToInt64(); if (start == 0 || end == 0) return 0; @@ -58,7 +53,10 @@ namespace Dalamud.Game.ClientState.Fates } } - private unsafe IntPtr FateTableAddress + /// + /// Gets the address of the Fate table. + /// + internal unsafe IntPtr FateTableAddress { get { @@ -69,6 +67,8 @@ namespace Dalamud.Game.ClientState.Fates } } + private unsafe FFXIVClientStructs.FFXIV.Client.Game.Fate.FateManager* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Fate.FateManager*)this.FateTableAddress; + /// /// Get an actor at the specified spawn index. /// @@ -80,22 +80,6 @@ namespace Dalamud.Game.ClientState.Fates get { var address = this.GetFateAddress(index); - return this[address]; - } - } - - /// - /// Get a Fate at the specified address. - /// - /// The Fate address. - /// A at the specified address. - public Fate this[IntPtr address] - { - get - { - if (address == IntPtr.Zero) - return null; - return this.CreateFateReference(address); } } @@ -114,7 +98,7 @@ namespace Dalamud.Game.ClientState.Fates if (fateTable == IntPtr.Zero) return IntPtr.Zero; - var firstFate = *(IntPtr*)(fateTable + FirstPtrOffset); + var firstFate = this.Struct->FirstFatePtr; return *(IntPtr*)(firstFate + (8 * index)); } @@ -139,20 +123,11 @@ namespace Dalamud.Game.ClientState.Fates /// /// This collection represents the currently available Fate events. /// - public sealed partial class FateTable : IReadOnlyCollection, ICollection + public sealed partial class FateTable : IReadOnlyCollection { /// int IReadOnlyCollection.Count => this.Length; - /// - int ICollection.Count => this.Length; - - /// - bool ICollection.IsSynchronized => false; - - /// - object ICollection.SyncRoot => this; - /// public IEnumerator GetEnumerator() { @@ -164,15 +139,5 @@ namespace Dalamud.Game.ClientState.Fates /// IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - - /// - void ICollection.CopyTo(Array array, int index) - { - for (var i = 0; i < this.Length; i++) - { - array.SetValue(this[i], index); - index++; - } - } } } diff --git a/Dalamud/Game/ClientState/Fates/Types/FateOffsets.cs b/Dalamud/Game/ClientState/Fates/Types/FateOffsets.cs deleted file mode 100644 index 73bc7a702..000000000 --- a/Dalamud/Game/ClientState/Fates/Types/FateOffsets.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Dalamud.Game.ClientState.Fates.Types -{ - /// - /// Memory offsets for the type. - /// - [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the offset usage instead.")] - public static class FateOffsets - { - public const int FateId = 0x18; - public const int StartTimeEpoch = 0x20; - public const int Duration = 0x28; - public const int Name = 0xC0; - public const int State = 0x3AC; - public const int Progress = 0x3B8; - public const int Level = 0x3F9; - public const int Position = 0x450; - public const int Territory = 0x74E; - } -} diff --git a/Dalamud/Game/ClientState/GamepadButtons.cs b/Dalamud/Game/ClientState/GamePad/GamepadButtons.cs similarity index 97% rename from Dalamud/Game/ClientState/GamepadButtons.cs rename to Dalamud/Game/ClientState/GamePad/GamepadButtons.cs index 80a745d53..7813803c8 100644 --- a/Dalamud/Game/ClientState/GamepadButtons.cs +++ b/Dalamud/Game/ClientState/GamePad/GamepadButtons.cs @@ -1,6 +1,6 @@ -using System; +using System; -namespace Dalamud.Game.ClientState +namespace Dalamud.Game.ClientState.GamePad { /// /// Bitmask of the Button ushort used by the game. diff --git a/Dalamud/Game/ClientState/Structs/GamepadInput.cs b/Dalamud/Game/ClientState/GamePad/GamepadInput.cs similarity index 98% rename from Dalamud/Game/ClientState/Structs/GamepadInput.cs rename to Dalamud/Game/ClientState/GamePad/GamepadInput.cs index df80b0ef4..d6d46a0cc 100644 --- a/Dalamud/Game/ClientState/Structs/GamepadInput.cs +++ b/Dalamud/Game/ClientState/GamePad/GamepadInput.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace Dalamud.Game.ClientState.Structs +namespace Dalamud.Game.ClientState.GamePad { /// /// Struct which gets populated by polling the gamepads. diff --git a/Dalamud/Game/ClientState/GamepadState.cs b/Dalamud/Game/ClientState/GamePad/GamepadState.cs similarity index 97% rename from Dalamud/Game/ClientState/GamepadState.cs rename to Dalamud/Game/ClientState/GamePad/GamepadState.cs index 2d84fdb83..8759673b2 100644 --- a/Dalamud/Game/ClientState/GamepadState.cs +++ b/Dalamud/Game/ClientState/GamePad/GamepadState.cs @@ -1,11 +1,10 @@ using System; -using Dalamud.Game.ClientState.Structs; using Dalamud.Hooking; using ImGuiNET; using Serilog; -namespace Dalamud.Game.ClientState +namespace Dalamud.Game.ClientState.GamePad { /// /// Exposes the game gamepad state to dalamud. @@ -24,7 +23,7 @@ namespace Dalamud.Game.ClientState private int rightStickY; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Resolver knowing the pointer to the GamepadPoll function. public GamepadState(ClientStateAddressResolver resolver) @@ -43,12 +42,10 @@ namespace Dalamud.Game.ClientState private delegate int ControllerPoll(IntPtr controllerInput); -#if DEBUG /// /// Gets the pointer to the current instance of the GamepadInput struct. /// - public IntPtr GamepadInput { get; private set; } -#endif + public IntPtr GamepadInputAddress { get; private set; } /// /// Gets the state of the left analogue stick in the left direction between 0 (not tilted) and 1 (max tilt). @@ -189,9 +186,7 @@ namespace Dalamud.Game.ClientState var original = this.gamepadPoll.Original(gamepadInput); try { -#if DEBUG - this.GamepadInput = gamepadInput; -#endif + this.GamepadInputAddress = gamepadInput; var input = (GamepadInput*)gamepadInput; this.leftStickX = input->LeftStickX; this.leftStickY = input->LeftStickY; diff --git a/Dalamud/Game/ClientState/KeyState.cs b/Dalamud/Game/ClientState/Keys/KeyState.cs similarity index 87% rename from Dalamud/Game/ClientState/KeyState.cs rename to Dalamud/Game/ClientState/Keys/KeyState.cs index e17d2cf50..b9d21ef2e 100644 --- a/Dalamud/Game/ClientState/KeyState.cs +++ b/Dalamud/Game/ClientState/Keys/KeyState.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; using Serilog; -namespace Dalamud.Game.ClientState +namespace Dalamud.Game.ClientState.Keys { /// /// Wrapper around the game keystate buffer, which contains the pressed state for all keyboard keys, indexed by virtual vkCode. @@ -52,6 +52,13 @@ namespace Dalamud.Game.ClientState } } + /// + /// Get or set the keypressed state for a given VirtualKey enum. + /// + /// The virtual key to change. + /// Whether the specified key is currently pressed. + public bool this[VirtualKey vk] => this[(int)vk]; + /// /// Clears the pressed state for all keys. /// diff --git a/Dalamud/Game/ClientState/Keys/VirtualKey.cs b/Dalamud/Game/ClientState/Keys/VirtualKey.cs new file mode 100644 index 000000000..ab9436822 --- /dev/null +++ b/Dalamud/Game/ClientState/Keys/VirtualKey.cs @@ -0,0 +1,1044 @@ +namespace Dalamud.Game.ClientState.Keys +{ + /// + /// Virtual-key codes. + /// + /// + /// Defined in winuser.h from Windows SDK v6.1. + /// + public enum VirtualKey : ushort + { + /// + /// This is an addendum to use on functions in which you have to pass a zero value to represent no key code. + /// + NO_KEY = 0, + + /// + /// Left mouse button. + /// + LBUTTON = 1, + + /// + /// Right mouse button. + /// + RBUTTON = 2, + + /// + /// Control-break processing. + /// + CANCEL = 3, + + /// + /// Middle mouse button (three-button mouse). + /// + /// + /// NOT contiguous with L and R buttons. + /// + MBUTTON = 4, + + /// + /// X1 mouse button. + /// + /// + /// NOT contiguous with L and R buttons. + /// + XBUTTON1 = 5, + + /// + /// X2 mouse button. + /// + /// + /// NOT contiguous with L and R buttons. + /// + XBUTTON2 = 6, + + /// + /// BACKSPACE key. + /// + BACK = 8, + + /// + /// TAB key. + /// + TAB = 9, + + /// + /// CLEAR key. + /// + CLEAR = 12, + + /// + /// RETURN key. + /// + RETURN = 13, + + /// + /// SHIFT key. + /// + SHIFT = 16, + + /// + /// CONTROL key. + /// + CONTROL = 17, + + /// + /// ALT key. + /// + MENU = 18, + + /// + /// PAUSE key. + /// + PAUSE = 19, + + /// + /// CAPS LOCK key. + /// + CAPITAL = 20, + + /// + /// IME Kana mode. + /// + KANA = 21, + + /// + /// IME Hanguel mode (maintained for compatibility; use User32.VirtualKey.HANGUL). + /// + HANGEUL = KANA, + + /// + /// IME Hangul mode. + /// + HANGUL = KANA, + + /// + /// IME Junja mode. + /// + JUNJA = 23, + + /// + /// IME final mode. + /// + FINAL = 24, + + /// + /// IME Hanja mode. + /// + HANJA = 25, + + /// + /// IME Kanji mode. + /// + KANJI = HANJA, + + /// + /// ESC key. + /// + ESCAPE = 27, + + /// + /// IME convert. + /// + CONVERT = 28, + + /// + /// IME nonconvert. + /// + NONCONVERT = 29, + + /// + /// IME accept. + /// + ACCEPT = 30, + + /// + /// IME mode change request. + /// + MODECHANGE = 31, + + /// + /// SPACEBAR. + /// + SPACE = 32, + + /// + /// PAGE UP key. + /// + PRIOR = 33, + + /// + /// PAGE DOWN key. + /// + NEXT = 34, + + /// + /// END key. + /// + END = 35, + + /// + /// HOME key. + /// + HOME = 36, + + /// + /// LEFT ARROW key. + /// + LEFT = 37, + + /// + /// UP ARROW key. + /// + UP = 38, + + /// + /// RIGHT ARROW key. + /// + RIGHT = 39, + + /// + /// DOWN ARROW key. + /// + DOWN = 40, + + /// + /// SELECT key. + /// + SELECT = 41, + + /// + /// PRINT key. + /// + PRINT = 42, + + /// + /// EXECUTE key. + /// + EXECUTE = 43, + + /// + /// PRINT SCREEN key. + /// + SNAPSHOT = 44, + + /// + /// INS key. + /// + INSERT = 45, + + /// + /// DEL key. + /// + DELETE = 46, + + /// + /// HELP key. + /// + HELP = 47, + + /// + /// 0 key. + /// + KEY_0 = 48, + + /// + /// 1 key. + /// + KEY_1 = 49, + + /// + /// 2 key. + /// + KEY_2 = 50, + + /// + /// 3 key. + /// + KEY_3 = 51, + + /// + /// 4 key. + /// + KEY_4 = 52, + + /// + /// 5 key. + /// + KEY_5 = 53, + + /// + /// 6 key. + /// + KEY_6 = 54, + + /// + /// 7 key. + /// + KEY_7 = 55, + + /// + /// 8 key. + /// + KEY_8 = 56, + + /// + /// 9 key. + /// + KEY_9 = 57, + + /// + /// A key. + /// + A = 65, + + /// + /// B key. + /// + B = 66, + + /// + /// C key. + /// + C = 67, + + /// + /// D key. + /// + D = 68, + + /// + /// E key. + /// + E = 69, + + /// + /// F key. + /// + F = 70, + + /// + /// G key. + /// + G = 71, + + /// + /// H key. + /// + H = 72, + + /// + /// I key. + /// + I = 73, + + /// + /// J key. + /// + J = 74, + + /// + /// K key. + /// + K = 75, + + /// + /// L key. + /// + L = 76, + + /// + /// M key. + /// + M = 77, + + /// + /// N key. + /// + N = 78, + + /// + /// O key. + /// + O = 79, + + /// + /// P key. + /// + P = 80, + + /// + /// Q key. + /// + Q = 81, + + /// + /// R key. + /// + R = 82, + + /// + /// S key. + /// + S = 83, + + /// + /// T key. + /// + T = 84, + + /// + /// U key. + /// + U = 85, + + /// + /// V key. + /// + V = 86, + + /// + /// W key. + /// + W = 87, + + /// + /// X key. + /// + X = 88, + + /// + /// Y key. + /// + Y = 89, + + /// + /// Z key. + /// + Z = 90, + + /// + /// Left Windows key (Natural keyboard). + /// + LWIN = 91, + + /// + /// Right Windows key (Natural keyboard). + /// + RWIN = 92, + + /// + /// Applications key (Natural keyboard). + /// + APPS = 93, + + /// + /// Computer Sleep key. + /// + SLEEP = 95, + + /// + /// Numeric keypad 0 key. + /// + NUMPAD0 = 96, + + /// + /// Numeric keypad 1 key. + /// + NUMPAD1 = 97, + + /// + /// Numeric keypad 2 key. + /// + NUMPAD2 = 98, + + /// + /// Numeric keypad 3 key. + /// + NUMPAD3 = 99, + + /// + /// Numeric keypad 4 key. + /// + NUMPAD4 = 100, + + /// + /// Numeric keypad 5 key. + /// + NUMPAD5 = 101, + + /// + /// Numeric keypad 6 key. + /// + NUMPAD6 = 102, + + /// + /// Numeric keypad 7 key. + /// + NUMPAD7 = 103, + + /// + /// Numeric keypad 8 key. + /// + NUMPAD8 = 104, + + /// + /// Numeric keypad 9 key. + /// + NUMPAD9 = 105, + + /// + /// Multiply key. + /// + MULTIPLY = 106, + + /// + /// Add key. + /// + ADD = 107, + + /// + /// Separator key. + /// + SEPARATOR = 108, + + /// + /// Subtract key. + /// + SUBTRACT = 109, + + /// + /// Decimal key. + /// + DECIMAL = 110, + + /// + /// Divide key. + /// + DIVIDE = 111, + + /// + /// F1 Key. + /// + F1 = 112, + + /// + /// F2 Key. + /// + F2 = 113, + + /// + /// F3 Key. + /// + F3 = 114, + + /// + /// F4 Key. + /// + F4 = 115, + + /// + /// F5 Key. + /// + F5 = 116, + + /// + /// F6 Key. + /// + F6 = 117, + + /// + /// F7 Key. + /// + F7 = 118, + + /// + /// F8 Key. + /// + F8 = 119, + + /// + /// F9 Key. + /// + F9 = 120, + + /// + /// F10 Key. + /// + F10 = 121, + + /// + /// F11 Key. + /// + F11 = 122, + + /// + /// F12 Key. + /// + F12 = 123, + + /// + /// F13 Key. + /// + F13 = 124, + + /// + /// F14 Key. + /// + F14 = 125, + + /// + /// F15 Key. + /// + F15 = 126, + + /// + /// F16 Key. + /// + F16 = 127, + + /// + /// F17 Key. + /// + F17 = 128, + + /// + /// F18 Key. + /// + F18 = 129, + + /// + /// F19 Key. + /// + F19 = 130, + + /// + /// F20 Key. + /// + F20 = 131, + + /// + /// F21 Key. + /// + F21 = 132, + + /// + /// F22 Key. + /// + F22 = 133, + + /// + /// F23 Key. + /// + F23 = 134, + + /// + /// F24 Key. + /// + F24 = 135, + + /// + /// NUM LOCK key. + /// + NUMLOCK = 144, + + /// + /// SCROLL LOCK key. + /// + SCROLL = 145, + + /// + /// '=' key on numpad (NEC PC-9800 kbd definitions). + /// + OEM_NEC_EQUAL = 146, + + /// + /// 'Dictionary' key (Fujitsu/OASYS kbd definitions). + /// + OEM_FJ_JISHO = OEM_NEC_EQUAL, + + /// + /// 'Unregister word' key (Fujitsu/OASYS kbd definitions). + /// + OEM_FJ_MASSHOU = 147, + + /// + /// 'Register word' key (Fujitsu/OASYS kbd definitions). + /// + OEM_FJ_TOUROKU = 148, + + /// + /// 'Left OYAYUBI' key (Fujitsu/OASYS kbd definitions). + /// + OEM_FJ_LOYA = 149, + + /// + /// 'Right OYAYUBI' key (Fujitsu/OASYS kbd definitions). + /// + OEM_FJ_ROYA = 150, + + /// + /// Left SHIFT key. + /// + /// + /// Used only as parameters to User32.GetAsyncKeyState and User32.GetKeyState. No other API or message will distinguish left and right keys in this way. + /// + LSHIFT = 160, + + /// + /// Right SHIFT key. + /// + RSHIFT = 161, + + /// + /// Left CONTROL key. + /// + LCONTROL = 162, + + /// + /// Right CONTROL key. + /// + RCONTROL = 163, + + /// + /// Left MENU key. + /// + LMENU = 164, + + /// + /// Right MENU key. + /// + RMENU = 165, + + /// + /// Browser Back key. + /// + BROWSER_BACK = 166, + + /// + /// Browser Forward key. + /// + BROWSER_FORWARD = 167, + + /// + /// Browser Refresh key. + /// + BROWSER_REFRESH = 168, + + /// + /// Browser Stop key. + /// + BROWSER_STOP = 169, + + /// + /// Browser Search key. + /// + BROWSER_SEARCH = 170, + + /// + /// Browser Favorites key. + /// + BROWSER_FAVORITES = 171, + + /// + /// Browser Start and Home key. + /// + BROWSER_HOME = 172, + + /// + /// Volume Mute key. + /// + VOLUME_MUTE = 173, + + /// + /// Volume Down key. + /// + VOLUME_DOWN = 174, + + /// + /// Volume Up key. + /// + VOLUME_UP = 175, + + /// + /// Next Track key. + /// + MEDIA_NEXT_TRACK = 176, + + /// + /// Previous Track key. + /// + MEDIA_PREV_TRACK = 177, + + /// + /// Stop Media key. + /// + MEDIA_STOP = 178, + + /// + /// Play/Pause Media key. + /// + MEDIA_PLAY_PAUSE = 179, + + /// + /// Start Mail key. + /// + LAUNCH_MAIL = 180, + + /// + /// Select Media key. + /// + LAUNCH_MEDIA_SELECT = 181, + + /// + /// Start Application 1 key. + /// + LAUNCH_APP1 = 182, + + /// + /// Start Application 2 key. + /// + LAUNCH_APP2 = 183, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the ';:' key. + /// + OEM_1 = 186, + + /// + /// For any country/region, the '+' key. + /// + OEM_PLUS = 187, + + /// + /// For any country/region, the ',' key. + /// + OEM_COMMA = 188, + + /// + /// For any country/region, the '-' key. + /// + OEM_MINUS = 189, + + /// + /// For any country/region, the '.' key. + /// + OEM_PERIOD = 190, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the '/?' key. + /// + OEM_2 = 191, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the '`~' key. + /// + OEM_3 = 192, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the '[{' key. + /// + OEM_4 = 219, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the '\|' key. + /// + OEM_5 = 220, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the ']}' key. + /// + OEM_6 = 221, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + /// + /// For the US standard keyboard, the 'single-quote/double-quote' (''"') key. + /// + OEM_7 = 222, + + /// + /// Used for miscellaneous characters; it can vary by keyboard.. + /// + OEM_8 = 223, + + /// + /// OEM specific. + /// + /// + /// 'AX' key on Japanese AX kbd. + /// + OEM_AX = 225, + + /// + /// Either the angle bracket ("<>") key or the backslash ("\|") key on the RT 102-key keyboard. + /// + OEM_102 = 226, + + /// + /// OEM specific. + /// + /// + /// Help key on ICO. + /// + ICO_HELP = 227, + + /// + /// OEM specific. + /// + /// + /// 00 key on ICO. + /// + ICO_00 = 228, + + /// + /// IME PROCESS key. + /// + PROCESSKEY = 229, + + /// + /// OEM specific. + /// + /// + /// Clear key on ICO. + /// + ICO_CLEAR = 230, + + /// + /// Used to pass Unicode characters as if they were keystrokes. The PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods.. + /// + /// + /// For more information, see Remark in User32.KEYBDINPUT, User32.SendInput, User32.WindowMessage.WM_KEYDOWN, and User32.WindowMessage.WM_KEYUP. + /// + PACKET = 231, + + /// + /// Nokia/Ericsson definition. + /// + OEM_RESET = 233, + + /// + /// Nokia/Ericsson definition. + /// + OEM_JUMP = 234, + + /// + /// Nokia/Ericsson definition. + /// + OEM_PA1 = 235, + + /// + /// Nokia/Ericsson definition. + /// + OEM_PA2 = 236, + + /// + /// Nokia/Ericsson definition. + /// + OEM_PA3 = 237, + + /// + /// Nokia/Ericsson definition. + /// + OEM_WSCTRL = 238, + + /// + /// Nokia/Ericsson definition. + /// + OEM_CUSEL = 239, + + /// + /// Nokia/Ericsson definition. + /// + OEM_ATTN = 240, + + /// + /// Nokia/Ericsson definition. + /// + OEM_FINISH = 241, + + /// + /// Nokia/Ericsson definition. + /// + OEM_COPY = 242, + + /// + /// Nokia/Ericsson definition. + /// + OEM_AUTO = 243, + + /// + /// Nokia/Ericsson definition. + /// + OEM_ENLW = 244, + + /// + /// Nokia/Ericsson definition. + /// + OEM_BACKTAB = 245, + + /// + /// Attn key. + /// + ATTN = 246, + + /// + /// CrSel key. + /// + CRSEL = 247, + + /// + /// ExSel key. + /// + EXSEL = 248, + + /// + /// Erase EOF key. + /// + EREOF = 249, + + /// + /// Play key. + /// + PLAY = 250, + + /// + /// Zoom key. + /// + ZOOM = 251, + + /// + /// Reserved constant by Windows headers definition. + /// + NONAME = 252, + + /// + /// PA1 key. + /// + PA1 = 253, + + /// + /// Clear key. + /// + OEM_CLEAR = 254, + } +} diff --git a/Dalamud/Game/ClientState/Resolvers/ClassJobResolver.cs b/Dalamud/Game/ClientState/Resolvers/ClassJobResolver.cs deleted file mode 100644 index b9603838d..000000000 --- a/Dalamud/Game/ClientState/Resolvers/ClassJobResolver.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Dalamud.Game.ClientState.Resolvers -{ - /// - /// This object represents a class or job. - /// - public class ClassJobResolver : BaseResolver - { - /// - /// Initializes a new instance of the class. - /// Set up the ClassJob resolver with the provided ID. - /// - /// The ID of the classJob. - /// The Dalamud instance. - internal ClassJobResolver(ushort id, Dalamud dalamud) - : base(id, dalamud) - { - } - } -} diff --git a/Dalamud/Game/ClientState/Resolvers/BaseResolver{T}.cs b/Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs similarity index 75% rename from Dalamud/Game/ClientState/Resolvers/BaseResolver{T}.cs rename to Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs index 2ded995d7..920f7b69e 100644 --- a/Dalamud/Game/ClientState/Resolvers/BaseResolver{T}.cs +++ b/Dalamud/Game/ClientState/Resolvers/ExcelResolver{T}.cs @@ -3,19 +3,19 @@ using Lumina.Excel; namespace Dalamud.Game.ClientState.Resolvers { /// - /// This object represents a class or job. + /// This object resolves a rowID within an Excel sheet. /// /// The type of Lumina sheet to resolve. - public class BaseResolver where T : ExcelRow + public class ExcelResolver where T : ExcelRow { private readonly Dalamud dalamud; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The ID of the classJob. /// The Dalamud instance. - internal BaseResolver(uint id, Dalamud dalamud) + internal ExcelResolver(uint id, Dalamud dalamud) { this.dalamud = dalamud; this.Id = id; diff --git a/Dalamud/Game/ClientState/Resolvers/FateResolver.cs b/Dalamud/Game/ClientState/Resolvers/FateResolver.cs deleted file mode 100644 index 15f2fce0d..000000000 --- a/Dalamud/Game/ClientState/Resolvers/FateResolver.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Dalamud.Game.ClientState.Resolvers -{ - /// - /// This object represents a Fate a character can participate in. - /// - public class FateResolver : BaseResolver - { - /// - /// Initializes a new instance of the class. - /// Set up the Fate resolver with the provided ID. - /// - /// The ID of the Fate. - /// The Dalamud instance. - internal FateResolver(ushort id, Dalamud dalamud) - : base(id, dalamud) - { - } - } -} diff --git a/Dalamud/Game/ClientState/Resolvers/TerritoryTypeResolver.cs b/Dalamud/Game/ClientState/Resolvers/TerritoryTypeResolver.cs deleted file mode 100644 index 248bf94bb..000000000 --- a/Dalamud/Game/ClientState/Resolvers/TerritoryTypeResolver.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Dalamud.Game.ClientState.Resolvers -{ - /// - /// This object represents a territory a character can be in. - /// - public class TerritoryTypeResolver : BaseResolver - { - /// - /// Initializes a new instance of the class. - /// Set up the territory type resolver with the provided ID. - /// - /// The ID of the territory type. - /// The Dalamud instance. - internal TerritoryTypeResolver(ushort id, Dalamud dalamud) - : base(id, dalamud) - { - } - } -} diff --git a/Dalamud/Game/ClientState/Resolvers/WorldResolver.cs b/Dalamud/Game/ClientState/Resolvers/WorldResolver.cs deleted file mode 100644 index 0d37e3549..000000000 --- a/Dalamud/Game/ClientState/Resolvers/WorldResolver.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Dalamud.Game.ClientState.Resolvers -{ - /// - /// This object represents a world a character can reside on. - /// - public class WorldResolver : BaseResolver - { - /// - /// Initializes a new instance of the class. - /// Set up the world resolver with the provided ID. - /// - /// The ID of the world. - /// The Dalamud instance. - internal WorldResolver(ushort id, Dalamud dalamud) - : base(id, dalamud) - { - } - } -} diff --git a/Dalamud/Game/Internal/Framework.cs b/Dalamud/Game/Framework.cs similarity index 98% rename from Dalamud/Game/Internal/Framework.cs rename to Dalamud/Game/Framework.cs index abe3272e0..cd16fb829 100644 --- a/Dalamud/Game/Internal/Framework.cs +++ b/Dalamud/Game/Framework.cs @@ -5,13 +5,13 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading; -using Dalamud.Game.Internal.Gui; -using Dalamud.Game.Internal.Libc; -using Dalamud.Game.Internal.Network; +using Dalamud.Game.Gui; +using Dalamud.Game.Libc; +using Dalamud.Game.Network; using Dalamud.Hooking; using Serilog; -namespace Dalamud.Game.Internal +namespace Dalamud.Game { /// /// This class represents the Framework of the native game client and grants access to various subsystems. @@ -90,7 +90,7 @@ namespace Dalamud.Game.Internal /// /// Gets the stats history mapping. /// - public static Dictionary> StatsHistory = new(); + public static Dictionary> StatsHistory { get; } = new(); #region Subsystems diff --git a/Dalamud/Game/Internal/FrameworkAddressResolver.cs b/Dalamud/Game/FrameworkAddressResolver.cs similarity index 97% rename from Dalamud/Game/Internal/FrameworkAddressResolver.cs rename to Dalamud/Game/FrameworkAddressResolver.cs index 1af2e9263..7bcae5045 100644 --- a/Dalamud/Game/Internal/FrameworkAddressResolver.cs +++ b/Dalamud/Game/FrameworkAddressResolver.cs @@ -1,7 +1,9 @@ using System; using System.Runtime.InteropServices; -namespace Dalamud.Game.Internal +using Dalamud.Game.Internal; + +namespace Dalamud.Game { /// /// The address resolver for the class. diff --git a/Dalamud/Game/GameVersion.cs b/Dalamud/Game/GameVersion.cs index 8ef76eabe..a93e0bff2 100644 --- a/Dalamud/Game/GameVersion.cs +++ b/Dalamud/Game/GameVersion.cs @@ -209,6 +209,32 @@ namespace Dalamud.Game return v2 <= v1; } + public static GameVersion operator +(GameVersion v1, TimeSpan v2) + { + if (v1 == null) + throw new ArgumentNullException(nameof(v1)); + + if (v1.Year == -1 || v1.Month == -1 || v1.Day == -1) + return v1; + + var date = new DateTime(v1.Year, v1.Month, v1.Day) + v2; + + return new GameVersion(date.Year, date.Month, date.Day, v1.Major, v1.Minor); + } + + public static GameVersion operator -(GameVersion v1, TimeSpan v2) + { + if (v1 == null) + throw new ArgumentNullException(nameof(v1)); + + if (v1.Year == -1 || v1.Month == -1 || v1.Day == -1) + return v1; + + var date = new DateTime(v1.Year, v1.Month, v1.Day) - v2; + + return new GameVersion(date.Year, date.Month, date.Day, v1.Major, v1.Minor); + } + /// /// Parse a version string. YYYY.MM.DD.majr.minr or "any". /// diff --git a/Dalamud/Game/Internal/Gui/Addon/Addon.cs b/Dalamud/Game/Gui/Addons/Addon.cs similarity index 56% rename from Dalamud/Game/Internal/Gui/Addon/Addon.cs rename to Dalamud/Game/Gui/Addons/Addon.cs index 5a0c4ce98..207443b8b 100644 --- a/Dalamud/Game/Internal/Gui/Addon/Addon.cs +++ b/Dalamud/Game/Gui/Addons/Addon.cs @@ -1,66 +1,63 @@ using System; -namespace Dalamud.Game.Internal.Gui.Addon +using Dalamud.Memory; + +namespace Dalamud.Game.Gui.Addons { /// /// This class represents an in-game UI "Addon". /// - public class Addon + public unsafe class Addon { - /// - /// The address of the addon. - /// - public IntPtr Address; - - /// - /// The addon interop data. - /// - protected Structs.Addon addonStruct; - /// /// Initializes a new instance of the class. /// /// The address of the addon. - /// The addon interop data. - public Addon(IntPtr address, Structs.Addon addonStruct) + public Addon(IntPtr address) { this.Address = address; - this.addonStruct = addonStruct; } + /// + /// Gets the address of the addon. + /// + public IntPtr Address { get; } + /// /// Gets the name of the addon. /// - public string Name => this.addonStruct.Name; + public string Name => MemoryHelper.ReadString((IntPtr)this.Struct->Name, 0x20); /// /// Gets the X position of the addon on screen. /// - public short X => this.addonStruct.X; + public short X => this.Struct->X; /// /// Gets the Y position of the addon on screen. /// - public short Y => this.addonStruct.Y; + public short Y => this.Struct->Y; /// /// Gets the scale of the addon. /// - public float Scale => this.addonStruct.Scale; + public float Scale => this.Struct->Scale; /// /// Gets the width of the addon. This may include non-visible parts. /// - public unsafe float Width => this.addonStruct.RootNode->Width * this.Scale; + public unsafe float Width => this.Struct->RootNode->Width * this.Scale; /// /// Gets the height of the addon. This may include non-visible parts. /// - public unsafe float Height => this.addonStruct.RootNode->Height * this.Scale; + public unsafe float Height => this.Struct->RootNode->Height * this.Scale; /// /// Gets a value indicating whether the addon is visible. /// - public bool Visible => (this.addonStruct.Flags & 0x20) == 0x20; + public bool Visible => this.Struct->IsVisible; + + private FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase* Struct => (FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase*)this.Address; } } diff --git a/Dalamud/Game/Internal/Gui/ChatGui.cs b/Dalamud/Game/Gui/ChatGui.cs similarity index 93% rename from Dalamud/Game/Internal/Gui/ChatGui.cs rename to Dalamud/Game/Gui/ChatGui.cs index 09aa234eb..09f5d2a2a 100644 --- a/Dalamud/Game/Internal/Gui/ChatGui.cs +++ b/Dalamud/Game/Gui/ChatGui.cs @@ -2,16 +2,15 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using Dalamud.Game.Internal.Libc; +using Dalamud.Game.Libc; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Hooking; using Serilog; -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui { /// /// This class handles interacting with the native chat UI. @@ -60,17 +59,6 @@ namespace Dalamud.Game.Internal.Gui /// A value indicating whether the message was handled or should be propagated. public delegate void OnMessageDelegate(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled); - /// - /// A delegate type used with the event. - /// - /// The type of chat. - /// The sender ID. - /// The sender name. - /// The message sent. - /// A value indicating whether the message was handled or should be propagated. - [Obsolete("Please use OnMessageDelegate instead. For modifications, it will take precedence.")] - public delegate void OnMessageRawDelegate(XivChatType type, uint senderId, ref StdString sender, ref StdString message, ref bool isHandled); - /// /// A delegate type used with the event. /// @@ -113,12 +101,6 @@ namespace Dalamud.Game.Internal.Gui /// public event OnMessageDelegate OnChatMessage; - /// - /// Event that will be fired when a chat message is sent by the game, containing raw, unparsed data. - /// - [Obsolete("Please use OnChatMessage instead. For modifications, it will take precedence.")] - public event OnMessageRawDelegate OnChatMessageRaw; - /// /// Event that allows you to stop messages from appearing in chat by setting the isHandled parameter to true. /// @@ -353,7 +335,7 @@ namespace Dalamud.Game.Internal.Gui this.LastLinkedItemId = Marshal.ReadInt32(itemInfoPtr, 8); this.LastLinkedItemFlags = Marshal.ReadByte(itemInfoPtr, 0x14); - Log.Debug($"HandlePopulateItemLinkDetour {linkObjectPtr} {itemInfoPtr} - linked:{this.LastLinkedItemId}"); + Log.Verbose($"HandlePopulateItemLinkDetour {linkObjectPtr} {itemInfoPtr} - linked:{this.LastLinkedItemId}"); } catch (Exception ex) { @@ -388,7 +370,6 @@ namespace Dalamud.Game.Internal.Gui if (!isHandled) { this.OnChatMessage?.Invoke(chattype, senderid, ref parsedSender, ref parsedMessage, ref isHandled); - this.OnChatMessageRaw?.Invoke(chattype, senderid, ref sender, ref message, ref isHandled); } var newEdited = parsedMessage.Encode(); diff --git a/Dalamud/Game/Internal/Gui/ChatGuiAddressResolver.cs b/Dalamud/Game/Gui/ChatGuiAddressResolver.cs similarity index 97% rename from Dalamud/Game/Internal/Gui/ChatGuiAddressResolver.cs rename to Dalamud/Game/Gui/ChatGuiAddressResolver.cs index 067558e12..07c154f1f 100644 --- a/Dalamud/Game/Internal/Gui/ChatGuiAddressResolver.cs +++ b/Dalamud/Game/Gui/ChatGuiAddressResolver.cs @@ -1,6 +1,8 @@ using System; -namespace Dalamud.Game.Internal.Gui +using Dalamud.Game.Internal; + +namespace Dalamud.Game.Gui { /// /// The address resolver for the class. @@ -102,7 +104,7 @@ namespace Dalamud.Game.Internal.Gui protected override void Setup64Bit(SigScanner sig) { // PrintMessage = sig.ScanText("4055 57 41 ?? 41 ?? 488DAC24D8FEFFFF 4881EC28020000 488B05???????? 4833C4 488985F0000000 4532D2 48894C2448"); LAST PART FOR 5.1??? - this.PrintMessage = sig.ScanText("4055 53 56 4154 4157 48 8d ac 24 ?? ?? ?? ?? 48 81 ec 20 02 00 00 48 8b 05"); + this.PrintMessage = sig.ScanText("40 55 53 56 41 54 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC 20 02 00 00 48 8B 05"); // PrintMessage = sig.ScanText("4055 57 41 ?? 41 ?? 488DAC24E8FEFFFF 4881EC18020000 488B05???????? 4833C4 488985E0000000 4532D2 48894C2438"); old // PrintMessage = sig.ScanText("40 55 57 41 56 41 57 48 8D AC 24 D8 FE FF FF 48 81 EC 28 02 00 00 48 8B 05 63 47 4A 01 48 33 C4 48 89 85 F0 00 00 00 45 32 D2 48 89 4C 24 48 33"); diff --git a/Dalamud/Game/Internal/Gui/FlyTextGui.cs b/Dalamud/Game/Gui/FlyTextGui.cs similarity index 100% rename from Dalamud/Game/Internal/Gui/FlyTextGui.cs rename to Dalamud/Game/Gui/FlyTextGui.cs diff --git a/Dalamud/Game/Internal/Gui/FlyTextGuiAddressResolver.cs b/Dalamud/Game/Gui/FlyTextGuiAddressResolver.cs similarity index 100% rename from Dalamud/Game/Internal/Gui/FlyTextGuiAddressResolver.cs rename to Dalamud/Game/Gui/FlyTextGuiAddressResolver.cs diff --git a/Dalamud/Game/Internal/Gui/FlyTextKind.cs b/Dalamud/Game/Gui/FlyTextKind.cs similarity index 100% rename from Dalamud/Game/Internal/Gui/FlyTextKind.cs rename to Dalamud/Game/Gui/FlyTextKind.cs diff --git a/Dalamud/Game/Internal/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs similarity index 86% rename from Dalamud/Game/Internal/Gui/GameGui.cs rename to Dalamud/Game/Gui/GameGui.cs index 005a15da9..c783d338f 100644 --- a/Dalamud/Game/Internal/Gui/GameGui.cs +++ b/Dalamud/Game/Gui/GameGui.cs @@ -1,25 +1,23 @@ using System; +using System.Numerics; using System.Runtime.InteropServices; +using Dalamud.Game.Gui.Addons; +using Dalamud.Game.Gui.PartyFinder; +using Dalamud.Game.Internal.Gui; using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Hooking; using Dalamud.Interface; +using Dalamud.Utility; using Serilog; -using SharpDX; -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui { /// /// A class handling many aspects of the in-game UI. /// public sealed class GameGui : IDisposable { - /// - /// The delegate of the native method that gets the Client::UI::UIModule address. - /// - /// The Client::UI::UIModule address. - public readonly GetBaseUIObjectDelegate GetBaseUIObject; - private readonly Dalamud dalamud; private readonly GameGuiAddressResolver address; @@ -147,6 +145,12 @@ namespace Dalamud.Game.Internal.Gui /// public event EventHandler OnUiHideToggled; + /// + /// Gets a callable delegate for the GetBaseUIObject game method. + /// + /// The Client::UI::UIModule address. + public GetBaseUIObjectDelegate GetBaseUIObject { get; } + /// /// Gets the instance. /// @@ -233,13 +237,13 @@ namespace Dalamud.Game.Internal.Gui /// Coordinates in the world. /// Converted coordinates. /// True if worldPos corresponds to a position in front of the camera. - public bool WorldToScreen(Vector3 worldPos, out Vector2 screenPos) + public bool WorldToScreen(SharpDX.Vector3 worldPos, out SharpDX.Vector2 screenPos) { // Get base object with matrices var matrixSingleton = this.getMatrixSingleton(); // Read current ViewProjectionMatrix plus game window size - var viewProjectionMatrix = default(Matrix); + var viewProjectionMatrix = default(SharpDX.Matrix); float width, height; var windowPos = ImGuiHelpers.MainViewport.Pos; @@ -254,9 +258,9 @@ namespace Dalamud.Game.Internal.Gui height = *(rawMatrix + 1); } - Vector3.Transform(ref worldPos, ref viewProjectionMatrix, out Vector3 pCoords); + SharpDX.Vector3.Transform(ref worldPos, ref viewProjectionMatrix, out SharpDX.Vector3 pCoords); - screenPos = new Vector2(pCoords.X / pCoords.Z, pCoords.Y / pCoords.Z); + screenPos = new SharpDX.Vector2(pCoords.X / pCoords.Z, pCoords.Y / pCoords.Z); screenPos.X = (0.5f * width * (screenPos.X + 1f)) + windowPos.X; screenPos.Y = (0.5f * height * (1f - screenPos.Y)) + windowPos.Y; @@ -266,6 +270,39 @@ namespace Dalamud.Game.Internal.Gui screenPos.Y > windowPos.Y && screenPos.Y < windowPos.Y + height; } + /// + /// Converts in-world coordinates to screen coordinates (upper left corner origin). + /// + /// Coordinates in the world. + /// Converted coordinates. + /// True if worldPos corresponds to a position in front of the camera. + /// + /// This overload requires a conversion to SharpDX vectors, however the penalty should be negligible. + /// + public bool WorldToScreen(Vector3 worldPos, out Vector2 screenPos) + { + var result = this.WorldToScreen(worldPos.ToSharpDX(), out var sharpScreenPos); + screenPos = sharpScreenPos.ToSystem(); + return result; + } + + /// + /// Converts in-world coordinates to screen coordinates (upper left corner origin). + /// + /// Coordinates in the world. + /// Converted coordinates. + /// True if worldPos corresponds to a position in front of the camera. + /// + /// This overload requires a conversion to SharpDX vectors, however the penalty should be negligible. + /// + public bool WorldToScreen(Position3 worldPos, out Vector2 screenPos) + { + // This overload is necessary due to Positon3 implicit operators. + var result = this.WorldToScreen((SharpDX.Vector3)worldPos, out var sharpScreenPos); + screenPos = sharpScreenPos.ToSystem(); + return result; + } + /// /// Converts screen coordinates to in-world coordinates via raycasting. /// @@ -273,7 +310,7 @@ namespace Dalamud.Game.Internal.Gui /// Converted coordinates. /// How far to search for a collision. /// True if successful. On false, worldPos's contents are undefined. - public bool ScreenToWorld(Vector2 screenPos, out Vector3 worldPos, float rayDistance = 100000.0f) + public bool ScreenToWorld(SharpDX.Vector2 screenPos, out SharpDX.Vector3 worldPos, float rayDistance = 100000.0f) { // The game is only visible in the main viewport, so if the cursor is outside // of the game window, do not bother calculating anything @@ -291,7 +328,7 @@ namespace Dalamud.Game.Internal.Gui var matrixSingleton = this.getMatrixSingleton(); // Read current ViewProjectionMatrix plus game window size - var viewProjectionMatrix = default(Matrix); + var viewProjectionMatrix = default(SharpDX.Matrix); float width, height; unsafe { @@ -306,18 +343,18 @@ namespace Dalamud.Game.Internal.Gui viewProjectionMatrix.Invert(); - var localScreenPos = new Vector2(screenPos.X - windowPos.X, screenPos.Y - windowPos.Y); - var screenPos3D = new Vector3 + var localScreenPos = new SharpDX.Vector2(screenPos.X - windowPos.X, screenPos.Y - windowPos.Y); + var screenPos3D = new SharpDX.Vector3 { X = (localScreenPos.X / width * 2.0f) - 1.0f, Y = -((localScreenPos.Y / height * 2.0f) - 1.0f), Z = 0, }; - Vector3.TransformCoordinate(ref screenPos3D, ref viewProjectionMatrix, out var camPos); + SharpDX.Vector3.TransformCoordinate(ref screenPos3D, ref viewProjectionMatrix, out var camPos); screenPos3D.Z = 1; - Vector3.TransformCoordinate(ref screenPos3D, ref viewProjectionMatrix, out var camPosOne); + SharpDX.Vector3.TransformCoordinate(ref screenPos3D, ref viewProjectionMatrix, out var camPosOne); var clipPos = camPosOne - camPos; clipPos.Normalize(); @@ -347,7 +384,7 @@ namespace Dalamud.Game.Internal.Gui } } - worldPos = new Vector3 + worldPos = new SharpDX.Vector3 { X = worldPosArray[0], Y = worldPosArray[1], @@ -358,6 +395,23 @@ namespace Dalamud.Game.Internal.Gui return isSuccess; } + /// + /// Converts screen coordinates to in-world coordinates via raycasting. + /// + /// Screen coordinates. + /// Converted coordinates. + /// How far to search for a collision. + /// True if successful. On false, worldPos's contents are undefined. + /// + /// This overload requires a conversion to SharpDX vectors, however the penalty should be negligible. + /// + public bool ScreenToWorld(Vector2 screenPos, out Vector3 worldPos, float rayDistance = 100000.0f) + { + var result = this.ScreenToWorld(screenPos.ToSharpDX(), out var sharpworldPos); + worldPos = sharpworldPos.ToSystem(); + return result; + } + /// /// Gets a pointer to the game's UI module. /// @@ -385,12 +439,14 @@ namespace Dalamud.Game.Internal.Gui /// The addon name. /// The index of the addon, starting at 1. /// The native memory representation of the addon, if it exists. - public Addon.Addon GetAddonByName(string name, int index) + public Addon GetAddonByName(string name, int index) { - var addonMem = this.GetUiObjectByName(name, index); - if (addonMem == IntPtr.Zero) return null; - var addonStruct = Marshal.PtrToStructure(addonMem); - return new Addon.Addon(addonMem, addonStruct); + var address = this.GetUiObjectByName(name, index); + + if (address == IntPtr.Zero) + return null; + + return new Addon(address); } /// diff --git a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs b/Dalamud/Game/Gui/GameGuiAddressResolver.cs similarity index 99% rename from Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs rename to Dalamud/Game/Gui/GameGuiAddressResolver.cs index 12c46faa4..b3e04d68d 100644 --- a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs +++ b/Dalamud/Game/Gui/GameGuiAddressResolver.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui { /// /// The address resolver for the class. diff --git a/Dalamud/Game/Internal/Gui/HoverActionKind.cs b/Dalamud/Game/Gui/HoverActionKind.cs similarity index 96% rename from Dalamud/Game/Internal/Gui/HoverActionKind.cs rename to Dalamud/Game/Gui/HoverActionKind.cs index f069cb614..217ea18fb 100644 --- a/Dalamud/Game/Internal/Gui/HoverActionKind.cs +++ b/Dalamud/Game/Gui/HoverActionKind.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui { /// /// ActionKinds used in AgentActionDetail. diff --git a/Dalamud/Game/Internal/Gui/HoveredAction.cs b/Dalamud/Game/Gui/HoveredAction.cs similarity index 94% rename from Dalamud/Game/Internal/Gui/HoveredAction.cs rename to Dalamud/Game/Gui/HoveredAction.cs index ebc0dea15..1a7336610 100644 --- a/Dalamud/Game/Internal/Gui/HoveredAction.cs +++ b/Dalamud/Game/Gui/HoveredAction.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui { /// /// This class represents the hotbar action currently hovered over by the cursor. diff --git a/Dalamud/Game/Gui/PartyFinder/Internal/PartyFinderPacket.cs b/Dalamud/Game/Gui/PartyFinder/Internal/PartyFinderPacket.cs new file mode 100644 index 000000000..9f8834ecd --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Internal/PartyFinderPacket.cs @@ -0,0 +1,28 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Dalamud.Game.Gui.PartyFinder.Internal +{ + /// + /// The structure of the PartyFinder packet. + /// + [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Sequential struct marshaling.")] + [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Sequential struct marshaling.")] + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the field usage.")] + [StructLayout(LayoutKind.Sequential)] + internal readonly struct PartyFinderPacket + { + /// + /// Gets the size of this packet. + /// + internal static int PacketSize { get; } = Marshal.SizeOf(); + + internal readonly int BatchNumber; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + private readonly byte[] padding1; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + internal readonly PartyFinderPacketListing[] Listings; + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Internal/PartyFinderPacketListing.cs b/Dalamud/Game/Gui/PartyFinder/Internal/PartyFinderPacketListing.cs new file mode 100644 index 000000000..75f24c88c --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Internal/PartyFinderPacketListing.cs @@ -0,0 +1,99 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Dalamud.Game.Gui.PartyFinder.Internal +{ + /// + /// The structure of an individual listing within a packet. + /// + [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Sequential struct marshaling.")] + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the field usage.")] + [StructLayout(LayoutKind.Sequential)] + internal readonly struct PartyFinderPacketListing + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + private readonly byte[] header1; + internal readonly uint Id; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + private readonly byte[] header2; + + internal readonly uint ContentIdLower; + private readonly ushort unknownShort1; + private readonly ushort unknownShort2; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + private readonly byte[] header3; + + internal readonly byte Category; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + private readonly byte[] header4; + + internal readonly ushort Duty; + internal readonly byte DutyType; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + private readonly byte[] header5; + + internal readonly ushort World; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + private readonly byte[] header6; + + internal readonly byte Objective; + internal readonly byte BeginnersWelcome; + internal readonly byte Conditions; + internal readonly byte DutyFinderSettings; + internal readonly byte LootRules; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + private readonly byte[] header7; // all zero in every pf I've examined + + private readonly uint lastPatchHotfixTimestamp; // last time the servers were restarted? + internal readonly ushort SecondsRemaining; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + private readonly byte[] header8; // 00 00 01 00 00 00 in every pf I've examined + + internal readonly ushort MinimumItemLevel; + internal readonly ushort HomeWorld; + internal readonly ushort CurrentWorld; + + private readonly byte header9; + + internal readonly byte NumSlots; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + private readonly byte[] header10; + + internal readonly byte SearchArea; + + private readonly byte header11; + + internal readonly byte NumParties; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + private readonly byte[] header12; // 00 00 00 always. maybe numParties is a u32? + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + internal readonly uint[] Slots; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + internal readonly byte[] JobsPresent; + + // Note that ByValTStr will not work here because the strings are UTF-8 and there's only a CharSet for UTF-16 in C#. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + internal readonly byte[] Name; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)] + internal readonly byte[] Description; + + internal bool IsNull() + { + // a valid party finder must have at least one slot set + return this.Slots.All(slot => slot == 0); + } + } +} diff --git a/Dalamud/Game/Internal/Gui/PartyFinderAddressResolver.cs b/Dalamud/Game/Gui/PartyFinder/PartyFinderAddressResolver.cs old mode 100755 new mode 100644 similarity index 82% rename from Dalamud/Game/Internal/Gui/PartyFinderAddressResolver.cs rename to Dalamud/Game/Gui/PartyFinder/PartyFinderAddressResolver.cs index 3c0f80e34..75da83180 --- a/Dalamud/Game/Internal/Gui/PartyFinderAddressResolver.cs +++ b/Dalamud/Game/Gui/PartyFinder/PartyFinderAddressResolver.cs @@ -1,11 +1,11 @@ using System; -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui.PartyFinder { /// /// The address resolver for the class. /// - internal class PartyFinderAddressResolver : BaseAddressResolver + public class PartyFinderAddressResolver : BaseAddressResolver { /// /// Gets the address of the native ReceiveListing method. diff --git a/Dalamud/Game/Internal/Gui/PartyFinderGui.cs b/Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs old mode 100755 new mode 100644 similarity index 79% rename from Dalamud/Game/Internal/Gui/PartyFinderGui.cs rename to Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs index 24079cf4e..dcfd03c46 --- a/Dalamud/Game/Internal/Gui/PartyFinderGui.cs +++ b/Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs @@ -1,11 +1,12 @@ using System; using System.Runtime.InteropServices; -using Dalamud.Game.Internal.Gui.Structs; +using Dalamud.Game.Gui.PartyFinder.Internal; +using Dalamud.Game.Gui.PartyFinder.Types; using Dalamud.Hooking; using Serilog; -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui.PartyFinder { /// /// This class handles interacting with the native PartyFinder window. @@ -30,7 +31,7 @@ namespace Dalamud.Game.Internal.Gui this.address = new PartyFinderAddressResolver(); this.address.Setup(scanner); - this.memory = Marshal.AllocHGlobal(PartyFinder.PacketInfo.PacketSize); + this.memory = Marshal.AllocHGlobal(PartyFinderPacket.PacketSize); this.receiveListingHook = new Hook(this.address.ReceiveListing, new ReceiveListingDelegate(this.HandleReceiveListingDetour)); } @@ -87,7 +88,7 @@ namespace Dalamud.Game.Internal.Gui { var dataPtr = data + 0x10; - var packet = Marshal.PtrToStructure(dataPtr); + var packet = Marshal.PtrToStructure(dataPtr); // rewriting is an expensive operation, so only do it if necessary var needToRewrite = false; @@ -125,33 +126,8 @@ namespace Dalamud.Game.Internal.Gui // copy our new memory over the game's unsafe { - Buffer.MemoryCopy((void*)this.memory, (void*)dataPtr, PartyFinder.PacketInfo.PacketSize, PartyFinder.PacketInfo.PacketSize); + Buffer.MemoryCopy((void*)this.memory, (void*)dataPtr, PartyFinderPacket.PacketSize, PartyFinderPacket.PacketSize); } } } - - /// - /// This class represents additional arguments passed by the game. - /// - public class PartyFinderListingEventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// The batch number. - internal PartyFinderListingEventArgs(int batchNumber) - { - this.BatchNumber = batchNumber; - } - - /// - /// Gets the batch number. - /// - public int BatchNumber { get; } - - /// - /// Gets or sets a value indicating whether the listing is visible. - /// - public bool Visible { get; set; } = true; - } } diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderCategory.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderCategory.cs new file mode 100644 index 000000000..d7ffe568b --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderCategory.cs @@ -0,0 +1,48 @@ +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Category flags for the class. + /// + public enum DutyFinderCategory + { + /// + /// The duty category. + /// + Duty = 0, + + /// + /// The quest battle category. + /// + QuestBattles = 1 << 0, + + /// + /// The fate category. + /// + Fates = 1 << 1, + + /// + /// The treasure hunt category. + /// + TreasureHunt = 1 << 2, + + /// + /// The hunt category. + /// + TheHunt = 1 << 3, + + /// + /// The gathering forays category. + /// + GatheringForays = 1 << 4, + + /// + /// The deep dungeons category. + /// + DeepDungeons = 1 << 5, + + /// + /// The adventuring forays category. + /// + AdventuringForays = 1 << 6, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderConditionFlags.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderConditionFlags.cs new file mode 100644 index 000000000..2abd371ab --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderConditionFlags.cs @@ -0,0 +1,26 @@ +using System; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Condition flags for the class. + /// + [Flags] + public enum DutyFinderConditionFlags : uint + { + /// + /// No duty condition. + /// + None = 1, + + /// + /// The duty complete condition. + /// + DutyComplete = 2, + + /// + /// The duty incomplete condition. + /// + DutyIncomplete = 4, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderLootRuleFlags.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderLootRuleFlags.cs new file mode 100644 index 000000000..aa75807fd --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderLootRuleFlags.cs @@ -0,0 +1,26 @@ +using System; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Loot rule flags for the class. + /// + [Flags] + public enum DutyFinderLootRuleFlags : uint + { + /// + /// No loot rules. + /// + None = 0, + + /// + /// The greed only rule. + /// + GreedOnly = 1, + + /// + /// The lootmaster rule. + /// + Lootmaster = 2, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderObjectiveFlags.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderObjectiveFlags.cs new file mode 100644 index 000000000..40e34c1fc --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderObjectiveFlags.cs @@ -0,0 +1,31 @@ +using System; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Objective flags for the class. + /// + [Flags] + public enum DutyFinderObjectiveFlags : uint + { + /// + /// No objective. + /// + None = 0, + + /// + /// The duty completion objective. + /// + DutyCompletion = 1, + + /// + /// The practice objective. + /// + Practice = 2, + + /// + /// The loot objective. + /// + Loot = 4, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderSearchAreaFlags.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderSearchAreaFlags.cs new file mode 100644 index 000000000..c9c238e48 --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderSearchAreaFlags.cs @@ -0,0 +1,36 @@ +using System; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Search area flags for the class. + /// + [Flags] + public enum DutyFinderSearchAreaFlags : uint + { + /// + /// Datacenter. + /// + DataCentre = 1 << 0, + + /// + /// Private. + /// + Private = 1 << 1, + + /// + /// Alliance raid. + /// + AllianceRaid = 1 << 2, + + /// + /// World. + /// + World = 1 << 3, + + /// + /// One player per job. + /// + OnePlayerPerJob = 1 << 5, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderSettingsFlags.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderSettingsFlags.cs new file mode 100644 index 000000000..6dfe10c69 --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyFinderSettingsFlags.cs @@ -0,0 +1,31 @@ +using System; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Duty finder settings flags for the class. + /// + [Flags] + public enum DutyFinderSettingsFlags : uint + { + /// + /// No duty finder settings. + /// + None = 0, + + /// + /// The undersized party setting. + /// + UndersizedParty = 1 << 0, + + /// + /// The minimum item level setting. + /// + MinimumItemLevel = 1 << 1, + + /// + /// The silence echo setting. + /// + SilenceEcho = 1 << 2, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/DutyType.cs b/Dalamud/Game/Gui/PartyFinder/Types/DutyType.cs new file mode 100644 index 000000000..3e3342938 --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/DutyType.cs @@ -0,0 +1,23 @@ +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Duty type flags for the class. + /// + public enum DutyType + { + /// + /// No duty type. + /// + Other = 0, + + /// + /// The roulette duty type. + /// + Roulette = 1 << 0, + + /// + /// The normal duty type. + /// + Normal = 1 << 1, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/JobFlags.cs b/Dalamud/Game/Gui/PartyFinder/Types/JobFlags.cs new file mode 100644 index 000000000..98fa1b1fe --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/JobFlags.cs @@ -0,0 +1,146 @@ +using System; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Job flags for the class. + /// + [Flags] + public enum JobFlags + { + /// + /// Gladiator (GLD). + /// + Gladiator = 1 << 1, + + /// + /// Pugilist (PGL). + /// + Pugilist = 1 << 2, + + /// + /// Marauder (MRD). + /// + Marauder = 1 << 3, + + /// + /// Lancer (LNC). + /// + Lancer = 1 << 4, + + /// + /// Archer (ARC). + /// + Archer = 1 << 5, + + /// + /// Conjurer (CNJ). + /// + Conjurer = 1 << 6, + + /// + /// Thaumaturge (THM). + /// + Thaumaturge = 1 << 7, + + /// + /// Paladin (PLD). + /// + Paladin = 1 << 8, + + /// + /// Monk (MNK). + /// + Monk = 1 << 9, + + /// + /// Warrior (WAR). + /// + Warrior = 1 << 10, + + /// + /// Dragoon (DRG). + /// + Dragoon = 1 << 11, + + /// + /// Bard (BRD). + /// + Bard = 1 << 12, + + /// + /// White mage (WHM). + /// + WhiteMage = 1 << 13, + + /// + /// Black mage (BLM). + /// + BlackMage = 1 << 14, + + /// + /// Arcanist (ACN). + /// + Arcanist = 1 << 15, + + /// + /// Summoner (SMN). + /// + Summoner = 1 << 16, + + /// + /// Scholar (SCH). + /// + Scholar = 1 << 17, + + /// + /// Rogue (ROG). + /// + Rogue = 1 << 18, + + /// + /// Ninja (NIN). + /// + Ninja = 1 << 19, + + /// + /// Machinist (MCH). + /// + Machinist = 1 << 20, + + /// + /// Dark Knight (DRK). + /// + DarkKnight = 1 << 21, + + /// + /// Astrologian (AST). + /// + Astrologian = 1 << 22, + + /// + /// Samurai (SAM). + /// + Samurai = 1 << 23, + + /// + /// Red mage (RDM). + /// + RedMage = 1 << 24, + + /// + /// Blue mage (BLM). + /// + BlueMage = 1 << 25, + + /// + /// Gunbreaker (GNB). + /// + Gunbreaker = 1 << 26, + + /// + /// Dancer (DNC). + /// + Dancer = 1 << 27, + } +} diff --git a/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs b/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs new file mode 100644 index 000000000..b899dd62f --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs @@ -0,0 +1,27 @@ +using System; + +using Dalamud.Data; +using Lumina.Excel.GeneratedSheets; + +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// Extensions for the enum. + /// + public static class JobFlagsExtensions + { + /// + /// Get the actual ClassJob from the in-game sheets for this JobFlags. + /// + /// A JobFlags enum member. + /// A DataManager to get the ClassJob from. + /// A ClassJob if found or null if not. + public static ClassJob ClassJob(this JobFlags job, DataManager data) + { + var result = Math.Log2((double)job); + return result % 1 == 0 + ? data.GetExcelSheet().GetRow((uint)result) + : null; + } + } +} diff --git a/Dalamud/Game/Internal/Gui/Structs/PartyFinderListing.cs b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs similarity index 87% rename from Dalamud/Game/Internal/Gui/Structs/PartyFinderListing.cs rename to Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs index b533a9741..c75748942 100644 --- a/Dalamud/Game/Internal/Gui/Structs/PartyFinderListing.cs +++ b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListing.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.Linq; using Dalamud.Data; +using Dalamud.Game.Gui.PartyFinder.Internal; using Dalamud.Game.Text.SeStringHandling; using Lumina.Excel.GeneratedSheets; -namespace Dalamud.Game.Internal.Gui.Structs +namespace Dalamud.Game.Gui.PartyFinder.Types { /// /// A single listing in party finder. @@ -31,7 +32,7 @@ namespace Dalamud.Game.Internal.Gui.Structs /// The interop listing data. /// The DataManager instance. /// The SeStringManager instance. - internal PartyFinderListing(PartyFinder.Listing listing, DataManager dataManager, SeStringManager seStringManager) + internal PartyFinderListing(PartyFinderPacketListing listing, DataManager dataManager, SeStringManager seStringManager) { this.objective = listing.Objective; this.conditions = listing.Conditions; @@ -48,7 +49,7 @@ namespace Dalamud.Game.Internal.Gui.Structs 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.Category = (Category)listing.Category; + this.Category = (DutyFinderCategory)listing.Category; this.RawDuty = listing.Duty; this.Duty = new Lazy(() => dataManager.GetExcelSheet().GetRow(listing.Duty)); this.DutyType = (DutyType)listing.DutyType; @@ -103,7 +104,7 @@ namespace Dalamud.Game.Internal.Gui.Structs /// /// Gets the Party Finder category this listing is listed under. /// - public Category Category { get; } + public DutyFinderCategory Category { get; } /// /// Gets the row ID of the duty this listing is for. May be 0 for non-duty listings. @@ -154,12 +155,12 @@ namespace Dalamud.Game.Internal.Gui.Structs /// /// Gets the objective of this listing. /// - public ObjectiveFlags Objective => (ObjectiveFlags)this.objective; + public DutyFinderObjectiveFlags Objective => (DutyFinderObjectiveFlags)this.objective; /// /// Gets the conditions of this listing. /// - public ConditionFlags Conditions => (ConditionFlags)this.conditions; + public DutyFinderConditionFlags Conditions => (DutyFinderConditionFlags)this.conditions; /// /// Gets the Duty Finder settings that will be used for this listing. @@ -169,13 +170,13 @@ namespace Dalamud.Game.Internal.Gui.Structs /// /// Gets the loot rules that will be used for this listing. /// - public LootRuleFlags LootRules => (LootRuleFlags)this.lootRules; + public DutyFinderLootRuleFlags LootRules => (DutyFinderLootRuleFlags)this.lootRules; /// /// Gets where this listing is searching. Note that this is also used for denoting alliance raid listings and one /// player per job. /// - public SearchAreaFlags SearchArea => (SearchAreaFlags)this.searchArea; + public DutyFinderSearchAreaFlags SearchArea => (DutyFinderSearchAreaFlags)this.searchArea; /// /// Gets a list of the class/job IDs that are currently present in the party. @@ -194,14 +195,14 @@ namespace Dalamud.Game.Internal.Gui.Structs /// /// The flag to check for. /// A value indicating whether the flag is present. - public bool this[ObjectiveFlags flag] => this.objective == 0 || (this.objective & (uint)flag) > 0; + public bool this[DutyFinderObjectiveFlags flag] => this.objective == 0 || (this.objective & (uint)flag) > 0; /// /// Check if the given flag is present. /// /// The flag to check for. /// A value indicating whether the flag is present. - public bool this[ConditionFlags flag] => this.conditions == 0 || (this.conditions & (uint)flag) > 0; + public bool this[DutyFinderConditionFlags flag] => this.conditions == 0 || (this.conditions & (uint)flag) > 0; /// /// Check if the given flag is present. @@ -215,14 +216,14 @@ namespace Dalamud.Game.Internal.Gui.Structs /// /// The flag to check for. /// A value indicating whether the flag is present. - public bool this[LootRuleFlags flag] => this.lootRules == 0 || (this.lootRules & (uint)flag) > 0; + public bool this[DutyFinderLootRuleFlags flag] => this.lootRules == 0 || (this.lootRules & (uint)flag) > 0; /// /// Check if the given flag is present. /// /// The flag to check for. /// A value indicating whether the flag is present. - public bool this[SearchAreaFlags flag] => this.searchArea == 0 || (this.searchArea & (uint)flag) > 0; + public bool this[DutyFinderSearchAreaFlags flag] => this.searchArea == 0 || (this.searchArea & (uint)flag) > 0; #endregion diff --git a/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListingEventArgs.cs b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListingEventArgs.cs new file mode 100644 index 000000000..ff6bd607d --- /dev/null +++ b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderListingEventArgs.cs @@ -0,0 +1,27 @@ +namespace Dalamud.Game.Gui.PartyFinder.Types +{ + /// + /// This class represents additional arguments passed by the game. + /// + public class PartyFinderListingEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The batch number. + internal PartyFinderListingEventArgs(int batchNumber) + { + this.BatchNumber = batchNumber; + } + + /// + /// Gets the batch number. + /// + public int BatchNumber { get; } + + /// + /// Gets or sets a value indicating whether the listing is visible. + /// + public bool Visible { get; set; } = true; + } +} diff --git a/Dalamud/Game/Internal/Gui/Structs/PartyFinderSlot.cs b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs similarity index 97% rename from Dalamud/Game/Internal/Gui/Structs/PartyFinderSlot.cs rename to Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs index 02b549842..d740c0c0a 100644 --- a/Dalamud/Game/Internal/Gui/Structs/PartyFinderSlot.cs +++ b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Dalamud.Game.Internal.Gui.Structs +namespace Dalamud.Game.Gui.PartyFinder.Types { /// /// A player slot in a Party Finder listing. diff --git a/Dalamud/Game/Internal/Gui/Toast/QuestToastOptions.cs b/Dalamud/Game/Gui/Toast/QuestToastOptions.cs old mode 100755 new mode 100644 similarity index 96% rename from Dalamud/Game/Internal/Gui/Toast/QuestToastOptions.cs rename to Dalamud/Game/Gui/Toast/QuestToastOptions.cs index 34fa674e7..11f09a523 --- a/Dalamud/Game/Internal/Gui/Toast/QuestToastOptions.cs +++ b/Dalamud/Game/Gui/Toast/QuestToastOptions.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui.Toast +namespace Dalamud.Game.Gui.Toast { /// /// This class represents options that can be used with the class for the quest toast variant. diff --git a/Dalamud/Game/Internal/Gui/Toast/QuestToastPosition.cs b/Dalamud/Game/Gui/Toast/QuestToastPosition.cs old mode 100755 new mode 100644 similarity index 92% rename from Dalamud/Game/Internal/Gui/Toast/QuestToastPosition.cs rename to Dalamud/Game/Gui/Toast/QuestToastPosition.cs index a6ea499b1..cc107ab6e --- a/Dalamud/Game/Internal/Gui/Toast/QuestToastPosition.cs +++ b/Dalamud/Game/Gui/Toast/QuestToastPosition.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui.Toast +namespace Dalamud.Game.Gui.Toast { /// /// The alignment of native quest toast windows. diff --git a/Dalamud/Game/Internal/Gui/Toast/ToastOptions.cs b/Dalamud/Game/Gui/Toast/ToastOptions.cs old mode 100755 new mode 100644 similarity index 92% rename from Dalamud/Game/Internal/Gui/Toast/ToastOptions.cs rename to Dalamud/Game/Gui/Toast/ToastOptions.cs index 5be757393..0939bb5bb --- a/Dalamud/Game/Internal/Gui/Toast/ToastOptions.cs +++ b/Dalamud/Game/Gui/Toast/ToastOptions.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui.Toast +namespace Dalamud.Game.Gui.Toast { /// /// This class represents options that can be used with the class. diff --git a/Dalamud/Game/Internal/Gui/Toast/ToastPosition.cs b/Dalamud/Game/Gui/Toast/ToastPosition.cs old mode 100755 new mode 100644 similarity index 89% rename from Dalamud/Game/Internal/Gui/Toast/ToastPosition.cs rename to Dalamud/Game/Gui/Toast/ToastPosition.cs index 4c01cb709..14f489711 --- a/Dalamud/Game/Internal/Gui/Toast/ToastPosition.cs +++ b/Dalamud/Game/Gui/Toast/ToastPosition.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui.Toast +namespace Dalamud.Game.Gui.Toast { /// /// The positioning of native toast windows. diff --git a/Dalamud/Game/Internal/Gui/Toast/ToastSpeed.cs b/Dalamud/Game/Gui/Toast/ToastSpeed.cs old mode 100755 new mode 100644 similarity index 90% rename from Dalamud/Game/Internal/Gui/Toast/ToastSpeed.cs rename to Dalamud/Game/Gui/Toast/ToastSpeed.cs index 620c65301..0f54df273 --- a/Dalamud/Game/Internal/Gui/Toast/ToastSpeed.cs +++ b/Dalamud/Game/Gui/Toast/ToastSpeed.cs @@ -1,4 +1,4 @@ -namespace Dalamud.Game.Internal.Gui.Toast +namespace Dalamud.Game.Gui.Toast { /// /// The speed at which native toast windows will persist. diff --git a/Dalamud/Game/Internal/Gui/ToastGui.cs b/Dalamud/Game/Gui/ToastGui.cs old mode 100755 new mode 100644 similarity index 99% rename from Dalamud/Game/Internal/Gui/ToastGui.cs rename to Dalamud/Game/Gui/ToastGui.cs index 4c1ce497f..c16066a09 --- a/Dalamud/Game/Internal/Gui/ToastGui.cs +++ b/Dalamud/Game/Gui/ToastGui.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using System.Text; -using Dalamud.Game.Internal.Gui.Toast; +using Dalamud.Game.Gui.Toast; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Hooking; -namespace Dalamud.Game.Internal.Gui +namespace Dalamud.Game.Gui { /// /// This class facilitates interacting with and creating native toast windows. diff --git a/Dalamud/Game/Internal/Gui/ToastGuiAddressResolver.cs b/Dalamud/Game/Gui/ToastGuiAddressResolver.cs old mode 100755 new mode 100644 similarity index 95% rename from Dalamud/Game/Internal/Gui/ToastGuiAddressResolver.cs rename to Dalamud/Game/Gui/ToastGuiAddressResolver.cs index 93b8eba04..adf5e3190 --- a/Dalamud/Game/Internal/Gui/ToastGuiAddressResolver.cs +++ b/Dalamud/Game/Gui/ToastGuiAddressResolver.cs @@ -1,6 +1,8 @@ using System; -namespace Dalamud.Game.Internal.Gui +using Dalamud.Game.Internal; + +namespace Dalamud.Game.Gui { /// /// An address resolver for the class. diff --git a/Dalamud/Game/Internal/AntiDebug.cs b/Dalamud/Game/Internal/AntiDebug.cs index 57c7fdeb4..59e2a1df4 100644 --- a/Dalamud/Game/Internal/AntiDebug.cs +++ b/Dalamud/Game/Internal/AntiDebug.cs @@ -8,7 +8,7 @@ namespace Dalamud.Game.Internal /// /// This class disables anti-debug functionality in the game client. /// - public sealed partial class AntiDebug + internal sealed partial class AntiDebug { private readonly byte[] nop = new byte[] { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 }; private byte[] original; @@ -79,7 +79,7 @@ namespace Dalamud.Game.Internal /// /// Implementing IDisposable. /// - public sealed partial class AntiDebug : IDisposable + internal sealed partial class AntiDebug : IDisposable { private bool disposed = false; diff --git a/Dalamud/Game/Addon/DalamudSystemMenu.cs b/Dalamud/Game/Internal/DalamudSystemMenu.cs similarity index 99% rename from Dalamud/Game/Addon/DalamudSystemMenu.cs rename to Dalamud/Game/Internal/DalamudSystemMenu.cs index e735b6154..673bcb55b 100644 --- a/Dalamud/Game/Addon/DalamudSystemMenu.cs +++ b/Dalamud/Game/Internal/DalamudSystemMenu.cs @@ -8,7 +8,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; -namespace Dalamud.Game.Addon +namespace Dalamud.Game.Internal { /// /// This class implements in-game Dalamud options in the in-game System menu. diff --git a/Dalamud/Game/Internal/Gui/Structs/Addon.cs b/Dalamud/Game/Internal/Gui/Structs/Addon.cs deleted file mode 100644 index 57595a2c7..000000000 --- a/Dalamud/Game/Internal/Gui/Structs/Addon.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Runtime.InteropServices; - -using FFXIVClientStructs.FFXIV.Component.GUI; - -namespace Dalamud.Game.Internal.Gui.Structs -{ - /// - /// Native memory representation of an FFXIV UI addon. - /// - [StructLayout(LayoutKind.Explicit)] - public struct Addon - { - /// - /// The name of the addon. - /// - [FieldOffset(AddonOffsets.Name)] - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] - public string Name; - - /// - /// Various flags that can be set on the addon. - /// - /// - /// This is a bitfield. - /// - [FieldOffset(AddonOffsets.Flags)] - public byte Flags; - - /// - /// The X position of the addon on screen. - /// - [FieldOffset(AddonOffsets.X)] - public short X; - - /// - /// The Y position of the addon on screen. - /// - [FieldOffset(AddonOffsets.Y)] - public short Y; - - /// - /// The scale of the addon. - /// - [FieldOffset(AddonOffsets.Scale)] - public float Scale; - - /// - /// The root node of the addon's node tree. - /// - [FieldOffset(AddonOffsets.RootNode)] - public unsafe AtkResNode* RootNode; - } - - /// - /// Memory offsets for the type. - /// - public static class AddonOffsets - { - public const int Name = 0x8; - public const int RootNode = 0xC8; - public const int Flags = 0x182; - public const int X = 0x1BC; - public const int Y = 0x1BE; - public const int Scale = 0x1AC; - } -} diff --git a/Dalamud/Game/Internal/Gui/Structs/PartyFinder.cs b/Dalamud/Game/Internal/Gui/Structs/PartyFinder.cs deleted file mode 100755 index 8fe3204b0..000000000 --- a/Dalamud/Game/Internal/Gui/Structs/PartyFinder.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System.Linq; -using System.Runtime.InteropServices; - -namespace Dalamud.Game.Internal.Gui.Structs -{ - /// - /// PartyFinder related network structs and static constants. - /// - internal static class PartyFinder - { - /// - /// The structure of the PartyFinder packet. - /// - [StructLayout(LayoutKind.Sequential)] - internal readonly struct Packet - { - internal readonly int BatchNumber; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - private readonly byte[] padding1; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - internal readonly Listing[] Listings; - } - - /// - /// The structure of an individual listing within a packet. - /// - [StructLayout(LayoutKind.Sequential)] - internal readonly struct Listing - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - private readonly byte[] header1; - - internal readonly uint Id; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - private readonly byte[] header2; - - internal readonly uint ContentIdLower; - private readonly ushort unknownShort1; - private readonly ushort unknownShort2; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - private readonly byte[] header3; - - internal readonly byte Category; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - private readonly byte[] header4; - - internal readonly ushort Duty; - internal readonly byte DutyType; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - private readonly byte[] header5; - - internal readonly ushort World; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - private readonly byte[] header6; - - internal readonly byte Objective; - internal readonly byte BeginnersWelcome; - internal readonly byte Conditions; - internal readonly byte DutyFinderSettings; - internal readonly byte LootRules; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - private readonly byte[] header7; // all zero in every pf I've examined - - private readonly uint lastPatchHotfixTimestamp; // last time the servers were restarted? - internal readonly ushort SecondsRemaining; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - private readonly byte[] header8; // 00 00 01 00 00 00 in every pf I've examined - - internal readonly ushort MinimumItemLevel; - internal readonly ushort HomeWorld; - internal readonly ushort CurrentWorld; - - private readonly byte header9; - - internal readonly byte NumSlots; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - private readonly byte[] header10; - - internal readonly byte SearchArea; - - private readonly byte header11; - - internal readonly byte NumParties; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - private readonly byte[] header12; // 00 00 00 always. maybe numParties is a u32? - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - internal readonly uint[] Slots; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - internal readonly byte[] JobsPresent; - - // Note that ByValTStr will not work here because the strings are UTF-8 and there's only a CharSet for UTF-16 in C#. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - internal readonly byte[] Name; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)] - internal readonly byte[] Description; - - internal bool IsNull() - { - // a valid party finder must have at least one slot set - return this.Slots.All(slot => slot == 0); - } - } - - /// - /// PartyFinder packet constants. - /// - public static class PacketInfo - { - /// - /// The size of the PartyFinder packet. - /// - public static readonly int PacketSize = Marshal.SizeOf(); - } - } -} diff --git a/Dalamud/Game/Internal/Gui/Structs/PartyFinderTypes.cs b/Dalamud/Game/Internal/Gui/Structs/PartyFinderTypes.cs deleted file mode 100644 index 7482b3ba3..000000000 --- a/Dalamud/Game/Internal/Gui/Structs/PartyFinderTypes.cs +++ /dev/null @@ -1,397 +0,0 @@ -using System; - -using Dalamud.Data; -using Lumina.Excel.GeneratedSheets; - -namespace Dalamud.Game.Internal.Gui.Structs -{ - /// - /// Search area flags for the class. - /// - [Flags] - public enum SearchAreaFlags : uint - { - /// - /// Datacenter. - /// - DataCentre = 1 << 0, - - /// - /// Private. - /// - Private = 1 << 1, - - /// - /// Alliance raid. - /// - AllianceRaid = 1 << 2, - - /// - /// World. - /// - World = 1 << 3, - - /// - /// One player per job. - /// - OnePlayerPerJob = 1 << 5, - } - - /// - /// Job flags for the class. - /// - [Flags] - public enum JobFlags - { - /// - /// Gladiator (GLD). - /// - Gladiator = 1 << 1, - - /// - /// Pugilist (PGL). - /// - Pugilist = 1 << 2, - - /// - /// Marauder (MRD). - /// - Marauder = 1 << 3, - - /// - /// Lancer (LNC). - /// - Lancer = 1 << 4, - - /// - /// Archer (ARC). - /// - Archer = 1 << 5, - - /// - /// Conjurer (CNJ). - /// - Conjurer = 1 << 6, - - /// - /// Thaumaturge (THM). - /// - Thaumaturge = 1 << 7, - - /// - /// Paladin (PLD). - /// - Paladin = 1 << 8, - - /// - /// Monk (MNK). - /// - Monk = 1 << 9, - - /// - /// Warrior (WAR). - /// - Warrior = 1 << 10, - - /// - /// Dragoon (DRG). - /// - Dragoon = 1 << 11, - - /// - /// Bard (BRD). - /// - Bard = 1 << 12, - - /// - /// White mage (WHM). - /// - WhiteMage = 1 << 13, - - /// - /// Black mage (BLM). - /// - BlackMage = 1 << 14, - - /// - /// Arcanist (ACN). - /// - Arcanist = 1 << 15, - - /// - /// Summoner (SMN). - /// - Summoner = 1 << 16, - - /// - /// Scholar (SCH). - /// - Scholar = 1 << 17, - - /// - /// Rogue (ROG). - /// - Rogue = 1 << 18, - - /// - /// Ninja (NIN). - /// - Ninja = 1 << 19, - - /// - /// Machinist (MCH). - /// - Machinist = 1 << 20, - - /// - /// Dark Knight (DRK). - /// - DarkKnight = 1 << 21, - - /// - /// Astrologian (AST). - /// - Astrologian = 1 << 22, - - /// - /// Samurai (SAM). - /// - Samurai = 1 << 23, - - /// - /// Red mage (RDM). - /// - RedMage = 1 << 24, - - /// - /// Blue mage (BLM). - /// - BlueMage = 1 << 25, - - /// - /// Gunbreaker (GNB). - /// - Gunbreaker = 1 << 26, - - /// - /// Dancer (DNC). - /// - Dancer = 1 << 27, - } - - /// - /// Objective flags for the class. - /// - [Flags] - public enum ObjectiveFlags : uint - { - /// - /// No objective. - /// - None = 0, - - /// - /// The duty completion objective. - /// - DutyCompletion = 1, - - /// - /// The practice objective. - /// - Practice = 2, - - /// - /// The loot objective. - /// - Loot = 4, - } - - /// - /// Condition flags for the class. - /// - [Flags] - public enum ConditionFlags : uint - { - /// - /// No duty condition. - /// - None = 1, - - /// - /// The duty complete condition. - /// - DutyComplete = 2, - - /// - /// The duty incomplete condition. - /// - DutyIncomplete = 4, - } - - /// - /// Duty finder settings flags for the class. - /// - [Flags] - public enum DutyFinderSettingsFlags : uint - { - /// - /// No duty finder settings. - /// - None = 0, - - /// - /// The undersized party setting. - /// - UndersizedParty = 1 << 0, - - /// - /// The minimum item level setting. - /// - MinimumItemLevel = 1 << 1, - - /// - /// The silence echo setting. - /// - SilenceEcho = 1 << 2, - } - - /// - /// Loot rule flags for the class. - /// - [Flags] - public enum LootRuleFlags : uint - { - /// - /// No loot rules. - /// - None = 0, - - /// - /// The greed only rule. - /// - GreedOnly = 1, - - /// - /// The lootmaster rule. - /// - Lootmaster = 2, - } - - /// - /// Category flags for the class. - /// - public enum Category - { - /// - /// The duty category. - /// - Duty = 0, - - /// - /// The quest battle category. - /// - QuestBattles = 1 << 0, - - /// - /// The fate category. - /// - Fates = 1 << 1, - - /// - /// The treasure hunt category. - /// - TreasureHunt = 1 << 2, - - /// - /// The hunt category. - /// - TheHunt = 1 << 3, - - /// - /// The gathering forays category. - /// - GatheringForays = 1 << 4, - - /// - /// The deep dungeons category. - /// - DeepDungeons = 1 << 5, - - /// - /// The adventuring forays category. - /// - AdventuringForays = 1 << 6, - } - - /// - /// Duty type flags for the class. - /// - public enum DutyType - { - /// - /// No duty type. - /// - Other = 0, - - /// - /// The roulette duty type. - /// - Roulette = 1 << 0, - - /// - /// The normal duty type. - /// - Normal = 1 << 1, - } - - /// - /// Extensions for the enum. - /// - public static class JobFlagsExt - { - /// - /// Get the actual ClassJob from the in-game sheets for this JobFlags. - /// - /// A JobFlags enum member. - /// A DataManager to get the ClassJob from. - /// A ClassJob if found or null if not. - public static ClassJob ClassJob(this JobFlags job, DataManager data) - { - var jobs = data.GetExcelSheet(); - - uint? row = job switch - { - JobFlags.Gladiator => 1, - JobFlags.Pugilist => 2, - JobFlags.Marauder => 3, - JobFlags.Lancer => 4, - JobFlags.Archer => 5, - JobFlags.Conjurer => 6, - JobFlags.Thaumaturge => 7, - JobFlags.Paladin => 19, - JobFlags.Monk => 20, - JobFlags.Warrior => 21, - JobFlags.Dragoon => 22, - JobFlags.Bard => 23, - JobFlags.WhiteMage => 24, - JobFlags.BlackMage => 25, - JobFlags.Arcanist => 26, - JobFlags.Summoner => 27, - JobFlags.Scholar => 28, - JobFlags.Rogue => 29, - JobFlags.Ninja => 30, - JobFlags.Machinist => 31, - JobFlags.DarkKnight => 32, - JobFlags.Astrologian => 33, - JobFlags.Samurai => 34, - JobFlags.RedMage => 35, - JobFlags.BlueMage => 36, - JobFlags.Gunbreaker => 37, - JobFlags.Dancer => 38, - _ => null, - }; - - return row == null ? null : jobs.GetRow((uint)row); - } - } -} diff --git a/Dalamud/Game/Internal/Resource/ResourceManager.cs b/Dalamud/Game/Internal/Resource/ResourceManager.cs deleted file mode 100644 index 7e3c2b045..000000000 --- a/Dalamud/Game/Internal/Resource/ResourceManager.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; - -using Dalamud.Hooking; -using Serilog; - -namespace Dalamud.Game.Internal.File -{ - /// - /// This class facilitates modifying how the game loads resources from disk. - /// - public class ResourceManager - { - private readonly Dalamud dalamud; - private readonly ResourceManagerAddressResolver address; - private readonly Hook getResourceAsyncHook; - private readonly Hook getResourceSyncHook; - - private Dictionary resourceHookMap = new(); - - /// - /// Initializes a new instance of the class. - /// - /// The Dalamud instance. - /// The SigScanner instance. - internal ResourceManager(Dalamud dalamud, SigScanner scanner) - { - this.dalamud = dalamud; - this.address = new ResourceManagerAddressResolver(); - this.address.Setup(scanner); - - Log.Verbose("===== R E S O U R C E M A N A G E R ====="); - Log.Verbose("GetResourceAsync address {GetResourceAsync}", this.address.GetResourceAsync); - Log.Verbose("GetResourceSync address {GetResourceSync}", this.address.GetResourceSync); - - this.getResourceAsyncHook = new Hook(this.address.GetResourceAsync, this.GetResourceAsyncDetour); - this.getResourceSyncHook = new Hook(this.address.GetResourceSync, this.GetResourceSyncDetour); - } - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - private delegate IntPtr GetResourceAsyncDelegate(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr pathPtr, IntPtr a6, byte a7); - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - private delegate IntPtr GetResourceSyncDelegate(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr pathPtr, IntPtr a6); - - /// - /// Check if a filepath has any invalid characters. - /// - /// The filepath to check. - /// A value indicating whether the filepath is safe to use. - public static bool FilePathHasInvalidChars(string path) - { - return !string.IsNullOrEmpty(path) && path.IndexOfAny(Path.GetInvalidPathChars()) >= 0; - } - - /// - /// Enable this module. - /// - public void Enable() - { - this.getResourceAsyncHook.Enable(); - this.getResourceSyncHook.Enable(); - } - - /// - /// Dispose of managed and unmanaged resources. - /// - public void Dispose() - { - this.getResourceAsyncHook.Dispose(); - this.getResourceSyncHook.Dispose(); - } - - private IntPtr GetResourceAsyncDetour(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr pathPtr, IntPtr a6, byte a7) - { - try - { - var path = Marshal.PtrToStringAnsi(pathPtr); - - var resourceHandle = this.getResourceAsyncHook.Original(manager, a2, a3, a4, IntPtr.Zero, a6, a7); - // var resourceHandle = IntPtr.Zero; - - Log.Verbose("GetResourceAsync CALL - this:{0} a2:{1} a3:{2} a4:{3} a5:{4} a6:{5} a7:{6} => RET:{7}", manager, a2, a3, a4, pathPtr, a6, a7, resourceHandle); - - Log.Verbose($"->{path}"); - - this.HandleGetResourceHookAcquire(resourceHandle, path); - - return resourceHandle; - } - catch (Exception ex) - { - Log.Error(ex, "Exception on ReadResourceAsync hook."); - - return this.getResourceAsyncHook.Original(manager, a2, a3, a4, pathPtr, a6, a7); - } - } - - private IntPtr GetResourceSyncDetour(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr pathPtr, IntPtr a6) - { - try - { - var resourceHandle = this.getResourceSyncHook.Original(manager, a2, a3, a4, pathPtr, a6); - - Log.Verbose("GetResourceSync CALL - this:{0} a2:{1} a3:{2} a4:{3} a5:{4} a6:{5} => RET:{6}", manager, a2, a3, a4, pathPtr, a6, resourceHandle); - - var path = Marshal.PtrToStringAnsi(pathPtr); - - Log.Verbose($"->{path}"); - - this.HandleGetResourceHookAcquire(resourceHandle, path); - - return resourceHandle; - } - catch (Exception ex) - { - Log.Error(ex, "Exception on ReadResourceSync hook."); - - return this.getResourceSyncHook.Original(manager, a2, a3, a4, pathPtr, a6); - } - } - - private void HandleGetResourceHookAcquire(IntPtr handlePtr, string path) - { - if (FilePathHasInvalidChars(path)) - return; - - if (this.resourceHookMap.ContainsKey(handlePtr)) - { - Log.Verbose($"-> Handle {handlePtr.ToInt64():X}({path}) was cached!"); - return; - } - - var hookInfo = new ResourceHandleHookInfo - { - Path = path, - }; - - var hookPath = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "ResourceHook", path); - - if (System.IO.File.Exists(hookPath)) - { - hookInfo.DetourFile = new FileStream(hookPath, FileMode.Open); - Log.Verbose("-> Added resource hook detour at {0}", hookPath); - } - - this.resourceHookMap.Add(handlePtr, hookInfo); - } - - private class ResourceHandleHookInfo - { - public string Path { get; set; } - - public Stream DetourFile { get; set; } - } - } -} diff --git a/Dalamud/Game/Internal/Resource/ResourceManagerAddressResolver.cs b/Dalamud/Game/Internal/Resource/ResourceManagerAddressResolver.cs deleted file mode 100644 index b92ea8209..000000000 --- a/Dalamud/Game/Internal/Resource/ResourceManagerAddressResolver.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -namespace Dalamud.Game.Internal.File -{ - /// - /// The address resolver for the class. - /// - internal class ResourceManagerAddressResolver : BaseAddressResolver - { - /// - /// Gets the address of the GetResourceAsync method. - /// - public IntPtr GetResourceAsync { get; private set; } - - /// - /// Gets the address of the GetResourceSync method. - /// - public IntPtr GetResourceSync { get; private set; } - - /// - protected override void Setup64Bit(SigScanner sig) - { - this.GetResourceAsync = sig.ScanText("48 89 5C 24 08 48 89 54 24 10 57 48 83 EC 20 B8 03 00 00 00 48 8B F9 86 82 A1 00 00 00 48 8B 5C 24 38 B8 01 00 00 00 87 83 90 00 00 00 85 C0 74"); - this.GetResourceSync = sig.ScanText("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 54 41 55 41 56 41 57 48 83 EC 30 48 8B F9 49 8B E9 48 83 C1 30 4D 8B F0 4C 8B EA FF 15 CE F6"); - // ReadResourceSync = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05"); - } - } -} diff --git a/Dalamud/Game/Internal/Libc/LibcFunction.cs b/Dalamud/Game/Libc/LibcFunction.cs similarity index 98% rename from Dalamud/Game/Internal/Libc/LibcFunction.cs rename to Dalamud/Game/Libc/LibcFunction.cs index 33990caae..cfab061c3 100644 --- a/Dalamud/Game/Internal/Libc/LibcFunction.cs +++ b/Dalamud/Game/Libc/LibcFunction.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.InteropServices; using System.Text; -namespace Dalamud.Game.Internal.Libc +namespace Dalamud.Game.Libc { /// /// This class handles creating cstrings utilizing native game methods. diff --git a/Dalamud/Game/Internal/Libc/LibcFunctionAddressResolver.cs b/Dalamud/Game/Libc/LibcFunctionAddressResolver.cs similarity index 94% rename from Dalamud/Game/Internal/Libc/LibcFunctionAddressResolver.cs rename to Dalamud/Game/Libc/LibcFunctionAddressResolver.cs index b96a37493..4d30a1e74 100644 --- a/Dalamud/Game/Internal/Libc/LibcFunctionAddressResolver.cs +++ b/Dalamud/Game/Libc/LibcFunctionAddressResolver.cs @@ -1,6 +1,8 @@ using System; -namespace Dalamud.Game.Internal.Libc +using Dalamud.Game.Internal; + +namespace Dalamud.Game.Libc { /// /// The address resolver for the class. diff --git a/Dalamud/Game/Internal/Libc/OwnedStdString.cs b/Dalamud/Game/Libc/OwnedStdString.cs similarity index 98% rename from Dalamud/Game/Internal/Libc/OwnedStdString.cs rename to Dalamud/Game/Libc/OwnedStdString.cs index 7969e4947..1939e068e 100644 --- a/Dalamud/Game/Internal/Libc/OwnedStdString.cs +++ b/Dalamud/Game/Libc/OwnedStdString.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace Dalamud.Game.Internal.Libc +namespace Dalamud.Game.Libc { /// /// An address wrapper around the class. diff --git a/Dalamud/Game/Internal/Libc/StdString.cs b/Dalamud/Game/Libc/StdString.cs similarity index 98% rename from Dalamud/Game/Internal/Libc/StdString.cs rename to Dalamud/Game/Libc/StdString.cs index 9b627c88d..4d4478687 100644 --- a/Dalamud/Game/Internal/Libc/StdString.cs +++ b/Dalamud/Game/Libc/StdString.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.InteropServices; using System.Text; -namespace Dalamud.Game.Internal.Libc +namespace Dalamud.Game.Libc { /// /// Interation with std::string. diff --git a/Dalamud/Game/Internal/Network/GameNetwork.cs b/Dalamud/Game/Network/GameNetwork.cs similarity index 98% rename from Dalamud/Game/Internal/Network/GameNetwork.cs rename to Dalamud/Game/Network/GameNetwork.cs index dff3ac535..0b982b2b0 100644 --- a/Dalamud/Game/Internal/Network/GameNetwork.cs +++ b/Dalamud/Game/Network/GameNetwork.cs @@ -6,18 +6,13 @@ using Dalamud.Game.Network; using Dalamud.Hooking; using Serilog; -namespace Dalamud.Game.Internal.Network +namespace Dalamud.Game.Network { /// /// This class handles interacting with game network events. /// public sealed class GameNetwork : IDisposable { - /// - /// Event that is called when a network message is sent/received. - /// - public OnNetworkMessageDelegate OnNetworkMessage; - private readonly GameNetworkAddressResolver address; private readonly Hook processZonePacketDownHook; private readonly Hook processZonePacketUpHook; @@ -58,6 +53,11 @@ namespace Dalamud.Game.Internal.Network [UnmanagedFunctionPointer(CallingConvention.ThisCall)] private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4); + /// + /// Event that is called when a network message is sent/received. + /// + public event OnNetworkMessageDelegate OnNetworkMessage; + /// /// Enable this module. /// diff --git a/Dalamud/Game/Internal/Network/GameNetworkAddressResolver.cs b/Dalamud/Game/Network/GameNetworkAddressResolver.cs similarity index 95% rename from Dalamud/Game/Internal/Network/GameNetworkAddressResolver.cs rename to Dalamud/Game/Network/GameNetworkAddressResolver.cs index 9c5eb00fc..130986197 100644 --- a/Dalamud/Game/Internal/Network/GameNetworkAddressResolver.cs +++ b/Dalamud/Game/Network/GameNetworkAddressResolver.cs @@ -1,6 +1,8 @@ using System; -namespace Dalamud.Game.Internal.Network +using Dalamud.Game.Internal; + +namespace Dalamud.Game.Network { /// /// The address resolver for the class. diff --git a/Dalamud/Game/Position3.cs b/Dalamud/Game/Position3.cs index 3812376df..ed477d511 100644 --- a/Dalamud/Game/Position3.cs +++ b/Dalamud/Game/Position3.cs @@ -23,6 +23,19 @@ namespace Dalamud.Game /// public float Y; + /// + /// Initializes a new instance of the struct. + /// + /// The X position. + /// The Z position. + /// The Y position. + public Position3(float x, float z, float y) + { + this.X = x; + this.Z = z; + this.Y = y; + } + /// /// Convert this Position3 to a System.Numerics.Vector3. /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payload.cs b/Dalamud/Game/Text/SeStringHandling/Payload.cs index ebf689646..3ace4ebf1 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payload.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using Dalamud.Data; @@ -21,15 +22,15 @@ namespace Dalamud.Game.Text.SeStringHandling /// public abstract partial class Payload { - /// - /// The Lumina instance to use for any necessary data lookups. - /// - public DataManager DataResolver; - - // private for now, since subclasses shouldn't interact with this + // private for now, since subclasses shouldn't interact with this. // To force-invalidate it, Dirty can be set to true private byte[] encodedData; + /// + /// Gets or sets the Lumina instance to use for any necessary data lookups. + /// + public DataManager DataResolver { get; set; } + /// /// Gets the type of this payload. /// @@ -233,11 +234,13 @@ namespace Dalamud.Game.Text.SeStringHandling /// /// The start byte of a payload. /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "This is prefered.")] protected const byte START_BYTE = 0x02; /// /// The end byte of a payload. /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "This is prefered.")] protected const byte END_BYTE = 0x03; /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs index e526d9c70..04bcd1029 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs @@ -19,17 +19,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads this.Icon = icon; } - /// - /// Initializes a new instance of the class. - /// Create a Icon payload for the specified icon. - /// - /// Index of the icon. - [Obsolete("IconPayload(uint) is deprecated, please use IconPayload(BitmapFontIcon).")] - public IconPayload(uint iconIndex) - : this((BitmapFontIcon)iconIndex) - { - } - /// /// Initializes a new instance of the class. /// Create a Icon payload for the specified icon. @@ -41,12 +30,6 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads /// public override PayloadType Type => PayloadType.Icon; - /// - /// Gets the index of the icon. - /// - [Obsolete("Use IconPayload.Icon")] - public uint IconIndex => (uint)this.Icon; - /// /// Gets or sets the icon the payload represents. /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs index fbcb447c7..a6e6c2e49 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs @@ -222,7 +222,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads var c = scale / 100.0f; var scaledPos = pos * c / 1000.0f; - return ((41.0f / c) * ((scaledPos + 1024.0f) / 2048.0f)) + 1.0f; + return (41.0f / c * ((scaledPos + 1024.0f) / 2048.0f)) + 1.0f; } // Created as the inverse of ConvertRawPositionToMapCoordinate(), since no one seemed to have a version of that @@ -230,7 +230,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads { var c = scale / 100.0f; - var scaledPos = ((((pos - 1.0f) * c / 41.0f) * 2048.0f) - 1024.0f) / c; + var scaledPos = (((pos - 1.0f) * c / 41.0f * 2048.0f) - 1024.0f) / c; scaledPos *= 1000.0f; return (int)scaledPos; diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs index ae3754839..0d80f015d 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs @@ -84,12 +84,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads /// public override int GetHashCode() { - // Generated random values. - var hashCode = 1216194372; - hashCode = (hashCode * -1521134295) + this.Type.GetHashCode(); - hashCode = (hashCode * -1521134295) + this.chunkType.GetHashCode(); - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.data); - return hashCode; + return HashCode.Combine(this.Type, this.chunkType, this.data); } /// diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/TextPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/TextPayload.cs index 9d05fb440..d12bdd3a7 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/TextPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/TextPayload.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -67,7 +68,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads // this may change or go away if (string.IsNullOrEmpty(this.text)) { - return new byte[] { }; + return Array.Empty(); } return Encoding.UTF8.GetBytes(this.text); diff --git a/Dalamud/Game/Text/XivChatType.cs b/Dalamud/Game/Text/XivChatType.cs index 9658078f0..d89fc5f0c 100644 --- a/Dalamud/Game/Text/XivChatType.cs +++ b/Dalamud/Game/Text/XivChatType.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; - namespace Dalamud.Game.Text { /// @@ -237,77 +234,4 @@ namespace Dalamud.Game.Text [XivChatTypeInfo("Crossworld Linkshell 8", "cw8", 0xFF1E90FF)] CrossLinkShell8 = 107, } - - /// - /// Extension methods for the type. - /// - public static class XivChatTypeExtensions - { - /// - /// Get the InfoAttribute associated with this chat type. - /// - /// The chat type. - /// The info attribute. - public static XivChatTypeInfoAttribute GetDetails(this XivChatType chatType) - { - return chatType.GetAttribute(); - } - } - - /// - /// Storage for relevant information associated with the chat type. - /// - public class XivChatTypeInfoAttribute : Attribute - { - /// - /// Initializes a new instance of the class. - /// - /// The fancy name. - /// The name slug. - /// The default color. - internal XivChatTypeInfoAttribute(string fancyName, string slug, uint defaultColor) - { - this.FancyName = fancyName; - this.Slug = slug; - this.DefaultColor = defaultColor; - } - - /// - /// Gets the "fancy" name of the type. - /// - public string FancyName { get; } - - /// - /// Gets the type name slug or short-form. - /// - public string Slug { get; } - - /// - /// Gets the type default color. - /// - public uint DefaultColor { get; } - } - - /// - /// Extension methods for enums. - /// - public static class EnumExtensions - { - /// - /// Gets an attribute on an enum. - /// - /// The type of attribute to get. - /// The enum value that has an attached attribute. - /// The attached attribute, if any. - public static TAttribute GetAttribute(this Enum value) - where TAttribute : Attribute - { - var type = value.GetType(); - var name = Enum.GetName(type, value); - return type.GetField(name) // I prefer to get attributes this way - .GetCustomAttributes(false) - .OfType() - .SingleOrDefault(); - } - } } diff --git a/Dalamud/Game/Text/XivChatTypeExtensions.cs b/Dalamud/Game/Text/XivChatTypeExtensions.cs new file mode 100644 index 000000000..a26687c47 --- /dev/null +++ b/Dalamud/Game/Text/XivChatTypeExtensions.cs @@ -0,0 +1,20 @@ +using Dalamud.Utility; + +namespace Dalamud.Game.Text +{ + /// + /// Extension methods for the type. + /// + public static class XivChatTypeExtensions + { + /// + /// Get the InfoAttribute associated with this chat type. + /// + /// The chat type. + /// The info attribute. + public static XivChatTypeInfoAttribute GetDetails(this XivChatType chatType) + { + return chatType.GetAttribute(); + } + } +} diff --git a/Dalamud/Game/Text/XivChatTypeInfoAttribute.cs b/Dalamud/Game/Text/XivChatTypeInfoAttribute.cs new file mode 100644 index 000000000..e549ac761 --- /dev/null +++ b/Dalamud/Game/Text/XivChatTypeInfoAttribute.cs @@ -0,0 +1,39 @@ +using System; + +namespace Dalamud.Game.Text +{ + /// + /// Storage for relevant information associated with the chat type. + /// + [AttributeUsage(AttributeTargets.Field)] + public class XivChatTypeInfoAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// The fancy name. + /// The name slug. + /// The default color. + internal XivChatTypeInfoAttribute(string fancyName, string slug, uint defaultColor) + { + this.FancyName = fancyName; + this.Slug = slug; + this.DefaultColor = defaultColor; + } + + /// + /// Gets the "fancy" name of the type. + /// + public string FancyName { get; } + + /// + /// Gets the type name slug or short-form. + /// + public string Slug { get; } + + /// + /// Gets the type default color. + /// + public uint DefaultColor { get; } + } +} diff --git a/Dalamud/Hooking/Internal/HookInfo.cs b/Dalamud/Hooking/Internal/HookInfo.cs index c2850b806..73db6864b 100644 --- a/Dalamud/Hooking/Internal/HookInfo.cs +++ b/Dalamud/Hooking/Internal/HookInfo.cs @@ -67,7 +67,7 @@ namespace Dalamud.Hooking.Internal internal Delegate Delegate { get; } /// - /// Gets the hooked assembly. + /// Gets the assembly implementing the hook. /// internal Assembly Assembly { get; } } diff --git a/Dalamud/Interface/FontAwesomeExtensions.cs b/Dalamud/Interface/FontAwesomeExtensions.cs new file mode 100644 index 000000000..734ec128d --- /dev/null +++ b/Dalamud/Interface/FontAwesomeExtensions.cs @@ -0,0 +1,30 @@ +// Font-Awesome - Version 5.0.9 + +namespace Dalamud.Interface +{ + /// + /// Extension methods for . + /// + public static class FontAwesomeExtensions + { + /// + /// Convert the FontAwesomeIcon to a type. + /// + /// The icon to convert. + /// The converted icon. + public static char ToIconChar(this FontAwesomeIcon icon) + { + return (char)icon; + } + + /// + /// Conver the FontAwesomeIcon to a type. + /// + /// The icon to convert. + /// The converted icon. + public static string ToIconString(this FontAwesomeIcon icon) + { + return string.Empty + (char)icon; + } + } +} diff --git a/Dalamud/Interface/FontAwesomeIcon.cs b/Dalamud/Interface/FontAwesomeIcon.cs index a8b93e9e7..c2267766c 100644 --- a/Dalamud/Interface/FontAwesomeIcon.cs +++ b/Dalamud/Interface/FontAwesomeIcon.cs @@ -7047,30 +7047,4 @@ namespace Dalamud.Interface /// Zhihu = 0xF63F, } - - /// - /// Extension methods for . - /// - public static class FontAwesomeExtensions - { - /// - /// Convert the FontAwesomeIcon to a type. - /// - /// The icon to convert. - /// The converted icon. - public static char ToIconChar(this FontAwesomeIcon icon) - { - return (char)icon; - } - - /// - /// Conver the FontAwesomeIcon to a type. - /// - /// The icon to convert. - /// The converted icon. - public static string ToIconString(this FontAwesomeIcon icon) - { - return string.Empty + (char)icon; - } - } } diff --git a/Dalamud/Interface/Internal/DalamudCommands.cs b/Dalamud/Interface/Internal/DalamudCommands.cs index 6e0f5e7a6..1a4f64815 100644 --- a/Dalamud/Interface/Internal/DalamudCommands.cs +++ b/Dalamud/Interface/Internal/DalamudCommands.cs @@ -242,7 +242,7 @@ namespace Dalamud.Interface.Internal if (string.IsNullOrEmpty(arguments)) this.dalamud.DalamudUi.ToggleDataWindow(); else - this.dalamud.DalamudUi.ToggleDataWindow(arguments); + this.dalamud.DalamudUi.OpenDataWindow(arguments); } private void OnOpenLog(string command, string arguments) diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 630f01296..3afcbe331 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -9,6 +9,7 @@ using Dalamud.Interface.Windowing; using Dalamud.Logging; using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal; +using Dalamud.Utility; using ImGuiNET; using Serilog.Events; diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 825495dd1..1976ac336 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -8,9 +8,11 @@ using System.Threading; using Dalamud.Game; using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.GamePad; using Dalamud.Game.Internal.DXGI; using Dalamud.Hooking; using Dalamud.Hooking.Internal; +using Dalamud.Utility; using ImGuiNET; using ImGuiScene; using Serilog; @@ -322,9 +324,7 @@ namespace Dalamud.Interface.Internal private static void ShowFontError(string path) { - Util.Fatal( - $"One or more files required by XIVLauncher were not found.\nPlease restart and report this error if it occurs again.\n\n{path}", - "Error"); + Util.Fatal($"One or more files required by XIVLauncher were not found.\nPlease restart and report this error if it occurs again.\n\n{path}", "Error"); } private IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags) diff --git a/Dalamud/Interface/Internal/Scratchpad/ScratchExecutionManager.cs b/Dalamud/Interface/Internal/Scratchpad/ScratchExecutionManager.cs index 729827b1e..ba3a501eb 100644 --- a/Dalamud/Interface/Internal/Scratchpad/ScratchExecutionManager.cs +++ b/Dalamud/Interface/Internal/Scratchpad/ScratchExecutionManager.cs @@ -83,7 +83,7 @@ namespace Dalamud.Interface.Internal.Scratchpad { var script = CSharpScript.Create(code, options); - var pi = new DalamudPluginInterface(this.dalamud, "Scratch-" + doc.Id, null, PluginLoadReason.Unknown); + var pi = new DalamudPluginInterface(this.dalamud, "Scratch-" + doc.Id, PluginLoadReason.Unknown); var plugin = script.ContinueWith("return new ScratchPlugin() as IDalamudPlugin;") .RunAsync().GetAwaiter().GetResult().ReturnValue; diff --git a/Dalamud/Interface/Internal/Scratchpad/ScratchMacroProcessor.cs b/Dalamud/Interface/Internal/Scratchpad/ScratchMacroProcessor.cs index 4fdbd64f5..e39741072 100644 --- a/Dalamud/Interface/Internal/Scratchpad/ScratchMacroProcessor.cs +++ b/Dalamud/Interface/Internal/Scratchpad/ScratchMacroProcessor.cs @@ -131,7 +131,7 @@ public class ScratchPlugin : IDalamudPlugin { case ParseContext.Dispose: break; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(paramName: nameof(input)); } ctx = ParseContext.None; @@ -156,7 +156,7 @@ public class ScratchPlugin : IDalamudPlugin { disposeBody += line + "\n"; break; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(paramName: nameof(input)); } } diff --git a/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs b/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs index 69c2ade06..0420fe591 100644 --- a/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using Dalamud.Interface.Windowing; +using Dalamud.Utility; using ImGuiNET; namespace Dalamud.Interface.Internal.Windows diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs index c2ad77d1b..868ea7592 100644 --- a/Dalamud/Interface/Internal/Windows/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs @@ -4,17 +4,20 @@ using System.Dynamic; using System.Linq; using System.Numerics; +using Dalamud.Game; using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.ClientState.Actors.Types.NonPlayer; +using Dalamud.Game.ClientState.Conditions; +using Dalamud.Game.ClientState.GamePad; using Dalamud.Game.ClientState.Structs.JobGauge; -using Dalamud.Game.Internal; +using Dalamud.Game.Gui.Addons; +using Dalamud.Game.Gui.Toast; using Dalamud.Game.Internal.Gui; -using Dalamud.Game.Internal.Gui.Addon; -using Dalamud.Game.Internal.Gui.Toast; using Dalamud.Game.Text; using Dalamud.Interface.Windowing; using Dalamud.Plugin; +using Dalamud.Utility; using ImGuiNET; using ImGuiScene; using Newtonsoft.Json; @@ -117,6 +120,17 @@ namespace Dalamud.Interface.Internal.Windows Gamepad, } + /// + public override void OnOpen() + { + } + + /// + public override void OnClose() + { + this.resultAddon = null; + } + /// /// Set the DataKind dropdown menu. /// @@ -303,11 +317,11 @@ namespace Dalamud.Interface.Internal.Windows foreach (var valueTuple in debugScannedValue.Value) { ImGui.TextUnformatted( - $" {valueTuple.Item1} - 0x{valueTuple.Item2.ToInt64():x}"); + $" {valueTuple.ClassName} - 0x{valueTuple.Address.ToInt64():x}"); ImGui.SameLine(); if (ImGui.Button($"C##copyAddress{this.copyButtonIndex++}")) - ImGui.SetClipboardText(valueTuple.Item2.ToInt64().ToString("x")); + ImGui.SetClipboardText(valueTuple.Address.ToInt64().ToString("x")); } } } @@ -486,8 +500,8 @@ namespace Dalamud.Interface.Internal.Windows private void DrawPluginIPC() { #pragma warning disable CS0618 // Type or member is obsolete - var i1 = new DalamudPluginInterface(this.dalamud, "DalamudTestSub", null, PluginLoadReason.Unknown); - var i2 = new DalamudPluginInterface(this.dalamud, "DalamudTestPub", null, PluginLoadReason.Unknown); + var i1 = new DalamudPluginInterface(this.dalamud, "DalamudTestSub", PluginLoadReason.Unknown); + var i2 = new DalamudPluginInterface(this.dalamud, "DalamudTestPub", PluginLoadReason.Unknown); if (ImGui.Button("Add test sub")) { @@ -579,9 +593,7 @@ namespace Dalamud.Interface.Internal.Windows if (ImGui.Button("Get Addon")) { - this.resultAddon = - this.dalamud.Framework.Gui.GetAddonByName( - this.inputAddonName, this.inputAddonIndex); + this.resultAddon = this.dalamud.Framework.Gui.GetAddonByName(this.inputAddonName, this.inputAddonIndex); } if (ImGui.Button("Find Agent")) @@ -589,14 +601,12 @@ namespace Dalamud.Interface.Internal.Windows if (this.resultAddon != null) { - ImGui.TextUnformatted( - $"{this.resultAddon.Name} - 0x{this.resultAddon.Address.ToInt64():x}\n v:{this.resultAddon.Visible} x:{this.resultAddon.X} y:{this.resultAddon.Y} s:{this.resultAddon.Scale}, w:{this.resultAddon.Width}, h:{this.resultAddon.Height}"); + ImGui.TextUnformatted($"{this.resultAddon.Name} - 0x{this.resultAddon.Address.ToInt64():x}\n v:{this.resultAddon.Visible} x:{this.resultAddon.X} y:{this.resultAddon.Y} s:{this.resultAddon.Scale}, w:{this.resultAddon.Width}, h:{this.resultAddon.Height}"); } if (this.findAgentInterfacePtr != IntPtr.Zero) { - ImGui.TextUnformatted( - $"Agent: 0x{this.findAgentInterfacePtr.ToInt64():x}"); + ImGui.TextUnformatted($"Agent: 0x{this.findAgentInterfacePtr.ToInt64():x}"); ImGui.SameLine(); if (ImGui.Button("C")) @@ -807,13 +817,13 @@ namespace Dalamud.Interface.Internal.Windows $"R3 {resolve(GamepadButtons.R3)} "); } #if DEBUG - ImGui.Text($"GamepadInput 0x{this.dalamud.ClientState.GamepadState.GamepadInput.ToInt64():X}"); + ImGui.Text($"GamepadInput 0x{this.dalamud.ClientState.GamepadState.GamepadInputAddress.ToInt64():X}"); if (ImGui.IsItemHovered()) ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); if (ImGui.IsItemClicked()) - ImGui.SetClipboardText($"0x{this.dalamud.ClientState.GamepadState.GamepadInput.ToInt64():X}"); + ImGui.SetClipboardText($"0x{this.dalamud.ClientState.GamepadState.GamepadInputAddress.ToInt64():X}"); #endif DrawHelper( diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index 870251645..a1c2954e5 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -18,6 +18,7 @@ using Dalamud.Plugin; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Types; +using Dalamud.Utility; using ImGuiNET; using ImGuiScene; @@ -613,6 +614,8 @@ namespace Dalamud.Interface.Internal.Windows label += Locs.PluginTitleMod_TestingVersion; } + ImGui.PushID($"available{index}{manifest.InternalName}"); + if (this.DrawPluginCollapsingHeader(label, manifest, false, false, index)) { ImGuiHelpers.ScaledDummy(5); @@ -708,6 +711,8 @@ namespace Dalamud.Interface.Internal.Windows ImGui.EndPopup(); } + + ImGui.PopID(); } private void DrawInstalledPlugin(LocalPlugin plugin, int index, bool showInstalled = false) @@ -781,6 +786,8 @@ namespace Dalamud.Interface.Internal.Windows trouble = true; } + ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}"); + if (this.DrawPluginCollapsingHeader(label, plugin.Manifest, trouble, availablePluginUpdate != default, index)) { var manifest = plugin.Manifest; @@ -791,7 +798,9 @@ namespace Dalamud.Interface.Internal.Windows ImGui.Text(manifest.Name); // Download count - var downloadText = manifest.DownloadCount > 0 + var downloadText = plugin.IsDev + ? Locs.PluginBody_AuthorWithoutDownloadCount(manifest.Author) + : manifest.DownloadCount > 0 ? Locs.PluginBody_AuthorWithDownloadCount(manifest.Author, manifest.DownloadCount) : Locs.PluginBody_AuthorWithDownloadCountUnavailable(manifest.Author); @@ -799,12 +808,15 @@ namespace Dalamud.Interface.Internal.Windows ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText); // Installed from - if (!string.IsNullOrEmpty(manifest.InstalledFromUrl)) + if (plugin.IsDev) + { + var fileText = Locs.PluginBody_DevPluginPath(plugin.DllFile.FullName); + ImGui.TextColored(ImGuiColors.DalamudGrey3, fileText); + } + else if (!string.IsNullOrEmpty(manifest.InstalledFromUrl)) { var repoText = Locs.PluginBody_Plugin3rdPartyRepo(manifest.InstalledFromUrl); ImGui.TextColored(ImGuiColors.DalamudGrey3, repoText); - - ImGuiHelpers.ScaledDummy(2); } // Description @@ -879,6 +891,8 @@ namespace Dalamud.Interface.Internal.Windows ImGui.EndPopup(); } + + ImGui.PopID(); } private void DrawPluginControlButton(LocalPlugin plugin) @@ -1493,10 +1507,14 @@ namespace Dalamud.Interface.Internal.Windows #region Plugin body + public static string PluginBody_AuthorWithoutDownloadCount(string author) => Loc.Localize("InstallerAuthorWithoutDownloadCount", " by {0}").Format(author); + public static string PluginBody_AuthorWithDownloadCount(string author, long count) => Loc.Localize("InstallerAuthorWithDownloadCount", " by {0}, {1} downloads").Format(author, count); public static string PluginBody_AuthorWithDownloadCountUnavailable(string author) => Loc.Localize("InstallerAuthorWithDownloadCountUnavailable", " by {0}, download count unavailable").Format(author); + public static string PluginBody_DevPluginPath(string path) => Loc.Localize("InstallerDevPluginPath", "From {0}").Format(path); + public static string PluginBody_Plugin3rdPartyRepo(string url) => Loc.Localize("InstallerPlugin3rdPartyRepo", "From custom plugin repository {0}").Format(url); public static string PluginBody_AvailableDevPlugin => Loc.Localize("InstallerDevPlugin", " This plugin is available in one of your repos, please remove it from the devPlugins folder."); diff --git a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs index cdb60d9b0..733baa454 100644 --- a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Reflection; +using Dalamud.Game; using Dalamud.Game.Internal; using Dalamud.Hooking.Internal; using Dalamud.Interface.Windowing; diff --git a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs index f5c13dd0a..fde2ad0c7 100644 --- a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs @@ -44,16 +44,21 @@ namespace Dalamud.Interface.Internal.Windows private bool doDocking; private bool doViewport; private bool doGamepad; + private List thirdRepoList; private bool thirdRepoListChanged; + private string thirdRepoTempUrl = string.Empty; + private string thirdRepoAddError = string.Empty; + + private List devPluginLocations; + private bool devPluginLocationsChanged; + private string devPluginTempLocation = string.Empty; + private string devPluginLocationAddError = string.Empty; private bool printPluginsWelcomeMsg; private bool autoUpdatePlugins; private bool doButtonsSystemMenu; - private string thirdRepoTempUrl = string.Empty; - private string thirdRepoAddError = string.Empty; - #region Experimental private bool doPluginTest; @@ -88,6 +93,7 @@ namespace Dalamud.Interface.Internal.Windows this.doPluginTest = this.dalamud.Configuration.DoPluginTest; this.thirdRepoList = this.dalamud.Configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); + this.devPluginLocations = this.dalamud.Configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); this.printPluginsWelcomeMsg = this.dalamud.Configuration.PrintPluginsWelcomeMsg; this.autoUpdatePlugins = this.dalamud.Configuration.AutoUpdatePlugins; @@ -144,14 +150,15 @@ namespace Dalamud.Interface.Internal.Windows public override void OnOpen() { this.thirdRepoListChanged = false; + this.devPluginLocationsChanged = false; } /// public override void OnClose() { ImGui.GetIO().FontGlobalScale = this.dalamud.Configuration.GlobalUiScale; - this.thirdRepoList = this.dalamud.Configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); + this.devPluginLocations = this.dalamud.Configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); } /// @@ -252,12 +259,18 @@ namespace Dalamud.Interface.Internal.Windows if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsExperimental", "Experimental"))) { + #region Plugin testing + ImGui.Checkbox(Loc.Localize("DalamudSettingsPluginTest", "Get plugin testing builds"), ref this.doPluginTest); ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsPluginTestHint", "Receive testing prereleases for plugins.")); ImGui.TextColored(this.warnTextColor, Loc.Localize("DalamudSettingsPluginTestWarning", "Testing plugins may not have been vetted before being published. Please only enable this if you are aware of the risks.")); + #endregion + ImGuiHelpers.ScaledDummy(12); + #region Hidden plugins + if (ImGui.Button(Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins"))) { this.dalamud.Configuration.HiddenPluginInternalName.Clear(); @@ -266,10 +279,12 @@ namespace Dalamud.Interface.Internal.Windows ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsClearHiddenHint", "Restore plugins you have previously hidden from the plugin installer.")); - ImGuiHelpers.ScaledDummy(12); + #endregion ImGuiHelpers.ScaledDummy(12); + #region Custom repos + ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories")); ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories.")); ImGui.TextColored(this.warnTextColor, Loc.Localize("DalamudSettingCustomRepoWarning", "We cannot take any responsibility for third-party plugins and repositories.\nTake care when installing third-party plugins from untrusted sources.")); @@ -278,7 +293,7 @@ namespace Dalamud.Interface.Internal.Windows ImGui.Columns(4); ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(1, ImGui.GetWindowWidth() - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionWidth() - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); @@ -303,7 +318,7 @@ namespace Dalamud.Interface.Internal.Windows ImGui.NextColumn(); ImGui.Separator(); - ThirdPartyRepoSettings toRemove = null; + ThirdPartyRepoSettings repoToRemove = null; var repoNumber = 1; foreach (var thirdRepoSetting in this.thirdRepoList) @@ -325,7 +340,7 @@ namespace Dalamud.Interface.Internal.Windows if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) { - toRemove = thirdRepoSetting; + repoToRemove = thirdRepoSetting; } ImGui.NextColumn(); @@ -336,9 +351,9 @@ namespace Dalamud.Interface.Internal.Windows repoNumber++; } - if (toRemove != null) + if (repoToRemove != null) { - this.thirdRepoList.Remove(toRemove); + this.thirdRepoList.Remove(repoToRemove); this.thirdRepoListChanged = true; } @@ -377,6 +392,115 @@ namespace Dalamud.Interface.Internal.Windows { ImGui.TextColored(new Vector4(1, 0, 0, 1), this.thirdRepoAddError); } + + #endregion + + ImGuiHelpers.ScaledDummy(12); + + #region Custom dev plugin load locations + + ImGui.Text(Loc.Localize("DalamudSettingsDevPluginLocation", "Dev Plugin Locations")); + ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path.")); + + ImGuiHelpers.ScaledDummy(5); + + ImGui.Columns(4); + ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionWidth() - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); + + ImGui.Separator(); + + ImGui.Text("#"); + ImGui.NextColumn(); + ImGui.Text("Path"); + ImGui.NextColumn(); + ImGui.Text("Enabled"); + ImGui.NextColumn(); + ImGui.Text(string.Empty); + ImGui.NextColumn(); + + ImGui.Separator(); + + DevPluginLocationSettings locationToRemove = null; + + var locNumber = 1; + foreach (var devPluginLocationSetting in this.devPluginLocations) + { + var isEnabled = devPluginLocationSetting.IsEnabled; + + ImGui.PushID($"devPluginLocation_{devPluginLocationSetting.Path}"); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2)); + ImGui.Text(locNumber.ToString()); + ImGui.NextColumn(); + + ImGui.TextWrapped(devPluginLocationSetting.Path); + ImGui.NextColumn(); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); + ImGui.Checkbox("##devPluginLocationCheck", ref isEnabled); + ImGui.NextColumn(); + + if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) + { + locationToRemove = devPluginLocationSetting; + } + + ImGui.NextColumn(); + ImGui.Separator(); + + devPluginLocationSetting.IsEnabled = isEnabled; + + locNumber++; + } + + if (locationToRemove != null) + { + this.devPluginLocations.Remove(locationToRemove); + this.devPluginLocationsChanged = true; + } + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2)); + ImGui.Text(locNumber.ToString()); + ImGui.NextColumn(); + ImGui.SetNextItemWidth(-1); + ImGui.InputText("##devPluginLocationInput", ref this.devPluginTempLocation, 300); + ImGui.NextColumn(); + // Enabled button + ImGui.NextColumn(); + if (!string.IsNullOrEmpty(this.devPluginTempLocation) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) + { + if (this.devPluginLocations.Any(r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase))) + { + this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists."); + Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty); + } + else + { + this.devPluginLocations.Add(new DevPluginLocationSettings + { + Path = this.devPluginTempLocation, + IsEnabled = true, + }); + this.devPluginLocationsChanged = true; + this.devPluginTempLocation = string.Empty; + } + } + + ImGui.Columns(1); + + ImGui.EndTabItem(); + + if (!string.IsNullOrEmpty(this.devPluginLocationAddError)) + { + ImGui.TextColored(new Vector4(1, 0, 0, 1), this.devPluginLocationAddError); + } + + #endregion + + ImGuiHelpers.ScaledDummy(12); } ImGui.EndTabBar(); @@ -384,20 +508,18 @@ namespace Dalamud.Interface.Internal.Windows ImGui.EndChild(); - if (ImGui.Button(Loc.Localize("Save", "Save"))) - { - this.Save(); + var buttonSave = false; + var buttonClose = false; - if (this.thirdRepoListChanged) - { - this.dalamud.PluginManager.SetPluginReposFromConfig(true); - this.thirdRepoListChanged = false; - } - } + if (ImGui.Button(Loc.Localize("Save", "Save"))) + buttonSave = true; ImGui.SameLine(); if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close"))) + buttonSave = buttonClose = true; + + if (buttonSave) { this.Save(); @@ -407,6 +529,15 @@ namespace Dalamud.Interface.Internal.Windows this.thirdRepoListChanged = false; } + if (this.devPluginLocationsChanged) + { + this.dalamud.PluginManager.ScanDevPlugins(); + this.devPluginLocationsChanged = false; + } + } + + if (buttonClose) + { this.IsOpen = false; } } @@ -456,6 +587,7 @@ namespace Dalamud.Interface.Internal.Windows this.dalamud.Configuration.DoPluginTest = this.doPluginTest; this.dalamud.Configuration.ThirdRepoList = this.thirdRepoList.Select(x => x.Clone()).ToList(); + this.dalamud.Configuration.DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList(); this.dalamud.Configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg; this.dalamud.Configuration.AutoUpdatePlugins = this.autoUpdatePlugins; diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs index e24ab8bc1..71ce244f7 100644 --- a/Dalamud/Interface/UiBuilder.cs +++ b/Dalamud/Interface/UiBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Conditions; using Dalamud.Interface.Internal; using ImGuiNET; using ImGuiScene; diff --git a/Dalamud/Logging/PluginLog.cs b/Dalamud/Logging/PluginLog.cs index fefb386c5..a21363854 100644 --- a/Dalamud/Logging/PluginLog.cs +++ b/Dalamud/Logging/PluginLog.cs @@ -8,6 +8,131 @@ namespace Dalamud.Logging /// public static class PluginLog { + #region "Log" prefixed Serilog style methods + + /// + /// Log a templated message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void Log(string messageTemplate, params object[] values) + => Serilog.Log.Information($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void Log(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Information(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated verbose message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void LogVerbose(string messageTemplate, params object[] values) + => Serilog.Log.Verbose($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated verbose message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void LogVerbose(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Verbose(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated debug message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void LogDebug(string messageTemplate, params object[] values) + => Serilog.Log.Debug($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated debug message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void LogDebug(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Debug(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated information message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void LogInformation(string messageTemplate, params object[] values) + => Serilog.Log.Information($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated information message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void LogInformation(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Information(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated warning message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void LogWarning(string messageTemplate, params object[] values) + => Serilog.Log.Warning($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated warning message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void LogWarning(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Warning(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated error message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void LogError(string messageTemplate, params object[] values) + => Serilog.Log.Error($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated error message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void LogError(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Error(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated fatal message to the in-game debug log. + /// + /// The message template. + /// Values to log. + public static void LogFatal(string messageTemplate, params object[] values) + => Serilog.Log.Fatal($"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + /// + /// Log a templated fatal message to the in-game debug log. + /// + /// The exception that caused the error. + /// The message template. + /// Values to log. + public static void LogFatal(Exception exception, string messageTemplate, params object[] values) + => Serilog.Log.Fatal(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + #endregion + + #region Serilog style methods + /// /// Log a templated verbose message to the in-game debug log. /// @@ -109,5 +234,7 @@ namespace Dalamud.Logging /// Values to log. public static void Fatal(Exception exception, string messageTemplate, params object[] values) => Serilog.Log.Fatal(exception, $"[{Assembly.GetCallingAssembly().GetName().Name}] {messageTemplate}", values); + + #endregion } } diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index 8814e494a..0cd7007a4 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -35,9 +35,8 @@ namespace Dalamud.Plugin /// /// The dalamud instance to expose. /// The internal name of the plugin. - /// The equivalent of what Assembly.GetExecutingAssembly().Location should return. /// The reason the plugin was loaded. - internal DalamudPluginInterface(Dalamud dalamud, string pluginName, string assemblyLocation, PluginLoadReason reason) + internal DalamudPluginInterface(Dalamud dalamud, string pluginName, PluginLoadReason reason) { this.CommandManager = dalamud.CommandManager; this.Framework = dalamud.Framework; @@ -50,7 +49,6 @@ namespace Dalamud.Plugin this.dalamud = dalamud; this.pluginName = pluginName; this.configs = dalamud.PluginManager.PluginConfigs; - this.AssemblyLocation = assemblyLocation; this.Reason = reason; this.GeneralChatType = this.dalamud.Configuration.GeneralChatType; @@ -88,11 +86,6 @@ namespace Dalamud.Plugin /// public PluginLoadReason Reason { get; } - /// - /// Gets the plugin assembly location. - /// - public string AssemblyLocation { get; private set; } - /// /// Gets the directory Dalamud assets are stored in. /// @@ -124,7 +117,7 @@ namespace Dalamud.Plugin public Framework Framework { get; private set; } /// - /// Gets the UiBuilder instance which allows you to draw UI into the game via ImGui draw calls. + /// Gets the instance which allows you to draw UI into the game via ImGui draw calls. /// public UiBuilder UiBuilder { get; private set; } @@ -172,6 +165,8 @@ namespace Dalamud.Plugin /// internal Action AnyPluginIpcAction { get; private set; } + #region Configuration + /// /// Save a plugin configuration(inheriting IPluginConfiguration). /// @@ -223,6 +218,8 @@ namespace Dalamud.Plugin /// directory with path of AppData/XIVLauncher/pluginConfig/PluginInternalName/loc. public string GetPluginLocDirectory() => this.configs.GetDirectory(Path.Combine(this.pluginName, "loc")); + #endregion + #region Chat Links /// diff --git a/Dalamud/Plugin/Internal/LocalPlugin.cs b/Dalamud/Plugin/Internal/LocalPlugin.cs index f5b3481f8..3299feced 100644 --- a/Dalamud/Plugin/Internal/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/LocalPlugin.cs @@ -272,7 +272,7 @@ namespace Dalamud.Plugin.Internal this.Manifest.Save(this.manifestFile); } - this.DalamudInterface = new DalamudPluginInterface(this.dalamud, this.pluginAssembly.GetName().Name, this.DllFile.FullName, reason); + this.DalamudInterface = new DalamudPluginInterface(this.dalamud, this.pluginAssembly.GetName().Name, reason); if (this.IsDev) { diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index a3f4f250e..cec465f9e 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Linq; -using System.Net; +using System.Net.Http; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -17,6 +17,7 @@ using Dalamud.Game.Text; using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Types; +using Dalamud.Utility; using HarmonyLib; using JetBrains.Annotations; using Newtonsoft.Json; @@ -185,7 +186,22 @@ namespace Dalamud.Plugin.Internal } // devPlugins are more freeform. Look for any dll and hope to get lucky. - var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories); + var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories).ToList(); + + foreach (var setting in this.dalamud.Configuration.DevPluginLoadLocations) + { + if (!setting.IsEnabled) + continue; + + if (Directory.Exists(setting.Path)) + { + devDllFiles.AddRange(new DirectoryInfo(setting.Path).GetFiles("*.dll", SearchOption.AllDirectories)); + } + else if (File.Exists(setting.Path)) + { + devDllFiles.Add(new FileInfo(setting.Path)); + } + } foreach (var dllFile in devDllFiles) { @@ -298,7 +314,22 @@ namespace Dalamud.Plugin.Internal this.devPluginDirectory.Create(); // devPlugins are more freeform. Look for any dll and hope to get lucky. - var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories); + var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories).ToList(); + + foreach (var setting in this.dalamud.Configuration.DevPluginLoadLocations) + { + if (!setting.IsEnabled) + continue; + + if (Directory.Exists(setting.Path)) + { + devDllFiles.AddRange(new DirectoryInfo(setting.Path).GetFiles("*.dll", SearchOption.AllDirectories)); + } + else if (File.Exists(setting.Path)) + { + devDllFiles.Add(new FileInfo(setting.Path)); + } + } var listChanged = false; @@ -359,16 +390,17 @@ namespace Dalamud.Plugin.Internal // ignored, since the plugin may be loaded already } - using var client = new WebClient(); - var tempZip = new FileInfo(Path.GetTempFileName()); try { Log.Debug($"Downloading plugin to {tempZip} from {downloadUrl}"); - client.DownloadFile(downloadUrl, tempZip.FullName); + using var client = new HttpClient(); + var response = client.GetAsync(downloadUrl).Result; + using var fs = new FileStream(tempZip.FullName, FileMode.CreateNew); + response.Content.CopyToAsync(fs).GetAwaiter().GetResult(); } - catch (WebException ex) + catch (HttpRequestException ex) { Log.Error(ex, $"Download of plugin {repoManifest.Name} failed unexpectedly."); throw; @@ -593,7 +625,7 @@ namespace Dalamud.Plugin.Internal continue; } - if (manifest.ApplicableVersion < this.dalamud.StartInfo.GameVersion) + if (manifest.ApplicableVersion < this.dalamud.StartInfo.GameVersion - TimeSpan.FromDays(90)) { Log.Information($"Inapplicable version: cleaning up {versionDir.FullName}"); versionDir.Delete(true); @@ -977,26 +1009,21 @@ namespace Dalamud.Plugin.Internal [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313:Parameter names should begin with lower-case letter", Justification = "Enforced naming for special injected parameters")] private static void AssemblyLocationPatch(Assembly __instance, ref string __result) { - // Assembly.GetExecutingAssembly can return this. - // Check for it as a special case and find the plugin. - if (__result.EndsWith("System.Private.CoreLib.dll", StringComparison.InvariantCultureIgnoreCase)) + if (string.IsNullOrEmpty(__result)) { foreach (var assemblyName in GetStackFrameAssemblyNames()) { if (PluginLocations.TryGetValue(assemblyName, out var data)) { __result = data.Location; - return; + break; } } } - else if (string.IsNullOrEmpty(__result)) - { - if (PluginLocations.TryGetValue(__instance.FullName, out var data)) - { - __result = data.Location; - } - } + + __result ??= string.Empty; + + Log.Verbose($"Assembly.Location // {__instance.FullName} // {__result}"); } /// @@ -1009,26 +1036,21 @@ namespace Dalamud.Plugin.Internal [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313:Parameter names should begin with lower-case letter", Justification = "Enforced naming for special injected parameters")] private static void AssemblyCodeBasePatch(Assembly __instance, ref string __result) { - // Assembly.GetExecutingAssembly can return this. - // Check for it as a special case and find the plugin. - if (__result.EndsWith("System.Private.CoreLib.dll")) + if (string.IsNullOrEmpty(__result)) { foreach (var assemblyName in GetStackFrameAssemblyNames()) { if (PluginLocations.TryGetValue(assemblyName, out var data)) { - __result = data.Location; - return; + __result = data.CodeBase; + break; } } } - else if (string.IsNullOrEmpty(__result)) - { - if (PluginLocations.TryGetValue(__instance.FullName, out var data)) - { - __result = data.Location; - } - } + + __result ??= string.Empty; + + Log.Verbose($"Assembly.CodeBase // {__instance.FullName} // {__result}"); } private static IEnumerable GetStackFrameAssemblyNames() diff --git a/Dalamud/Plugin/Internal/PluginRepository.cs b/Dalamud/Plugin/Internal/PluginRepository.cs index e76aa67d1..d90efaee8 100644 --- a/Dalamud/Plugin/Internal/PluginRepository.cs +++ b/Dalamud/Plugin/Internal/PluginRepository.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Net; +using System.Net.Http; using System.Threading.Tasks; using Dalamud.Logging.Internal; @@ -74,11 +74,10 @@ namespace Dalamud.Plugin.Internal return Task.Run(() => { - using var client = new WebClient(); - Log.Information($"Fetching repo: {this.PluginMasterUrl}"); - - var data = client.DownloadString(this.PluginMasterUrl); + using var client = new HttpClient(); + using var response = client.GetAsync(this.PluginMasterUrl).Result; + var data = response.Content.ReadAsStringAsync().Result; var pluginMaster = JsonConvert.DeserializeObject>(data); pluginMaster.Sort((pm1, pm2) => pm1.Name.CompareTo(pm2.Name)); diff --git a/Dalamud/Troubleshooting.cs b/Dalamud/Troubleshooting.cs index 69b0df23e..7aba6ec2c 100644 --- a/Dalamud/Troubleshooting.cs +++ b/Dalamud/Troubleshooting.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Dalamud.Configuration; -using Dalamud.Plugin; using Dalamud.Plugin.Internal.Types; +using Dalamud.Utility; using Newtonsoft.Json; using Serilog; diff --git a/Dalamud/Utility/EnumExtensions.cs b/Dalamud/Utility/EnumExtensions.cs new file mode 100644 index 000000000..5a2d9172b --- /dev/null +++ b/Dalamud/Utility/EnumExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; + +namespace Dalamud.Utility +{ + /// + /// Extension methods for enums. + /// + public static class EnumExtensions + { + /// + /// Gets an attribute on an enum. + /// + /// The type of attribute to get. + /// The enum value that has an attached attribute. + /// The attached attribute, if any. + public static TAttribute GetAttribute(this Enum value) + where TAttribute : Attribute + { + var type = value.GetType(); + var name = Enum.GetName(type, value); + return type.GetField(name) // I prefer to get attributes this way + .GetCustomAttributes(false) + .OfType() + .SingleOrDefault(); + } + } +} diff --git a/Dalamud/Utility/StringExtensions.cs b/Dalamud/Utility/StringExtensions.cs new file mode 100644 index 000000000..f452a2a0f --- /dev/null +++ b/Dalamud/Utility/StringExtensions.cs @@ -0,0 +1,30 @@ +namespace Dalamud.Utility +{ + /// + /// Extension methods for strings. + /// + public static class StringExtensions + { + /// + /// An extension method to chain usage of string.Format. + /// + /// Format string. + /// Format arguments. + /// Formatted string. + public static string Format(this string format, params object[] args) => string.Format(format, args); + + /// + /// Indicates whether the specified string is null or an empty string (""). + /// + /// The string to test. + /// true if the value parameter is null or an empty string (""); otherwise, false. + public static bool IsNullOrEmpty(this string value) => string.IsNullOrEmpty(value); + + /// + /// Indicates whether a specified string is null, empty, or consists only of white-space characters. + /// + /// The string to test. + /// true if the value parameter is null or an empty string (""), or if value consists exclusively of white-space characters. + public static bool IsNullOrWhitespace(this string value) => string.IsNullOrWhiteSpace(value); + } +} diff --git a/Dalamud/Data/LuminaExtensions/TexFileExtensions.cs b/Dalamud/Utility/TexFileExtensions.cs similarity index 95% rename from Dalamud/Data/LuminaExtensions/TexFileExtensions.cs rename to Dalamud/Utility/TexFileExtensions.cs index d2bb7b736..ddfccba9c 100644 --- a/Dalamud/Data/LuminaExtensions/TexFileExtensions.cs +++ b/Dalamud/Utility/TexFileExtensions.cs @@ -1,7 +1,7 @@ using ImGuiScene; using Lumina.Data.Files; -namespace Dalamud.Data.LuminaExtensions +namespace Dalamud.Utility { /// /// Extensions to . diff --git a/Dalamud/Util.cs b/Dalamud/Utility/Util.cs similarity index 94% rename from Dalamud/Util.cs rename to Dalamud/Utility/Util.cs index 3084e1bab..edd2d8c97 100644 --- a/Dalamud/Util.cs +++ b/Dalamud/Utility/Util.cs @@ -7,10 +7,11 @@ using System.Text; using Dalamud.Game; using Dalamud.Interface; using Dalamud.Interface.Colors; +using Dalamud.Logging.Internal; using ImGuiNET; using Serilog; -namespace Dalamud +namespace Dalamud.Utility { /// /// Class providing various helper methods for use in Dalamud and plugins. @@ -196,13 +197,5 @@ namespace Dalamud // TODO: Someone implement GetUTF8String with some IntPtr overloads. // while(Marshal.ReadByte(0, sz) != 0) { sz++; } - - /// - /// An extension method to chain usage of string.Format. - /// - /// Format string. - /// Format arguments. - /// Formatted string. - public static string Format(this string format, params object[] args) => string.Format(format, args); } } diff --git a/Dalamud/Utility/VectorExtensions.cs b/Dalamud/Utility/VectorExtensions.cs new file mode 100644 index 000000000..0a14299c2 --- /dev/null +++ b/Dalamud/Utility/VectorExtensions.cs @@ -0,0 +1,52 @@ +using System.Numerics; + +namespace Dalamud.Utility +{ + /// + /// Extension methods for System.Numerics.VectorN and SharpDX.VectorN. + /// + public static class VectorExtensions + { + /// + /// Converts a SharpDX vector to System.Numerics. + /// + /// Vector to convert. + /// A converted vector. + public static Vector2 ToSystem(this SharpDX.Vector2 vec) => new(x: vec.X, y: vec.Y); + + /// + /// Converts a SharpDX vector to System.Numerics. + /// + /// Vector to convert. + /// A converted vector. + public static Vector3 ToSystem(this SharpDX.Vector3 vec) => new(x: vec.X, y: vec.Y, z: vec.Z); + + /// + /// Converts a SharpDX vector to System.Numerics. + /// + /// Vector to convert. + /// A converted vector. + public static Vector4 ToSystem(this SharpDX.Vector4 vec) => new(x: vec.X, y: vec.Y, z: vec.Z, w: vec.W); + + /// + /// Converts a System.Numerics vector to SharpDX. + /// + /// Vector to convert. + /// A converted vector. + public static SharpDX.Vector2 ToSharpDX(this Vector2 vec) => new(x: vec.X, y: vec.Y); + + /// + /// Converts a System.Numerics vector to SharpDX. + /// + /// Vector to convert. + /// A converted vector. + public static SharpDX.Vector3 ToSharpDX(this Vector3 vec) => new(x: vec.X, y: vec.Y, z: vec.Z); + + /// + /// Converts a System.Numerics vector to SharpDX. + /// + /// Vector to convert. + /// A converted vector. + public static SharpDX.Vector4 ToSharpDX(this Vector4 vec) => new(x: vec.X, y: vec.Y, z: vec.Z, w: vec.W); + } +}