Skip to content

Commit 155f47d

Browse files
authored
Reduce the amount of sliding NPCs by caching and replaying animations (#811)
* Greatly reduce the amount of sliding NPCs by caching and replaying animations Having a single `LatestAction` wasn't enough to bring Actors into a correct animation state. Now non-cell-owners (aka party members) will replay recently run animations when an Actor is being set up in their world * No need for start actions, also removed `g_actionsSkipIntermediate` and related code * Replace actions with instant counterparts when possible * Simplify `ActionsToReplay` serialization in AssignCharacterResponse and CharacterSpawnRequest `ApplyDifferential` doesn't work like I expected, and on top of that it doesn't cut that much bytes. We should be fine * Add ability to replay actions manually in ComponentDebugView * Small AnimationEventLists reorganization and renames * Delay actions queued for replay if the first one is `IdleForceDefaultState` (temporary solution) * Replace `IdleForceDefaultState` plus a delay with a proper solution (call to `RevertAnimationGraphManager`) * Remove redundant check in `ActorMediator::ForceAction` Since we now check for readiness in `AnimationSystem::Update` * More AnimationEventLists actions, remove some Exits, clean up * Move call to `RefineReplayCache` to the right place; drop useless exit action * Introduce `EarlyAnimationBufferComponent` to improve animation sync on cell enter Particularly, when a party member enters the cell first, before the leader. Note that this commit also reverts af0561f (PR #762) as storing `LatestWeapEquipAnimation` is no longer necessary * Add more actions to AnimationEventLists * Address review comments: String -> std::string_view, and other misc and naming fixes
1 parent 4f552c5 commit 155f47d

27 files changed

+614
-37
lines changed

Code/client/Components.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include <Components/LocalAnimationComponent.h>
77
#include <Components/RemoteAnimationComponent.h>
8+
#include <Components/EarlyAnimationBufferComponent.h>
9+
#include <Components/ReplayedActionsDebugComponent.h>
810
#include <Components/FormIdComponent.h>
911
#include <Components/InterpolationComponent.h>
1012
#include <Components/WaitingForAssignmentComponent.h>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
3+
#ifndef TP_INTERNAL_COMPONENTS_GUARD
4+
#error Include Components.h instead
5+
#endif
6+
7+
#include <Structs/ActionEvent.h>
8+
9+
/**
10+
* @brief `LocalAnimationComponent` is typically added several frames after the Actor
11+
* has been spawned, causing some of the earliest actions to be missed and not sent
12+
* over the network. `EarlyAnimationBufferComponent` takes care of this.
13+
*/
14+
struct EarlyAnimationBufferComponent
15+
{
16+
Vector<ActionEvent> Actions{};
17+
};

Code/client/Components/RemoteAnimationComponent.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ struct RemoteAnimationComponent
99
List<ActionEvent> TimePoints;
1010
ActionEvent LastRanAction;
1111
ActionEvent LastProcessedAction;
12+
uint32_t ReplayCount;
13+
bool ResetAnimationGraphForReplay{false};
1214
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
3+
#ifndef TP_INTERNAL_COMPONENTS_GUARD
4+
#error Include Components.h instead
5+
#endif
6+
7+
#include <Structs/ActionReplayChain.h>
8+
9+
/**
10+
* @brief Used for in-game animation debugging purposes. Makes it easier
11+
* to see which actions were replayed on a particular Actor.
12+
*
13+
* @see ComponentView
14+
*/
15+
struct ReplayedActionsDebugComponent
16+
{
17+
ActionReplayChain ActionsReceivedForReplay;
18+
};

Code/client/Games/ActorExtension.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ struct ActorExtension
1919
void SetPlayer(bool aSet) noexcept;
2020

2121
ActionEvent LatestAnimation{};
22-
ActionEvent LatestWeapEquipAnimation{};
2322
size_t GraphDescriptorHash = 0;
2423

2524
private:

Code/client/Games/Animation.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ uint8_t TP_MAKE_THISCALL(HookPerformAction, ActorMediator, TESActionData* apActi
5454
if (res)
5555
{
5656
pExtension->LatestAnimation = action;
57-
58-
if(apAction->action->formID == 0x132AF)
59-
pExtension->LatestWeapEquipAnimation = action;
6057
}
6158

6259
World::Get().GetRunner().Trigger(action);
@@ -117,7 +114,7 @@ bool ActorMediator::ForceAction(TESActionData* apAction) noexcept
117114
uint8_t result = 0;
118115

119116
auto pActor = static_cast<Actor*>(apAction->actor);
120-
if (!pActor || pActor->animationGraphHolder.IsReady())
117+
if (pActor)
121118
{
122119
result = TiltedPhoques::ThisCall(PerformComplexAction, this, apAction);
123120

Code/client/Games/Animation/IAnimationGraphManagerHolder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ struct IAnimationGraphManagerHolder
2929
virtual bool GetVariableBool(BSFixedString* apVariable, bool* apReturn);
3030

3131
bool SetVariableFloat(BSFixedString* apVariable, float aValue);
32+
bool SetVariableInt(BSFixedString* apVariable, int32_t aValue);
33+
bool SetVariableBool(BSFixedString* apVariable, bool aValue);
3234
bool IsReady();
35+
bool RevertAnimationGraphManager();
3336

3437
bool ReSendAnimationEvent(BSFixedString* apAnimEvent);
3538
};

Code/client/Games/IAnimationGraphManagerHolder.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,30 @@ bool IAnimationGraphManagerHolder::SetVariableFloat(BSFixedString* apVariable, f
1212
return TiltedPhoques::ThisCall(InternalSetFloatVariable, this, apVariable, aValue);
1313
}
1414

15+
bool IAnimationGraphManagerHolder::SetVariableInt(BSFixedString* apVariable, int32_t aValue)
16+
{
17+
TP_THIS_FUNCTION(TSetIntVariable, bool, IAnimationGraphManagerHolder, BSFixedString*, int32_t);
18+
POINTER_SKYRIMSE(TSetIntVariable, InternalSetIntVariable, 32886);
19+
20+
return TiltedPhoques::ThisCall(InternalSetIntVariable, this, apVariable, aValue);
21+
}
22+
23+
bool IAnimationGraphManagerHolder::SetVariableBool(BSFixedString* apVariable, bool aValue)
24+
{
25+
TP_THIS_FUNCTION(TSetBoolVariable, bool, IAnimationGraphManagerHolder, BSFixedString*, bool);
26+
POINTER_SKYRIMSE(TSetBoolVariable, InternalSetBoolVariable, 32885);
27+
28+
return TiltedPhoques::ThisCall(InternalSetBoolVariable, this, apVariable, aValue);
29+
}
30+
31+
bool IAnimationGraphManagerHolder::RevertAnimationGraphManager()
32+
{
33+
TP_THIS_FUNCTION(TRevertAnimationGraphManager, bool, IAnimationGraphManagerHolder);
34+
POINTER_SKYRIMSE(TRevertAnimationGraphManager, InternalRevertAnimationGraphManager, 32883);
35+
36+
return TiltedPhoques::ThisCall(InternalRevertAnimationGraphManager, this);
37+
}
38+
1539
bool IAnimationGraphManagerHolder::IsReady()
1640
{
1741
BSAnimationGraphManager* pAnimationGraph = nullptr;

Code/client/Services/Debug/DebugService.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include <AI/AIProcess.h>
4545

4646
#include <Messages/RequestRespawn.h>
47+
#include <Messages/PartyCreateRequest.h>
48+
#include <Messages/PartyLeaveRequest.h>
4749

4850
#include <Games/Misc/SubtitleManager.h>
4951
#include <Games/Overrides.h>
@@ -189,7 +191,10 @@ void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
189191
{
190192
s_f7Pressed = true;
191193

192-
//
194+
if (!m_world.GetPartyService().IsInParty())
195+
m_transport.Send(PartyCreateRequest{});
196+
else
197+
m_transport.Send(PartyLeaveRequest{});
193198
}
194199
}
195200
else

Code/client/Services/Debug/Views/AnimDebugView.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#include <imgui.h>
32
#include <EquipManager.h>
43
#include <services/DebugService.h>
@@ -133,6 +132,12 @@ void DebugService::DrawAnimDebugView()
133132
s_cachedKeys[hash] = pActor->formID;
134133
}
135134

135+
if (ImGui::Button("Revert animation graph"))
136+
{
137+
spdlog::info("RevertAnimationGraphManager success? {}",
138+
pActor->animationGraphHolder.RevertAnimationGraphManager());
139+
}
140+
136141
if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
137142
{
138143
if (ImGui::BeginTabItem("Variables"))

0 commit comments

Comments
 (0)