Merge branch 'master' into AgentLifecycle

This commit is contained in:
MidoriKami 2026-01-10 08:16:52 -08:00
commit d689c4763a
319 changed files with 2127 additions and 1093 deletions

View file

@ -1,5 +1,4 @@
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Component.GUI;

View file

@ -24,7 +24,7 @@ internal unsafe class AddonEventManager : IInternalDisposableService
/// </summary>
public static readonly Guid DalamudInternalKey = Guid.NewGuid();
private static readonly ModuleLog Log = new("AddonEventManager");
private static readonly ModuleLog Log = ModuleLog.Create<AddonEventManager>();
[ServiceManager.ServiceDependency]
private readonly AddonLifecycle addonLifecycle = Service<AddonLifecycle>.Get();

View file

@ -61,6 +61,11 @@ public enum AddonEventType : byte
/// </summary>
InputBaseInputReceived = 15,
/// <summary>
/// Fired at the very beginning of AtkInputManager.HandleInput on AtkStage.ViewportEventManager. Used in LovmMiniMap.
/// </summary>
RawInputData = 16,
/// <summary>
/// Focus Start.
/// </summary>
@ -107,7 +112,12 @@ public enum AddonEventType : byte
SliderReleased = 30,
/// <summary>
/// AtkComponentList RollOver.
/// AtkComponentList Button Press.
/// </summary>
ListButtonPress = 31,
/// <summary>
/// AtkComponentList Roll Over.
/// </summary>
ListItemRollOver = 33,
@ -126,11 +136,31 @@ public enum AddonEventType : byte
/// </summary>
ListItemDoubleClick = 36,
/// <summary>
/// AtkComponentList Highlight.
/// </summary>
ListItemHighlight = 37,
/// <summary>
/// AtkComponentList Select.
/// </summary>
ListItemSelect = 38,
/// <summary>
/// AtkComponentList Pad Drag Drop Begin.
/// </summary>
ListItemPadDragDropBegin = 40,
/// <summary>
/// AtkComponentList Pad Drag Drop End.
/// </summary>
ListItemPadDragDropEnd = 41,
/// <summary>
/// AtkComponentList Pad Drag Drop Insert.
/// </summary>
ListItemPadDragDropInsert = 42,
/// <summary>
/// AtkComponentDragDrop Begin.
/// Sent on MouseDown over a draggable icon (will NOT send for a locked icon).
@ -142,12 +172,22 @@ public enum AddonEventType : byte
/// </summary>
DragDropEnd = 51,
/// <summary>
/// AtkComponentDragDrop Insert Attempt.
/// </summary>
DragDropInsertAttempt = 52,
/// <summary>
/// AtkComponentDragDrop Insert.
/// Sent when dropping an icon into a hotbar/inventory slot or similar.
/// </summary>
DragDropInsert = 53,
/// <summary>
/// AtkComponentDragDrop Can Accept Check.
/// </summary>
DragDropCanAcceptCheck = 54,
/// <summary>
/// AtkComponentDragDrop Roll Over.
/// </summary>
@ -165,23 +205,18 @@ public enum AddonEventType : byte
DragDropDiscard = 57,
/// <summary>
/// Drag Drop Unknown.
/// AtkComponentDragDrop Click.
/// Sent on MouseUp if the cursor has not moved since DragDropBegin, OR on MouseDown over a locked icon.
/// </summary>
[Obsolete("Use DragDropDiscard", true)]
DragDropUnk54 = 54,
DragDropClick = 58,
/// <summary>
/// AtkComponentDragDrop Cancel.
/// Sent on MouseUp if the cursor has not moved since DragDropBegin, OR on MouseDown over a locked icon.
/// </summary>
[Obsolete("Renamed to DragDropClick")]
DragDropCancel = 58,
/// <summary>
/// Drag Drop Unknown.
/// </summary>
[Obsolete("Use DragDropCancel", true)]
DragDropUnk55 = 55,
/// <summary>
/// AtkComponentIconText Roll Over.
/// </summary>
@ -217,6 +252,11 @@ public enum AddonEventType : byte
/// </summary>
TimerEnd = 65,
/// <summary>
/// AtkTimer Start.
/// </summary>
TimerStart = 66,
/// <summary>
/// AtkSimpleTween Progress.
/// </summary>
@ -247,6 +287,11 @@ public enum AddonEventType : byte
/// </summary>
WindowChangeScale = 72,
/// <summary>
/// AtkTimeline Active Label Changed.
/// </summary>
TimelineActiveLabelChanged = 75,
/// <summary>
/// AtkTextNode Link Mouse Click.
/// </summary>

View file

@ -5,7 +5,6 @@ using Dalamud.Game.Addon.Events.EventDataTypes;
using Dalamud.Game.Gui;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Component.GUI;
@ -16,7 +15,7 @@ namespace Dalamud.Game.Addon.Events;
/// </summary>
internal unsafe class PluginEventController : IDisposable
{
private static readonly ModuleLog Log = new("AddonEventManager");
private static readonly ModuleLog Log = ModuleLog.Create<AddonEventManager>();
/// <summary>
/// Initializes a new instance of the <see cref="PluginEventController"/> class.
@ -28,7 +27,7 @@ internal unsafe class PluginEventController : IDisposable
private AddonEventListener EventListener { get; init; }
private List<AddonEventEntry> Events { get; } = new();
private List<AddonEventEntry> Events { get; } = [];
/// <summary>
/// Adds a tracked event.

View file

@ -25,9 +25,13 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// </summary>
public static readonly List<AddonVirtualTable> AllocatedTables = [];
private static readonly ModuleLog Log = new("AddonLifecycle");
private static readonly ModuleLog Log = ModuleLog.Create<AddonLifecycle>();
[ServiceManager.ServiceDependency]
private readonly Framework framework = Service<Framework>.Get();
private Hook<AtkUnitBase.Delegates.Initialize>? onInitializeAddonHook;
private bool isInvokingListeners = false;
[ServiceManager.ServiceConstructor]
private AddonLifecycle()
@ -58,20 +62,23 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// <param name="listener">The listener to register.</param>
internal void RegisterListener(AddonLifecycleEventListener listener)
{
if (!this.EventListeners.ContainsKey(listener.EventType))
this.framework.RunOnTick(() =>
{
if (!this.EventListeners.TryAdd(listener.EventType, []))
return;
}
if (!this.EventListeners.ContainsKey(listener.EventType))
{
if (!this.EventListeners.TryAdd(listener.EventType, []))
return;
}
// Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName))
{
if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, []))
return;
}
// Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type
if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName))
{
if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, []))
return;
}
this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
this.EventListeners[listener.EventType][listener.AddonName].Add(listener);
}, delayTicks: this.isInvokingListeners ? 1 : 0);
}
/// <summary>
@ -80,13 +87,16 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// <param name="listener">The listener to unregister.</param>
internal void UnregisterListener(AddonLifecycleEventListener listener)
{
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
this.framework.RunOnTick(() =>
{
if (addonListeners.TryGetValue(listener.AddonName, out var addonListener))
if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners))
{
addonListener.Remove(listener);
if (addonListeners.TryGetValue(listener.AddonName, out var addonListener))
{
addonListener.Remove(listener);
}
}
}
}, delayTicks: this.isInvokingListeners ? 1 : 0);
}
/// <summary>
@ -97,6 +107,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
/// <param name="blame">What to blame on errors.</param>
internal void InvokeListenersSafely(AddonEvent eventType, AddonArgs args, [CallerMemberName] string blame = "")
{
this.isInvokingListeners = true;
// Early return if we don't have any listeners of this type
if (!this.EventListeners.TryGetValue(eventType, out var addonListeners)) return;
@ -131,6 +143,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
}
}
}
this.isInvokingListeners = false;
}
/// <summary>

View file

@ -14,7 +14,7 @@ public abstract class BaseAddressResolver
/// <summary>
/// Gets a list of memory addresses that were found, to list in /xldata.
/// </summary>
public static Dictionary<string, List<(string ClassName, IntPtr Address)>> DebugScannedValues { get; } = new();
public static Dictionary<string, List<(string ClassName, IntPtr Address)>> DebugScannedValues { get; } = [];
/// <summary>
/// Gets or sets a value indicating whether the resolver has successfully run <see cref="Setup32Bit(ISigScanner)"/> or <see cref="Setup64Bit(ISigScanner)"/>.

