Skip to content

Event Object animations!!#1877

Merged
Haselnussbomber merged 7 commits into
aers:mainfrom
redstrate:work/redstrate/eobj-animation-woot
Jul 14, 2026
Merged

Event Object animations!!#1877
Haselnussbomber merged 7 commits into
aers:mainfrom
redstrate:work/redstrate/eobj-animation-woot

Conversation

@redstrate

Copy link
Copy Markdown
Contributor

This whole system has been confusing me for a while, so I started documenting the functions I found in the disassembly the best I could. Now I have... this - which is adding a bunch of random crap so methods like EventObject.PlayAnimation can look like this 😍

void Client::Game::Object::EventObject.PlayAnimation
               (EventObject *this,uint sharedTimelineState,uint bitmask,ulonglong unknown)

{
  byte *pbVar1;
  char cVar2;
  int numEventHandlers;
  uint uVar3;
  uint index;
  undefined1 auStackY_168 [32];
  EventHandler *eventHandlers [32];
  ulonglong local_38;
  
  local_38 = g_StackCookie ^ (ulonglong)auStackY_168;
  numEventHandlers = Client::Game::Object::EventObject.GetEventHandlers(this,eventHandlers);
  if (numEventHandlers == 0) {
    cVar2 = Client::Game::Object::GameObject.IsSharedGroupLoaded((GameObject *)this);
    if (cVar2 != '\0') {
      index = 0;
      uVar3 = 1;
      do {
        cVar2 = (*((this->Union).VTable)->IsTimelinePlaying)((GameObject *)this,index);
        if ((uVar3 & bitmask & 0xffff) == 0) {
          if (cVar2 == '\x01') {
            (*((this->Union).VTable)->StopTimeline)((GameObject *)this,index);
          }
        }
        else if (cVar2 == '\0') {
          (*((this->Union).VTable)->PlayTimeline)((GameObject *)this,index,0);
        }
        index = index + 1;
        uVar3 = uVar3 << 1 | (uint)((int)uVar3 < 0);
      } while (index < 0x10);
    }
    if (this->SharedTimelineState != (ushort)sharedTimelineState) {
      this->SharedTimelineState = (ushort)sharedTimelineState;
    }
  }
  else {
    (*eventHandlers[0]->VTable->UpdateTimelinesByBitmask)
              (eventHandlers[0],(GameObject *)this,sharedTimelineState & 0xffff,bitmask & 0xffff,
               unknown);
  }
  cVar2 = Client::Game::Object::GameObject.IsSharedGroupLoaded((GameObject *)this);
  if (cVar2 == '\0') {
    pbVar1 = (byte *)((longlong)&this->Union + 0x9b);
    *pbVar1 = *pbVar1 | 8;
    this->Flags = 0;
  }
  return;
}

This PR looks bigger than it really is, SharedGroupLayoutInstance and EventObject duplicate a bunch of API surface and then also through EventHandler. I almost certainly made a mistake somewhere because they can't decide whether indices are shorts or ints, and there's a billion functions with the word Timeline in them. I tried to break up the commits so someone could be pulled though.

Thanks to #1851 for figuring out that this is a bitmask, I took some of their documentation.

@redstrate

redstrate commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

Also something I left out was touching SpawnObjectPacket, that should be updated but it's at least pretty clear now what that unknown is (for eobjs):

...
      Client::Game::Object::GameObject.SetFateId(this,packet->FateId);
      pbVar1 = (byte *)((longlong)&this->Union + 0x9c);
      *pbVar1 = *pbVar1 ^ (packet->TargetableStatus << 3 ^ *(byte *)((longlong)&this->Union + 0x9c))
                          & 0x20;
      Client::Game::Object::EventObject.SetSharedTimelineState(this,(ushort)packet->Unk2C,'\x01',0);
      *(uint *)&this->field_0x1b4 = packet->Unk30;
      if (packet->GimmickId == 0) {
...

(I plan on updating that packet in another PR or someone else can do it :-))

@Haselnussbomber Haselnussbomber left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice if you could fix those xmldoc warnings.

Comment thread FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs Outdated
Comment thread FFXIVClientStructs/FFXIV/Client/Game/Network/MapEffectPacket.cs Outdated
Comment thread FFXIVClientStructs/FFXIV/Client/Game/Object/EventObject.cs Outdated
Comment thread FFXIVClientStructs/FFXIV/Client/Game/Object/EventObject.cs Outdated
Comment thread FFXIVClientStructs/FFXIV/Client/Game/Object/GameObject.cs Outdated
Comment thread FFXIVClientStructs/FFXIV/Client/LayoutEngine/Group/SharedGroupLayoutInstance.cs Outdated
Comment thread FFXIVClientStructs/FFXIV/Client/LayoutEngine/Group/SharedGroupLayoutInstance.cs Outdated
There's no reason to refer to this old column anymore,
it's been renamed in EXDSchema for a while.
Some small functions used for checking if the primary draw object is
ready and what not. Is used heavily in EObj animation code!
This has been replaced by GetEventHandlersImpl.
This is used in EObj animation code, and pretty much just proxies what
the GameObject function does.
This adds a variety of functions used for managing event obj animations,
centered around making the disassembly much more readable. It looks
bigger than it is, because it's spread across a few different systems.
I'm not 100% certain about map effects in general, but this is connected
to figuring out how SGB animations work in more detail.
@redstrate
redstrate force-pushed the work/redstrate/eobj-animation-woot branch from aa1dcb6 to 9453fd6 Compare July 14, 2026 02:56
@Haselnussbomber
Haselnussbomber merged commit d2e8e04 into aers:main Jul 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants