Skip to content

OAR cannot replace paired-idle clips when they are triggered directly via animation events without synchronized clip setup #20

Description

@Acook1e

Sorry, I'm not good at English and I ask AI to help me wrote this issue.

Hi, I’m running into a limitation with OAR when trying to replace paired animations that are triggered directly by animation events, without going through the normal synchronized clip pipeline.

Summary
OAR seems able to handle normal clip replacement and synchronized/paired flows that go through the game’s synchronized clip system, but in my use case I am not using the Havok synchronized clip path.

Instead, I manually:

position/rotate both actors,
set some graph variables,
then call NotifyAnimationGraph(...) on each actor separately,
where each actor enters one side of a paired idle / paired animation.
In this situation, OAR does not replace the animation, even though the graph event successfully triggers the clip.

What I am doing
I have a custom execution system.
The key part is that I directly trigger the paired animation events on both actors:

if (!aggressor->NotifyAnimationGraph(aggressorAnimEvent) ||
!victim->NotifyAnimationGraph(victimAnimEvent)) {
logger::warn("Execution::TryExecute: Failed to send animation event. Aggressor: {}, Victim: {}",
aggressor->GetDisplayFullName(), victim->GetDisplayFullName());
UnlockActor(victim);
return false;

This does not use the synchronized clip / synchronized scene pipeline.
It only triggers one side of a paired idle on each actor through graph events.

For example, for human front execution I use events like:

aggressor: pa_KillMove
victim: KillMove
and for backstab:

aggressor: pa_KillMove1HMBackStab
victim: KillMove1HMBackStab
The actual paired animation hkx files are things like:

Animations\Paired_1HMKillMove.hkx
Animations\Paired_1HMKillMoveBackStab.hkx
Expected behavior
I expected OAR to still be able to replace these clips, because from the user/mod author perspective, the clip is still being activated through the behavior graph and eventually reaches a playable clip.

Even if this is not treated as a “true synchronized animation” internally, I expected OAR to at least be able to replace the underlying activated clip based on the event-triggered animation path / binding.

Actual behavior
The events are accepted.
The animation plays.
But OAR does not replace the animation in this direct-event paired-idle case.
Important detail
This is not a regular synced killmove / synchronized scene setup.
I am deliberately bypassing Havok sync and manually synchronizing:

actor positions
headings
execution state
damage timing
So this is effectively:

two actors
each receives one event
each enters one side of a paired animation
but no BSSynchronizedClipGenerator / BGSSynchronizedAnimationInstance path is used
My suspicion
From reading the code, it looks like OAR’s paired/synchronized replacement logic depends on the synchronized clip pipeline, especially around:

BSSynchronizedClipGenerator
BGSSynchronizedAnimationInstance
synchronized clip binding/index handling
If the paired animation is entered only as a normal event-driven clip and never becomes a synchronized clip object, then OAR may only see it as a regular hkbClipGenerator activation without enough context to treat it as a replaceable paired animation.

Question
Is this current behavior expected?

And if so, would it be possible to support one of the following in the future?

Allow replacement of event-triggered paired-idle clips even when they do not go through the synchronized clip system
Or expose/document what conditions are required for OAR to recognize and replace this kind of clip
Or provide a hook point / API hint for mods that manually trigger both sides of a paired animation without Havok sync
Minimal reproduction idea
Create a paired-idle style setup
Do not use synchronized clips / synchronized scene
Manually align two actors
Call NotifyAnimationGraph("pa_KillMove") on actor A
Call NotifyAnimationGraph("KillMove") on actor B
Let OAR try to replace the resulting animation
Observe that replacement does not happen
Additional context
I am using graph variables to indicate execution state before sending the events, so OAR has time to evaluate conditions, but the replacement still does not occur.

If needed, I can provide a smaller test project or a more focused repro.

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions