mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-19 14:27:45 +01:00
Merge branch 'api12'
This commit is contained in:
commit
f94f03e114
137 changed files with 6870 additions and 944 deletions
|
|
@ -5,11 +5,6 @@ namespace Dalamud.Configuration.Internal;
|
|||
/// </summary>
|
||||
internal class EnvironmentConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the XL_WINEONLINUX setting has been enabled.
|
||||
/// </summary>
|
||||
public static bool XlWineOnLinux { get; } = GetEnvironmentVariable("XL_WINEONLINUX");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the DALAMUD_NOT_HAVE_PLUGINS setting has been enabled.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Target">
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64</Platforms>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
<EnableWindowsTargeting>True</EnableWindowsTargeting>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Feature">
|
||||
<Description>XIV Launcher addon framework</Description>
|
||||
<DalamudVersion>11.0.8.0</DalamudVersion>
|
||||
<DalamudVersion>12.0.0.0</DalamudVersion>
|
||||
<AssemblyVersion>$(DalamudVersion)</AssemblyVersion>
|
||||
<Version>$(DalamudVersion)</Version>
|
||||
<FileVersion>$(DalamudVersion)</FileVersion>
|
||||
|
|
@ -94,6 +90,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dalamud.Common\Dalamud.Common.csproj" />
|
||||
<ProjectReference Include="..\lib\FFXIVClientStructs\FFXIVClientStructs\FFXIVClientStructs.csproj" />
|
||||
<ProjectReference Include="..\lib\FFXIVClientStructs\InteropGenerator.Runtime\InteropGenerator.Runtime.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\ImGuiScene\ImGuiScene.csproj" />
|
||||
|
|
|
|||
|
|
@ -178,20 +178,18 @@ public sealed class EntryPoint
|
|||
throw new Exception("Working directory was invalid");
|
||||
|
||||
Reloaded.Hooks.Tools.Utilities.FasmBasePath = new DirectoryInfo(info.WorkingDirectory);
|
||||
|
||||
|
||||
// Apply common fixes for culture issues
|
||||
CultureFixes.Apply();
|
||||
|
||||
// This is due to GitHub not supporting TLS 1.0, so we enable all TLS versions globally
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls;
|
||||
|
||||
if (!Util.IsWine())
|
||||
// Currently VEH is not fully functional on WINE
|
||||
if (info.Platform != OSPlatform.Windows)
|
||||
InitSymbolHandler(info);
|
||||
|
||||
var dalamud = new Dalamud(info, fs, configuration, mainThreadContinueEvent);
|
||||
Log.Information("This is Dalamud - Core: {GitHash}, CS: {CsGitHash} [{CsVersion}]",
|
||||
Util.GetScmVersion(),
|
||||
Util.GetGitHashClientStructs(),
|
||||
Log.Information("This is Dalamud - Core: {GitHash}, CS: {CsGitHash} [{CsVersion}]",
|
||||
Util.GetScmVersion(),
|
||||
Util.GetGitHashClientStructs(),
|
||||
FFXIVClientStructs.ThisAssembly.Git.Commits);
|
||||
|
||||
dalamud.WaitForUnload();
|
||||
|
|
|
|||
89
Dalamud/Game/ActionKind.cs
Normal file
89
Dalamud/Game/ActionKind.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
namespace Dalamud.Game;
|
||||
|
||||
/// <summary>
|
||||
/// Enum describing possible action kinds.
|
||||
/// </summary>
|
||||
public enum ActionKind
|
||||
{
|
||||
/// <summary>
|
||||
/// A Trait.
|
||||
/// </summary>
|
||||
Trait = 0,
|
||||
|
||||
/// <summary>
|
||||
/// An Action.
|
||||
/// </summary>
|
||||
Action = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A usable Item.
|
||||
/// </summary>
|
||||
Item = 2, // does not work?
|
||||
|
||||
/// <summary>
|
||||
/// A usable EventItem.
|
||||
/// </summary>
|
||||
EventItem = 3, // does not work?
|
||||
|
||||
/// <summary>
|
||||
/// An EventAction.
|
||||
/// </summary>
|
||||
EventAction = 4,
|
||||
|
||||
/// <summary>
|
||||
/// A GeneralAction.
|
||||
/// </summary>
|
||||
GeneralAction = 5,
|
||||
|
||||
/// <summary>
|
||||
/// A BuddyAction.
|
||||
/// </summary>
|
||||
BuddyAction = 6,
|
||||
|
||||
/// <summary>
|
||||
/// A MainCommand.
|
||||
/// </summary>
|
||||
MainCommand = 7,
|
||||
|
||||
/// <summary>
|
||||
/// A Companion.
|
||||
/// </summary>
|
||||
Companion = 8, // unresolved?!
|
||||
|
||||
/// <summary>
|
||||
/// A CraftAction.
|
||||
/// </summary>
|
||||
CraftAction = 9,
|
||||
|
||||
/// <summary>
|
||||
/// An Action (again).
|
||||
/// </summary>
|
||||
Action2 = 10, // what's the difference?
|
||||
|
||||
/// <summary>
|
||||
/// A PetAction.
|
||||
/// </summary>
|
||||
PetAction = 11,
|
||||
|
||||
/// <summary>
|
||||
/// A CompanyAction.
|
||||
/// </summary>
|
||||
CompanyAction = 12,
|
||||
|
||||
/// <summary>
|
||||
/// A Mount.
|
||||
/// </summary>
|
||||
Mount = 13,
|
||||
|
||||
// 14-18 unused
|
||||
|
||||
/// <summary>
|
||||
/// A BgcArmyAction.
|
||||
/// </summary>
|
||||
BgcArmyAction = 19,
|
||||
|
||||
/// <summary>
|
||||
/// An Ornament.
|
||||
/// </summary>
|
||||
Ornament = 20,
|
||||
}
|
||||
|
|
@ -11,9 +11,9 @@ namespace Dalamud.Game.Addon.Events;
|
|||
internal unsafe class AddonEventListener : IDisposable
|
||||
{
|
||||
private ReceiveEventDelegate? receiveEventDelegate;
|
||||
|
||||
|
||||
private AtkEventListener* eventListener;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AddonEventListener"/> class.
|
||||
/// </summary>
|
||||
|
|
@ -24,7 +24,7 @@ internal unsafe class AddonEventListener : IDisposable
|
|||
|
||||
this.eventListener = (AtkEventListener*)Marshal.AllocHGlobal(sizeof(AtkEventListener));
|
||||
this.eventListener->VirtualTable = (AtkEventListener.AtkEventListenerVirtualTable*)Marshal.AllocHGlobal(sizeof(void*) * 3);
|
||||
this.eventListener->VirtualTable->Dtor = (delegate* unmanaged<AtkEventListener*, byte, void>)(delegate* unmanaged<void>)&NullSub;
|
||||
this.eventListener->VirtualTable->Dtor = (delegate* unmanaged<AtkEventListener*, byte, AtkEventListener*>)(delegate* unmanaged<void>)&NullSub;
|
||||
this.eventListener->VirtualTable->ReceiveGlobalEvent = (delegate* unmanaged<AtkEventListener*, AtkEventType, int, AtkEvent*, AtkEventData*, void>)(delegate* unmanaged<void>)&NullSub;
|
||||
this.eventListener->VirtualTable->ReceiveEvent = (delegate* unmanaged<AtkEventListener*, AtkEventType, int, AtkEvent*, AtkEventData*, void>)Marshal.GetFunctionPointerForDelegate(this.receiveEventDelegate);
|
||||
}
|
||||
|
|
@ -38,17 +38,17 @@ internal unsafe class AddonEventListener : IDisposable
|
|||
/// <param name="eventPtr">Pointer to the AtkEvent.</param>
|
||||
/// <param name="eventDataPtr">Pointer to the AtkEventData.</param>
|
||||
public delegate void ReceiveEventDelegate(AtkEventListener* self, AtkEventType eventType, uint eventParam, AtkEvent* eventPtr, AtkEventData* eventDataPtr);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of this listener.
|
||||
/// </summary>
|
||||
public nint Address => (nint)this.eventListener;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.eventListener is null) return;
|
||||
|
||||
|
||||
Marshal.FreeHGlobal((nint)this.eventListener->VirtualTable);
|
||||
Marshal.FreeHGlobal((nint)this.eventListener);
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ internal unsafe class AddonEventListener : IDisposable
|
|||
node->RemoveEvent(eventType, param, this.eventListener, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
private static void NullSub()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,19 +13,19 @@ internal unsafe class AddonLifecycleAddressResolver : BaseAddressResolver
|
|||
/// This is called for a majority of all addon OnSetup's.
|
||||
/// </summary>
|
||||
public nint AddonSetup { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the other addon setup hook invoked by the AtkUnitManager.
|
||||
/// There are two callsites for this vFunc, we need to hook both of them to catch both normal UI and special UI cases like dialogue.
|
||||
/// This seems to be called rarely for specific addons.
|
||||
/// </summary>
|
||||
public nint AddonSetup2 { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the addon finalize hook invoked by the AtkUnitManager.
|
||||
/// </summary>
|
||||
public nint AddonFinalize { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the addon draw hook invoked by virtual function call.
|
||||
/// </summary>
|
||||
|
|
@ -35,7 +35,7 @@ internal unsafe class AddonLifecycleAddressResolver : BaseAddressResolver
|
|||
/// Gets the address of the addon update hook invoked by virtual function call.
|
||||
/// </summary>
|
||||
public nint AddonUpdate { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the addon onRequestedUpdate hook invoked by virtual function call.
|
||||
/// </summary>
|
||||
|
|
@ -51,6 +51,6 @@ internal unsafe class AddonLifecycleAddressResolver : BaseAddressResolver
|
|||
this.AddonFinalize = sig.ScanText("E8 ?? ?? ?? ?? 48 83 EF 01 75 D5");
|
||||
this.AddonDraw = sig.ScanText("FF 90 ?? ?? ?? ?? 83 EB 01 79 C4 48 81 EF ?? ?? ?? ?? 48 83 ED 01");
|
||||
this.AddonUpdate = sig.ScanText("FF 90 ?? ?? ?? ?? 40 88 AF ?? ?? ?? ?? 45 33 D2");
|
||||
this.AddonOnRequestedUpdate = sig.ScanText("FF 90 98 01 00 00 48 8B 5C 24 30 48 83 C4 20");
|
||||
this.AddonOnRequestedUpdate = sig.ScanText("FF 90 A0 01 00 00 48 8B 5C 24 30");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,6 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
|||
/// </summary>
|
||||
public IntPtr ProcessPacketPlayerSetup { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the method which polls the gamepads for data.
|
||||
/// Called every frame, even when `Enable Gamepad` is off in the settings.
|
||||
/// </summary>
|
||||
public IntPtr GamepadPoll { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scan for and setup any configured address pointers.
|
||||
/// </summary>
|
||||
|
|
@ -43,7 +37,5 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
|||
// movzx edx, byte ptr [rbx+rsi+1D5E0E0h] KeyboardStateIndexArray
|
||||
this.KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4;
|
||||
this.KeyboardStateIndexArray = sig.ScanText("0F B6 94 33 ?? ?? ?? ?? 84 D2") + 0x4;
|
||||
|
||||
this.GamepadPoll = sig.ScanText("40 55 53 57 41 54 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 B4 24"); // unnamed in cs
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dalamud.Game.ClientState.GamePad;
|
||||
|
||||
/// <summary>
|
||||
/// Struct which gets populated by polling the gamepads.
|
||||
///
|
||||
/// Has an array of gamepads, among many other things (here not mapped).
|
||||
/// All we really care about is the final data which the game uses to determine input.
|
||||
///
|
||||
/// The size is definitely bigger than only the following fields but I do not know how big.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct GamepadInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Left analogue stick's horizontal value, -99 for left, 99 for right.
|
||||
/// </summary>
|
||||
[FieldOffset(0x78)]
|
||||
public int LeftStickX;
|
||||
|
||||
/// <summary>
|
||||
/// Left analogue stick's vertical value, -99 for down, 99 for up.
|
||||
/// </summary>
|
||||
[FieldOffset(0x7C)]
|
||||
public int LeftStickY;
|
||||
|
||||
/// <summary>
|
||||
/// Right analogue stick's horizontal value, -99 for left, 99 for right.
|
||||
/// </summary>
|
||||
[FieldOffset(0x80)]
|
||||
public int RightStickX;
|
||||
|
||||
/// <summary>
|
||||
/// Right analogue stick's vertical value, -99 for down, 99 for up.
|
||||
/// </summary>
|
||||
[FieldOffset(0x84)]
|
||||
public int RightStickY;
|
||||
|
||||
/// <summary>
|
||||
/// Raw input, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x88)]
|
||||
public ushort ButtonsRaw;
|
||||
|
||||
/// <summary>
|
||||
/// Button pressed, set once when the button is pressed. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x8C)]
|
||||
public ushort ButtonsPressed;
|
||||
|
||||
/// <summary>
|
||||
/// Button released input, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x90)]
|
||||
public ushort ButtonsReleased;
|
||||
|
||||
/// <summary>
|
||||
/// Repeatedly emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a bitfield.
|
||||
/// </remarks>
|
||||
[FieldOffset(0x94)]
|
||||
public ushort ButtonsRepeat;
|
||||
}
|
||||
|
|
@ -4,7 +4,8 @@ using Dalamud.Hooking;
|
|||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Input;
|
||||
|
||||
using ImGuiNET;
|
||||
using Serilog;
|
||||
|
|
@ -23,7 +24,7 @@ namespace Dalamud.Game.ClientState.GamePad;
|
|||
#pragma warning restore SA1015
|
||||
internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||
{
|
||||
private readonly Hook<ControllerPoll>? gamepadPoll;
|
||||
private readonly Hook<PadDevice.Delegates.Poll>? gamepadPoll;
|
||||
|
||||
private bool isDisposed;
|
||||
|
||||
|
|
@ -35,25 +36,21 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
[ServiceManager.ServiceConstructor]
|
||||
private GamepadState(ClientState clientState)
|
||||
{
|
||||
var resolver = clientState.AddressResolver;
|
||||
Log.Verbose($"GamepadPoll address {Util.DescribeAddress(resolver.GamepadPoll)}");
|
||||
this.gamepadPoll = Hook<ControllerPoll>.FromAddress(resolver.GamepadPoll, this.GamepadPollDetour);
|
||||
this.gamepadPoll = Hook<PadDevice.Delegates.Poll>.FromAddress((nint)PadDevice.StaticVirtualTablePointer->Poll, this.GamepadPollDetour);
|
||||
this.gamepadPoll?.Enable();
|
||||
}
|
||||
|
||||
private delegate int ControllerPoll(IntPtr controllerInput);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pointer to the current instance of the GamepadInput struct.
|
||||
/// </summary>
|
||||
public IntPtr GamepadInputAddress { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Vector2 LeftStick =>
|
||||
public Vector2 LeftStick =>
|
||||
new(this.leftStickX, this.leftStickY);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Vector2 RightStick =>
|
||||
public Vector2 RightStick =>
|
||||
new(this.rightStickX, this.rightStickY);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -61,28 +58,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsPressed { get; private set; }
|
||||
internal GamepadButtons ButtonsPressed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets raw button bitmask, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsRaw { get; private set; }
|
||||
internal GamepadButtons ButtonsRaw { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets button released bitmask, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsReleased { get; private set; }
|
||||
internal GamepadButtons ButtonsReleased { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets button repeat bitmask, emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
/// Exposed internally for Debug Data window.
|
||||
/// </summary>
|
||||
internal ushort ButtonsRepeat { get; private set; }
|
||||
internal GamepadButtons ButtonsRepeat { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether detour should block gamepad input for game.
|
||||
|
|
@ -95,16 +92,16 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
internal bool NavEnableGamepad { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Pressed(GamepadButtons button) => (this.ButtonsPressed & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Pressed(GamepadButtons button) => (this.ButtonsPressed & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Released(GamepadButtons button) => (this.ButtonsReleased & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Released(GamepadButtons button) => (this.ButtonsReleased & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Raw(GamepadButtons button) => (this.ButtonsRaw & (ushort)button) > 0 ? 1 : 0;
|
||||
public float Raw(GamepadButtons button) => (this.ButtonsRaw & button) > 0 ? 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance, alongside its hooks.
|
||||
|
|
@ -115,28 +112,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private int GamepadPollDetour(IntPtr gamepadInput)
|
||||
private nint GamepadPollDetour(PadDevice* gamepadInput)
|
||||
{
|
||||
var original = this.gamepadPoll!.Original(gamepadInput);
|
||||
try
|
||||
{
|
||||
this.GamepadInputAddress = gamepadInput;
|
||||
var input = (GamepadInput*)gamepadInput;
|
||||
this.leftStickX = input->LeftStickX;
|
||||
this.leftStickY = input->LeftStickY;
|
||||
this.rightStickX = input->RightStickX;
|
||||
this.rightStickY = input->RightStickY;
|
||||
this.ButtonsRaw = input->ButtonsRaw;
|
||||
this.ButtonsPressed = input->ButtonsPressed;
|
||||
this.ButtonsReleased = input->ButtonsReleased;
|
||||
this.ButtonsRepeat = input->ButtonsRepeat;
|
||||
this.GamepadInputAddress = (nint)gamepadInput;
|
||||
|
||||
this.leftStickX = gamepadInput->GamepadInputData.LeftStickX;
|
||||
this.leftStickY = gamepadInput->GamepadInputData.LeftStickY;
|
||||
this.rightStickX = gamepadInput->GamepadInputData.RightStickX;
|
||||
this.rightStickY = gamepadInput->GamepadInputData.RightStickY;
|
||||
this.ButtonsRaw = (GamepadButtons)gamepadInput->GamepadInputData.Buttons;
|
||||
this.ButtonsPressed = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsPressed;
|
||||
this.ButtonsReleased = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsReleased;
|
||||
this.ButtonsRepeat = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsRepeat;
|
||||
|
||||
if (this.NavEnableGamepad)
|
||||
{
|
||||
input->LeftStickX = 0;
|
||||
input->LeftStickY = 0;
|
||||
input->RightStickX = 0;
|
||||
input->RightStickY = 0;
|
||||
gamepadInput->GamepadInputData.LeftStickX = 0;
|
||||
gamepadInput->GamepadInputData.LeftStickY = 0;
|
||||
gamepadInput->GamepadInputData.RightStickX = 0;
|
||||
gamepadInput->GamepadInputData.RightStickY = 0;
|
||||
|
||||
// NOTE (Chiv) Zeroing `ButtonsRaw` destroys `ButtonPressed`, `ButtonReleased`
|
||||
// and `ButtonRepeat` as the game uses the RAW input to determine those (apparently).
|
||||
|
|
@ -153,16 +150,16 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
|||
// `ButtonPressed` while ImGuiConfigFlags.NavEnableGamepad is set.
|
||||
// This is debatable.
|
||||
// ImGui itself does not care either way as it uses the Raw values and does its own state handling.
|
||||
const ushort deletionMask = (ushort)(~GamepadButtons.L2
|
||||
& ~GamepadButtons.R2
|
||||
& ~GamepadButtons.DpadDown
|
||||
& ~GamepadButtons.DpadLeft
|
||||
& ~GamepadButtons.DpadUp
|
||||
& ~GamepadButtons.DpadRight);
|
||||
input->ButtonsRaw &= deletionMask;
|
||||
input->ButtonsPressed = 0;
|
||||
input->ButtonsReleased = 0;
|
||||
input->ButtonsRepeat = 0;
|
||||
const GamepadButtonsFlags deletionMask = ~GamepadButtonsFlags.L2
|
||||
& ~GamepadButtonsFlags.R2
|
||||
& ~GamepadButtonsFlags.DPadDown
|
||||
& ~GamepadButtonsFlags.DPadLeft
|
||||
& ~GamepadButtonsFlags.DPadUp
|
||||
& ~GamepadButtonsFlags.DPadRight;
|
||||
gamepadInput->GamepadInputData.Buttons &= deletionMask;
|
||||
gamepadInput->GamepadInputData.ButtonsPressed = 0;
|
||||
gamepadInput->GamepadInputData.ButtonsReleased = 0;
|
||||
gamepadInput->GamepadInputData.ButtonsRepeat = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@ public enum BeastChakra : byte
|
|||
/// <summary>
|
||||
/// No chakra.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The Opo-Opo chakra.
|
||||
/// </summary>
|
||||
OPOOPO = 1,
|
||||
OpoOpo = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The Raptor chakra.
|
||||
/// </summary>
|
||||
RAPTOR = 2,
|
||||
Raptor = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The Coeurl chakra.
|
||||
/// </summary>
|
||||
COEURL = 3,
|
||||
Coeurl = 3,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,45 +8,45 @@ public enum CardType : byte
|
|||
/// <summary>
|
||||
/// No card.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The Balance card.
|
||||
/// </summary>
|
||||
BALANCE = 1,
|
||||
Balance = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The Bole card.
|
||||
/// </summary>
|
||||
BOLE = 2,
|
||||
Bole = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The Arrow card.
|
||||
/// </summary>
|
||||
ARROW = 3,
|
||||
Arrow = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The Spear card.
|
||||
/// </summary>
|
||||
SPEAR = 4,
|
||||
Spear = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The Ewer card.
|
||||
/// </summary>
|
||||
EWER = 5,
|
||||
Ewer = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The Spire card.
|
||||
/// </summary>
|
||||
SPIRE = 6,
|
||||
Spire = 6,
|
||||
|
||||
/// <summary>
|
||||
/// The Lord of Crowns card.
|
||||
/// </summary>
|
||||
LORD = 7,
|
||||
Lord = 7,
|
||||
|
||||
/// <summary>
|
||||
/// The Lady of Crowns card.
|
||||
/// </summary>
|
||||
LADY = 8,
|
||||
Lady = 8,
|
||||
}
|
||||
|
|
|
|||
22
Dalamud/Game/ClientState/JobGauge/Enums/DeliriumStep.cs
Normal file
22
Dalamud/Game/ClientState/JobGauge/Enums/DeliriumStep.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
namespace Dalamud.Game.ClientState.JobGauge.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the current step of Delirium.
|
||||
/// </summary>
|
||||
public enum DeliriumStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Scarlet Delirium can be used.
|
||||
/// </summary>
|
||||
ScarletDelirium = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Comeuppance can be used.
|
||||
/// </summary>
|
||||
Comeuppance = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Torcleaver can be used.
|
||||
/// </summary>
|
||||
Torcleaver = 2,
|
||||
}
|
||||
|
|
@ -8,10 +8,10 @@ public enum DismissedFairy : byte
|
|||
/// <summary>
|
||||
/// Dismissed fairy is Eos.
|
||||
/// </summary>
|
||||
EOS = 6,
|
||||
Eos = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Dismissed fairy is Selene.
|
||||
/// </summary>
|
||||
SELENE = 7,
|
||||
Selene = 7,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ public enum DrawType : byte
|
|||
/// <summary>
|
||||
/// Astral Draw active.
|
||||
/// </summary>
|
||||
ASTRAL = 0,
|
||||
Astral = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Umbral Draw active.
|
||||
/// </summary>
|
||||
UMBRAL = 1,
|
||||
Umbral = 1,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,25 +8,25 @@ public enum Kaeshi : byte
|
|||
/// <summary>
|
||||
/// No Kaeshi is active.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Kaeshi: Higanbana type.
|
||||
/// </summary>
|
||||
HIGANBANA = 1,
|
||||
Higanbana = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Kaeshi: Goken type.
|
||||
/// </summary>
|
||||
GOKEN = 2,
|
||||
Goken = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Kaeshi: Setsugekka type.
|
||||
/// </summary>
|
||||
SETSUGEKKA = 3,
|
||||
Setsugekka = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Kaeshi: Namikiri type.
|
||||
/// </summary>
|
||||
NAMIKIRI = 4,
|
||||
Namikiri = 4,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ public enum Mudras : byte
|
|||
/// <summary>
|
||||
/// Ten mudra.
|
||||
/// </summary>
|
||||
TEN = 1,
|
||||
Ten = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Chi mudra.
|
||||
/// </summary>
|
||||
CHI = 2,
|
||||
Chi = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Jin mudra.
|
||||
/// </summary>
|
||||
JIN = 3,
|
||||
Jin = 3,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@ public enum Nadi : byte
|
|||
/// <summary>
|
||||
/// No nadi.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The Lunar nadi.
|
||||
/// </summary>
|
||||
LUNAR = 1,
|
||||
Lunar = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The Solar nadi.
|
||||
/// </summary>
|
||||
SOLAR = 2,
|
||||
Solar = 2,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,40 +8,40 @@ public enum PetGlam : byte
|
|||
/// <summary>
|
||||
/// No pet glam.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Emerald carbuncle pet glam.
|
||||
/// </summary>
|
||||
EMERALD = 1,
|
||||
Emerald = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Topaz carbuncle pet glam.
|
||||
/// </summary>
|
||||
TOPAZ = 2,
|
||||
Topaz = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Ruby carbuncle pet glam.
|
||||
/// </summary>
|
||||
RUBY = 3,
|
||||
Ruby = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Normal carbuncle pet glam.
|
||||
/// </summary>
|
||||
CARBUNCLE = 4,
|
||||
Carbuncle = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Ifrit Egi pet glam.
|
||||
/// </summary>
|
||||
IFRIT = 5,
|
||||
Ifrit = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Titan Egi pet glam.
|
||||
/// </summary>
|
||||
TITAN = 6,
|
||||
Titan = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Garuda Egi pet glam.
|
||||
/// </summary>
|
||||
GARUDA = 7,
|
||||
Garuda = 7,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ public enum Sen : byte
|
|||
/// <summary>
|
||||
/// No Sen.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Setsu Sen type.
|
||||
/// </summary>
|
||||
SETSU = 1 << 0,
|
||||
Setsu = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Getsu Sen type.
|
||||
/// </summary>
|
||||
GETSU = 1 << 1,
|
||||
Getsu = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Ka Sen type.
|
||||
/// </summary>
|
||||
KA = 1 << 2,
|
||||
Ka = 1 << 2,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,35 +8,35 @@ public enum SerpentCombo : byte
|
|||
/// <summary>
|
||||
/// No Serpent combo is active.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Death Rattle action.
|
||||
/// </summary>
|
||||
DEATHRATTLE = 1,
|
||||
DeathRattle = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Last Lash action.
|
||||
/// </summary>
|
||||
LASTLASH = 2,
|
||||
LastLash = 2,
|
||||
|
||||
/// <summary>
|
||||
/// First Legacy action.
|
||||
/// </summary>
|
||||
FIRSTLEGACY = 3,
|
||||
FirstLegacy = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Second Legacy action.
|
||||
/// </summary>
|
||||
SECONDLEGACY = 4,
|
||||
SecondLegacy = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Third Legacy action.
|
||||
/// </summary>
|
||||
THIRDLEGACY = 5,
|
||||
ThirdLegacy = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Fourth Legacy action.
|
||||
/// </summary>
|
||||
FOURTHLEGACY = 6,
|
||||
FourthLegacy = 6,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@ public enum Song : byte
|
|||
/// <summary>
|
||||
/// No song is active type.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Mage's Ballad type.
|
||||
/// </summary>
|
||||
MAGE = 1,
|
||||
Mage = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Army's Paeon type.
|
||||
/// </summary>
|
||||
ARMY = 2,
|
||||
Army = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The Wanderer's Minuet type.
|
||||
/// </summary>
|
||||
WANDERER = 3,
|
||||
Wanderer = 3,
|
||||
}
|
||||
|
|
|
|||
30
Dalamud/Game/ClientState/JobGauge/Enums/SummonAttunement.cs
Normal file
30
Dalamud/Game/ClientState/JobGauge/Enums/SummonAttunement.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
namespace Dalamud.Game.ClientState.JobGauge.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the current attunement of a summoner.
|
||||
/// </summary>
|
||||
public enum SummonAttunement
|
||||
{
|
||||
/// <summary>
|
||||
/// No attunement.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Attuned to the summon Ifrit.
|
||||
/// Same as <see cref="JobGauge.Types.SMNGauge.IsIfritAttuned"/>.
|
||||
/// </summary>
|
||||
Ifrit = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Attuned to the summon Titan.
|
||||
/// Same as <see cref="JobGauge.Types.SMNGauge.IsTitanAttuned"/>.
|
||||
/// </summary>
|
||||
Titan = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Attuned to the summon Garuda.
|
||||
/// Same as <see cref="JobGauge.Types.SMNGauge.IsGarudaAttuned"/>.
|
||||
/// </summary>
|
||||
Garuda = 3,
|
||||
}
|
||||
|
|
@ -8,10 +8,10 @@ public enum SummonPet : byte
|
|||
/// <summary>
|
||||
/// No pet.
|
||||
/// </summary>
|
||||
NONE = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The summoned pet Carbuncle.
|
||||
/// </summary>
|
||||
CARBUNCLE = 23,
|
||||
Carbuncle = 23,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,15 +40,15 @@ public unsafe class BRDGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
get
|
||||
{
|
||||
if (this.Struct->SongFlags.HasFlag(SongFlags.WanderersMinuet))
|
||||
return Song.WANDERER;
|
||||
return Song.Wanderer;
|
||||
|
||||
if (this.Struct->SongFlags.HasFlag(SongFlags.ArmysPaeon))
|
||||
return Song.ARMY;
|
||||
return Song.Army;
|
||||
|
||||
if (this.Struct->SongFlags.HasFlag(SongFlags.MagesBallad))
|
||||
return Song.MAGE;
|
||||
return Song.Mage;
|
||||
|
||||
return Song.NONE;
|
||||
return Song.None;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,15 +60,15 @@ public unsafe class BRDGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
get
|
||||
{
|
||||
if (this.Struct->SongFlags.HasFlag(SongFlags.WanderersMinuetLastPlayed))
|
||||
return Song.WANDERER;
|
||||
return Song.Wanderer;
|
||||
|
||||
if (this.Struct->SongFlags.HasFlag(SongFlags.ArmysPaeonLastPlayed))
|
||||
return Song.ARMY;
|
||||
return Song.Army;
|
||||
|
||||
if (this.Struct->SongFlags.HasFlag(SongFlags.MagesBalladLastPlayed))
|
||||
return Song.MAGE;
|
||||
return Song.Mage;
|
||||
|
||||
return Song.NONE;
|
||||
return Song.None;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ public unsafe class BRDGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
/// Gets the song Coda that are currently active.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will always return an array of size 3, inactive Coda are represented by <see cref="Song.NONE"/>.
|
||||
/// This will always return an array of size 3, inactive Coda are represented by <see cref="Enums.Song.None"/>.
|
||||
/// </remarks>
|
||||
public Song[] Coda
|
||||
{
|
||||
|
|
@ -84,9 +84,9 @@ public unsafe class BRDGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
{
|
||||
return new[]
|
||||
{
|
||||
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,
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
using Dalamud.Game.ClientState.JobGauge.Enums;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
|
||||
|
||||
namespace Dalamud.Game.ClientState.JobGauge.Types;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory DRK job gauge.
|
||||
/// </summary>
|
||||
public unsafe class DRKGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game.Gauge.DarkKnightGauge>
|
||||
public unsafe class DRKGauge : JobGaugeBase<DarkKnightGauge>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DRKGauge"/> class.
|
||||
|
|
@ -34,4 +37,16 @@ public unsafe class DRKGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool HasDarkArts => this.Struct->DarkArtsState > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the step of the Delirium Combo (Scarlet Delirium, Comeuppance,
|
||||
/// Torcleaver) that the player is on.<br/>
|
||||
/// Does not in any way consider whether the player is still under Delirium, or
|
||||
/// if the player still has stacks of Delirium to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Value will persist until combo is finished OR
|
||||
/// if the combo is not completed then the value will stay until about halfway into Delirium's cooldown.
|
||||
/// </remarks>
|
||||
public DeliriumStep DeliriumComboStep => (DeliriumStep)this.Struct->DeliriumStep;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public unsafe class MNKGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
/// Gets the types of Beast Chakra available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will always return an array of size 3, inactive Beast Chakra are represented by <see cref="BeastChakra.NONE"/>.
|
||||
/// This will always return an array of size 3, inactive Beast Chakra are represented by <see cref="Enums.BeastChakra.None"/>.
|
||||
/// </remarks>
|
||||
public BeastChakra[] BeastChakra => this.Struct->BeastChakra.Select(c => (BeastChakra)c).ToArray();
|
||||
|
||||
|
|
|
|||
|
|
@ -40,17 +40,17 @@ public unsafe class SAMGauge : JobGaugeBase<FFXIVClientStructs.FFXIV.Client.Game
|
|||
/// Gets a value indicating whether the Setsu Sen is active.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool HasSetsu => (this.Sen & Sen.SETSU) != 0;
|
||||
public bool HasSetsu => (this.Sen & Sen.Setsu) != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the Getsu Sen is active.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool HasGetsu => (this.Sen & Sen.GETSU) != 0;
|
||||
public bool HasGetsu => (this.Sen & Sen.Getsu) != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the Ka Sen is active.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool HasKa => (this.Sen & Sen.KA) != 0;
|
||||
public bool HasKa => (this.Sen & Sen.Ka) != 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@ public unsafe class SMNGauge : JobGaugeBase<SummonerGauge>
|
|||
/// <summary>
|
||||
/// Gets the time remaining for the current attunement.
|
||||
/// </summary>
|
||||
public ushort AttunmentTimerRemaining => this.Struct->AttunementTimer;
|
||||
[Obsolete("Typo fixed. Use AttunementTimerRemaining instead.", true)]
|
||||
public ushort AttunmentTimerRemaining => this.AttunementTimerRemaining;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time remaining for the current attunement.
|
||||
/// </summary>
|
||||
public ushort AttunementTimerRemaining => this.Struct->AttunementTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the summon that will return after the current summon expires.
|
||||
|
|
@ -40,10 +46,25 @@ public unsafe class SMNGauge : JobGaugeBase<SummonerGauge>
|
|||
public PetGlam ReturnSummonGlam => (PetGlam)this.Struct->ReturnSummonGlam;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of aspected Attunment remaining.
|
||||
/// Gets the amount of aspected Attunement remaining.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As of 7.01, this should be treated as a bit field.
|
||||
/// Use <see cref="AttunementCount"/> and <see cref="AttunementType"/> instead.
|
||||
/// </remarks>
|
||||
public byte Attunement => this.Struct->Attunement;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count of attunement cost resource available.
|
||||
/// </summary>
|
||||
public byte AttunementCount => this.Struct->AttunementCount;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of attunement available.
|
||||
/// Use the summon attuned accessors instead.
|
||||
/// </summary>
|
||||
public SummonAttunement AttunementType => (SummonAttunement)this.Struct->AttunementType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current aether flags.
|
||||
/// Use the summon accessors instead.
|
||||
|
|
@ -84,19 +105,19 @@ public unsafe class SMNGauge : JobGaugeBase<SummonerGauge>
|
|||
/// Gets a value indicating whether if Ifrit is currently attuned.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool IsIfritAttuned => this.AetherFlags.HasFlag(AetherFlags.IfritAttuned) && !this.AetherFlags.HasFlag(AetherFlags.GarudaAttuned);
|
||||
public bool IsIfritAttuned => this.AttunementType == SummonAttunement.Ifrit;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether if Titan is currently attuned.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool IsTitanAttuned => this.AetherFlags.HasFlag(AetherFlags.TitanAttuned) && !this.AetherFlags.HasFlag(AetherFlags.GarudaAttuned);
|
||||
public bool IsTitanAttuned => this.AttunementType == SummonAttunement.Titan;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether if Garuda is currently attuned.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> or <c>false</c>.</returns>
|
||||
public bool IsGarudaAttuned => this.AetherFlags.HasFlag(AetherFlags.GarudaAttuned);
|
||||
public bool IsGarudaAttuned => this.AttunementType == SummonAttunement.Garuda;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether there are any Aetherflow stacks available.
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
|
|||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
||||
|
|
@ -31,20 +29,13 @@ namespace Dalamud.Game.ClientState.Objects;
|
|||
#pragma warning restore SA1015
|
||||
internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
||||
{
|
||||
private static readonly ModuleLog Log = new("ObjectTable");
|
||||
|
||||
private static int objectTableLength;
|
||||
|
||||
private readonly ClientState clientState;
|
||||
private readonly CachedEntry[] cachedObjectTable;
|
||||
|
||||
private readonly ObjectPool<Enumerator> multiThreadedEnumerators =
|
||||
new DefaultObjectPoolProvider().Create<Enumerator>();
|
||||
|
||||
private readonly Enumerator?[] frameworkThreadEnumerators = new Enumerator?[4];
|
||||
|
||||
private long nextMultithreadedUsageWarnTime;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private unsafe ObjectTable(ClientState clientState)
|
||||
{
|
||||
|
|
@ -66,7 +57,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
{
|
||||
get
|
||||
{
|
||||
_ = this.WarnMultithreadedUsage();
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
return (nint)(&CSGameObjectManager.Instance()->Objects);
|
||||
}
|
||||
|
|
@ -80,7 +71,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
{
|
||||
get
|
||||
{
|
||||
_ = this.WarnMultithreadedUsage();
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
return (index >= objectTableLength || index < 0) ? null : this.cachedObjectTable[index].Update();
|
||||
}
|
||||
|
|
@ -89,7 +80,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
/// <inheritdoc/>
|
||||
public IGameObject? SearchById(ulong gameObjectId)
|
||||
{
|
||||
_ = this.WarnMultithreadedUsage();
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
if (gameObjectId is 0)
|
||||
return null;
|
||||
|
|
@ -106,7 +97,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
/// <inheritdoc/>
|
||||
public IGameObject? SearchByEntityId(uint entityId)
|
||||
{
|
||||
_ = this.WarnMultithreadedUsage();
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
if (entityId is 0 or 0xE0000000)
|
||||
return null;
|
||||
|
|
@ -123,7 +114,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
/// <inheritdoc/>
|
||||
public unsafe nint GetObjectAddress(int index)
|
||||
{
|
||||
_ = this.WarnMultithreadedUsage();
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
return (index >= objectTableLength || index < 0) ? nint.Zero : (nint)this.cachedObjectTable[index].Address;
|
||||
}
|
||||
|
|
@ -131,7 +122,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
/// <inheritdoc/>
|
||||
public unsafe IGameObject? CreateObjectReference(nint address)
|
||||
{
|
||||
_ = this.WarnMultithreadedUsage();
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
if (this.clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
|
@ -155,27 +146,6 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
};
|
||||
}
|
||||
|
||||
[Api12ToDo("Use ThreadSafety.AssertMainThread() instead of this.")]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool WarnMultithreadedUsage()
|
||||
{
|
||||
if (ThreadSafety.IsMainThread)
|
||||
return false;
|
||||
|
||||
var n = Environment.TickCount64;
|
||||
if (this.nextMultithreadedUsageWarnTime < n)
|
||||
{
|
||||
this.nextMultithreadedUsageWarnTime = n + 30000;
|
||||
|
||||
Log.Warning(
|
||||
"{plugin} is accessing {objectTable} outside the main thread. This is deprecated.",
|
||||
Service<PluginManager>.Get().FindCallingPlugin()?.Name ?? "<unknown plugin>",
|
||||
nameof(ObjectTable));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Stores an object table entry, with preallocated concrete types.</summary>
|
||||
/// <remarks>Initializes a new instance of the <see cref="CachedEntry"/> struct.</remarks>
|
||||
/// <param name="gameObjectPtr">A pointer to the object table entry this entry should be pointing to.</param>
|
||||
|
|
@ -228,14 +198,7 @@ internal sealed partial class ObjectTable
|
|||
/// <inheritdoc/>
|
||||
public IEnumerator<IGameObject> GetEnumerator()
|
||||
{
|
||||
// If something's trying to enumerate outside the framework thread, we use the ObjectPool.
|
||||
if (this.WarnMultithreadedUsage())
|
||||
{
|
||||
// let's not
|
||||
var e = this.multiThreadedEnumerators.Get();
|
||||
e.InitializeForPooledObjects(this);
|
||||
return e;
|
||||
}
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
// If we're on the framework thread, see if there's an already allocated enumerator available for use.
|
||||
foreach (ref var x in this.frameworkThreadEnumerators.AsSpan())
|
||||
|
|
@ -256,21 +219,12 @@ internal sealed partial class ObjectTable
|
|||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
private sealed class Enumerator : IEnumerator<IGameObject>, IResettable
|
||||
private sealed class Enumerator(ObjectTable owner, int slotId) : IEnumerator<IGameObject>, IResettable
|
||||
{
|
||||
private readonly int slotId;
|
||||
private ObjectTable? owner;
|
||||
private ObjectTable? owner = owner;
|
||||
|
||||
private int index = -1;
|
||||
|
||||
public Enumerator() => this.slotId = -1;
|
||||
|
||||
public Enumerator(ObjectTable owner, int slotId)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.slotId = slotId;
|
||||
}
|
||||
|
||||
public IGameObject Current { get; private set; } = null!;
|
||||
|
||||
object IEnumerator.Current => this.Current;
|
||||
|
|
@ -293,8 +247,6 @@ internal sealed partial class ObjectTable
|
|||
return false;
|
||||
}
|
||||
|
||||
public void InitializeForPooledObjects(ObjectTable ot) => this.owner = ot;
|
||||
|
||||
public void Reset() => this.index = -1;
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -302,10 +254,8 @@ internal sealed partial class ObjectTable
|
|||
if (this.owner is not { } o)
|
||||
return;
|
||||
|
||||
if (this.slotId == -1)
|
||||
o.multiThreadedEnumerators.Return(this);
|
||||
else
|
||||
o.frameworkThreadEnumerators[this.slotId] = this;
|
||||
if (slotId != -1)
|
||||
o.frameworkThreadEnumerators[slotId] = this;
|
||||
}
|
||||
|
||||
public bool TryReset()
|
||||
|
|
|
|||
|
|
@ -42,8 +42,10 @@ public unsafe class Status
|
|||
|
||||
/// <summary>
|
||||
/// Gets the stack count of this status.
|
||||
/// Only valid if this is a non-food status.
|
||||
/// </summary>
|
||||
public byte StackCount => this.Struct->StackCount;
|
||||
[Obsolete($"Replaced with {nameof(Param)}", true)]
|
||||
public byte StackCount => (byte)this.Struct->Param;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time remaining of this status.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class GameConfigSection
|
|||
/// <summary>
|
||||
/// Event which is fired when a game config option is changed within the section.
|
||||
/// </summary>
|
||||
internal event EventHandler<ConfigChangeEvent>? Changed;
|
||||
internal event EventHandler<ConfigChangeEvent>? Changed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of config entries contained within the section.
|
||||
|
|
@ -526,8 +526,8 @@ public class GameConfigSection
|
|||
{
|
||||
if (!this.enumMap.TryGetValue(entry->Index, out var enumObject))
|
||||
{
|
||||
if (entry->Name == null) return null;
|
||||
var name = MemoryHelper.ReadStringNullTerminated(new IntPtr(entry->Name));
|
||||
if (entry->Name.Value == null) return null;
|
||||
var name = entry->Name.ToString();
|
||||
if (Enum.TryParse(typeof(TEnum), name, out enumObject))
|
||||
{
|
||||
this.enumMap.TryAdd(entry->Index, enumObject);
|
||||
|
|
@ -544,7 +544,7 @@ public class GameConfigSection
|
|||
this.Changed?.InvokeSafely(this, eventArgs);
|
||||
return eventArgs;
|
||||
}
|
||||
|
||||
|
||||
private unsafe bool TryGetIndex(string name, out uint index)
|
||||
{
|
||||
if (this.indexMap.TryGetValue(name, out index))
|
||||
|
|
@ -556,12 +556,12 @@ public class GameConfigSection
|
|||
var e = configBase->ConfigEntry;
|
||||
for (var i = 0U; i < configBase->ConfigCount; i++, e++)
|
||||
{
|
||||
if (e->Name == null)
|
||||
if (e->Name.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var eName = MemoryHelper.ReadStringNullTerminated(new IntPtr(e->Name));
|
||||
var eName = e->Name.ToString();
|
||||
if (eName.Equals(name))
|
||||
{
|
||||
this.indexMap.TryAdd(name, i);
|
||||
|
|
|
|||
|
|
@ -597,6 +597,20 @@ public enum SystemConfigOption
|
|||
[GameConfigOption("EnablePsFunction", ConfigType.UInt)]
|
||||
EnablePsFunction,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name ActiveInstanceGuid.
|
||||
/// This option is a String.
|
||||
/// </summary>
|
||||
[GameConfigOption("ActiveInstanceGuid", ConfigType.String)]
|
||||
ActiveInstanceGuid,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name ActiveProductGuid.
|
||||
/// This option is a String.
|
||||
/// </summary>
|
||||
[GameConfigOption("ActiveProductGuid", ConfigType.String)]
|
||||
ActiveProductGuid,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name WaterWet.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -996,6 +1010,27 @@ public enum SystemConfigOption
|
|||
[GameConfigOption("AutoChangeCameraMode", ConfigType.UInt)]
|
||||
AutoChangeCameraMode,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name MsqProgress.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("MsqProgress", ConfigType.UInt)]
|
||||
MsqProgress,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name PromptConfigUpdate.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("PromptConfigUpdate", ConfigType.UInt)]
|
||||
PromptConfigUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name TitleScreenType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("TitleScreenType", ConfigType.UInt)]
|
||||
TitleScreenType,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name AccessibilitySoundVisualEnable.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -1059,6 +1094,13 @@ public enum SystemConfigOption
|
|||
[GameConfigOption("IdlingCameraAFK", ConfigType.UInt)]
|
||||
IdlingCameraAFK,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name FirstConfigBackup.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("FirstConfigBackup", ConfigType.UInt)]
|
||||
FirstConfigBackup,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name MouseSpeed.
|
||||
/// This option is a Float.
|
||||
|
|
@ -1436,46 +1478,4 @@ public enum SystemConfigOption
|
|||
/// </summary>
|
||||
[GameConfigOption("PadButton_R3", ConfigType.String)]
|
||||
PadButton_R3,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name ActiveInstanceGuid.
|
||||
/// This option is a String.
|
||||
/// </summary>
|
||||
[GameConfigOption("ActiveInstanceGuid", ConfigType.String)]
|
||||
ActiveInstanceGuid,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name ActiveProductGuid.
|
||||
/// This option is a String.
|
||||
/// </summary>
|
||||
[GameConfigOption("ActiveProductGuid", ConfigType.String)]
|
||||
ActiveProductGuid,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name MsqProgress.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("MsqProgress", ConfigType.UInt)]
|
||||
MsqProgress,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name PromptConfigUpdate.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("PromptConfigUpdate", ConfigType.UInt)]
|
||||
PromptConfigUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name TitleScreenType.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("TitleScreenType", ConfigType.UInt)]
|
||||
TitleScreenType,
|
||||
|
||||
/// <summary>
|
||||
/// System option with the internal name FirstConfigBackup.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("FirstConfigBackup", ConfigType.UInt)]
|
||||
FirstConfigBackup,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,13 @@ public enum UiConfigOption
|
|||
[GameConfigOption("BattleEffectPvPEnemyPc", ConfigType.UInt)]
|
||||
BattleEffectPvPEnemyPc,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name PadMode.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("PadMode", ConfigType.UInt)]
|
||||
PadMode,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name WeaponAutoPutAway.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -114,14 +121,6 @@ public enum UiConfigOption
|
|||
[GameConfigOption("LockonDefaultZoom", ConfigType.Float)]
|
||||
LockonDefaultZoom,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name LockonDefaultZoom_179.
|
||||
/// This option is a Float.
|
||||
/// </summary>
|
||||
[Obsolete("This option won't work. Use LockonDefaultZoom.", true)]
|
||||
[GameConfigOption("LockonDefaultZoom_179", ConfigType.Float)]
|
||||
LockonDefaultZoom_179,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name CameraProductionOfAction.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -311,6 +310,27 @@ public enum UiConfigOption
|
|||
[GameConfigOption("RightClickExclusionMinion", ConfigType.UInt)]
|
||||
RightClickExclusionMinion,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name EnableMoveTiltCharacter.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("EnableMoveTiltCharacter", ConfigType.UInt)]
|
||||
EnableMoveTiltCharacter,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name EnableMoveTiltMountGround.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("EnableMoveTiltMountGround", ConfigType.UInt)]
|
||||
EnableMoveTiltMountGround,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name EnableMoveTiltMountFly.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("EnableMoveTiltMountFly", ConfigType.UInt)]
|
||||
EnableMoveTiltMountFly,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name TurnSpeed.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -1130,6 +1150,27 @@ public enum UiConfigOption
|
|||
[GameConfigOption("HotbarXHBEditEnable", ConfigType.UInt)]
|
||||
HotbarXHBEditEnable,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name HotbarContentsAction2ReverseOperation.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("HotbarContentsAction2ReverseOperation", ConfigType.UInt)]
|
||||
HotbarContentsAction2ReverseOperation,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name HotbarContentsAction2ReturnInitialSlot.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("HotbarContentsAction2ReturnInitialSlot", ConfigType.UInt)]
|
||||
HotbarContentsAction2ReturnInitialSlot,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name HotbarContentsAction2ReverseRotate.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("HotbarContentsAction2ReverseRotate", ConfigType.UInt)]
|
||||
HotbarContentsAction2ReverseRotate,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name PlateType.
|
||||
/// This option is a UInt.
|
||||
|
|
@ -3572,32 +3613,4 @@ public enum UiConfigOption
|
|||
/// </summary>
|
||||
[GameConfigOption("PvPFrontlinesGCFree", ConfigType.UInt)]
|
||||
PvPFrontlinesGCFree,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name PadMode.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("PadMode", ConfigType.UInt)]
|
||||
PadMode,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name EnableMoveTiltCharacter.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("EnableMoveTiltCharacter", ConfigType.UInt)]
|
||||
EnableMoveTiltCharacter,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name EnableMoveTiltMountGround.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("EnableMoveTiltMountGround", ConfigType.UInt)]
|
||||
EnableMoveTiltMountGround,
|
||||
|
||||
/// <summary>
|
||||
/// UiConfig option with the internal name EnableMoveTiltMountFly.
|
||||
/// This option is a UInt.
|
||||
/// </summary>
|
||||
[GameConfigOption("EnableMoveTiltMountFly", ConfigType.UInt)]
|
||||
EnableMoveTiltMountFly,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
private const uint BaseNodeId = 1000;
|
||||
|
||||
private static readonly ModuleLog Log = new("DtrBar");
|
||||
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Framework framework = Service<Framework>.Get();
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
private ImmutableList<IReadOnlyDtrBarEntry>? entriesReadOnlyCopy;
|
||||
|
||||
private Utf8String* emptyString;
|
||||
|
||||
|
||||
private uint runningNodeIds = BaseNodeId;
|
||||
private float entryStartPos = float.NaN;
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
this.addonLifecycle.RegisterListener(this.dtrPostDrawListener);
|
||||
this.addonLifecycle.RegisterListener(this.dtrPostRequestedUpdateListener);
|
||||
this.addonLifecycle.RegisterListener(this.dtrPreFinalizeListener);
|
||||
|
||||
|
||||
this.framework.Update += this.Update;
|
||||
|
||||
this.configuration.DtrOrder ??= [];
|
||||
|
|
@ -522,7 +522,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseOut, this.DtrEventHandler),
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseClick, this.DtrEventHandler),
|
||||
});
|
||||
|
||||
|
||||
var lastChild = dtr->RootNode->ChildNode;
|
||||
while (lastChild->PrevSiblingNode != null) lastChild = lastChild->PrevSiblingNode;
|
||||
Log.Debug($"Found last sibling: {(ulong)lastChild:X}");
|
||||
|
|
@ -590,7 +590,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
|
||||
if (this.emptyString == null)
|
||||
this.emptyString = Utf8String.FromString(" ");
|
||||
|
||||
|
||||
newTextNode->SetText(this.emptyString->StringPtr);
|
||||
|
||||
newTextNode->TextColor = new ByteColor { R = 255, G = 255, B = 255, A = 255 };
|
||||
|
|
@ -609,7 +609,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
|
||||
return newTextNode;
|
||||
}
|
||||
|
||||
|
||||
private void DtrEventHandler(AddonEventType atkEventType, IntPtr atkUnitBase, IntPtr atkResNode)
|
||||
{
|
||||
var addon = (AtkUnitBase*)atkUnitBase;
|
||||
|
|
@ -632,7 +632,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
case AddonEventType.MouseOver:
|
||||
AtkStage.Instance()->TooltipManager.ShowTooltip(addon->Id, node, dtrBarEntry.Tooltip.Encode());
|
||||
break;
|
||||
|
||||
|
||||
case AddonEventType.MouseOut:
|
||||
AtkStage.Instance()->TooltipManager.HideTooltip(addon->Id);
|
||||
break;
|
||||
|
|
@ -646,11 +646,11 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
case AddonEventType.MouseOver:
|
||||
this.uiEventManager.SetCursor(AddonCursorType.Clickable);
|
||||
break;
|
||||
|
||||
|
||||
case AddonEventType.MouseOut:
|
||||
this.uiEventManager.ResetCursor();
|
||||
break;
|
||||
|
||||
|
||||
case AddonEventType.MouseClick:
|
||||
dtrBarEntry.OnClick.Invoke();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -92,214 +92,232 @@ public enum FlyTextKind : int
|
|||
/// </summary>
|
||||
IslandExp = 15,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font next to all caps condensed font Text1 with Text2 in sans-serif as subtitle.
|
||||
/// Added in 7.2, usage currently unknown.
|
||||
/// </summary>
|
||||
Unknown16 = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle.
|
||||
/// Added in 7.2, usage currently unknown.
|
||||
/// </summary>
|
||||
Unknown17 = 17,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle.
|
||||
/// Added in 7.2, usage currently unknown.
|
||||
/// </summary>
|
||||
Unknown18 = 18,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
MpDrain = 16,
|
||||
MpDrain = 19,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedTp = 17,
|
||||
NamedTp = 20,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// </summary>
|
||||
Healing = 18,
|
||||
Healing = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
MpRegen = 19,
|
||||
MpRegen = 22,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedTp2 = 20,
|
||||
NamedTp2 = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font EP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
EpRegen = 21,
|
||||
EpRegen = 24,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font CP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
CpRegen = 22,
|
||||
CpRegen = 25,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font GP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
GpRegen = 23,
|
||||
GpRegen = 26,
|
||||
|
||||
/// <summary>
|
||||
/// Displays nothing.
|
||||
/// </summary>
|
||||
None = 24,
|
||||
None = 27,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif INVULNERABLE.
|
||||
/// </summary>
|
||||
Invulnerable = 25,
|
||||
Invulnerable = 28,
|
||||
|
||||
/// <summary>
|
||||
/// All caps sans-serif condensed font INTERRUPTED!
|
||||
/// Does a large bounce effect on appearance.
|
||||
/// Does not scroll up or down the screen.
|
||||
/// </summary>
|
||||
Interrupted = 26,
|
||||
Interrupted = 29,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
CraftingProgress = 27,
|
||||
CraftingProgress = 30,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
CraftingQuality = 28,
|
||||
CraftingQuality = 31,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle. Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CraftingQualityCrit = 29,
|
||||
CraftingQualityCrit = 32,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
AutoAttackNoText3 = 30,
|
||||
AutoAttackNoText3 = 33,
|
||||
|
||||
/// <summary>
|
||||
/// CriticalHit with sans-serif Text1 to the left of the Val1 (2).
|
||||
/// </summary>
|
||||
HealingCrit = 31,
|
||||
HealingCrit = 34,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Same as DamageCrit with a MP in condensed font to the right of Val1.
|
||||
/// Does a jiggle effect to the right on appearance.
|
||||
/// </summary>
|
||||
NamedCriticalHitWithMp = 32,
|
||||
NamedCriticalHitWithMp = 35,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Same as DamageCrit with a TP in condensed font to the right of Val1.
|
||||
/// Does a jiggle effect to the right on appearance.
|
||||
/// </summary>
|
||||
NamedCriticalHitWithTp = 33,
|
||||
NamedCriticalHitWithTp = 36,
|
||||
|
||||
/// <summary>
|
||||
/// Icon next to sans-serif Text1 with sans-serif "has no effect!" to the right.
|
||||
/// </summary>
|
||||
DebuffNoEffect = 34,
|
||||
DebuffNoEffect = 37,
|
||||
|
||||
/// <summary>
|
||||
/// Icon next to sans-serif slightly faded Text1.
|
||||
/// </summary>
|
||||
BuffFading = 35,
|
||||
BuffFading = 38,
|
||||
|
||||
/// <summary>
|
||||
/// Icon next to sans-serif slightly faded Text1.
|
||||
/// </summary>
|
||||
DebuffFading = 36,
|
||||
DebuffFading = 39,
|
||||
|
||||
/// <summary>
|
||||
/// Text1 in sans-serif font.
|
||||
/// </summary>
|
||||
Named = 37,
|
||||
Named = 40,
|
||||
|
||||
/// <summary>
|
||||
/// Icon next to sans-serif Text1 with sans-serif "(fully resisted)" to the right.
|
||||
/// </summary>
|
||||
DebuffResisted = 38,
|
||||
DebuffResisted = 41,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif 'INCAPACITATED!'.
|
||||
/// </summary>
|
||||
Incapacitated = 39,
|
||||
Incapacitated = 42,
|
||||
|
||||
/// <summary>
|
||||
/// Text1 with sans-serif "(fully resisted)" to the right.
|
||||
/// </summary>
|
||||
FullyResisted = 40,
|
||||
FullyResisted = 43,
|
||||
|
||||
/// <summary>
|
||||
/// Text1 with sans-serif "has no effect!" to the right.
|
||||
/// </summary>
|
||||
HasNoEffect = 41,
|
||||
HasNoEffect = 44,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// </summary>
|
||||
HpDrain = 42,
|
||||
HpDrain = 45,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedMp3 = 43,
|
||||
NamedMp3 = 46,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedTp3 = 44,
|
||||
NamedTp3 = 47,
|
||||
|
||||
/// <summary>
|
||||
/// Icon next to sans-serif Text1 with serif "INVULNERABLE!" beneath the Text1.
|
||||
/// </summary>
|
||||
DebuffInvulnerable = 45,
|
||||
DebuffInvulnerable = 48,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif RESIST.
|
||||
/// </summary>
|
||||
Resist = 46,
|
||||
Resist = 49,
|
||||
|
||||
/// <summary>
|
||||
/// Icon with an item icon outline next to sans-serif Text1.
|
||||
/// </summary>
|
||||
LootedItem = 47,
|
||||
LootedItem = 50,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
Collectability = 48,
|
||||
Collectability = 51,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle.
|
||||
/// Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CollectabilityCrit = 49,
|
||||
CollectabilityCrit = 52,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif REFLECT.
|
||||
/// </summary>
|
||||
Reflect = 50,
|
||||
Reflect = 53,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif REFLECTED.
|
||||
/// </summary>
|
||||
Reflected = 51,
|
||||
Reflected = 54,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle.
|
||||
/// Does a bounce effect on appearance.
|
||||
/// </summary>
|
||||
CraftingQualityDh = 52,
|
||||
CraftingQualityDh = 55,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle.
|
||||
/// Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CriticalHit4 = 53,
|
||||
CriticalHit4 = 56,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in even larger serif font with 2 exclamations, Text2 in sans-serif as subtitle.
|
||||
/// Does a large bounce effect on appearance. Does not scroll up or down the screen.
|
||||
/// </summary>
|
||||
CraftingQualityCritDh = 54,
|
||||
CraftingQualityCritDh = 57,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
|
|||
return ret;
|
||||
}
|
||||
|
||||
private void HandleActionHoverDetour(AgentActionDetail* hoverState, ActionKind actionKind, uint actionId, int a4, byte a5)
|
||||
private void HandleActionHoverDetour(AgentActionDetail* hoverState, FFXIVClientStructs.FFXIV.Client.UI.Agent.ActionKind actionKind, uint actionId, int a4, byte a5)
|
||||
{
|
||||
this.handleActionHoverHook.Original(hoverState, actionKind, actionId, a4, a5);
|
||||
this.HoveredAction.ActionKind = (HoverActionKind)actionKind;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
|
|||
this.locDalamudSettings = Loc.Localize("SystemMenuSettings", "Dalamud Settings");
|
||||
|
||||
// this.contextMenu.ContextMenuOpened += this.ContextMenuOnContextMenuOpened;
|
||||
|
||||
|
||||
this.hookAgentHudOpenSystemMenu.Enable();
|
||||
this.hookUiModuleExecuteMainCommand.Enable();
|
||||
this.hookAtkUnitBaseReceiveGlobalEvent.Enable();
|
||||
|
|
@ -180,7 +180,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
|
|||
// about hooking the exd reader, thank god
|
||||
var firstStringEntry = &atkValueArgs[5 + 18];
|
||||
firstStringEntry->ChangeType(ValueType.String);
|
||||
|
||||
|
||||
var secondStringEntry = &atkValueArgs[6 + 18];
|
||||
secondStringEntry->ChangeType(ValueType.String);
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
|
|||
.Append($"{SeIconChar.BoxedLetterD.ToIconString()} ")
|
||||
.Append(new UIForegroundPayload(0))
|
||||
.Append(this.locDalamudSettings).Encode();
|
||||
|
||||
|
||||
firstStringEntry->SetManagedString(strPlugins);
|
||||
secondStringEntry->SetManagedString(strSettings);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public unsafe struct GameInventoryItem : IEquatable<GameInventoryItem>
|
|||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
internal readonly InventoryItem InternalItem;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The view of the backing data, in <see cref="ulong"/>.
|
||||
/// </summary>
|
||||
|
|
@ -55,10 +55,16 @@ public unsafe struct GameInventoryItem : IEquatable<GameInventoryItem>
|
|||
/// </summary>
|
||||
public int Quantity => this.InternalItem.Quantity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the spiritbond or collectability of this item.
|
||||
/// </summary>
|
||||
public uint SpiritbondOrCollectability => this.InternalItem.SpiritbondOrCollectability;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the spiritbond of this item.
|
||||
/// </summary>
|
||||
public uint Spiritbond => this.InternalItem.Spiritbond;
|
||||
[Obsolete($"Renamed to {nameof(SpiritbondOrCollectability)}", true)]
|
||||
public uint Spiritbond => this.SpiritbondOrCollectability;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the repair condition of this item.
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
|
|||
return this.configuration.IsMbCollect;
|
||||
}
|
||||
|
||||
private void MarketPurchasePacketDetour(PacketDispatcher* a1, nint packetData)
|
||||
private void MarketPurchasePacketDetour(uint targetId, nint packetData)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -576,7 +576,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
|
|||
Log.Error(ex, "MarketPurchasePacketHandler threw an exception");
|
||||
}
|
||||
|
||||
this.mbPurchaseHook.OriginalDisposeSafe(a1, packetData);
|
||||
this.mbPurchaseHook.OriginalDisposeSafe(targetId, packetData);
|
||||
}
|
||||
|
||||
private void MarketHistoryPacketDetour(InfoProxyItemSearch* a1, nint packetData)
|
||||
|
|
@ -609,7 +609,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
|
|||
this.customTalkHook.OriginalDisposeSafe(a1, eventId, responseId, args, argCount);
|
||||
}
|
||||
|
||||
private void MarketItemRequestStartDetour(PacketDispatcher* a1, nint packetRef)
|
||||
private void MarketItemRequestStartDetour(uint targetId, nint packetRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -620,7 +620,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
|
|||
Log.Error(ex, "MarketItemRequestStartDetour threw an exception");
|
||||
}
|
||||
|
||||
this.mbItemRequestStartHook.OriginalDisposeSafe(a1, packetRef);
|
||||
this.mbItemRequestStartHook.OriginalDisposeSafe(targetId, packetRef);
|
||||
}
|
||||
|
||||
private void MarketBoardOfferingsDetour(InfoProxyItemSearch* a1, nint packetRef)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
using Lumina.Text;
|
||||
|
||||
namespace Dalamud.Game.Text.Evaluator.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps payloads in an open and close icon, for example the Auto Translation open/close brackets.
|
||||
/// </summary>
|
||||
internal readonly struct SeStringBuilderIconWrap : IDisposable
|
||||
{
|
||||
private readonly SeStringBuilder builder;
|
||||
private readonly uint iconClose;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeStringBuilderIconWrap"/> struct.<br/>
|
||||
/// Appends an icon macro with <paramref name="iconOpen"/> on creation, and an icon macro with
|
||||
/// <paramref name="iconClose"/> on disposal.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder to use.</param>
|
||||
/// <param name="iconOpen">The open icon id.</param>
|
||||
/// <param name="iconClose">The close icon id.</param>
|
||||
public SeStringBuilderIconWrap(SeStringBuilder builder, uint iconOpen, uint iconClose)
|
||||
{
|
||||
this.builder = builder;
|
||||
this.iconClose = iconClose;
|
||||
this.builder.AppendIcon(iconOpen);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose() => this.builder.AppendIcon(this.iconClose);
|
||||
}
|
||||
83
Dalamud/Game/Text/Evaluator/Internal/SeStringContext.cs
Normal file
83
Dalamud/Game/Text/Evaluator/Internal/SeStringContext.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
using System.Globalization;
|
||||
|
||||
using Dalamud.Utility;
|
||||
|
||||
using Lumina.Text;
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
namespace Dalamud.Game.Text.Evaluator.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// A context wrapper used in <see cref="SeStringEvaluator"/>.
|
||||
/// </summary>
|
||||
internal readonly ref struct SeStringContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="SeStringBuilder"/> to append text and macros to.
|
||||
/// </summary>
|
||||
internal readonly SeStringBuilder Builder;
|
||||
|
||||
/// <summary>
|
||||
/// A list of local parameters.
|
||||
/// </summary>
|
||||
internal readonly Span<SeStringParameter> LocalParameters;
|
||||
|
||||
/// <summary>
|
||||
/// The target language, used for sheet lookups.
|
||||
/// </summary>
|
||||
internal readonly ClientLanguage Language;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeStringContext"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="SeStringBuilder"/> to append text and macros to.</param>
|
||||
/// <param name="localParameters">A list of local parameters.</param>
|
||||
/// <param name="language">The target language, used for sheet lookups.</param>
|
||||
internal SeStringContext(SeStringBuilder builder, Span<SeStringParameter> localParameters, ClientLanguage language)
|
||||
{
|
||||
this.Builder = builder;
|
||||
this.LocalParameters = localParameters;
|
||||
this.Language = language;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="System.Globalization.CultureInfo"/> of the current target <see cref="Language"/>.
|
||||
/// </summary>
|
||||
internal CultureInfo CultureInfo => Localization.GetCultureInfoFromLangCode(this.Language.ToCode());
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a number from the local parameters at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index in the <see cref="LocalParameters"/> list.</param>
|
||||
/// <param name="value">The local parameter number.</param>
|
||||
/// <returns><c>true</c> if the local parameters list contained a parameter at given index, <c>false</c> otherwise.</returns>
|
||||
internal bool TryGetLNum(int index, out uint value)
|
||||
{
|
||||
if (index >= 0 && this.LocalParameters.Length > index)
|
||||
{
|
||||
value = this.LocalParameters[index].UIntValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a string from the local parameters at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index in the <see cref="LocalParameters"/> list.</param>
|
||||
/// <param name="value">The local parameter string.</param>
|
||||
/// <returns><c>true</c> if the local parameters list contained a parameter at given index, <c>false</c> otherwise.</returns>
|
||||
internal bool TryGetLStr(int index, out ReadOnlySeString value)
|
||||
{
|
||||
if (index >= 0 && this.LocalParameters.Length > index)
|
||||
{
|
||||
value = this.LocalParameters[index].StringValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
49
Dalamud/Game/Text/Evaluator/Internal/SheetRedirectFlags.cs
Normal file
49
Dalamud/Game/Text/Evaluator/Internal/SheetRedirectFlags.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
namespace Dalamud.Game.Text.Evaluator.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// An enum providing additional information about the sheet redirect.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum SheetRedirectFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// No flags.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Resolved to a sheet related with items.
|
||||
/// </summary>
|
||||
Item = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Resolved to the EventItem sheet.
|
||||
/// </summary>
|
||||
EventItem = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Resolved to a high quality item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Append Addon#9.
|
||||
/// </remarks>
|
||||
HighQuality = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Resolved to a collectible item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Append Addon#150.
|
||||
/// </remarks>
|
||||
Collectible = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Resolved to a sheet related with actions.
|
||||
/// </summary>
|
||||
Action = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Resolved to the Action sheet.
|
||||
/// </summary>
|
||||
ActionSheet = 32,
|
||||
}
|
||||
233
Dalamud/Game/Text/Evaluator/Internal/SheetRedirectResolver.cs
Normal file
233
Dalamud/Game/Text/Evaluator/Internal/SheetRedirectResolver.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
using Dalamud.Data;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using Lumina.Extensions;
|
||||
|
||||
using ItemKind = Dalamud.Game.Text.SeStringHandling.Payloads.ItemPayload.ItemKind;
|
||||
using LSheets = Lumina.Excel.Sheets;
|
||||
|
||||
namespace Dalamud.Game.Text.Evaluator.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// A service to resolve sheet redirects in expressions.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class SheetRedirectResolver : IServiceType
|
||||
{
|
||||
private static readonly (string SheetName, uint ColumnIndex, bool ReturnActionSheetFlag)[] ActStrSheets =
|
||||
[
|
||||
(nameof(LSheets.Trait), 0, false),
|
||||
(nameof(LSheets.Action), 0, true),
|
||||
(nameof(LSheets.Item), 0, false),
|
||||
(nameof(LSheets.EventItem), 0, false),
|
||||
(nameof(LSheets.EventAction), 0, false),
|
||||
(nameof(LSheets.GeneralAction), 0, false),
|
||||
(nameof(LSheets.BuddyAction), 0, false),
|
||||
(nameof(LSheets.MainCommand), 5, false),
|
||||
(nameof(LSheets.Companion), 0, false),
|
||||
(nameof(LSheets.CraftAction), 0, false),
|
||||
(nameof(LSheets.Action), 0, true),
|
||||
(nameof(LSheets.PetAction), 0, false),
|
||||
(nameof(LSheets.CompanyAction), 0, false),
|
||||
(nameof(LSheets.Mount), 0, false),
|
||||
(string.Empty, 0, false),
|
||||
(string.Empty, 0, false),
|
||||
(string.Empty, 0, false),
|
||||
(string.Empty, 0, false),
|
||||
(string.Empty, 0, false),
|
||||
(nameof(LSheets.BgcArmyAction), 1, false),
|
||||
(nameof(LSheets.Ornament), 8, false),
|
||||
];
|
||||
|
||||
private static readonly string[] ObjStrSheetNames =
|
||||
[
|
||||
nameof(LSheets.BNpcName),
|
||||
nameof(LSheets.ENpcResident),
|
||||
nameof(LSheets.Treasure),
|
||||
nameof(LSheets.Aetheryte),
|
||||
nameof(LSheets.GatheringPointName),
|
||||
nameof(LSheets.EObjName),
|
||||
nameof(LSheets.Mount),
|
||||
nameof(LSheets.Companion),
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
nameof(LSheets.Item),
|
||||
];
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DataManager dataManager = Service<DataManager>.Get();
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private SheetRedirectResolver()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the sheet redirect, if any is present.
|
||||
/// </summary>
|
||||
/// <param name="sheetName">The sheet name.</param>
|
||||
/// <param name="rowId">The row id.</param>
|
||||
/// <param name="colIndex">The column index. Use <c>ushort.MaxValue</c> as default.</param>
|
||||
/// <returns>Flags giving additional information about the redirect.</returns>
|
||||
internal SheetRedirectFlags Resolve(ref string sheetName, ref uint rowId, ref uint colIndex)
|
||||
{
|
||||
var flags = SheetRedirectFlags.None;
|
||||
|
||||
switch (sheetName)
|
||||
{
|
||||
case nameof(LSheets.Item) or "ItemHQ" or "ItemMP":
|
||||
{
|
||||
flags |= SheetRedirectFlags.Item;
|
||||
|
||||
var (itemId, kind) = ItemUtil.GetBaseId(rowId);
|
||||
|
||||
if (kind == ItemKind.Hq || sheetName == "ItemHQ")
|
||||
{
|
||||
flags |= SheetRedirectFlags.HighQuality;
|
||||
}
|
||||
else if (kind == ItemKind.Collectible || sheetName == "ItemMP")
|
||||
{
|
||||
// MP for Masterpiece?!
|
||||
flags |= SheetRedirectFlags.Collectible;
|
||||
}
|
||||
|
||||
if (kind == ItemKind.EventItem &&
|
||||
rowId - 2_000_000 <= this.dataManager.GetExcelSheet<LSheets.EventItem>().Count)
|
||||
{
|
||||
flags |= SheetRedirectFlags.EventItem;
|
||||
sheetName = nameof(LSheets.EventItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
sheetName = nameof(LSheets.Item);
|
||||
rowId = itemId;
|
||||
}
|
||||
|
||||
if (colIndex is >= 4 and <= 7)
|
||||
return SheetRedirectFlags.None;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "ActStr":
|
||||
{
|
||||
var returnActionSheetFlag = false;
|
||||
(var index, rowId) = uint.DivRem(rowId, 1000000);
|
||||
if (index < ActStrSheets.Length)
|
||||
(sheetName, colIndex, returnActionSheetFlag) = ActStrSheets[index];
|
||||
|
||||
if (sheetName != nameof(LSheets.Companion) && colIndex != 13)
|
||||
flags |= SheetRedirectFlags.Action;
|
||||
|
||||
if (returnActionSheetFlag)
|
||||
flags |= SheetRedirectFlags.ActionSheet;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "ObjStr":
|
||||
{
|
||||
(var index, rowId) = uint.DivRem(rowId, 1000000);
|
||||
if (index < ObjStrSheetNames.Length)
|
||||
sheetName = ObjStrSheetNames[index];
|
||||
|
||||
colIndex = 0;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0: // BNpcName
|
||||
if (rowId >= 100000)
|
||||
rowId += 900000;
|
||||
break;
|
||||
|
||||
case 1: // ENpcResident
|
||||
rowId += 1000000;
|
||||
break;
|
||||
|
||||
case 2: // Treasure
|
||||
if (this.dataManager.GetExcelSheet<LSheets.Treasure>().TryGetRow(rowId, out var treasureRow) &&
|
||||
treasureRow.Unknown0.IsEmpty)
|
||||
rowId = 0; // defaulting to "Treasure Coffer"
|
||||
break;
|
||||
|
||||
case 3: // Aetheryte
|
||||
rowId = this.dataManager.GetExcelSheet<LSheets.Aetheryte>()
|
||||
.TryGetRow(rowId, out var aetheryteRow) && aetheryteRow.IsAetheryte
|
||||
? 0u // "Aetheryte"
|
||||
: 1; // "Aethernet Shard"
|
||||
break;
|
||||
|
||||
case 5: // EObjName
|
||||
rowId += 2000000;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case nameof(LSheets.EObj) when colIndex is <= 7 or ushort.MaxValue:
|
||||
sheetName = nameof(LSheets.EObjName);
|
||||
break;
|
||||
|
||||
case nameof(LSheets.Treasure)
|
||||
when this.dataManager.GetExcelSheet<LSheets.Treasure>().TryGetRow(rowId, out var treasureRow) &&
|
||||
treasureRow.Unknown0.IsEmpty:
|
||||
rowId = 0; // defaulting to "Treasure Coffer"
|
||||
break;
|
||||
|
||||
case "WeatherPlaceName":
|
||||
{
|
||||
sheetName = nameof(LSheets.PlaceName);
|
||||
|
||||
var placeNameSubId = rowId;
|
||||
if (this.dataManager.GetExcelSheet<LSheets.WeatherReportReplace>().TryGetFirst(
|
||||
r => r.PlaceNameSub.RowId == placeNameSubId,
|
||||
out var row))
|
||||
rowId = row.PlaceNameParent.RowId;
|
||||
break;
|
||||
}
|
||||
|
||||
case nameof(LSheets.InstanceContent) when colIndex == 3:
|
||||
{
|
||||
sheetName = nameof(LSheets.ContentFinderCondition);
|
||||
colIndex = 43;
|
||||
|
||||
if (this.dataManager.GetExcelSheet<LSheets.InstanceContent>().TryGetRow(rowId, out var row))
|
||||
rowId = row.ContentFinderCondition.RowId;
|
||||
break;
|
||||
}
|
||||
|
||||
case nameof(LSheets.PartyContent) when colIndex == 2:
|
||||
{
|
||||
sheetName = nameof(LSheets.ContentFinderCondition);
|
||||
colIndex = 43;
|
||||
|
||||
if (this.dataManager.GetExcelSheet<LSheets.PartyContent>().TryGetRow(rowId, out var row))
|
||||
rowId = row.ContentFinderCondition.RowId;
|
||||
break;
|
||||
}
|
||||
|
||||
case nameof(LSheets.PublicContent) when colIndex == 3:
|
||||
{
|
||||
sheetName = nameof(LSheets.ContentFinderCondition);
|
||||
colIndex = 43;
|
||||
|
||||
if (this.dataManager.GetExcelSheet<LSheets.PublicContent>().TryGetRow(rowId, out var row))
|
||||
rowId = row.ContentFinderCondition.RowId;
|
||||
break;
|
||||
}
|
||||
|
||||
case nameof(LSheets.AkatsukiNote):
|
||||
{
|
||||
sheetName = nameof(LSheets.AkatsukiNoteString);
|
||||
colIndex = 0;
|
||||
|
||||
if (this.dataManager.Excel.GetSubrowSheet<LSheets.AkatsukiNote>().TryGetRow(rowId, out var row))
|
||||
rowId = (uint)row[0].Unknown2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
1995
Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs
Normal file
1995
Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs
Normal file
File diff suppressed because it is too large
Load diff
79
Dalamud/Game/Text/Evaluator/SeStringParameter.cs
Normal file
79
Dalamud/Game/Text/Evaluator/SeStringParameter.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
using System.Globalization;
|
||||
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
using DSeString = Dalamud.Game.Text.SeStringHandling.SeString;
|
||||
using LSeString = Lumina.Text.SeString;
|
||||
|
||||
namespace Dalamud.Game.Text.Evaluator;
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for a local parameter, holding either a number or a string.
|
||||
/// </summary>
|
||||
public readonly struct SeStringParameter
|
||||
{
|
||||
private readonly uint num;
|
||||
private readonly ReadOnlySeString str;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeStringParameter"/> struct for a number parameter.
|
||||
/// </summary>
|
||||
/// <param name="value">The number value.</param>
|
||||
public SeStringParameter(uint value)
|
||||
{
|
||||
this.num = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeStringParameter"/> struct for a string parameter.
|
||||
/// </summary>
|
||||
/// <param name="value">The string value.</param>
|
||||
public SeStringParameter(ReadOnlySeString value)
|
||||
{
|
||||
this.str = value;
|
||||
this.IsString = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeStringParameter"/> struct for a string parameter.
|
||||
/// </summary>
|
||||
/// <param name="value">The string value.</param>
|
||||
public SeStringParameter(string value)
|
||||
{
|
||||
this.str = new ReadOnlySeString(value);
|
||||
this.IsString = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the backing type of this parameter is a string.
|
||||
/// </summary>
|
||||
public bool IsString { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a numeric value.
|
||||
/// </summary>
|
||||
public uint UIntValue =>
|
||||
!this.IsString
|
||||
? this.num
|
||||
: uint.TryParse(this.str.ExtractText(), out var value) ? value : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string value.
|
||||
/// </summary>
|
||||
public ReadOnlySeString StringValue =>
|
||||
this.IsString ? this.str : new(this.num.ToString("D", CultureInfo.InvariantCulture));
|
||||
|
||||
public static implicit operator SeStringParameter(int value) => new((uint)value);
|
||||
|
||||
public static implicit operator SeStringParameter(uint value) => new(value);
|
||||
|
||||
public static implicit operator SeStringParameter(ReadOnlySeString value) => new(value);
|
||||
|
||||
public static implicit operator SeStringParameter(ReadOnlySeStringSpan value) => new(new ReadOnlySeString(value));
|
||||
|
||||
public static implicit operator SeStringParameter(LSeString value) => new(new ReadOnlySeString(value.RawData));
|
||||
|
||||
public static implicit operator SeStringParameter(DSeString value) => new(new ReadOnlySeString(value.Encode()));
|
||||
|
||||
public static implicit operator SeStringParameter(string value) => new(value);
|
||||
}
|
||||
17
Dalamud/Game/Text/Noun/Enums/EnglishArticleType.cs
Normal file
17
Dalamud/Game/Text/Noun/Enums/EnglishArticleType.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace Dalamud.Game.Text.Noun.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Article types for <see cref="ClientLanguage.English"/>.
|
||||
/// </summary>
|
||||
public enum EnglishArticleType
|
||||
{
|
||||
/// <summary>
|
||||
/// Indefinite article (a, an).
|
||||
/// </summary>
|
||||
Indefinite = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Definite article (the).
|
||||
/// </summary>
|
||||
Definite = 2,
|
||||
}
|
||||
32
Dalamud/Game/Text/Noun/Enums/FrenchArticleType.cs
Normal file
32
Dalamud/Game/Text/Noun/Enums/FrenchArticleType.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
namespace Dalamud.Game.Text.Noun.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Article types for <see cref="ClientLanguage.French"/>.
|
||||
/// </summary>
|
||||
public enum FrenchArticleType
|
||||
{
|
||||
/// <summary>
|
||||
/// Indefinite article (une, des).
|
||||
/// </summary>
|
||||
Indefinite = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Definite article (le, la, les).
|
||||
/// </summary>
|
||||
Definite = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Possessive article (mon, mes).
|
||||
/// </summary>
|
||||
PossessiveFirstPerson = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Possessive article (ton, tes).
|
||||
/// </summary>
|
||||
PossessiveSecondPerson = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Possessive article (son, ses).
|
||||
/// </summary>
|
||||
PossessiveThirdPerson = 5,
|
||||
}
|
||||
37
Dalamud/Game/Text/Noun/Enums/GermanArticleType.cs
Normal file
37
Dalamud/Game/Text/Noun/Enums/GermanArticleType.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
namespace Dalamud.Game.Text.Noun.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Article types for <see cref="ClientLanguage.German"/>.
|
||||
/// </summary>
|
||||
public enum GermanArticleType
|
||||
{
|
||||
/// <summary>
|
||||
/// Unbestimmter Artikel (ein, eine, etc.).
|
||||
/// </summary>
|
||||
Indefinite = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Bestimmter Artikel (der, die, das, etc.).
|
||||
/// </summary>
|
||||
Definite = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Possessivartikel "dein" (dein, deine, etc.).
|
||||
/// </summary>
|
||||
Possessive = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Negativartikel "kein" (kein, keine, etc.).
|
||||
/// </summary>
|
||||
Negative = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Nullartikel.
|
||||
/// </summary>
|
||||
ZeroArticle = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrativpronomen "dieser" (dieser, diese, etc.).
|
||||
/// </summary>
|
||||
Demonstrative = 6,
|
||||
}
|
||||
17
Dalamud/Game/Text/Noun/Enums/JapaneseArticleType.cs
Normal file
17
Dalamud/Game/Text/Noun/Enums/JapaneseArticleType.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace Dalamud.Game.Text.Noun.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Article types for <see cref="ClientLanguage.Japanese"/>.
|
||||
/// </summary>
|
||||
public enum JapaneseArticleType
|
||||
{
|
||||
/// <summary>
|
||||
/// Near listener (それら).
|
||||
/// </summary>
|
||||
NearListener = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Distant from both speaker and listener (あれら).
|
||||
/// </summary>
|
||||
Distant = 2,
|
||||
}
|
||||
73
Dalamud/Game/Text/Noun/NounParams.cs
Normal file
73
Dalamud/Game/Text/Noun/NounParams.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
using Dalamud.Game.Text.Noun.Enums;
|
||||
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
using LSheets = Lumina.Excel.Sheets;
|
||||
|
||||
namespace Dalamud.Game.Text.Noun;
|
||||
|
||||
/// <summary>
|
||||
/// Parameters for noun processing.
|
||||
/// </summary>
|
||||
internal record struct NounParams()
|
||||
{
|
||||
/// <summary>
|
||||
/// The language of the sheet to be processed.
|
||||
/// </summary>
|
||||
public required ClientLanguage Language;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the sheet containing the row to process.
|
||||
/// </summary>
|
||||
public required string SheetName = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The row id within the sheet to process.
|
||||
/// </summary>
|
||||
public required uint RowId;
|
||||
|
||||
/// <summary>
|
||||
/// The quantity of the entity (default is 1). Used to determine grammatical number (e.g., singular or plural).
|
||||
/// </summary>
|
||||
public int Quantity = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The article type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Depending on the <see cref="Language"/>, this has different meanings.<br/>
|
||||
/// See <see cref="JapaneseArticleType"/>, <see cref="GermanArticleType"/>, <see cref="FrenchArticleType"/>, <see cref="EnglishArticleType"/>.
|
||||
/// </remarks>
|
||||
public int ArticleType = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The grammatical case (e.g., Nominative, Genitive, Dative, Accusative) used for German texts (default is 0).
|
||||
/// </summary>
|
||||
public int GrammaticalCase = 0;
|
||||
|
||||
/// <summary>
|
||||
/// An optional string that is placed in front of the text that should be linked, such as item names (default is an empty string; the game uses "//").
|
||||
/// </summary>
|
||||
public ReadOnlySeString LinkMarker = default;
|
||||
|
||||
/// <summary>
|
||||
/// An indicator that this noun will be processed from an Action sheet. Only used for German texts.
|
||||
/// </summary>
|
||||
public bool IsActionSheet;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the column offset.
|
||||
/// </summary>
|
||||
public readonly int ColumnOffset => this.SheetName switch
|
||||
{
|
||||
// See "E8 ?? ?? ?? ?? 44 8B 6B 08"
|
||||
nameof(LSheets.BeastTribe) => 10,
|
||||
nameof(LSheets.DeepDungeonItem) => 1,
|
||||
nameof(LSheets.DeepDungeonEquipment) => 1,
|
||||
nameof(LSheets.DeepDungeonMagicStone) => 1,
|
||||
nameof(LSheets.DeepDungeonDemiclone) => 1,
|
||||
nameof(LSheets.Glasses) => 4,
|
||||
nameof(LSheets.GlassesStyle) => 15,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
461
Dalamud/Game/Text/Noun/NounProcessor.cs
Normal file
461
Dalamud/Game/Text/Noun/NounProcessor.cs
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
using System.Collections.Concurrent;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.Text.Noun.Enums;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using Lumina.Excel;
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
using LSeStringBuilder = Lumina.Text.SeStringBuilder;
|
||||
using LSheets = Lumina.Excel.Sheets;
|
||||
|
||||
namespace Dalamud.Game.Text.Noun;
|
||||
|
||||
/*
|
||||
Attributive sheet:
|
||||
Japanese:
|
||||
Unknown0 = Singular Demonstrative
|
||||
Unknown1 = Plural Demonstrative
|
||||
English:
|
||||
Unknown2 = Article before a singular noun beginning with a consonant sound
|
||||
Unknown3 = Article before a generic noun beginning with a consonant sound
|
||||
Unknown4 = N/A
|
||||
Unknown5 = Article before a singular noun beginning with a vowel sound
|
||||
Unknown6 = Article before a generic noun beginning with a vowel sound
|
||||
Unknown7 = N/A
|
||||
German:
|
||||
Unknown8 = Nominative Masculine
|
||||
Unknown9 = Nominative Feminine
|
||||
Unknown10 = Nominative Neutral
|
||||
Unknown11 = Nominative Plural
|
||||
Unknown12 = Genitive Masculine
|
||||
Unknown13 = Genitive Feminine
|
||||
Unknown14 = Genitive Neutral
|
||||
Unknown15 = Genitive Plural
|
||||
Unknown16 = Dative Masculine
|
||||
Unknown17 = Dative Feminine
|
||||
Unknown18 = Dative Neutral
|
||||
Unknown19 = Dative Plural
|
||||
Unknown20 = Accusative Masculine
|
||||
Unknown21 = Accusative Feminine
|
||||
Unknown22 = Accusative Neutral
|
||||
Unknown23 = Accusative Plural
|
||||
French (unsure):
|
||||
Unknown24 = Singular Article
|
||||
Unknown25 = Singular Masculine Article
|
||||
Unknown26 = Plural Masculine Article
|
||||
Unknown27 = ?
|
||||
Unknown28 = ?
|
||||
Unknown29 = Singular Masculine/Feminine Article, before a noun beginning in a vowel or an h
|
||||
Unknown30 = Plural Masculine/Feminine Article, before a noun beginning in a vowel or an h
|
||||
Unknown31 = ?
|
||||
Unknown32 = ?
|
||||
Unknown33 = Singular Feminine Article
|
||||
Unknown34 = Plural Feminine Article
|
||||
Unknown35 = ?
|
||||
Unknown36 = ?
|
||||
Unknown37 = Singular Masculine/Feminine Article, before a noun beginning in a vowel or an h
|
||||
Unknown38 = Plural Masculine/Feminine Article, before a noun beginning in a vowel or an h
|
||||
Unknown39 = ?
|
||||
Unknown40 = ?
|
||||
|
||||
Placeholders:
|
||||
[t] = article or grammatical gender (EN: the, DE: der, die, das)
|
||||
[n] = amount (number)
|
||||
[a] = declension
|
||||
[p] = plural
|
||||
[pa] = ?
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality to process texts from sheets containing grammatical placeholders.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class NounProcessor : IServiceType
|
||||
{
|
||||
// column names from ExdSchema, most likely incorrect
|
||||
private const int SingularColumnIdx = 0;
|
||||
private const int AdjectiveColumnIdx = 1;
|
||||
private const int PluralColumnIdx = 2;
|
||||
private const int PossessivePronounColumnIdx = 3;
|
||||
private const int StartsWithVowelColumnIdx = 4;
|
||||
private const int Unknown5ColumnIdx = 5; // probably used in Chinese texts
|
||||
private const int PronounColumnIdx = 6;
|
||||
private const int ArticleColumnIdx = 7;
|
||||
|
||||
private static readonly ModuleLog Log = new("NounProcessor");
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DataManager dataManager = Service<DataManager>.Get();
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DalamudConfiguration dalamudConfiguration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
private readonly ConcurrentDictionary<NounParams, ReadOnlySeString> cache = [];
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private NounProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes a specific row from a sheet and generates a formatted string based on grammatical and language-specific rules.
|
||||
/// </summary>
|
||||
/// <param name="nounParams">Parameters for processing.</param>
|
||||
/// <returns>A ReadOnlySeString representing the processed text.</returns>
|
||||
public ReadOnlySeString ProcessNoun(NounParams nounParams)
|
||||
{
|
||||
if (nounParams.GrammaticalCase < 0 || nounParams.GrammaticalCase > 5)
|
||||
return default;
|
||||
|
||||
if (this.cache.TryGetValue(nounParams, out var value))
|
||||
return value;
|
||||
|
||||
var output = nounParams.Language switch
|
||||
{
|
||||
ClientLanguage.Japanese => this.ResolveNounJa(nounParams),
|
||||
ClientLanguage.English => this.ResolveNounEn(nounParams),
|
||||
ClientLanguage.German => this.ResolveNounDe(nounParams),
|
||||
ClientLanguage.French => this.ResolveNounFr(nounParams),
|
||||
_ => default,
|
||||
};
|
||||
|
||||
this.cache.TryAdd(nounParams, output);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves noun placeholders in Japanese text.
|
||||
/// </summary>
|
||||
/// <param name="nounParams">Parameters for processing.</param>
|
||||
/// <returns>A ReadOnlySeString representing the processed text.</returns>
|
||||
/// <remarks>
|
||||
/// This is a C# implementation of Component::Text::Localize::NounJa.Resolve.
|
||||
/// </remarks>
|
||||
private ReadOnlySeString ResolveNounJa(NounParams nounParams)
|
||||
{
|
||||
var sheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nounParams.SheetName);
|
||||
if (!sheet.TryGetRow(nounParams.RowId, out var row))
|
||||
{
|
||||
Log.Warning("Sheet {SheetName} does not contain row #{RowId}", nounParams.SheetName, nounParams.RowId);
|
||||
return default;
|
||||
}
|
||||
|
||||
var attributiveSheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nameof(LSheets.Attributive));
|
||||
|
||||
var builder = LSeStringBuilder.SharedPool.Get();
|
||||
|
||||
// Ko-So-A-Do
|
||||
var ksad = attributiveSheet.GetRow((uint)nounParams.ArticleType).ReadStringColumn(nounParams.Quantity > 1 ? 1 : 0);
|
||||
if (!ksad.IsEmpty)
|
||||
{
|
||||
builder.Append(ksad);
|
||||
|
||||
if (nounParams.Quantity > 1)
|
||||
{
|
||||
builder.ReplaceText("[n]"u8, ReadOnlySeString.FromText(nounParams.Quantity.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!nounParams.LinkMarker.IsEmpty)
|
||||
builder.Append(nounParams.LinkMarker);
|
||||
|
||||
var text = row.ReadStringColumn(nounParams.ColumnOffset);
|
||||
if (!text.IsEmpty)
|
||||
builder.Append(text);
|
||||
|
||||
var ross = builder.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
return ross;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves noun placeholders in English text.
|
||||
/// </summary>
|
||||
/// <param name="nounParams">Parameters for processing.</param>
|
||||
/// <returns>A ReadOnlySeString representing the processed text.</returns>
|
||||
/// <remarks>
|
||||
/// This is a C# implementation of Component::Text::Localize::NounEn.Resolve.
|
||||
/// </remarks>
|
||||
private ReadOnlySeString ResolveNounEn(NounParams nounParams)
|
||||
{
|
||||
/*
|
||||
a1->Offsets[0] = SingularColumnIdx
|
||||
a1->Offsets[1] = PluralColumnIdx
|
||||
a1->Offsets[2] = StartsWithVowelColumnIdx
|
||||
a1->Offsets[3] = PossessivePronounColumnIdx
|
||||
a1->Offsets[4] = ArticleColumnIdx
|
||||
*/
|
||||
|
||||
var sheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nounParams.SheetName);
|
||||
if (!sheet.TryGetRow(nounParams.RowId, out var row))
|
||||
{
|
||||
Log.Warning("Sheet {SheetName} does not contain row #{RowId}", nounParams.SheetName, nounParams.RowId);
|
||||
return default;
|
||||
}
|
||||
|
||||
var attributiveSheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nameof(LSheets.Attributive));
|
||||
|
||||
var builder = LSeStringBuilder.SharedPool.Get();
|
||||
|
||||
var isProperNounColumn = nounParams.ColumnOffset + ArticleColumnIdx;
|
||||
var isProperNoun = isProperNounColumn >= 0 ? row.ReadInt8Column(isProperNounColumn) : ~isProperNounColumn;
|
||||
if (isProperNoun == 0)
|
||||
{
|
||||
var startsWithVowelColumn = nounParams.ColumnOffset + StartsWithVowelColumnIdx;
|
||||
var startsWithVowel = startsWithVowelColumn >= 0
|
||||
? row.ReadInt8Column(startsWithVowelColumn)
|
||||
: ~startsWithVowelColumn;
|
||||
|
||||
var articleColumn = startsWithVowel + (2 * (startsWithVowel + 1));
|
||||
var grammaticalNumberColumnOffset = nounParams.Quantity == 1 ? SingularColumnIdx : PluralColumnIdx;
|
||||
var article = attributiveSheet.GetRow((uint)nounParams.ArticleType)
|
||||
.ReadStringColumn(articleColumn + grammaticalNumberColumnOffset);
|
||||
if (!article.IsEmpty)
|
||||
builder.Append(article);
|
||||
|
||||
if (!nounParams.LinkMarker.IsEmpty)
|
||||
builder.Append(nounParams.LinkMarker);
|
||||
}
|
||||
|
||||
var text = row.ReadStringColumn(nounParams.ColumnOffset + (nounParams.Quantity == 1 ? SingularColumnIdx : PluralColumnIdx));
|
||||
if (!text.IsEmpty)
|
||||
builder.Append(text);
|
||||
|
||||
builder.ReplaceText("[n]"u8, ReadOnlySeString.FromText(nounParams.Quantity.ToString()));
|
||||
|
||||
var ross = builder.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
return ross;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves noun placeholders in German text.
|
||||
/// </summary>
|
||||
/// <param name="nounParams">Parameters for processing.</param>
|
||||
/// <returns>A ReadOnlySeString representing the processed text.</returns>
|
||||
/// <remarks>
|
||||
/// This is a C# implementation of Component::Text::Localize::NounDe.Resolve.
|
||||
/// </remarks>
|
||||
private ReadOnlySeString ResolveNounDe(NounParams nounParams)
|
||||
{
|
||||
/*
|
||||
a1->Offsets[0] = SingularColumnIdx
|
||||
a1->Offsets[1] = PluralColumnIdx
|
||||
a1->Offsets[2] = PronounColumnIdx
|
||||
a1->Offsets[3] = AdjectiveColumnIdx
|
||||
a1->Offsets[4] = PossessivePronounColumnIdx
|
||||
a1->Offsets[5] = Unknown5ColumnIdx
|
||||
a1->Offsets[6] = ArticleColumnIdx
|
||||
*/
|
||||
|
||||
var sheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nounParams.SheetName);
|
||||
if (!sheet.TryGetRow(nounParams.RowId, out var row))
|
||||
{
|
||||
Log.Warning("Sheet {SheetName} does not contain row #{RowId}", nounParams.SheetName, nounParams.RowId);
|
||||
return default;
|
||||
}
|
||||
|
||||
var attributiveSheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nameof(LSheets.Attributive));
|
||||
|
||||
var builder = LSeStringBuilder.SharedPool.Get();
|
||||
ReadOnlySeString ross;
|
||||
|
||||
if (nounParams.IsActionSheet)
|
||||
{
|
||||
builder.Append(row.ReadStringColumn(nounParams.GrammaticalCase));
|
||||
builder.ReplaceText("[n]"u8, ReadOnlySeString.FromText(nounParams.Quantity.ToString()));
|
||||
|
||||
ross = builder.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
return ross;
|
||||
}
|
||||
|
||||
var genderIndexColumn = nounParams.ColumnOffset + PronounColumnIdx;
|
||||
var genderIndex = genderIndexColumn >= 0 ? row.ReadInt8Column(genderIndexColumn) : ~genderIndexColumn;
|
||||
|
||||
var articleIndexColumn = nounParams.ColumnOffset + ArticleColumnIdx;
|
||||
var articleIndex = articleIndexColumn >= 0 ? row.ReadInt8Column(articleIndexColumn) : ~articleIndexColumn;
|
||||
|
||||
var caseColumnOffset = (4 * nounParams.GrammaticalCase) + 8;
|
||||
|
||||
var caseRowOffsetColumn = nounParams.ColumnOffset + (nounParams.Quantity == 1 ? AdjectiveColumnIdx : PossessivePronounColumnIdx);
|
||||
var caseRowOffset = caseRowOffsetColumn >= 0
|
||||
? row.ReadInt8Column(caseRowOffsetColumn)
|
||||
: (sbyte)~caseRowOffsetColumn;
|
||||
|
||||
if (nounParams.Quantity != 1)
|
||||
genderIndex = 3;
|
||||
|
||||
var hasT = false;
|
||||
var text = row.ReadStringColumn(nounParams.ColumnOffset + (nounParams.Quantity == 1 ? SingularColumnIdx : PluralColumnIdx));
|
||||
if (!text.IsEmpty)
|
||||
{
|
||||
hasT = text.ContainsText("[t]"u8);
|
||||
|
||||
if (articleIndex == 0 && !hasT)
|
||||
{
|
||||
var grammaticalGender = attributiveSheet.GetRow((uint)nounParams.ArticleType)
|
||||
.ReadStringColumn(caseColumnOffset + genderIndex); // Genus
|
||||
if (!grammaticalGender.IsEmpty)
|
||||
builder.Append(grammaticalGender);
|
||||
}
|
||||
|
||||
if (!nounParams.LinkMarker.IsEmpty)
|
||||
builder.Append(nounParams.LinkMarker);
|
||||
|
||||
builder.Append(text);
|
||||
|
||||
var plural = attributiveSheet.GetRow((uint)(caseRowOffset + 26))
|
||||
.ReadStringColumn(caseColumnOffset + genderIndex);
|
||||
if (builder.ContainsText("[p]"u8))
|
||||
builder.ReplaceText("[p]"u8, plural);
|
||||
else
|
||||
builder.Append(plural);
|
||||
|
||||
if (hasT)
|
||||
{
|
||||
var article =
|
||||
attributiveSheet.GetRow(39).ReadStringColumn(caseColumnOffset + genderIndex); // Definiter Artikel
|
||||
builder.ReplaceText("[t]"u8, article);
|
||||
}
|
||||
}
|
||||
|
||||
var pa = attributiveSheet.GetRow(24).ReadStringColumn(caseColumnOffset + genderIndex);
|
||||
builder.ReplaceText("[pa]"u8, pa);
|
||||
|
||||
RawRow declensionRow;
|
||||
|
||||
declensionRow = (GermanArticleType)nounParams.ArticleType switch
|
||||
{
|
||||
// Schwache Flexion eines Adjektivs?!
|
||||
GermanArticleType.Possessive or GermanArticleType.Demonstrative => attributiveSheet.GetRow(25),
|
||||
_ when hasT => attributiveSheet.GetRow(25),
|
||||
|
||||
// Starke Deklination
|
||||
GermanArticleType.ZeroArticle => attributiveSheet.GetRow(38),
|
||||
|
||||
// Gemischte Deklination
|
||||
GermanArticleType.Definite => attributiveSheet.GetRow(37),
|
||||
|
||||
// Starke Flexion eines Artikels?!
|
||||
GermanArticleType.Indefinite or GermanArticleType.Negative => attributiveSheet.GetRow(26),
|
||||
_ => attributiveSheet.GetRow(26),
|
||||
};
|
||||
|
||||
var declension = declensionRow.ReadStringColumn(caseColumnOffset + genderIndex);
|
||||
builder.ReplaceText("[a]"u8, declension);
|
||||
|
||||
builder.ReplaceText("[n]"u8, ReadOnlySeString.FromText(nounParams.Quantity.ToString()));
|
||||
|
||||
ross = builder.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
return ross;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves noun placeholders in French text.
|
||||
/// </summary>
|
||||
/// <param name="nounParams">Parameters for processing.</param>
|
||||
/// <returns>A ReadOnlySeString representing the processed text.</returns>
|
||||
/// <remarks>
|
||||
/// This is a C# implementation of Component::Text::Localize::NounFr.Resolve.
|
||||
/// </remarks>
|
||||
private ReadOnlySeString ResolveNounFr(NounParams nounParams)
|
||||
{
|
||||
/*
|
||||
a1->Offsets[0] = SingularColumnIdx
|
||||
a1->Offsets[1] = PluralColumnIdx
|
||||
a1->Offsets[2] = StartsWithVowelColumnIdx
|
||||
a1->Offsets[3] = PronounColumnIdx
|
||||
a1->Offsets[4] = Unknown5ColumnIdx
|
||||
a1->Offsets[5] = ArticleColumnIdx
|
||||
*/
|
||||
|
||||
var sheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nounParams.SheetName);
|
||||
if (!sheet.TryGetRow(nounParams.RowId, out var row))
|
||||
{
|
||||
Log.Warning("Sheet {SheetName} does not contain row #{RowId}", nounParams.SheetName, nounParams.RowId);
|
||||
return default;
|
||||
}
|
||||
|
||||
var attributiveSheet = this.dataManager.Excel.GetSheet<RawRow>(nounParams.Language.ToLumina(), nameof(LSheets.Attributive));
|
||||
|
||||
var builder = LSeStringBuilder.SharedPool.Get();
|
||||
ReadOnlySeString ross;
|
||||
|
||||
var startsWithVowelColumn = nounParams.ColumnOffset + StartsWithVowelColumnIdx;
|
||||
var startsWithVowel = startsWithVowelColumn >= 0
|
||||
? row.ReadInt8Column(startsWithVowelColumn)
|
||||
: ~startsWithVowelColumn;
|
||||
|
||||
var pronounColumn = nounParams.ColumnOffset + PronounColumnIdx;
|
||||
var pronoun = pronounColumn >= 0 ? row.ReadInt8Column(pronounColumn) : ~pronounColumn;
|
||||
|
||||
var articleColumn = nounParams.ColumnOffset + ArticleColumnIdx;
|
||||
var article = articleColumn >= 0 ? row.ReadInt8Column(articleColumn) : ~articleColumn;
|
||||
|
||||
var v20 = 4 * (startsWithVowel + 6 + (2 * pronoun));
|
||||
|
||||
if (article != 0)
|
||||
{
|
||||
var v21 = attributiveSheet.GetRow((uint)nounParams.ArticleType).ReadStringColumn(v20);
|
||||
if (!v21.IsEmpty)
|
||||
builder.Append(v21);
|
||||
|
||||
if (!nounParams.LinkMarker.IsEmpty)
|
||||
builder.Append(nounParams.LinkMarker);
|
||||
|
||||
var text = row.ReadStringColumn(nounParams.ColumnOffset + (nounParams.Quantity <= 1 ? SingularColumnIdx : PluralColumnIdx));
|
||||
if (!text.IsEmpty)
|
||||
builder.Append(text);
|
||||
|
||||
if (nounParams.Quantity <= 1)
|
||||
builder.ReplaceText("[n]"u8, ReadOnlySeString.FromText(nounParams.Quantity.ToString()));
|
||||
|
||||
ross = builder.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
return ross;
|
||||
}
|
||||
|
||||
var v17 = row.ReadInt8Column(nounParams.ColumnOffset + Unknown5ColumnIdx);
|
||||
if (v17 != 0 && (nounParams.Quantity > 1 || v17 == 2))
|
||||
{
|
||||
var v29 = attributiveSheet.GetRow((uint)nounParams.ArticleType).ReadStringColumn(v20 + 2);
|
||||
if (!v29.IsEmpty)
|
||||
{
|
||||
builder.Append(v29);
|
||||
|
||||
if (!nounParams.LinkMarker.IsEmpty)
|
||||
builder.Append(nounParams.LinkMarker);
|
||||
|
||||
var text = row.ReadStringColumn(nounParams.ColumnOffset + PluralColumnIdx);
|
||||
if (!text.IsEmpty)
|
||||
builder.Append(text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var v27 = attributiveSheet.GetRow((uint)nounParams.ArticleType).ReadStringColumn(v20 + (v17 != 0 ? 1 : 3));
|
||||
if (!v27.IsEmpty)
|
||||
builder.Append(v27);
|
||||
|
||||
if (!nounParams.LinkMarker.IsEmpty)
|
||||
builder.Append(nounParams.LinkMarker);
|
||||
|
||||
var text = row.ReadStringColumn(nounParams.ColumnOffset + SingularColumnIdx);
|
||||
if (!text.IsEmpty)
|
||||
builder.Append(text);
|
||||
}
|
||||
|
||||
builder.ReplaceText("[n]"u8, ReadOnlySeString.FromText(nounParams.Quantity.ToString()));
|
||||
|
||||
ross = builder.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
return ross;
|
||||
}
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ public abstract partial class Payload
|
|||
case SeStringChunkType.Icon:
|
||||
payload = new IconPayload();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// Log.Verbose("Unhandled SeStringChunkType: {0}", chunkType);
|
||||
break;
|
||||
|
|
@ -306,7 +306,7 @@ public abstract partial class Payload
|
|||
/// See the <see cref="NewLinePayload"/>.
|
||||
/// </summary>
|
||||
NewLine = 0x10,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// See the <see cref="IconPayload"/> class.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ using System.Linq;
|
|||
using System.Text;
|
||||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -73,6 +75,7 @@ public class ItemPayload : Payload
|
|||
/// <summary>
|
||||
/// Kinds of items that can be fetched from this payload.
|
||||
/// </summary>
|
||||
[Api12ToDo("Move this out of ItemPayload. It's used in other classes too.")]
|
||||
public enum ItemKind : uint
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -121,7 +124,7 @@ public class ItemPayload : Payload
|
|||
/// Gets the actual item ID of this payload.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint ItemId => GetAdjustedId(this.rawItemId).ItemId;
|
||||
public uint ItemId => ItemUtil.GetBaseId(this.rawItemId).ItemId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw, unadjusted item ID of this payload.
|
||||
|
|
@ -161,7 +164,7 @@ public class ItemPayload : Payload
|
|||
/// <returns>The created item payload.</returns>
|
||||
public static ItemPayload FromRaw(uint rawItemId, string? displayNameOverride = null)
|
||||
{
|
||||
var (id, kind) = GetAdjustedId(rawItemId);
|
||||
var (id, kind) = ItemUtil.GetBaseId(rawItemId);
|
||||
return new ItemPayload(id, kind, displayNameOverride);
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +233,7 @@ public class ItemPayload : Payload
|
|||
protected override void DecodeImpl(BinaryReader reader, long endOfStream)
|
||||
{
|
||||
this.rawItemId = GetInteger(reader);
|
||||
this.Kind = GetAdjustedId(this.rawItemId).Kind;
|
||||
this.Kind = ItemUtil.GetBaseId(this.rawItemId).Kind;
|
||||
|
||||
if (reader.BaseStream.Position + 3 < endOfStream)
|
||||
{
|
||||
|
|
@ -255,15 +258,4 @@ public class ItemPayload : Payload
|
|||
this.displayName = Encoding.UTF8.GetString(itemNameBytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static (uint ItemId, ItemKind Kind) GetAdjustedId(uint rawItemId)
|
||||
{
|
||||
return rawItemId switch
|
||||
{
|
||||
> 500_000 and < 1_000_000 => (rawItemId - 500_000, ItemKind.Collectible),
|
||||
> 1_000_000 and < 2_000_000 => (rawItemId - 1_000_000, ItemKind.Hq),
|
||||
> 2_000_000 => (rawItemId, ItemKind.EventItem), // EventItem IDs are NOT adjusted
|
||||
_ => (rawItemId, ItemKind.Normal),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ using Newtonsoft.Json;
|
|||
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
|
||||
/// <summary>
|
||||
/// An SeString Payload representing a UI foreground color applied to following text payloads.
|
||||
/// An SeString Payload that allows text to have a specific color. The color selected will be determined by the
|
||||
/// <see cref="Lumina.Excel.Sheets.UIColor.Dark"/> theme's coloring, regardless of the active theme.
|
||||
/// </summary>
|
||||
public class UIForegroundPayload : Payload
|
||||
{
|
||||
|
|
@ -74,13 +75,13 @@ public class UIForegroundPayload : Payload
|
|||
/// Gets the Red/Green/Blue/Alpha values for this foreground color, encoded as a typical hex color.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint RGBA => this.UIColor.Value.UIForeground;
|
||||
public uint RGBA => this.UIColor.Value.Dark;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ABGR value for this foreground color, as ImGui requires it in PushColor.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.Value.UIForeground);
|
||||
public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.Value.Dark);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ using Newtonsoft.Json;
|
|||
namespace Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
|
||||
/// <summary>
|
||||
/// An SeString Payload representing a UI glow color applied to following text payloads.
|
||||
/// An SeString Payload that allows text to have a specific edge glow. The color selected will be determined by the
|
||||
/// <see cref="Lumina.Excel.Sheets.UIColor.Light"/> theme's coloring, regardless of the active theme.
|
||||
/// </summary>
|
||||
public class UIGlowPayload : Payload
|
||||
{
|
||||
|
|
@ -71,13 +72,13 @@ public class UIGlowPayload : Payload
|
|||
/// Gets the Red/Green/Blue/Alpha values for this glow color, encoded as a typical hex color.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint RGBA => this.UIColor.Value.UIGlow;
|
||||
public uint RGBA => this.UIColor.Value.Light;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ABGR value for this glow color, as ImGui requires it in PushColor.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.Value.UIGlow);
|
||||
public uint ABGR => Interface.ColorHelpers.SwapEndianness(this.UIColor.Value.Light);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Lumina UIColor object representing this payload. The actual color data is at UIColor.UIGlow.
|
||||
|
|
|
|||
|
|
@ -5,11 +5,16 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.Text.Evaluator;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using LSeStringBuilder = Lumina.Text.SeStringBuilder;
|
||||
|
||||
namespace Dalamud.Game.Text.SeStringHandling;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -187,57 +192,32 @@ public class SeString
|
|||
/// <returns>An SeString containing all the payloads necessary to display an item link in the chat log.</returns>
|
||||
public static SeString CreateItemLink(uint itemId, ItemPayload.ItemKind kind = ItemPayload.ItemKind.Normal, string? displayNameOverride = null)
|
||||
{
|
||||
var data = Service<DataManager>.Get();
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
var seStringEvaluator = Service<SeStringEvaluator>.Get();
|
||||
|
||||
var displayName = displayNameOverride;
|
||||
var rarity = 1; // default: white
|
||||
if (displayName == null)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ItemPayload.ItemKind.Normal:
|
||||
case ItemPayload.ItemKind.Collectible:
|
||||
case ItemPayload.ItemKind.Hq:
|
||||
var item = data.GetExcelSheet<Item>()?.GetRowOrDefault(itemId);
|
||||
displayName = item?.Name.ExtractText();
|
||||
rarity = item?.Rarity ?? 1;
|
||||
break;
|
||||
case ItemPayload.ItemKind.EventItem:
|
||||
displayName = data.GetExcelSheet<EventItem>()?.GetRowOrDefault(itemId)?.Name.ExtractText();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(kind), kind, null);
|
||||
}
|
||||
}
|
||||
var rawId = ItemUtil.GetRawId(itemId, kind);
|
||||
|
||||
if (displayName == null)
|
||||
{
|
||||
var displayName = displayNameOverride ?? ItemUtil.GetItemName(rawId);
|
||||
if (displayName.IsEmpty)
|
||||
throw new Exception("Invalid item ID specified, could not determine item name.");
|
||||
}
|
||||
|
||||
if (kind == ItemPayload.ItemKind.Hq)
|
||||
{
|
||||
displayName += $" {(char)SeIconChar.HighQuality}";
|
||||
}
|
||||
else if (kind == ItemPayload.ItemKind.Collectible)
|
||||
{
|
||||
displayName += $" {(char)SeIconChar.Collectible}";
|
||||
}
|
||||
var copyName = ItemUtil.GetItemName(rawId, false).ExtractText();
|
||||
var textColor = ItemUtil.GetItemRarityColorType(rawId);
|
||||
var textEdgeColor = textColor + 1u;
|
||||
|
||||
var textColor = (ushort)(549 + ((rarity - 1) * 2));
|
||||
var textGlowColor = (ushort)(textColor + 1);
|
||||
var sb = LSeStringBuilder.SharedPool.Get();
|
||||
var itemLink = sb
|
||||
.PushColorType(textColor)
|
||||
.PushEdgeColorType(textEdgeColor)
|
||||
.PushLinkItem(rawId, copyName)
|
||||
.Append(displayName)
|
||||
.PopLink()
|
||||
.PopEdgeColorType()
|
||||
.PopColorType()
|
||||
.ToReadOnlySeString();
|
||||
LSeStringBuilder.SharedPool.Return(sb);
|
||||
|
||||
// Note: `SeStringBuilder.AddItemLink` uses this function, so don't call it here!
|
||||
return new SeStringBuilder()
|
||||
.AddUiForeground(textColor)
|
||||
.AddUiGlow(textGlowColor)
|
||||
.Add(new ItemPayload(itemId, kind))
|
||||
.Append(TextArrowPayloads)
|
||||
.AddText(displayName)
|
||||
.AddUiGlowOff()
|
||||
.AddUiForegroundOff()
|
||||
.Add(RawPayload.LinkTerminator)
|
||||
.Build();
|
||||
return SeString.Parse(seStringEvaluator.EvaluateFromAddon(371, [itemLink], clientState.ClientLanguage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -301,7 +281,7 @@ public class SeString
|
|||
public static SeString CreateMapLink(
|
||||
uint territoryId, uint mapId, float xCoord, float yCoord, float fudgeFactor = 0.05f) =>
|
||||
CreateMapLinkWithInstance(territoryId, mapId, null, xCoord, yCoord, fudgeFactor);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates an SeString representing an entire Payload chain that can be used to link a map position in the chat log.
|
||||
/// </summary>
|
||||
|
|
@ -340,7 +320,7 @@ public class SeString
|
|||
/// <returns>An SeString containing all of the payloads necessary to display a map link in the chat log.</returns>
|
||||
public static SeString? CreateMapLink(string placeName, float xCoord, float yCoord, float fudgeFactor = 0.05f) =>
|
||||
CreateMapLinkWithInstance(placeName, null, xCoord, yCoord, fudgeFactor);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates an SeString representing an entire Payload chain that can be used to link a map position in the chat log, matching a specified zone name.
|
||||
/// Returns null if no corresponding PlaceName was found.
|
||||
|
|
@ -511,7 +491,7 @@ public class SeString
|
|||
{
|
||||
messageBytes.AddRange(p.Encode());
|
||||
}
|
||||
|
||||
|
||||
// Add Null Terminator
|
||||
messageBytes.Add(0);
|
||||
|
||||
|
|
@ -526,7 +506,7 @@ public class SeString
|
|||
{
|
||||
return this.TextValue;
|
||||
}
|
||||
|
||||
|
||||
private static string GetMapLinkNameString(string placeName, int? instance, string coordinateString)
|
||||
{
|
||||
var instanceString = string.Empty;
|
||||
|
|
@ -534,7 +514,7 @@ public class SeString
|
|||
{
|
||||
instanceString = (SeIconChar.Instance1 + instance.Value - 1).ToIconString();
|
||||
}
|
||||
|
||||
|
||||
return $"{placeName}{instanceString} {coordinateString}";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ namespace Dalamud.Interface.Animation;
|
|||
/// <summary>
|
||||
/// Base class facilitating the implementation of easing functions.
|
||||
/// </summary>
|
||||
[Api12ToDo("Re-apply https://github.com/goatcorp/Dalamud/commit/1aada983931d9e45a250eebbc17c8b782d07701b")]
|
||||
public abstract class Easing
|
||||
{
|
||||
// TODO: Use game delta time here instead
|
||||
|
|
@ -46,9 +45,22 @@ public abstract class Easing
|
|||
public bool IsInverse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current value of the animation, from 0 to 1.
|
||||
/// Gets the current value of the animation, following unclamped logic.
|
||||
/// </summary>
|
||||
public double Value
|
||||
[Obsolete($"This field has been deprecated. Use either {nameof(ValueClamped)} or {nameof(ValueUnclamped)} instead.", true)]
|
||||
[Api13ToDo("Map this field to ValueClamped, probably.")]
|
||||
public double Value => this.ValueUnclamped;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the animation, from 0 to 1.
|
||||
/// </summary>
|
||||
public double ValueClamped => Math.Clamp(this.ValueUnclamped, 0, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current value of the animation, not limited to a range of 0 to 1.
|
||||
/// Will return numbers outside of this range if accessed beyond animation time.
|
||||
/// </summary>
|
||||
public double ValueUnclamped
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InCirc : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = 1 - Math.Sqrt(1 - Math.Pow(p, 2));
|
||||
this.ValueUnclamped = 1 - Math.Sqrt(1 - Math.Pow(p, 2));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InCubic : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p * p * p;
|
||||
this.ValueUnclamped = p * p * p;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ public class InElastic : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p == 0
|
||||
? 0
|
||||
: p == 1
|
||||
? 1
|
||||
: -Math.Pow(2, (10 * p) - 10) * Math.Sin(((p * 10) - 10.75) * Constant);
|
||||
this.ValueUnclamped = p == 0
|
||||
? 0
|
||||
: p == 1
|
||||
? 1
|
||||
: -Math.Pow(2, (10 * p) - 10) * Math.Sin(((p * 10) - 10.75) * Constant);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ public class InOutCirc : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p < 0.5
|
||||
? (1 - Math.Sqrt(1 - Math.Pow(2 * p, 2))) / 2
|
||||
: (Math.Sqrt(1 - Math.Pow((-2 * p) + 2, 2)) + 1) / 2;
|
||||
this.ValueUnclamped = p < 0.5
|
||||
? (1 - Math.Sqrt(1 - Math.Pow(2 * p, 2))) / 2
|
||||
: (Math.Sqrt(1 - Math.Pow((-2 * p) + 2, 2)) + 1) / 2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InOutCubic : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p < 0.5 ? 4 * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 3) / 2);
|
||||
this.ValueUnclamped = p < 0.5 ? 4 * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 3) / 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ public class InOutElastic : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p == 0
|
||||
? 0
|
||||
: p == 1
|
||||
? 1
|
||||
: p < 0.5
|
||||
? -(Math.Pow(2, (20 * p) - 10) * Math.Sin(((20 * p) - 11.125) * Constant)) / 2
|
||||
: (Math.Pow(2, (-20 * p) + 10) * Math.Sin(((20 * p) - 11.125) * Constant) / 2) + 1;
|
||||
this.ValueUnclamped = p == 0
|
||||
? 0
|
||||
: p == 1
|
||||
? 1
|
||||
: p < 0.5
|
||||
? -(Math.Pow(2, (20 * p) - 10) * Math.Sin(((20 * p) - 11.125) * Constant)) / 2
|
||||
: (Math.Pow(2, (-20 * p) + 10) * Math.Sin(((20 * p) - 11.125) * Constant) / 2) + 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InOutQuint : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p < 0.5 ? 16 * p * p * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 5) / 2);
|
||||
this.ValueUnclamped = p < 0.5 ? 16 * p * p * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 5) / 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InOutSine : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = -(Math.Cos(Math.PI * p) - 1) / 2;
|
||||
this.ValueUnclamped = -(Math.Cos(Math.PI * p) - 1) / 2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InQuint : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p * p * p * p * p;
|
||||
this.ValueUnclamped = p * p * p * p * p;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class InSine : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = 1 - Math.Cos((p * Math.PI) / 2);
|
||||
this.ValueUnclamped = 1 - Math.Cos((p * Math.PI) / 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class OutCirc : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = Math.Sqrt(1 - Math.Pow(p - 1, 2));
|
||||
this.ValueUnclamped = Math.Sqrt(1 - Math.Pow(p - 1, 2));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class OutCubic : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = 1 - Math.Pow(1 - p, 3);
|
||||
this.ValueUnclamped = 1 - Math.Pow(1 - p, 3);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ public class OutElastic : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = p == 0
|
||||
? 0
|
||||
: p == 1
|
||||
? 1
|
||||
: (Math.Pow(2, -10 * p) * Math.Sin(((p * 10) - 0.75) * Constant)) + 1;
|
||||
this.ValueUnclamped = p == 0
|
||||
? 0
|
||||
: p == 1
|
||||
? 1
|
||||
: (Math.Pow(2, -10 * p) * Math.Sin(((p * 10) - 0.75) * Constant)) + 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class OutQuint : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = 1 - Math.Pow(1 - p, 5);
|
||||
this.ValueUnclamped = 1 - Math.Pow(1 - p, 5);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class OutSine : Easing
|
|||
public override void Update()
|
||||
{
|
||||
var p = this.Progress;
|
||||
this.Value = Math.Sin((p * Math.PI) / 2);
|
||||
this.ValueUnclamped = Math.Sin((p * Math.PI) / 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ internal sealed partial class ActiveNotification
|
|||
var opacity =
|
||||
Math.Clamp(
|
||||
(float)(this.hideEasing.IsRunning
|
||||
? (this.hideEasing.IsDone || ReducedMotions ? 0 : 1f - this.hideEasing.Value)
|
||||
: (this.showEasing.IsDone || ReducedMotions ? 1 : this.showEasing.Value)),
|
||||
? (this.hideEasing.IsDone || ReducedMotions ? 0 : 1f - this.hideEasing.ValueClamped)
|
||||
: (this.showEasing.IsDone || ReducedMotions ? 1 : this.showEasing.ValueClamped)),
|
||||
0f,
|
||||
1f);
|
||||
if (opacity <= 0)
|
||||
|
|
@ -106,7 +106,7 @@ internal sealed partial class ActiveNotification
|
|||
}
|
||||
else if (this.expandoEasing.IsRunning)
|
||||
{
|
||||
var easedValue = ReducedMotions ? 1f : (float)this.expandoEasing.Value;
|
||||
var easedValue = ReducedMotions ? 1f : (float)this.expandoEasing.ValueClamped;
|
||||
if (this.underlyingNotification.Minimized)
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, opacity * (1f - easedValue));
|
||||
else
|
||||
|
|
@ -295,8 +295,8 @@ internal sealed partial class ActiveNotification
|
|||
{
|
||||
relativeOpacity =
|
||||
this.underlyingNotification.Minimized
|
||||
? 1f - (float)this.expandoEasing.Value
|
||||
: (float)this.expandoEasing.Value;
|
||||
? 1f - (float)this.expandoEasing.ValueClamped
|
||||
: (float)this.expandoEasing.ValueClamped;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -543,7 +543,7 @@ internal sealed partial class ActiveNotification
|
|||
float barL, barR;
|
||||
if (this.DismissReason is not null)
|
||||
{
|
||||
var v = this.hideEasing.IsDone || ReducedMotions ? 0f : 1f - (float)this.hideEasing.Value;
|
||||
var v = this.hideEasing.IsDone || ReducedMotions ? 0f : 1f - (float)this.hideEasing.ValueClamped;
|
||||
var midpoint = (this.prevProgressL + this.prevProgressR) / 2f;
|
||||
var length = (this.prevProgressR - this.prevProgressL) / 2f;
|
||||
barL = midpoint - (length * v);
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ internal sealed partial class ActiveNotification : IActiveNotification
|
|||
if (Math.Abs(underlyingProgress - this.progressBefore) < 0.000001f || this.progressEasing.IsDone || ReducedMotions)
|
||||
return underlyingProgress;
|
||||
|
||||
var state = ReducedMotions ? 1f : Math.Clamp((float)this.progressEasing.Value, 0f, 1f);
|
||||
var state = ReducedMotions ? 1f : Math.Clamp((float)this.progressEasing.ValueClamped, 0f, 1f);
|
||||
return this.progressBefore + (state * (underlyingProgress - this.progressBefore));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ internal sealed class SeStringColorStackSet
|
|||
foreach (var row in uiColor)
|
||||
{
|
||||
// Contains ABGR.
|
||||
this.colorTypes[row.RowId, 0] = row.UIForeground;
|
||||
this.colorTypes[row.RowId, 1] = row.UIGlow;
|
||||
this.colorTypes[row.RowId, 2] = row.Unknown0;
|
||||
this.colorTypes[row.RowId, 3] = row.Unknown1;
|
||||
this.colorTypes[row.RowId, 0] = row.Dark;
|
||||
this.colorTypes[row.RowId, 1] = row.Light;
|
||||
this.colorTypes[row.RowId, 2] = row.ClassicFF;
|
||||
this.colorTypes[row.RowId, 3] = row.ClearBlue;
|
||||
}
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using BitFaster.Caching.Lru;
|
|||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Config;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Interface.ImGuiSeStringRenderer.Internal.TextProcessing;
|
||||
using Dalamud.Interface.Utility;
|
||||
|
|
@ -44,9 +43,6 @@ internal unsafe class SeStringRenderer : IInternalDisposableService
|
|||
/// of this placeholder. On its own, usually displayed like <c>[OBJ]</c>.</summary>
|
||||
private const int ObjectReplacementCharacter = '\uFFFC';
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameConfig gameConfig = Service<GameConfig>.Get();
|
||||
|
||||
/// <summary>Cache of compiled SeStrings from <see cref="CompileAndCache"/>.</summary>
|
||||
private readonly ConcurrentLru<string, ReadOnlySeString> cache = new(1024);
|
||||
|
||||
|
|
@ -570,70 +566,16 @@ internal unsafe class SeStringRenderer : IInternalDisposableService
|
|||
// Apply gamepad key mapping to icons.
|
||||
case MacroCode.Icon2
|
||||
when payload.TryGetExpression(out var icon) && icon.TryGetInt(out var iconId):
|
||||
var configName = (BitmapFontIcon)iconId switch
|
||||
ref var iconMapping = ref RaptureAtkModule.Instance()->AtkFontManager.Icon2RemapTable;
|
||||
for (var i = 0; i < 30; i++)
|
||||
{
|
||||
ControllerShoulderLeft => SystemConfigOption.PadButton_L1,
|
||||
ControllerShoulderRight => SystemConfigOption.PadButton_R1,
|
||||
ControllerTriggerLeft => SystemConfigOption.PadButton_L2,
|
||||
ControllerTriggerRight => SystemConfigOption.PadButton_R2,
|
||||
ControllerButton3 => SystemConfigOption.PadButton_Triangle,
|
||||
ControllerButton1 => SystemConfigOption.PadButton_Cross,
|
||||
ControllerButton0 => SystemConfigOption.PadButton_Circle,
|
||||
ControllerButton2 => SystemConfigOption.PadButton_Square,
|
||||
ControllerStart => SystemConfigOption.PadButton_Start,
|
||||
ControllerBack => SystemConfigOption.PadButton_Select,
|
||||
ControllerAnalogLeftStick => SystemConfigOption.PadButton_LS,
|
||||
ControllerAnalogLeftStickIn => SystemConfigOption.PadButton_LS,
|
||||
ControllerAnalogLeftStickUpDown => SystemConfigOption.PadButton_LS,
|
||||
ControllerAnalogLeftStickLeftRight => SystemConfigOption.PadButton_LS,
|
||||
ControllerAnalogRightStick => SystemConfigOption.PadButton_RS,
|
||||
ControllerAnalogRightStickIn => SystemConfigOption.PadButton_RS,
|
||||
ControllerAnalogRightStickUpDown => SystemConfigOption.PadButton_RS,
|
||||
ControllerAnalogRightStickLeftRight => SystemConfigOption.PadButton_RS,
|
||||
_ => (SystemConfigOption?)null,
|
||||
};
|
||||
|
||||
if (configName is null || !this.gameConfig.TryGet(configName.Value, out PadButtonValue pb))
|
||||
return (BitmapFontIcon)iconId;
|
||||
|
||||
return pb switch
|
||||
{
|
||||
PadButtonValue.Autorun_Support => ControllerShoulderLeft,
|
||||
PadButtonValue.Hotbar_Set_Change => ControllerShoulderRight,
|
||||
PadButtonValue.XHB_Left_Start => ControllerTriggerLeft,
|
||||
PadButtonValue.XHB_Right_Start => ControllerTriggerRight,
|
||||
PadButtonValue.Jump => ControllerButton3,
|
||||
PadButtonValue.Accept => ControllerButton0,
|
||||
PadButtonValue.Cancel => ControllerButton1,
|
||||
PadButtonValue.Map_Sub => ControllerButton2,
|
||||
PadButtonValue.MainCommand => ControllerStart,
|
||||
PadButtonValue.HUD_Select => ControllerBack,
|
||||
PadButtonValue.Move_Operation => (BitmapFontIcon)iconId switch
|
||||
if (iconMapping[i].IconId == iconId)
|
||||
{
|
||||
ControllerAnalogLeftStick => ControllerAnalogLeftStick,
|
||||
ControllerAnalogLeftStickIn => ControllerAnalogLeftStickIn,
|
||||
ControllerAnalogLeftStickUpDown => ControllerAnalogLeftStickUpDown,
|
||||
ControllerAnalogLeftStickLeftRight => ControllerAnalogLeftStickLeftRight,
|
||||
ControllerAnalogRightStick => ControllerAnalogLeftStick,
|
||||
ControllerAnalogRightStickIn => ControllerAnalogLeftStickIn,
|
||||
ControllerAnalogRightStickUpDown => ControllerAnalogLeftStickUpDown,
|
||||
ControllerAnalogRightStickLeftRight => ControllerAnalogLeftStickLeftRight,
|
||||
_ => (BitmapFontIcon)iconId,
|
||||
},
|
||||
PadButtonValue.Camera_Operation => (BitmapFontIcon)iconId switch
|
||||
{
|
||||
ControllerAnalogLeftStick => ControllerAnalogRightStick,
|
||||
ControllerAnalogLeftStickIn => ControllerAnalogRightStickIn,
|
||||
ControllerAnalogLeftStickUpDown => ControllerAnalogRightStickUpDown,
|
||||
ControllerAnalogLeftStickLeftRight => ControllerAnalogRightStickLeftRight,
|
||||
ControllerAnalogRightStick => ControllerAnalogRightStick,
|
||||
ControllerAnalogRightStickIn => ControllerAnalogRightStickIn,
|
||||
ControllerAnalogRightStickUpDown => ControllerAnalogRightStickUpDown,
|
||||
ControllerAnalogRightStickLeftRight => ControllerAnalogRightStickLeftRight,
|
||||
_ => (BitmapFontIcon)iconId,
|
||||
},
|
||||
_ => (BitmapFontIcon)iconId,
|
||||
};
|
||||
return (BitmapFontIcon)iconMapping[i].RemappedIconId;
|
||||
}
|
||||
}
|
||||
|
||||
return (BitmapFontIcon)iconId;
|
||||
}
|
||||
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ internal unsafe class UiDebug
|
|||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button($"Decode##{(ulong)textNode:X}"))
|
||||
textNode->NodeText.SetString(new ReadOnlySeStringSpan(textNode->NodeText.StringPtr).ToString());
|
||||
textNode->NodeText.SetString(textNode->NodeText.StringPtr.AsReadOnlySeStringSpan().ToString());
|
||||
|
||||
ImGui.Text($"AlignmentType: {(AlignmentType)textNode->AlignmentFontType} FontSize: {textNode->FontSize}");
|
||||
int b = textNode->AlignmentFontType;
|
||||
|
|
@ -418,27 +418,27 @@ internal unsafe class UiDebug
|
|||
ImGui.Text("InputBase Text1: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->AtkComponentInputBase.UnkText1);
|
||||
|
||||
|
||||
ImGui.Text("InputBase Text2: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->AtkComponentInputBase.UnkText2);
|
||||
|
||||
|
||||
ImGui.Text("Text1: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->UnkText01);
|
||||
|
||||
|
||||
ImGui.Text("Text2: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->UnkText02);
|
||||
|
||||
|
||||
ImGui.Text("Text3: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->UnkText03);
|
||||
|
||||
|
||||
ImGui.Text("Text4: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->UnkText04);
|
||||
|
||||
|
||||
ImGui.Text("Text5: ");
|
||||
ImGui.SameLine();
|
||||
Service<SeStringRenderer>.Get().Draw(textInputComponent->UnkText05);
|
||||
|
|
|
|||
|
|
@ -76,14 +76,13 @@ public unsafe partial class AddonTree
|
|||
case ValueType.String8:
|
||||
case ValueType.String:
|
||||
{
|
||||
if (atkValue->String == null)
|
||||
if (atkValue->String.Value == null)
|
||||
{
|
||||
ImGui.TextDisabled("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
var str = MemoryHelper.ReadSeStringNullTerminated(new nint(atkValue->String));
|
||||
Util.ShowStruct(str, (ulong)atkValue);
|
||||
Util.ShowStruct(atkValue->String.ToString(), (ulong)atkValue);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ internal unsafe partial class TextNodeTree : ResNodeTree
|
|||
var seStringBytes = new byte[utf8String.BufUsed];
|
||||
for (var i = 0L; i < utf8String.BufUsed; i++)
|
||||
{
|
||||
seStringBytes[i] = utf8String.StringPtr[i];
|
||||
seStringBytes[i] = utf8String.StringPtr.Value[i];
|
||||
}
|
||||
|
||||
var seString = SeString.Parse(seStringBytes);
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ internal sealed class ComponentDemoWindow : Window
|
|||
ImGui.Bullet();
|
||||
|
||||
ImGui.SetCursorPos(cursor + new Vector2(0, 10));
|
||||
ImGui.Text($"{easing.GetType().Name} ({easing.Value})");
|
||||
ImGui.Text($"{easing.GetType().Name} ({easing.ValueClamped})");
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,11 +47,13 @@ internal class DataWindow : Window, IDisposable
|
|||
new KeyStateWidget(),
|
||||
new MarketBoardWidget(),
|
||||
new NetworkMonitorWidget(),
|
||||
new NounProcessorWidget(),
|
||||
new ObjectTableWidget(),
|
||||
new PartyListWidget(),
|
||||
new PluginIpcWidget(),
|
||||
new SeFontTestWidget(),
|
||||
new ServicesWidget(),
|
||||
new SeStringCreatorWidget(),
|
||||
new SeStringRendererTestWidget(),
|
||||
new StartInfoWidget(),
|
||||
new TargetWidget(),
|
||||
|
|
@ -68,6 +70,7 @@ internal class DataWindow : Window, IDisposable
|
|||
private bool isExcept;
|
||||
private bool selectionCollapsed;
|
||||
private IDataWindowWidget currentWidget;
|
||||
private bool isLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataWindow"/> class.
|
||||
|
|
@ -81,8 +84,6 @@ internal class DataWindow : Window, IDisposable
|
|||
this.RespectCloseHotkey = false;
|
||||
this.orderedModules = this.modules.OrderBy(module => module.DisplayName);
|
||||
this.currentWidget = this.orderedModules.First();
|
||||
|
||||
this.Load();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -91,6 +92,7 @@ internal class DataWindow : Window, IDisposable
|
|||
/// <inheritdoc/>
|
||||
public override void OnOpen()
|
||||
{
|
||||
this.Load();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -183,6 +185,7 @@ internal class DataWindow : Window, IDisposable
|
|||
|
||||
if (ImGuiComponents.IconButton("forceReload", FontAwesomeIcon.Sync))
|
||||
{
|
||||
this.isLoaded = false;
|
||||
this.Load();
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +239,11 @@ internal class DataWindow : Window, IDisposable
|
|||
|
||||
private void Load()
|
||||
{
|
||||
if (this.isLoaded)
|
||||
return;
|
||||
|
||||
this.isLoaded = true;
|
||||
|
||||
foreach (var widget in this.modules)
|
||||
{
|
||||
widget.Load();
|
||||
|
|
|
|||
34
Dalamud/Interface/Internal/Windows/Data/WidgetUtil.cs
Normal file
34
Dalamud/Interface/Internal/Windows/Data/WidgetUtil.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Common utilities used in Widgets.
|
||||
/// </summary>
|
||||
internal class WidgetUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws text that can be copied on click.
|
||||
/// </summary>
|
||||
/// <param name="text">The text shown and to be copied.</param>
|
||||
/// <param name="tooltipText">The text in the tooltip.</param>
|
||||
internal static void DrawCopyableText(string text, string tooltipText = "Copy")
|
||||
{
|
||||
ImGuiHelpers.SafeTextWrapped(text);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
|
||||
ImGui.BeginTooltip();
|
||||
ImGui.TextUnformatted(tooltipText);
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,24 +57,6 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
|
|||
this.DrawExtendArrayTab();
|
||||
}
|
||||
|
||||
private static void DrawCopyableText(string text, string tooltipText)
|
||||
{
|
||||
ImGuiHelpers.SafeTextWrapped(text);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
|
||||
ImGui.BeginTooltip();
|
||||
ImGui.TextUnformatted(tooltipText);
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText(text);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawArrayList(Type? arrayType, int arrayCount, short* arrayKeys, AtkArrayData** arrays, ref int selectedIndex)
|
||||
{
|
||||
using var table = ImRaii.Table("ArkArrayTable", 3, ImGuiTableFlags.ScrollY | ImGuiTableFlags.Borders, new Vector2(300, -1));
|
||||
|
|
@ -162,7 +144,7 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
|
|||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("Address: ");
|
||||
ImGui.SameLine(0, 0);
|
||||
DrawCopyableText($"0x{(nint)array:X}", "Copy address");
|
||||
WidgetUtil.DrawCopyableText($"0x{(nint)array:X}", "Copy address");
|
||||
|
||||
if (array->SubscribedAddonsCount > 0)
|
||||
{
|
||||
|
|
@ -238,22 +220,22 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
|
|||
var ptr = &array->IntArray[i];
|
||||
|
||||
ImGui.TableNextColumn(); // Address
|
||||
DrawCopyableText($"0x{(nint)ptr:X}", "Copy entry address");
|
||||
WidgetUtil.DrawCopyableText($"0x{(nint)ptr:X}", "Copy entry address");
|
||||
|
||||
ImGui.TableNextColumn(); // Integer
|
||||
DrawCopyableText((*ptr).ToString(), "Copy value");
|
||||
WidgetUtil.DrawCopyableText((*ptr).ToString(), "Copy value");
|
||||
|
||||
ImGui.TableNextColumn(); // Short
|
||||
DrawCopyableText((*(short*)ptr).ToString(), "Copy as short");
|
||||
WidgetUtil.DrawCopyableText((*(short*)ptr).ToString(), "Copy as short");
|
||||
|
||||
ImGui.TableNextColumn(); // Byte
|
||||
DrawCopyableText((*(byte*)ptr).ToString(), "Copy as byte");
|
||||
WidgetUtil.DrawCopyableText((*(byte*)ptr).ToString(), "Copy as byte");
|
||||
|
||||
ImGui.TableNextColumn(); // Float
|
||||
DrawCopyableText((*(float*)ptr).ToString(), "Copy as float");
|
||||
WidgetUtil.DrawCopyableText((*(float*)ptr).ToString(), "Copy as float");
|
||||
|
||||
ImGui.TableNextColumn(); // Hex
|
||||
DrawCopyableText($"0x{array->IntArray[i]:X2}", "Copy Hex");
|
||||
WidgetUtil.DrawCopyableText($"0x{array->IntArray[i]:X2}", "Copy Hex");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -333,11 +315,11 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
|
|||
if (this.showTextAddress)
|
||||
{
|
||||
if (!isNull)
|
||||
DrawCopyableText($"0x{(nint)array->StringArray[i]:X}", "Copy text address");
|
||||
WidgetUtil.DrawCopyableText($"0x{(nint)array->StringArray[i]:X}", "Copy text address");
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawCopyableText($"0x{(nint)(&array->StringArray[i]):X}", "Copy entry address");
|
||||
WidgetUtil.DrawCopyableText($"0x{(nint)(&array->StringArray[i]):X}", "Copy entry address");
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn(); // Managed
|
||||
|
|
@ -351,7 +333,7 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
|
|||
{
|
||||
if (this.showMacroString)
|
||||
{
|
||||
DrawCopyableText(new ReadOnlySeStringSpan(array->StringArray[i]).ToString(), "Copy text");
|
||||
WidgetUtil.DrawCopyableText(new ReadOnlySeStringSpan(array->StringArray[i]).ToString(), "Copy text");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -408,11 +390,11 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
|
|||
ImGui.TextUnformatted($"#{i}");
|
||||
|
||||
ImGui.TableNextColumn(); // Address
|
||||
DrawCopyableText($"0x{(nint)(&array->DataArray[i]):X}", "Copy entry address");
|
||||
WidgetUtil.DrawCopyableText($"0x{(nint)(&array->DataArray[i]):X}", "Copy entry address");
|
||||
|
||||
ImGui.TableNextColumn(); // Pointer
|
||||
if (!isNull)
|
||||
DrawCopyableText($"0x{(nint)array->DataArray[i]:X}", "Copy address");
|
||||
WidgetUtil.DrawCopyableText($"0x{(nint)array->DataArray[i]:X}", "Copy address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,10 +69,10 @@ internal class FateTableWidget : IDataWindowWidget
|
|||
ImGui.TextUnformatted($"#{i}");
|
||||
|
||||
ImGui.TableNextColumn(); // Address
|
||||
DrawCopyableText($"0x{fate.Address:X}", "Click to copy Address");
|
||||
WidgetUtil.DrawCopyableText($"0x{fate.Address:X}", "Click to copy Address");
|
||||
|
||||
ImGui.TableNextColumn(); // FateId
|
||||
DrawCopyableText(fate.FateId.ToString(), "Click to copy FateId (RowId of Fate sheet)");
|
||||
WidgetUtil.DrawCopyableText(fate.FateId.ToString(), "Click to copy FateId (RowId of Fate sheet)");
|
||||
|
||||
ImGui.TableNextColumn(); // State
|
||||
ImGui.TextUnformatted(fate.State.ToString());
|
||||
|
|
@ -140,7 +140,7 @@ internal class FateTableWidget : IDataWindowWidget
|
|||
|
||||
ImGui.TableNextColumn(); // Name
|
||||
|
||||
DrawCopyableText(fate.Name.ToString(), "Click to copy Name");
|
||||
WidgetUtil.DrawCopyableText(fate.Name.ToString(), "Click to copy Name");
|
||||
|
||||
ImGui.TableNextColumn(); // Progress
|
||||
ImGui.TextUnformatted($"{fate.Progress}%");
|
||||
|
|
@ -156,28 +156,10 @@ internal class FateTableWidget : IDataWindowWidget
|
|||
ImGui.TextUnformatted(fate.HasBonus.ToString());
|
||||
|
||||
ImGui.TableNextColumn(); // Position
|
||||
DrawCopyableText(fate.Position.ToString(), "Click to copy Position");
|
||||
WidgetUtil.DrawCopyableText(fate.Position.ToString(), "Click to copy Position");
|
||||
|
||||
ImGui.TableNextColumn(); // Radius
|
||||
DrawCopyableText(fate.Radius.ToString(), "Click to copy Radius");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawCopyableText(string text, string tooltipText)
|
||||
{
|
||||
ImGuiHelpers.SafeTextWrapped(text);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
|
||||
ImGui.BeginTooltip();
|
||||
ImGui.TextUnformatted(tooltipText);
|
||||
ImGui.EndTooltip();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText(text);
|
||||
WidgetUtil.DrawCopyableText(fate.Radius.ToString(), "Click to copy Radius");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ internal class GamepadWidget : IDataWindowWidget
|
|||
{
|
||||
/// <inheritdoc/>
|
||||
public string[]? CommandShortcuts { get; init; } = { "gamepad", "controller" };
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string DisplayName { get; init; } = "Gamepad";
|
||||
public string DisplayName { get; init; } = "Gamepad";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Ready { get; set; }
|
||||
|
|
@ -42,24 +42,24 @@ internal class GamepadWidget : IDataWindowWidget
|
|||
|
||||
this.DrawHelper(
|
||||
"Buttons Raw",
|
||||
gamepadState.ButtonsRaw,
|
||||
(uint)gamepadState.ButtonsRaw,
|
||||
gamepadState.Raw);
|
||||
this.DrawHelper(
|
||||
"Buttons Pressed",
|
||||
gamepadState.ButtonsPressed,
|
||||
(uint)gamepadState.ButtonsPressed,
|
||||
gamepadState.Pressed);
|
||||
this.DrawHelper(
|
||||
"Buttons Repeat",
|
||||
gamepadState.ButtonsRepeat,
|
||||
(uint)gamepadState.ButtonsRepeat,
|
||||
gamepadState.Repeat);
|
||||
this.DrawHelper(
|
||||
"Buttons Released",
|
||||
gamepadState.ButtonsReleased,
|
||||
(uint)gamepadState.ButtonsReleased,
|
||||
gamepadState.Released);
|
||||
ImGui.Text($"LeftStick {gamepadState.LeftStick}");
|
||||
ImGui.Text($"RightStick {gamepadState.RightStick}");
|
||||
}
|
||||
|
||||
|
||||
private void DrawHelper(string text, uint mask, Func<GamepadButtons, float> resolve)
|
||||
{
|
||||
ImGui.Text($"{text} {mask:X4}");
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ internal class InventoryWidget : IDataWindowWidget
|
|||
|
||||
if (!this.IsEventItem(item.ItemId))
|
||||
{
|
||||
AddKeyValueRow(item.IsCollectable ? "Collectability" : "Spiritbond", item.Spiritbond.ToString());
|
||||
AddKeyValueRow(item.IsCollectable ? "Collectability" : "Spiritbond", item.SpiritbondOrCollectability.ToString());
|
||||
|
||||
if (item.CrafterContentId != 0)
|
||||
AddKeyValueRow("CrafterContentId", item.CrafterContentId.ToString());
|
||||
|
|
@ -380,7 +380,7 @@ internal class InventoryWidget : IDataWindowWidget
|
|||
|
||||
var rowId = this.GetItemRarityColorType(item, isEdgeColor);
|
||||
return this.dataManager.Excel.GetSheet<UIColor>().TryGetRow(rowId, out var color)
|
||||
? BinaryPrimitives.ReverseEndianness(color.UIForeground) | 0xFF000000
|
||||
? BinaryPrimitives.ReverseEndianness(color.Dark) | 0xFF000000
|
||||
: 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,207 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Text.Noun;
|
||||
using Dalamud.Game.Text.Noun.Enums;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using ImGuiNET;
|
||||
using Lumina.Data;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||
|
||||
/// <summary>
|
||||
/// Widget for the NounProcessor service.
|
||||
/// </summary>
|
||||
internal class NounProcessorWidget : IDataWindowWidget
|
||||
{
|
||||
/// <summary>A list of German grammatical cases.</summary>
|
||||
internal static readonly string[] GermanCases = ["Nominative", "Genitive", "Dative", "Accusative"];
|
||||
|
||||
private static readonly Type[] NounSheets = [
|
||||
typeof(Aetheryte),
|
||||
typeof(BNpcName),
|
||||
typeof(BeastTribe),
|
||||
typeof(DeepDungeonEquipment),
|
||||
typeof(DeepDungeonItem),
|
||||
typeof(DeepDungeonMagicStone),
|
||||
typeof(DeepDungeonDemiclone),
|
||||
typeof(ENpcResident),
|
||||
typeof(EObjName),
|
||||
typeof(EurekaAetherItem),
|
||||
typeof(EventItem),
|
||||
typeof(GCRankGridaniaFemaleText),
|
||||
typeof(GCRankGridaniaMaleText),
|
||||
typeof(GCRankLimsaFemaleText),
|
||||
typeof(GCRankLimsaMaleText),
|
||||
typeof(GCRankUldahFemaleText),
|
||||
typeof(GCRankUldahMaleText),
|
||||
typeof(GatheringPointName),
|
||||
typeof(Glasses),
|
||||
typeof(GlassesStyle),
|
||||
typeof(HousingPreset),
|
||||
typeof(Item),
|
||||
typeof(MJIName),
|
||||
typeof(Mount),
|
||||
typeof(Ornament),
|
||||
typeof(TripleTriadCard),
|
||||
];
|
||||
|
||||
private ClientLanguage[] languages = [];
|
||||
private string[] languageNames = [];
|
||||
|
||||
private int selectedSheetNameIndex = 0;
|
||||
private int selectedLanguageIndex = 0;
|
||||
private int rowId = 1;
|
||||
private int amount = 1;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string[]? CommandShortcuts { get; init; } = { "noun" };
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string DisplayName { get; init; } = "Noun Processor";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Ready { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Load()
|
||||
{
|
||||
this.languages = Enum.GetValues<ClientLanguage>();
|
||||
this.languageNames = Enum.GetNames<ClientLanguage>();
|
||||
this.selectedLanguageIndex = (int)Service<ClientState>.Get().ClientLanguage;
|
||||
|
||||
this.Ready = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Draw()
|
||||
{
|
||||
var nounProcessor = Service<NounProcessor>.Get();
|
||||
var dataManager = Service<DataManager>.Get();
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
var sheetType = NounSheets.ElementAt(this.selectedSheetNameIndex);
|
||||
var language = this.languages[this.selectedLanguageIndex];
|
||||
|
||||
ImGui.SetNextItemWidth(300);
|
||||
if (ImGui.Combo("###SelectedSheetName", ref this.selectedSheetNameIndex, NounSheets.Select(t => t.Name).ToArray(), NounSheets.Length))
|
||||
{
|
||||
this.rowId = 1;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.SetNextItemWidth(120);
|
||||
if (ImGui.Combo("###SelectedLanguage", ref this.selectedLanguageIndex, this.languageNames, this.languageNames.Length))
|
||||
{
|
||||
language = this.languages[this.selectedLanguageIndex];
|
||||
this.rowId = 1;
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(120);
|
||||
var sheet = dataManager.Excel.GetSheet<RawRow>(Language.English, sheetType.Name);
|
||||
var minRowId = (int)sheet.FirstOrDefault().RowId;
|
||||
var maxRowId = (int)sheet.LastOrDefault().RowId;
|
||||
if (ImGui.InputInt("RowId###RowId", ref this.rowId, 1, 10, ImGuiInputTextFlags.AutoSelectAll))
|
||||
{
|
||||
if (this.rowId < minRowId)
|
||||
this.rowId = minRowId;
|
||||
|
||||
if (this.rowId >= maxRowId)
|
||||
this.rowId = maxRowId;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted($"(Range: {minRowId} - {maxRowId})");
|
||||
|
||||
ImGui.SetNextItemWidth(120);
|
||||
if (ImGui.InputInt("Amount###Amount", ref this.amount, 1, 10, ImGuiInputTextFlags.AutoSelectAll))
|
||||
{
|
||||
if (this.amount <= 0)
|
||||
this.amount = 1;
|
||||
}
|
||||
|
||||
var articleTypeEnumType = language switch
|
||||
{
|
||||
ClientLanguage.Japanese => typeof(JapaneseArticleType),
|
||||
ClientLanguage.German => typeof(GermanArticleType),
|
||||
ClientLanguage.French => typeof(FrenchArticleType),
|
||||
_ => typeof(EnglishArticleType),
|
||||
};
|
||||
|
||||
var numCases = language == ClientLanguage.German ? 4 : 1;
|
||||
|
||||
#if DEBUG
|
||||
if (ImGui.Button("Copy as self-test entry"))
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var articleType in Enum.GetValues(articleTypeEnumType))
|
||||
{
|
||||
for (var grammaticalCase = 0; grammaticalCase < numCases; grammaticalCase++)
|
||||
{
|
||||
var nounParams = new NounParams()
|
||||
{
|
||||
SheetName = sheetType.Name,
|
||||
RowId = (uint)this.rowId,
|
||||
Language = language,
|
||||
Quantity = this.amount,
|
||||
ArticleType = (int)articleType,
|
||||
GrammaticalCase = grammaticalCase,
|
||||
};
|
||||
var output = nounProcessor.ProcessNoun(nounParams).ExtractText().Replace("\"", "\\\"");
|
||||
var caseParam = language == ClientLanguage.German ? $"(int)GermanCases.{GermanCases[grammaticalCase]}" : "1";
|
||||
sb.AppendLine($"new(nameof(LSheets.{sheetType.Name}), {this.rowId}, ClientLanguage.{language}, {this.amount}, (int){articleTypeEnumType.Name}.{Enum.GetName(articleTypeEnumType, articleType)}, {caseParam}, \"{output}\"),");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetClipboardText(sb.ToString());
|
||||
}
|
||||
#endif
|
||||
|
||||
using var table = ImRaii.Table("TextDecoderTable", 1 + numCases, ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.NoSavedSettings);
|
||||
if (!table) return;
|
||||
|
||||
ImGui.TableSetupColumn("ArticleType", ImGuiTableColumnFlags.WidthFixed, 150);
|
||||
for (var i = 0; i < numCases; i++)
|
||||
ImGui.TableSetupColumn(language == ClientLanguage.German ? GermanCases[i] : "Text");
|
||||
ImGui.TableSetupScrollFreeze(6, 1);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
foreach (var articleType in Enum.GetValues(articleTypeEnumType))
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableHeader(articleType.ToString());
|
||||
|
||||
for (var currentCase = 0; currentCase < numCases; currentCase++)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
try
|
||||
{
|
||||
var nounParams = new NounParams()
|
||||
{
|
||||
SheetName = sheetType.Name,
|
||||
RowId = (uint)this.rowId,
|
||||
Language = language,
|
||||
Quantity = this.amount,
|
||||
ArticleType = (int)articleType,
|
||||
GrammaticalCase = currentCase,
|
||||
};
|
||||
ImGui.TextUnformatted(nounProcessor.ProcessNoun(nounParams).ExtractText());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ImGui.TextUnformatted(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -93,34 +93,34 @@ internal class UiColorWidget : IDataWindowWidget
|
|||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.PushID($"row{id}_col1");
|
||||
if (this.DrawColorColumn(row.UIForeground) &&
|
||||
ImGui.PushID($"row{id}_dark");
|
||||
if (this.DrawColorColumn(row.Dark) &&
|
||||
adjacentRow.HasValue)
|
||||
DrawEdgePreview(id, row.UIForeground, adjacentRow.Value.UIForeground);
|
||||
DrawEdgePreview(id, row.Dark, adjacentRow.Value.Dark);
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.PushID($"row{id}_col2");
|
||||
if (this.DrawColorColumn(row.UIGlow) &&
|
||||
ImGui.PushID($"row{id}_light");
|
||||
if (this.DrawColorColumn(row.Light) &&
|
||||
adjacentRow.HasValue)
|
||||
DrawEdgePreview(id, row.UIGlow, adjacentRow.Value.UIGlow);
|
||||
DrawEdgePreview(id, row.Light, adjacentRow.Value.Light);
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.PushID($"row{id}_col3");
|
||||
if (this.DrawColorColumn(row.Unknown0) &&
|
||||
ImGui.PushID($"row{id}_classic");
|
||||
if (this.DrawColorColumn(row.ClassicFF) &&
|
||||
adjacentRow.HasValue)
|
||||
DrawEdgePreview(id, row.Unknown0, adjacentRow.Value.Unknown0);
|
||||
DrawEdgePreview(id, row.ClassicFF, adjacentRow.Value.ClassicFF);
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.PushID($"row{id}_col4");
|
||||
if (this.DrawColorColumn(row.Unknown1) &&
|
||||
ImGui.PushID($"row{id}_blue");
|
||||
if (this.DrawColorColumn(row.ClearBlue) &&
|
||||
adjacentRow.HasValue)
|
||||
DrawEdgePreview(id, row.Unknown1, adjacentRow.Value.Unknown1);
|
||||
DrawEdgePreview(id, row.ClearBlue, adjacentRow.Value.ClearBlue);
|
||||
ImGui.PopID();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ internal class ContextMenuAgingStep : IAgingStep
|
|||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
|
|
@ -244,7 +244,7 @@ internal class ContextMenuAgingStep : IAgingStep
|
|||
b.AppendLine($"Container: {item.ContainerType}");
|
||||
b.AppendLine($"Slot: {item.InventorySlot}");
|
||||
b.AppendLine($"Quantity: {item.Quantity}");
|
||||
b.AppendLine($"{(item.IsCollectable ? "Collectability" : "Spiritbond")}: {item.Spiritbond}");
|
||||
b.AppendLine($"{(item.IsCollectable ? "Collectability" : "Spiritbond")}: {item.SpiritbondOrCollectability}");
|
||||
b.AppendLine($"Condition: {item.Condition / 300f:0.00}% ({item.Condition})");
|
||||
b.AppendLine($"Is HQ: {item.IsHq}");
|
||||
b.AppendLine($"Is Company Crest Applied: {item.IsCompanyCrestApplied}");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
using Dalamud.Game.ClientState.GamePad;
|
||||
using System.Linq;
|
||||
|
||||
using ImGuiNET;
|
||||
using Dalamud.Game.ClientState.GamePad;
|
||||
using Dalamud.Interface.Utility;
|
||||
|
||||
using Lumina.Text.Payloads;
|
||||
|
||||
using LSeStringBuilder = Lumina.Text.SeStringBuilder;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
|
|
@ -17,11 +22,34 @@ internal class GamepadStateAgingStep : IAgingStep
|
|||
{
|
||||
var gamepadState = Service<GamepadState>.Get();
|
||||
|
||||
ImGui.Text("Hold down North, East, L1");
|
||||
var buttons = new (GamepadButtons Button, uint IconId)[]
|
||||
{
|
||||
(GamepadButtons.North, 11),
|
||||
(GamepadButtons.East, 8),
|
||||
(GamepadButtons.L1, 12),
|
||||
};
|
||||
|
||||
if (gamepadState.Raw(GamepadButtons.North) == 1
|
||||
&& gamepadState.Raw(GamepadButtons.East) == 1
|
||||
&& gamepadState.Raw(GamepadButtons.L1) == 1)
|
||||
var builder = LSeStringBuilder.SharedPool.Get();
|
||||
|
||||
builder.Append("Hold down ");
|
||||
|
||||
for (var i = 0; i < buttons.Length; i++)
|
||||
{
|
||||
var (button, iconId) = buttons[i];
|
||||
|
||||
builder.BeginMacro(MacroCode.Icon).AppendUIntExpression(iconId).EndMacro();
|
||||
builder.PushColorRgba(gamepadState.Raw(button) == 1 ? 0x0000FF00u : 0x000000FF);
|
||||
builder.Append(button.ToString());
|
||||
builder.PopColor();
|
||||
|
||||
builder.Append(i < buttons.Length - 1 ? ", " : ".");
|
||||
}
|
||||
|
||||
ImGuiHelpers.SeStringWrapped(builder.ToReadOnlySeString());
|
||||
|
||||
LSeStringBuilder.SharedPool.Return(builder);
|
||||
|
||||
if (buttons.All(tuple => gamepadState.Raw(tuple.Button) == 1))
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,257 @@
|
|||
using Dalamud.Game;
|
||||
using Dalamud.Game.Text.Noun;
|
||||
using Dalamud.Game.Text.Noun.Enums;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
using LSheets = Lumina.Excel.Sheets;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for NounProcessor.
|
||||
/// </summary>
|
||||
internal class NounProcessorAgingStep : IAgingStep
|
||||
{
|
||||
private NounTestEntry[] tests =
|
||||
[
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.Japanese, 1, (int)JapaneseArticleType.NearListener, 1, "その蜂蜜酒の運び人"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.Japanese, 1, (int)JapaneseArticleType.Distant, 1, "蜂蜜酒の運び人"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.Japanese, 2, (int)JapaneseArticleType.NearListener, 1, "それらの蜂蜜酒の運び人"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.Japanese, 2, (int)JapaneseArticleType.Distant, 1, "あれらの蜂蜜酒の運び人"),
|
||||
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.English, 1, (int)EnglishArticleType.Indefinite, 1, "a mead-porting Midlander"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.English, 1, (int)EnglishArticleType.Definite, 1, "the mead-porting Midlander"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.English, 2, (int)EnglishArticleType.Indefinite, 1, "mead-porting Midlanders"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.English, 2, (int)EnglishArticleType.Definite, 1, "mead-porting Midlanders"),
|
||||
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Nominative, "ein Met schleppender Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Genitive, "eines Met schleppenden Wiesländers"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Dative, "einem Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Accusative, "einen Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Nominative, "der Met schleppender Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Genitive, "des Met schleppenden Wiesländers"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Dative, "dem Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Accusative, "den Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Nominative, "dein Met schleppende Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Genitive, "deines Met schleppenden Wiesländers"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Dative, "deinem Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Accusative, "deinen Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Nominative, "kein Met schleppender Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Genitive, "keines Met schleppenden Wiesländers"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Dative, "keinem Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Accusative, "keinen Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Nominative, "Met schleppender Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Genitive, "Met schleppenden Wiesländers"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Dative, "Met schleppendem Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Accusative, "Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Nominative, "dieser Met schleppende Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Genitive, "dieses Met schleppenden Wiesländers"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Dative, "diesem Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Accusative, "diesen Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Nominative, "2 Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Genitive, "2 Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Dative, "2 Met schleppenden Wiesländern"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Accusative, "2 Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Nominative, "die Met schleppende Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Genitive, "der Met schleppender Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Dative, "den Met schleppenden Wiesländern"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Accusative, "die Met schleppende Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Nominative, "deine Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Genitive, "deiner Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Dative, "deinen Met schleppenden Wiesländern"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Accusative, "deine Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Nominative, "keine Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Genitive, "keiner Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Dative, "keinen Met schleppenden Wiesländern"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Accusative, "keine Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Nominative, "Met schleppende Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Genitive, "Met schleppender Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Dative, "Met schleppenden Wiesländern"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Accusative, "Met schleppende Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Nominative, "diese Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Genitive, "dieser Met schleppenden Wiesländer"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Dative, "diesen Met schleppenden Wiesländern"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Accusative, "diese Met schleppenden Wiesländer"),
|
||||
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 1, (int)FrenchArticleType.Indefinite, 1, "un livreur d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 1, (int)FrenchArticleType.Definite, 1, "le livreur d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveFirstPerson, 1, "mon livreur d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveSecondPerson, 1, "ton livreur d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveThirdPerson, 1, "son livreur d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 2, (int)FrenchArticleType.Indefinite, 1, "des livreurs d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 2, (int)FrenchArticleType.Definite, 1, "les livreurs d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 2, (int)FrenchArticleType.PossessiveFirstPerson, 1, "mes livreurs d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 2, (int)FrenchArticleType.PossessiveSecondPerson, 1, "tes livreurs d'hydromel"),
|
||||
new(nameof(LSheets.BNpcName), 1330, ClientLanguage.French, 2, (int)FrenchArticleType.PossessiveThirdPerson, 1, "ses livreurs d'hydromel"),
|
||||
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.Japanese, 1, (int)JapaneseArticleType.NearListener, 1, "その酔いどれのネル"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.Japanese, 1, (int)JapaneseArticleType.Distant, 1, "酔いどれのネル"),
|
||||
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.English, 1, (int)EnglishArticleType.Indefinite, 1, "Nell Half-full"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.English, 1, (int)EnglishArticleType.Definite, 1, "Nell Half-full"),
|
||||
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Nominative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Genitive, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Dative, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Accusative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Nominative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Genitive, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Dative, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Accusative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Nominative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Genitive, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Dative, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Accusative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Nominative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Genitive, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Dative, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Accusative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Nominative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Genitive, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Dative, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Accusative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Nominative, "Nell die Beschwipste"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Genitive, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Dative, "Nell der Beschwipsten"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Accusative, "Nell die Beschwipste"),
|
||||
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.French, 1, (int)FrenchArticleType.Indefinite, 1, "Nell la Boit-sans-soif"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.French, 1, (int)FrenchArticleType.Definite, 1, "Nell la Boit-sans-soif"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveFirstPerson, 1, "ma Nell la Boit-sans-soif"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveSecondPerson, 1, "ta Nell la Boit-sans-soif"),
|
||||
new(nameof(LSheets.ENpcResident), 1031947, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveThirdPerson, 1, "sa Nell la Boit-sans-soif"),
|
||||
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.Japanese, 1, (int)JapaneseArticleType.NearListener, 1, "その希少トームストーン:幻想"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.Japanese, 1, (int)JapaneseArticleType.Distant, 1, "希少トームストーン:幻想"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.Japanese, 2, (int)JapaneseArticleType.NearListener, 1, "それらの希少トームストーン:幻想"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.Japanese, 2, (int)JapaneseArticleType.Distant, 1, "あれらの希少トームストーン:幻想"),
|
||||
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.English, 1, (int)EnglishArticleType.Indefinite, 1, "an irregular tomestone of phantasmagoria"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.English, 1, (int)EnglishArticleType.Definite, 1, "the irregular tomestone of phantasmagoria"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.English, 2, (int)EnglishArticleType.Indefinite, 1, "irregular tomestones of phantasmagoria"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.English, 2, (int)EnglishArticleType.Definite, 1, "irregular tomestones of phantasmagoria"),
|
||||
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Nominative, "ein ungewöhnlicher Allagischer Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Genitive, "eines ungewöhnlichen Allagischen Steins der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Dative, "einem ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Indefinite, (int)GermanCases.Accusative, "einen ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Nominative, "der ungewöhnlicher Allagischer Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Genitive, "des ungewöhnlichen Allagischen Steins der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Dative, "dem ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Definite, (int)GermanCases.Accusative, "den ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Nominative, "dein ungewöhnliche Allagische Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Genitive, "deines ungewöhnlichen Allagischen Steins der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Dative, "deinem ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Possessive, (int)GermanCases.Accusative, "deinen ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Nominative, "kein ungewöhnlicher Allagischer Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Genitive, "keines ungewöhnlichen Allagischen Steins der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Dative, "keinem ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Negative, (int)GermanCases.Accusative, "keinen ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Nominative, "ungewöhnlicher Allagischer Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Genitive, "ungewöhnlichen Allagischen Steins der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Dative, "ungewöhnlichem Allagischem Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Accusative, "ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Nominative, "dieser ungewöhnliche Allagische Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Genitive, "dieses ungewöhnlichen Allagischen Steins der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Dative, "diesem ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 1, (int)GermanArticleType.Demonstrative, (int)GermanCases.Accusative, "diesen ungewöhnlichen Allagischen Stein der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Nominative, "2 ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Genitive, "2 ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Dative, "2 ungewöhnlichen Allagischen Steinen der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Indefinite, (int)GermanCases.Accusative, "2 ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Nominative, "die ungewöhnliche Allagische Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Genitive, "der ungewöhnlicher Allagischer Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Dative, "den ungewöhnlichen Allagischen Steinen der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Definite, (int)GermanCases.Accusative, "die ungewöhnliche Allagische Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Nominative, "deine ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Genitive, "deiner ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Dative, "deinen ungewöhnlichen Allagischen Steinen der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Possessive, (int)GermanCases.Accusative, "deine ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Nominative, "keine ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Genitive, "keiner ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Dative, "keinen ungewöhnlichen Allagischen Steinen der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Negative, (int)GermanCases.Accusative, "keine ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Nominative, "ungewöhnliche Allagische Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Genitive, "ungewöhnlicher Allagischer Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Dative, "ungewöhnlichen Allagischen Steinen der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.ZeroArticle, (int)GermanCases.Accusative, "ungewöhnliche Allagische Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Nominative, "diese ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Genitive, "dieser ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Dative, "diesen ungewöhnlichen Allagischen Steinen der Phantasmagorie"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.German, 2, (int)GermanArticleType.Demonstrative, (int)GermanCases.Accusative, "diese ungewöhnlichen Allagischen Steine der Phantasmagorie"),
|
||||
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 1, (int)FrenchArticleType.Indefinite, 1, "un mémoquartz inhabituel fantasmagorique"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 1, (int)FrenchArticleType.Definite, 1, "le mémoquartz inhabituel fantasmagorique"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveFirstPerson, 1, "mon mémoquartz inhabituel fantasmagorique"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveSecondPerson, 1, "ton mémoquartz inhabituel fantasmagorique"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 1, (int)FrenchArticleType.PossessiveThirdPerson, 1, "son mémoquartz inhabituel fantasmagorique"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 2, (int)FrenchArticleType.Indefinite, 1, "des mémoquartz inhabituels fantasmagoriques"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 2, (int)FrenchArticleType.Definite, 1, "les mémoquartz inhabituels fantasmagoriques"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 2, (int)FrenchArticleType.PossessiveFirstPerson, 1, "mes mémoquartz inhabituels fantasmagoriques"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 2, (int)FrenchArticleType.PossessiveSecondPerson, 1, "tes mémoquartz inhabituels fantasmagoriques"),
|
||||
new(nameof(LSheets.Item), 44348, ClientLanguage.French, 2, (int)FrenchArticleType.PossessiveThirdPerson, 1, "ses mémoquartz inhabituels fantasmagoriques"),
|
||||
];
|
||||
|
||||
private enum GermanCases
|
||||
{
|
||||
Nominative,
|
||||
Genitive,
|
||||
Dative,
|
||||
Accusative,
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test NounProcessor";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe SelfTestStepResult RunStep()
|
||||
{
|
||||
var nounProcessor = Service<NounProcessor>.Get();
|
||||
|
||||
for (var i = 0; i < this.tests.Length; i++)
|
||||
{
|
||||
var e = this.tests[i];
|
||||
|
||||
var nounParams = new NounParams()
|
||||
{
|
||||
SheetName = e.SheetName,
|
||||
RowId = e.RowId,
|
||||
Language = e.Language,
|
||||
Quantity = e.Quantity,
|
||||
ArticleType = e.ArticleType,
|
||||
GrammaticalCase = e.GrammaticalCase,
|
||||
};
|
||||
var output = nounProcessor.ProcessNoun(nounParams);
|
||||
|
||||
if (e.ExpectedResult != output)
|
||||
{
|
||||
ImGui.TextUnformatted($"Mismatch detected (Test #{i}):");
|
||||
ImGui.TextUnformatted($"Got: {output}");
|
||||
ImGui.TextUnformatted($"Expected: {e.ExpectedResult}");
|
||||
|
||||
if (ImGui.Button("Continue"))
|
||||
return SelfTestStepResult.Fail;
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
private record struct NounTestEntry(
|
||||
string SheetName,
|
||||
uint RowId,
|
||||
ClientLanguage Language,
|
||||
int Quantity,
|
||||
int ArticleType,
|
||||
int GrammaticalCase,
|
||||
string ExpectedResult);
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Text.Evaluator;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for SeStringEvaluator.
|
||||
/// </summary>
|
||||
internal class SeStringEvaluatorAgingStep : IAgingStep
|
||||
{
|
||||
private int step = 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test SeStringEvaluator";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
var seStringEvaluator = Service<SeStringEvaluator>.Get();
|
||||
|
||||
switch (this.step)
|
||||
{
|
||||
case 0:
|
||||
ImGui.TextUnformatted("Is this the current time, and is it ticking?");
|
||||
|
||||
// This checks that EvaluateFromAddon fetches the correct Addon row,
|
||||
// that MacroDecoder.GetMacroTime()->SetTime() has been called
|
||||
// and that local and global parameters have been read correctly.
|
||||
|
||||
ImGui.TextUnformatted(seStringEvaluator.EvaluateFromAddon(31, [(uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds()]).ExtractText());
|
||||
|
||||
if (ImGui.Button("Yes"))
|
||||
this.step++;
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button("No"))
|
||||
return SelfTestStepResult.Fail;
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ImGui.TextUnformatted("Checking pcname macro using the local player name...");
|
||||
|
||||
// This makes sure that NameCache.Instance()->TryGetCharacterInfoByEntityId() has been called,
|
||||
// that it returned the local players name by using its EntityId,
|
||||
// and that it didn't include the world name by checking the HomeWorldId against AgentLobby.Instance()->LobbyData.HomeWorldId.
|
||||
|
||||
var clientState = Service<ClientState>.Get();
|
||||
var localPlayer = clientState.LocalPlayer;
|
||||
if (localPlayer is null)
|
||||
{
|
||||
ImGui.TextUnformatted("You need to be logged in for this step.");
|
||||
|
||||
if (ImGui.Button("Skip"))
|
||||
return SelfTestStepResult.NotRan;
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
var evaluatedPlayerName = seStringEvaluator.Evaluate(ReadOnlySeString.FromMacroString("<pcname(lnum1)>"), [localPlayer.EntityId]).ExtractText();
|
||||
var localPlayerName = localPlayer.Name.TextValue;
|
||||
|
||||
if (evaluatedPlayerName != localPlayerName)
|
||||
{
|
||||
ImGui.TextUnformatted("The player name doesn't match:");
|
||||
ImGui.TextUnformatted($"Evaluated Player Name (got): {evaluatedPlayerName}");
|
||||
ImGui.TextUnformatted($"Local Player Name (expected): {localPlayerName}");
|
||||
|
||||
if (ImGui.Button("Continue"))
|
||||
return SelfTestStepResult.Fail;
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
this.step = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Text.Evaluator.Internal;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for SheetRedirectResolver.
|
||||
/// </summary>
|
||||
internal class SheetRedirectResolverAgingStep : IAgingStep
|
||||
{
|
||||
private RedirectEntry[] redirects =
|
||||
[
|
||||
new("Item", 10, SheetRedirectFlags.Item),
|
||||
new("ItemHQ", 10, SheetRedirectFlags.Item | SheetRedirectFlags.HighQuality),
|
||||
new("ItemMP", 10, SheetRedirectFlags.Item | SheetRedirectFlags.Collectible),
|
||||
new("Item", 35588, SheetRedirectFlags.Item),
|
||||
new("Item", 1035588, SheetRedirectFlags.Item | SheetRedirectFlags.HighQuality),
|
||||
new("Item", 2000217, SheetRedirectFlags.Item | SheetRedirectFlags.EventItem),
|
||||
new("ActStr", 10, SheetRedirectFlags.Action), // Trait
|
||||
new("ActStr", 1000010, SheetRedirectFlags.Action | SheetRedirectFlags.ActionSheet), // Action
|
||||
new("ActStr", 2000010, SheetRedirectFlags.Action), // Item
|
||||
new("ActStr", 3000010, SheetRedirectFlags.Action), // EventItem
|
||||
new("ActStr", 4000010, SheetRedirectFlags.Action), // EventAction
|
||||
new("ActStr", 5000010, SheetRedirectFlags.Action), // GeneralAction
|
||||
new("ActStr", 6000010, SheetRedirectFlags.Action), // BuddyAction
|
||||
new("ActStr", 7000010, SheetRedirectFlags.Action), // MainCommand
|
||||
new("ActStr", 8000010, SheetRedirectFlags.Action), // Companion
|
||||
new("ActStr", 9000010, SheetRedirectFlags.Action), // CraftAction
|
||||
new("ActStr", 10000010, SheetRedirectFlags.Action | SheetRedirectFlags.ActionSheet), // Action
|
||||
new("ActStr", 11000010, SheetRedirectFlags.Action), // PetAction
|
||||
new("ActStr", 12000010, SheetRedirectFlags.Action), // CompanyAction
|
||||
new("ActStr", 13000010, SheetRedirectFlags.Action), // Mount
|
||||
// new("ActStr", 14000010, RedirectFlags.Action),
|
||||
// new("ActStr", 15000010, RedirectFlags.Action),
|
||||
// new("ActStr", 16000010, RedirectFlags.Action),
|
||||
// new("ActStr", 17000010, RedirectFlags.Action),
|
||||
// new("ActStr", 18000010, RedirectFlags.Action),
|
||||
new("ActStr", 19000010, SheetRedirectFlags.Action), // BgcArmyAction
|
||||
new("ActStr", 20000010, SheetRedirectFlags.Action), // Ornament
|
||||
new("ObjStr", 10), // BNpcName
|
||||
new("ObjStr", 1000010), // ENpcResident
|
||||
new("ObjStr", 2000010), // Treasure
|
||||
new("ObjStr", 3000010), // Aetheryte
|
||||
new("ObjStr", 4000010), // GatheringPointName
|
||||
new("ObjStr", 5000010), // EObjName
|
||||
new("ObjStr", 6000010), // Mount
|
||||
new("ObjStr", 7000010), // Companion
|
||||
// new("ObjStr", 8000010),
|
||||
// new("ObjStr", 9000010),
|
||||
new("ObjStr", 10000010), // Item
|
||||
new("EObj", 2003479), // EObj => EObjName
|
||||
new("Treasure", 1473), // Treasure (without name, falls back to rowId 0)
|
||||
new("Treasure", 1474), // Treasure (with name)
|
||||
new("WeatherPlaceName", 0),
|
||||
new("WeatherPlaceName", 28),
|
||||
new("WeatherPlaceName", 40),
|
||||
new("WeatherPlaceName", 52),
|
||||
new("WeatherPlaceName", 2300),
|
||||
];
|
||||
|
||||
private unsafe delegate SheetRedirectFlags ResolveSheetRedirect(RaptureTextModule* thisPtr, Utf8String* sheetName, uint* rowId, uint* flags);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test SheetRedirectResolver";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe SelfTestStepResult RunStep()
|
||||
{
|
||||
// Client::UI::Misc::RaptureTextModule_ResolveSheetRedirect
|
||||
if (!Service<TargetSigScanner>.Get().TryScanText("E8 ?? ?? ?? ?? 44 8B E8 A8 10", out var addr))
|
||||
return SelfTestStepResult.Fail;
|
||||
|
||||
var sheetRedirectResolver = Service<SheetRedirectResolver>.Get();
|
||||
var resolveSheetRedirect = Marshal.GetDelegateForFunctionPointer<ResolveSheetRedirect>(addr);
|
||||
var utf8SheetName = Utf8String.CreateEmpty();
|
||||
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < this.redirects.Length; i++)
|
||||
{
|
||||
var redirect = this.redirects[i];
|
||||
|
||||
utf8SheetName->SetString(redirect.SheetName);
|
||||
|
||||
var rowId1 = redirect.RowId;
|
||||
uint colIndex1 = ushort.MaxValue;
|
||||
var flags1 = resolveSheetRedirect(RaptureTextModule.Instance(), utf8SheetName, &rowId1, &colIndex1);
|
||||
|
||||
var sheetName2 = redirect.SheetName;
|
||||
var rowId2 = redirect.RowId;
|
||||
uint colIndex2 = ushort.MaxValue;
|
||||
var flags2 = sheetRedirectResolver.Resolve(ref sheetName2, ref rowId2, ref colIndex2);
|
||||
|
||||
if (utf8SheetName->ToString() != sheetName2 || rowId1 != rowId2 || colIndex1 != colIndex2 || flags1 != flags2)
|
||||
{
|
||||
ImGui.TextUnformatted($"Mismatch detected (Test #{i}):");
|
||||
ImGui.TextUnformatted($"Input: {redirect.SheetName}#{redirect.RowId}");
|
||||
ImGui.TextUnformatted($"Game: {utf8SheetName->ToString()}#{rowId1}-{colIndex1} ({flags1})");
|
||||
ImGui.TextUnformatted($"Evaluated: {sheetName2}#{rowId2}-{colIndex2} ({flags2})");
|
||||
|
||||
if (ImGui.Button("Continue"))
|
||||
return SelfTestStepResult.Fail;
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
finally
|
||||
{
|
||||
utf8SheetName->Dtor(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
private record struct RedirectEntry(string SheetName, uint RowId, SheetRedirectFlags Flags = SheetRedirectFlags.None);
|
||||
}
|
||||
|
|
@ -50,6 +50,9 @@ internal class SelfTestWindow : Window
|
|||
new DutyStateAgingStep(),
|
||||
new GameConfigAgingStep(),
|
||||
new MarketBoardAgingStep(),
|
||||
new SheetRedirectResolverAgingStep(),
|
||||
new NounProcessorAgingStep(),
|
||||
new SeStringEvaluatorAgingStep(),
|
||||
new LogoutEventAgingStep(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
moveEasing.Update();
|
||||
|
||||
var finalPos = (i + 1) * this.shadeTexture.Value.Height * scale;
|
||||
var pos = moveEasing.Value * finalPos;
|
||||
var pos = moveEasing.ValueClamped * finalPos;
|
||||
|
||||
// FIXME(goat): Sometimes, easings can overshoot and bring things out of alignment.
|
||||
if (moveEasing.IsDone)
|
||||
|
|
@ -270,7 +270,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
|
||||
this.fadeOutEasing.Update();
|
||||
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)Math.Max(this.fadeOutEasing.Value, 0)))
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.ValueClamped))
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var entry in entries)
|
||||
|
|
@ -353,7 +353,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
|
||||
var initialCursor = ImGui.GetCursorPos();
|
||||
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)shadeEasing.Value))
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)shadeEasing.ValueClamped))
|
||||
{
|
||||
var texture = this.shadeTexture.Value;
|
||||
ImGui.Image(texture.ImGuiHandle, new Vector2(texture.Width, texture.Height) * scale);
|
||||
|
|
@ -403,7 +403,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
|
||||
if (overrideAlpha)
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, isFirst ? 1f : (float)logoEasing.Value);
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, isFirst ? 1f : (float)logoEasing.ValueClamped);
|
||||
}
|
||||
else if (isFirst)
|
||||
{
|
||||
|
|
@ -430,7 +430,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
|
||||
if (overrideAlpha)
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)Math.Min(logoEasing.Value, 1) : 0f);
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)logoEasing.ValueClamped : 0f);
|
||||
}
|
||||
|
||||
// Drop shadow
|
||||
|
|
@ -480,7 +480,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
textNode->TextFlags |= (byte)TextFlags.MultiLine;
|
||||
textNode->AlignmentType = AlignmentType.TopLeft;
|
||||
|
||||
var containsDalamudVersionString = textNode->OriginalTextPointer == textNode->NodeText.StringPtr;
|
||||
var containsDalamudVersionString = textNode->OriginalTextPointer.Value == textNode->NodeText.StringPtr.Value;
|
||||
if (!this.configuration.ShowTsm || !this.showTsm.Value)
|
||||
{
|
||||
if (containsDalamudVersionString)
|
||||
|
|
@ -498,7 +498,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
this.lastLoadedPluginCount = count;
|
||||
|
||||
var lssb = LSeStringBuilder.SharedPool.Get();
|
||||
lssb.Append(new ReadOnlySeStringSpan(addon->AtkValues[1].String)).Append("\n\n");
|
||||
lssb.Append(new ReadOnlySeStringSpan(addon->AtkValues[1].String.Value)).Append("\n\n");
|
||||
lssb.PushEdgeColorType(701).PushColorType(539)
|
||||
.Append(SeIconChar.BoxedLetterD.ToIconChar())
|
||||
.PopColorType().PopEdgeColorType();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility;
|
||||
using Dalamud.Utility.TerraFxCom;
|
||||
|
||||
using Lumina.Data.Files;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
|
@ -24,32 +24,30 @@ internal sealed partial class TextureManager
|
|||
(nint)this.ConvertToKernelTexture(wrap, leaveWrapOpen);
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.ConvertToKernelTexture"/>
|
||||
public unsafe FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture* ConvertToKernelTexture(
|
||||
IDalamudTextureWrap wrap,
|
||||
bool leaveWrapOpen = false)
|
||||
public unsafe Texture* ConvertToKernelTexture(IDalamudTextureWrap wrap, bool leaveWrapOpen = false)
|
||||
{
|
||||
using var wrapAux = new WrapAux(wrap, leaveWrapOpen);
|
||||
|
||||
var flags = TexFile.Attribute.TextureType2D;
|
||||
var flags = TextureFlags.TextureType2D;
|
||||
if (wrapAux.Desc.Usage == D3D11_USAGE.D3D11_USAGE_IMMUTABLE)
|
||||
flags |= TexFile.Attribute.Immutable;
|
||||
flags |= TextureFlags.Immutable;
|
||||
if (wrapAux.Desc.Usage == D3D11_USAGE.D3D11_USAGE_DYNAMIC)
|
||||
flags |= TexFile.Attribute.ReadWrite;
|
||||
flags |= TextureFlags.ReadWrite;
|
||||
if ((wrapAux.Desc.CPUAccessFlags & (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ) != 0)
|
||||
flags |= TexFile.Attribute.CpuRead;
|
||||
flags |= TextureFlags.CpuRead;
|
||||
if ((wrapAux.Desc.BindFlags & (uint)D3D11_BIND_FLAG.D3D11_BIND_RENDER_TARGET) != 0)
|
||||
flags |= TexFile.Attribute.TextureRenderTarget;
|
||||
flags |= TextureFlags.TextureRenderTarget;
|
||||
if ((wrapAux.Desc.BindFlags & (uint)D3D11_BIND_FLAG.D3D11_BIND_DEPTH_STENCIL) != 0)
|
||||
flags |= TexFile.Attribute.TextureDepthStencil;
|
||||
flags |= TextureFlags.TextureDepthStencil;
|
||||
if (wrapAux.Desc.ArraySize != 1)
|
||||
throw new NotSupportedException("TextureArray2D is currently not supported.");
|
||||
|
||||
var gtex = FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture.CreateTexture2D(
|
||||
var gtex = Texture.CreateTexture2D(
|
||||
(int)wrapAux.Desc.Width,
|
||||
(int)wrapAux.Desc.Height,
|
||||
(byte)wrapAux.Desc.MipLevels,
|
||||
(uint)TexFile.TextureFormat.Null, // instructs the game to skip preprocessing it seems
|
||||
(uint)flags,
|
||||
0, // instructs the game to skip preprocessing it seems
|
||||
flags,
|
||||
0);
|
||||
|
||||
// Kernel::Texture owns these resources. We're passing the ownership to them.
|
||||
|
|
@ -57,28 +55,27 @@ internal sealed partial class TextureManager
|
|||
wrapAux.SrvPtr->AddRef();
|
||||
|
||||
// Not sure this is needed
|
||||
var ltf = wrapAux.Desc.Format switch
|
||||
gtex->TextureFormat = wrapAux.Desc.Format switch
|
||||
{
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT => TexFile.TextureFormat.R32G32B32A32F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16G16B16A16_FLOAT => TexFile.TextureFormat.R16G16B16A16F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT => TexFile.TextureFormat.R32G32F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16G16_FLOAT => TexFile.TextureFormat.R16G16F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT => TexFile.TextureFormat.R32F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R24G8_TYPELESS => TexFile.TextureFormat.D24S8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16_TYPELESS => TexFile.TextureFormat.D16,
|
||||
DXGI_FORMAT.DXGI_FORMAT_A8_UNORM => TexFile.TextureFormat.A8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM => TexFile.TextureFormat.BC1,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM => TexFile.TextureFormat.BC2,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM => TexFile.TextureFormat.BC3,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM => TexFile.TextureFormat.BC5,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM => TexFile.TextureFormat.B4G4R4A4,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM => TexFile.TextureFormat.B5G5R5A1,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM => TexFile.TextureFormat.B8G8R8A8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8X8_UNORM => TexFile.TextureFormat.B8G8R8X8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM => TexFile.TextureFormat.BC7,
|
||||
_ => TexFile.TextureFormat.Null,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT => TextureFormat.R32G32B32A32_FLOAT,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16G16B16A16_FLOAT => TextureFormat.R16G16B16A16_FLOAT,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT => TextureFormat.R32G32_FLOAT,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16G16_FLOAT => TextureFormat.R16G16_FLOAT,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT => TextureFormat.R32_FLOAT,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R24G8_TYPELESS => TextureFormat.D24_UNORM_S8_UINT,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16_TYPELESS => TextureFormat.D16_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_A8_UNORM => TextureFormat.A8_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM => TextureFormat.BC1_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM => TextureFormat.BC2_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM => TextureFormat.BC3_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM => TextureFormat.BC5_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM => TextureFormat.B4G4R4A4_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM => TextureFormat.B5G5R5A1_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM => TextureFormat.B8G8R8A8_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8X8_UNORM => TextureFormat.B8G8R8X8_UNORM,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM => TextureFormat.BC7_UNORM,
|
||||
_ => 0,
|
||||
};
|
||||
gtex->TextureFormat = (FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.TextureFormat)ltf;
|
||||
|
||||
gtex->D3D11Texture2D = wrapAux.TexPtr;
|
||||
gtex->D3D11ShaderResourceView = wrapAux.SrvPtr;
|
||||
|
|
|
|||
|
|
@ -210,8 +210,6 @@ public static class ImGuiHelpers
|
|||
/// <param name="imGuiId">ImGui ID, if link functionality is desired.</param>
|
||||
/// <param name="buttonFlags">Button flags to use on link interaction.</param>
|
||||
/// <returns>Interaction result of the rendered text.</returns>
|
||||
/// <remarks>This function is experimental. Report any issues to GitHub issues or to Discord #dalamud-dev channel.
|
||||
/// The function definition is stable; only in the next API version a function may be removed.</remarks>
|
||||
public static SeStringDrawResult SeStringWrapped(
|
||||
ReadOnlySpan<byte> sss,
|
||||
scoped in SeStringDrawParams style = default,
|
||||
|
|
@ -226,8 +224,6 @@ public static class ImGuiHelpers
|
|||
/// <param name="imGuiId">ImGui ID, if link functionality is desired.</param>
|
||||
/// <param name="buttonFlags">Button flags to use on link interaction.</param>
|
||||
/// <returns>Interaction result of the rendered text.</returns>
|
||||
/// <remarks>This function is experimental. Report any issues to GitHub issues or to Discord #dalamud-dev channel.
|
||||
/// The function definition is stable; only in the next API version a function may be removed.</remarks>
|
||||
public static SeStringDrawResult CompileSeStringWrapped(
|
||||
string text,
|
||||
scoped in SeStringDrawParams style = default,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -216,7 +216,12 @@ internal class PluginManagementCommandHandler : IInternalDisposableService
|
|||
|
||||
this.chat.Print(onSuccess);
|
||||
}
|
||||
|
||||
|
||||
if (operation == PluginCommandOperation.Toggle)
|
||||
{
|
||||
operation = plugin.State == PluginState.Loaded ? PluginCommandOperation.Disable : PluginCommandOperation.Enable;
|
||||
}
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case PluginCommandOperation.Enable:
|
||||
|
|
@ -235,14 +240,6 @@ internal class PluginManagementCommandHandler : IInternalDisposableService
|
|||
Loc.Localize("PluginCommandsDisableFailed", "Failed to disable plugin \"{0}\". Please check the console for errors.").Format(plugin.Name)))
|
||||
.ConfigureAwait(false);
|
||||
break;
|
||||
case PluginCommandOperation.Toggle:
|
||||
this.chat.Print(Loc.Localize("PluginCommandsToggling", "Toggling plugin \"{0}\"...").Format(plugin.Name));
|
||||
Task.Run(() => plugin.State == PluginState.Loaded ? plugin.UnloadAsync() : plugin.LoadAsync(PluginLoadReason.Installer))
|
||||
.ContinueWith(t => Continuation(t,
|
||||
Loc.Localize("PluginCommandsToggleSuccess", "Plugin \"{0}\" toggled.").Format(plugin.Name),
|
||||
Loc.Localize("PluginCommandsToggleFailed", "Failed to toggle plugin \"{0}\". Please check the console for errors.").Format(plugin.Name)))
|
||||
.ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(operation), operation, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,32 +3,31 @@ namespace Dalamud.Plugin;
|
|||
/// <summary>
|
||||
/// This enum reflects reasons for loading a plugin.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum PluginLoadReason
|
||||
{
|
||||
/// <summary>
|
||||
/// We don't know why this plugin was loaded.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
Unknown = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// This plugin was loaded because it was installed with the plugin installer.
|
||||
/// </summary>
|
||||
Installer,
|
||||
Installer = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// This plugin was loaded because it was just updated.
|
||||
/// </summary>
|
||||
Update,
|
||||
Update = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// This plugin was loaded because it was told to reload.
|
||||
/// </summary>
|
||||
Reload,
|
||||
Reload = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// This plugin was loaded because the game was started or Dalamud was reinjected.
|
||||
/// </summary>
|
||||
Boot,
|
||||
Boot = 1 << 4,
|
||||
}
|
||||
|
||||
// TODO(api9): This should be a mask, so that we can combine Installer | ProfileLoaded
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue