diff --git a/FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs b/FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs index 002f18ea4d..03116473b2 100644 --- a/FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs +++ b/FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs @@ -62,6 +62,22 @@ public unsafe partial struct EventHandler { [VirtualFunction(209)] public partial uint GetNameplateIconForObject(GameObject* gameObject); + /// Changes the currently playing timelines based on the difference between oldSharedTimelineState and newSharedTimelineState. + /// The game object to update. + /// The new SharedTimelineState value. + /// The old SharedTimelineState value. + /// Seems to modify newSharedTimelineState in in some EventHandlers. + [VirtualFunction(253)] + public partial void UpdateSharedTimelineState(GameObject* gameObject, ushort oldSharedTimelineState, ushort newSharedTimelineState, ulong timelineIndices); + + /// Changes the currently playing timelines based on a bitmask. + /// The game object to update. + /// The new SharedTimelineState value. + /// The new timeline bitmask. + /// Unused and can be left empty. + [VirtualFunction(254)] + public partial void UpdateTimelinesByBitmask(GameObject* gameObject, uint sharedTimelineState, uint bitmask, ulong unused); + [VirtualFunction(258)] public partial void GetDescription(Utf8String* outDescription); diff --git a/FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/ContentDirector.cs b/FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/ContentDirector.cs index 6a326b4f24..20c10b2c39 100644 --- a/FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/ContentDirector.cs +++ b/FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/ContentDirector.cs @@ -34,6 +34,19 @@ public unsafe partial struct ContentDirector { [VirtualFunction(329)] public partial uint GetContentTimeMax(); + /// Changes the state of a map effect. + /// Index into MapEffects. + /// The new state for this MapEffect. + /// Which timeline to play. + [MemberFunction("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 8B FA 41 0F B7 E8")] + public partial void ApplyMapEffect(uint index, ushort state, ushort timelineIndex); + + /// Handles changes the timeline for a map effect + /// Index into MapEffects. + /// Which timeline to play. + [MemberFunction("E8 ?? ?? ?? ?? 3A C3 74 ?? 44 0F B7 C5")] + public partial bool PlayMapEffectTimeline(uint index, ushort timelineIndex); + [GenerateInterop] [StructLayout(LayoutKind.Explicit, Size = 0x608)] public partial struct MapEffectList { @@ -45,7 +58,7 @@ public partial struct MapEffectList { [StructLayout(LayoutKind.Explicit, Size = 0xC)] public struct MapEffectItem { - [FieldOffset(0x00)] public uint LayoutId; // ContentDirectorManagedSG.Unknown0 + [FieldOffset(0x00)] public uint LayoutId; [FieldOffset(0x05)] public byte Unknown1; // ContentDirectorManagedSG.Unknown1 [FieldOffset(0x08)] public ushort State; [FieldOffset(0x0A)] public byte Flags; diff --git a/FFXIVClientStructs/FFXIV/Client/Game/Network/MapEffectPacket.cs b/FFXIVClientStructs/FFXIV/Client/Game/Network/MapEffectPacket.cs new file mode 100644 index 0000000000..445d3cea0a --- /dev/null +++ b/FFXIVClientStructs/FFXIV/Client/Game/Network/MapEffectPacket.cs @@ -0,0 +1,11 @@ +namespace FFXIVClientStructs.FFXIV.Client.Game.Network; + +[GenerateInterop] +[StructLayout(LayoutKind.Explicit, Size = 0x10)] +public partial struct MapEffectPacket { + [FieldOffset(0x00)] public uint EventId; + [FieldOffset(0x04)] public ushort State; + [FieldOffset(0x06)] public ushort TimelineIndex; + /// Which map effect this applies to. + [FieldOffset(0x08)] public byte Index; +} diff --git a/FFXIVClientStructs/FFXIV/Client/Game/Object/EventObject.cs b/FFXIVClientStructs/FFXIV/Client/Game/Object/EventObject.cs index 853becd45d..d7b035b668 100644 --- a/FFXIVClientStructs/FFXIV/Client/Game/Object/EventObject.cs +++ b/FFXIVClientStructs/FFXIV/Client/Game/Object/EventObject.cs @@ -1,3 +1,5 @@ +using EventHandler = FFXIVClientStructs.FFXIV.Client.Game.Event.EventHandler; + namespace FFXIVClientStructs.FFXIV.Client.Game.Object; // Client::Game::Object::EventObject @@ -5,12 +7,33 @@ namespace FFXIVClientStructs.FFXIV.Client.Game.Object; [GenerateInterop] [Inherits] [StructLayout(LayoutKind.Explicit, Size = 0x1C0)] -public partial struct EventObject { +public unsafe partial struct EventObject { [FieldOffset(0x1A0), CExporterExcel("EObj")] public nint EObjRowPtr; [FieldOffset(0x1A8), CExporterExcel("ExportedSG")] public nint ExportedSGRowPtr; [FieldOffset(0x1B2)] public ushort SharedTimelineState; // ActorControl category 0x199 (SetSharedTimelineState) sets this field [FieldOffset(0x1B8)] public byte Flags; + /// Changes the currently playing timelines based on a bitmask. + /// Only sets SharedTimelineState, does not have any other effect in this function. + /// Each bit represents a timeline index in the SharedGroup. Setting a bit means play, an unset bit means stop. + /// Unused, can be left as zero. + [MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 4D 85 F6 0F 84 ?? ?? ?? ?? 8B 44 24 70 BE ?? ?? ?? ??")] + public partial void PlayAnimation(uint sharedTimelineState, uint bitmask, ulong unknown); + /// Changes the currently playing timelines based on a bitmask. + /// The new SharedTimelineState value. + /// The new timeline bitmask. + [MemberFunction("48 89 5C 24 ?? 41 56 48 83 EC ?? 48 89 6C 24 ?? 44 0F B7 F2")] + public partial void UpdateTimelinesByBitmask(ushort sharedTimelineState, uint bitmask); + + /// Should point to array that can fit up to 32 pointers. + /// Num elements filled. [MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 4D 85 F6 0F 84 ?? ?? ?? ?? 8B 44 24 70 BE ?? ?? ?? ??")] - public partial void PlayAnimation(uint entityId, uint actionId, ulong unknown); + public partial int GetEventHandlers(EventHandler** outHandlers); + + /// Changes the currently playing timelines based on the difference between oldSharedTimelineState and newSharedTimelineState. + /// The new SharedTimelineState value. + /// If we should check if the layout is ready before continuing. + /// Unused and can be left empty. + [MemberFunction("E8 ?? ?? ?? ?? 49 8B 06 44 0F B6 C5")] + public partial void SetSharedTimelineState(ushort sharedTimelineState, bool checkIfLayoutReady, ulong unused); } diff --git a/FFXIVClientStructs/FFXIV/Client/Game/Object/GameObject.cs b/FFXIVClientStructs/FFXIV/Client/Game/Object/GameObject.cs index 03444ff933..1a7c9a37e2 100644 --- a/FFXIVClientStructs/FFXIV/Client/Game/Object/GameObject.cs +++ b/FFXIVClientStructs/FFXIV/Client/Game/Object/GameObject.cs @@ -124,6 +124,18 @@ public unsafe partial struct GameObject { [VirtualFunction(17)] public partial void SetDrawObject(DrawObject* drawObject); + /// Start playing this timeline. + [VirtualFunction(20)] + public partial bool PlayTimeline(uint index, uint a2); + + /// Stops this timeline's playback. + [VirtualFunction(21)] + public partial bool StopTimeline(uint index); + + /// Checks if this timeline is currently playing. + [VirtualFunction(22)] + public partial bool IsTimelinePlaying(uint index); + [VirtualFunction(23)] public partial DrawObject* GetDrawObject(); @@ -147,6 +159,12 @@ public unsafe partial struct GameObject { [VirtualFunction(48)] public partial uint GetNameId(); + /// Changes the currently playing timelines based on the difference between oldSharedTimelineState and newSharedTimelineState. + /// The old SharedTimelineState value. + /// The new SharedTimelineState value. + [VirtualFunction(49)] + public partial void UpdateSharedTimelineState(ushort oldSharedTimelineState, ushort newSharedTimelineState); + [VirtualFunction(54)] public partial TargetType GetTargetType(); @@ -253,6 +271,10 @@ public unsafe partial struct GameObject { [MemberFunction("E8 ?? ?? ?? ?? 48 85 FF 0F 84 ?? ?? ?? ?? F3 0F 10 97")] public partial Vector3* GetNamePlateWorldPosition(Vector3* vector); + /// If we have a SharedGroupLayoutInstance and it's loaded. + [MemberFunction("E8 ?? ?? ?? ?? 84 C0 74 ?? 33 FF 48 89 B4 24")] + public partial bool IsSharedGroupLoaded(); + [StructLayout(LayoutKind.Explicit, Size = 0x08)] public struct NamePlateColors { [FieldOffset(0x00), CExporterIgnore] public ulong Data; diff --git a/FFXIVClientStructs/FFXIV/Client/LayoutEngine/Group/SharedGroupLayoutInstance.cs b/FFXIVClientStructs/FFXIV/Client/LayoutEngine/Group/SharedGroupLayoutInstance.cs index 9589c845d1..135ab14c44 100644 --- a/FFXIVClientStructs/FFXIV/Client/LayoutEngine/Group/SharedGroupLayoutInstance.cs +++ b/FFXIVClientStructs/FFXIV/Client/LayoutEngine/Group/SharedGroupLayoutInstance.cs @@ -46,7 +46,11 @@ public unsafe partial struct SharedGroupLayoutInstance { [FieldOffset(0x120)] public uint PrefabFlags1; // 0x1 = load started; 0x3 = load failed or contents added; 0x4 = failed to add contents [FieldOffset(0x12C)] public uint PrefabFlags2; // 0x8 = colliders active - // [FieldOffset(0x14C), FixedSizeArray] internal FixedSizeArray16 _timelineIndices; // used by EventObjAnimation ActorControl packet, some kind of simple lookup table + /// Used by EventObjAnimation ActorControl packet, it's some kind of simple lookup table. + [FieldOffset(0x154), FixedSizeArray] internal FixedSizeArray16 _timelineIndices; + + /// Set in PlayAnimation, it's an index into TimelineIndices. + [FieldOffset(0x16D)] public byte PlayingTimelineIndex; [MemberFunction("E8 ?? ?? ?? ?? 41 FF C7 4D 8D 76 ?? 44 3B 7B")] public partial bool InitAnimationHandlers(void* fileData); @@ -71,6 +75,27 @@ public unsafe partial struct SharedGroupLayoutInstance { [MemberFunction("33 C0 81 F9 ?? ?? ?? ?? 0F 42 C1")] public static partial ByteColor* GetObjectStainColorByIndex(byte stainIndex); + /// Checks if this timeline is currently playing. + /// Stops this timeline's playback. + [MemberFunction("E8 ?? ?? ?? ?? 85 EF 74 ?? 84 C0")] + public partial bool IsTimelinePlaying(uint index); + + /// Stops this timeline's playback. + /// Index into TimelineIndices. + [MemberFunction("E8 ?? ?? ?? ?? EB ?? 41 80 F9")] + public partial bool StopTimeline(uint index); + + /// Start playing this timeline. + /// Index into TimelineIndices. + /// + [MemberFunction("E8 ?? ?? ?? ?? 0F B6 B6")] + public partial bool PlayTimeline(uint index, uint a1); + + /// Checks if the timeline index is in range, and actually backed by something. + /// Index into TimelineIndices. + [MemberFunction("E8 ?? ?? ?? ?? 84 C0 74 ?? 3B FD")] + public partial bool IsTimelineIndexValid(uint index); + /// /// Attempts to set the stain on the models in this group. /// diff --git a/FFXIVClientStructs/FFXIV/Client/LayoutEngine/ILayoutInstance.cs b/FFXIVClientStructs/FFXIV/Client/LayoutEngine/ILayoutInstance.cs index 7c5bbf9117..6cc78071be 100644 --- a/FFXIVClientStructs/FFXIV/Client/LayoutEngine/ILayoutInstance.cs +++ b/FFXIVClientStructs/FFXIV/Client/LayoutEngine/ILayoutInstance.cs @@ -69,6 +69,10 @@ public unsafe partial struct Identifier { [VirtualFunction(21)] public partial bool HavePrimary(); + /// If the primary object has been loaded. + [VirtualFunction(21)] + public partial bool IsPrimaryLoaded(); + [VirtualFunction(23)] public partial Graphics.Scene.Object* GetGraphics(); @@ -151,6 +155,10 @@ public unsafe partial struct Identifier { [VirtualFunction(72)] public partial Vector4* GetBoundingSphereImpl(Vector4* result); + /// If we have a primary object and its been loaded. Basically HavePrimary() and IsPrimaryLoaded() in one call. + [MemberFunction("E8 ?? ?? ?? ?? 3C ?? 75 ?? 8B D5")] + public partial bool IsPrimaryReady(); + // vf73: getWorldBB, uses AABB with padded vec3's // vf74: get transform split into RT matrix + scale diff --git a/FFXIVClientStructs/FFXIV/Client/Network/PacketDispatcher.cs b/FFXIVClientStructs/FFXIV/Client/Network/PacketDispatcher.cs index 60e577b6d1..f0782d17b6 100644 --- a/FFXIVClientStructs/FFXIV/Client/Network/PacketDispatcher.cs +++ b/FFXIVClientStructs/FFXIV/Client/Network/PacketDispatcher.cs @@ -93,6 +93,9 @@ public static partial void HandleActorControlPacket( [MemberFunction("40 53 57 48 81 EC ?? ?? ?? ?? 48 8B FA 8B")] public static partial void HandleActorCastPacket(uint entityId, ActorCastPacket* packet); + [MemberFunction("E8 ?? ?? ?? ?? B0 ?? 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 ?? 5F C3 0F B6 7B")] + public static partial void HandleMapEffectPacket(MapEffectPacket* packet); + [VirtualFunction(1)] public partial void OnReceivePacket(uint targetId, nint packet); } diff --git a/ida/data.yml b/ida/data.yml index 1d68a8df71..66c9ada98a 100644 --- a/ida/data.yml +++ b/ida/data.yml @@ -9636,6 +9636,7 @@ classes: 17: GetTransform 18: SetTransform 21: HavePrimary + 22: IsPrimaryLoaded 23: GetGraphics 24: GetGraphics2 25: SetGraphics @@ -9663,6 +9664,8 @@ classes: 70: GetTransformImpl 71: SetTransformImpl 72: GetBoundingSphereImpl + funcs: + 0x1406FA0E0: IsPrimaryReady Client::LayoutEngine::LayoutWorld: instances: - ea: 0x142A8BB60 @@ -9870,6 +9873,10 @@ classes: 0x1407077C0: InitAnimationHandlers 0x1407071A0: InitTimelines 0x1406FE9F0: ReapplyStain + 0x1407065C0: IsTimelineIndexValid + 0x140706420: PlayTimeline + 0x140706520: StopTimeline + 0x1407065F0: IsTimelinePlaying 0x1407985B0: GetObjectStainColorByIndex # static Client::LayoutEngine::Layer::TreasureLayoutInstance: vtbls: @@ -11606,16 +11613,19 @@ classes: 15: SetTargetStatus 16: SetDistance 17: SetDrawObject + 20: PlayTimeline + 21: StopTimeline + 22: IsTimelinePlaying 23: GetDrawObject 24: GetCharacterBase 25: UpdateRadius 26: Highlight - #30: TryGetEventHandler 30: GetEventHandlersImpl 34: SetReadyToDraw 36: Update 47: GetCenterPosition 48: GetNameId + 49: UpdateSharedTimelineState 54: GetTargetType 55: PositionModified 56: RotationModified @@ -11641,6 +11651,7 @@ classes: 0x1408985D0: UpdateVisualRotation 0x140898780: UpdateVisualScale 0x140898AB0: GetEventHandlers + 0x1408991E0: IsSharedGroupLoaded 0x140899230: IsReadyToDraw 0x140899B70: SetEventId 0x140899BE0: SetFateId @@ -16034,6 +16045,8 @@ classes: 232: GetOccupiedConditionId 233: GetOccupiedPermissionId 251: GetScriptVersion + 253: UpdateSharedTimelineState + 254: UpdateTimelinesByBitmask 258: GetDescription 259: GetReliefText 260: GetTimeRemaining # pass current unix timestamp as a2 @@ -17990,6 +18003,7 @@ classes: funcs: 0x140B6D8A0: ctor 0x140B6F470: ApplyMapEffect + 0x140B6F2E0: PlayMapEffectTimeline 0x140B703F0: IsPlayCutscene Client::Game::InstanceContent::InstanceContentDirector: vtbls: @@ -26219,7 +26233,10 @@ classes: - ea: 0x1422C4DB0 base: Client::Game::Object::GameObject funcs: + 0x140898A40: GetEventHandlers + 0x14174DCC0: SetSharedTimelineState 0x14174DE10: PlayAnimation + 0x14174DF40: UpdateTimelinesByBitmask Client::Game::Object::Treasure: vtbls: - ea: 0x1422C5020