Optimize rollback sync-test performance (#86)
## Summary - remove immutable stage geometry and derived animation/collision data from rollback snapshots - avoid a duplicate full skeletal hierarchy traversal during root-motion sampling - cache root-motion cycle deltas per animation clip - optimize the game crate in development builds - make Tracy profiling opt-in via the `tracy` feature Reviewed-on: #86 Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #86.
This commit is contained in:
@@ -127,6 +127,8 @@ pub struct FighterBoneMatrices {
|
||||
/// pose has the root translation removed.
|
||||
previous_root_motion_translation: Option<FGVec3>,
|
||||
root_motion_delta: crate::math::vec3::FGVec3,
|
||||
cached_root_motion_kind: Option<AnimKind>,
|
||||
cached_root_motion_cycle_delta: FGVec3,
|
||||
}
|
||||
|
||||
#[derive(Component, Clone, Debug, Default)]
|
||||
@@ -366,12 +368,6 @@ impl FighterBoneMatrices {
|
||||
.expect("configured root motion bone should exist"),
|
||||
)
|
||||
};
|
||||
self.model_matrices.resize(local.len(), None);
|
||||
self.model_matrices.fill(None);
|
||||
for index in 0..local.len() {
|
||||
resolve_model_transform(index, parents, local, &mut self.model_matrices)
|
||||
.expect("baked bone hierarchy should be valid");
|
||||
}
|
||||
let model_scale = FixedMat4 {
|
||||
cols: [
|
||||
[model_scale, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||
@@ -380,13 +376,16 @@ impl FighterBoneMatrices {
|
||||
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||
],
|
||||
};
|
||||
// Root motion only needs the configured bone's model transform. Resolve
|
||||
// that ancestry first, then do the normal full-pose pass once below.
|
||||
// Previously the complete hierarchy was resolved once before removing
|
||||
// root translation and once afterwards.
|
||||
let raw_root_motion_translation = root_index.map(|root_index| {
|
||||
model_scale
|
||||
.mul(
|
||||
self.model_matrices[root_index]
|
||||
.expect("baked bone hierarchy should be valid"),
|
||||
)
|
||||
.get_translation()
|
||||
self.model_matrices.resize(local.len(), None);
|
||||
self.model_matrices.fill(None);
|
||||
let root = resolve_model_transform(root_index, parents, local, &mut self.model_matrices)
|
||||
.expect("baked bone hierarchy should be valid");
|
||||
model_scale.mul(root).get_translation()
|
||||
});
|
||||
|
||||
// Gameplay owns the root's displacement. Keep rotation and scale in
|
||||
@@ -394,11 +393,12 @@ impl FighterBoneMatrices {
|
||||
// used by visuals and gameplay volumes.
|
||||
if let Some(root_index) = root_index {
|
||||
self.local_matrices[root_index].translate(FGVec3::ZERO);
|
||||
self.model_matrices.fill(None);
|
||||
for index in 0..local.len() {
|
||||
resolve_model_transform(index, parents, &self.local_matrices, &mut self.model_matrices)
|
||||
.expect("baked bone hierarchy should be valid");
|
||||
}
|
||||
}
|
||||
self.model_matrices.resize(local.len(), None);
|
||||
self.model_matrices.fill(None);
|
||||
for index in 0..local.len() {
|
||||
resolve_model_transform(index, parents, &self.local_matrices, &mut self.model_matrices)
|
||||
.expect("baked bone hierarchy should be valid");
|
||||
}
|
||||
self.matrices.clear();
|
||||
self.matrices.extend(
|
||||
@@ -517,9 +517,16 @@ fn sample_fighter_bone_matrices(
|
||||
let manifest = manifests
|
||||
.get(&fighter.manifest)
|
||||
.expect("fighter manifest should be loaded before the match starts");
|
||||
let root_motion_cycle_delta = baked
|
||||
.root_motion_cycle_delta(frame.kind, &manifest.root_motion_bone, manifest.model_scale)
|
||||
.unwrap_or(FGVec3::ZERO);
|
||||
let root_motion_cycle_delta = if matrices.cached_root_motion_kind == Some(frame.kind) {
|
||||
matrices.cached_root_motion_cycle_delta
|
||||
} else {
|
||||
let delta = baked
|
||||
.root_motion_cycle_delta(frame.kind, &manifest.root_motion_bone, manifest.model_scale)
|
||||
.unwrap_or(FGVec3::ZERO);
|
||||
matrices.cached_root_motion_kind = Some(frame.kind);
|
||||
matrices.cached_root_motion_cycle_delta = delta;
|
||||
delta
|
||||
};
|
||||
let root_motion_loop_frame_count = baked
|
||||
.frame_count(frame.kind)
|
||||
.map(|count| count.saturating_sub(1).max(1));
|
||||
|
||||
+2
-6
@@ -42,8 +42,8 @@ use crate::{
|
||||
AttackKind, FighterAttackPlugin, FighterAttackScriptAssets, FighterDamage,
|
||||
FighterKnockbackVelocity, FighterPendingHitReaction, FighterSolvedHurtboxes,
|
||||
FighterStaleMoveQueue,
|
||||
}, baked_animation::{FighterBoneIndexMap, FighterBoneMatrices}, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::{FighterAnimations, FighterInvulnerabilityVisualState},
|
||||
}, game_settings::GameSettings, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript, stage::line::StageCollision,
|
||||
}, baked_animation::FighterBoneIndexMap, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::{FighterAnimations, FighterInvulnerabilityVisualState},
|
||||
}, game_settings::GameSettings, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript,
|
||||
};
|
||||
use state::state_interrupt_system;
|
||||
|
||||
@@ -250,7 +250,6 @@ impl Plugin for FighterPlugin {
|
||||
.checksum_component_with_hash::<FighterInvulnerabilityState>()
|
||||
.rollback_component_with_copy::<FighterKnockbackVelocity>()
|
||||
.checksum_component_with_hash::<FighterKnockbackVelocity>()
|
||||
.rollback_resource_with_reflect::<StageCollision>()
|
||||
// Debug views.
|
||||
.add_systems(
|
||||
FixedPostUpdate,
|
||||
@@ -284,11 +283,8 @@ impl Plugin for FighterPlugin {
|
||||
)
|
||||
.rollback_component_with_clone::<FighterState>()
|
||||
.rollback_component_with_clone::<FighterHitboxes>()
|
||||
.rollback_component_with_clone::<FighterBoneMatrices>()
|
||||
.rollback_component_with_clone::<FighterHitstopShake>()
|
||||
.checksum_component_with_hash::<FighterHitboxes>()
|
||||
.rollback_component_with_clone::<FighterSolvedHurtboxes>()
|
||||
.checksum_component_with_hash::<FighterSolvedHurtboxes>()
|
||||
.checksum_component_with_hash::<FighterState>()
|
||||
.checksum_component_with_hash::<FighterFacingDirection>()
|
||||
.register_type::<FighterFacingDirection>();
|
||||
|
||||
Reference in New Issue
Block a user