View file

@ -0,0 +1,221 @@
using System.Diagnostics.CodeAnalysis;
using Dalamud.Data;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using FFXIVClientStructs.FFXIV.Component.Text;
using FFXIVClientStructs.Interop;
using Lumina.Excel;
using Lumina.Text.ReadOnly;
namespace Dalamud.Game.Chat;
/// <summary>
/// Interface representing a log message.
/// </summary>
public interface ILogMessage : IEquatable<ILogMessage>
{
/// <summary>
/// Gets the address of the log message in memory.
/// </summary>
nint Address { get; }
/// <summary>
/// Gets the ID of this log message.
/// </summary>
uint LogMessageId { get; }
/// <summary>
/// Gets the GameData associated with this log message.
/// </summary>
RowRef<Lumina.Excel.Sheets.LogMessage> GameData { get; }
/// <summary>
/// Gets the entity that is the source of this log message, if any.
/// </summary>
ILogMessageEntity? SourceEntity { get; }
/// <summary>
/// Gets the entity that is the target of this log message, if any.
/// </summary>
ILogMessageEntity? TargetEntity { get; }
/// <summary>
/// Gets the number of parameters.
/// </summary>
int ParameterCount { get; }
/// <summary>
/// Retrieves the value of a parameter for the log message if it is an int.
/// </summary>
/// <param name="index">The index of the parameter to retrieve.</param>
/// <param name="value">The value of the parameter.</param>
/// <returns><see langword="true"/> if the parameter was retrieved successfully.</returns>
bool TryGetIntParameter(int index, out int value);
/// <summary>
/// Retrieves the value of a parameter for the log message if it is a string.
/// </summary>
/// <param name="index">The index of the parameter to retrieve.</param>
/// <param name="value">The value of the parameter.</param>
/// <returns><see langword="true"/> if the parameter was retrieved successfully.</returns>
bool TryGetStringParameter(int index, out ReadOnlySeString value);
/// <summary>
/// Formats this log message into an approximation of the string that will eventually be shown in the log.
/// </summary>
/// <remarks>This can cause side effects such as playing sound effects and thus should only be used for debugging.</remarks>
/// <returns>The formatted string.</returns>
ReadOnlySeString FormatLogMessageForDebugging();
}
/// <summary>
/// This struct represents log message in the queue to be added to the chat.
/// </summary>
/// <param name="ptr">A pointer to the log message.</param>
internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessage
{
/// <inheritdoc/>
public nint Address => (nint)ptr;
/// <inheritdoc/>
public uint LogMessageId => ptr->LogMessageId;
/// <inheritdoc/>
public RowRef<Lumina.Excel.Sheets.LogMessage> GameData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.LogMessage>(ptr->LogMessageId);
/// <inheritdoc/>
ILogMessageEntity? ILogMessage.SourceEntity => ptr->SourceKind == EntityRelationKind.None ? null : this.SourceEntity;
/// <inheritdoc/>
ILogMessageEntity? ILogMessage.TargetEntity => ptr->TargetKind == EntityRelationKind.None ? null : this.TargetEntity;
/// <inheritdoc/>
public int ParameterCount => ptr->Parameters.Count;
private LogMessageEntity SourceEntity => new(ptr, true);
private LogMessageEntity TargetEntity => new(ptr, false);
public static bool operator ==(LogMessage x, LogMessage y) => x.Equals(y);
public static bool operator !=(LogMessage x, LogMessage y) => !(x == y);
/// <inheritdoc/>
public bool Equals(ILogMessage? other)
{
return other is LogMessage logMessage && this.Equals(logMessage);
}
/// <inheritdoc/>
public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj is LogMessage logMessage && this.Equals(logMessage);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return HashCode.Combine(this.LogMessageId, this.SourceEntity, this.TargetEntity);
}
/// <inheritdoc/>
public bool TryGetIntParameter(int index, out int value)
{
value = 0;
if (!this.TryGetParameter(index, out var parameter)) return false;
if (parameter.Type != TextParameterType.Integer) return false;
value = parameter.IntValue;
return true;
}
/// <inheritdoc/>
public bool TryGetStringParameter(int index, out ReadOnlySeString value)
{
value = default;
if (!this.TryGetParameter(index, out var parameter)) return false;
if (parameter.Type == TextParameterType.String)
{
value = new(parameter.StringValue.AsSpan());
return true;
}
if (parameter.Type == TextParameterType.ReferencedUtf8String)
{
value = new(parameter.ReferencedUtf8StringValue->Utf8String.AsSpan());
return true;
}
return false;
}
/// <inheritdoc/>
public ReadOnlySeString FormatLogMessageForDebugging()
{
var logModule = RaptureLogModule.Instance();
// the formatting logic is taken from RaptureLogModule_Update
using var utf8 = new Utf8String();
SetName(logModule, this.SourceEntity);
SetName(logModule, this.TargetEntity);
using var rssb = new RentedSeStringBuilder();
logModule->RaptureTextModule->FormatString(rssb.Builder.Append(this.GameData.Value.Text).GetViewAsSpan(), &ptr->Parameters, &utf8);
return new ReadOnlySeString(utf8.AsSpan());
static void SetName(RaptureLogModule* self, LogMessageEntity item)
{
var name = item.NameSpan.GetPointer(0);
if (item.IsPlayer)
{
var str = self->TempParseMessage.GetPointer(item.IsSourceEntity ? 8 : 9);
self->FormatPlayerLink(name, str, null, 0, item.Kind != 1 /* LocalPlayer */, item.HomeWorldId, false, null, false);
if (item.HomeWorldId != 0 && item.HomeWorldId != AgentLobby.Instance()->LobbyData.HomeWorldId)
{
var crossWorldSymbol = self->RaptureTextModule->UnkStrings0.GetPointer(3);
if (!crossWorldSymbol->StringPtr.HasValue)
self->RaptureTextModule->ProcessMacroCode(crossWorldSymbol, "<icon(88)>\0"u8);
str->Append(crossWorldSymbol);
if (self->UIModule->GetWorldHelper()->AllWorlds.TryGetValuePointer(item.HomeWorldId, out var world))
str->ConcatCStr(world->Name);
}
name = str->StringPtr;
}
if (item.IsSourceEntity)
{
self->RaptureTextModule->SetGlobalTempEntity1(name, item.Sex, item.ObjStrId);
}
else
{
self->RaptureTextModule->SetGlobalTempEntity2(name, item.Sex, item.ObjStrId);
}
}
}
private bool TryGetParameter(int index, out TextParameter value)
{
if (index < 0 || index >= ptr->Parameters.Count)
{
value = default;
return false;
}
value = ptr->Parameters[index];
return true;
}
private bool Equals(LogMessage other)
{
return this.LogMessageId == other.LogMessageId && this.SourceEntity == other.SourceEntity && this.TargetEntity == other.TargetEntity;
}
}

View file

@ -0,0 +1,113 @@
using System.Diagnostics.CodeAnalysis;
using Dalamud.Data;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Lumina.Text.ReadOnly;
namespace Dalamud.Game.Chat;
/// <summary>
/// Interface representing an entity related to a log message.
/// </summary>
public interface ILogMessageEntity : IEquatable<ILogMessageEntity>
{
/// <summary>
/// Gets the name of this entity.
/// </summary>
ReadOnlySeString Name { get; }
/// <summary>
/// Gets the ID of the homeworld of this entity, if it is a player.
/// </summary>
ushort HomeWorldId { get; }
/// <summary>
/// Gets the homeworld of this entity, if it is a player.
/// </summary>
RowRef<World> HomeWorld { get; }
/// <summary>
/// Gets the ObjStr ID of this entity, if not a player. See <seealso cref="ISeStringEvaluator.EvaluateObjStr"/>.
/// </summary>
uint ObjStrId { get; }
/// <summary>
/// Gets a value indicating whether this entity is a player.
/// </summary>
bool IsPlayer { get; }
}
/// <summary>
/// This struct represents an entity related to a log message.
/// </summary>
/// <param name="ptr">A pointer to the log message item.</param>
/// <param name="source">If <see langword="true"/> represents the source entity of the log message, otherwise represents the target entity.</param>
internal unsafe readonly struct LogMessageEntity(LogMessageQueueItem* ptr, bool source) : ILogMessageEntity
{
/// <inheritdoc/>
public ReadOnlySeString Name => new(this.NameSpan[..this.NameSpan.IndexOf((byte)0)]);
/// <inheritdoc/>
public ushort HomeWorldId => source ? ptr->SourceHomeWorld : ptr->TargetHomeWorld;
/// <inheritdoc/>
public RowRef<World> HomeWorld => LuminaUtils.CreateRef<World>(this.HomeWorldId);
/// <inheritdoc/>
public uint ObjStrId => source ? ptr->SourceObjStrId : ptr->TargetObjStrId;
/// <inheritdoc/>
public bool IsPlayer => source ? ptr->SourceIsPlayer : ptr->TargetIsPlayer;
/// <summary>
/// Gets the Span containing the raw name of this entity.
/// </summary>
internal Span<byte> NameSpan => source ? ptr->SourceName : ptr->TargetName;
/// <summary>
/// Gets the kind of the entity.
/// </summary>
internal byte Kind => source ? (byte)ptr->SourceKind : (byte)ptr->TargetKind;
/// <summary>
/// Gets the Sex of this entity.
/// </summary>
internal byte Sex => source ? ptr->SourceSex : ptr->TargetSex;
/// <summary>
/// Gets a value indicating whether this entity is the source entity of a log message.
/// </summary>
internal bool IsSourceEntity => source;
public static bool operator ==(LogMessageEntity x, LogMessageEntity y) => x.Equals(y);
public static bool operator !=(LogMessageEntity x, LogMessageEntity y) => !(x == y);
/// <inheritdoc/>
public bool Equals(ILogMessageEntity other)
{
return other is LogMessageEntity entity && this.Equals(entity);
}
/// <inheritdoc/>
public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj is LogMessageEntity entity && this.Equals(entity);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return HashCode.Combine(this.Name, this.HomeWorldId, this.ObjStrId, this.Sex, this.IsPlayer);
}
private bool Equals(LogMessageEntity other)
{
return this.Name == other.Name && this.HomeWorldId == other.HomeWorldId && this.ObjStrId == other.ObjStrId && this.Kind == other.Kind && this.Sex == other.Sex && this.IsPlayer == other.IsPlayer;
}
}

View file

@ -1,5 +1,4 @@
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using CheapLoc;
@ -23,7 +22,7 @@ namespace Dalamud.Game;
[ServiceManager.EarlyLoadedService]
internal partial class ChatHandlers : IServiceType
{
private static readonly ModuleLog Log = new("ChatHandlers");
private static readonly ModuleLog Log = ModuleLog.Create<ChatHandlers>();
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();

View file

@ -8,6 +8,7 @@ using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using Serilog;
namespace Dalamud.Game.ClientState.Aetherytes;

View file

@ -33,7 +33,7 @@ namespace Dalamud.Game.ClientState;
[ServiceManager.EarlyLoadedService]
internal sealed class ClientState : IInternalDisposableService, IClientState
{
private static readonly ModuleLog Log = new("ClientState");
private static readonly ModuleLog Log = ModuleLog.Create<ClientState>();
private readonly GameLifecycle lifecycle;
private readonly ClientStateAddressResolver address;

View file

@ -5,7 +5,9 @@ using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.System.Input;
using Serilog;
namespace Dalamud.Game.ClientState.GamePad;

View file

@ -37,7 +37,7 @@ internal class JobGauges : IServiceType, IJobGauges
// Since the gauge itself reads from live memory, there isn't much downside to doing this.
if (!this.cache.TryGetValue(typeof(T), out var gauge))
{
gauge = this.cache[typeof(T)] = (T)Activator.CreateInstance(typeof(T), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.Address }, null);
gauge = this.cache[typeof(T)] = (T)Activator.CreateInstance(typeof(T), BindingFlags.NonPublic | BindingFlags.Instance, null, [this.Address], null);
}
return (T)gauge;

View file

@ -1,4 +1,5 @@
using Dalamud.Game.ClientState.JobGauge.Enums;
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
namespace Dalamud.Game.ClientState.JobGauge.Types;
@ -82,12 +83,12 @@ public unsafe class BRDGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
{
get
{
return new[]
{
return
[
this.Struct->SongFlags.HasFlag(SongFlags.MagesBalladCoda) ? Song.Mage : Song.None,
this.Struct->SongFlags.HasFlag(SongFlags.ArmysPaeonCoda) ? Song.Army : Song.None,
this.Struct->SongFlags.HasFlag(SongFlags.WanderersMinuetCoda) ? Song.Wanderer : Song.None,
};
];
}
}
}

View file

@ -1,4 +1,5 @@
using Dalamud.Game.ClientState.JobGauge.Enums;
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
namespace Dalamud.Game.ClientState.JobGauge.Types;

View file

@ -1,4 +1,4 @@
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
using CanvasFlags = Dalamud.Game.ClientState.JobGauge.Enums.CanvasFlags;
using CreatureFlags = Dalamud.Game.ClientState.JobGauge.Enums.CreatureFlags;
@ -22,45 +22,45 @@ public unsafe class PCTGauge : JobGaugeBase<PictomancerGauge>
/// <summary>
/// Gets the use of subjective pallete.
/// </summary>
public byte PalleteGauge => Struct->PalleteGauge;
public byte PalleteGauge => this.Struct->PalleteGauge;
/// <summary>
/// Gets the amount of paint the player has.
/// </summary>
public byte Paint => Struct->Paint;
public byte Paint => this.Struct->Paint;
/// <summary>
/// Gets a value indicating whether a creature motif is drawn.
/// </summary>
public bool CreatureMotifDrawn => Struct->CreatureMotifDrawn;
public bool CreatureMotifDrawn => this.Struct->CreatureMotifDrawn;
/// <summary>
/// Gets a value indicating whether a weapon motif is drawn.
/// </summary>
public bool WeaponMotifDrawn => Struct->WeaponMotifDrawn;
public bool WeaponMotifDrawn => this.Struct->WeaponMotifDrawn;
/// <summary>
/// Gets a value indicating whether a landscape motif is drawn.
/// </summary>
public bool LandscapeMotifDrawn => Struct->LandscapeMotifDrawn;
public bool LandscapeMotifDrawn => this.Struct->LandscapeMotifDrawn;
/// <summary>
/// Gets a value indicating whether a moogle portrait is ready.
/// </summary>
public bool MooglePortraitReady => Struct->MooglePortraitReady;
public bool MooglePortraitReady => this.Struct->MooglePortraitReady;
/// <summary>
/// Gets a value indicating whether a madeen portrait is ready.
/// </summary>
public bool MadeenPortraitReady => Struct->MadeenPortraitReady;
public bool MadeenPortraitReady => this.Struct->MadeenPortraitReady;
/// <summary>
/// Gets which creature flags are present.
/// </summary>
public CreatureFlags CreatureFlags => (CreatureFlags)Struct->CreatureFlags;
public CreatureFlags CreatureFlags => (CreatureFlags)this.Struct->CreatureFlags;
/// <summary>
/// Gets which canvas flags are present.
/// </summary>
public CanvasFlags CanvasFlags => (CanvasFlags)Struct->CanvasFlags;
public CanvasFlags CanvasFlags => (CanvasFlags)this.Struct->CanvasFlags;
}

View file

@ -1,4 +1,5 @@
using Dalamud.Game.ClientState.JobGauge.Enums;
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
namespace Dalamud.Game.ClientState.JobGauge.Types;

View file

