Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/Game/Control/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public unsafe partial struct Control {

[FieldOffset(0x7518)] public bool IsWalkingDuringAutorun;
[FieldOffset(0x7637)] public bool IsWalking;
[FieldOffset(0x7688)] public SpectatorSystem* SpectatorSystem;
[FieldOffset(0x7698)] public uint LocalPlayerEntityId;
[FieldOffset(0x76A0)] public BattleChara* LocalPlayer;
[FieldOffset(0x76B0)] public Matrix4x4 ViewProjectionMatrix;
Expand All @@ -40,4 +41,12 @@ public enum FlightAllowedStatus {
DefaultCase = 7,
PlayerOrMountNull = 8
}

/// <summary> Creates a new SpectatorSystem. </summary>
[MemberFunction("E8 ?? ?? ?? ?? 33 DB 48 8B FD 66 90")]
public partial void CreateSpectatorControl();

/// <summary> Calls the destructor for SpectatorSystem and sets it back to null. </summary>
[MemberFunction("E8 ?? ?? ?? ?? 33 D2 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B F0")]
public partial void FreeSpectatorControl();
}
36 changes: 36 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/Game/Control/SpectatorSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Common.Math;

namespace FFXIVClientStructs.FFXIV.Client.Game.Control;

// Client::Game::Control::SpectatorSystem
[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0xD0)]
public unsafe partial struct SpectatorSystem {
[FieldOffset(0x08), FixedSizeArray] internal FixedSizeArray8<SpectatorSpot> _spectatorSpots;
[FieldOffset(0xAC)] public uint FocusObjectId;
[FieldOffset(0xB0)] public uint FocusSpotIndex;
[FieldOffset(0xB4)] public float FocusX;
[FieldOffset(0xB8)] public float FocusY;
[FieldOffset(0xBC)] public float FocusZ;
[FieldOffset(0xC0)] public float FocusDirH;
[FieldOffset(0xC4)] public float FocusDirV;

/// <summary> Moves the spectator camera to a specific object. </summary>
[MemberFunction("E8 ?? ?? ?? ?? 48 8B 83 ?? ?? ?? ?? 45 85 FF")]
public partial void FocusOnObject(uint objectId);

/// <summary> Moves the spectator camera to a spot at this index. </summary>
[MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 0F B6 86 ?? ?? ?? ?? 3B D8")]
public partial void FocusOnSpot(uint index, bool a3);

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x14)]
public unsafe partial struct SpectatorSpot {
[FieldOffset(0x00)] public float X; // Spectator.X
[FieldOffset(0x04)] public float Y; // Spectator.Y
[FieldOffset(0x08)] public float Z; // Spectator.Z
[FieldOffset(0x0C)] public float DirH; // Spectator.DirH
[FieldOffset(0x10)] public float DirV; // Spectator.DirV
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace FFXIVClientStructs.FFXIV.Client.Game.Network;

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x24)]
public partial struct SpectatorListPacket {
[FieldOffset(0x0), FixedSizeArray] internal FixedSizeArray8<uint> _spectatorIds;
[FieldOffset(0x20)] private byte Flag; // Used as a count for spectator ids, maybe?
}
55 changes: 55 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/Game/SpectatorManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using FFXIVClientStructs.FFXIV.Common.Component.Excel;
using FFXIVClientStructs.FFXIV.Component.GUI;

namespace FFXIVClientStructs.FFXIV.Client.Game;

// Client::Game::SpectatorManager
/// <remarks>
/// Initializes and manages the spectator system
/// </remarks>
[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x4E0)]
public unsafe partial struct SpectatorManager {
[StaticAddress("4C 89 2D ?? ?? ?? ?? 45 33 C0", 3, isPointer: true)]
public static partial SpectatorManager* Instance();

[FieldOffset(0x008)] public ExcelSheet* Sheet;
[FieldOffset(0x010)] public SpectatorManagerWaiter* Waiter;
[FieldOffset(0x08C)] public uint SpectatorRowId;
[FieldOffset(0x094)] private uint Unk94;
[FieldOffset(0x098)] private uint Unk98;
[FieldOffset(0x090)] private byte Unk90;
[FieldOffset(0x0A1)] private byte Unknown40; // Set with Spectator.Unknown40 in ReadSpectatorRow
[FieldOffset(0x0A2)] public byte SheetStatus; // 0 = Missing, 1 = Sheet loaded, 2 = Row read
[FieldOffset(0x0DA)] private byte UnkDA; // 1, 2 and 100 (default?) are known flags. 2 shows the spectator management UI

/// <summary> Initializes the SpectatorManager global. </summary>
[MemberFunction("48 89 5C 24 ?? 55 41 54 41 55 41 56 41 57 48 83 EC ?? 44 8B E1")]
public static partial void Initialize(uint spectatorRowId, uint a3, byte a4, uint a5);

/// <summary> Updates and manages the Excel waiters here. </summary>
[MemberFunction("48 89 5C 24 ?? 56 48 83 EC ?? F3 0F 10 89")]
public partial void Update();

/// <summary> Reads spectator data from Excel, puts most of it into Control.SpectatorSystem. </summary>
[MemberFunction("48 8D 05 ?? ?? ?? ?? 48 89 47 ?? 48 89 5F ?? 48 89 77 ?? EB ?? 48 8B FE 44 8B 83")]
public partial void ReadSpectatorRow([CExporterExcel("Spectator")] void *spectatorRow);

/// <summary> Changes an internal flag to tell the spectator UI to show itself. </summary>
[MemberFunction("40 53 48 83 EC ?? 80 A1 ?? ?? ?? ?? ?? 48 8B D9 E8 ?? ?? ?? ?? 80 8B")]
public partial void ShowSpectatorUI();

/// <summary> Used by AgentPvPSpectator to check if the regular PvP spectator UI should be visible. </summary>
[MemberFunction("E8 ?? ?? ?? ?? 84 C0 0F 84 ?? ?? ?? ?? 48 8B 83 ?? ?? ?? ?? 41 B0")]
public partial bool ShouldShowSpectatorUI();

[GenerateInterop]
[Inherits<ExcelSheetWaiter>]
[StructLayout(LayoutKind.Explicit, Size = 0x50)]
public partial struct SpectatorManagerWaiter {
[FieldOffset(0x030)] private void* Unk30;
[FieldOffset(0x038)] public void* Arg;
[FieldOffset(0x040)] public void* Callback;
[FieldOffset(0x048)] private void* Unk48;
}
}
5 changes: 5 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/Game/UI/InstanceContent.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.System.Memory;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Client.Game.Network;

namespace FFXIVClientStructs.FFXIV.Client.Game.UI;

Expand All @@ -10,6 +11,7 @@ public unsafe partial struct InstanceContent {
[StaticAddress("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 84 C0 0F 94 C3", 3)]
public static partial InstanceContent* Instance();

[FieldOffset(0x38), FixedSizeArray] internal FixedSizeArray8<uint> _spectatorIds;
[FieldOffset(0x6C)] public byte RankedCrystallineConflictHostingDataCenterId; // saved as uint, used as byte? checks against 0xFF too
[FieldOffset(0x70)] public bool IsLimitedTimeBonusActive;

Expand All @@ -27,6 +29,9 @@ public unsafe partial struct InstanceContent {
[MemberFunction("48 83 EC 28 84 D2 74 33")]
public partial bool IsRouletteIncomplete(byte roulette);

[MemberFunction("8B 02 4C 8B C9 89 41")]
public partial void ProcessSpectatorListPacket(SpectatorListPacket* packet);

public bool IsRouletteComplete(byte roulette) => !IsRouletteIncomplete(roulette);

[GenerateInterop]
Expand Down
3 changes: 3 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/Network/PacketDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public static partial void HandleActorControlPacket(
[MemberFunction("E8 ?? ?? ?? ?? B0 ?? 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 ?? 5F C3 48 8B CB E8 ?? ?? ?? ?? B0 ?? 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 ?? 5F C3 48 8B 4B")]
public static partial void HandleMapEffectPacket(MapEffectPacket* packet);

[MemberFunction("E8 ?? ?? ?? ?? B0 ?? 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 ?? 5F C3 48 8B CB E8 ?? ?? ?? ?? B0 ?? 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 ?? 5F C3 48 8B CB E8 ?? ?? ?? ?? 48 8B 5C 24")]
public static partial void HandleSpectatorListPacket(SpectatorListPacket* packet);

[VirtualFunction(1)]
public partial void OnReceivePacket(uint targetId, nint packet);
}
20 changes: 20 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentPvPSpectator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace FFXIVClientStructs.FFXIV.Client.UI.Agent;

// Client::UI::Agent::AgentPvPSpectator
// Client::UI::Agent::AgentInterface
// Component::GUI::AtkModuleInterface::AtkEventInterface
[Agent(AgentId.PvPSpectator)]
[GenerateInterop]
[Inherits<AgentInterface>]
[StructLayout(LayoutKind.Explicit, Size = 0xC0)]
public unsafe partial struct AgentPvPSpectator {
[FieldOffset(0x88)] public AgentPvPSpectatorData* Data;

[MemberFunction("E8 ?? ?? ?? ?? 80 BB ?? ?? ?? ?? ?? 0F 84 ?? ?? ?? ?? 48 8B 4B ?? 48 89 AC 24")]
public partial void UpdateAddonVisibility();
}

[StructLayout(LayoutKind.Explicit, Size = 0x378)]
public unsafe partial struct AgentPvPSpectatorData {
[FieldOffset(0x354)] public uint AddonPvPSpectatorCameraList;
}
36 changes: 36 additions & 0 deletions ida/data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ globals:
0x142A71554: g_animationFactorRemainder
0x142A71AB0: g_animationFactor #percentage of a 30fps frame rendered this frame
0x142A76110: g_PerformanceFrequency
0x142A823E8: g_Client::Game::Control::Control_SpectatorSystem
0x142A823F8: g_Client::Game::Control::Control_LocalPlayerEntityId
0x142A82400: g_Client::Game::Control::Control_LocalPlayer
0x142A91500: g_NounPlaceholder_n
Expand Down Expand Up @@ -627,6 +628,14 @@ classes:
0x141962EC0: ExecuteEmote # (emoteId, targetInfo)
0x141963780: CanExecuteEmote # (emoteId)
0x141964030: Update
Client::Game::Control::SpectatorSystem:
vtbls:
- ea: 0x142170A70
vfuncs:
0: dtor
funcs:
0x14062D2F0: FocusOnObject
0x14062D390: FocusOnSpot
Application::Network::NetworkModule:
funcs:
0x141CF2680: ctor
Expand Down Expand Up @@ -954,6 +963,26 @@ classes:
0x141A7C840: GetAdjustedTimestamp # static
0x141A7C860: GetBonusGuaranteeForTimestamp # static
0x141A7C8A0: GetSatisfactionBonusesForNpc # static
Client::Game::SpectatorManager:
vtbls:
- ea: 0x1422CB8F8
vfuncs:
0: dtor
instances:
- ea: 0x142ACAC58
pointer: true
funcs:
0x141783290: Initialize
0x141783490: GetInstance
0x141785260: GetInstance2
0x141782A10: Update
0x141782D60: ShowSpectatorUI
0x1417834F0: ReadSpectatorRow
0x141782C80: ShouldShowSpectatorUI
Client::Game::SpectatorManagerWaiter:
vtbls:
- ea: 0x1422CB988
base: Common::Component::Excel::ExcelSheetWaiter
Client::Game::InstanceContent::ContentSheetWaiterInterface:
vtbls:
- ea: 0x14218BBC8
Expand Down Expand Up @@ -3601,6 +3630,7 @@ classes:
- ea: 0x1421BA2B8
funcs:
0x140C27C10: GetPenaltyRemainingInMinutes
0x140C28280: ProcessSpectatorListPacket
0x140C29720: GetContentInterface
0x140C2A5A0: IsRouletteIncomplete
Client::Game::UI::GuildOrderReward:
Expand Down Expand Up @@ -4291,6 +4321,7 @@ classes:
0x142084B50: Finalizer
vfuncs:
0: dtor
1: Finish
Component::Excel::ExcelModuleInterface:
vtbls:
- ea: 0x14211ED90
Expand Down Expand Up @@ -6555,6 +6586,7 @@ classes:
0x140B485E0: HandleDeepDungeonPartyInfoPacket
0x140B48620: HandleDeepDungeonChestInfoPacket
0x140B48660: HandleDeepDungeonBlacklistPacket
0x140B48840: HandleSpectatorListPacket
0x140B497B0: HandlePrepareZoningPacket
0x140B49CB0: HandleMapEffectPacket
0x140B4A290: HandleQuestManagerUnkArray2SecondHalfPacket
Expand Down Expand Up @@ -8491,6 +8523,8 @@ classes:
0x14062C630: Initialize
0x14062C6C0: Terminate
0x14062C900: Update
0x14062CEF0: CreateSpectatorControl
0x14062CF70: FreeSpectatorControl
0x141832940: GetFlightAllowedStatus # static
Client::Game::Control::CameraManager:
funcs:
Expand Down Expand Up @@ -14179,6 +14213,8 @@ classes:
vtbls:
- ea: 0x1421BFF58
base: Client::UI::Agent::AgentInterface
funcs:
0x140D62EC0: UpdateAddonVisibility
Client::UI::Agent::AgentAquarium:
vtbls:
- ea: 0x1421ED3B0
Expand Down
Loading