@ -1,7 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
using Reloaded.Memory;
using DreadCombo = Dalamud.Game.ClientState.JobGauge.Enums.DreadCombo;
using SerpentCombo = Dalamud.Game.ClientState.JobGauge.Enums.SerpentCombo;
@ -24,25 +22,25 @@ public unsafe class VPRGauge : JobGaugeBase<ViperGauge>
/// <summary>
/// Gets how many uses of uncoiled fury the player has.
/// </summary>
public byte RattlingCoilStacks => Struct->RattlingCoilStacks;
public byte RattlingCoilStacks => this.Struct->RattlingCoilStacks;
/// <summary>
/// Gets Serpent Offering stacks and gauge.
/// </summary>
public byte SerpentOffering => Struct->SerpentOffering;
public byte SerpentOffering => this.Struct->SerpentOffering;
/// <summary>
/// Gets value indicating the use of 1st, 2nd, 3rd, 4th generation and Ouroboros.
/// </summary>
public byte AnguineTribute => Struct->AnguineTribute;
public byte AnguineTribute => this.Struct->AnguineTribute;
/// <summary>
/// Gets the last Weaponskill used in DreadWinder/Pit of Dread combo.
/// </summary>
public DreadCombo DreadCombo => (DreadCombo)Struct->DreadCombo;
public DreadCombo DreadCombo => (DreadCombo)this.Struct->DreadCombo;
/// <summary>
/// Gets current ability for Serpent's Tail.
/// </summary>
public SerpentCombo SerpentCombo => (SerpentCombo)Struct->SerpentCombo;
public SerpentCombo SerpentCombo => (SerpentCombo)this.Struct->SerpentCombo;
}

View file

@ -30,50 +30,50 @@ internal sealed unsafe class TargetManager : IServiceType, ITargetManager
/// <inheritdoc/>
public IGameObject? Target
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->GetHardTarget());
set => Struct->SetHardTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address);
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->GetHardTarget());
set => this.Struct->SetHardTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address);
}
/// <inheritdoc/>
public IGameObject? MouseOverTarget
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->MouseOverTarget);
set => Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->MouseOverTarget);
set => this.Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
}
/// <inheritdoc/>
public IGameObject? FocusTarget
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->FocusTarget);
set => Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->FocusTarget);
set => this.Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
}
/// <inheritdoc/>
public IGameObject? PreviousTarget
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->PreviousTarget);
set => Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->PreviousTarget);
set => this.Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
}
/// <inheritdoc/>
public IGameObject? SoftTarget
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->GetSoftTarget());
set => Struct->SetSoftTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address);
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->GetSoftTarget());
set => this.Struct->SetSoftTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address);
}
/// <inheritdoc/>
public IGameObject? GPoseTarget
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->GPoseTarget);
set => Struct->GPoseTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->GPoseTarget);
set => this.Struct->GPoseTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
}
/// <inheritdoc/>
public IGameObject? MouseOverNameplateTarget
{
get => this.objectTable.CreateObjectReference((IntPtr)Struct->MouseOverNameplateTarget);
set => Struct->MouseOverNameplateTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->MouseOverNameplateTarget);
set => this.Struct->MouseOverNameplateTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
}
private TargetSystem* Struct => TargetSystem.Instance();

View file

@ -1,5 +1,4 @@
using Dalamud.Game.ClientState.Statuses;
using Dalamud.Utility;
namespace Dalamud.Game.ClientState.Objects.Types;

View file

@ -1,9 +1,6 @@
using System.Runtime.CompilerServices;
using Dalamud.Data;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Memory;
using Lumina.Excel;
using Lumina.Excel.Sheets;

View file

@ -47,7 +47,7 @@ internal sealed unsafe partial class PartyList : IServiceType, IPartyList
public unsafe nint GroupManagerAddress => (nint)CSGroupManager.Instance();
/// <inheritdoc/>
public nint GroupListAddress => (nint)Unsafe.AsPointer(ref GroupManagerStruct->MainGroup.PartyMembers[0]);
public nint GroupListAddress => (nint)Unsafe.AsPointer(ref this.GroupManagerStruct->MainGroup.PartyMembers[0]);
/// <inheritdoc/>
public nint AllianceListAddress => (nint)Unsafe.AsPointer(ref this.GroupManagerStruct->MainGroup.AllianceMembers[0]);

View file

@ -6,6 +6,7 @@ using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.ClientState.Statuses;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Utility;
using Lumina.Excel;

View file

@ -38,7 +38,7 @@ public sealed unsafe partial class StatusList
/// <summary>
/// Gets the amount of status effect slots the actor has.
/// </summary>
public int Length => Struct->NumValidStatuses;
public int Length => this.Struct->NumValidStatuses;
private static int StatusSize { get; } = Marshal.SizeOf<FFXIVClientStructs.FFXIV.Client.Game.Status>();

View file

@ -24,7 +24,7 @@ namespace Dalamud.Game.Command;
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class CommandManager : IInternalDisposableService, ICommandManager
{
private static readonly ModuleLog Log = new("Command");
private static readonly ModuleLog Log = ModuleLog.Create<CommandManager>();
private readonly ConcurrentDictionary<string, IReadOnlyCommandInfo> commandMap = new();
private readonly ConcurrentDictionary<(string, IReadOnlyCommandInfo), string> commandAssemblyNameMap = new();
@ -71,7 +71,7 @@ internal sealed unsafe class CommandManager : IInternalDisposableService, IComma
if (separatorPosition + 1 >= content.Length)
{
// Remove the trailing space
command = content.Substring(0, separatorPosition);
command = content[..separatorPosition];
}
else
{
@ -262,12 +262,12 @@ internal sealed unsafe class CommandManager : IInternalDisposableService, IComma
#pragma warning restore SA1015
internal class CommandManagerPluginScoped : IInternalDisposableService, ICommandManager
{
private static readonly ModuleLog Log = new("Command");
private static readonly ModuleLog Log = ModuleLog.Create<CommandManager>();
[ServiceManager.ServiceDependency]
private readonly CommandManager commandManagerService = Service<CommandManager>.Get();
private readonly List<string> pluginRegisteredCommands = new();
private readonly List<string> pluginRegisteredCommands = [];
private readonly LocalPlugin pluginInfo;
/// <summary>

View file

@ -1,11 +1,13 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Common.Configuration;
using Serilog;
namespace Dalamud.Game.Config;

View file

@ -1,10 +1,12 @@
using System.Collections.Concurrent;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
using Dalamud.Memory;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Common.Configuration;
using Serilog;
namespace Dalamud.Game.Config;

View file

@ -26,7 +26,7 @@ namespace Dalamud.Game;
[ServiceManager.EarlyLoadedService]
internal sealed class Framework : IInternalDisposableService, IFramework
{
private static readonly ModuleLog Log = new("Framework");
private static readonly ModuleLog Log = ModuleLog.Create<Framework>();
private static readonly Stopwatch StatsStopwatch = new();
@ -86,7 +86,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework
/// <summary>
/// Gets the stats history mapping.
/// </summary>
public static Dictionary<string, List<double>> StatsHistory { get; } = new();
public static Dictionary<string, List<double>> StatsHistory { get; } = [];
/// <inheritdoc/>
public DateTime LastUpdate { get; private set; } = DateTime.MinValue;
@ -106,7 +106,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework
/// <summary>
/// Gets the list of update sub-delegates that didn't get updated this frame.
/// </summary>
internal List<string> NonUpdatedSubDelegates { get; private set; } = new();
internal List<string> NonUpdatedSubDelegates { get; private set; } = [];
/// <summary>
/// Gets or sets a value indicating whether to dispatch update events.
@ -212,11 +212,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework
if (cancellationToken == default)
cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken;
return this.FrameworkThreadTaskFactory.ContinueWhenAll(
new[]
{
[
Task.Delay(delay, cancellationToken),
this.DelayTicks(delayTicks, cancellationToken),
},
],
_ => func(),
cancellationToken,
TaskContinuationOptions.HideScheduler,
@ -239,11 +238,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework
if (cancellationToken == default)
cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken;
return this.FrameworkThreadTaskFactory.ContinueWhenAll(
new[]
{
[
Task.Delay(delay, cancellationToken),
this.DelayTicks(delayTicks, cancellationToken),
},
],
_ => action(),
cancellationToken,
TaskContinuationOptions.HideScheduler,
@ -266,11 +264,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework
if (cancellationToken == default)
cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken;
return this.FrameworkThreadTaskFactory.ContinueWhenAll(
new[]
{
[
Task.Delay(delay, cancellationToken),
this.DelayTicks(delayTicks, cancellationToken),
},
],
_ => func(),
cancellationToken,
TaskContinuationOptions.HideScheduler,
@ -293,11 +290,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework
if (cancellationToken == default)
cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken;
return this.FrameworkThreadTaskFactory.ContinueWhenAll(
new[]
{
[
Task.Delay(delay, cancellationToken),
this.DelayTicks(delayTicks, cancellationToken),
},
],
_ => func(),
cancellationToken,
TaskContinuationOptions.HideScheduler,
@ -333,7 +329,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework
internal static void AddToStats(string key, double ms)
{
if (!StatsHistory.ContainsKey(key))
StatsHistory.Add(key, new List<double>());
StatsHistory.Add(key, []);
StatsHistory[key].Add(ms);

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Dalamud.Configuration.Internal;
@ -37,14 +38,16 @@ namespace Dalamud.Game.Gui;
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
{
private static readonly ModuleLog Log = new("ChatGui");
private static readonly ModuleLog Log = ModuleLog.Create<ChatGui>();
private readonly Queue<XivChatEntry> chatQueue = new();
private readonly Dictionary<(string PluginName, uint CommandId), Action<uint, SeString>> dalamudLinkHandlers = new();
private readonly Dictionary<(string PluginName, uint CommandId), Action<uint, SeString>> dalamudLinkHandlers = [];
private readonly List<nint> seenLogMessageObjects = [];
private readonly Hook<PrintMessageDelegate> printMessageHook;
private readonly Hook<InventoryItem.Delegates.Copy> inventoryItemCopyHook;
private readonly Hook<LogViewer.Delegates.HandleLinkClick> handleLinkClickHook;
private readonly Hook<RaptureLogModule.Delegates.Update> handleLogModuleUpdate;
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
@ -58,10 +61,12 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
this.printMessageHook = Hook<PrintMessageDelegate>.FromAddress(RaptureLogModule.Addresses.PrintMessage.Value, this.HandlePrintMessageDetour);
this.inventoryItemCopyHook = Hook<InventoryItem.Delegates.Copy>.FromAddress((nint)InventoryItem.StaticVirtualTablePointer->Copy, this.InventoryItemCopyDetour);
this.handleLinkClickHook = Hook<LogViewer.Delegates.HandleLinkClick>.FromAddress(LogViewer.Addresses.HandleLinkClick.Value, this.HandleLinkClickDetour);
this.handleLogModuleUpdate = Hook<RaptureLogModule.Delegates.Update>.FromAddress(RaptureLogModule.Addresses.Update.Value, this.UpdateDetour);
this.printMessageHook.Enable();
this.inventoryItemCopyHook.Enable();
this.handleLinkClickHook.Enable();
this.handleLogModuleUpdate.Enable();
}
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
@ -79,6 +84,9 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
/// <inheritdoc/>
public event IChatGui.OnMessageUnhandledDelegate? ChatMessageUnhandled;
/// <inheritdoc/>
public event IChatGui.OnLogMessageDelegate? LogMessage;
/// <inheritdoc/>
public uint LastLinkedItemId { get; private set; }
@ -110,6 +118,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
this.printMessageHook.Dispose();
this.inventoryItemCopyHook.Dispose();
this.handleLinkClickHook.Dispose();
this.handleLogModuleUpdate.Dispose();
}
#region DalamudSeString
@ -493,6 +502,46 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
Log.Error(ex, "Exception in HandleLinkClickDetour");
}
}
private void UpdateDetour(RaptureLogModule* thisPtr)
{
try
{
foreach (ref var item in thisPtr->LogMessageQueue)
{
var logMessage = new Chat.LogMessage((LogMessageQueueItem*)Unsafe.AsPointer(ref item));
// skip any entries that survived the previous Update call as the event was already called for them
if (this.seenLogMessageObjects.Contains(logMessage.Address))
continue;
foreach (var action in Delegate.EnumerateInvocationList(this.LogMessage))
{
try
{
action(logMessage);
}
catch (Exception e)
{
Log.Error(e, "Could not invoke registered OnLogMessageDelegate for {Name}", action.Method);
}
}
}
this.handleLogModuleUpdate.Original(thisPtr);
// record the log messages for that we already called the event, but are still in the queue
this.seenLogMessageObjects.Clear();
foreach (ref var item in thisPtr->LogMessageQueue)
{
this.seenLogMessageObjects.Add((nint)Unsafe.AsPointer(ref item));
}
}
catch (Exception ex)
{
Log.Error(ex, "Exception in UpdateDetour");
}
}
}
/// <summary>
@ -521,6 +570,7 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
this.chatGuiService.CheckMessageHandled += this.OnCheckMessageForward;
this.chatGuiService.ChatMessageHandled += this.OnMessageHandledForward;
this.chatGuiService.ChatMessageUnhandled += this.OnMessageUnhandledForward;
this.chatGuiService.LogMessage += this.OnLogMessageForward;
}
/// <inheritdoc/>
@ -535,6 +585,9 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
/// <inheritdoc/>
public event IChatGui.OnMessageUnhandledDelegate? ChatMessageUnhandled;
/// <inheritdoc/>
public event IChatGui.OnLogMessageDelegate? LogMessage;
/// <inheritdoc/>
public uint LastLinkedItemId => this.chatGuiService.LastLinkedItemId;
@ -551,11 +604,13 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
this.chatGuiService.CheckMessageHandled -= this.OnCheckMessageForward;
this.chatGuiService.ChatMessageHandled -= this.OnMessageHandledForward;
this.chatGuiService.ChatMessageUnhandled -= this.OnMessageUnhandledForward;
this.chatGuiService.LogMessage -= this.OnLogMessageForward;
this.ChatMessage = null;
this.CheckMessageHandled = null;
this.ChatMessageHandled = null;
this.ChatMessageUnhandled = null;
this.LogMessage = null;
}
/// <inheritdoc/>
@ -609,4 +664,7 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
private void OnMessageUnhandledForward(XivChatType type, int timestamp, SeString sender, SeString message)
=> this.ChatMessageUnhandled?.Invoke(type, timestamp, sender, message);
private void OnLogMessageForward(Chat.ILogMessage message)
=> this.LogMessage?.Invoke(message);
}

View file

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
@ -28,7 +29,7 @@ namespace Dalamud.Game.Gui.ContextMenu;
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextMenu
{
private static readonly ModuleLog Log = new("ContextMenu");
private static readonly ModuleLog Log = ModuleLog.Create<ContextMenu>();
private readonly Hook<AtkModuleVf22OpenAddonByAgentDelegate> atkModuleVf22OpenAddonByAgentHook;
private readonly Hook<AddonContextMenu.Delegates.OnMenuSelected> addonContextMenuOnMenuSelectedHook;
@ -53,7 +54,7 @@ internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextM
private Dictionary<ContextMenuType, List<IMenuItem>> MenuItems { get; } = [];
private object MenuItemsLock { get; } = new();
private Lock MenuItemsLock { get; } = new();
private AgentInterface* SelectedAgent { get; set; }

View file

@ -1,6 +1,5 @@
using System.Collections.Generic;
using Dalamud.Memory;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;

View file

@ -30,7 +30,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
{
private const uint BaseNodeId = 1000;
private static readonly ModuleLog Log = new("DtrBar");
private static readonly ModuleLog Log = ModuleLog.Create<DtrBar>();
[ServiceManager.ServiceDependency]
private readonly Framework framework = Service<Framework>.Get();
@ -54,7 +54,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
private readonly ReaderWriterLockSlim entriesLock = new();
private readonly List<DtrBarEntry> entries = [];
private readonly Dictionary<uint, List<IAddonEventHandle>> eventHandles = new();
private readonly Dictionary<uint, List<IAddonEventHandle>> eventHandles = [];
private ImmutableList<IReadOnlyDtrBarEntry>? entriesReadOnlyCopy;
@ -516,7 +516,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
var node = data.TextNode = this.MakeNode(++this.runningNodeIds);
this.eventHandles.TryAdd(node->NodeId, new List<IAddonEventHandle>());
this.eventHandles.TryAdd(node->NodeId, []);
this.eventHandles[node->NodeId].AddRange(new List<IAddonEventHandle>
{
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseOver, this.DtrEventHandler),

View file

@ -1,7 +1,6 @@
using System.Numerics;
using System.Numerics;
using Dalamud.Configuration.Internal;
using Dalamud.Game.Addon.Events.EventDataTypes;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Utility;

View file

@ -32,7 +32,7 @@ namespace Dalamud.Game.Gui;
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
{
private static readonly ModuleLog Log = new("GameGui");
private static readonly ModuleLog Log = ModuleLog.Create<GameGui>();
private readonly GameGuiAddressResolver address;

View file

@ -427,8 +427,8 @@ internal unsafe class NamePlateUpdateHandler : INamePlateUpdateHandler
/// <inheritdoc/>
public int VisibilityFlags
{
get => ObjectData->VisibilityFlags;
set => ObjectData->VisibilityFlags = value;
get => this.ObjectData->VisibilityFlags;
set => this.ObjectData->VisibilityFlags = value;
}
/// <inheritdoc/>

View file

@ -1,4 +1,5 @@
using Dalamud.Plugin.Services;
using Lumina.Excel.Sheets;
namespace Dalamud.Game.Gui.PartyFinder.Types;

View file

@ -23,23 +23,7 @@ public class PartyFinderSlot
/// <summary>
/// Gets a list of jobs that this slot is accepting.
/// </summary>
public IReadOnlyCollection<JobFlags> Accepting
{
get
{
if (this.listAccepting != null)
{
return this.listAccepting;
}
this.listAccepting = Enum.GetValues(typeof(JobFlags))
.Cast<JobFlags>()
.Where(flag => this[flag])
.ToArray();
return this.listAccepting;
}
}
public IReadOnlyCollection<JobFlags> Accepting => this.listAccepting ??= Enum.GetValues<JobFlags>().Where(flag => this[flag]).ToArray();
/// <summary>
/// Tests if this slot is accepting a job.

View file

@ -22,7 +22,7 @@ namespace Dalamud.Game.Internal;
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
{
private static readonly ModuleLog Log = new("DalamudAtkTweaks");
private static readonly ModuleLog Log = ModuleLog.Create<DalamudAtkTweaks>();
private readonly Hook<AgentHUD.Delegates.OpenSystemMenu> hookAgentHudOpenSystemMenu;

View file

@ -18,15 +18,15 @@ namespace Dalamud.Game.Inventory;
[ServiceManager.EarlyLoadedService]
internal class GameInventory : IInternalDisposableService
{
private readonly List<GameInventoryPluginScoped> subscribersPendingChange = new();
private readonly List<GameInventoryPluginScoped> subscribers = new();
private readonly List<GameInventoryPluginScoped> subscribersPendingChange = [];
private readonly List<GameInventoryPluginScoped> subscribers = [];
private readonly List<InventoryItemAddedArgs> addedEvents = new();
private readonly List<InventoryItemRemovedArgs> removedEvents = new();
private readonly List<InventoryItemChangedArgs> changedEvents = new();
private readonly List<InventoryItemMovedArgs> movedEvents = new();
private readonly List<InventoryItemSplitArgs> splitEvents = new();
private readonly List<InventoryItemMergedArgs> mergedEvents = new();
private readonly List<InventoryItemAddedArgs> addedEvents = [];
private readonly List<InventoryItemRemovedArgs> removedEvents = [];
private readonly List<InventoryItemChangedArgs> changedEvents = [];
private readonly List<InventoryItemMovedArgs> movedEvents = [];
private readonly List<InventoryItemSplitArgs> splitEvents = [];
private readonly List<InventoryItemMergedArgs> mergedEvents = [];
[ServiceManager.ServiceDependency]
private readonly Framework framework = Service<Framework>.Get();
@ -151,7 +151,7 @@ internal class GameInventory : IInternalDisposableService
bool isNew;
lock (this.subscribersPendingChange)
{
isNew = this.subscribersPendingChange.Any() && !this.subscribers.Any();
isNew = this.subscribersPendingChange.Count != 0 && this.subscribers.Count == 0;
this.subscribers.Clear();
this.subscribers.AddRange(this.subscribersPendingChange);
this.subscribersChanged = false;
@ -348,7 +348,7 @@ internal class GameInventory : IInternalDisposableService
#pragma warning restore SA1015
internal class GameInventoryPluginScoped : IInternalDisposableService, IGameInventory
{
private static readonly ModuleLog Log = new(nameof(GameInventoryPluginScoped));
private static readonly ModuleLog Log = ModuleLog.Create<GameInventoryPluginScoped>();
[ServiceManager.ServiceDependency]
private readonly GameInventory gameInventoryService = Service<GameInventory>.Get();

View file

@ -1,5 +1,3 @@
using System.Linq;
using Dalamud.Game.Network.Internal;
using Dalamud.Game.Network.Structures;
using Dalamud.IoC;
@ -95,7 +93,7 @@ internal class MarketBoard : IInternalDisposableService, IMarketBoard
#pragma warning restore SA1015
internal class MarketBoardPluginScoped : IInternalDisposableService, IMarketBoard
{
private static readonly ModuleLog Log = new(nameof(MarketBoardPluginScoped));
private static readonly ModuleLog Log = ModuleLog.Create<MarketBoardPluginScoped>();
[ServiceManager.ServiceDependency]
private readonly MarketBoard marketBoardService = Service<MarketBoard>.Get();

View file

@ -89,7 +89,7 @@ public readonly unsafe struct AtkValuePtr(nint address) : IEquatable<AtkValuePtr
/// </returns>
public unsafe bool TryGet<T>([NotNullWhen(true)] out T? result) where T : struct
{
object? value = this.GetValue();
var value = this.GetValue();
if (value is T typed)
{
result = typed;

View file

@ -2,9 +2,6 @@ using System.Runtime.InteropServices;
using Dalamud.Configuration.Internal;
using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Network;

View file

@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
@ -8,6 +7,7 @@ using Dalamud.Game.Network.Structures;
using Dalamud.Networking.Http;
using Newtonsoft.Json;
using Serilog;
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis;
@ -64,7 +64,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader
PricePerUnit = marketBoardItemListing.PricePerUnit,
Quantity = marketBoardItemListing.ItemQuantity,
RetainerCity = marketBoardItemListing.RetainerCityId,
Materia = new List<UniversalisItemMateria>(),
Materia = [],
};
#pragma warning restore CS0618 // Type or member is obsolete

View file

@ -33,7 +33,7 @@ namespace Dalamud.Game.Network.Internal;
[ServiceManager.EarlyLoadedService]
internal unsafe class NetworkHandlers : IInternalDisposableService
{
private readonly IMarketBoardUploader uploader;
private readonly UniversalisMarketBoardUploader uploader;
private readonly IDisposable handleMarketBoardItemRequest;
private readonly IDisposable handleMarketTaxRates;
@ -419,7 +419,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private IDisposable HandleMarketBoardItemRequest()
{
void LogStartObserved(MarketBoardItemRequest request)
static void LogStartObserved(MarketBoardItemRequest request)
{
Log.Verbose("Observed start of request for item with {NumListings} expected listings", request.AmountToArrive);
}
@ -448,7 +448,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private void UploadMarketBoardData(
MarketBoardItemRequest request,
(uint CatalogId, ICollection<MarketBoardHistory.MarketBoardHistoryListing> Sales) sales,
ICollection<MarketBoardCurrentOfferings.MarketBoardItemListing> listings,
List<MarketBoardCurrentOfferings.MarketBoardItemListing> listings,
ulong uploaderId,
uint worldId)
{

View file

@ -11,7 +11,9 @@ using System.Threading;
using Dalamud.Plugin.Services;
using Iced.Intel;
using Newtonsoft.Json;
using Serilog;
namespace Dalamud.Game;

View file

@ -48,7 +48,7 @@ namespace Dalamud.Game.Text.Evaluator;
[ResolveVia<ISeStringEvaluator>]
internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
{
private static readonly ModuleLog Log = new("SeStringEvaluator");
private static readonly ModuleLog Log = ModuleLog.Create<SeStringEvaluator>();
[ServiceManager.ServiceDependency]
private readonly ClientState.ClientState clientState = Service<ClientState.ClientState>.Get();
@ -244,154 +244,67 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
// if (context.HandlePayload(payload, in context))
// return true;
switch (payload.MacroCode)
return payload.MacroCode switch
{
case MacroCode.SetResetTime:
return this.TryResolveSetResetTime(in context, payload);
case MacroCode.SetTime:
return this.TryResolveSetTime(in context, payload);
case MacroCode.If:
return this.TryResolveIf(in context, payload);
case MacroCode.Switch:
return this.TryResolveSwitch(in context, payload);
case MacroCode.SwitchPlatform:
return this.TryResolveSwitchPlatform(in context, payload);
case MacroCode.PcName:
return this.TryResolvePcName(in context, payload);
case MacroCode.IfPcGender:
return this.TryResolveIfPcGender(in context, payload);
case MacroCode.IfPcName:
return this.TryResolveIfPcName(in context, payload);
// case MacroCode.Josa:
// case MacroCode.Josaro:
case MacroCode.IfSelf:
return this.TryResolveIfSelf(in context, payload);
// case MacroCode.NewLine: // pass through
// case MacroCode.Wait: // pass through
// case MacroCode.Icon: // pass through
case MacroCode.Color:
return this.TryResolveColor(in context, payload);
case MacroCode.EdgeColor:
return this.TryResolveEdgeColor(in context, payload);
case MacroCode.ShadowColor:
return this.TryResolveShadowColor(in context, payload);
// case MacroCode.SoftHyphen: // pass through
// case MacroCode.Key:
// case MacroCode.Scale:
case MacroCode.Bold:
return this.TryResolveBold(in context, payload);
case MacroCode.Italic:
return this.TryResolveItalic(in context, payload);
// case MacroCode.Edge:
// case MacroCode.Shadow:
// case MacroCode.NonBreakingSpace: // pass through
// case MacroCode.Icon2: // pass through
// case MacroCode.Hyphen: // pass through
case MacroCode.Num:
return this.TryResolveNum(in context, payload);
case MacroCode.Hex:
return this.TryResolveHex(in context, payload);
case MacroCode.Kilo:
return this.TryResolveKilo(in context, payload);
// case MacroCode.Byte:
case MacroCode.Sec:
return this.TryResolveSec(in context, payload);
// case MacroCode.Time:
case MacroCode.Float:
return this.TryResolveFloat(in context, payload);
// case MacroCode.Link: // pass through
case MacroCode.Sheet:
return this.TryResolveSheet(in context, payload);
case MacroCode.SheetSub:
return this.TryResolveSheetSub(in context, payload);
case MacroCode.String:
return this.TryResolveString(in context, payload);
case MacroCode.Caps:
return this.TryResolveCaps(in context, payload);
case MacroCode.Head:
return this.TryResolveHead(in context, payload);
case MacroCode.Split:
return this.TryResolveSplit(in context, payload);
case MacroCode.HeadAll:
return this.TryResolveHeadAll(in context, payload);
case MacroCode.Fixed:
return this.TryResolveFixed(in context, payload);
case MacroCode.Lower:
return this.TryResolveLower(in context, payload);
case MacroCode.JaNoun:
return this.TryResolveNoun(ClientLanguage.Japanese, in context, payload);
case MacroCode.EnNoun:
return this.TryResolveNoun(ClientLanguage.English, in context, payload);
case MacroCode.DeNoun:
return this.TryResolveNoun(ClientLanguage.German, in context, payload);
case MacroCode.FrNoun:
return this.TryResolveNoun(ClientLanguage.French, in context, payload);
// case MacroCode.ChNoun:
case MacroCode.LowerHead:
return this.TryResolveLowerHead(in context, payload);
case MacroCode.ColorType:
return this.TryResolveColorType(in context, payload);
case MacroCode.EdgeColorType:
return this.TryResolveEdgeColorType(in context, payload);
// case MacroCode.Ruby:
case MacroCode.Digit:
return this.TryResolveDigit(in context, payload);
case MacroCode.Ordinal:
return this.TryResolveOrdinal(in context, payload);
// case MacroCode.Sound: // pass through
case MacroCode.LevelPos:
return this.TryResolveLevelPos(in context, payload);
default:
return false;
}
MacroCode.SetResetTime => this.TryResolveSetResetTime(in context, payload),
MacroCode.SetTime => this.TryResolveSetTime(in context, payload),
MacroCode.If => this.TryResolveIf(in context, payload),
MacroCode.Switch => this.TryResolveSwitch(in context, payload),
MacroCode.SwitchPlatform => this.TryResolveSwitchPlatform(in context, payload),
MacroCode.PcName => this.TryResolvePcName(in context, payload),
MacroCode.IfPcGender => this.TryResolveIfPcGender(in context, payload),
MacroCode.IfPcName => this.TryResolveIfPcName(in context, payload),
// MacroCode.Josa
// MacroCode.Josaro
MacroCode.IfSelf => this.TryResolveIfSelf(in context, payload),
// MacroCode.NewLine (pass through)
// MacroCode.Wait (pass through)
// MacroCode.Icon (pass through)
MacroCode.Color => this.TryResolveColor(in context, payload),
MacroCode.EdgeColor => this.TryResolveEdgeColor(in context, payload),
MacroCode.ShadowColor => this.TryResolveShadowColor(in context, payload),
// MacroCode.SoftHyphen (pass through)
// MacroCode.Key
// MacroCode.Scale
MacroCode.Bold => this.TryResolveBold(in context, payload),
MacroCode.Italic => this.TryResolveItalic(in context, payload),
// MacroCode.Edge
// MacroCode.Shadow
// MacroCode.NonBreakingSpace (pass through)
// MacroCode.Icon2 (pass through)
// MacroCode.Hyphen (pass through)
MacroCode.Num => this.TryResolveNum(in context, payload),
MacroCode.Hex => this.TryResolveHex(in context, payload),
MacroCode.Kilo => this.TryResolveKilo(in context, payload),
// MacroCode.Byte
MacroCode.Sec => this.TryResolveSec(in context, payload),
// MacroCode.Time
MacroCode.Float => this.TryResolveFloat(in context, payload),
// MacroCode.Link (pass through)
MacroCode.Sheet => this.TryResolveSheet(in context, payload),
MacroCode.SheetSub => this.TryResolveSheetSub(in context, payload),
MacroCode.String => this.TryResolveString(in context, payload),
MacroCode.Caps => this.TryResolveCaps(in context, payload),
MacroCode.Head => this.TryResolveHead(in context, payload),
MacroCode.Split => this.TryResolveSplit(in context, payload),
MacroCode.HeadAll => this.TryResolveHeadAll(in context, payload),
MacroCode.Fixed => this.TryResolveFixed(in context, payload),
MacroCode.Lower => this.TryResolveLower(in context, payload),
MacroCode.JaNoun => this.TryResolveNoun(ClientLanguage.Japanese, in context, payload),
MacroCode.EnNoun => this.TryResolveNoun(ClientLanguage.English, in context, payload),
MacroCode.DeNoun => this.TryResolveNoun(ClientLanguage.German, in context, payload),
MacroCode.FrNoun => this.TryResolveNoun(ClientLanguage.French, in context, payload),
// MacroCode.ChNoun
MacroCode.LowerHead => this.TryResolveLowerHead(in context, payload),
MacroCode.ColorType => this.TryResolveColorType(in context, payload),
MacroCode.EdgeColorType => this.TryResolveEdgeColorType(in context, payload),
// MacroCode.Ruby
MacroCode.Digit => this.TryResolveDigit(in context, payload),
MacroCode.Ordinal => this.TryResolveOrdinal(in context, payload),
// MacroCode.Sound (pass through)
MacroCode.LevelPos => this.TryResolveLevelPos(in context, payload),
_ => false,
};
}
private unsafe bool TryResolveSetResetTime(in SeStringContext context, in ReadOnlySePayloadSpan payload)
@ -932,7 +845,7 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
using var rssb = new RentedSeStringBuilder();
var sb = rssb.Builder;
sb.Append(this.EvaluateFromAddon(6, [rarity], context.Language));
sb.Append(this.EvaluateFromAddon(6, [rarity], context.Language)); // appends colortype and edgecolortype
if (!skipLink)
sb.PushLink(LinkMacroPayloadType.Item, itemId, rarity, 0u); // arg3 = some LogMessage flag based on LogKind RowId? => "89 5C 24 20 E8 ?? ?? ?? ?? 48 8B 1F"
@ -955,6 +868,9 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator
if (!skipLink)
sb.PopLink();
sb.PopEdgeColorType();
sb.PopColorType();
text = sb.ToReadOnlySeString();
}

View file

@ -85,7 +85,7 @@ internal class NounProcessor : IServiceType
private const int PronounColumnIdx = 6;
private const int ArticleColumnIdx = 7;
private static readonly ModuleLog Log = new("NounProcessor");
private static readonly ModuleLog Log = ModuleLog.Create<NounProcessor>();
[ServiceManager.ServiceDependency]
private readonly DataManager dataManager = Service<DataManager>.Get();

View file

@ -213,11 +213,10 @@ public abstract partial class Payload
return payload;
}
private static Payload DecodeText(BinaryReader reader)
private static TextPayload DecodeText(BinaryReader reader)
{
var payload = new TextPayload();
payload.DecodeImpl(reader, reader.BaseStream.Length);
return payload;
}
}
@ -382,7 +381,7 @@ public abstract partial class Payload
{
if (value < 0xCF)
{
return new byte[] { (byte)(value + 1) };
return [(byte)(value + 1)];
}
var bytes = BitConverter.GetBytes(value);

View file

@ -45,10 +45,10 @@ public class IconPayload : Payload
{
var indexBytes = MakeInteger((uint)this.Icon);
var chunkLen = indexBytes.Length + 1;
var bytes = new List<byte>(new byte[]
{
var bytes = new List<byte>(
[
START_BYTE, (byte)SeStringChunkType.Icon, (byte)chunkLen,
});
]);
bytes.AddRange(indexBytes);
bytes.Add(END_BYTE);
return bytes.ToArray();

View file

@ -8,6 +8,7 @@ using Dalamud.Utility;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
@ -172,7 +173,7 @@ public class ItemPayload : Payload
};
bytes.AddRange(idBytes);
// unk
bytes.AddRange(new byte[] { 0x02, 0x01 });
bytes.AddRange([0x02, 0x01]);
// Links don't have to include the name, but if they do, it requires additional work
if (hasName)
@ -183,17 +184,17 @@ public class ItemPayload : Payload
nameLen += 4; // space plus 3 bytes for HQ symbol
}
bytes.AddRange(new byte[]
{
bytes.AddRange(
[
0xFF, // unk
(byte)nameLen,
});
]);
bytes.AddRange(Encoding.UTF8.GetBytes(this.displayName));
if (this.IsHQ)
{
// space and HQ symbol
bytes.AddRange(new byte[] { 0x20, 0xEE, 0x80, 0xBC });
bytes.AddRange([0x20, 0xEE, 0x80, 0xBC]);
}
}

View file

@ -5,6 +5,7 @@ using Dalamud.Data;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
@ -174,7 +175,7 @@ public class MapLinkPayload : Payload
bytes.AddRange(yBytes);
// unk
bytes.AddRange(new byte[] { 0xFF, 0x01, END_BYTE });
bytes.AddRange([0xFF, 0x01, END_BYTE]);
return bytes.ToArray();
}

View file

@ -7,7 +7,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads;
/// </summary>
public class NewLinePayload : Payload, ITextProvider
{
private readonly byte[] bytes = { START_BYTE, (byte)SeStringChunkType.NewLine, 0x01, END_BYTE };
private readonly byte[] bytes = [START_BYTE, (byte)SeStringChunkType.NewLine, 0x01, END_BYTE];
/// <summary>
/// Gets an instance of NewLinePayload.

View file

@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using Lumina.Extensions;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads
@ -97,7 +98,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads
reader.ReadByte();
// if the next byte is 0xF3 then this listing is limited to home world
byte nextByte = reader.ReadByte();
var nextByte = reader.ReadByte();
switch (nextByte)
{
case (byte)PartyFinderLinkType.LimitedToHomeWorld:
@ -121,11 +122,11 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads
// if the link type is notification, just use premade payload data since it's always the same.
// i have no idea why it is formatted like this, but it is how it is.
// note it is identical to the link terminator payload except the embedded info type is 0x08
if (this.LinkType == PartyFinderLinkType.PartyFinderNotification) return new byte[] { 0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03, };
if (this.LinkType == PartyFinderLinkType.PartyFinderNotification) return [0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03,];
// back to our regularly scheduled programming...
var listingIDBytes = MakeInteger(this.ListingId);
bool isFlagSpecified = this.LinkType != PartyFinderLinkType.NotSpecified;
var isFlagSpecified = this.LinkType != PartyFinderLinkType.NotSpecified;
var chunkLen = listingIDBytes.Length + 4;
// 1 more byte for the type flag if it is specified

View file

@ -5,6 +5,7 @@ using Dalamud.Data;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
@ -62,7 +63,7 @@ public class QuestPayload : Payload
};
bytes.AddRange(idBytes);
bytes.AddRange(new byte[] { 0x01, 0x01, END_BYTE });
bytes.AddRange([0x01, 0x01, END_BYTE]);
return bytes.ToArray();
}

View file

@ -45,7 +45,7 @@ public class RawPayload : Payload
/// <summary>
/// Gets a fixed Payload representing a common link-termination sequence, found in many payload chains.
/// </summary>
public static RawPayload LinkTerminator => new(new byte[] { 0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03 });
public static RawPayload LinkTerminator => new([0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]);
/// <inheritdoc/>
public override PayloadType Type => PayloadType.Unknown;

View file

@ -7,7 +7,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads;
/// </summary>
public class SeHyphenPayload : Payload, ITextProvider
{
private readonly byte[] bytes = { START_BYTE, (byte)SeStringChunkType.SeHyphen, 0x01, END_BYTE };
private readonly byte[] bytes = [START_BYTE, (byte)SeStringChunkType.SeHyphen, 0x01, END_BYTE];
/// <summary>
/// Gets an instance of SeHyphenPayload.

View file

@ -5,6 +5,7 @@ using Dalamud.Data;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
@ -63,7 +64,7 @@ public class StatusPayload : Payload
bytes.AddRange(idBytes);
// unk
bytes.AddRange(new byte[] { 0x01, 0x01, 0xFF, 0x02, 0x20, END_BYTE });
bytes.AddRange([0x01, 0x01, 0xFF, 0x02, 0x20, END_BYTE]);
return bytes.ToArray();
}

View file

@ -5,6 +5,7 @@ using Dalamud.Data;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
@ -95,10 +96,10 @@ public class UIForegroundPayload : Payload
var colorBytes = MakeInteger(this.colorKey);
var chunkLen = colorBytes.Length + 1;
var bytes = new List<byte>(new byte[]
{
var bytes = new List<byte>(
[
START_BYTE, (byte)SeStringChunkType.UIForeground, (byte)chunkLen,
});
]);
bytes.AddRange(colorBytes);
bytes.Add(END_BYTE);

View file

@ -5,6 +5,7 @@ using Dalamud.Data;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Newtonsoft.Json;
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
@ -98,10 +99,10 @@ public class UIGlowPayload : Payload
var colorBytes = MakeInteger(this.colorKey);
var chunkLen = colorBytes.Length + 1;
var bytes = new List<byte>(new byte[]
{
var bytes = new List<byte>(
[
START_BYTE, (byte)SeStringChunkType.UIGlow, (byte)chunkLen,
});
]);
bytes.AddRange(colorBytes);
bytes.Add(END_BYTE);

View file

@ -28,7 +28,7 @@ public class SeString
/// </summary>
public SeString()
{
this.Payloads = new List<Payload>();
this.Payloads = [];
}
/// <summary>