1pub mod cache;
2pub mod load;
3mod volume;
4
5pub(super) use cache::FigureModelCache;
6use common_net::synced_components::Heads;
7pub use load::load_mesh; pub use volume::VolumeKey;
9
10use crate::{
11 ecs::comp::Interpolated,
12 render::{
13 AltIndices, CullingMode, FigureBoneData, FigureDrawer, FigureLocals, FigureModel,
14 FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer, SpriteDrawer,
15 SpriteInstance, SubModel, TerrainVertex,
16 pipelines::{
17 self, AtlasData, AtlasTextures, FigureSpriteAtlasData,
18 terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
19 trail,
20 },
21 },
22 scene::{
23 RAIN_THRESHOLD, SceneData, TrailMgr,
24 camera::{Camera, CameraMode, Dependents},
25 math,
26 terrain::Terrain,
27 },
28};
29#[cfg(feature = "plugins")]
30use anim::plugin::PluginSkeleton;
31use anim::{
32 Animation, Skeleton, arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton,
33 biped_small::BipedSmallSkeleton, bird_large::BirdLargeSkeleton,
34 bird_medium::BirdMediumSkeleton, character::CharacterSkeleton, crustacean::CrustaceanSkeleton,
35 dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, fish_small::FishSmallSkeleton,
36 golem::GolemSkeleton, item::ItemSkeleton, object::ObjectSkeleton,
37 quadruped_low::QuadrupedLowSkeleton, quadruped_medium::QuadrupedMediumSkeleton,
38 quadruped_small::QuadrupedSmallSkeleton, ship::ShipSkeleton, theropod::TheropodSkeleton,
39};
40use common::{
41 comp::{
42 Body, CharacterActivity, CharacterState, Collider, Controller, Health, Inventory, ItemKey,
43 Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PickupItem, PoiseState, Pos,
44 Scale, ThrownItem, Vel,
45 body::{self, parts::HeadState},
46 inventory::slot::EquipSlot,
47 item::{Hands, ItemKind, ToolKind, armor::ArmorKind},
48 ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST},
49 slot::ArmorSlot,
50 },
51 interaction::InteractionKind,
52 link::Is,
53 mounting::{Mount, Rider, Volume, VolumeRider, VolumeRiders},
54 resources::{DeltaTime, Time},
55 slowjob::SlowJobPool,
56 states::{equipping, idle, interact, utils::StageSection, wielding},
57 terrain::{SpriteKind, TerrainChunk, TerrainGrid},
58 uid::IdMaps,
59 util::Dir,
60 vol::RectRasterableVol,
61};
62use common_base::span;
63use common_state::State;
64use core::{
65 borrow::Borrow,
66 convert::TryFrom,
67 hash::Hash,
68 ops::{Deref, DerefMut, Range},
69};
70use guillotiere::AtlasAllocator;
71use hashbrown::HashMap;
72use specs::{
73 Entities, Entity as EcsEntity, Join, LazyUpdate, LendJoin, ReadExpect, ReadStorage, SystemData,
74 WorldExt, shred,
75};
76use std::sync::Arc;
77use treeculler::{BVol, BoundingSphere};
78use vek::*;
79
80use super::terrain::{BlocksOfInterest, SPRITE_LOD_LEVELS};
81
82const DAMAGE_FADE_COEFFICIENT: f64 = 15.0;
83const MOVING_THRESHOLD: f32 = 0.2;
84const MOVING_THRESHOLD_SQR: f32 = MOVING_THRESHOLD * MOVING_THRESHOLD;
85
86pub type CameraData<'a> = (&'a Camera, f32);
88
89pub type FigureModelRef<'a> = (
91 &'a pipelines::figure::BoundLocals,
92 SubModel<'a, TerrainVertex>,
93 &'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
94);
95
96pub trait ModelEntry {
97 fn allocation(&self) -> &guillotiere::Allocation;
98
99 fn lod_model(&self, lod: usize) -> Option<SubModel<TerrainVertex>>;
100
101 fn atlas_textures(&self) -> &AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>;
102}
103
104pub struct FigureModelEntry<const N: usize> {
107 _bounds: math::Aabb<f32>,
110 allocation: guillotiere::Allocation,
114 atlas_textures: AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
118 lod_vertex_ranges: [Range<u32>; N],
121 model: FigureModel,
122}
123
124impl<const N: usize> ModelEntry for FigureModelEntry<N> {
125 fn allocation(&self) -> &guillotiere::Allocation { &self.allocation }
126
127 fn lod_model(&self, lod: usize) -> Option<SubModel<TerrainVertex>> {
128 self.model
130 .opaque
131 .as_ref()
132 .map(|m| m.submodel(self.lod_vertex_ranges[lod].clone()))
133 }
134
135 fn atlas_textures(&self) -> &AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
136 &self.atlas_textures
137 }
138}
139
140pub struct TerrainModelEntry<const N: usize> {
143 _bounds: math::Aabb<f32>,
146 allocation: guillotiere::Allocation,
150 atlas_textures: AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
154 lod_vertex_ranges: [Range<u32>; N],
157 model: FigureModel,
158
159 blocks_offset: Vec3<f32>,
160
161 sprite_instances: [Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
162
163 blocks_of_interest: BlocksOfInterest,
164}
165
166impl<const N: usize> ModelEntry for TerrainModelEntry<N> {
167 fn allocation(&self) -> &guillotiere::Allocation { &self.allocation }
168
169 fn lod_model(&self, lod: usize) -> Option<SubModel<TerrainVertex>> {
170 self.model
172 .opaque
173 .as_ref()
174 .map(|m| m.submodel(self.lod_vertex_ranges[lod].clone()))
175 }
176
177 fn atlas_textures(&self) -> &AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
178 &self.atlas_textures
179 }
180}
181
182#[derive(Clone, Copy)]
183pub enum ModelEntryRef<'a, const N: usize> {
184 Figure(&'a FigureModelEntry<N>),
185 Terrain(&'a TerrainModelEntry<N>),
186}
187
188impl<'a, const N: usize> ModelEntryRef<'a, N> {
189 fn lod_model(&self, lod: usize) -> Option<SubModel<'a, TerrainVertex>> {
190 match self {
191 ModelEntryRef::Figure(e) => e.lod_model(lod),
192 ModelEntryRef::Terrain(e) => e.lod_model(lod),
193 }
194 }
195
196 fn atlas_textures(
197 &self,
198 ) -> &'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
199 match self {
200 ModelEntryRef::Figure(e) => e.atlas_textures(),
201 ModelEntryRef::Terrain(e) => e.atlas_textures(),
202 }
203 }
204}
205
206#[derive(Default)]
207pub struct FigureMgrStates {
208 pub character_states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
209 quadruped_small_states: HashMap<EcsEntity, FigureState<QuadrupedSmallSkeleton>>,
210 quadruped_medium_states: HashMap<EcsEntity, FigureState<QuadrupedMediumSkeleton>>,
211 quadruped_low_states: HashMap<EcsEntity, FigureState<QuadrupedLowSkeleton>>,
212 bird_medium_states: HashMap<EcsEntity, FigureState<BirdMediumSkeleton>>,
213 fish_medium_states: HashMap<EcsEntity, FigureState<FishMediumSkeleton>>,
214 theropod_states: HashMap<EcsEntity, FigureState<TheropodSkeleton>>,
215 dragon_states: HashMap<EcsEntity, FigureState<DragonSkeleton>>,
216 bird_large_states: HashMap<EcsEntity, FigureState<BirdLargeSkeleton>>,
217 fish_small_states: HashMap<EcsEntity, FigureState<FishSmallSkeleton>>,
218 biped_large_states: HashMap<EcsEntity, FigureState<BipedLargeSkeleton>>,
219 biped_small_states: HashMap<EcsEntity, FigureState<BipedSmallSkeleton>>,
220 golem_states: HashMap<EcsEntity, FigureState<GolemSkeleton>>,
221 object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
222 item_states: HashMap<EcsEntity, FigureState<ItemSkeleton>>,
223 ship_states: HashMap<EcsEntity, FigureState<ShipSkeleton, BoundTerrainLocals>>,
224 volume_states: HashMap<EcsEntity, FigureState<VolumeKey, BoundTerrainLocals>>,
225 arthropod_states: HashMap<EcsEntity, FigureState<ArthropodSkeleton>>,
226 crustacean_states: HashMap<EcsEntity, FigureState<CrustaceanSkeleton>>,
227 #[cfg(feature = "plugins")]
228 plugin_states: HashMap<EcsEntity, FigureState<PluginSkeleton>>,
229}
230
231impl FigureMgrStates {
232 fn get_mut<'a, Q>(&'a mut self, body: &Body, entity: &Q) -> Option<&'a mut FigureStateMeta>
233 where
234 EcsEntity: Borrow<Q>,
235 Q: Hash + Eq + ?Sized,
236 {
237 match body {
238 Body::Humanoid(_) => self
239 .character_states
240 .get_mut(entity)
241 .map(DerefMut::deref_mut),
242 Body::QuadrupedSmall(_) => self
243 .quadruped_small_states
244 .get_mut(entity)
245 .map(DerefMut::deref_mut),
246 Body::QuadrupedMedium(_) => self
247 .quadruped_medium_states
248 .get_mut(entity)
249 .map(DerefMut::deref_mut),
250 Body::QuadrupedLow(_) => self
251 .quadruped_low_states
252 .get_mut(entity)
253 .map(DerefMut::deref_mut),
254 Body::BirdMedium(_) => self
255 .bird_medium_states
256 .get_mut(entity)
257 .map(DerefMut::deref_mut),
258 Body::FishMedium(_) => self
259 .fish_medium_states
260 .get_mut(entity)
261 .map(DerefMut::deref_mut),
262 Body::Theropod(_) => self
263 .theropod_states
264 .get_mut(entity)
265 .map(DerefMut::deref_mut),
266 Body::Dragon(_) => self.dragon_states.get_mut(entity).map(DerefMut::deref_mut),
267 Body::BirdLarge(_) => self
268 .bird_large_states
269 .get_mut(entity)
270 .map(DerefMut::deref_mut),
271 Body::FishSmall(_) => self
272 .fish_small_states
273 .get_mut(entity)
274 .map(DerefMut::deref_mut),
275 Body::BipedLarge(_) => self
276 .biped_large_states
277 .get_mut(entity)
278 .map(DerefMut::deref_mut),
279 Body::BipedSmall(_) => self
280 .biped_small_states
281 .get_mut(entity)
282 .map(DerefMut::deref_mut),
283 Body::Golem(_) => self.golem_states.get_mut(entity).map(DerefMut::deref_mut),
284 Body::Object(_) => self.object_states.get_mut(entity).map(DerefMut::deref_mut),
285 Body::Item(_) => self.item_states.get_mut(entity).map(DerefMut::deref_mut),
286 Body::Ship(ship) => {
287 if ship.manifest_entry().is_some() {
288 self.ship_states.get_mut(entity).map(DerefMut::deref_mut)
289 } else {
290 self.volume_states.get_mut(entity).map(DerefMut::deref_mut)
291 }
292 },
293 Body::Arthropod(_) => self
294 .arthropod_states
295 .get_mut(entity)
296 .map(DerefMut::deref_mut),
297 Body::Crustacean(_) => self
298 .crustacean_states
299 .get_mut(entity)
300 .map(DerefMut::deref_mut),
301 Body::Plugin(_body) => {
302 #[cfg(not(feature = "plugins"))]
303 unreachable!("Plugins require feature");
304 #[cfg(feature = "plugins")]
305 self.plugin_states.get_mut(entity).map(DerefMut::deref_mut)
306 },
307 }
308 }
309
310 fn remove<Q>(&mut self, body: &Body, entity: &Q) -> Option<FigureStateMeta>
311 where
312 EcsEntity: Borrow<Q>,
313 Q: Hash + Eq + ?Sized,
314 {
315 match body {
316 Body::Humanoid(_) => self.character_states.remove(entity).map(|e| e.meta),
317 Body::QuadrupedSmall(_) => self.quadruped_small_states.remove(entity).map(|e| e.meta),
318 Body::QuadrupedMedium(_) => self.quadruped_medium_states.remove(entity).map(|e| e.meta),
319 Body::QuadrupedLow(_) => self.quadruped_low_states.remove(entity).map(|e| e.meta),
320 Body::BirdMedium(_) => self.bird_medium_states.remove(entity).map(|e| e.meta),
321 Body::FishMedium(_) => self.fish_medium_states.remove(entity).map(|e| e.meta),
322 Body::Theropod(_) => self.theropod_states.remove(entity).map(|e| e.meta),
323 Body::Dragon(_) => self.dragon_states.remove(entity).map(|e| e.meta),
324 Body::BirdLarge(_) => self.bird_large_states.remove(entity).map(|e| e.meta),
325 Body::FishSmall(_) => self.fish_small_states.remove(entity).map(|e| e.meta),
326 Body::BipedLarge(_) => self.biped_large_states.remove(entity).map(|e| e.meta),
327 Body::BipedSmall(_) => self.biped_small_states.remove(entity).map(|e| e.meta),
328 Body::Golem(_) => self.golem_states.remove(entity).map(|e| e.meta),
329 Body::Object(_) => self.object_states.remove(entity).map(|e| e.meta),
330 Body::Item(_) => self.item_states.remove(entity).map(|e| e.meta),
331 Body::Ship(ship) => {
332 if matches!(ship, ship::Body::Volume) {
333 self.volume_states.remove(entity).map(|e| e.meta)
334 } else if ship.manifest_entry().is_some() {
335 self.ship_states.remove(entity).map(|e| e.meta)
336 } else {
337 None
338 }
339 },
340 Body::Arthropod(_) => self.arthropod_states.remove(entity).map(|e| e.meta),
341 Body::Crustacean(_) => self.crustacean_states.remove(entity).map(|e| e.meta),
342 Body::Plugin(_) => {
343 #[cfg(not(feature = "plugins"))]
344 unreachable!("Plugins require feature");
345 #[cfg(feature = "plugins")]
346 self.plugin_states.remove(entity).map(|e| e.meta)
347 },
348 }
349 }
350
351 fn retain(&mut self, mut f: impl FnMut(&EcsEntity, &mut FigureStateMeta) -> bool) {
352 span!(_guard, "retain", "FigureManagerStates::retain");
353 self.character_states.retain(|k, v| f(k, &mut *v));
354 self.quadruped_small_states.retain(|k, v| f(k, &mut *v));
355 self.quadruped_medium_states.retain(|k, v| f(k, &mut *v));
356 self.quadruped_low_states.retain(|k, v| f(k, &mut *v));
357 self.bird_medium_states.retain(|k, v| f(k, &mut *v));
358 self.fish_medium_states.retain(|k, v| f(k, &mut *v));
359 self.theropod_states.retain(|k, v| f(k, &mut *v));
360 self.dragon_states.retain(|k, v| f(k, &mut *v));
361 self.bird_large_states.retain(|k, v| f(k, &mut *v));
362 self.fish_small_states.retain(|k, v| f(k, &mut *v));
363 self.biped_large_states.retain(|k, v| f(k, &mut *v));
364 self.biped_small_states.retain(|k, v| f(k, &mut *v));
365 self.golem_states.retain(|k, v| f(k, &mut *v));
366 self.object_states.retain(|k, v| f(k, &mut *v));
367 self.item_states.retain(|k, v| f(k, &mut *v));
368 self.ship_states.retain(|k, v| f(k, &mut *v));
369 self.volume_states.retain(|k, v| f(k, &mut *v));
370 self.arthropod_states.retain(|k, v| f(k, &mut *v));
371 self.crustacean_states.retain(|k, v| f(k, &mut *v));
372 #[cfg(feature = "plugins")]
373 self.plugin_states.retain(|k, v| f(k, &mut *v));
374 }
375
376 fn count(&self) -> usize {
377 #[cfg(feature = "plugins")]
378 let plugin_states = self.plugin_states.len();
379 #[cfg(not(feature = "plugins"))]
380 let plugin_states = 0;
381 self.character_states.len()
382 + self.quadruped_small_states.len()
383 + self.character_states.len()
384 + self.quadruped_medium_states.len()
385 + self.quadruped_low_states.len()
386 + self.bird_medium_states.len()
387 + self.fish_medium_states.len()
388 + self.theropod_states.len()
389 + self.dragon_states.len()
390 + self.bird_large_states.len()
391 + self.fish_small_states.len()
392 + self.biped_large_states.len()
393 + self.biped_small_states.len()
394 + self.golem_states.len()
395 + self.object_states.len()
396 + self.item_states.len()
397 + self.ship_states.len()
398 + self.volume_states.len()
399 + self.arthropod_states.len()
400 + self.crustacean_states.len()
401 + plugin_states
402 }
403
404 fn count_visible(&self) -> usize {
405 #[cfg(feature = "plugins")]
406 let plugin_states = self
407 .plugin_states
408 .iter()
409 .filter(|(_, c)| c.visible())
410 .count();
411 #[cfg(not(feature = "plugins"))]
412 let plugin_states = 0;
413 self.character_states
414 .iter()
415 .filter(|(_, c)| c.visible())
416 .count()
417 + self
418 .quadruped_small_states
419 .iter()
420 .filter(|(_, c)| c.visible())
421 .count()
422 + self
423 .quadruped_medium_states
424 .iter()
425 .filter(|(_, c)| c.visible())
426 .count()
427 + self
428 .quadruped_low_states
429 .iter()
430 .filter(|(_, c)| c.visible())
431 .count()
432 + self
433 .bird_medium_states
434 .iter()
435 .filter(|(_, c)| c.visible())
436 .count()
437 + self
438 .theropod_states
439 .iter()
440 .filter(|(_, c)| c.visible())
441 .count()
442 + self
443 .dragon_states
444 .iter()
445 .filter(|(_, c)| c.visible())
446 .count()
447 + self
448 .fish_medium_states
449 .iter()
450 .filter(|(_, c)| c.visible())
451 .count()
452 + self
453 .bird_large_states
454 .iter()
455 .filter(|(_, c)| c.visible())
456 .count()
457 + self
458 .fish_small_states
459 .iter()
460 .filter(|(_, c)| c.visible())
461 .count()
462 + self
463 .biped_large_states
464 .iter()
465 .filter(|(_, c)| c.visible())
466 .count()
467 + self
468 .biped_small_states
469 .iter()
470 .filter(|(_, c)| c.visible())
471 .count()
472 + self
473 .golem_states
474 .iter()
475 .filter(|(_, c)| c.visible())
476 .count()
477 + self
478 .object_states
479 .iter()
480 .filter(|(_, c)| c.visible())
481 .count()
482 + self.item_states.iter().filter(|(_, c)| c.visible()).count()
483 + self
484 .arthropod_states
485 .iter()
486 .filter(|(_, c)| c.visible())
487 .count()
488 + self
489 .crustacean_states
490 .iter()
491 .filter(|(_, c)| c.visible())
492 .count()
493 + self.ship_states.iter().filter(|(_, c)| c.visible()).count()
494 + self
495 .volume_states
496 .iter()
497 .filter(|(_, c)| c.visible())
498 .count()
499 + plugin_states
500 }
501
502 fn get_terrain_locals<'a, Q>(
503 &'a self,
504 body: &Body,
505 entity: &Q,
506 ) -> Option<&'a BoundTerrainLocals>
507 where
508 EcsEntity: Borrow<Q>,
509 Q: Hash + Eq + ?Sized,
510 {
511 match body {
512 Body::Ship(body) => {
513 if matches!(body, ship::Body::Volume) {
514 self.volume_states.get(entity).map(|state| &state.extra)
515 } else if body.manifest_entry().is_some() {
516 self.ship_states.get(entity).map(|state| &state.extra)
517 } else {
518 None
519 }
520 },
521 _ => None,
522 }
523 }
524}
525
526#[derive(SystemData)]
527struct FigureReadData<'a> {
528 terrain_grid: ReadExpect<'a, TerrainGrid>,
529 id_maps: ReadExpect<'a, IdMaps>,
530 entities: Entities<'a>,
531 positions: ReadStorage<'a, Pos>,
532 controllers: ReadStorage<'a, Controller>,
533 interpolated: ReadStorage<'a, Interpolated>,
534 velocities: ReadStorage<'a, Vel>,
535 scales: ReadStorage<'a, Scale>,
536 bodies: ReadStorage<'a, Body>,
537 character_states: ReadStorage<'a, CharacterState>,
538 character_activitys: ReadStorage<'a, CharacterActivity>,
539 last_character_states: ReadStorage<'a, Last<CharacterState>>,
540 physics_states: ReadStorage<'a, PhysicsState>,
541 healths: ReadStorage<'a, Health>,
542 inventories: ReadStorage<'a, Inventory>,
543 pickup_items: ReadStorage<'a, PickupItem>,
544 thrown_items: ReadStorage<'a, ThrownItem>,
545 light_emitters: ReadStorage<'a, LightEmitter>,
546 is_riders: ReadStorage<'a, Is<Rider>>,
547 is_mounts: ReadStorage<'a, Is<Mount>>,
548 is_volume_riders: ReadStorage<'a, Is<VolumeRider>>,
549 volume_riders: ReadStorage<'a, VolumeRiders>,
550 colliders: ReadStorage<'a, Collider>,
551 heads: ReadStorage<'a, Heads>,
552}
553
554struct FigureUpdateData<'a, CSS, COR> {
555 #[cfg(feature = "plugins")]
556 plugins: &'a mut common_state::plugin::PluginMgr,
557 scene_data: &'a SceneData<'a>,
558 terrain: Option<&'a Terrain>,
559 camera_mode: CameraMode,
560 can_shadow_sun: CSS,
561 can_occlude_rain: COR,
562 tick: u64,
563 time: f32,
564 renderer: &'a mut Renderer,
565 trail_mgr: &'a mut TrailMgr,
566 slow_jobs: &'a SlowJobPool,
567 update_buf: &'a mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
568 dt_lerp: f32,
569 dt: f32,
570 player_pos: anim::vek::Vec3<f32>,
571 view_distance: u32,
572 frustum: &'a treeculler::Frustum<f32>,
573 focus_pos: anim::vek::Vec3<f32>,
574}
575
576impl FigureReadData<'_> {
577 pub fn get_entity(&self, entity: EcsEntity) -> Option<FigureUpdateParams> {
578 Some(FigureUpdateParams {
579 entity,
580 pos: self.positions.get(entity)?,
581 controller: self.controllers.get(entity),
582 interpolated: self.interpolated.get(entity),
583 vel: self.velocities.get(entity)?,
584 scale: self.scales.get(entity),
585 body: self.bodies.get(entity)?,
586 character_state: self.character_states.get(entity),
587 character_activity: self.character_activitys.get(entity),
588 last_character_state: self.last_character_states.get(entity),
589 physics_state: self.physics_states.get(entity)?,
590 health: self.healths.get(entity),
591 inventory: self.inventories.get(entity),
592 pickup_item: self.pickup_items.get(entity),
593 thrown_item: self.thrown_items.get(entity),
594 light_emitter: self.light_emitters.get(entity),
595 is_rider: self.is_riders.get(entity),
596 is_mount: self.is_mounts.get(entity),
597 is_volume_rider: self.is_volume_riders.get(entity),
598 volume_riders: self.volume_riders.get(entity),
599 collider: self.colliders.get(entity),
600 heads: self.heads.get(entity),
601 })
602 }
603
604 pub fn iter(&self) -> impl Iterator<Item = FigureUpdateParams<'_>> {
605 (
606 &self.entities,
607 &self.positions,
608 self.controllers.maybe(),
609 self.interpolated.maybe(),
610 &self.velocities,
611 self.scales.maybe(),
612 &self.bodies,
613 self.character_states.maybe(),
614 self.character_activitys.maybe(),
615 self.last_character_states.maybe(),
616 &self.physics_states,
617 self.healths.maybe(),
618 self.inventories.maybe(),
619 self.pickup_items.maybe(),
620 (
621 self.thrown_items.maybe(),
622 self.light_emitters.maybe(),
623 self.is_riders.maybe(),
624 self.is_mounts.maybe(),
625 self.is_volume_riders.maybe(),
626 self.volume_riders.maybe(),
627 self.colliders.maybe(),
628 self.heads.maybe(),
629 ),
630 )
631 .join()
632 .map(
633 |(
634 entity,
635 pos,
636 controller,
637 interpolated,
638 vel,
639 scale,
640 body,
641 character_state,
642 character_activity,
643 last_character_state,
644 physics_state,
645 health,
646 inventory,
647 pickup_item,
648 (
649 thrown_item,
650 light_emitter,
651 is_rider,
652 is_mount,
653 is_volume_rider,
654 volume_riders,
655 collider,
656 heads,
657 ),
658 )| FigureUpdateParams {
659 entity,
660 pos,
661 controller,
662 interpolated,
663 vel,
664 scale,
665 body,
666 character_state,
667 character_activity,
668 last_character_state,
669 physics_state,
670 health,
671 inventory,
672 pickup_item,
673 thrown_item,
674 light_emitter,
675 is_rider,
676 is_mount,
677 is_volume_rider,
678 volume_riders,
679 collider,
680 heads,
681 },
682 )
683 }
684}
685
686struct FigureUpdateParams<'a> {
687 entity: EcsEntity,
688 pos: &'a Pos,
689 controller: Option<&'a Controller>,
690 interpolated: Option<&'a Interpolated>,
691 vel: &'a Vel,
692 scale: Option<&'a Scale>,
693 body: &'a Body,
694 character_state: Option<&'a CharacterState>,
695 character_activity: Option<&'a CharacterActivity>,
696 last_character_state: Option<&'a Last<CharacterState>>,
697 physics_state: &'a PhysicsState,
698 health: Option<&'a Health>,
699 inventory: Option<&'a Inventory>,
700 pickup_item: Option<&'a PickupItem>,
701 thrown_item: Option<&'a ThrownItem>,
702 light_emitter: Option<&'a LightEmitter>,
703 is_rider: Option<&'a Is<Rider>>,
704 is_mount: Option<&'a Is<Mount>>,
705 is_volume_rider: Option<&'a Is<VolumeRider>>,
706 volume_riders: Option<&'a VolumeRiders>,
707 collider: Option<&'a Collider>,
708 heads: Option<&'a Heads>,
709}
710
711pub struct FigureMgr {
712 atlas: FigureAtlas,
713 model_cache: FigureModelCache,
714 theropod_model_cache: FigureModelCache<TheropodSkeleton>,
715 quadruped_small_model_cache: FigureModelCache<QuadrupedSmallSkeleton>,
716 quadruped_medium_model_cache: FigureModelCache<QuadrupedMediumSkeleton>,
717 quadruped_low_model_cache: FigureModelCache<QuadrupedLowSkeleton>,
718 bird_medium_model_cache: FigureModelCache<BirdMediumSkeleton>,
719 bird_large_model_cache: FigureModelCache<BirdLargeSkeleton>,
720 dragon_model_cache: FigureModelCache<DragonSkeleton>,
721 fish_medium_model_cache: FigureModelCache<FishMediumSkeleton>,
722 fish_small_model_cache: FigureModelCache<FishSmallSkeleton>,
723 biped_large_model_cache: FigureModelCache<BipedLargeSkeleton>,
724 biped_small_model_cache: FigureModelCache<BipedSmallSkeleton>,
725 object_model_cache: FigureModelCache<ObjectSkeleton>,
726 item_model_cache: FigureModelCache<ItemSkeleton>,
727 ship_model_cache: FigureModelCache<ShipSkeleton>,
728 golem_model_cache: FigureModelCache<GolemSkeleton>,
729 volume_model_cache: FigureModelCache<VolumeKey>,
730 arthropod_model_cache: FigureModelCache<ArthropodSkeleton>,
731 crustacean_model_cache: FigureModelCache<CrustaceanSkeleton>,
732 #[cfg(feature = "plugins")]
733 plugin_model_cache: FigureModelCache<PluginSkeleton>,
734 pub states: FigureMgrStates,
735}
736
737impl FigureMgr {
738 pub fn new(renderer: &mut Renderer) -> Self {
739 Self {
740 atlas: FigureAtlas::new(renderer),
741 model_cache: FigureModelCache::new(),
742 theropod_model_cache: FigureModelCache::new(),
743 quadruped_small_model_cache: FigureModelCache::new(),
744 quadruped_medium_model_cache: FigureModelCache::new(),
745 quadruped_low_model_cache: FigureModelCache::new(),
746 bird_medium_model_cache: FigureModelCache::new(),
747 bird_large_model_cache: FigureModelCache::new(),
748 dragon_model_cache: FigureModelCache::new(),
749 fish_medium_model_cache: FigureModelCache::new(),
750 fish_small_model_cache: FigureModelCache::new(),
751 biped_large_model_cache: FigureModelCache::new(),
752 biped_small_model_cache: FigureModelCache::new(),
753 object_model_cache: FigureModelCache::new(),
754 item_model_cache: FigureModelCache::new(),
755 ship_model_cache: FigureModelCache::new(),
756 golem_model_cache: FigureModelCache::new(),
757 volume_model_cache: FigureModelCache::new(),
758 arthropod_model_cache: FigureModelCache::new(),
759 crustacean_model_cache: FigureModelCache::new(),
760 #[cfg(feature = "plugins")]
761 plugin_model_cache: FigureModelCache::new(),
762 states: FigureMgrStates::default(),
763 }
764 }
765
766 pub fn atlas(&self) -> &FigureAtlas { &self.atlas }
767
768 fn any_watcher_reloaded(&mut self) -> bool {
769 #[cfg(feature = "plugins")]
770 let plugin_reloaded = self.plugin_model_cache.watcher_reloaded();
771 #[cfg(not(feature = "plugins"))]
772 let plugin_reloaded = false;
773 self.model_cache.watcher_reloaded()
774 || self.theropod_model_cache.watcher_reloaded()
775 || self.quadruped_small_model_cache.watcher_reloaded()
776 || self.quadruped_medium_model_cache.watcher_reloaded()
777 || self.quadruped_low_model_cache.watcher_reloaded()
778 || self.bird_medium_model_cache.watcher_reloaded()
779 || self.bird_large_model_cache.watcher_reloaded()
780 || self.dragon_model_cache.watcher_reloaded()
781 || self.fish_medium_model_cache.watcher_reloaded()
782 || self.fish_small_model_cache.watcher_reloaded()
783 || self.biped_large_model_cache.watcher_reloaded()
784 || self.biped_small_model_cache.watcher_reloaded()
785 || self.object_model_cache.watcher_reloaded()
786 || self.item_model_cache.watcher_reloaded()
787 || self.ship_model_cache.watcher_reloaded()
788 || self.golem_model_cache.watcher_reloaded()
789 || self.volume_model_cache.watcher_reloaded()
790 || self.arthropod_model_cache.watcher_reloaded()
791 || self.crustacean_model_cache.watcher_reloaded()
792 || plugin_reloaded
793 }
794
795 pub fn clean(&mut self, tick: u64) {
796 span!(_guard, "clean", "FigureManager::clean");
797
798 if self.any_watcher_reloaded() {
799 self.atlas.allocator.clear();
800
801 self.model_cache.clear_models();
802 self.theropod_model_cache.clear_models();
803 self.quadruped_small_model_cache.clear_models();
804 self.quadruped_medium_model_cache.clear_models();
805 self.quadruped_low_model_cache.clear_models();
806 self.bird_medium_model_cache.clear_models();
807 self.bird_large_model_cache.clear_models();
808 self.dragon_model_cache.clear_models();
809 self.fish_medium_model_cache.clear_models();
810 self.fish_small_model_cache.clear_models();
811 self.biped_large_model_cache.clear_models();
812 self.biped_small_model_cache.clear_models();
813 self.object_model_cache.clear_models();
814 self.item_model_cache.clear_models();
815 self.ship_model_cache.clear_models();
816 self.golem_model_cache.clear_models();
817 self.volume_model_cache.clear_models();
818 self.arthropod_model_cache.clear_models();
819 self.crustacean_model_cache.clear_models();
820 #[cfg(feature = "plugins")]
821 self.plugin_model_cache.clear_models();
822 }
823
824 self.model_cache.clean(&mut self.atlas, tick);
825 self.theropod_model_cache.clean(&mut self.atlas, tick);
826 self.quadruped_small_model_cache
827 .clean(&mut self.atlas, tick);
828 self.quadruped_medium_model_cache
829 .clean(&mut self.atlas, tick);
830 self.quadruped_low_model_cache.clean(&mut self.atlas, tick);
831 self.bird_medium_model_cache.clean(&mut self.atlas, tick);
832 self.bird_large_model_cache.clean(&mut self.atlas, tick);
833 self.dragon_model_cache.clean(&mut self.atlas, tick);
834 self.fish_medium_model_cache.clean(&mut self.atlas, tick);
835 self.fish_small_model_cache.clean(&mut self.atlas, tick);
836 self.biped_large_model_cache.clean(&mut self.atlas, tick);
837 self.biped_small_model_cache.clean(&mut self.atlas, tick);
838 self.object_model_cache.clean(&mut self.atlas, tick);
839 self.item_model_cache.clean(&mut self.atlas, tick);
840 self.ship_model_cache.clean(&mut self.atlas, tick);
841 self.golem_model_cache.clean(&mut self.atlas, tick);
842 self.volume_model_cache.clean(&mut self.atlas, tick);
843 self.arthropod_model_cache.clean(&mut self.atlas, tick);
844 self.crustacean_model_cache.clean(&mut self.atlas, tick);
845 #[cfg(feature = "plugins")]
846 self.plugin_model_cache.clean(&mut self.atlas, tick);
847 }
848
849 pub fn update_lighting(&mut self, scene_data: &SceneData) {
850 span!(_guard, "update_lighting", "FigureManager::update_lighting");
851 let ecs = scene_data.state.ecs();
852 for (entity, body, light_emitter) in (
853 &ecs.entities(),
854 ecs.read_storage::<Body>().maybe(),
855 &ecs.read_storage::<LightEmitter>(),
856 )
857 .join()
858 {
859 let mut anim_storage = ecs.write_storage::<LightAnimation>();
861 if anim_storage.get_mut(entity).is_none() {
862 let anim = LightAnimation {
863 offset: body
864 .map(|b| b.default_light_offset())
865 .unwrap_or_else(Vec3::zero),
866 col: light_emitter.col,
867 strength: 0.0,
868 };
869 let _ = anim_storage.insert(entity, anim);
870 }
871 }
872 let dt = ecs.fetch::<DeltaTime>().0;
873 let updater = ecs.read_resource::<LazyUpdate>();
874 for (entity, light_emitter_opt, interpolated, pos, body, light_anim) in (
875 &ecs.entities(),
876 ecs.read_storage::<LightEmitter>().maybe(),
877 ecs.read_storage::<Interpolated>().maybe(),
878 &ecs.read_storage::<Pos>(),
879 ecs.read_storage::<Body>().maybe(),
880 &mut ecs.write_storage::<LightAnimation>(),
881 )
882 .join()
883 {
884 let (target_col, target_strength, flicker, animated) =
885 if let Some(emitter) = light_emitter_opt {
886 (
887 emitter.col,
888 if emitter.strength.is_normal() {
889 emitter.strength
890 } else {
891 0.0
892 },
893 emitter.flicker,
894 emitter.animated,
895 )
896 } else {
897 (Rgb::zero(), 0.0, 0.0, true)
898 };
899 if let Some(lantern_offset) = body
900 .and_then(|body| self.states.get_mut(body, &entity))
901 .and_then(|state| {
902 let pos = anim::vek::Vec3::from(
904 interpolated.map(|i| i.pos).unwrap_or(pos.0).into_array(),
905 );
906 Some(
907 state.mount_world_pos
908 + anim::vek::Vec3::from(state.lantern_offset?.into_array())
909 - pos,
910 )
911 })
912 {
913 light_anim.offset = lantern_offset;
914 } else if let Some(body) = body {
915 light_anim.offset = body.default_light_offset();
916 }
917 if !light_anim.strength.is_normal() {
918 light_anim.strength = 0.0;
919 }
920 if animated {
921 let flicker = (rand::random::<f32>() - 0.5) * flicker / dt.sqrt();
922 let delta = 0.05_f32.powf(dt);
924 light_anim.strength =
925 light_anim.strength * delta + (target_strength + flicker) * (1.0 - delta);
926 light_anim.col = light_anim.col * delta + target_col * (1.0 - delta)
927 } else {
928 light_anim.strength = target_strength;
929 light_anim.col = target_col;
930 }
931 const LIGHT_EPSILON: f32 = 0.0001;
937 if (light_anim.strength - target_strength).abs() < LIGHT_EPSILON {
938 light_anim.strength = target_strength;
939 if light_anim.strength == 0.0 {
940 updater.remove::<LightAnimation>(entity);
941 }
942 }
943 }
944 }
945
946 pub fn maintain(
947 &mut self,
948 renderer: &mut Renderer,
949 trail_mgr: &mut TrailMgr,
950 scene_data: &SceneData,
951 visible_psr_bounds: math::Aabr<f32>,
953 visible_por_bounds: math::Aabr<f32>,
954 camera: &Camera,
955 terrain: Option<&Terrain>,
956 ) -> anim::vek::Aabb<f32> {
957 span!(_guard, "maintain", "FigureManager::maintain");
958 let state = scene_data.state;
959 let time = state.get_time() as f32;
960 let tick = scene_data.tick;
961 let ecs = state.ecs();
962 let view_distance = scene_data.entity_view_distance;
963 let dt = state.get_delta_time();
964 let dt_lerp = (15.0 * dt).min(1.0);
965 let frustum = camera.frustum();
966
967 let (can_shadow_sun, can_occlude_rain) = {
974 let Dependents {
975 proj_mat: _,
976 view_mat: _,
977 cam_pos,
978 ..
979 } = camera.dependents();
980
981 let sun_dir = scene_data.get_sun_dir();
982 let is_daylight = sun_dir.z < 0.0;
983 let can_shadow_sun = renderer.pipeline_modes().shadow.is_map() && is_daylight;
985
986 let weather = scene_data.client.weather_at_player();
987
988 let focus_off = camera.get_focus_pos().map(f32::trunc);
989 let focus_off_mat = math::Mat4::translation_3d(-focus_off);
990
991 let collides_with_aabr = |a: math::Aabr<f32>, b: math::Aabr<f32>| {
992 let min = math::Vec4::new(a.min.x, a.min.y, b.min.x, b.min.y);
993 let max = math::Vec4::new(b.max.x, b.max.y, a.max.x, a.max.y);
994 #[cfg(feature = "simd")]
995 return min.partial_cmple_simd(max).reduce_and();
996 #[cfg(not(feature = "simd"))]
997 return min.partial_cmple(&max).reduce_and();
998 };
999
1000 let can_shadow = |ray_direction: Vec3<f32>,
1001 enabled: bool,
1002 visible_bounds: math::Aabr<f32>| {
1003 let ray_mat: math::Mat4<f32> =
1005 math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, math::Vec3::unit_y());
1006 let ray_mat = ray_mat * focus_off_mat;
1007 move |pos: (anim::vek::Vec3<f32>,), radius: f32| {
1008 if !enabled {
1010 return false;
1011 }
1012 let center = (ray_mat * math::Vec4::new(pos.0.x, pos.0.y, pos.0.z, 1.0)).xy();
1014 let figure_box = math::Aabr {
1016 min: center - radius,
1017 max: center + radius,
1018 };
1019 collides_with_aabr(figure_box, visible_bounds)
1022 }
1023 };
1024 (
1025 can_shadow(sun_dir, can_shadow_sun, visible_psr_bounds),
1026 can_shadow(
1027 weather.rain_vel(),
1028 weather.rain > RAIN_THRESHOLD,
1029 visible_por_bounds,
1030 ),
1031 )
1032 };
1033
1034 let read_data = ecs.system_data::<FigureReadData>();
1035
1036 let player_pos = read_data
1038 .positions
1039 .get(scene_data.viewpoint_entity)
1040 .map_or(anim::vek::Vec3::zero(), |pos| pos.0);
1041 let visible_aabb = anim::vek::Aabb {
1042 min: player_pos - 2.0,
1043 max: player_pos + 2.0,
1044 };
1045 let slow_jobs = state.slow_job_pool();
1046
1047 let focus_pos = camera.get_focus_pos();
1048
1049 let mut data = FigureUpdateData {
1050 #[cfg(feature = "plugins")]
1051 plugins: &mut ecs.write_resource(),
1052 scene_data,
1053 terrain,
1054 camera_mode: camera.get_mode(),
1055 can_shadow_sun,
1056 can_occlude_rain,
1057 tick,
1058 renderer,
1059 trail_mgr,
1060 slow_jobs: &slow_jobs,
1061 time,
1062 update_buf: &mut [Default::default(); anim::MAX_BONE_COUNT],
1063 dt_lerp,
1064 dt,
1065 player_pos,
1066 view_distance,
1067 frustum,
1068 focus_pos,
1069 };
1070
1071 fn update_riders(
1072 this: &mut FigureMgr,
1073 mount_data: &FigureUpdateParams,
1074 read_data: &FigureReadData,
1075 data: &mut FigureUpdateData<
1076 impl Fn((anim::vek::Vec3<f32>,), f32) -> bool,
1077 impl Fn((anim::vek::Vec3<f32>,), f32) -> bool,
1078 >,
1079 ) {
1080 if let Some(is_mount) = mount_data.is_mount
1081 && let Some(rider) = read_data.id_maps.uid_entity(is_mount.rider)
1082 && let Some(rider_data) = read_data.get_entity(rider)
1083 {
1084 this.maintain_entity(&rider_data, read_data, data);
1085 update_riders(this, &rider_data, read_data, data);
1086 }
1087 if let Some(volume_riders) = mount_data.volume_riders {
1088 for rider_data in volume_riders
1089 .iter_riders()
1090 .filter_map(|rider| read_data.id_maps.uid_entity(rider))
1091 .filter_map(|rider| read_data.get_entity(rider))
1092 {
1093 this.maintain_entity(&rider_data, read_data, data);
1094 update_riders(this, &rider_data, read_data, data);
1095 }
1096 }
1097 }
1098
1099 for (i, entity_data) in read_data.iter().enumerate() {
1100 if entity_data
1102 .is_rider
1103 .is_some_and(|is_rider| read_data.id_maps.uid_entity(is_rider.mount).is_some())
1104 || entity_data
1105 .is_volume_rider
1106 .is_some_and(|is_volume_rider| match is_volume_rider.pos.kind {
1107 Volume::Terrain => false,
1108 Volume::Entity(uid) => read_data.id_maps.uid_entity(uid).is_some(),
1109 })
1110 {
1111 continue;
1112 }
1113
1114 let pos = entity_data
1115 .interpolated
1116 .map_or(entity_data.pos.0, |i| i.pos);
1117
1118 const MIN_PERFECT_RATE_DIST: f32 = 100.0;
1126
1127 if (i as u64 + data.tick)
1128 % ((((pos.distance_squared(focus_pos) / entity_data.scale.map_or(1.0, |s| s.0))
1129 .powf(0.25)
1130 - MIN_PERFECT_RATE_DIST.sqrt())
1131 .max(0.0)
1132 / 3.0) as u64)
1133 .saturating_add(1)
1134 != 0
1135 {
1136 continue;
1137 }
1138
1139 self.maintain_entity(&entity_data, &read_data, &mut data);
1140 update_riders(self, &entity_data, &read_data, &mut data);
1141 }
1142
1143 self.update_lighting(scene_data);
1145
1146 self.states
1148 .retain(|entity, _| ecs.entities().is_alive(*entity));
1149
1150 visible_aabb
1151 }
1152
1153 fn maintain_entity(
1154 &mut self,
1155 entity_data: &FigureUpdateParams,
1156 read_data: &FigureReadData,
1157 data: &mut FigureUpdateData<
1158 impl Fn((anim::vek::Vec3<f32>,), f32) -> bool,
1159 impl Fn((anim::vek::Vec3<f32>,), f32) -> bool,
1160 >,
1161 ) {
1162 let FigureUpdateParams {
1163 entity,
1164 pos,
1165 controller,
1166 interpolated,
1167 vel,
1168 scale,
1169 body,
1170 character_state: character,
1171 character_activity,
1172 last_character_state: last_character,
1173 physics_state: physics,
1174 health,
1175 inventory,
1176 pickup_item: item,
1177 thrown_item,
1178 light_emitter,
1179 is_rider,
1180 is_mount: _,
1181 is_volume_rider,
1182 volume_riders: _,
1183 collider,
1184 heads,
1185 } = *entity_data;
1186
1187 let renderer = &mut *data.renderer;
1188 let tick = data.tick;
1189 let slow_jobs = data.slow_jobs;
1190 let dt = data.dt;
1191 let time = data.time;
1192 let dt_lerp = data.dt_lerp;
1193 let update_buf = &mut *data.update_buf;
1194
1195 let rel_vel = (vel.0 - physics.ground_vel) / scale.map_or(1.0, |s| s.0);
1197
1198 let look_dir = character_activity.and_then(|ca| ca.look_dir)
1200 .or_else(|| controller.map(|c| c.inputs.look_dir))
1202 .or_else(|| interpolated.map(|i| i.ori.look_dir()))
1204 .unwrap_or_default();
1205 let is_viewpoint = data.scene_data.viewpoint_entity == entity;
1206 let viewpoint_camera_mode = if is_viewpoint {
1207 data.camera_mode
1208 } else {
1209 CameraMode::default()
1210 };
1211 let viewpoint_character_state = if is_viewpoint { character } else { None };
1212
1213 let (pos, ori) = interpolated
1214 .map(|i| ((i.pos,), anim::vek::Quaternion::<f32>::from(i.ori)))
1215 .unwrap_or(((pos.0,), anim::vek::Quaternion::<f32>::default()));
1216 let wall_dir = physics.on_wall;
1217
1218 let mut state = self.states.get_mut(body, &entity);
1220 let can_shadow_prev = state
1221 .as_mut()
1222 .map(|state| state.can_shadow_sun())
1223 .unwrap_or(false);
1224
1225 let vd_frac = anim::vek::Vec2::from(pos.0 - data.player_pos)
1227 .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| d.abs() / sz as f32)
1228 .magnitude()
1229 / data.view_distance as f32;
1230
1231 if vd_frac > 1.2 {
1233 self.states.remove(body, &entity);
1234 return;
1235 } else if vd_frac > 1.0 {
1236 state.as_mut().map(|state| state.visible = false);
1237 if !can_shadow_prev {
1241 return;
1242 }
1243 }
1244
1245 let radius = scale.unwrap_or(&Scale(1.0)).0 * 2.0;
1252 let (in_frustum, _lpindex) = if let Some(ref mut meta) = state {
1253 let (in_frustum, lpindex) = BoundingSphere::new(pos.0.into_array(), radius)
1254 .coherent_test_against_frustum(data.frustum, meta.lpindex);
1255 let in_frustum = in_frustum
1256 || matches!(body, Body::Ship(_))
1257 || pos.0.distance_squared(data.focus_pos) < 32.0f32.powi(2);
1258 meta.visible = in_frustum;
1259 meta.lpindex = lpindex;
1260 if in_frustum {
1261 } else {
1267 meta.can_shadow_sun = (data.can_shadow_sun)(pos, radius);
1269 meta.can_occlude_rain = (data.can_occlude_rain)(pos, radius);
1270 }
1271 (in_frustum, lpindex)
1272 } else {
1273 (true, 0)
1274 };
1275
1276 if !in_frustum {
1277 return;
1278 }
1279
1280 let col = health
1282 .map(|h| {
1283 let time = data.scene_data.state.ecs().read_resource::<Time>();
1284 let time_since_health_change = time.0 - h.last_change.time.0;
1285 Rgba::broadcast(1.0)
1286 + Rgba::new(10.0, 10.0, 10.0, 0.0).map(|c| {
1287 (c / (1.0 + DAMAGE_FADE_COEFFICIENT * time_since_health_change)) as f32
1288 })
1289 })
1290 .unwrap_or_else(|| Rgba::broadcast(1.0))
1291 * if item.is_some() && data.scene_data.target_entities.contains(&entity) {
1293 Rgba::new(1.5, 1.5, 1.5, 1.0)
1294 } else {
1295 Rgba::one()
1296 };
1297
1298 let scale = scale.map(|s| s.0).unwrap_or(1.0);
1299
1300 let mut state_animation_rate = 1.0;
1301
1302 let tool_info = |equip_slot| {
1303 inventory
1304 .and_then(|i| i.equipped(equip_slot))
1305 .map(|i| {
1306 if let ItemKind::Tool(tool) = &*i.kind() {
1307 (Some(tool.kind), Some(tool.hands), i.ability_spec())
1308 } else {
1309 (None, None, None)
1310 }
1311 })
1312 .unwrap_or((None, None, None))
1313 };
1314
1315 let (active_tool_kind, active_tool_hand, active_tool_spec) =
1316 tool_info(EquipSlot::ActiveMainhand);
1317 let active_tool_spec = active_tool_spec.as_deref();
1318 let (second_tool_kind, second_tool_hand, second_tool_spec) =
1319 tool_info(EquipSlot::ActiveOffhand);
1320 let second_tool_spec = second_tool_spec.as_deref();
1321 let hands = (active_tool_hand, second_tool_hand);
1322
1323 let ability_id = character.and_then(|c| {
1324 c.ability_info()
1325 .and_then(|a| a.ability)
1326 .and_then(|a| a.ability_id(Some(c), inventory))
1327 });
1328
1329 let move_dir = {
1330 let ori = ori * *Dir::default();
1331 let theta = vel.0.y.atan2(vel.0.x) - ori.y.atan2(ori.x);
1332 anim::vek::Vec2::unit_y().rotated_z(theta)
1333 };
1334
1335 let mount_transform_pos = (|| -> Option<_> {
1337 if let Some(is_rider) = is_rider {
1338 let mount = is_rider.mount;
1339 let mount = read_data.id_maps.uid_entity(mount)?;
1340 let body = *read_data.bodies.get(mount)?;
1341 let meta = self.states.get_mut(&body, &mount)?;
1342 Some((meta.mount_transform, meta.mount_world_pos))
1343 } else if let Some(is_volume_rider) = is_volume_rider
1344 && matches!(is_volume_rider.pos.kind, Volume::Entity(_))
1345 {
1346 let (mat, _) = is_volume_rider.pos.get_mount_mat(
1347 &read_data.terrain_grid,
1348 &read_data.id_maps,
1349 |e| read_data.interpolated.get(e).map(|i| (Pos(i.pos), i.ori)),
1350 &read_data.colliders,
1351 )?;
1352 Some((anim::vek::Transform::default(), mat.mul_point(Vec3::zero())))
1353 } else {
1354 None
1355 }
1356 })();
1357
1358 let body = *body;
1359
1360 let trail_mgr = data
1362 .scene_data
1363 .weapon_trails_enabled
1364 .then_some(&mut *data.trail_mgr);
1365
1366 let common_params = FigureUpdateCommonParameters {
1367 entity: Some(entity),
1368 pos: pos.0,
1369 ori,
1370 scale,
1371 mount_transform_pos,
1372 body: Some(body),
1373 tools: (active_tool_kind, second_tool_kind),
1374 col,
1375 dt,
1376 is_player: is_viewpoint,
1377 terrain: data.terrain,
1378 ground_vel: physics.ground_vel,
1379 };
1380
1381 match body {
1382 Body::Humanoid(body) => {
1383 let (model, skeleton_attr) = self.model_cache.get_or_create_model(
1384 renderer,
1385 &mut self.atlas,
1386 body,
1387 inventory,
1388 (),
1389 tick,
1390 viewpoint_camera_mode,
1391 viewpoint_character_state,
1392 slow_jobs,
1393 None,
1394 );
1395
1396 let holding_lantern = inventory
1397 .is_some_and(|i| i.equipped(EquipSlot::Lantern).is_some())
1398 && light_emitter.is_some()
1399 && ((second_tool_hand.is_none()
1400 && matches!(active_tool_hand, Some(Hands::One)))
1401 || !character.is_some_and(|c| c.is_wield()))
1402 && !character.is_some_and(|c| c.is_using_hands())
1403 && physics.in_liquid().is_none()
1404 && is_volume_rider.is_none_or(|volume_rider| {
1405 !matches!(volume_rider.block.get_sprite(), Some(SpriteKind::Helm))
1406 });
1407
1408 let back_carry_offset = inventory
1409 .and_then(|i| i.equipped(EquipSlot::Armor(ArmorSlot::Back)))
1410 .and_then(|i| {
1411 if let ItemKind::Armor(armor) = i.kind().as_ref() {
1412 match &armor.kind {
1413 ArmorKind::Backpack => Some(4.0),
1414 ArmorKind::Back => Some(1.5),
1415 _ => None,
1416 }
1417 } else {
1418 None
1419 }
1420 })
1421 .unwrap_or(0.0);
1422
1423 let state = self
1424 .states
1425 .character_states
1426 .entry(entity)
1427 .or_insert_with(|| {
1428 FigureState::new(
1429 renderer,
1430 CharacterSkeleton::new(holding_lantern, back_carry_offset),
1431 body,
1432 )
1433 });
1434
1435 let rel_avg_vel = (state.avg_vel - physics.ground_vel) / scale;
1437
1438 let orientation = ori * anim::vek::Vec3::<f32>::unit_y();
1439 let last_ori = state.last_ori * anim::vek::Vec3::<f32>::unit_y();
1440
1441 let (character, last_character) = match (character, last_character) {
1442 (Some(c), Some(l)) => (c, l),
1443 _ => return,
1444 };
1445
1446 if !character.same_variant(&last_character.0) {
1447 state.state_time = 0.0;
1448 }
1449
1450 let is_riding = is_rider.is_some() || is_volume_rider.is_some();
1451
1452 let target_base = match (
1453 physics.on_ground.is_some(),
1454 rel_vel.magnitude_squared() > 0.01, physics.in_liquid().is_some(), is_riding,
1457 physics.skating_active,
1458 ) {
1459 (true, false, false, false, _) | (_, _, false, false, true) => {
1461 anim::character::StandAnimation::update_skeleton(
1462 &CharacterSkeleton::new(holding_lantern, back_carry_offset),
1463 (
1464 active_tool_kind,
1465 second_tool_kind,
1466 hands,
1467 ori * anim::vek::Vec3::<f32>::unit_y(),
1469 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1470 time,
1471 rel_avg_vel,
1472 ),
1473 state.state_time,
1474 &mut state_animation_rate,
1475 skeleton_attr,
1476 )
1477 },
1478 (true, true, false, false, _) => {
1480 anim::character::RunAnimation::update_skeleton(
1481 &CharacterSkeleton::new(holding_lantern, back_carry_offset),
1482 (
1483 active_tool_kind,
1484 second_tool_kind,
1485 hands,
1486 rel_vel,
1487 ori * anim::vek::Vec3::<f32>::unit_y(),
1489 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1490 time,
1491 rel_avg_vel,
1492 state.acc_vel,
1493 wall_dir,
1494 ),
1495 state.state_time,
1496 &mut state_animation_rate,
1497 skeleton_attr,
1498 )
1499 },
1500 (false, _, false, false, _) => {
1502 anim::character::JumpAnimation::update_skeleton(
1503 &CharacterSkeleton::new(holding_lantern, back_carry_offset),
1504 (
1505 active_tool_kind,
1506 second_tool_kind,
1507 hands,
1508 rel_vel,
1509 ori * anim::vek::Vec3::<f32>::unit_y(),
1511 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1512 time,
1513 ),
1514 state.state_time,
1515 &mut state_animation_rate,
1516 skeleton_attr,
1517 )
1518 },
1519 (_, _, true, false, _) => anim::character::SwimAnimation::update_skeleton(
1521 &CharacterSkeleton::new(holding_lantern, back_carry_offset),
1522 (
1523 active_tool_kind,
1524 second_tool_kind,
1525 hands,
1526 rel_vel,
1527 ori * anim::vek::Vec3::<f32>::unit_y(),
1529 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1530 time,
1531 rel_avg_vel,
1532 ),
1533 state.state_time,
1534 &mut state_animation_rate,
1535 skeleton_attr,
1536 ),
1537 (_, _, _, true, _) => {
1539 let base = anim::character::MountAnimation::update_skeleton(
1540 &CharacterSkeleton::new(holding_lantern, back_carry_offset),
1541 (
1542 active_tool_kind,
1543 second_tool_kind,
1544 hands,
1545 time,
1546 rel_vel,
1547 rel_avg_vel,
1548 ori * anim::vek::Vec3::<f32>::unit_y(),
1550 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1551 ),
1552 state.state_time,
1553 &mut state_animation_rate,
1554 skeleton_attr,
1555 );
1556 if let Some(is_volume_rider) = is_volume_rider
1557 && let Some(sprite) = is_volume_rider.block.get_sprite()
1558 {
1559 match sprite {
1560 _ if sprite.is_controller() => {
1561 anim::character::SteerAnimation::update_skeleton(
1562 &base,
1563 (
1564 active_tool_kind,
1565 second_tool_kind,
1566 character_activity.map(|a| a.steer_dir).unwrap_or(0.0),
1567 time,
1568 ),
1569 state.state_time,
1570 &mut state_animation_rate,
1571 skeleton_attr,
1572 )
1573 },
1574 _ if sprite.is_bed() => {
1575 anim::character::SleepAnimation::update_skeleton(
1576 &base,
1577 (active_tool_kind, second_tool_kind, time),
1578 state.state_time,
1579 &mut state_animation_rate,
1580 skeleton_attr,
1581 )
1582 },
1583 _ => anim::character::SitAnimation::update_skeleton(
1584 &base,
1585 (active_tool_kind, second_tool_kind, time),
1586 state.state_time,
1587 &mut state_animation_rate,
1588 skeleton_attr,
1589 ),
1590 }
1591 } else {
1592 base
1593 }
1594 },
1595 };
1596 let target_bones = match &character {
1597 CharacterState::Roll(s) => {
1598 let stage_time = s.timer.as_secs_f32();
1599 let wield_status = s.was_wielded;
1600 let stage_progress = match s.stage_section {
1601 StageSection::Buildup => {
1602 stage_time / s.static_data.buildup_duration.as_secs_f32()
1603 },
1604 StageSection::Movement => {
1605 stage_time / s.static_data.movement_duration.as_secs_f32()
1606 },
1607 StageSection::Recover => {
1608 stage_time / s.static_data.recover_duration.as_secs_f32()
1609 },
1610 _ => 0.0,
1611 };
1612 anim::character::RollAnimation::update_skeleton(
1613 &target_base,
1614 (
1615 active_tool_kind,
1616 second_tool_kind,
1617 hands,
1618 wield_status,
1619 ori * anim::vek::Vec3::<f32>::unit_y(),
1621 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1622 time,
1623 Some(s.stage_section),
1624 s.prev_aimed_dir,
1625 ),
1626 stage_progress,
1627 &mut state_animation_rate,
1628 skeleton_attr,
1629 )
1630 },
1631 CharacterState::Throw(s) => {
1632 let timer = character.timer();
1633 let stage_section = character.stage_section();
1634 let durations = character.durations();
1635 let progress = if let Some(((timer, stage_section), durations)) =
1636 timer.zip(stage_section).zip(durations)
1637 {
1638 let base_dur = match stage_section {
1639 StageSection::Buildup => durations.buildup,
1640 StageSection::Charge => durations.charge,
1641 StageSection::Movement => None,
1642 StageSection::Action => durations.action,
1643 StageSection::Recover => durations.recover,
1644 };
1645 if let Some(base_dur) = base_dur {
1646 timer.as_secs_f32() / base_dur.as_secs_f32()
1647 } else {
1648 timer.as_secs_f32()
1649 }
1650 } else {
1651 0.0
1652 };
1653
1654 anim::character::ThrowAnimation::update_skeleton(
1655 &target_base,
1656 (
1657 stage_section,
1658 s.static_data.tool_kind,
1659 s.static_data.hand_info,
1660 ),
1661 progress,
1662 &mut state_animation_rate,
1663 skeleton_attr,
1664 )
1665 },
1666 CharacterState::BasicMelee(_)
1667 | CharacterState::FinisherMelee(_)
1668 | CharacterState::DiveMelee(_)
1669 | CharacterState::SelfBuff(_)
1670 | CharacterState::ChargedRanged(_)
1671 | CharacterState::BasicRanged(_)
1672 | CharacterState::ChargedMelee(_)
1673 | CharacterState::DashMelee(_)
1674 | CharacterState::Shockwave(_)
1675 | CharacterState::BasicAura(_)
1676 | CharacterState::StaticAura(_)
1677 | CharacterState::BasicBeam(_)
1678 | CharacterState::BasicBlock(_)
1679 | CharacterState::RiposteMelee(_) => {
1680 let timer = character.timer();
1681 let stage_section = character.stage_section();
1682 let durations = character.durations();
1683 let progress = if let Some(((timer, stage_section), durations)) =
1684 timer.zip(stage_section).zip(durations)
1685 {
1686 let base_dur = match stage_section {
1687 StageSection::Buildup => durations.buildup,
1688 StageSection::Charge => {
1689 if matches!(character, CharacterState::DashMelee(_)) {
1690 None
1691 } else {
1692 durations.charge
1693 }
1694 },
1695 StageSection::Movement => {
1696 if matches!(character, CharacterState::DiveMelee(_)) {
1697 None
1698 } else {
1699 durations.movement
1700 }
1701 },
1702 StageSection::Action => {
1703 if matches!(
1704 character,
1705 CharacterState::BasicBeam(_)
1706 | CharacterState::BasicBlock(_)
1707 ) {
1708 None
1709 } else {
1710 durations.action
1711 }
1712 },
1713 StageSection::Recover => durations.recover,
1714 };
1715 if let Some(base_dur) = base_dur {
1716 timer.as_secs_f32() / base_dur.as_secs_f32()
1717 } else {
1718 timer.as_secs_f32()
1719 }
1720 } else {
1721 0.0
1722 };
1723
1724 anim::character::BasicAction::update_skeleton(
1725 &target_base,
1726 anim::character::BasicActionDependency {
1727 ability_id,
1728 hands,
1729 stage_section,
1730 ability_info: character.ability_info(),
1731 velocity: rel_vel,
1732 last_ori,
1733 orientation,
1734 look_dir,
1735 is_riding,
1736 },
1737 progress,
1738 &mut state_animation_rate,
1739 skeleton_attr,
1740 )
1741 },
1742 CharacterState::ComboMelee2(_)
1743 | CharacterState::RepeaterRanged(_)
1744 | CharacterState::RapidMelee(_) => {
1745 let timer = character.timer();
1746 let stage_section = character.stage_section();
1747 let durations = character.durations();
1748 let progress = if let Some(((timer, stage_section), durations)) =
1749 timer.zip(stage_section).zip(durations)
1750 {
1751 let base_dur = match stage_section {
1752 StageSection::Buildup => durations.buildup,
1753 StageSection::Charge => durations.charge,
1754 StageSection::Movement => durations.movement,
1755 StageSection::Action => durations.action,
1756 StageSection::Recover => durations.recover,
1757 };
1758 if let Some(base_dur) = base_dur {
1759 timer.as_secs_f32() / base_dur.as_secs_f32()
1760 } else {
1761 timer.as_secs_f32()
1762 }
1763 } else {
1764 0.0
1765 };
1766
1767 let (current_action, max_actions) = match character {
1768 CharacterState::ComboMelee2(s) => (
1769 (s.completed_strikes % s.static_data.strikes.len()) as u32,
1770 Some(s.static_data.strikes.len() as u32),
1771 ),
1772 CharacterState::RepeaterRanged(s) => (s.projectiles_fired, None),
1773 CharacterState::RapidMelee(s) => {
1774 (s.current_strike, s.static_data.max_strikes)
1775 },
1776 _ => (0, None),
1777 };
1778
1779 anim::character::MultiAction::update_skeleton(
1780 &target_base,
1781 anim::character::MultiActionDependency {
1782 ability_id,
1783 stage_section,
1784 ability_info: character.ability_info(),
1785 current_action,
1786 max_actions,
1787 move_dir,
1788 orientation,
1789 look_dir,
1790 velocity: rel_vel,
1791 is_riding,
1792 },
1793 progress,
1794 &mut state_animation_rate,
1795 skeleton_attr,
1796 )
1797 },
1798 CharacterState::Idle(idle::Data {
1799 is_sneaking: true, ..
1800 }) => {
1801 anim::character::SneakAnimation::update_skeleton(
1802 &target_base,
1803 (
1804 active_tool_kind,
1805 rel_vel,
1806 ori * anim::vek::Vec3::<f32>::unit_y(),
1808 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1809 time,
1810 ),
1811 state.state_time,
1812 &mut state_animation_rate,
1813 skeleton_attr,
1814 )
1815 },
1816 CharacterState::Interact(s) => {
1817 let stage_time = s.timer.as_secs_f32();
1818 let interact_pos = match s.static_data.interact {
1819 interact::InteractKind::Invalid => pos.0,
1820 interact::InteractKind::Entity { target, .. } => read_data
1821 .id_maps
1822 .uid_entity(target)
1823 .and_then(|target| read_data.positions.get(target))
1824 .map(|pos| pos.0)
1825 .unwrap_or(pos.0),
1826 interact::InteractKind::Sprite { pos, .. } => pos.as_() + 0.5,
1827 };
1828 let stage_progress = match s.stage_section {
1829 StageSection::Buildup => {
1830 stage_time / s.static_data.buildup_duration.as_secs_f32()
1831 },
1832 StageSection::Action => s.timer.as_secs_f32(),
1833 StageSection::Recover => {
1834 stage_time / s.static_data.recover_duration.as_secs_f32()
1835 },
1836 _ => 0.0,
1837 };
1838 match s.static_data.interact {
1839 interact::InteractKind::Entity {
1840 kind: InteractionKind::Pet,
1841 ..
1842 } => anim::character::PetAnimation::update_skeleton(
1843 &target_base,
1844 (pos.0, interact_pos, time),
1845 state.state_time,
1846 &mut state_animation_rate,
1847 skeleton_attr,
1848 ),
1849 _ => anim::character::CollectAnimation::update_skeleton(
1850 &target_base,
1851 (pos.0, time, Some(s.stage_section), interact_pos, is_riding),
1852 stage_progress,
1853 &mut state_animation_rate,
1854 skeleton_attr,
1855 ),
1856 }
1857 },
1858 CharacterState::Boost(_) => anim::character::BoostAnimation::update_skeleton(
1859 &target_base,
1860 (),
1861 0.5,
1862 &mut state_animation_rate,
1863 skeleton_attr,
1864 ),
1865 CharacterState::Stunned(s) => {
1866 let stage_time = s.timer.as_secs_f32();
1867 let wield_status = s.was_wielded;
1868 let stage_progress = match s.stage_section {
1869 StageSection::Buildup => {
1870 stage_time / s.static_data.buildup_duration.as_secs_f32()
1871 },
1872 StageSection::Recover => {
1873 stage_time / s.static_data.recover_duration.as_secs_f32()
1874 },
1875 _ => 0.0,
1876 };
1877 match s.static_data.poise_state {
1878 PoiseState::Normal | PoiseState::Stunned | PoiseState::Interrupted => {
1879 anim::character::StunnedAnimation::update_skeleton(
1880 &target_base,
1881 (
1882 active_tool_kind,
1883 second_tool_kind,
1884 hands,
1885 rel_vel.magnitude(),
1886 time,
1887 Some(s.stage_section),
1888 state.state_time,
1889 wield_status,
1890 ),
1891 stage_progress,
1892 &mut state_animation_rate,
1893 skeleton_attr,
1894 )
1895 },
1896 PoiseState::Dazed | PoiseState::KnockedDown => {
1897 anim::character::StaggeredAnimation::update_skeleton(
1898 &target_base,
1899 (
1900 active_tool_kind,
1901 second_tool_kind,
1902 hands,
1903 rel_vel.magnitude(),
1904 time,
1905 Some(s.stage_section),
1906 state.state_time,
1907 wield_status,
1908 ),
1909 stage_progress,
1910 &mut state_animation_rate,
1911 skeleton_attr,
1912 )
1913 },
1914 }
1915 },
1916 CharacterState::UseItem(s) => {
1917 let stage_time = s.timer.as_secs_f32();
1918 let item_kind = s.static_data.item_kind;
1919 let stage_progress = match s.stage_section {
1920 StageSection::Buildup => {
1921 stage_time / s.static_data.buildup_duration.as_secs_f32()
1922 },
1923 StageSection::Action => stage_time,
1924 StageSection::Recover => {
1925 stage_time / s.static_data.recover_duration.as_secs_f32()
1926 },
1927 _ => 0.0,
1928 };
1929 anim::character::ConsumeAnimation::update_skeleton(
1930 &target_base,
1931 (time, Some(s.stage_section), Some(item_kind)),
1932 stage_progress,
1933 &mut state_animation_rate,
1934 skeleton_attr,
1935 )
1936 },
1937 CharacterState::Equipping(equipping::Data { is_sneaking, .. }) => {
1938 if *is_sneaking {
1939 anim::character::SneakEquipAnimation::update_skeleton(
1940 &target_base,
1941 (
1942 active_tool_kind,
1943 rel_vel,
1944 ori * anim::vek::Vec3::<f32>::unit_y(),
1946 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
1947 time,
1948 ),
1949 state.state_time,
1950 &mut state_animation_rate,
1951 skeleton_attr,
1952 )
1953 } else {
1954 anim::character::EquipAnimation::update_skeleton(
1955 &target_base,
1956 (
1957 active_tool_kind,
1958 second_tool_kind,
1959 rel_vel.magnitude(),
1960 time,
1961 ),
1962 state.state_time,
1963 &mut state_animation_rate,
1964 skeleton_attr,
1965 )
1966 }
1967 },
1968 CharacterState::Talk(_) => anim::character::TalkAnimation::update_skeleton(
1969 &target_base,
1970 (
1971 active_tool_kind,
1972 second_tool_kind,
1973 rel_vel.magnitude(),
1974 time,
1975 look_dir,
1976 ),
1977 state.state_time,
1978 &mut state_animation_rate,
1979 skeleton_attr,
1980 ),
1981 CharacterState::Wielding(wielding::Data { is_sneaking, .. }) => {
1982 if physics.in_liquid().is_some() {
1983 anim::character::SwimWieldAnimation::update_skeleton(
1984 &target_base,
1985 (
1986 active_tool_kind,
1987 second_tool_kind,
1988 hands,
1989 rel_vel.magnitude(),
1990 time,
1991 ),
1992 state.state_time,
1993 &mut state_animation_rate,
1994 skeleton_attr,
1995 )
1996 } else if *is_sneaking {
1997 anim::character::SneakWieldAnimation::update_skeleton(
1998 &target_base,
1999 (
2000 (active_tool_kind, active_tool_spec),
2001 second_tool_kind,
2002 hands,
2003 rel_vel,
2004 ori * anim::vek::Vec3::<f32>::unit_y(),
2006 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2007 time,
2008 ),
2009 state.state_time,
2010 &mut state_animation_rate,
2011 skeleton_attr,
2012 )
2013 } else {
2014 anim::character::WieldAnimation::update_skeleton(
2015 &target_base,
2016 (
2017 (active_tool_kind, active_tool_spec),
2018 second_tool_kind,
2019 hands,
2020 ori * anim::vek::Vec3::<f32>::unit_y(),
2022 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2023 look_dir,
2024 rel_vel,
2025 is_riding,
2026 time,
2027 ),
2028 state.state_time,
2029 &mut state_animation_rate,
2030 skeleton_attr,
2031 )
2032 }
2033 },
2034 CharacterState::Glide(data) => {
2035 anim::character::GlidingAnimation::update_skeleton(
2036 &target_base,
2037 (rel_vel, ori, data.ori.into(), time, state.acc_vel),
2038 state.state_time,
2039 &mut state_animation_rate,
2040 skeleton_attr,
2041 )
2042 },
2043 CharacterState::Climb { .. } => {
2044 anim::character::ClimbAnimation::update_skeleton(
2045 &target_base,
2046 (
2047 active_tool_kind,
2048 second_tool_kind,
2049 rel_vel,
2050 ori * anim::vek::Vec3::<f32>::unit_y(),
2052 time,
2053 ),
2054 state.state_time,
2055 &mut state_animation_rate,
2056 skeleton_attr,
2057 )
2058 },
2059 CharacterState::Sit => anim::character::SitAnimation::update_skeleton(
2060 &target_base,
2061 (active_tool_kind, second_tool_kind, time),
2062 state.state_time,
2063 &mut state_animation_rate,
2064 skeleton_attr,
2065 ),
2066 CharacterState::Crawl => {
2067 anim::character::CrawlAnimation::update_skeleton(
2068 &target_base,
2069 (
2070 rel_vel,
2071 ori * anim::vek::Vec3::<f32>::unit_y(),
2073 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2074 time,
2075 ),
2076 state.state_time,
2077 &mut state_animation_rate,
2078 skeleton_attr,
2079 )
2080 },
2081 CharacterState::GlideWield(data) => {
2082 anim::character::GlideWieldAnimation::update_skeleton(
2083 &target_base,
2084 (ori, data.ori.into()),
2085 state.state_time,
2086 &mut state_animation_rate,
2087 skeleton_attr,
2088 )
2089 },
2090 CharacterState::Wallrun(data) => {
2091 anim::character::WallrunAnimation::update_skeleton(
2092 &target_base,
2093 (
2094 (active_tool_kind, active_tool_spec),
2095 second_tool_kind,
2096 hands,
2097 ori * anim::vek::Vec3::<f32>::unit_y(),
2098 state.acc_vel,
2099 wall_dir,
2100 data.was_wielded,
2101 ),
2102 state.state_time,
2103 &mut state_animation_rate,
2104 skeleton_attr,
2105 )
2106 },
2107 CharacterState::Dance => anim::character::DanceAnimation::update_skeleton(
2108 &target_base,
2109 (active_tool_kind, second_tool_kind, time),
2110 state.state_time,
2111 &mut state_animation_rate,
2112 skeleton_attr,
2113 ),
2114 CharacterState::Music(s) => anim::character::MusicAnimation::update_skeleton(
2115 &target_base,
2116 (
2117 hands,
2118 (Some(s.static_data.ability_info), time),
2119 rel_vel,
2120 ability_id,
2121 ),
2122 state.state_time,
2123 &mut state_animation_rate,
2124 skeleton_attr,
2125 ),
2126 _ => target_base,
2127 };
2128
2129 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, data.dt_lerp);
2130 state.update(
2131 renderer,
2132 trail_mgr,
2133 update_buf,
2134 &common_params,
2135 state_animation_rate,
2136 model,
2137 body,
2138 );
2139 },
2140 Body::QuadrupedSmall(body) => {
2141 let (model, skeleton_attr) = self.quadruped_small_model_cache.get_or_create_model(
2142 renderer,
2143 &mut self.atlas,
2144 body,
2145 inventory,
2146 (),
2147 data.tick,
2148 viewpoint_camera_mode,
2149 viewpoint_character_state,
2150 slow_jobs,
2151 None,
2152 );
2153
2154 let state = self
2155 .states
2156 .quadruped_small_states
2157 .entry(entity)
2158 .or_insert_with(|| {
2159 FigureState::new(renderer, QuadrupedSmallSkeleton::default(), body)
2160 });
2161
2162 let rel_avg_vel = state.avg_vel - physics.ground_vel;
2164
2165 let (character, last_character) = match (character, last_character) {
2166 (Some(c), Some(l)) => (c, l),
2167 _ => return,
2168 };
2169
2170 if !character.same_variant(&last_character.0) {
2171 state.state_time = 0.0;
2172 }
2173
2174 let target_base = match (
2175 physics.on_ground.is_some(),
2176 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
2179 (true, false, false) => anim::quadruped_small::IdleAnimation::update_skeleton(
2181 &QuadrupedSmallSkeleton::default(),
2182 time,
2183 state.state_time,
2184 &mut state_animation_rate,
2185 skeleton_attr,
2186 ),
2187 (true, true, false) => {
2189 anim::quadruped_small::RunAnimation::update_skeleton(
2190 &QuadrupedSmallSkeleton::default(),
2191 (
2192 rel_vel.magnitude(),
2193 ori * anim::vek::Vec3::<f32>::unit_y(),
2195 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2196 time,
2197 rel_avg_vel,
2198 state.acc_vel,
2199 ),
2200 state.state_time,
2201 &mut state_animation_rate,
2202 skeleton_attr,
2203 )
2204 },
2205 (_, _, true) => anim::quadruped_small::RunAnimation::update_skeleton(
2207 &QuadrupedSmallSkeleton::default(),
2208 (
2209 rel_vel.magnitude(),
2210 ori * anim::vek::Vec3::<f32>::unit_y(),
2212 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2213 time,
2214 rel_avg_vel,
2215 state.acc_vel,
2216 ),
2217 state.state_time,
2218 &mut state_animation_rate,
2219 skeleton_attr,
2220 ),
2221 (false, _, false) => anim::quadruped_small::RunAnimation::update_skeleton(
2223 &QuadrupedSmallSkeleton::default(),
2224 (
2225 rel_vel.magnitude(),
2226 ori * anim::vek::Vec3::<f32>::unit_y(),
2228 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2229 time,
2230 rel_avg_vel,
2231 state.acc_vel,
2232 ),
2233 state.state_time,
2234 &mut state_animation_rate,
2235 skeleton_attr,
2236 ),
2237 };
2238 let target_bones = match &character {
2239 CharacterState::BasicMelee(s) => {
2240 let stage_time = s.timer.as_secs_f32();
2241
2242 let stage_progress = match s.stage_section {
2243 StageSection::Buildup => {
2244 stage_time / s.static_data.buildup_duration.as_secs_f32()
2245 },
2246 StageSection::Action => {
2247 stage_time / s.static_data.swing_duration.as_secs_f32()
2248 },
2249 StageSection::Recover => {
2250 stage_time / s.static_data.recover_duration.as_secs_f32()
2251 },
2252
2253 _ => 0.0,
2254 };
2255 anim::quadruped_small::AlphaAnimation::update_skeleton(
2256 &target_base,
2257 (time, s.stage_section, state.state_time),
2258 stage_progress,
2259 &mut state_animation_rate,
2260 skeleton_attr,
2261 )
2262 },
2263 CharacterState::ComboMelee2(s) => {
2264 let timer = s.timer.as_secs_f32();
2265 let current_strike = s.completed_strikes % s.static_data.strikes.len();
2266 let strike_data = s.static_data.strikes[current_strike];
2267 let progress = match s.stage_section {
2268 StageSection::Buildup => {
2269 timer / strike_data.buildup_duration.as_secs_f32()
2270 },
2271 StageSection::Action => {
2272 timer / strike_data.swing_duration.as_secs_f32()
2273 },
2274 StageSection::Recover => {
2275 timer / strike_data.recover_duration.as_secs_f32()
2276 },
2277 _ => 0.0,
2278 };
2279
2280 anim::quadruped_small::ComboAnimation::update_skeleton(
2281 &target_base,
2282 (
2283 ability_id,
2284 Some(s.stage_section),
2285 Some(s.static_data.ability_info),
2286 current_strike,
2287 time,
2288 state.state_time,
2289 ),
2290 progress,
2291 &mut state_animation_rate,
2292 skeleton_attr,
2293 )
2294 },
2295 CharacterState::Stunned(s) => {
2296 let stage_time = s.timer.as_secs_f32();
2297 let stage_progress = match s.stage_section {
2298 StageSection::Buildup => {
2299 stage_time / s.static_data.buildup_duration.as_secs_f32()
2300 },
2301 StageSection::Recover => {
2302 stage_time / s.static_data.recover_duration.as_secs_f32()
2303 },
2304 _ => 0.0,
2305 };
2306 match s.static_data.poise_state {
2307 PoiseState::Normal
2308 | PoiseState::Interrupted
2309 | PoiseState::Stunned
2310 | PoiseState::Dazed
2311 | PoiseState::KnockedDown => {
2312 anim::quadruped_small::StunnedAnimation::update_skeleton(
2313 &target_base,
2314 (
2315 rel_vel.magnitude(),
2316 time,
2317 Some(s.stage_section),
2318 state.state_time,
2319 ),
2320 stage_progress,
2321 &mut state_animation_rate,
2322 skeleton_attr,
2323 )
2324 },
2325 }
2326 },
2327 CharacterState::Sit => anim::quadruped_small::FeedAnimation::update_skeleton(
2328 &target_base,
2329 time,
2330 state.state_time,
2331 &mut state_animation_rate,
2332 skeleton_attr,
2333 ),
2334 CharacterState::Shockwave(s) => {
2335 let stage_time = s.timer.as_secs_f32();
2336 let stage_progress = match s.stage_section {
2337 StageSection::Buildup => {
2338 stage_time / s.static_data.buildup_duration.as_secs_f32()
2339 },
2340 StageSection::Charge => stage_time,
2341 StageSection::Action => {
2342 stage_time / s.static_data.swing_duration.as_secs_f32()
2343 },
2344 StageSection::Recover => {
2345 stage_time / s.static_data.recover_duration.as_secs_f32()
2346 },
2347 _ => 0.0,
2348 };
2349 anim::quadruped_small::ShockwaveAnimation::update_skeleton(
2350 &target_base,
2351 (
2352 rel_vel.magnitude(),
2353 time,
2354 Some(s.stage_section),
2355 state.state_time,
2356 ),
2357 stage_progress,
2358 &mut state_animation_rate,
2359 skeleton_attr,
2360 )
2361 },
2362 _ => target_base,
2364 };
2365
2366 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
2367 state.update(
2368 renderer,
2369 trail_mgr,
2370 update_buf,
2371 &common_params,
2372 state_animation_rate,
2373 model,
2374 body,
2375 );
2376 },
2377 Body::QuadrupedMedium(body) => {
2378 let (model, skeleton_attr) = self.quadruped_medium_model_cache.get_or_create_model(
2379 renderer,
2380 &mut self.atlas,
2381 body,
2382 inventory,
2383 (),
2384 tick,
2385 viewpoint_camera_mode,
2386 viewpoint_character_state,
2387 slow_jobs,
2388 None,
2389 );
2390
2391 let state = self
2392 .states
2393 .quadruped_medium_states
2394 .entry(entity)
2395 .or_insert_with(|| {
2396 FigureState::new(renderer, QuadrupedMediumSkeleton::default(), body)
2397 });
2398
2399 let rel_avg_vel = state.avg_vel - physics.ground_vel;
2401
2402 let (character, last_character) = match (character, last_character) {
2403 (Some(c), Some(l)) => (c, l),
2404 _ => return,
2405 };
2406
2407 if !character.same_variant(&last_character.0) {
2408 state.state_time = 0.0;
2409 }
2410
2411 let target_base = match (
2412 physics.on_ground.is_some(),
2413 rel_vel.magnitude_squared() > 0.25, physics.in_liquid().is_some(), ) {
2416 (true, false, false) => anim::quadruped_medium::IdleAnimation::update_skeleton(
2418 &QuadrupedMediumSkeleton::default(),
2419 time,
2420 state.state_time,
2421 &mut state_animation_rate,
2422 skeleton_attr,
2423 ),
2424 (true, true, false) => {
2426 anim::quadruped_medium::RunAnimation::update_skeleton(
2427 &QuadrupedMediumSkeleton::default(),
2428 (
2429 rel_vel.magnitude(),
2430 ori * anim::vek::Vec3::<f32>::unit_y(),
2432 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2433 time,
2434 rel_avg_vel,
2435 state.acc_vel,
2436 ),
2437 state.state_time,
2438 &mut state_animation_rate,
2439 skeleton_attr,
2440 )
2441 },
2442 (_, _, true) => anim::quadruped_medium::RunAnimation::update_skeleton(
2444 &QuadrupedMediumSkeleton::default(),
2445 (
2446 rel_vel.magnitude(),
2447 ori * anim::vek::Vec3::<f32>::unit_y(),
2449 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2450 time,
2451 rel_avg_vel,
2452 state.acc_vel,
2453 ),
2454 state.state_time,
2455 &mut state_animation_rate,
2456 skeleton_attr,
2457 ),
2458 (false, _, false) => anim::quadruped_medium::JumpAnimation::update_skeleton(
2460 &QuadrupedMediumSkeleton::default(),
2461 (time, rel_vel, rel_avg_vel),
2462 state.state_time,
2463 &mut state_animation_rate,
2464 skeleton_attr,
2465 ),
2466 };
2467 let target_bones = match &character {
2468 CharacterState::BasicMelee(s) => {
2469 let stage_time = s.timer.as_secs_f32();
2470
2471 let stage_progress = match s.stage_section {
2472 StageSection::Buildup => {
2473 stage_time / s.static_data.buildup_duration.as_secs_f32()
2474 },
2475 StageSection::Action => {
2476 stage_time / s.static_data.swing_duration.as_secs_f32()
2477 },
2478 StageSection::Recover => {
2479 stage_time / s.static_data.recover_duration.as_secs_f32()
2480 },
2481
2482 _ => 0.0,
2483 };
2484 anim::quadruped_medium::HoofAnimation::update_skeleton(
2485 &target_base,
2486 (
2487 rel_vel.magnitude(),
2488 time,
2489 Some(s.stage_section),
2490 state.state_time,
2491 ),
2492 stage_progress,
2493 &mut state_animation_rate,
2494 skeleton_attr,
2495 )
2496 },
2497 CharacterState::DashMelee(s) => {
2498 let stage_time = s.timer.as_secs_f32();
2499 let stage_progress = match s.stage_section {
2500 StageSection::Buildup => {
2501 stage_time / s.static_data.buildup_duration.as_secs_f32()
2502 },
2503 StageSection::Charge => stage_time,
2504 StageSection::Action => {
2505 stage_time / s.static_data.swing_duration.as_secs_f32()
2506 },
2507 StageSection::Recover => {
2508 stage_time / s.static_data.recover_duration.as_secs_f32()
2509 },
2510 _ => 0.0,
2511 };
2512 anim::quadruped_medium::DashAnimation::update_skeleton(
2513 &target_base,
2514 (
2515 rel_vel.magnitude(),
2516 time,
2517 Some(s.stage_section),
2518 state.state_time,
2519 ),
2520 stage_progress,
2521 &mut state_animation_rate,
2522 skeleton_attr,
2523 )
2524 },
2525 CharacterState::Shockwave(s) => {
2526 let stage_time = s.timer.as_secs_f32();
2527 let stage_progress = match s.stage_section {
2528 StageSection::Buildup => {
2529 stage_time / s.static_data.buildup_duration.as_secs_f32()
2530 },
2531 StageSection::Charge => stage_time,
2532 StageSection::Action => {
2533 stage_time / s.static_data.swing_duration.as_secs_f32()
2534 },
2535 StageSection::Recover => {
2536 stage_time / s.static_data.recover_duration.as_secs_f32()
2537 },
2538 _ => 0.0,
2539 };
2540 anim::quadruped_medium::ShockwaveAnimation::update_skeleton(
2541 &target_base,
2542 (
2543 rel_vel.magnitude(),
2544 time,
2545 Some(s.stage_section),
2546 state.state_time,
2547 ),
2548 stage_progress,
2549 &mut state_animation_rate,
2550 skeleton_attr,
2551 )
2552 },
2553 CharacterState::LeapMelee(s) => {
2554 let stage_time = s.timer.as_secs_f32();
2555 let stage_progress = match s.stage_section {
2556 StageSection::Buildup => {
2557 stage_time / s.static_data.buildup_duration.as_secs_f32()
2558 },
2559 StageSection::Movement => {
2560 stage_time / s.static_data.movement_duration.as_secs_f32()
2561 },
2562 StageSection::Action => {
2563 stage_time / s.static_data.swing_duration.as_secs_f32()
2564 },
2565 StageSection::Recover => {
2566 stage_time / s.static_data.recover_duration.as_secs_f32()
2567 },
2568 _ => 0.0,
2569 };
2570 anim::quadruped_medium::LeapMeleeAnimation::update_skeleton(
2571 &target_base,
2572 (
2573 rel_vel.magnitude(),
2574 time,
2575 Some(s.stage_section),
2576 state.state_time,
2577 ),
2578 stage_progress,
2579 &mut state_animation_rate,
2580 skeleton_attr,
2581 )
2582 },
2583 CharacterState::ComboMelee2(s) => {
2584 let timer = s.timer.as_secs_f32();
2585 let current_strike = s.completed_strikes % s.static_data.strikes.len();
2586 let strike_data = s.static_data.strikes[current_strike];
2587 let progress = match s.stage_section {
2588 StageSection::Buildup => {
2589 timer / strike_data.buildup_duration.as_secs_f32()
2590 },
2591 StageSection::Action => {
2592 timer / strike_data.swing_duration.as_secs_f32()
2593 },
2594 StageSection::Recover => {
2595 timer / strike_data.recover_duration.as_secs_f32()
2596 },
2597 _ => 0.0,
2598 };
2599
2600 anim::quadruped_medium::ComboAnimation::update_skeleton(
2601 &target_base,
2602 (
2603 ability_id,
2604 s.stage_section,
2605 current_strike,
2606 rel_vel.magnitude(),
2607 time,
2608 state.state_time,
2609 ),
2610 progress,
2611 &mut state_animation_rate,
2612 skeleton_attr,
2613 )
2614 },
2615 CharacterState::Stunned(s) => {
2616 let stage_time = s.timer.as_secs_f32();
2617 let stage_progress = match s.stage_section {
2618 StageSection::Buildup => {
2619 stage_time / s.static_data.buildup_duration.as_secs_f32()
2620 },
2621 StageSection::Recover => {
2622 stage_time / s.static_data.recover_duration.as_secs_f32()
2623 },
2624 _ => 0.0,
2625 };
2626 match s.static_data.poise_state {
2627 PoiseState::Normal | PoiseState::Stunned | PoiseState::Interrupted => {
2628 anim::quadruped_medium::StunnedAnimation::update_skeleton(
2629 &target_base,
2630 (
2631 rel_vel.magnitude(),
2632 time,
2633 Some(s.stage_section),
2634 state.state_time,
2635 ),
2636 stage_progress,
2637 &mut state_animation_rate,
2638 skeleton_attr,
2639 )
2640 },
2641 PoiseState::Dazed | PoiseState::KnockedDown => {
2642 anim::quadruped_medium::StunnedAnimation::update_skeleton(
2643 &target_base,
2644 (
2645 rel_vel.magnitude(),
2646 time,
2647 Some(s.stage_section),
2648 state.state_time,
2649 ),
2650 stage_progress,
2651 &mut state_animation_rate,
2652 skeleton_attr,
2653 )
2654 },
2655 }
2656 },
2657 CharacterState::Sit => anim::quadruped_medium::FeedAnimation::update_skeleton(
2658 &target_base,
2659 time,
2660 state.state_time,
2661 &mut state_animation_rate,
2662 skeleton_attr,
2663 ),
2664 _ => target_base,
2666 };
2667
2668 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
2669 state.update(
2670 renderer,
2671 trail_mgr,
2672 update_buf,
2673 &common_params,
2674 state_animation_rate,
2675 model,
2676 body,
2677 );
2678 },
2679 Body::QuadrupedLow(body) => {
2680 let (model, skeleton_attr) = self.quadruped_low_model_cache.get_or_create_model(
2681 renderer,
2682 &mut self.atlas,
2683 body,
2684 inventory,
2685 (),
2686 data.tick,
2687 viewpoint_camera_mode,
2688 viewpoint_character_state,
2689 slow_jobs,
2690 None,
2691 );
2692
2693 let state = self
2694 .states
2695 .quadruped_low_states
2696 .entry(entity)
2697 .or_insert_with(|| {
2698 FigureState::new(renderer, QuadrupedLowSkeleton::default(), body)
2699 });
2700
2701 let rel_avg_vel = state.avg_vel - physics.ground_vel;
2703
2704 let (character, last_character) = match (character, last_character) {
2705 (Some(c), Some(l)) => (c, l),
2706 _ => return,
2707 };
2708
2709 if !character.same_variant(&last_character.0) {
2710 state.state_time = 0.0;
2711 }
2712
2713 let heads = heads
2714 .and_then(|heads| {
2715 let res = heads.heads().try_into().ok();
2716
2717 if res.is_none() {
2718 tracing::error!(
2719 "Server sent another amount of heads than 3 for a QuadrupedLow \
2720 body"
2721 );
2722 }
2723 res
2724 })
2725 .unwrap_or([
2726 HeadState::Attached,
2727 HeadState::Attached,
2728 HeadState::Attached,
2729 ]);
2730
2731 let target_base = match (
2732 physics.on_ground.is_some(),
2733 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
2736 (true, false, false) => anim::quadruped_low::IdleAnimation::update_skeleton(
2738 &QuadrupedLowSkeleton::default(),
2739 (time, heads),
2740 state.state_time,
2741 &mut state_animation_rate,
2742 skeleton_attr,
2743 ),
2744 (true, true, false) => anim::quadruped_low::RunAnimation::update_skeleton(
2746 &QuadrupedLowSkeleton::default(),
2747 (
2748 rel_vel.magnitude(),
2749 ori * anim::vek::Vec3::<f32>::unit_y(),
2751 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2752 time,
2753 rel_avg_vel,
2754 state.acc_vel,
2755 heads,
2756 ),
2757 state.state_time,
2758 &mut state_animation_rate,
2759 skeleton_attr,
2760 ),
2761 (_, _, true) => anim::quadruped_low::RunAnimation::update_skeleton(
2763 &QuadrupedLowSkeleton::default(),
2764 (
2765 rel_vel.magnitude(),
2766 ori * anim::vek::Vec3::<f32>::unit_y(),
2768 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2769 time,
2770 rel_avg_vel,
2771 state.acc_vel,
2772 heads,
2773 ),
2774 state.state_time,
2775 &mut state_animation_rate,
2776 skeleton_attr,
2777 ),
2778 (false, _, false) => anim::quadruped_low::RunAnimation::update_skeleton(
2780 &QuadrupedLowSkeleton::default(),
2781 (
2782 rel_vel.magnitude(),
2783 ori * anim::vek::Vec3::<f32>::unit_y(),
2785 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
2786 time,
2787 rel_avg_vel,
2788 state.acc_vel,
2789 heads,
2790 ),
2791 state.state_time,
2792 &mut state_animation_rate,
2793 skeleton_attr,
2794 ),
2795 };
2796 let target_bones = match &character {
2797 CharacterState::BasicRanged(s) => {
2798 let stage_time = s.timer.as_secs_f32();
2799
2800 let stage_progress = match s.stage_section {
2801 StageSection::Buildup => {
2802 stage_time / s.static_data.buildup_duration.as_secs_f32()
2803 },
2804 StageSection::Recover => {
2805 stage_time / s.static_data.recover_duration.as_secs_f32()
2806 },
2807
2808 _ => 0.0,
2809 };
2810 anim::quadruped_low::ShootAnimation::update_skeleton(
2811 &target_base,
2812 (ability_id, rel_vel.magnitude(), time, Some(s.stage_section)),
2813 stage_progress,
2814 &mut state_animation_rate,
2815 skeleton_attr,
2816 )
2817 },
2818 CharacterState::Shockwave(s) => {
2819 let stage_time = s.timer.as_secs_f32();
2820 let stage_progress = match s.stage_section {
2821 StageSection::Buildup => {
2822 stage_time / s.static_data.buildup_duration.as_secs_f32()
2823 },
2824 StageSection::Charge => stage_time,
2825 StageSection::Action => {
2826 stage_time / s.static_data.swing_duration.as_secs_f32()
2827 },
2828 StageSection::Recover => {
2829 stage_time / s.static_data.recover_duration.as_secs_f32()
2830 },
2831 _ => 0.0,
2832 };
2833 anim::quadruped_low::ShockwaveAnimation::update_skeleton(
2834 &target_base,
2835 (
2836 rel_vel.magnitude(),
2837 time,
2838 Some(s.stage_section),
2839 state.state_time,
2840 ),
2841 stage_progress,
2842 &mut state_animation_rate,
2843 skeleton_attr,
2844 )
2845 },
2846 CharacterState::SpriteSummon(s) => {
2847 let stage_time = s.timer.as_secs_f32();
2848 let stage_progress = match s.stage_section {
2849 StageSection::Buildup => {
2850 stage_time / s.static_data.buildup_duration.as_secs_f32()
2851 },
2852 StageSection::Action => {
2853 stage_time / s.static_data.cast_duration.as_secs_f32()
2854 },
2855 StageSection::Recover => {
2856 stage_time / s.static_data.recover_duration.as_secs_f32()
2857 },
2858 _ => 0.0,
2859 };
2860 anim::quadruped_low::SpriteSummonAnimation::update_skeleton(
2861 &target_base,
2862 (
2863 rel_vel.magnitude(),
2864 time,
2865 Some(s.stage_section),
2866 state.state_time,
2867 ),
2868 stage_progress,
2869 &mut state_animation_rate,
2870 skeleton_attr,
2871 )
2872 },
2873 CharacterState::BasicMelee(s) => {
2874 let stage_time = s.timer.as_secs_f32();
2875
2876 let stage_progress = match s.stage_section {
2877 StageSection::Buildup => {
2878 stage_time / s.static_data.buildup_duration.as_secs_f32()
2879 },
2880 StageSection::Action => {
2881 stage_time / s.static_data.swing_duration.as_secs_f32()
2882 },
2883 StageSection::Recover => {
2884 stage_time / s.static_data.recover_duration.as_secs_f32()
2885 },
2886
2887 _ => 0.0,
2888 };
2889 anim::quadruped_low::BetaAnimation::update_skeleton(
2890 &target_base,
2891 (rel_vel.magnitude(), time, s.stage_section, state.state_time),
2892 stage_progress,
2893 &mut state_animation_rate,
2894 skeleton_attr,
2895 )
2896 },
2897
2898 CharacterState::ChargedMelee(s) => {
2899 let stage_time = s.timer.as_secs_f32();
2900
2901 let stage_progress = match s.stage_section {
2902 StageSection::Buildup => {
2903 if let Some((dur, _)) = s.static_data.buildup_strike {
2904 stage_time / dur.as_secs_f32()
2905 } else {
2906 stage_time
2907 }
2908 },
2909 StageSection::Charge => {
2910 stage_time / s.static_data.charge_duration.as_secs_f32()
2911 },
2912 StageSection::Action => {
2913 stage_time / s.static_data.swing_duration.as_secs_f32()
2914 },
2915 StageSection::Recover => {
2916 stage_time / s.static_data.recover_duration.as_secs_f32()
2917 },
2918
2919 _ => 0.0,
2920 };
2921 anim::quadruped_low::TailwhipAnimation::update_skeleton(
2922 &target_base,
2923 (
2924 ability_id,
2925 rel_vel.magnitude(),
2926 time,
2927 Some(s.stage_section),
2928 state.state_time,
2929 ),
2930 stage_progress,
2931 &mut state_animation_rate,
2932 skeleton_attr,
2933 )
2934 },
2935 CharacterState::Stunned(s) => {
2936 let stage_time = s.timer.as_secs_f32();
2937 let stage_progress = match s.stage_section {
2938 StageSection::Buildup => {
2939 stage_time / s.static_data.buildup_duration.as_secs_f32()
2940 },
2941 StageSection::Recover => {
2942 stage_time / s.static_data.recover_duration.as_secs_f32()
2943 },
2944 _ => 0.0,
2945 };
2946 match s.static_data.poise_state {
2947 PoiseState::Normal | PoiseState::Stunned | PoiseState::Interrupted => {
2948 anim::quadruped_low::StunnedAnimation::update_skeleton(
2949 &target_base,
2950 (
2951 rel_vel.magnitude(),
2952 time,
2953 Some(s.stage_section),
2954 state.state_time,
2955 ),
2956 stage_progress,
2957 &mut state_animation_rate,
2958 skeleton_attr,
2959 )
2960 },
2961 PoiseState::Dazed | PoiseState::KnockedDown => {
2962 anim::quadruped_low::StunnedAnimation::update_skeleton(
2963 &target_base,
2964 (
2965 rel_vel.magnitude(),
2966 time,
2967 Some(s.stage_section),
2968 state.state_time,
2969 ),
2970 stage_progress,
2971 &mut state_animation_rate,
2972 skeleton_attr,
2973 )
2974 },
2975 }
2976 },
2977 CharacterState::ComboMelee2(s) => {
2978 let timer = s.timer.as_secs_f32();
2979 let current_strike = s.completed_strikes % s.static_data.strikes.len();
2980 let strike_data = s.static_data.strikes[current_strike];
2981 let progress = match s.stage_section {
2982 StageSection::Buildup => {
2983 timer / strike_data.buildup_duration.as_secs_f32()
2984 },
2985 StageSection::Action => {
2986 timer / strike_data.swing_duration.as_secs_f32()
2987 },
2988 StageSection::Recover => {
2989 timer / strike_data.recover_duration.as_secs_f32()
2990 },
2991 _ => 0.0,
2992 };
2993
2994 anim::quadruped_low::ComboAnimation::update_skeleton(
2995 &target_base,
2996 (
2997 ability_id,
2998 s.stage_section,
2999 current_strike,
3000 time,
3001 state.state_time,
3002 ),
3003 progress,
3004 &mut state_animation_rate,
3005 skeleton_attr,
3006 )
3007 },
3008 CharacterState::BasicBeam(s) => {
3009 let stage_time = s.timer.as_secs_f32();
3010 let stage_progress = match s.stage_section {
3011 StageSection::Buildup => {
3012 stage_time / s.static_data.buildup_duration.as_secs_f32()
3013 },
3014 StageSection::Action => s.timer.as_secs_f32(),
3015 StageSection::Recover => {
3016 stage_time / s.static_data.recover_duration.as_secs_f32()
3017 },
3018 _ => 0.0,
3019 };
3020 anim::quadruped_low::BreatheAnimation::update_skeleton(
3021 &target_base,
3022 (
3023 rel_vel.magnitude(),
3024 time,
3025 Some(s.stage_section),
3026 state.state_time,
3027 ),
3028 stage_progress,
3029 &mut state_animation_rate,
3030 skeleton_attr,
3031 )
3032 },
3033 CharacterState::DashMelee(s) => {
3034 let stage_time = s.timer.as_secs_f32();
3035 let stage_progress = match s.stage_section {
3036 StageSection::Buildup => {
3037 stage_time / s.static_data.buildup_duration.as_secs_f32()
3038 },
3039 StageSection::Charge => stage_time,
3040 StageSection::Action => {
3041 stage_time / s.static_data.swing_duration.as_secs_f32()
3042 },
3043 StageSection::Recover => {
3044 stage_time / s.static_data.recover_duration.as_secs_f32()
3045 },
3046 _ => 0.0,
3047 };
3048 anim::quadruped_low::DashAnimation::update_skeleton(
3049 &target_base,
3050 (
3051 ability_id,
3052 rel_vel.magnitude(),
3053 time,
3054 Some(s.stage_section),
3055 state.state_time,
3056 heads,
3057 ),
3058 stage_progress,
3059 &mut state_animation_rate,
3060 skeleton_attr,
3061 )
3062 },
3063 CharacterState::LeapShockwave(s) => {
3064 let stage_time = s.timer.as_secs_f32();
3065 let stage_progress = match s.stage_section {
3066 StageSection::Buildup => {
3067 stage_time / s.static_data.buildup_duration.as_secs_f32()
3068 },
3069 StageSection::Movement => {
3070 stage_time / s.static_data.buildup_duration.as_secs_f32()
3071 },
3072 StageSection::Action => {
3073 stage_time / s.static_data.swing_duration.as_secs_f32()
3074 },
3075 StageSection::Recover => {
3076 stage_time / s.static_data.recover_duration.as_secs_f32()
3077 },
3078 _ => 0.0,
3079 };
3080 anim::quadruped_low::LeapShockAnimation::update_skeleton(
3081 &target_base,
3082 (ability_id, rel_vel, time, Some(s.stage_section), heads),
3083 stage_progress,
3084 &mut state_animation_rate,
3085 skeleton_attr,
3086 )
3087 },
3088 _ => target_base,
3090 };
3091
3092 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
3093 state.update(
3094 renderer,
3095 trail_mgr,
3096 update_buf,
3097 &common_params,
3098 state_animation_rate,
3099 model,
3100 body,
3101 );
3102 },
3103 Body::BirdMedium(body) => {
3104 let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model(
3105 renderer,
3106 &mut self.atlas,
3107 body,
3108 inventory,
3109 (),
3110 tick,
3111 viewpoint_camera_mode,
3112 viewpoint_character_state,
3113 slow_jobs,
3114 None,
3115 );
3116
3117 let state = self
3118 .states
3119 .bird_medium_states
3120 .entry(entity)
3121 .or_insert_with(|| {
3122 FigureState::new(renderer, BirdMediumSkeleton::default(), body)
3123 });
3124
3125 let rel_avg_vel = state.avg_vel - physics.ground_vel;
3127
3128 let (character, last_character) = match (character, last_character) {
3129 (Some(c), Some(l)) => (c, l),
3130 _ => return,
3131 };
3132
3133 if !character.same_variant(&last_character.0) {
3134 state.state_time = 0.0;
3135 }
3136
3137 let target_base = match (
3138 physics.on_ground.is_some(),
3139 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), is_rider.is_some() || is_volume_rider.is_some(),
3142 ) {
3143 (true, false, false, _) => anim::bird_medium::IdleAnimation::update_skeleton(
3145 &BirdMediumSkeleton::default(),
3146 time,
3147 state.state_time,
3148 &mut state_animation_rate,
3149 skeleton_attr,
3150 ),
3151 (true, true, false, false) => {
3153 anim::bird_medium::RunAnimation::update_skeleton(
3154 &BirdMediumSkeleton::default(),
3155 (
3156 rel_vel,
3157 ori * anim::vek::Vec3::<f32>::unit_y(),
3159 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3160 rel_avg_vel,
3161 state.acc_vel,
3162 ),
3163 state.state_time,
3164 &mut state_animation_rate,
3165 skeleton_attr,
3166 )
3167 },
3168 (false, _, false, false) => {
3170 anim::bird_medium::FlyAnimation::update_skeleton(
3171 &BirdMediumSkeleton::default(),
3172 (
3173 rel_vel,
3174 ori * anim::vek::Vec3::<f32>::unit_y(),
3176 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3177 ),
3178 state.state_time,
3179 &mut state_animation_rate,
3180 skeleton_attr,
3181 )
3182 },
3183 (_, true, _, false) => anim::bird_medium::SwimAnimation::update_skeleton(
3185 &BirdMediumSkeleton::default(),
3186 time,
3187 state.state_time,
3188 &mut state_animation_rate,
3189 skeleton_attr,
3190 ),
3191 _ => anim::bird_medium::IdleAnimation::update_skeleton(
3193 &BirdMediumSkeleton::default(),
3194 time,
3195 state.state_time,
3196 &mut state_animation_rate,
3197 skeleton_attr,
3198 ),
3199 };
3200 let target_bones = match &character {
3201 CharacterState::Sit => anim::bird_medium::FeedAnimation::update_skeleton(
3202 &target_base,
3203 time,
3204 state.state_time,
3205 &mut state_animation_rate,
3206 skeleton_attr,
3207 ),
3208 CharacterState::BasicBeam(s) => {
3209 let stage_time = s.timer.as_secs_f32();
3210 let stage_progress = match s.stage_section {
3211 StageSection::Buildup => {
3212 stage_time / s.static_data.buildup_duration.as_secs_f32()
3213 },
3214 StageSection::Action => s.timer.as_secs_f32(),
3215 StageSection::Recover => {
3216 stage_time / s.static_data.recover_duration.as_secs_f32()
3217 },
3218 _ => 0.0,
3219 };
3220 anim::bird_medium::BreatheAnimation::update_skeleton(
3221 &target_base,
3222 (
3223 rel_vel,
3224 time,
3225 ori * anim::vek::Vec3::<f32>::unit_y(),
3226 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3227 Some(s.stage_section),
3228 state.state_time,
3229 look_dir,
3230 physics.on_ground.is_some(),
3231 ),
3232 stage_progress,
3233 &mut state_animation_rate,
3234 skeleton_attr,
3235 )
3236 },
3237 CharacterState::BasicMelee(s) => {
3238 let stage_time = s.timer.as_secs_f32();
3239 let stage_progress = match s.stage_section {
3240 StageSection::Buildup => {
3241 stage_time / s.static_data.buildup_duration.as_secs_f32()
3242 },
3243 StageSection::Action => {
3244 stage_time / s.static_data.swing_duration.as_secs_f32()
3245 },
3246 StageSection::Recover => {
3247 stage_time / s.static_data.recover_duration.as_secs_f32()
3248 },
3249 _ => 0.0,
3250 };
3251 anim::bird_medium::AlphaAnimation::update_skeleton(
3252 &target_base,
3253 (
3254 Some(s.stage_section),
3255 time,
3256 state.state_time,
3257 ori * anim::vek::Vec3::<f32>::unit_y(),
3258 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3259 physics.on_ground.is_some(),
3260 ),
3261 stage_progress,
3262 &mut state_animation_rate,
3263 skeleton_attr,
3264 )
3265 },
3266 CharacterState::BasicRanged(s) => {
3267 let stage_time = s.timer.as_secs_f32();
3268
3269 let stage_progress = match s.stage_section {
3270 StageSection::Buildup => {
3271 stage_time / s.static_data.buildup_duration.as_secs_f32()
3272 },
3273 StageSection::Recover => {
3274 stage_time / s.static_data.recover_duration.as_secs_f32()
3275 },
3276
3277 _ => 0.0,
3278 };
3279 anim::bird_medium::ShootAnimation::update_skeleton(
3280 &target_base,
3281 (
3282 rel_vel,
3283 time,
3284 Some(s.stage_section),
3285 state.state_time,
3286 look_dir,
3287 physics.on_ground.is_some(),
3288 ),
3289 stage_progress,
3290 &mut state_animation_rate,
3291 skeleton_attr,
3292 )
3293 },
3294 CharacterState::Shockwave(s) => {
3295 let stage_time = s.timer.as_secs_f32();
3296 let stage_progress = match s.stage_section {
3297 StageSection::Buildup => {
3298 stage_time / s.static_data.buildup_duration.as_secs_f32()
3299 },
3300 StageSection::Action => {
3301 stage_time / s.static_data.swing_duration.as_secs_f32()
3302 },
3303 StageSection::Recover => {
3304 stage_time / s.static_data.recover_duration.as_secs_f32()
3305 },
3306 _ => 0.0,
3307 };
3308 anim::bird_medium::ShockwaveAnimation::update_skeleton(
3309 &target_base,
3310 (Some(s.stage_section), physics.on_ground.is_some()),
3311 stage_progress,
3312 &mut state_animation_rate,
3313 skeleton_attr,
3314 )
3315 },
3316 CharacterState::BasicSummon(s) => {
3317 let stage_time = s.timer.as_secs_f32();
3318 let stage_progress = match s.stage_section {
3319 StageSection::Buildup => {
3320 stage_time / s.static_data.buildup_duration.as_secs_f32()
3321 },
3322
3323 StageSection::Action => {
3324 stage_time / s.static_data.cast_duration.as_secs_f32()
3325 },
3326 StageSection::Recover => {
3327 stage_time / s.static_data.recover_duration.as_secs_f32()
3328 },
3329 _ => 0.0,
3330 };
3331
3332 anim::bird_medium::SummonAnimation::update_skeleton(
3333 &target_base,
3334 (
3335 time,
3336 Some(s.stage_section),
3337 state.state_time,
3338 look_dir,
3339 physics.on_ground.is_some(),
3340 ),
3341 stage_progress,
3342 &mut state_animation_rate,
3343 skeleton_attr,
3344 )
3345 },
3346 CharacterState::DashMelee(s) => {
3347 let stage_time = s.timer.as_secs_f32();
3348 let stage_progress = match s.stage_section {
3349 StageSection::Buildup => {
3350 stage_time / s.static_data.buildup_duration.as_secs_f32()
3351 },
3352 StageSection::Charge => {
3353 stage_time / s.static_data.charge_duration.as_secs_f32()
3354 },
3355 StageSection::Action => {
3356 stage_time / s.static_data.swing_duration.as_secs_f32()
3357 },
3358 StageSection::Recover => {
3359 stage_time / s.static_data.recover_duration.as_secs_f32()
3360 },
3361 _ => 0.0,
3362 };
3363 anim::bird_medium::DashAnimation::update_skeleton(
3364 &target_base,
3365 (
3366 rel_vel,
3367 ori * anim::vek::Vec3::<f32>::unit_y(),
3369 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3370 state.acc_vel,
3371 Some(s.stage_section),
3372 time,
3373 state.state_time,
3374 ),
3375 stage_progress,
3376 &mut state_animation_rate,
3377 skeleton_attr,
3378 )
3379 },
3380 CharacterState::Stunned(s) => {
3381 let stage_time = s.timer.as_secs_f32();
3382 let stage_progress = match s.stage_section {
3383 StageSection::Buildup => {
3384 stage_time / s.static_data.buildup_duration.as_secs_f32()
3385 },
3386 StageSection::Recover => {
3387 stage_time / s.static_data.recover_duration.as_secs_f32()
3388 },
3389 _ => 0.0,
3390 };
3391 match s.static_data.poise_state {
3392 PoiseState::Normal
3393 | PoiseState::Interrupted
3394 | PoiseState::Stunned
3395 | PoiseState::Dazed
3396 | PoiseState::KnockedDown => {
3397 anim::bird_medium::StunnedAnimation::update_skeleton(
3398 &target_base,
3399 (time, Some(s.stage_section), state.state_time),
3400 stage_progress,
3401 &mut state_animation_rate,
3402 skeleton_attr,
3403 )
3404 },
3405 }
3406 },
3407 _ => target_base,
3409 };
3410
3411 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
3412 state.update(
3413 renderer,
3414 trail_mgr,
3415 update_buf,
3416 &common_params,
3417 state_animation_rate,
3418 model,
3419 body,
3420 );
3421 },
3422 Body::FishMedium(body) => {
3423 let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model(
3424 renderer,
3425 &mut self.atlas,
3426 body,
3427 inventory,
3428 (),
3429 tick,
3430 viewpoint_camera_mode,
3431 viewpoint_character_state,
3432 slow_jobs,
3433 None,
3434 );
3435
3436 let state = self
3437 .states
3438 .fish_medium_states
3439 .entry(entity)
3440 .or_insert_with(|| {
3441 FigureState::new(renderer, FishMediumSkeleton::default(), body)
3442 });
3443
3444 let rel_avg_vel = state.avg_vel - physics.ground_vel;
3446
3447 let (character, last_character) = match (character, last_character) {
3448 (Some(c), Some(l)) => (c, l),
3449 _ => return,
3450 };
3451
3452 if !character.same_variant(&last_character.0) {
3453 state.state_time = 0.0;
3454 }
3455
3456 let target_base = match (
3457 physics.on_ground.is_some(),
3458 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
3461 (_, false, _) => anim::fish_medium::IdleAnimation::update_skeleton(
3463 &FishMediumSkeleton::default(),
3464 (
3465 rel_vel,
3466 ori * anim::vek::Vec3::<f32>::unit_y(),
3468 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3469 time,
3470 rel_avg_vel,
3471 ),
3472 state.state_time,
3473 &mut state_animation_rate,
3474 skeleton_attr,
3475 ),
3476 (_, true, _) => anim::fish_medium::SwimAnimation::update_skeleton(
3478 &FishMediumSkeleton::default(),
3479 (
3480 rel_vel,
3481 ori * anim::vek::Vec3::<f32>::unit_y(),
3483 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3484 time,
3485 rel_avg_vel,
3486 state.acc_vel,
3487 ),
3488 state.state_time,
3489 &mut state_animation_rate,
3490 skeleton_attr,
3491 ),
3492 };
3493
3494 state.skeleton = Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
3495 state.update(
3496 renderer,
3497 trail_mgr,
3498 update_buf,
3499 &common_params,
3500 state_animation_rate,
3501 model,
3502 body,
3503 );
3504 },
3505 Body::BipedSmall(body) => {
3506 let (model, skeleton_attr) = self.biped_small_model_cache.get_or_create_model(
3507 renderer,
3508 &mut self.atlas,
3509 body,
3510 inventory,
3511 (),
3512 tick,
3513 viewpoint_camera_mode,
3514 viewpoint_character_state,
3515 slow_jobs,
3516 None,
3517 );
3518
3519 let state = self
3520 .states
3521 .biped_small_states
3522 .entry(entity)
3523 .or_insert_with(|| {
3524 FigureState::new(renderer, BipedSmallSkeleton::default(), body)
3525 });
3526
3527 let rel_avg_vel = state.avg_vel - physics.ground_vel;
3529
3530 let (character, last_character) = match (character, last_character) {
3531 (Some(c), Some(l)) => (c, l),
3532 _ => return,
3533 };
3534
3535 if !character.same_variant(&last_character.0) {
3536 state.state_time = 0.0;
3537 }
3538
3539 let target_base = match (
3540 physics.on_ground.is_some(),
3541 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
3544 (true, false, false) => anim::biped_small::IdleAnimation::update_skeleton(
3546 &BipedSmallSkeleton::default(),
3547 (
3548 rel_vel,
3549 ori * anim::vek::Vec3::<f32>::unit_y(),
3550 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3551 time,
3552 rel_avg_vel,
3553 ),
3554 state.state_time,
3555 &mut state_animation_rate,
3556 skeleton_attr,
3557 ),
3558 (true, true, _) => anim::biped_small::RunAnimation::update_skeleton(
3560 &BipedSmallSkeleton::default(),
3561 (
3562 rel_vel,
3563 ori * anim::vek::Vec3::<f32>::unit_y(),
3564 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3565 time,
3566 rel_avg_vel,
3567 state.acc_vel,
3568 ),
3569 state.state_time,
3570 &mut state_animation_rate,
3571 skeleton_attr,
3572 ),
3573 (false, _, false) => anim::biped_small::RunAnimation::update_skeleton(
3575 &BipedSmallSkeleton::default(),
3576 (
3577 rel_vel,
3578 ori * anim::vek::Vec3::<f32>::unit_y(),
3579 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3580 time,
3581 rel_avg_vel,
3582 state.acc_vel,
3583 ),
3584 state.state_time,
3585 &mut state_animation_rate,
3586 skeleton_attr,
3587 ),
3588 (false, _, true) => anim::biped_small::RunAnimation::update_skeleton(
3590 &BipedSmallSkeleton::default(),
3591 (
3592 rel_vel,
3593 ori * anim::vek::Vec3::<f32>::unit_y(),
3594 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3595 time,
3596 rel_avg_vel,
3597 state.acc_vel,
3598 ),
3599 state.state_time,
3600 &mut state_animation_rate,
3601 skeleton_attr,
3602 ),
3603 _ => anim::biped_small::IdleAnimation::update_skeleton(
3604 &BipedSmallSkeleton::default(),
3605 (
3606 rel_vel,
3607 ori * anim::vek::Vec3::<f32>::unit_y(),
3608 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3609 time,
3610 rel_avg_vel,
3611 ),
3612 state.state_time,
3613 &mut state_animation_rate,
3614 skeleton_attr,
3615 ),
3616 };
3617
3618 let target_bones = match &character {
3619 CharacterState::Wielding { .. } => {
3620 anim::biped_small::WieldAnimation::update_skeleton(
3621 &target_base,
3622 (
3623 (active_tool_kind, active_tool_spec),
3624 second_tool_kind,
3625 rel_vel,
3626 ori * anim::vek::Vec3::<f32>::unit_y(),
3627 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3628 time,
3629 rel_avg_vel,
3630 state.acc_vel,
3631 ),
3632 state.state_time,
3633 &mut state_animation_rate,
3634 skeleton_attr,
3635 )
3636 },
3637 CharacterState::DashMelee(s) => {
3638 let stage_time = s.timer.as_secs_f32();
3639 let stage_progress = match s.stage_section {
3640 StageSection::Buildup => {
3641 stage_time / s.static_data.buildup_duration.as_secs_f32()
3642 },
3643 StageSection::Charge => {
3644 stage_time / s.static_data.charge_duration.as_secs_f32()
3645 },
3646 StageSection::Action => {
3647 stage_time / s.static_data.swing_duration.as_secs_f32()
3648 },
3649 StageSection::Recover => {
3650 stage_time / s.static_data.recover_duration.as_secs_f32()
3651 },
3652 _ => 0.0,
3653 };
3654 anim::biped_small::DashAnimation::update_skeleton(
3655 &target_base,
3656 (
3657 ability_id,
3658 rel_vel,
3659 ori * anim::vek::Vec3::<f32>::unit_y(),
3660 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3661 time,
3662 rel_avg_vel,
3663 state.acc_vel,
3664 Some(s.stage_section),
3665 state.state_time,
3666 ),
3667 stage_progress,
3668 &mut state_animation_rate,
3669 skeleton_attr,
3670 )
3671 },
3672 CharacterState::ComboMelee2(s) => {
3673 let timer = s.timer.as_secs_f32();
3674 let current_strike = s.completed_strikes % s.static_data.strikes.len();
3675 let strike_data = s.static_data.strikes[current_strike];
3676 let progress = match s.stage_section {
3677 StageSection::Buildup => {
3678 timer / strike_data.buildup_duration.as_secs_f32()
3679 },
3680 StageSection::Action => {
3681 timer / strike_data.swing_duration.as_secs_f32()
3682 },
3683 StageSection::Recover => {
3684 timer / strike_data.recover_duration.as_secs_f32()
3685 },
3686 _ => 0.0,
3687 };
3688
3689 anim::biped_small::ComboAnimation::update_skeleton(
3690 &target_base,
3691 (
3692 ability_id,
3693 s.stage_section,
3694 current_strike,
3695 rel_vel,
3696 time,
3697 state.state_time,
3698 ),
3699 progress,
3700 &mut state_animation_rate,
3701 skeleton_attr,
3702 )
3703 },
3704 CharacterState::Stunned(s) => {
3705 let stage_time = s.timer.as_secs_f32();
3706 let wield_status = s.was_wielded;
3707 let stage_progress = match s.stage_section {
3708 StageSection::Buildup => {
3709 stage_time / s.static_data.buildup_duration.as_secs_f32()
3710 },
3711 StageSection::Recover => {
3712 stage_time / s.static_data.recover_duration.as_secs_f32()
3713 },
3714 _ => 0.0,
3715 };
3716 match s.static_data.poise_state {
3717 PoiseState::Normal
3718 | PoiseState::Interrupted
3719 | PoiseState::Stunned
3720 | PoiseState::Dazed
3721 | PoiseState::KnockedDown => {
3722 anim::biped_small::StunnedAnimation::update_skeleton(
3723 &target_base,
3724 (
3725 active_tool_kind,
3726 rel_vel,
3727 ori * anim::vek::Vec3::<f32>::unit_y(),
3728 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3729 time,
3730 state.avg_vel,
3731 state.acc_vel,
3732 wield_status,
3733 Some(s.stage_section),
3734 state.state_time,
3735 ),
3736 stage_progress,
3737 &mut state_animation_rate,
3738 skeleton_attr,
3739 )
3740 },
3741 }
3742 },
3743 CharacterState::ChargedRanged(s) => {
3744 let stage_time = s.timer.as_secs_f32();
3745
3746 let stage_progress = match s.stage_section {
3747 StageSection::Buildup => {
3748 stage_time / s.static_data.buildup_duration.as_secs_f32()
3749 },
3750 StageSection::Recover => {
3751 stage_time / s.static_data.recover_duration.as_secs_f32()
3752 },
3753
3754 _ => 0.0,
3755 };
3756 anim::biped_small::ShootAnimation::update_skeleton(
3757 &target_base,
3758 (
3759 active_tool_kind,
3760 rel_vel,
3761 ori * anim::vek::Vec3::<f32>::unit_y(),
3762 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3763 time,
3764 rel_avg_vel,
3765 state.acc_vel,
3766 Some(s.stage_section),
3767 state.state_time,
3768 ability_id,
3769 ),
3770 stage_progress,
3771 &mut state_animation_rate,
3772 skeleton_attr,
3773 )
3774 },
3775 CharacterState::RepeaterRanged(s) => {
3776 let stage_time = s.timer.as_secs_f32();
3777
3778 let stage_progress = match s.stage_section {
3779 StageSection::Buildup => {
3780 stage_time / s.static_data.buildup_duration.as_secs_f32()
3781 },
3782 StageSection::Recover => {
3783 stage_time / s.static_data.recover_duration.as_secs_f32()
3784 },
3785
3786 _ => 0.0,
3787 };
3788 anim::biped_small::ShootAnimation::update_skeleton(
3789 &target_base,
3790 (
3791 active_tool_kind,
3792 rel_vel,
3793 ori * anim::vek::Vec3::<f32>::unit_y(),
3794 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3795 time,
3796 rel_avg_vel,
3797 state.acc_vel,
3798 Some(s.stage_section),
3799 state.state_time,
3800 ability_id,
3801 ),
3802 stage_progress,
3803 &mut state_animation_rate,
3804 skeleton_attr,
3805 )
3806 },
3807 CharacterState::BasicRanged(s) => {
3808 let stage_time = s.timer.as_secs_f32();
3809
3810 let stage_progress = match s.stage_section {
3811 StageSection::Buildup => {
3812 stage_time / s.static_data.buildup_duration.as_secs_f32()
3813 },
3814 StageSection::Recover => {
3815 stage_time / s.static_data.recover_duration.as_secs_f32()
3816 },
3817
3818 _ => 0.0,
3819 };
3820 anim::biped_small::ShootAnimation::update_skeleton(
3821 &target_base,
3822 (
3823 active_tool_kind,
3824 rel_vel,
3825 ori * anim::vek::Vec3::<f32>::unit_y(),
3826 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3827 time,
3828 rel_avg_vel,
3829 state.acc_vel,
3830 Some(s.stage_section),
3831 state.state_time,
3832 ability_id,
3833 ),
3834 stage_progress,
3835 &mut state_animation_rate,
3836 skeleton_attr,
3837 )
3838 },
3839 CharacterState::BasicBeam(s) => {
3840 let stage_time = s.timer.as_secs_f32();
3841 let stage_progress = match s.stage_section {
3842 StageSection::Buildup => {
3843 stage_time / s.static_data.buildup_duration.as_secs_f32()
3844 },
3845 StageSection::Action => s.timer.as_secs_f32(),
3846 StageSection::Recover => {
3847 stage_time / s.static_data.recover_duration.as_secs_f32()
3848 },
3849 _ => 0.0,
3850 };
3851 anim::biped_small::BeamAnimation::update_skeleton(
3852 &target_base,
3853 (
3854 ability_id,
3855 active_tool_kind,
3856 rel_vel,
3857 ori * anim::vek::Vec3::<f32>::unit_y(),
3858 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3859 time,
3860 rel_avg_vel,
3861 state.acc_vel,
3862 Some(s.stage_section),
3863 state.state_time,
3864 ),
3865 stage_progress,
3866 &mut state_animation_rate,
3867 skeleton_attr,
3868 )
3869 },
3870 CharacterState::BasicMelee(s) => {
3871 let stage_time = s.timer.as_secs_f32();
3872 let stage_progress = match s.stage_section {
3873 StageSection::Buildup => {
3874 stage_time / s.static_data.buildup_duration.as_secs_f32()
3875 },
3876 StageSection::Action => {
3877 stage_time / s.static_data.swing_duration.as_secs_f32()
3878 },
3879 StageSection::Recover => {
3880 stage_time / s.static_data.recover_duration.as_secs_f32()
3881 },
3882 _ => 0.0,
3883 };
3884 anim::biped_small::AlphaAnimation::update_skeleton(
3885 &target_base,
3886 (
3887 ability_id,
3888 active_tool_kind,
3889 rel_vel,
3890 ori * anim::vek::Vec3::<f32>::unit_y(),
3891 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3892 time,
3893 rel_avg_vel,
3894 state.acc_vel,
3895 Some(s.stage_section),
3896 state.state_time,
3897 ),
3898 stage_progress,
3899 &mut state_animation_rate,
3900 skeleton_attr,
3901 )
3902 },
3903 CharacterState::LeapMelee(s) => {
3904 let stage_time = s.timer.as_secs_f32();
3905 let stage_progress = match s.stage_section {
3906 StageSection::Buildup => {
3907 stage_time / s.static_data.buildup_duration.as_secs_f32()
3908 },
3909 StageSection::Movement => {
3910 stage_time / s.static_data.movement_duration.as_secs_f32()
3911 },
3912 StageSection::Action => {
3913 stage_time / s.static_data.swing_duration.as_secs_f32()
3914 },
3915 StageSection::Recover => {
3916 stage_time / s.static_data.recover_duration.as_secs_f32()
3917 },
3918 _ => 0.0,
3919 };
3920 anim::biped_small::LeapAnimation::update_skeleton(
3921 &target_base,
3922 (
3923 active_tool_kind,
3924 second_tool_kind,
3925 rel_vel,
3926 time,
3927 Some(s.stage_section),
3928 ),
3929 stage_progress,
3930 &mut state_animation_rate,
3931 skeleton_attr,
3932 )
3933 },
3934 CharacterState::Shockwave(s) => {
3935 let stage_time = s.timer.as_secs_f32();
3936 let stage_progress = match s.stage_section {
3937 StageSection::Buildup => {
3938 stage_time / s.static_data.buildup_duration.as_secs_f32()
3939 },
3940 StageSection::Action => {
3941 stage_time / s.static_data.swing_duration.as_secs_f32()
3942 },
3943 StageSection::Recover => {
3944 stage_time / s.static_data.recover_duration.as_secs_f32()
3945 },
3946 _ => 0.0,
3947 };
3948 anim::biped_small::ShockwaveAnimation::update_skeleton(
3949 &target_base,
3950 (
3951 active_tool_kind,
3952 second_tool_kind,
3953 rel_vel,
3954 ori * anim::vek::Vec3::<f32>::unit_y(),
3955 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3956 time,
3957 rel_avg_vel,
3958 state.acc_vel,
3959 Some(s.stage_section),
3960 state.state_time,
3961 ),
3962 stage_progress,
3963 &mut state_animation_rate,
3964 skeleton_attr,
3965 )
3966 },
3967 CharacterState::SpriteSummon(s) => {
3968 let stage_time = s.timer.as_secs_f32();
3969 let stage_progress = match s.stage_section {
3970 StageSection::Buildup => {
3971 stage_time / s.static_data.buildup_duration.as_secs_f32()
3972 },
3973 StageSection::Action => {
3974 stage_time / s.static_data.cast_duration.as_secs_f32()
3975 },
3976 StageSection::Recover => {
3977 stage_time / s.static_data.recover_duration.as_secs_f32()
3978 },
3979 _ => 0.0,
3980 };
3981 anim::biped_small::SpriteSummonAnimation::update_skeleton(
3982 &target_base,
3983 (
3984 active_tool_kind,
3985 rel_vel,
3986 ori * anim::vek::Vec3::<f32>::unit_y(),
3987 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
3988 time,
3989 rel_avg_vel,
3990 state.acc_vel,
3991 Some(s.stage_section),
3992 state.state_time,
3993 ),
3994 stage_progress,
3995 &mut state_animation_rate,
3996 skeleton_attr,
3997 )
3998 },
3999 CharacterState::BasicSummon(s) => {
4000 let stage_time = s.timer.as_secs_f32();
4001 let stage_progress = match s.stage_section {
4002 StageSection::Buildup => {
4003 stage_time / s.static_data.buildup_duration.as_secs_f32()
4004 },
4005 StageSection::Action => {
4006 stage_time / s.static_data.cast_duration.as_secs_f32()
4007 },
4008 StageSection::Recover => {
4009 stage_time / s.static_data.recover_duration.as_secs_f32()
4010 },
4011 _ => 0.0,
4012 };
4013 anim::biped_small::SummonAnimation::update_skeleton(
4014 &target_base,
4015 (
4016 ability_id,
4017 active_tool_kind,
4018 rel_vel,
4019 ori * anim::vek::Vec3::<f32>::unit_y(),
4020 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4021 time,
4022 rel_avg_vel,
4023 state.acc_vel,
4024 Some(s.stage_section),
4025 state.state_time,
4026 ),
4027 stage_progress,
4028 &mut state_animation_rate,
4029 skeleton_attr,
4030 )
4031 },
4032 CharacterState::SelfBuff(_) | CharacterState::BasicAura(_) => {
4033 let progress = if let Some(((timer, stage_section), durations)) = character
4034 .timer()
4035 .zip(character.stage_section())
4036 .zip(character.durations())
4037 {
4038 match stage_section {
4039 StageSection::Buildup => durations.buildup,
4040 StageSection::Action => durations.action,
4041 StageSection::Recover => durations.recover,
4042 _ => None,
4043 }
4044 .map_or(timer.as_secs_f32(), |stage_duration| {
4045 timer.as_secs_f32() / stage_duration.as_secs_f32()
4046 })
4047 } else {
4048 0.0
4049 };
4050
4051 anim::biped_small::BuffAnimation::update_skeleton(
4052 &target_base,
4053 (
4054 active_tool_kind,
4055 second_tool_kind,
4056 character.stage_section(),
4057 ),
4058 progress,
4059 &mut state_animation_rate,
4060 skeleton_attr,
4061 )
4062 },
4063 CharacterState::BasicBlock(s) => {
4064 let stage_time = s.timer.as_secs_f32();
4065 let stage_progress = match s.stage_section {
4066 StageSection::Buildup => {
4067 stage_time / s.static_data.buildup_duration.as_secs_f32()
4068 },
4069 StageSection::Action => stage_time,
4070 StageSection::Recover => {
4071 stage_time / s.static_data.recover_duration.as_secs_f32()
4072 },
4073 _ => 0.0,
4074 };
4075 anim::biped_small::BlockAnimation::update_skeleton(
4076 &target_base,
4077 (ability_id, s.stage_section),
4078 stage_progress,
4079 &mut state_animation_rate,
4080 skeleton_attr,
4081 )
4082 },
4083 CharacterState::RapidMelee(s) => {
4084 let stage_time = s.timer.as_secs_f32();
4085 let stage_progress = match s.stage_section {
4086 StageSection::Buildup => {
4087 stage_time / s.static_data.buildup_duration.as_secs_f32()
4088 },
4089 StageSection::Action => {
4090 stage_time / s.static_data.swing_duration.as_secs_f32()
4091 },
4092 StageSection::Recover => {
4093 stage_time / s.static_data.recover_duration.as_secs_f32()
4094 },
4095 _ => 0.0,
4096 };
4097
4098 anim::biped_small::RapidMeleeAnimation::update_skeleton(
4099 &target_base,
4100 (ability_id, s.stage_section),
4101 stage_progress,
4102 &mut state_animation_rate,
4103 skeleton_attr,
4104 )
4105 },
4106 CharacterState::RiposteMelee(s) => {
4107 let stage_time = s.timer.as_secs_f32();
4108 let stage_progress = match s.stage_section {
4109 StageSection::Buildup => {
4110 stage_time / s.static_data.buildup_duration.as_secs_f32()
4111 },
4112 StageSection::Action => {
4113 stage_time / s.static_data.swing_duration.as_secs_f32()
4114 },
4115 StageSection::Recover => {
4116 let recover_duration = if s.whiffed {
4117 s.static_data.whiffed_recover_duration.as_secs_f32()
4118 } else {
4119 s.static_data.recover_duration.as_secs_f32()
4120 };
4121 stage_time / recover_duration
4122 },
4123 _ => 0.0,
4124 };
4125
4126 anim::biped_small::RiposteMeleeAnimation::update_skeleton(
4127 &target_base,
4128 (ability_id, s.stage_section),
4129 stage_progress,
4130 &mut state_animation_rate,
4131 skeleton_attr,
4132 )
4133 },
4134 _ => target_base,
4136 };
4137
4138 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
4139 state.update(
4140 renderer,
4141 trail_mgr,
4142 update_buf,
4143 &common_params,
4144 state_animation_rate,
4145 model,
4146 body,
4147 );
4148 },
4149 Body::Dragon(body) => {
4150 let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model(
4151 renderer,
4152 &mut self.atlas,
4153 body,
4154 inventory,
4155 (),
4156 tick,
4157 viewpoint_camera_mode,
4158 viewpoint_character_state,
4159 slow_jobs,
4160 None,
4161 );
4162
4163 let state =
4164 self.states.dragon_states.entry(entity).or_insert_with(|| {
4165 FigureState::new(renderer, DragonSkeleton::default(), body)
4166 });
4167
4168 let rel_avg_vel = state.avg_vel - physics.ground_vel;
4170
4171 let (character, last_character) = match (character, last_character) {
4172 (Some(c), Some(l)) => (c, l),
4173 _ => return,
4174 };
4175
4176 if !character.same_variant(&last_character.0) {
4177 state.state_time = 0.0;
4178 }
4179
4180 let target_base = match (
4181 physics.on_ground.is_some(),
4182 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
4185 (true, false, false) => anim::dragon::IdleAnimation::update_skeleton(
4187 &DragonSkeleton::default(),
4188 time,
4189 state.state_time,
4190 &mut state_animation_rate,
4191 skeleton_attr,
4192 ),
4193 (true, true, false) => anim::dragon::RunAnimation::update_skeleton(
4195 &DragonSkeleton::default(),
4196 (
4197 rel_vel.magnitude(),
4198 ori * anim::vek::Vec3::<f32>::unit_y(),
4200 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4201 time,
4202 rel_avg_vel,
4203 ),
4204 state.state_time,
4205 &mut state_animation_rate,
4206 skeleton_attr,
4207 ),
4208 (false, _, false) => anim::dragon::FlyAnimation::update_skeleton(
4210 &DragonSkeleton::default(),
4211 (rel_vel.magnitude(), time),
4212 state.state_time,
4213 &mut state_animation_rate,
4214 skeleton_attr,
4215 ),
4216 _ => anim::dragon::IdleAnimation::update_skeleton(
4218 &DragonSkeleton::default(),
4219 time,
4220 state.state_time,
4221 &mut state_animation_rate,
4222 skeleton_attr,
4223 ),
4224 };
4225
4226 state.skeleton = Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
4227 state.update(
4228 renderer,
4229 trail_mgr,
4230 update_buf,
4231 &common_params,
4232 state_animation_rate,
4233 model,
4234 body,
4235 );
4236 },
4237 Body::Theropod(body) => {
4238 let (model, skeleton_attr) = self.theropod_model_cache.get_or_create_model(
4239 renderer,
4240 &mut self.atlas,
4241 body,
4242 inventory,
4243 (),
4244 tick,
4245 viewpoint_camera_mode,
4246 viewpoint_character_state,
4247 slow_jobs,
4248 None,
4249 );
4250
4251 let state = self
4252 .states
4253 .theropod_states
4254 .entry(entity)
4255 .or_insert_with(|| {
4256 FigureState::new(renderer, TheropodSkeleton::default(), body)
4257 });
4258
4259 let rel_avg_vel = state.avg_vel - physics.ground_vel;
4261
4262 let (character, last_character) = match (character, last_character) {
4263 (Some(c), Some(l)) => (c, l),
4264 _ => return,
4265 };
4266
4267 if !character.same_variant(&last_character.0) {
4268 state.state_time = 0.0;
4269 }
4270
4271 let target_base = match (
4272 physics.on_ground.is_some(),
4273 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
4276 (true, false, false) => anim::theropod::IdleAnimation::update_skeleton(
4278 &TheropodSkeleton::default(),
4279 time,
4280 state.state_time,
4281 &mut state_animation_rate,
4282 skeleton_attr,
4283 ),
4284 (true, true, false) => anim::theropod::RunAnimation::update_skeleton(
4286 &TheropodSkeleton::default(),
4287 (
4288 rel_vel,
4289 ori * anim::vek::Vec3::<f32>::unit_y(),
4291 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4292 time,
4293 rel_avg_vel,
4294 state.acc_vel,
4295 ),
4296 state.state_time,
4297 &mut state_animation_rate,
4298 skeleton_attr,
4299 ),
4300 (false, _, false) => anim::theropod::JumpAnimation::update_skeleton(
4302 &TheropodSkeleton::default(),
4303 (
4304 rel_vel.magnitude(),
4305 ori * anim::vek::Vec3::<f32>::unit_y(),
4307 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4308 time,
4309 rel_avg_vel,
4310 ),
4311 state.state_time,
4312 &mut state_animation_rate,
4313 skeleton_attr,
4314 ),
4315 _ => anim::theropod::IdleAnimation::update_skeleton(
4316 &TheropodSkeleton::default(),
4317 time,
4318 state.state_time,
4319 &mut state_animation_rate,
4320 skeleton_attr,
4321 ),
4322 };
4323 let target_bones = match &character {
4324 CharacterState::ComboMelee2(s) => {
4325 let timer = s.timer.as_secs_f32();
4326 let current_strike = s.completed_strikes % s.static_data.strikes.len();
4327 let strike_data = s.static_data.strikes[current_strike];
4328 let progress = match s.stage_section {
4329 StageSection::Buildup => {
4330 timer / strike_data.buildup_duration.as_secs_f32()
4331 },
4332 StageSection::Action => {
4333 timer / strike_data.swing_duration.as_secs_f32()
4334 },
4335 StageSection::Recover => {
4336 timer / strike_data.recover_duration.as_secs_f32()
4337 },
4338 _ => 0.0,
4339 };
4340
4341 anim::theropod::ComboAnimation::update_skeleton(
4342 &target_base,
4343 (
4344 ability_id,
4345 s.stage_section,
4346 current_strike,
4347 time,
4348 state.state_time,
4349 ),
4350 progress,
4351 &mut state_animation_rate,
4352 skeleton_attr,
4353 )
4354 },
4355 CharacterState::DashMelee(s) => {
4356 let stage_time = s.timer.as_secs_f32();
4357 let stage_progress = match s.stage_section {
4358 StageSection::Buildup => {
4359 stage_time / s.static_data.buildup_duration.as_secs_f32()
4360 },
4361 StageSection::Charge => {
4362 stage_time / s.static_data.charge_duration.as_secs_f32()
4363 },
4364 StageSection::Action => {
4365 stage_time / s.static_data.swing_duration.as_secs_f32()
4366 },
4367 StageSection::Recover => {
4368 stage_time / s.static_data.recover_duration.as_secs_f32()
4369 },
4370 _ => 0.0,
4371 };
4372 anim::theropod::DashAnimation::update_skeleton(
4373 &target_base,
4374 (
4375 rel_vel.magnitude(),
4376 time,
4377 Some(s.stage_section),
4378 state.state_time,
4379 ),
4380 stage_progress,
4381 &mut state_animation_rate,
4382 skeleton_attr,
4383 )
4384 },
4385 _ => target_base,
4387 };
4388
4389 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
4390 state.update(
4391 renderer,
4392 trail_mgr,
4393 update_buf,
4394 &common_params,
4395 state_animation_rate,
4396 model,
4397 body,
4398 );
4399 },
4400 Body::Arthropod(body) => {
4401 let (model, skeleton_attr) = self.arthropod_model_cache.get_or_create_model(
4402 renderer,
4403 &mut self.atlas,
4404 body,
4405 inventory,
4406 (),
4407 tick,
4408 viewpoint_camera_mode,
4409 viewpoint_character_state,
4410 slow_jobs,
4411 None,
4412 );
4413
4414 let state = self
4415 .states
4416 .arthropod_states
4417 .entry(entity)
4418 .or_insert_with(|| {
4419 FigureState::new(renderer, ArthropodSkeleton::default(), body)
4420 });
4421
4422 let rel_avg_vel = state.avg_vel - physics.ground_vel;
4424
4425 let (character, last_character) = match (character, last_character) {
4426 (Some(c), Some(l)) => (c, l),
4427 _ => return,
4428 };
4429
4430 if !character.same_variant(&last_character.0) {
4431 state.state_time = 0.0;
4432 }
4433
4434 let target_base = match (
4435 physics.on_ground.is_some(),
4436 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
4439 (true, false, false) => anim::arthropod::IdleAnimation::update_skeleton(
4441 &ArthropodSkeleton::default(),
4442 time,
4443 state.state_time,
4444 &mut state_animation_rate,
4445 skeleton_attr,
4446 ),
4447 (true, true, false) => anim::arthropod::RunAnimation::update_skeleton(
4449 &ArthropodSkeleton::default(),
4450 (
4451 rel_vel,
4452 ori * anim::vek::Vec3::<f32>::unit_y(),
4454 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4455 time,
4456 rel_avg_vel,
4457 state.acc_vel,
4458 ),
4459 state.state_time,
4460 &mut state_animation_rate,
4461 skeleton_attr,
4462 ),
4463 (false, _, false) => anim::arthropod::JumpAnimation::update_skeleton(
4465 &ArthropodSkeleton::default(),
4466 (
4467 rel_vel.magnitude(),
4468 ori * anim::vek::Vec3::<f32>::unit_y(),
4470 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4471 time,
4472 rel_avg_vel,
4473 ),
4474 state.state_time,
4475 &mut state_animation_rate,
4476 skeleton_attr,
4477 ),
4478 _ => anim::arthropod::IdleAnimation::update_skeleton(
4479 &ArthropodSkeleton::default(),
4480 time,
4481 state.state_time,
4482 &mut state_animation_rate,
4483 skeleton_attr,
4484 ),
4485 };
4486 let target_bones = match &character {
4487 CharacterState::BasicRanged(_)
4488 | CharacterState::DashMelee(_)
4489 | CharacterState::LeapMelee(_)
4490 | CharacterState::LeapShockwave(_)
4491 | CharacterState::SpriteSummon(_) => {
4492 let timer = character.timer();
4493 let stage_section = character.stage_section();
4494 let durations = character.durations();
4495 let progress = if let Some(((timer, stage_section), durations)) =
4496 timer.zip(stage_section).zip(durations)
4497 {
4498 let base_dur = match stage_section {
4499 StageSection::Buildup => durations.buildup,
4500 StageSection::Charge => durations.charge,
4501 StageSection::Movement => durations.movement,
4502 StageSection::Action => durations.action,
4503 StageSection::Recover => durations.recover,
4504 };
4505 if let Some(base_dur) = base_dur {
4506 timer.as_secs_f32() / base_dur.as_secs_f32()
4507 } else {
4508 timer.as_secs_f32()
4509 }
4510 } else {
4511 0.0
4512 };
4513
4514 anim::arthropod::BasicAction::update_skeleton(
4515 &target_base,
4516 anim::arthropod::BasicActionDependency {
4517 ability_id,
4518 stage_section,
4519 global_time: time,
4520 timer: state.state_time,
4521 },
4522 progress,
4523 &mut state_animation_rate,
4524 skeleton_attr,
4525 )
4526 },
4527 CharacterState::ComboMelee2(_) => {
4528 let timer = character.timer();
4529 let stage_section = character.stage_section();
4530 let durations = character.durations();
4531 let progress = if let Some(((timer, stage_section), durations)) =
4532 timer.zip(stage_section).zip(durations)
4533 {
4534 let base_dur = match stage_section {
4535 StageSection::Buildup => durations.buildup,
4536 StageSection::Charge => durations.charge,
4537 StageSection::Movement => durations.movement,
4538 StageSection::Action => durations.action,
4539 StageSection::Recover => durations.recover,
4540 };
4541 if let Some(base_dur) = base_dur {
4542 timer.as_secs_f32() / base_dur.as_secs_f32()
4543 } else {
4544 timer.as_secs_f32()
4545 }
4546 } else {
4547 0.0
4548 };
4549
4550 let (current_action, max_actions) = match character {
4551 CharacterState::ComboMelee2(s) => (
4552 (s.completed_strikes % s.static_data.strikes.len()) as u32,
4553 Some(s.static_data.strikes.len() as u32),
4554 ),
4555 _ => (0, None),
4556 };
4557
4558 anim::arthropod::MultiAction::update_skeleton(
4559 &target_base,
4560 anim::arthropod::MultiActionDependency {
4561 ability_id,
4562 stage_section,
4563 current_action,
4564 max_actions,
4565 global_time: time,
4566 timer: state.state_time,
4567 },
4568 progress,
4569 &mut state_animation_rate,
4570 skeleton_attr,
4571 )
4572 },
4573 CharacterState::Stunned(s) => {
4574 let stage_time = s.timer.as_secs_f32();
4575 let stage_progress = match s.stage_section {
4576 StageSection::Buildup => {
4577 stage_time / s.static_data.buildup_duration.as_secs_f32()
4578 },
4579 StageSection::Recover => {
4580 stage_time / s.static_data.recover_duration.as_secs_f32()
4581 },
4582 _ => 0.0,
4583 };
4584 match s.static_data.poise_state {
4585 PoiseState::Normal
4586 | PoiseState::Interrupted
4587 | PoiseState::Stunned
4588 | PoiseState::Dazed
4589 | PoiseState::KnockedDown => {
4590 anim::arthropod::StunnedAnimation::update_skeleton(
4591 &target_base,
4592 (
4593 rel_vel.magnitude(),
4594 time,
4595 Some(s.stage_section),
4596 state.state_time,
4597 ),
4598 stage_progress,
4599 &mut state_animation_rate,
4600 skeleton_attr,
4601 )
4602 },
4603 }
4604 },
4605 _ => target_base,
4607 };
4608
4609 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
4610 state.update(
4611 renderer,
4612 trail_mgr,
4613 update_buf,
4614 &common_params,
4615 state_animation_rate,
4616 model,
4617 body,
4618 );
4619 },
4620 Body::Crustacean(body) => {
4621 let (model, skeleton_attr) = self.crustacean_model_cache.get_or_create_model(
4622 renderer,
4623 &mut self.atlas,
4624 body,
4625 inventory,
4626 (),
4627 tick,
4628 viewpoint_camera_mode,
4629 viewpoint_character_state,
4630 slow_jobs,
4631 None,
4632 );
4633
4634 let state = self
4635 .states
4636 .crustacean_states
4637 .entry(entity)
4638 .or_insert_with(|| {
4639 FigureState::new(renderer, CrustaceanSkeleton::default(), body)
4640 });
4641
4642 let rel_avg_vel = state.avg_vel - physics.ground_vel;
4644
4645 let (character, last_character) = match (character, last_character) {
4646 (Some(c), Some(l)) => (c, l),
4647 _ => return,
4648 };
4649
4650 if !character.same_variant(&last_character.0) {
4651 state.state_time = 0.0;
4652 }
4653
4654 let target_base = match (
4655 physics.on_ground.is_some(),
4656 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
4659 (true, false, false) => anim::crustacean::IdleAnimation::update_skeleton(
4661 &CrustaceanSkeleton::default(),
4662 time,
4663 state.state_time,
4664 &mut state_animation_rate,
4665 skeleton_attr,
4666 ),
4667 (true, true, false) => anim::crustacean::RunAnimation::update_skeleton(
4669 &CrustaceanSkeleton::default(),
4670 (
4671 rel_vel,
4672 ori * anim::vek::Vec3::<f32>::unit_y(),
4674 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4675 time,
4676 rel_avg_vel,
4677 state.acc_vel,
4678 ),
4679 state.state_time,
4680 &mut state_animation_rate,
4681 skeleton_attr,
4682 ),
4683 (false, _, false) => anim::crustacean::JumpAnimation::update_skeleton(
4685 &CrustaceanSkeleton::default(),
4686 (
4687 rel_vel.magnitude(),
4688 ori * anim::vek::Vec3::<f32>::unit_y(),
4690 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4691 time,
4692 rel_avg_vel,
4693 ),
4694 state.state_time,
4695 &mut state_animation_rate,
4696 skeleton_attr,
4697 ),
4698 (_, _, true) => anim::crustacean::SwimAnimation::update_skeleton(
4700 &CrustaceanSkeleton::default(),
4701 (
4702 rel_vel,
4703 ori * anim::vek::Vec3::<f32>::unit_y(),
4705 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4706 time,
4707 rel_avg_vel,
4708 state.acc_vel,
4709 ),
4710 state.state_time,
4711 &mut state_animation_rate,
4712 skeleton_attr,
4713 ),
4714 };
4715 let target_bones = match &character {
4716 CharacterState::ComboMelee2(s) => {
4717 let timer = s.timer.as_secs_f32();
4718 let current_strike = s.completed_strikes % s.static_data.strikes.len();
4719 let strike_data = s.static_data.strikes[current_strike];
4720 let progress = match s.stage_section {
4721 StageSection::Buildup => {
4722 timer / strike_data.buildup_duration.as_secs_f32()
4723 },
4724 StageSection::Action => {
4725 timer / strike_data.swing_duration.as_secs_f32()
4726 },
4727 StageSection::Recover => {
4728 timer / strike_data.recover_duration.as_secs_f32()
4729 },
4730 _ => 0.0,
4731 };
4732
4733 anim::crustacean::ComboAnimation::update_skeleton(
4734 &target_base,
4735 (
4736 ability_id,
4737 Some(s.stage_section),
4738 Some(s.static_data.ability_info),
4739 current_strike,
4740 time,
4741 rel_avg_vel,
4742 state.state_time,
4743 ),
4744 progress,
4745 &mut state_animation_rate,
4746 skeleton_attr,
4747 )
4748 },
4749 CharacterState::LeapMelee(s) => {
4750 let stage_time = s.timer.as_secs_f32();
4751 let stage_progress = match s.stage_section {
4752 StageSection::Buildup => {
4753 stage_time / s.static_data.buildup_duration.as_secs_f32()
4754 },
4755 StageSection::Movement => {
4756 stage_time / s.static_data.movement_duration.as_secs_f32()
4757 },
4758 StageSection::Action => {
4759 stage_time / s.static_data.swing_duration.as_secs_f32()
4760 },
4761 StageSection::Recover => {
4762 stage_time / s.static_data.recover_duration.as_secs_f32()
4763 },
4764 _ => 0.0,
4765 };
4766 anim::crustacean::LeapMeleeAnimation::update_skeleton(
4767 &target_base,
4768 (
4769 ability_id,
4770 rel_vel.magnitude(),
4771 time,
4772 Some(s.stage_section),
4773 state.state_time,
4774 ),
4775 stage_progress,
4776 &mut state_animation_rate,
4777 skeleton_attr,
4778 )
4779 },
4780 CharacterState::BasicSummon(s) => {
4781 let stage_time = s.timer.as_secs_f32();
4782 let stage_progress = match s.stage_section {
4783 StageSection::Buildup => {
4784 stage_time / s.static_data.buildup_duration.as_secs_f32()
4785 },
4786
4787 StageSection::Action => {
4788 stage_time / s.static_data.cast_duration.as_secs_f32()
4789 },
4790 StageSection::Recover => {
4791 stage_time / s.static_data.recover_duration.as_secs_f32()
4792 },
4793 _ => 0.0,
4794 };
4795
4796 anim::crustacean::SummonAnimation::update_skeleton(
4797 &target_base,
4798 (
4799 time,
4800 Some(s.stage_section),
4801 state.state_time,
4802 look_dir,
4803 physics.on_ground.is_some(),
4804 ),
4805 stage_progress,
4806 &mut state_animation_rate,
4807 skeleton_attr,
4808 )
4809 },
4810 CharacterState::RiposteMelee(s) => {
4811 let stage_time = s.timer.as_secs_f32();
4812 let stage_progress = match s.stage_section {
4813 StageSection::Buildup => {
4814 stage_time / s.static_data.buildup_duration.as_secs_f32()
4815 },
4816 StageSection::Action => {
4817 stage_time / s.static_data.swing_duration.as_secs_f32()
4818 },
4819 StageSection::Recover => {
4820 let recover_duration = if s.whiffed {
4821 s.static_data.whiffed_recover_duration.as_secs_f32()
4822 } else {
4823 s.static_data.recover_duration.as_secs_f32()
4824 };
4825 stage_time / recover_duration
4826 },
4827 _ => 0.0,
4828 };
4829 anim::crustacean::RiposteMeleeAnimation::update_skeleton(
4830 &target_base,
4831 (ability_id, s.stage_section),
4832 stage_progress,
4833 &mut state_animation_rate,
4834 skeleton_attr,
4835 )
4836 },
4837 CharacterState::Stunned(s) => {
4838 let stage_time = s.timer.as_secs_f32();
4839 let stage_progress = match s.stage_section {
4840 StageSection::Buildup => {
4841 stage_time / s.static_data.buildup_duration.as_secs_f32()
4842 },
4843 StageSection::Recover => {
4844 stage_time / s.static_data.recover_duration.as_secs_f32()
4845 },
4846 _ => 0.0,
4847 };
4848 match s.static_data.poise_state {
4849 PoiseState::Normal
4850 | PoiseState::Interrupted
4851 | PoiseState::Stunned
4852 | PoiseState::Dazed
4853 | PoiseState::KnockedDown => {
4854 anim::crustacean::StunnedAnimation::update_skeleton(
4855 &target_base,
4856 (
4857 rel_vel.magnitude(),
4858 time,
4859 Some(s.stage_section),
4860 state.state_time,
4861 ),
4862 stage_progress,
4863 &mut state_animation_rate,
4864 skeleton_attr,
4865 )
4866 },
4867 }
4868 },
4869 _ => target_base,
4871 };
4872
4873 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
4874 state.update(
4875 renderer,
4876 trail_mgr,
4877 update_buf,
4878 &common_params,
4879 state_animation_rate,
4880 model,
4881 body,
4882 );
4883 },
4884 Body::BirdLarge(body) => {
4885 let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model(
4886 renderer,
4887 &mut self.atlas,
4888 body,
4889 inventory,
4890 (),
4891 tick,
4892 viewpoint_camera_mode,
4893 viewpoint_character_state,
4894 slow_jobs,
4895 None,
4896 );
4897
4898 let state = self
4899 .states
4900 .bird_large_states
4901 .entry(entity)
4902 .or_insert_with(|| {
4903 FigureState::new(renderer, BirdLargeSkeleton::default(), body)
4904 });
4905
4906 let rel_avg_vel = state.avg_vel - physics.ground_vel;
4908
4909 let (character, last_character) = match (character, last_character) {
4910 (Some(c), Some(l)) => (c, l),
4911 _ => return,
4912 };
4913
4914 if !character.same_variant(&last_character.0) {
4915 state.state_time = 0.0;
4916 }
4917
4918 let target_base = match (
4919 physics.on_ground.is_some(),
4920 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
4923 (true, false, false) => anim::bird_large::IdleAnimation::update_skeleton(
4925 &BirdLargeSkeleton::default(),
4926 time,
4927 state.state_time,
4928 &mut state_animation_rate,
4929 skeleton_attr,
4930 ),
4931 (true, true, false) => anim::bird_large::RunAnimation::update_skeleton(
4933 &BirdLargeSkeleton::default(),
4934 (
4935 rel_vel,
4936 ori * anim::vek::Vec3::<f32>::unit_y(),
4938 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4939 rel_avg_vel,
4940 state.acc_vel,
4941 ),
4942 state.state_time,
4943 &mut state_animation_rate,
4944 skeleton_attr,
4945 ),
4946 (false, _, false) => anim::bird_large::FlyAnimation::update_skeleton(
4948 &BirdLargeSkeleton::default(),
4949 (
4950 rel_vel,
4951 ori * anim::vek::Vec3::<f32>::unit_y(),
4953 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
4954 ),
4955 state.state_time,
4956 &mut state_animation_rate,
4957 skeleton_attr,
4958 ),
4959 (_, true, _) => anim::bird_large::SwimAnimation::update_skeleton(
4961 &BirdLargeSkeleton::default(),
4962 time,
4963 state.state_time,
4964 &mut state_animation_rate,
4965 skeleton_attr,
4966 ),
4967 _ => anim::bird_large::IdleAnimation::update_skeleton(
4969 &BirdLargeSkeleton::default(),
4970 time,
4971 state.state_time,
4972 &mut state_animation_rate,
4973 skeleton_attr,
4974 ),
4975 };
4976 let target_bones = match &character {
4977 CharacterState::Sit => anim::bird_large::FeedAnimation::update_skeleton(
4978 &target_base,
4979 time,
4980 state.state_time,
4981 &mut state_animation_rate,
4982 skeleton_attr,
4983 ),
4984 CharacterState::BasicBeam(s) => {
4985 let stage_time = s.timer.as_secs_f32();
4986 let stage_progress = match s.stage_section {
4987 StageSection::Buildup => {
4988 stage_time / s.static_data.buildup_duration.as_secs_f32()
4989 },
4990 StageSection::Action => s.timer.as_secs_f32(),
4991 StageSection::Recover => {
4992 stage_time / s.static_data.recover_duration.as_secs_f32()
4993 },
4994 _ => 0.0,
4995 };
4996 anim::bird_large::BreatheAnimation::update_skeleton(
4997 &target_base,
4998 (
4999 rel_vel,
5000 time,
5001 ori * anim::vek::Vec3::<f32>::unit_y(),
5002 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5003 Some(s.stage_section),
5004 state.state_time,
5005 look_dir,
5006 physics.on_ground.is_some(),
5007 ability_id,
5008 ),
5009 stage_progress,
5010 &mut state_animation_rate,
5011 skeleton_attr,
5012 )
5013 },
5014 CharacterState::ComboMelee2(s) => {
5015 let timer = s.timer.as_secs_f32();
5016 let current_strike = s.completed_strikes % s.static_data.strikes.len();
5017 let strike_data = s.static_data.strikes[current_strike];
5018 let progress = match s.stage_section {
5019 StageSection::Buildup => {
5020 timer / strike_data.buildup_duration.as_secs_f32()
5021 },
5022 StageSection::Action => {
5023 timer / strike_data.swing_duration.as_secs_f32()
5024 },
5025 StageSection::Recover => {
5026 timer / strike_data.recover_duration.as_secs_f32()
5027 },
5028 _ => 0.0,
5029 };
5030
5031 anim::bird_large::ComboAnimation::update_skeleton(
5032 &target_base,
5033 (
5034 ability_id,
5035 Some(s.stage_section),
5036 current_strike,
5037 time,
5038 state.state_time,
5039 ori * anim::vek::Vec3::<f32>::unit_y(),
5040 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5041 physics.on_ground.is_some(),
5042 ),
5043 progress,
5044 &mut state_animation_rate,
5045 skeleton_attr,
5046 )
5047 },
5048 CharacterState::BasicRanged(s) => {
5049 let stage_time = s.timer.as_secs_f32();
5050
5051 let stage_progress = match s.stage_section {
5052 StageSection::Buildup => {
5053 stage_time / s.static_data.buildup_duration.as_secs_f32()
5054 },
5055 StageSection::Recover => {
5056 stage_time / s.static_data.recover_duration.as_secs_f32()
5057 },
5058
5059 _ => 0.0,
5060 };
5061 anim::bird_large::ShootAnimation::update_skeleton(
5062 &target_base,
5063 (
5064 rel_vel,
5065 time,
5066 Some(s.stage_section),
5067 state.state_time,
5068 look_dir,
5069 physics.on_ground.is_some(),
5070 ability_id,
5071 ),
5072 stage_progress,
5073 &mut state_animation_rate,
5074 skeleton_attr,
5075 )
5076 },
5077 CharacterState::RepeaterRanged(s) => {
5078 let stage_time = s.timer.as_secs_f32();
5079
5080 let stage_progress = match s.stage_section {
5081 StageSection::Buildup => {
5082 stage_time / s.static_data.buildup_duration.as_secs_f32()
5083 },
5084 StageSection::Recover => {
5085 stage_time / s.static_data.recover_duration.as_secs_f32()
5086 },
5087
5088 _ => 0.0,
5089 };
5090 anim::bird_large::ShootAnimation::update_skeleton(
5091 &target_base,
5092 (
5093 rel_vel,
5094 time,
5095 Some(s.stage_section),
5096 state.state_time,
5097 look_dir,
5098 physics.on_ground.is_some(),
5099 ability_id,
5100 ),
5101 stage_progress,
5102 &mut state_animation_rate,
5103 skeleton_attr,
5104 )
5105 },
5106 CharacterState::Shockwave(s) => {
5107 let stage_time = s.timer.as_secs_f32();
5108 let stage_progress = match s.stage_section {
5109 StageSection::Buildup => {
5110 stage_time / s.static_data.buildup_duration.as_secs_f32()
5111 },
5112 StageSection::Action => {
5113 stage_time / s.static_data.swing_duration.as_secs_f32()
5114 },
5115 StageSection::Recover => {
5116 stage_time / s.static_data.recover_duration.as_secs_f32()
5117 },
5118 _ => 0.0,
5119 };
5120 anim::bird_large::ShockwaveAnimation::update_skeleton(
5121 &target_base,
5122 (Some(s.stage_section), physics.on_ground.is_some()),
5123 stage_progress,
5124 &mut state_animation_rate,
5125 skeleton_attr,
5126 )
5127 },
5128 CharacterState::BasicAura(s) => {
5129 let stage_time = s.timer.as_secs_f32();
5130 let stage_progress = match s.stage_section {
5131 StageSection::Buildup => {
5132 stage_time / s.static_data.buildup_duration.as_secs_f32()
5133 },
5134 StageSection::Action => {
5135 stage_time / s.static_data.cast_duration.as_secs_f32()
5136 },
5137 StageSection::Recover => {
5138 stage_time / s.static_data.recover_duration.as_secs_f32()
5139 },
5140 _ => 0.0,
5141 };
5142 anim::bird_large::AuraAnimation::update_skeleton(
5143 &target_base,
5144 (Some(s.stage_section), physics.on_ground.is_some()),
5145 stage_progress,
5146 &mut state_animation_rate,
5147 skeleton_attr,
5148 )
5149 },
5150 CharacterState::SelfBuff(s) => {
5151 let stage_time = s.timer.as_secs_f32();
5152 let stage_progress = match s.stage_section {
5153 StageSection::Buildup => {
5154 stage_time / s.static_data.buildup_duration.as_secs_f32()
5155 },
5156 StageSection::Action => {
5157 stage_time / s.static_data.cast_duration.as_secs_f32()
5158 },
5159 StageSection::Recover => {
5160 stage_time / s.static_data.recover_duration.as_secs_f32()
5161 },
5162 _ => 0.0,
5163 };
5164 anim::bird_large::SelfBuffAnimation::update_skeleton(
5165 &target_base,
5166 (Some(s.stage_section), physics.on_ground.is_some()),
5167 stage_progress,
5168 &mut state_animation_rate,
5169 skeleton_attr,
5170 )
5171 },
5172 CharacterState::BasicSummon(s) => {
5173 let stage_time = s.timer.as_secs_f32();
5174 let stage_progress = match s.stage_section {
5175 StageSection::Buildup => {
5176 stage_time / s.static_data.buildup_duration.as_secs_f32()
5177 },
5178
5179 StageSection::Action => {
5180 stage_time / s.static_data.cast_duration.as_secs_f32()
5181 },
5182 StageSection::Recover => {
5183 stage_time / s.static_data.recover_duration.as_secs_f32()
5184 },
5185 _ => 0.0,
5186 };
5187
5188 anim::bird_large::SummonAnimation::update_skeleton(
5189 &target_base,
5190 (
5191 time,
5192 Some(s.stage_section),
5193 state.state_time,
5194 look_dir,
5195 physics.on_ground.is_some(),
5196 ),
5197 stage_progress,
5198 &mut state_animation_rate,
5199 skeleton_attr,
5200 )
5201 },
5202 CharacterState::DashMelee(s) => {
5203 let stage_time = s.timer.as_secs_f32();
5204 let stage_progress = match s.stage_section {
5205 StageSection::Buildup => {
5206 stage_time / s.static_data.buildup_duration.as_secs_f32()
5207 },
5208 StageSection::Charge => {
5209 stage_time / s.static_data.charge_duration.as_secs_f32()
5210 },
5211 StageSection::Action => {
5212 stage_time / s.static_data.swing_duration.as_secs_f32()
5213 },
5214 StageSection::Recover => {
5215 stage_time / s.static_data.recover_duration.as_secs_f32()
5216 },
5217 _ => 0.0,
5218 };
5219 anim::bird_large::DashAnimation::update_skeleton(
5220 &target_base,
5221 (
5222 rel_vel,
5223 ori * anim::vek::Vec3::<f32>::unit_y(),
5225 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5226 state.acc_vel,
5227 Some(s.stage_section),
5228 time,
5229 state.state_time,
5230 ),
5231 stage_progress,
5232 &mut state_animation_rate,
5233 skeleton_attr,
5234 )
5235 },
5236 CharacterState::Stunned(s) => {
5237 let stage_time = s.timer.as_secs_f32();
5238 let stage_progress = match s.stage_section {
5239 StageSection::Buildup => {
5240 stage_time / s.static_data.buildup_duration.as_secs_f32()
5241 },
5242 StageSection::Recover => {
5243 stage_time / s.static_data.recover_duration.as_secs_f32()
5244 },
5245 _ => 0.0,
5246 };
5247 match s.static_data.poise_state {
5248 PoiseState::Normal
5249 | PoiseState::Interrupted
5250 | PoiseState::Stunned
5251 | PoiseState::Dazed
5252 | PoiseState::KnockedDown => {
5253 anim::bird_large::StunnedAnimation::update_skeleton(
5254 &target_base,
5255 (time, Some(s.stage_section), state.state_time),
5256 stage_progress,
5257 &mut state_animation_rate,
5258 skeleton_attr,
5259 )
5260 },
5261 }
5262 },
5263 _ => target_base,
5265 };
5266
5267 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
5268 state.update(
5269 renderer,
5270 trail_mgr,
5271 update_buf,
5272 &common_params,
5273 state_animation_rate,
5274 model,
5275 body,
5276 );
5277 },
5278 Body::FishSmall(body) => {
5279 let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model(
5280 renderer,
5281 &mut self.atlas,
5282 body,
5283 inventory,
5284 (),
5285 tick,
5286 viewpoint_camera_mode,
5287 viewpoint_character_state,
5288 slow_jobs,
5289 None,
5290 );
5291
5292 let state = self
5293 .states
5294 .fish_small_states
5295 .entry(entity)
5296 .or_insert_with(|| {
5297 FigureState::new(renderer, FishSmallSkeleton::default(), body)
5298 });
5299
5300 let rel_avg_vel = state.avg_vel - physics.ground_vel;
5302
5303 let (character, last_character) = match (character, last_character) {
5304 (Some(c), Some(l)) => (c, l),
5305 _ => return,
5306 };
5307
5308 if !character.same_variant(&last_character.0) {
5309 state.state_time = 0.0;
5310 }
5311
5312 let target_base = match (
5313 physics.on_ground.is_some(),
5314 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
5317 (_, false, _) => anim::fish_small::IdleAnimation::update_skeleton(
5319 &FishSmallSkeleton::default(),
5320 (
5321 rel_vel,
5322 ori * anim::vek::Vec3::<f32>::unit_y(),
5324 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5325 time,
5326 rel_avg_vel,
5327 ),
5328 state.state_time,
5329 &mut state_animation_rate,
5330 skeleton_attr,
5331 ),
5332 (_, true, _) => anim::fish_small::SwimAnimation::update_skeleton(
5334 &FishSmallSkeleton::default(),
5335 (
5336 rel_vel,
5337 ori * anim::vek::Vec3::<f32>::unit_y(),
5339 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5340 time,
5341 rel_avg_vel,
5342 state.acc_vel,
5343 ),
5344 state.state_time,
5345 &mut state_animation_rate,
5346 skeleton_attr,
5347 ),
5348 };
5349
5350 state.skeleton = Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
5351 state.update(
5352 renderer,
5353 trail_mgr,
5354 update_buf,
5355 &common_params,
5356 state_animation_rate,
5357 model,
5358 body,
5359 );
5360 },
5361 Body::BipedLarge(body) => {
5362 let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model(
5363 renderer,
5364 &mut self.atlas,
5365 body,
5366 inventory,
5367 (),
5368 tick,
5369 viewpoint_camera_mode,
5370 viewpoint_character_state,
5371 slow_jobs,
5372 None,
5373 );
5374
5375 let state = self
5376 .states
5377 .biped_large_states
5378 .entry(entity)
5379 .or_insert_with(|| {
5380 FigureState::new(renderer, BipedLargeSkeleton::default(), body)
5381 });
5382
5383 let rel_avg_vel = state.avg_vel - physics.ground_vel;
5385
5386 let (character, last_character) = match (character, last_character) {
5387 (Some(c), Some(l)) => (c, l),
5388 _ => return,
5389 };
5390
5391 if !character.same_variant(&last_character.0) {
5392 state.state_time = 0.0;
5393 }
5394
5395 let target_base = match (
5396 physics.on_ground.is_some(),
5397 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
5400 (true, true, false) => anim::biped_large::RunAnimation::update_skeleton(
5402 &BipedLargeSkeleton::default(),
5403 (
5404 active_tool_kind,
5405 second_tool_kind,
5406 rel_vel,
5407 ori * anim::vek::Vec3::<f32>::unit_y(),
5409 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5410 time,
5411 rel_avg_vel,
5412 state.acc_vel,
5413 ),
5414 state.state_time,
5415 &mut state_animation_rate,
5416 skeleton_attr,
5417 ),
5418 (false, _, false) => anim::biped_large::JumpAnimation::update_skeleton(
5420 &BipedLargeSkeleton::default(),
5421 (active_tool_kind, second_tool_kind, time),
5422 state.state_time,
5423 &mut state_animation_rate,
5424 skeleton_attr,
5425 ),
5426 _ => anim::biped_large::IdleAnimation::update_skeleton(
5427 &BipedLargeSkeleton::default(),
5428 (active_tool_kind, second_tool_kind, time),
5429 state.state_time,
5430 &mut state_animation_rate,
5431 skeleton_attr,
5432 ),
5433 };
5434 let target_bones = match &character {
5435 CharacterState::Equipping { .. } => {
5436 anim::biped_large::EquipAnimation::update_skeleton(
5437 &target_base,
5438 (
5439 active_tool_kind,
5440 second_tool_kind,
5441 rel_vel.magnitude(),
5442 time,
5443 ),
5444 state.state_time,
5445 &mut state_animation_rate,
5446 skeleton_attr,
5447 )
5448 },
5449 CharacterState::Wielding { .. } => {
5450 anim::biped_large::WieldAnimation::update_skeleton(
5451 &target_base,
5452 (
5453 (active_tool_kind, active_tool_spec),
5454 (second_tool_kind, second_tool_spec),
5455 rel_vel,
5456 time,
5457 state.acc_vel,
5458 ),
5459 state.state_time,
5460 &mut state_animation_rate,
5461 skeleton_attr,
5462 )
5463 },
5464 CharacterState::ChargedMelee(s) => {
5465 let stage_time = s.timer.as_secs_f32();
5466
5467 let stage_progress = match s.stage_section {
5468 StageSection::Buildup => {
5469 if let Some((dur, _)) = s.static_data.buildup_strike {
5470 stage_time / dur.as_secs_f32()
5471 } else {
5472 stage_time
5473 }
5474 },
5475 StageSection::Charge => {
5476 stage_time / s.static_data.charge_duration.as_secs_f32()
5477 },
5478 StageSection::Action => {
5479 stage_time / s.static_data.swing_duration.as_secs_f32()
5480 },
5481 StageSection::Recover => {
5482 stage_time / s.static_data.recover_duration.as_secs_f32()
5483 },
5484 _ => 0.0,
5485 };
5486
5487 anim::biped_large::ChargeMeleeAnimation::update_skeleton(
5488 &target_base,
5489 (
5490 active_tool_kind,
5491 (second_tool_kind, second_tool_spec),
5492 rel_vel,
5493 time,
5494 Some(s.stage_section),
5495 state.acc_vel,
5496 ability_id,
5497 ),
5498 stage_progress,
5499 &mut state_animation_rate,
5500 skeleton_attr,
5501 )
5502 },
5503 CharacterState::SelfBuff(s) => {
5504 let stage_time = s.timer.as_secs_f32();
5505
5506 let stage_progress = match s.stage_section {
5507 StageSection::Buildup => {
5508 stage_time / s.static_data.buildup_duration.as_secs_f32()
5509 },
5510 StageSection::Action => {
5511 stage_time / s.static_data.cast_duration.as_secs_f32()
5512 },
5513 StageSection::Recover => {
5514 stage_time / s.static_data.recover_duration.as_secs_f32()
5515 },
5516 _ => 0.0,
5517 };
5518
5519 anim::biped_large::SelfBuffAnimation::update_skeleton(
5520 &target_base,
5521 (
5522 (active_tool_kind, active_tool_spec),
5523 (second_tool_kind, second_tool_spec),
5524 rel_vel,
5525 time,
5526 Some(s.stage_section),
5527 state.acc_vel,
5528 ),
5529 stage_progress,
5530 &mut state_animation_rate,
5531 skeleton_attr,
5532 )
5533 },
5534 CharacterState::BasicMelee(s) => {
5535 let stage_time = s.timer.as_secs_f32();
5536
5537 let stage_progress = match s.stage_section {
5538 StageSection::Buildup => {
5539 stage_time / s.static_data.buildup_duration.as_secs_f32()
5540 },
5541 StageSection::Action => {
5542 stage_time / s.static_data.swing_duration.as_secs_f32()
5543 },
5544 StageSection::Recover => {
5545 stage_time / s.static_data.recover_duration.as_secs_f32()
5546 },
5547 _ => 0.0,
5548 };
5549
5550 anim::biped_large::AlphaAnimation::update_skeleton(
5551 &target_base,
5552 (
5553 active_tool_kind,
5554 (second_tool_kind, second_tool_spec),
5555 rel_vel,
5556 time,
5557 Some(s.stage_section),
5558 state.acc_vel,
5559 state.state_time,
5560 ability_id,
5561 ),
5562 stage_progress,
5563 &mut state_animation_rate,
5564 skeleton_attr,
5565 )
5566 },
5567 CharacterState::ComboMelee2(s) => {
5568 let timer = s.timer.as_secs_f32();
5569 let current_strike = s.completed_strikes % s.static_data.strikes.len();
5570 let strike_data = s.static_data.strikes[current_strike];
5571 let progress = match s.stage_section {
5572 StageSection::Buildup => {
5573 timer / strike_data.buildup_duration.as_secs_f32()
5574 },
5575 StageSection::Action => {
5576 timer / strike_data.swing_duration.as_secs_f32()
5577 },
5578 StageSection::Recover => {
5579 timer / strike_data.recover_duration.as_secs_f32()
5580 },
5581 _ => 0.0,
5582 };
5583
5584 anim::biped_large::ComboAnimation::update_skeleton(
5585 &target_base,
5586 (
5587 ability_id,
5588 Some(s.stage_section),
5589 Some(s.static_data.ability_info),
5590 current_strike,
5591 move_dir,
5592 rel_vel,
5593 state.acc_vel,
5594 ),
5595 progress,
5596 &mut state_animation_rate,
5597 skeleton_attr,
5598 )
5599 },
5600 CharacterState::BasicRanged(s) => {
5601 let stage_time = s.timer.as_secs_f32();
5602
5603 let stage_progress = match s.stage_section {
5604 StageSection::Buildup => {
5605 stage_time / s.static_data.buildup_duration.as_secs_f32()
5606 },
5607 StageSection::Recover => {
5608 stage_time / s.static_data.recover_duration.as_secs_f32()
5609 },
5610
5611 _ => 0.0,
5612 };
5613
5614 anim::biped_large::ShootAnimation::update_skeleton(
5615 &target_base,
5616 (
5617 active_tool_kind,
5618 (second_tool_kind, second_tool_spec),
5619 rel_vel,
5620 ori * anim::vek::Vec3::<f32>::unit_y(),
5622 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5623 time,
5624 Some(s.stage_section),
5625 state.acc_vel,
5626 ability_id,
5627 ),
5628 stage_progress,
5629 &mut state_animation_rate,
5630 skeleton_attr,
5631 )
5632 },
5633 CharacterState::RepeaterRanged(s) => {
5634 let stage_time = s.timer.as_secs_f32();
5635
5636 let stage_progress = match s.stage_section {
5637 StageSection::Buildup => {
5638 stage_time / s.static_data.buildup_duration.as_secs_f32()
5639 },
5640 StageSection::Recover => {
5641 stage_time / s.static_data.recover_duration.as_secs_f32()
5642 },
5643
5644 _ => 0.0,
5645 };
5646 anim::biped_large::ShootAnimation::update_skeleton(
5647 &target_base,
5648 (
5649 active_tool_kind,
5650 (second_tool_kind, second_tool_spec),
5651 rel_vel,
5652 ori * anim::vek::Vec3::<f32>::unit_y(),
5654 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5655 time,
5656 Some(s.stage_section),
5657 state.acc_vel,
5658 ability_id,
5659 ),
5660 stage_progress,
5661 &mut state_animation_rate,
5662 skeleton_attr,
5663 )
5664 },
5665 CharacterState::Stunned(s) => {
5666 let stage_time = s.timer.as_secs_f32();
5667 let stage_progress = match s.stage_section {
5668 StageSection::Buildup => {
5669 stage_time / s.static_data.buildup_duration.as_secs_f32()
5670 },
5671 StageSection::Recover => {
5672 stage_time / s.static_data.recover_duration.as_secs_f32()
5673 },
5674 _ => 0.0,
5675 };
5676 match s.static_data.poise_state {
5677 PoiseState::Normal
5678 | PoiseState::Interrupted
5679 | PoiseState::Stunned
5680 | PoiseState::Dazed
5681 | PoiseState::KnockedDown => {
5682 anim::biped_large::StunnedAnimation::update_skeleton(
5683 &target_base,
5684 (
5685 (active_tool_kind, active_tool_spec),
5686 rel_vel,
5687 state.acc_vel,
5688 Some(s.stage_section),
5689 ),
5690 stage_progress,
5691 &mut state_animation_rate,
5692 skeleton_attr,
5693 )
5694 },
5695 }
5696 },
5697 CharacterState::Blink(s) => {
5698 let stage_time = s.timer.as_secs_f32();
5699
5700 let stage_progress = match s.stage_section {
5701 StageSection::Buildup => {
5702 stage_time / s.static_data.buildup_duration.as_secs_f32()
5703 },
5704 StageSection::Recover => {
5705 stage_time / s.static_data.recover_duration.as_secs_f32()
5706 },
5707
5708 _ => 0.0,
5709 };
5710
5711 anim::biped_large::BlinkAnimation::update_skeleton(
5712 &target_base,
5713 (
5714 active_tool_kind,
5715 second_tool_kind,
5716 rel_vel,
5717 time,
5718 Some(s.stage_section),
5719 state.acc_vel,
5720 ),
5721 stage_progress,
5722 &mut state_animation_rate,
5723 skeleton_attr,
5724 )
5725 },
5726 CharacterState::ChargedRanged(s) => {
5727 let stage_time = s.timer.as_secs_f32();
5728
5729 let stage_progress = match s.stage_section {
5730 StageSection::Buildup => {
5731 stage_time / s.static_data.buildup_duration.as_secs_f32()
5732 },
5733 StageSection::Recover => {
5734 stage_time / s.static_data.recover_duration.as_secs_f32()
5735 },
5736
5737 _ => 0.0,
5738 };
5739
5740 anim::biped_large::ShootAnimation::update_skeleton(
5741 &target_base,
5742 (
5743 active_tool_kind,
5744 (second_tool_kind, second_tool_spec),
5745 rel_vel,
5746 ori * anim::vek::Vec3::<f32>::unit_y(),
5748 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
5749 time,
5750 Some(s.stage_section),
5751 state.acc_vel,
5752 ability_id,
5753 ),
5754 stage_progress,
5755 &mut state_animation_rate,
5756 skeleton_attr,
5757 )
5758 },
5759 CharacterState::DashMelee(s) => {
5760 let stage_time = s.timer.as_secs_f32();
5761 let stage_progress = match s.stage_section {
5762 StageSection::Buildup => {
5763 stage_time / s.static_data.buildup_duration.as_secs_f32()
5764 },
5765 StageSection::Charge => {
5766 stage_time / s.static_data.charge_duration.as_secs_f32()
5767 },
5768 StageSection::Action => {
5769 stage_time / s.static_data.swing_duration.as_secs_f32()
5770 },
5771 StageSection::Recover => {
5772 stage_time / s.static_data.recover_duration.as_secs_f32()
5773 },
5774 _ => 0.0,
5775 };
5776 anim::biped_large::DashAnimation::update_skeleton(
5777 &target_base,
5778 (
5779 active_tool_kind,
5780 (second_tool_kind, second_tool_spec),
5781 rel_vel,
5782 time,
5783 Some(s.stage_section),
5784 state.acc_vel,
5785 ability_id,
5786 ),
5787 stage_progress,
5788 &mut state_animation_rate,
5789 skeleton_attr,
5790 )
5791 },
5792 CharacterState::RapidMelee(s) => {
5793 let stage_time = s.timer.as_secs_f32();
5794 let stage_progress = match s.stage_section {
5795 StageSection::Buildup => {
5796 stage_time / s.static_data.buildup_duration.as_secs_f32()
5797 },
5798
5799 StageSection::Action => {
5800 stage_time / s.static_data.swing_duration.as_secs_f32()
5801 },
5802 StageSection::Recover => {
5803 stage_time / s.static_data.recover_duration.as_secs_f32()
5804 },
5805 _ => 0.0,
5806 };
5807
5808 anim::biped_large::RapidMeleeAnimation::update_skeleton(
5809 &target_base,
5810 (
5811 active_tool_kind,
5812 second_tool_kind,
5813 rel_vel,
5814 time,
5815 Some(s.stage_section),
5816 state.acc_vel,
5817 ability_id,
5818 ),
5819 stage_progress,
5820 &mut state_animation_rate,
5821 skeleton_attr,
5822 )
5823 },
5824 CharacterState::BasicSummon(s) => {
5825 let stage_time = s.timer.as_secs_f32();
5826 let stage_progress = match s.stage_section {
5827 StageSection::Buildup => {
5828 stage_time / s.static_data.buildup_duration.as_secs_f32()
5829 },
5830
5831 StageSection::Action => {
5832 stage_time / s.static_data.cast_duration.as_secs_f32()
5833 },
5834 StageSection::Recover => {
5835 stage_time / s.static_data.recover_duration.as_secs_f32()
5836 },
5837 _ => 0.0,
5838 };
5839
5840 anim::biped_large::SummonAnimation::update_skeleton(
5841 &target_base,
5842 (
5843 active_tool_kind,
5844 (second_tool_kind, second_tool_spec),
5845 rel_vel,
5846 time,
5847 Some(s.stage_section),
5848 state.acc_vel,
5849 ability_id,
5850 ),
5851 stage_progress,
5852 &mut state_animation_rate,
5853 skeleton_attr,
5854 )
5855 },
5856 CharacterState::LeapExplosionShockwave(s) => {
5857 let stage_time = s.timer.as_secs_f32();
5858 let stage_progress = match s.stage_section {
5859 StageSection::Buildup => {
5860 stage_time / s.static_data.buildup_duration.as_secs_f32()
5861 },
5862 StageSection::Movement => {
5863 stage_time / s.static_data.buildup_duration.as_secs_f32()
5864 },
5865 StageSection::Action => {
5866 stage_time / s.static_data.swing_duration.as_secs_f32()
5867 },
5868 StageSection::Recover => {
5869 stage_time / s.static_data.recover_duration.as_secs_f32()
5870 },
5871 _ => 0.0,
5872 };
5873
5874 anim::biped_large::LeapExplosionShockAnimation::update_skeleton(
5875 &target_base,
5876 (Some(s.stage_section), ability_id),
5877 stage_progress,
5878 &mut state_animation_rate,
5879 skeleton_attr,
5880 )
5881 },
5882 CharacterState::LeapMelee(s) => {
5883 let stage_progress = match active_tool_kind {
5884 Some(ToolKind::Sword | ToolKind::Axe | ToolKind::Hammer) => {
5885 let stage_time = s.timer.as_secs_f32();
5886 match s.stage_section {
5887 StageSection::Buildup => {
5888 stage_time / s.static_data.buildup_duration.as_secs_f32()
5889 },
5890 StageSection::Movement => {
5891 stage_time / s.static_data.movement_duration.as_secs_f32()
5892 },
5893 StageSection::Action => {
5894 stage_time / s.static_data.swing_duration.as_secs_f32()
5895 },
5896 StageSection::Recover => {
5897 stage_time / s.static_data.recover_duration.as_secs_f32()
5898 },
5899 _ => 0.0,
5900 }
5901 },
5902 _ => state.state_time,
5903 };
5904
5905 anim::biped_large::LeapAnimation::update_skeleton(
5906 &target_base,
5907 (
5908 active_tool_kind,
5909 second_tool_kind,
5910 rel_vel,
5911 time,
5912 Some(s.stage_section),
5913 ability_id,
5914 ),
5915 stage_progress,
5916 &mut state_animation_rate,
5917 skeleton_attr,
5918 )
5919 },
5920 CharacterState::LeapShockwave(s) => {
5921 let stage_time = s.timer.as_secs_f32();
5922 let stage_progress = match s.stage_section {
5923 StageSection::Buildup => {
5924 stage_time / s.static_data.buildup_duration.as_secs_f32()
5925 },
5926 StageSection::Movement => {
5927 stage_time / s.static_data.buildup_duration.as_secs_f32()
5928 },
5929 StageSection::Action => {
5930 stage_time / s.static_data.swing_duration.as_secs_f32()
5931 },
5932 StageSection::Recover => {
5933 stage_time / s.static_data.recover_duration.as_secs_f32()
5934 },
5935 _ => 0.0,
5936 };
5937
5938 anim::biped_large::LeapShockAnimation::update_skeleton(
5939 &target_base,
5940 (
5941 active_tool_kind,
5942 second_tool_kind,
5943 rel_vel,
5944 time,
5945 Some(s.stage_section),
5946 ),
5947 stage_progress,
5948 &mut state_animation_rate,
5949 skeleton_attr,
5950 )
5951 },
5952 CharacterState::Shockwave(s) => {
5953 let stage_time = s.timer.as_secs_f32();
5954 let stage_progress = match s.stage_section {
5955 StageSection::Buildup => {
5956 stage_time / s.static_data.buildup_duration.as_secs_f32()
5957 },
5958 StageSection::Action => {
5959 stage_time / s.static_data.swing_duration.as_secs_f32()
5960 },
5961 StageSection::Recover => {
5962 stage_time / s.static_data.recover_duration.as_secs_f32()
5963 },
5964 _ => 0.0,
5965 };
5966 anim::biped_large::ShockwaveAnimation::update_skeleton(
5967 &target_base,
5968 (
5969 active_tool_kind,
5970 (second_tool_kind, second_tool_spec),
5971 time,
5972 rel_vel.magnitude(),
5973 Some(s.stage_section),
5974 ability_id,
5975 ),
5976 stage_progress,
5977 &mut state_animation_rate,
5978 skeleton_attr,
5979 )
5980 },
5981 CharacterState::Explosion(s) => {
5982 let stage_time = s.timer.as_secs_f32();
5983 let stage_progress = match s.stage_section {
5984 StageSection::Buildup => {
5985 stage_time / s.static_data.buildup_duration.as_secs_f32()
5986 },
5987 StageSection::Action => {
5988 stage_time / s.static_data.action_duration.as_secs_f32()
5989 },
5990 StageSection::Recover => {
5991 stage_time / s.static_data.recover_duration.as_secs_f32()
5992 },
5993 _ => 0.0,
5994 };
5995
5996 anim::biped_large::ExplosionAnimation::update_skeleton(
5997 &target_base,
5998 (rel_vel, state.acc_vel, Some(s.stage_section), ability_id),
5999 stage_progress,
6000 &mut state_animation_rate,
6001 skeleton_attr,
6002 )
6003 },
6004 CharacterState::BasicBeam(s) => {
6005 let stage_time = s.timer.as_secs_f32();
6006 let stage_progress = match s.stage_section {
6007 StageSection::Buildup => {
6008 stage_time / s.static_data.buildup_duration.as_secs_f32()
6009 },
6010 StageSection::Action => s.timer.as_secs_f32(),
6011 StageSection::Recover => {
6012 stage_time / s.static_data.recover_duration.as_secs_f32()
6013 },
6014 _ => 0.0,
6015 };
6016 anim::biped_large::BeamAnimation::update_skeleton(
6017 &target_base,
6018 (
6019 active_tool_kind,
6020 (second_tool_kind, second_tool_spec),
6021 time,
6022 rel_vel,
6023 Some(s.stage_section),
6024 state.acc_vel,
6025 state.state_time,
6026 ability_id,
6027 ),
6028 stage_progress,
6029 &mut state_animation_rate,
6030 skeleton_attr,
6031 )
6032 },
6033 CharacterState::SpriteSummon(s) => {
6034 let stage_time = s.timer.as_secs_f32();
6035 let stage_progress = match s.stage_section {
6036 StageSection::Buildup => {
6037 stage_time / s.static_data.buildup_duration.as_secs_f32()
6038 },
6039 StageSection::Action => {
6040 stage_time / s.static_data.cast_duration.as_secs_f32()
6041 },
6042 StageSection::Recover => {
6043 stage_time / s.static_data.recover_duration.as_secs_f32()
6044 },
6045 _ => 0.0,
6046 };
6047 anim::biped_large::SpriteSummonAnimation::update_skeleton(
6048 &target_base,
6049 (
6050 active_tool_kind,
6051 (second_tool_kind, second_tool_spec),
6052 time,
6053 rel_vel.magnitude(),
6054 Some(s.stage_section),
6055 ability_id,
6056 ),
6057 stage_progress,
6058 &mut state_animation_rate,
6059 skeleton_attr,
6060 )
6061 },
6062 _ => target_base,
6064 };
6065
6066 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
6067 state.update(
6068 renderer,
6069 trail_mgr,
6070 update_buf,
6071 &common_params,
6072 state_animation_rate,
6073 model,
6074 body,
6075 );
6076 },
6077 Body::Golem(body) => {
6078 let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model(
6079 renderer,
6080 &mut self.atlas,
6081 body,
6082 inventory,
6083 (),
6084 tick,
6085 viewpoint_camera_mode,
6086 viewpoint_character_state,
6087 slow_jobs,
6088 None,
6089 );
6090
6091 let state =
6092 self.states.golem_states.entry(entity).or_insert_with(|| {
6093 FigureState::new(renderer, GolemSkeleton::default(), body)
6094 });
6095
6096 let _rel_avg_vel = state.avg_vel - physics.ground_vel;
6098
6099 let (character, last_character) = match (character, last_character) {
6100 (Some(c), Some(l)) => (c, l),
6101 _ => return,
6102 };
6103
6104 if !character.same_variant(&last_character.0) {
6105 state.state_time = 0.0;
6106 }
6107
6108 let target_base = match (
6109 physics.on_ground.is_some(),
6110 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
6113 (true, false, false) => anim::golem::IdleAnimation::update_skeleton(
6115 &GolemSkeleton::default(),
6116 time,
6117 state.state_time,
6118 &mut state_animation_rate,
6119 skeleton_attr,
6120 ),
6121 (true, true, false) => anim::golem::RunAnimation::update_skeleton(
6123 &GolemSkeleton::default(),
6124 (
6125 rel_vel,
6126 ori * anim::vek::Vec3::<f32>::unit_y(),
6128 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
6129 time,
6130 state.acc_vel,
6131 ),
6132 state.state_time,
6133 &mut state_animation_rate,
6134 skeleton_attr,
6135 ),
6136 (false, _, false) => anim::golem::RunAnimation::update_skeleton(
6138 &GolemSkeleton::default(),
6139 (
6140 rel_vel,
6141 ori * anim::vek::Vec3::<f32>::unit_y(),
6142 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
6143 time,
6144 state.acc_vel,
6145 ),
6146 state.state_time,
6147 &mut state_animation_rate,
6148 skeleton_attr,
6149 ),
6150
6151 _ => anim::golem::IdleAnimation::update_skeleton(
6152 &GolemSkeleton::default(),
6153 time,
6154 state.state_time,
6155 &mut state_animation_rate,
6156 skeleton_attr,
6157 ),
6158 };
6159 let target_bones = match &character {
6160 CharacterState::BasicRanged(s) => {
6161 let stage_time = s.timer.as_secs_f32();
6162
6163 let stage_progress = match s.stage_section {
6164 StageSection::Buildup => {
6165 stage_time / s.static_data.buildup_duration.as_secs_f32()
6166 },
6167 StageSection::Recover => {
6168 stage_time / s.static_data.recover_duration.as_secs_f32()
6169 },
6170
6171 _ => 0.0,
6172 };
6173
6174 anim::golem::ShootAnimation::update_skeleton(
6175 &target_base,
6176 (
6177 Some(s.stage_section),
6178 time,
6179 state.state_time,
6180 look_dir,
6181 ability_id,
6182 ),
6183 stage_progress,
6184 &mut state_animation_rate,
6185 skeleton_attr,
6186 )
6187 },
6188 CharacterState::BasicBeam(s) => {
6189 let stage_time = s.timer.as_secs_f32();
6190
6191 let stage_progress = match s.stage_section {
6192 StageSection::Buildup => {
6193 stage_time / s.static_data.buildup_duration.as_secs_f32()
6194 },
6195 StageSection::Action => s.timer.as_secs_f32(),
6196 StageSection::Recover => {
6197 stage_time / s.static_data.recover_duration.as_secs_f32()
6198 },
6199
6200 _ => 0.0,
6201 };
6202
6203 anim::golem::BeamAnimation::update_skeleton(
6204 &target_base,
6205 (
6206 Some(s.stage_section),
6207 time,
6208 state.state_time,
6209 look_dir,
6210 ability_id,
6211 ),
6212 stage_progress,
6213 &mut state_animation_rate,
6214 skeleton_attr,
6215 )
6216 },
6217 CharacterState::BasicMelee(s) => {
6218 let stage_time = s.timer.as_secs_f32();
6219 let stage_progress = match s.stage_section {
6220 StageSection::Buildup => {
6221 stage_time / s.static_data.buildup_duration.as_secs_f32()
6222 },
6223 StageSection::Action => {
6224 stage_time / s.static_data.swing_duration.as_secs_f32()
6225 },
6226 StageSection::Recover => {
6227 stage_time / s.static_data.recover_duration.as_secs_f32()
6228 },
6229 _ => 0.0,
6230 };
6231
6232 anim::golem::AlphaAnimation::update_skeleton(
6233 &target_base,
6234 (Some(s.stage_section), time, state.state_time, ability_id),
6235 stage_progress,
6236 &mut state_animation_rate,
6237 skeleton_attr,
6238 )
6239 },
6240 CharacterState::ComboMelee2(s) => {
6241 let timer = s.timer.as_secs_f32();
6242 let current_strike = s.completed_strikes % s.static_data.strikes.len();
6243 let strike_data = s.static_data.strikes[current_strike];
6244 let progress = match s.stage_section {
6245 StageSection::Buildup => {
6246 timer / strike_data.buildup_duration.as_secs_f32()
6247 },
6248 StageSection::Action => {
6249 timer / strike_data.swing_duration.as_secs_f32()
6250 },
6251 StageSection::Recover => {
6252 timer / strike_data.recover_duration.as_secs_f32()
6253 },
6254 _ => 0.0,
6255 };
6256
6257 anim::golem::ComboAnimation::update_skeleton(
6258 &target_base,
6259 (
6260 ability_id,
6261 Some(s.stage_section),
6262 Some(s.static_data.ability_info),
6263 current_strike,
6264 move_dir,
6265 ),
6266 progress,
6267 &mut state_animation_rate,
6268 skeleton_attr,
6269 )
6270 },
6271 CharacterState::Shockwave(s) => {
6272 let stage_time = s.timer.as_secs_f32();
6273 let stage_progress = match s.stage_section {
6274 StageSection::Buildup => {
6275 stage_time / s.static_data.buildup_duration.as_secs_f32()
6276 },
6277 StageSection::Action => {
6278 stage_time / s.static_data.swing_duration.as_secs_f32()
6279 },
6280 StageSection::Recover => {
6281 stage_time / s.static_data.recover_duration.as_secs_f32()
6282 },
6283 _ => 0.0,
6284 };
6285 anim::golem::ShockwaveAnimation::update_skeleton(
6286 &target_base,
6287 (Some(s.stage_section), rel_vel.magnitude(), time),
6288 stage_progress,
6289 &mut state_animation_rate,
6290 skeleton_attr,
6291 )
6292 },
6293 _ => target_base,
6295 };
6296
6297 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
6298 state.update(
6299 renderer,
6300 trail_mgr,
6301 update_buf,
6302 &common_params,
6303 state_animation_rate,
6304 model,
6305 body,
6306 );
6307 },
6308 Body::Object(body) => {
6309 let (model, skeleton_attr) = self.object_model_cache.get_or_create_model(
6310 renderer,
6311 &mut self.atlas,
6312 body,
6313 inventory,
6314 (),
6315 tick,
6316 viewpoint_camera_mode,
6317 viewpoint_character_state,
6318 slow_jobs,
6319 None,
6320 );
6321
6322 let state =
6323 self.states.object_states.entry(entity).or_insert_with(|| {
6324 FigureState::new(renderer, ObjectSkeleton::default(), body)
6325 });
6326
6327 let _rel_avg_vel = state.avg_vel - physics.ground_vel;
6329
6330 let idlestate = CharacterState::Idle(idle::Data::default());
6331 let last = Last(idlestate.clone());
6332 let (character, last_character) = match (character, last_character) {
6333 (Some(c), Some(l)) => (c, l),
6334 _ => (&idlestate, &last),
6335 };
6336
6337 if !character.same_variant(&last_character.0) {
6338 state.state_time = 0.0;
6339 }
6340
6341 let target_base = match (
6342 physics.on_ground.is_some(),
6343 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
6346 (true, false, false) => anim::object::IdleAnimation::update_skeleton(
6348 &ObjectSkeleton::default(),
6349 (active_tool_kind, second_tool_kind, time),
6350 state.state_time,
6351 &mut state_animation_rate,
6352 skeleton_attr,
6353 ),
6354 _ => anim::object::IdleAnimation::update_skeleton(
6355 &ObjectSkeleton::default(),
6356 (active_tool_kind, second_tool_kind, time),
6357 state.state_time,
6358 &mut state_animation_rate,
6359 skeleton_attr,
6360 ),
6361 };
6362
6363 let target_bones = match &character {
6364 CharacterState::BasicRanged(s) => {
6365 let stage_time = s.timer.as_secs_f32();
6366
6367 let stage_progress = match s.stage_section {
6368 StageSection::Buildup => {
6369 stage_time / s.static_data.buildup_duration.as_secs_f32()
6370 },
6371 StageSection::Recover => {
6372 stage_time / s.static_data.recover_duration.as_secs_f32()
6373 },
6374
6375 _ => 0.0,
6376 };
6377 anim::object::ShootAnimation::update_skeleton(
6378 &target_base,
6379 (
6380 active_tool_kind,
6381 second_tool_kind,
6382 Some(s.stage_section),
6383 body,
6384 ),
6385 stage_progress,
6386 &mut state_animation_rate,
6387 skeleton_attr,
6388 )
6389 },
6390 CharacterState::BasicBeam(s) => {
6391 let stage_time = s.timer.as_secs_f32();
6392 let stage_progress = match s.stage_section {
6393 StageSection::Buildup => {
6394 stage_time / s.static_data.buildup_duration.as_secs_f32()
6395 },
6396 StageSection::Action => s.timer.as_secs_f32(),
6397 StageSection::Recover => {
6398 stage_time / s.static_data.recover_duration.as_secs_f32()
6399 },
6400 _ => 0.0,
6401 };
6402 anim::object::BeamAnimation::update_skeleton(
6403 &target_base,
6404 (
6405 active_tool_kind,
6406 second_tool_kind,
6407 Some(s.stage_section),
6408 body,
6409 ),
6410 stage_progress,
6411 &mut state_animation_rate,
6412 skeleton_attr,
6413 )
6414 },
6415 _ => target_base,
6417 };
6418
6419 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
6420 state.update(
6421 renderer,
6422 trail_mgr,
6423 update_buf,
6424 &common_params,
6425 state_animation_rate,
6426 model,
6427 body,
6428 );
6429 },
6430 Body::Item(body) => {
6431 let item_key = match body {
6432 body::item::Body::Thrown(_) => {
6433 thrown_item.map(|thrown_item| ItemKey::from(&thrown_item.0))
6434 },
6435 _ => item.map(|item| ItemKey::from(item.item())),
6436 };
6437
6438 let (model, skeleton_attr) = self.item_model_cache.get_or_create_model(
6439 renderer,
6440 &mut self.atlas,
6441 body,
6442 inventory,
6443 (),
6444 tick,
6445 viewpoint_camera_mode,
6446 viewpoint_character_state,
6447 slow_jobs,
6448 item_key,
6449 );
6450
6451 let state =
6452 self.states.item_states.entry(entity).or_insert_with(|| {
6453 FigureState::new(renderer, ItemSkeleton::default(), body)
6454 });
6455
6456 let _rel_avg_vel = state.avg_vel - physics.ground_vel;
6458
6459 let idle_state = CharacterState::Idle(idle::Data::default());
6460 let last = Last(idle_state.clone());
6461 let (character, last_character) = match (character, last_character) {
6462 (Some(c), Some(l)) => (c, l),
6463 _ => (&idle_state, &last),
6464 };
6465
6466 if !character.same_variant(&last_character.0) {
6467 state.state_time = 0.0;
6468 }
6469
6470 let target_bones = anim::item::IdleAnimation::update_skeleton(
6471 &ItemSkeleton::default(),
6472 time,
6473 state.state_time,
6474 &mut state_animation_rate,
6475 skeleton_attr,
6476 );
6477
6478 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
6479 state.update(
6480 renderer,
6481 trail_mgr,
6482 update_buf,
6483 &common_params,
6484 state_animation_rate,
6485 model,
6486 body,
6487 );
6488 },
6489 Body::Ship(body) => {
6490 let Some(terrain) = data.terrain else {
6491 return;
6492 };
6493 let (model, skeleton_attr) = if let Some(Collider::Volume(vol)) = collider {
6494 let vk = VolumeKey {
6495 entity,
6496 mut_count: vol.mut_count,
6497 };
6498 let (model, _skeleton_attr) =
6499 self.volume_model_cache.get_or_create_terrain_model(
6500 renderer,
6501 &mut self.atlas,
6502 vk,
6503 Arc::clone(vol),
6504 tick,
6505 slow_jobs,
6506 &terrain.sprite_render_state,
6507 );
6508
6509 let state = self
6510 .states
6511 .volume_states
6512 .entry(entity)
6513 .or_insert_with(|| FigureState::new(renderer, vk, vk));
6514
6515 state.update(
6516 renderer,
6517 trail_mgr,
6518 update_buf,
6519 &common_params,
6520 state_animation_rate,
6521 model,
6522 vk,
6523 );
6524 return;
6525 } else if body.manifest_entry().is_some() {
6526 self.ship_model_cache.get_or_create_terrain_model(
6527 renderer,
6528 &mut self.atlas,
6529 body,
6530 (),
6531 tick,
6532 slow_jobs,
6533 &terrain.sprite_render_state,
6534 )
6535 } else {
6536 return;
6540 };
6541
6542 let state =
6543 self.states.ship_states.entry(entity).or_insert_with(|| {
6544 FigureState::new(renderer, ShipSkeleton::default(), body)
6545 });
6546
6547 let _rel_avg_vel = state.avg_vel - physics.ground_vel;
6549
6550 let idlestate = CharacterState::Idle(idle::Data::default());
6551 let last = Last(idlestate.clone());
6552 let (character, last_character) = match (character, last_character) {
6553 (Some(c), Some(l)) => (c, l),
6554 _ => (&idlestate, &last),
6555 };
6556
6557 if !character.same_variant(&last_character.0) {
6558 state.state_time = 0.0;
6559 }
6560
6561 let target_base = match (
6562 physics.on_ground.is_some(),
6563 rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, physics.in_liquid().is_some(), ) {
6566 (true, false, false) => anim::ship::IdleAnimation::update_skeleton(
6568 &ShipSkeleton::default(),
6569 (
6570 active_tool_kind,
6571 second_tool_kind,
6572 time,
6573 state.acc_vel,
6574 ori * anim::vek::Vec3::<f32>::unit_y(),
6575 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
6576 ),
6577 state.state_time,
6578 &mut state_animation_rate,
6579 skeleton_attr,
6580 ),
6581 _ => anim::ship::IdleAnimation::update_skeleton(
6582 &ShipSkeleton::default(),
6583 (
6584 active_tool_kind,
6585 second_tool_kind,
6586 time,
6587 state.acc_vel,
6588 ori * anim::vek::Vec3::<f32>::unit_y(),
6589 state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
6590 ),
6591 state.state_time,
6592 &mut state_animation_rate,
6593 skeleton_attr,
6594 ),
6595 };
6596
6597 let target_bones = target_base;
6598 state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
6599 state.update(
6600 renderer,
6601 trail_mgr,
6602 update_buf,
6603 &common_params,
6604 state_animation_rate,
6605 model,
6606 body,
6607 );
6608 },
6609 Body::Plugin(body) => {
6610 #[cfg(feature = "plugins")]
6611 {
6612 let (model, _skeleton_attr) = self.plugin_model_cache.get_or_create_model(
6613 renderer,
6614 &mut self.atlas,
6615 body,
6616 inventory,
6617 (),
6618 tick,
6619 viewpoint_camera_mode,
6620 viewpoint_character_state,
6621 slow_jobs,
6622 None,
6623 );
6624
6625 let state = self.states.plugin_states.entry(entity).or_insert_with(|| {
6626 FigureState::new(renderer, PluginSkeleton::default(), body)
6627 });
6628
6629 let rel_avg_vel = state.avg_vel - physics.ground_vel;
6631
6632 let idle_state = CharacterState::Idle(idle::Data::default());
6633 let last = Last(idle_state.clone());
6634 let (character, last_character) = match (character, last_character) {
6635 (Some(c), Some(l)) => (c, l),
6636 _ => (&idle_state, &last),
6637 };
6638
6639 if !character.same_variant(&last_character.0) {
6640 state.state_time = 0.0;
6641 }
6642
6643 let char_state = match character {
6644 CharacterState::BasicMelee(_) => {
6645 common_state::plugin::module::CharacterState::Melee
6646 },
6647 CharacterState::Sit => common_state::plugin::module::CharacterState::Feed,
6648 CharacterState::Stunned(_) => {
6649 common_state::plugin::module::CharacterState::Stunned
6650 },
6651 _ if physics.on_ground.is_none() => {
6652 common_state::plugin::module::CharacterState::Jump
6653 },
6654 _ if physics.in_liquid().is_some() => {
6655 common_state::plugin::module::CharacterState::Swim
6656 },
6657 _ if rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR => {
6658 common_state::plugin::module::CharacterState::Run
6659 },
6660 _ => common_state::plugin::module::CharacterState::Idle,
6661 };
6662
6663 if let Some(bodyobj) = data.plugins.create_body("lizard") {
6664 let dep = common_state::plugin::module::Dependency {
6665 velocity: state.avg_vel.into_tuple(),
6666 ori: ori.into_vec4().into_tuple(),
6667 last_ori: state.last_ori.into_vec4().into_tuple(),
6668 global_time: time,
6669 avg_vel: rel_avg_vel.into_tuple(),
6670 state: char_state,
6671 };
6672
6673 if let Some(target_bones) =
6674 data.plugins.update_skeleton(&bodyobj, &dep, time)
6675 {
6676 state.skeleton = Lerp::lerp(
6677 &state.skeleton,
6678 &PluginSkeleton::from_module(target_bones),
6679 dt_lerp,
6680 );
6681 state.update(
6682 renderer,
6683 trail_mgr,
6684 update_buf,
6685 &common_params,
6686 state_animation_rate,
6687 model,
6688 body,
6689 );
6690 }
6691 }
6692 }
6693 #[cfg(not(feature = "plugins"))]
6694 let _ = body;
6695 },
6696 }
6697 }
6698
6699 fn render_shadow_mapping<'a>(
6700 &'a self,
6701 drawer: &mut FigureShadowDrawer<'_, 'a>,
6702 state: &State,
6703 tick: u64,
6704 (camera, figure_lod_render_distance): CameraData,
6705 filter_state: impl Fn(&FigureStateMeta) -> bool,
6706 ) {
6707 let ecs = state.ecs();
6708 let time = ecs.read_resource::<Time>();
6709 let items = ecs.read_storage::<PickupItem>();
6710 let thrown_items = ecs.read_storage::<ThrownItem>();
6711 (
6712 &ecs.entities(),
6713 &ecs.read_storage::<Pos>(),
6714 ecs.read_storage::<Ori>().maybe(),
6715 &ecs.read_storage::<Body>(),
6716 ecs.read_storage::<Health>().maybe(),
6717 ecs.read_storage::<Inventory>().maybe(),
6718 ecs.read_storage::<Scale>().maybe(),
6719 ecs.read_storage::<Collider>().maybe(),
6720 ecs.read_storage::<Object>().maybe(),
6721 )
6722 .join()
6723 .filter(|(_, _, _, _, health, _, _, _, _)| health.is_none_or(|h| !h.is_dead))
6725 .filter(|(_, _, _, _, _, _, _, _, obj)| !self.should_flicker(*time, *obj))
6726 .for_each(|(entity, pos, _, body, _, inventory, scale, collider, _)| {
6727 if let Some((bound, model, _)) = self.get_model_for_render(
6728 tick,
6729 camera,
6730 None,
6731 entity,
6732 body,
6733 scale.copied(),
6734 inventory,
6735 false,
6736 pos.0,
6737 figure_lod_render_distance * scale.map_or(1.0, |s| s.0),
6738 match collider {
6739 Some(Collider::Volume(vol)) => vol.mut_count,
6740 _ => 0,
6741 },
6742 &filter_state,
6743 match body {
6744 Body::Item(body) => match body {
6745 body::item::Body::Thrown(_) => thrown_items
6746 .get(entity)
6747 .map(|thrown_item| ItemKey::from(&thrown_item.0)),
6748 _ => items.get(entity).map(|item| ItemKey::from(item.item())),
6749 },
6750 _ => None,
6751 }
6752 ) {
6753 drawer.draw(model, bound);
6754 }
6755 });
6756 }
6757
6758 pub fn render_shadows<'a>(
6759 &'a self,
6760 drawer: &mut FigureShadowDrawer<'_, 'a>,
6761 state: &State,
6762 tick: u64,
6763 camera_data: CameraData,
6764 ) {
6765 span!(_guard, "render_shadows", "FigureManager::render_shadows");
6766 self.render_shadow_mapping(drawer, state, tick, camera_data, |state| {
6767 state.can_shadow_sun()
6768 })
6769 }
6770
6771 pub fn render_rain_occlusion<'a>(
6772 &'a self,
6773 drawer: &mut FigureShadowDrawer<'_, 'a>,
6774 state: &State,
6775 tick: u64,
6776 camera_data: CameraData,
6777 ) {
6778 span!(
6779 _guard,
6780 "render_rain_occlusion",
6781 "FigureManager::render_rain_occlusion"
6782 );
6783 self.render_shadow_mapping(drawer, state, tick, camera_data, |state| {
6784 state.can_occlude_rain()
6785 })
6786 }
6787
6788 pub fn render_sprites<'a>(
6789 &'a self,
6790 drawer: &mut SpriteDrawer<'_, 'a>,
6791 state: &State,
6792 cam_pos: Vec3<f32>,
6793 sprite_render_distance: f32,
6794 ) {
6795 span!(_guard, "render", "FigureManager::render_sprites");
6796 let ecs = state.ecs();
6797 let sprite_low_detail_distance = sprite_render_distance * 0.75;
6798 let sprite_mid_detail_distance = sprite_render_distance * 0.5;
6799 let sprite_hid_detail_distance = sprite_render_distance * 0.35;
6800 let sprite_high_detail_distance = sprite_render_distance * 0.15;
6801
6802 let voxel_colliders_manifest = VOXEL_COLLIDER_MANIFEST.read();
6803
6804 for (entity, pos, ori, body, _, collider) in (
6805 &ecs.entities(),
6806 &ecs.read_storage::<Pos>(),
6807 &ecs.read_storage::<Ori>(),
6808 &ecs.read_storage::<Body>(),
6809 ecs.read_storage::<Health>().maybe(),
6810 ecs.read_storage::<Collider>().maybe(),
6811 )
6812 .join()
6813 .filter(|(_, _, _, _, health, _)| health.is_none_or(|h| !h.is_dead))
6815 {
6816 if let Some((sprite_instances, data)) = self
6817 .get_sprite_instances(entity, body, collider)
6818 .zip(self.states.get_terrain_locals(body, &entity))
6819 {
6820 let dist = collider
6821 .and_then(|collider| {
6822 let vol = collider.get_vol(&voxel_colliders_manifest)?;
6823
6824 let mat = Mat4::from(ori.to_quat()).translated_3d(pos.0)
6825 * Mat4::translation_3d(vol.translation);
6826
6827 let p = mat.inverted().mul_point(cam_pos);
6828 let aabb = Aabb {
6829 min: Vec3::zero(),
6830 max: vol.volume().sz.as_(),
6831 };
6832 Some(if aabb.contains_point(p) {
6833 0.0
6834 } else {
6835 aabb.distance_to_point(p)
6836 })
6837 })
6838 .unwrap_or_else(|| pos.0.distance(cam_pos));
6839
6840 if dist < sprite_render_distance {
6841 let lod_level = if dist < sprite_high_detail_distance {
6842 0
6843 } else if dist < sprite_hid_detail_distance {
6844 1
6845 } else if dist < sprite_mid_detail_distance {
6846 2
6847 } else if dist < sprite_low_detail_distance {
6848 3
6849 } else {
6850 4
6851 };
6852
6853 drawer.draw(
6854 data,
6855 &sprite_instances[lod_level],
6856 &AltIndices {
6857 deep_end: 0,
6858 underground_end: 0,
6859 },
6860 CullingMode::None,
6861 )
6862 }
6863 }
6864 }
6865 }
6866
6867 fn should_flicker(&self, time: Time, obj: Option<&Object>) -> bool {
6869 if let Some(Object::DeleteAfter {
6870 spawned_at,
6871 timeout,
6872 }) = obj
6873 {
6874 time.0 > spawned_at.0 + timeout.as_secs_f64() - 10.0 && (time.0 * 8.0).fract() < 0.5
6875 } else {
6876 false
6877 }
6878 }
6879
6880 pub fn render<'a>(
6881 &'a self,
6882 drawer: &mut FigureDrawer<'_, 'a>,
6883 state: &State,
6884 viewpoint_entity: EcsEntity,
6885 tick: u64,
6886 (camera, figure_lod_render_distance): CameraData,
6887 ) {
6888 span!(_guard, "render", "FigureManager::render");
6889 let ecs = state.ecs();
6890
6891 let time = ecs.read_resource::<Time>();
6892 let character_state_storage = state.read_storage::<CharacterState>();
6893 let character_state = character_state_storage.get(viewpoint_entity);
6894 let items = ecs.read_storage::<PickupItem>();
6895 let thrown_items = ecs.read_storage::<ThrownItem>();
6896 for (entity, pos, body, _, inventory, scale, collider, _) in (
6897 &ecs.entities(),
6898 &ecs.read_storage::<Pos>(),
6899 &ecs.read_storage::<Body>(),
6900 ecs.read_storage::<Health>().maybe(),
6901 ecs.read_storage::<Inventory>().maybe(),
6902 ecs.read_storage::<Scale>().maybe(),
6903 ecs.read_storage::<Collider>().maybe(),
6904 ecs.read_storage::<Object>().maybe(),
6905 )
6906 .join()
6907 .filter(|(_, _, _, health, _, _, _, _)| health.is_none_or(|h| !h.is_dead))
6909 .filter(|(entity, _, _, _, _, _, _, _)| *entity != viewpoint_entity)
6911 .filter(|(_, _, _, _, _, _, _, obj)| !self.should_flicker(*time, *obj))
6912 {
6913 if let Some((bound, model, atlas)) = self.get_model_for_render(
6914 tick,
6915 camera,
6916 character_state,
6917 entity,
6918 body,
6919 scale.copied(),
6920 inventory,
6921 false,
6922 pos.0,
6923 figure_lod_render_distance * scale.map_or(1.0, |s| s.0),
6924 match collider {
6925 Some(Collider::Volume(vol)) => vol.mut_count,
6926 _ => 0,
6927 },
6928 |state| state.visible(),
6929 match body {
6930 Body::Item(body) => match body {
6931 body::item::Body::Thrown(_) => thrown_items
6932 .get(entity)
6933 .map(|thrown_item| ItemKey::from(&thrown_item.0)),
6934 _ => items.get(entity).map(|item| ItemKey::from(item.item())),
6935 },
6936 _ => None,
6937 },
6938 ) {
6939 drawer.draw(model, bound, atlas);
6940 }
6941 }
6942 }
6943
6944 pub fn render_viewpoint<'a>(
6945 &'a self,
6946 drawer: &mut FigureDrawer<'_, 'a>,
6947 state: &State,
6948 viewpoint_entity: EcsEntity,
6949 tick: u64,
6950 (camera, figure_lod_render_distance): CameraData,
6951 ) {
6952 span!(_guard, "render_player", "FigureManager::render_player");
6953 let ecs = state.ecs();
6954
6955 let character_state_storage = state.read_storage::<CharacterState>();
6956 let character_state = character_state_storage.get(viewpoint_entity);
6957 let items = ecs.read_storage::<PickupItem>();
6958 let thrown_items = ecs.read_storage::<ThrownItem>();
6959
6960 if let (Some(pos), Some(body), scale) = (
6961 ecs.read_storage::<Pos>().get(viewpoint_entity),
6962 ecs.read_storage::<Body>().get(viewpoint_entity),
6963 ecs.read_storage::<Scale>().get(viewpoint_entity),
6964 ) {
6965 let healths = state.read_storage::<Health>();
6966 let health = healths.get(viewpoint_entity);
6967 if health.is_some_and(|h| h.is_dead) {
6968 return;
6969 }
6970
6971 let inventory_storage = ecs.read_storage::<Inventory>();
6972 let inventory = inventory_storage.get(viewpoint_entity);
6973
6974 if let Some((bound, model, atlas)) = self.get_model_for_render(
6975 tick,
6976 camera,
6977 character_state,
6978 viewpoint_entity,
6979 body,
6980 scale.copied(),
6981 inventory,
6982 true,
6983 pos.0,
6984 figure_lod_render_distance,
6985 0,
6986 |state| state.visible(),
6987 match body {
6988 Body::Item(body) => match body {
6989 body::item::Body::Thrown(_) => thrown_items
6990 .get(viewpoint_entity)
6991 .map(|thrown_item| ItemKey::from(&thrown_item.0)),
6992 _ => items
6993 .get(viewpoint_entity)
6994 .map(|item| ItemKey::from(item.item())),
6995 },
6996 _ => None,
6997 },
6998 ) {
6999 drawer.draw(model, bound, atlas);
7000 }
7009 }
7010 }
7011
7012 fn get_model_for_render(
7013 &self,
7014 tick: u64,
7015 camera: &Camera,
7016 character_state: Option<&CharacterState>,
7017 entity: EcsEntity,
7018 body: &Body,
7019 scale: Option<Scale>,
7020 inventory: Option<&Inventory>,
7021 is_viewpoint: bool,
7022 pos: Vec3<f32>,
7023 figure_lod_render_distance: f32,
7024 mut_count: usize,
7025 filter_state: impl Fn(&FigureStateMeta) -> bool,
7026 item_key: Option<ItemKey>,
7027 ) -> Option<FigureModelRef> {
7028 let body = *body;
7029
7030 let viewpoint_camera_mode = if is_viewpoint {
7031 camera.get_mode()
7032 } else {
7033 CameraMode::default()
7034 };
7035 let focus_pos = camera.get_focus_pos();
7036 let cam_pos = camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
7037 let character_state = if is_viewpoint { character_state } else { None };
7038
7039 let FigureMgr {
7040 atlas: atlas_,
7041 model_cache,
7042 theropod_model_cache,
7043 quadruped_small_model_cache,
7044 quadruped_medium_model_cache,
7045 quadruped_low_model_cache,
7046 bird_medium_model_cache,
7047 bird_large_model_cache,
7048 dragon_model_cache,
7049 fish_medium_model_cache,
7050 fish_small_model_cache,
7051 biped_large_model_cache,
7052 biped_small_model_cache,
7053 object_model_cache,
7054 item_model_cache,
7055 ship_model_cache,
7056 golem_model_cache,
7057 volume_model_cache,
7058 arthropod_model_cache,
7059 crustacean_model_cache,
7060 #[cfg(feature = "plugins")]
7061 plugin_model_cache,
7062 states:
7063 FigureMgrStates {
7064 character_states,
7065 quadruped_small_states,
7066 quadruped_medium_states,
7067 quadruped_low_states,
7068 bird_medium_states,
7069 fish_medium_states,
7070 theropod_states,
7071 dragon_states,
7072 bird_large_states,
7073 fish_small_states,
7074 biped_large_states,
7075 biped_small_states,
7076 golem_states,
7077 object_states,
7078 item_states,
7079 ship_states,
7080 volume_states,
7081 arthropod_states,
7082 crustacean_states,
7083 #[cfg(feature = "plugins")]
7084 plugin_states,
7085 },
7086 } = self;
7087 let atlas = atlas_;
7088 if let Some((bound, model_entry)) = match body {
7089 Body::Humanoid(body) => character_states
7090 .get(&entity)
7091 .filter(|state| filter_state(state))
7092 .map(move |state| {
7093 (
7094 state.bound(),
7095 model_cache
7096 .get_model(
7097 atlas,
7098 body,
7099 inventory,
7100 tick,
7101 viewpoint_camera_mode,
7102 character_state,
7103 None,
7104 )
7105 .map(ModelEntryRef::Figure),
7106 )
7107 }),
7108 Body::QuadrupedSmall(body) => quadruped_small_states
7109 .get(&entity)
7110 .filter(|state| filter_state(state))
7111 .map(move |state| {
7112 (
7113 state.bound(),
7114 quadruped_small_model_cache
7115 .get_model(
7116 atlas,
7117 body,
7118 inventory,
7119 tick,
7120 viewpoint_camera_mode,
7121 character_state,
7122 None,
7123 )
7124 .map(ModelEntryRef::Figure),
7125 )
7126 }),
7127 Body::QuadrupedMedium(body) => quadruped_medium_states
7128 .get(&entity)
7129 .filter(|state| filter_state(state))
7130 .map(move |state| {
7131 (
7132 state.bound(),
7133 quadruped_medium_model_cache
7134 .get_model(
7135 atlas,
7136 body,
7137 inventory,
7138 tick,
7139 viewpoint_camera_mode,
7140 character_state,
7141 None,
7142 )
7143 .map(ModelEntryRef::Figure),
7144 )
7145 }),
7146 Body::QuadrupedLow(body) => quadruped_low_states
7147 .get(&entity)
7148 .filter(|state| filter_state(state))
7149 .map(move |state| {
7150 (
7151 state.bound(),
7152 quadruped_low_model_cache
7153 .get_model(
7154 atlas,
7155 body,
7156 inventory,
7157 tick,
7158 viewpoint_camera_mode,
7159 character_state,
7160 None,
7161 )
7162 .map(ModelEntryRef::Figure),
7163 )
7164 }),
7165 Body::BirdMedium(body) => bird_medium_states
7166 .get(&entity)
7167 .filter(|state| filter_state(state))
7168 .map(move |state| {
7169 (
7170 state.bound(),
7171 bird_medium_model_cache
7172 .get_model(
7173 atlas,
7174 body,
7175 inventory,
7176 tick,
7177 viewpoint_camera_mode,
7178 character_state,
7179 None,
7180 )
7181 .map(ModelEntryRef::Figure),
7182 )
7183 }),
7184 Body::FishMedium(body) => fish_medium_states
7185 .get(&entity)
7186 .filter(|state| filter_state(state))
7187 .map(move |state| {
7188 (
7189 state.bound(),
7190 fish_medium_model_cache
7191 .get_model(
7192 atlas,
7193 body,
7194 inventory,
7195 tick,
7196 viewpoint_camera_mode,
7197 character_state,
7198 None,
7199 )
7200 .map(ModelEntryRef::Figure),
7201 )
7202 }),
7203 Body::Theropod(body) => theropod_states
7204 .get(&entity)
7205 .filter(|state| filter_state(state))
7206 .map(move |state| {
7207 (
7208 state.bound(),
7209 theropod_model_cache
7210 .get_model(
7211 atlas,
7212 body,
7213 inventory,
7214 tick,
7215 viewpoint_camera_mode,
7216 character_state,
7217 None,
7218 )
7219 .map(ModelEntryRef::Figure),
7220 )
7221 }),
7222 Body::Dragon(body) => dragon_states
7223 .get(&entity)
7224 .filter(|state| filter_state(state))
7225 .map(move |state| {
7226 (
7227 state.bound(),
7228 dragon_model_cache
7229 .get_model(
7230 atlas,
7231 body,
7232 inventory,
7233 tick,
7234 viewpoint_camera_mode,
7235 character_state,
7236 None,
7237 )
7238 .map(ModelEntryRef::Figure),
7239 )
7240 }),
7241 Body::BirdLarge(body) => bird_large_states
7242 .get(&entity)
7243 .filter(|state| filter_state(state))
7244 .map(move |state| {
7245 (
7246 state.bound(),
7247 bird_large_model_cache
7248 .get_model(
7249 atlas,
7250 body,
7251 inventory,
7252 tick,
7253 viewpoint_camera_mode,
7254 character_state,
7255 None,
7256 )
7257 .map(ModelEntryRef::Figure),
7258 )
7259 }),
7260 Body::FishSmall(body) => fish_small_states
7261 .get(&entity)
7262 .filter(|state| filter_state(state))
7263 .map(move |state| {
7264 (
7265 state.bound(),
7266 fish_small_model_cache
7267 .get_model(
7268 atlas,
7269 body,
7270 inventory,
7271 tick,
7272 viewpoint_camera_mode,
7273 character_state,
7274 None,
7275 )
7276 .map(ModelEntryRef::Figure),
7277 )
7278 }),
7279 Body::BipedLarge(body) => biped_large_states
7280 .get(&entity)
7281 .filter(|state| filter_state(state))
7282 .map(move |state| {
7283 (
7284 state.bound(),
7285 biped_large_model_cache
7286 .get_model(
7287 atlas,
7288 body,
7289 inventory,
7290 tick,
7291 viewpoint_camera_mode,
7292 character_state,
7293 None,
7294 )
7295 .map(ModelEntryRef::Figure),
7296 )
7297 }),
7298 Body::BipedSmall(body) => biped_small_states
7299 .get(&entity)
7300 .filter(|state| filter_state(state))
7301 .map(move |state| {
7302 (
7303 state.bound(),
7304 biped_small_model_cache
7305 .get_model(
7306 atlas,
7307 body,
7308 inventory,
7309 tick,
7310 viewpoint_camera_mode,
7311 character_state,
7312 None,
7313 )
7314 .map(ModelEntryRef::Figure),
7315 )
7316 }),
7317 Body::Golem(body) => golem_states
7318 .get(&entity)
7319 .filter(|state| filter_state(state))
7320 .map(move |state| {
7321 (
7322 state.bound(),
7323 golem_model_cache
7324 .get_model(
7325 atlas,
7326 body,
7327 inventory,
7328 tick,
7329 viewpoint_camera_mode,
7330 character_state,
7331 None,
7332 )
7333 .map(ModelEntryRef::Figure),
7334 )
7335 }),
7336 Body::Arthropod(body) => arthropod_states
7337 .get(&entity)
7338 .filter(|state| filter_state(state))
7339 .map(move |state| {
7340 (
7341 state.bound(),
7342 arthropod_model_cache
7343 .get_model(
7344 atlas,
7345 body,
7346 inventory,
7347 tick,
7348 viewpoint_camera_mode,
7349 character_state,
7350 None,
7351 )
7352 .map(ModelEntryRef::Figure),
7353 )
7354 }),
7355 Body::Crustacean(body) => crustacean_states
7356 .get(&entity)
7357 .filter(|state| filter_state(state))
7358 .map(move |state| {
7359 (
7360 state.bound(),
7361 crustacean_model_cache
7362 .get_model(
7363 atlas,
7364 body,
7365 inventory,
7366 tick,
7367 viewpoint_camera_mode,
7368 character_state,
7369 None,
7370 )
7371 .map(ModelEntryRef::Figure),
7372 )
7373 }),
7374 Body::Object(body) => object_states
7375 .get(&entity)
7376 .filter(|state| filter_state(state))
7377 .map(move |state| {
7378 (
7379 state.bound(),
7380 object_model_cache
7381 .get_model(
7382 atlas,
7383 body,
7384 inventory,
7385 tick,
7386 viewpoint_camera_mode,
7387 character_state,
7388 None,
7389 )
7390 .map(ModelEntryRef::Figure),
7391 )
7392 }),
7393 Body::Item(body) => item_states
7394 .get(&entity)
7395 .filter(|state| filter_state(state))
7396 .map(move |state| {
7397 (
7398 state.bound(),
7399 item_model_cache
7400 .get_model(
7401 atlas,
7402 body,
7403 inventory,
7404 tick,
7405 viewpoint_camera_mode,
7406 character_state,
7407 item_key,
7408 )
7409 .map(ModelEntryRef::Figure),
7410 )
7411 }),
7412 Body::Ship(body) => {
7413 if matches!(body, ship::Body::Volume) {
7414 volume_states
7415 .get(&entity)
7416 .filter(|state| filter_state(state))
7417 .map(move |state| {
7418 (
7419 state.bound(),
7420 volume_model_cache
7421 .get_model(
7422 atlas,
7423 VolumeKey { entity, mut_count },
7424 None,
7425 tick,
7426 CameraMode::default(),
7427 None,
7428 None,
7429 )
7430 .map(ModelEntryRef::Terrain),
7431 )
7432 })
7433 } else if body.manifest_entry().is_some() {
7434 ship_states
7435 .get(&entity)
7436 .filter(|state| filter_state(state))
7437 .map(move |state| {
7438 (
7439 state.bound(),
7440 ship_model_cache
7441 .get_model(
7442 atlas,
7443 body,
7444 None,
7445 tick,
7446 CameraMode::default(),
7447 None,
7448 None,
7449 )
7450 .map(ModelEntryRef::Terrain),
7451 )
7452 })
7453 } else {
7454 None
7455 }
7456 },
7457 Body::Plugin(body) => {
7458 #[cfg(not(feature = "plugins"))]
7459 {
7460 let _ = body;
7461 unreachable!("Plugins require feature");
7462 }
7463 #[cfg(feature = "plugins")]
7464 {
7465 plugin_states
7466 .get(&entity)
7467 .filter(|state| filter_state(state))
7468 .map(move |state| {
7469 (
7470 state.bound(),
7471 plugin_model_cache
7472 .get_model(
7473 atlas,
7474 body,
7475 inventory,
7476 tick,
7477 viewpoint_camera_mode,
7478 character_state,
7479 item_key,
7480 )
7481 .map(ModelEntryRef::Figure),
7482 )
7483 })
7484 }
7485 },
7486 } {
7487 let model_entry = model_entry?;
7488
7489 let figure_low_detail_distance = figure_lod_render_distance
7490 * if matches!(body, Body::Ship(_)) {
7491 ship::AIRSHIP_SCALE
7492 } else {
7493 1.0
7494 }
7495 * scale.map_or(1.0, |s| s.0)
7496 * 0.75;
7497 let figure_mid_detail_distance = figure_lod_render_distance
7498 * if matches!(body, Body::Ship(_)) {
7499 ship::AIRSHIP_SCALE
7500 } else {
7501 1.0
7502 }
7503 * scale.map_or(1.0, |s| s.0)
7504 * 0.5;
7505
7506 let model = if pos.distance_squared(cam_pos) > figure_low_detail_distance.powi(2) {
7507 model_entry.lod_model(2)
7508 } else if pos.distance_squared(cam_pos) > figure_mid_detail_distance.powi(2) {
7509 model_entry.lod_model(1)
7510 } else {
7511 model_entry.lod_model(0)
7512 };
7513
7514 Some((bound, model?, atlas_.texture(model_entry)))
7515 } else {
7516 None
7518 }
7519 }
7520
7521 fn get_sprite_instances<'a>(
7522 &'a self,
7523 entity: EcsEntity,
7524 body: &Body,
7525 collider: Option<&Collider>,
7526 ) -> Option<&'a [Instances<SpriteInstance>; SPRITE_LOD_LEVELS]> {
7527 match body {
7528 Body::Ship(body) => {
7529 if let Some(Collider::Volume(vol)) = collider {
7530 let vk = VolumeKey {
7531 entity,
7532 mut_count: vol.mut_count,
7533 };
7534 self.volume_model_cache.get_sprites(vk)
7535 } else if body.manifest_entry().is_some() {
7536 self.ship_model_cache.get_sprites(*body)
7537 } else {
7538 None
7539 }
7540 },
7541 _ => None,
7542 }
7543 }
7544
7545 pub fn get_blocks_of_interest<'a>(
7546 &'a self,
7547 entity: EcsEntity,
7548 body: &Body,
7549 collider: Option<&Collider>,
7550 ) -> Option<(&'a BlocksOfInterest, Vec3<f32>)> {
7551 match body {
7552 Body::Ship(body) => {
7553 if let Some(Collider::Volume(vol)) = collider {
7554 let vk = VolumeKey {
7555 entity,
7556 mut_count: vol.mut_count,
7557 };
7558 self.volume_model_cache.get_blocks_of_interest(vk)
7559 } else {
7560 self.ship_model_cache.get_blocks_of_interest(*body)
7561 }
7562 },
7563 _ => None,
7564 }
7565 }
7566
7567 pub fn get_heads(&self, scene_data: &SceneData, entity: EcsEntity) -> &[anim::vek::Vec3<f32>] {
7568 scene_data
7569 .state
7570 .ecs()
7571 .read_storage::<Body>()
7572 .get(entity)
7573 .and_then(|b| match b {
7574 Body::Humanoid(_) => self
7575 .states
7576 .character_states
7577 .get(&entity)
7578 .map(|state| &state.heads),
7579 Body::QuadrupedSmall(_) => self
7580 .states
7581 .quadruped_small_states
7582 .get(&entity)
7583 .map(|state| &state.heads),
7584 Body::QuadrupedMedium(_) => self
7585 .states
7586 .quadruped_medium_states
7587 .get(&entity)
7588 .map(|state| &state.heads),
7589 Body::BirdMedium(_) => self
7590 .states
7591 .bird_medium_states
7592 .get(&entity)
7593 .map(|state| &state.heads),
7594 Body::FishMedium(_) => self
7595 .states
7596 .fish_medium_states
7597 .get(&entity)
7598 .map(|state| &state.heads),
7599 Body::Dragon(_) => self
7600 .states
7601 .dragon_states
7602 .get(&entity)
7603 .map(|state| &state.heads),
7604 Body::BirdLarge(_) => self
7605 .states
7606 .bird_large_states
7607 .get(&entity)
7608 .map(|state| &state.heads),
7609 Body::FishSmall(_) => self
7610 .states
7611 .fish_small_states
7612 .get(&entity)
7613 .map(|state| &state.heads),
7614 Body::BipedLarge(_) => self
7615 .states
7616 .biped_large_states
7617 .get(&entity)
7618 .map(|state| &state.heads),
7619 Body::BipedSmall(_) => self
7620 .states
7621 .biped_small_states
7622 .get(&entity)
7623 .map(|state| &state.heads),
7624 Body::Golem(_) => self
7625 .states
7626 .golem_states
7627 .get(&entity)
7628 .map(|state| &state.heads),
7629 Body::Theropod(_) => self
7630 .states
7631 .theropod_states
7632 .get(&entity)
7633 .map(|state| &state.heads),
7634 Body::QuadrupedLow(_) => self
7635 .states
7636 .quadruped_low_states
7637 .get(&entity)
7638 .map(|state| &state.heads),
7639 Body::Arthropod(_) => self
7640 .states
7641 .arthropod_states
7642 .get(&entity)
7643 .map(|state| &state.heads),
7644 Body::Object(_) => self
7645 .states
7646 .object_states
7647 .get(&entity)
7648 .map(|state| &state.heads),
7649 Body::Ship(_) => self
7650 .states
7651 .ship_states
7652 .get(&entity)
7653 .map(|state| &state.heads),
7654 Body::Item(_) => self
7655 .states
7656 .item_states
7657 .get(&entity)
7658 .map(|state| &state.heads),
7659 Body::Crustacean(_) => self
7660 .states
7661 .crustacean_states
7662 .get(&entity)
7663 .map(|state| &state.heads),
7664 Body::Plugin(_) => {
7665 #[cfg(not(feature = "plugins"))]
7666 unreachable!("Plugins require feature");
7667 #[cfg(feature = "plugins")]
7668 self.states
7669 .plugin_states
7670 .get(&entity)
7671 .map(|state| &state.heads)
7672 },
7673 })
7674 .map(|v| v.as_slice())
7675 .unwrap_or(&[])
7676 }
7677
7678 pub fn get_tail(
7679 &self,
7680 scene_data: &SceneData,
7681 entity: EcsEntity,
7682 ) -> Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)> {
7683 scene_data
7684 .state
7685 .ecs()
7686 .read_storage::<Body>()
7687 .get(entity)
7688 .and_then(|b| match b {
7689 Body::Humanoid(_) => self.states.character_states.get(&entity)?.tail,
7690 Body::QuadrupedSmall(_) => self.states.quadruped_small_states.get(&entity)?.tail,
7691 Body::QuadrupedMedium(_) => self.states.quadruped_medium_states.get(&entity)?.tail,
7692 Body::BirdMedium(_) => self.states.bird_medium_states.get(&entity)?.tail,
7693 Body::FishMedium(_) => self.states.fish_medium_states.get(&entity)?.tail,
7694 Body::Dragon(_) => self.states.dragon_states.get(&entity)?.tail,
7695 Body::BirdLarge(_) => self.states.bird_large_states.get(&entity)?.tail,
7696 Body::FishSmall(_) => self.states.fish_small_states.get(&entity)?.tail,
7697 Body::BipedLarge(_) => self.states.biped_large_states.get(&entity)?.tail,
7698 Body::BipedSmall(_) => self.states.biped_small_states.get(&entity)?.tail,
7699 Body::Golem(_) => self.states.golem_states.get(&entity)?.tail,
7700 Body::Theropod(_) => self.states.theropod_states.get(&entity)?.tail,
7701 Body::QuadrupedLow(_) => self.states.quadruped_low_states.get(&entity)?.tail,
7702 Body::Arthropod(_) => self.states.arthropod_states.get(&entity)?.tail,
7703 Body::Object(_) => self.states.object_states.get(&entity)?.tail,
7704 Body::Ship(_) => self.states.ship_states.get(&entity)?.tail,
7705 Body::Item(_) => self.states.item_states.get(&entity)?.tail,
7706 Body::Crustacean(_) => self.states.crustacean_states.get(&entity)?.tail,
7707 Body::Plugin(_) => {
7708 #[cfg(not(feature = "plugins"))]
7709 unreachable!("Plugins require feature");
7710 #[cfg(feature = "plugins")]
7711 self.states.plugin_states.get(&entity)?.tail
7712 },
7713 })
7714 }
7715
7716 pub fn viewpoint_offset(&self, scene_data: &SceneData, entity: EcsEntity) -> Vec3<f32> {
7717 scene_data
7718 .state
7719 .ecs()
7720 .read_storage::<Body>()
7721 .get(entity)
7722 .and_then(|b| match b {
7723 Body::Humanoid(_) => self
7724 .states
7725 .character_states
7726 .get(&entity)
7727 .and_then(|state| state.viewpoint_offset),
7728 Body::QuadrupedSmall(_) => self
7729 .states
7730 .quadruped_small_states
7731 .get(&entity)
7732 .and_then(|state| state.viewpoint_offset),
7733 Body::QuadrupedMedium(_) => self
7734 .states
7735 .quadruped_medium_states
7736 .get(&entity)
7737 .and_then(|state| state.viewpoint_offset),
7738 Body::BirdMedium(_) => self
7739 .states
7740 .bird_medium_states
7741 .get(&entity)
7742 .and_then(|state| state.viewpoint_offset),
7743 Body::FishMedium(_) => self
7744 .states
7745 .fish_medium_states
7746 .get(&entity)
7747 .and_then(|state| state.viewpoint_offset),
7748 Body::Dragon(_) => self
7749 .states
7750 .dragon_states
7751 .get(&entity)
7752 .and_then(|state| state.viewpoint_offset),
7753 Body::BirdLarge(_) => self
7754 .states
7755 .bird_large_states
7756 .get(&entity)
7757 .and_then(|state| state.viewpoint_offset),
7758 Body::FishSmall(_) => self
7759 .states
7760 .fish_small_states
7761 .get(&entity)
7762 .and_then(|state| state.viewpoint_offset),
7763 Body::BipedLarge(_) => self
7764 .states
7765 .biped_large_states
7766 .get(&entity)
7767 .and_then(|state| state.viewpoint_offset),
7768 Body::BipedSmall(_) => self
7769 .states
7770 .biped_small_states
7771 .get(&entity)
7772 .and_then(|state| state.viewpoint_offset),
7773 Body::Golem(_) => self
7774 .states
7775 .golem_states
7776 .get(&entity)
7777 .and_then(|state| state.viewpoint_offset),
7778 Body::Theropod(_) => self
7779 .states
7780 .theropod_states
7781 .get(&entity)
7782 .and_then(|state| state.viewpoint_offset),
7783 Body::QuadrupedLow(_) => self
7784 .states
7785 .quadruped_low_states
7786 .get(&entity)
7787 .and_then(|state| state.viewpoint_offset),
7788 Body::Arthropod(_) => self
7789 .states
7790 .arthropod_states
7791 .get(&entity)
7792 .and_then(|state| state.viewpoint_offset),
7793 Body::Object(_) => self
7794 .states
7795 .object_states
7796 .get(&entity)
7797 .and_then(|state| state.viewpoint_offset),
7798 Body::Ship(_) => self
7799 .states
7800 .ship_states
7801 .get(&entity)
7802 .and_then(|state| state.viewpoint_offset),
7803 Body::Item(_) => self
7804 .states
7805 .item_states
7806 .get(&entity)
7807 .and_then(|state| state.viewpoint_offset),
7808 Body::Crustacean(_) => self
7809 .states
7810 .crustacean_states
7811 .get(&entity)
7812 .and_then(|state| state.viewpoint_offset),
7813 Body::Plugin(_) => {
7814 #[cfg(not(feature = "plugins"))]
7815 unreachable!("Plugins require feature");
7816 #[cfg(feature = "plugins")]
7817 {
7818 self.states
7819 .plugin_states
7820 .get(&entity)
7821 .and_then(|state| state.viewpoint_offset)
7822 }
7823 },
7824 })
7825 .unwrap_or_else(Vec3::zero)
7826 }
7827
7828 pub fn figure_count(&self) -> usize { self.states.count() }
7829
7830 pub fn figure_count_visible(&self) -> usize { self.states.count_visible() }
7831}
7832
7833pub struct FigureAtlas {
7834 allocator: AtlasAllocator,
7835 }
7837
7838impl FigureAtlas {
7839 pub fn new(renderer: &mut Renderer) -> Self {
7840 let allocator =
7841 Self::make_allocator(renderer).expect("Failed to create texture atlas for figures");
7842 Self {
7843 allocator, }
7845 }
7846
7847 pub fn texture<'a, const N: usize>(
7849 &'a self,
7850 model: ModelEntryRef<'a, N>,
7851 ) -> &'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
7852 model.atlas_textures()
7854 }
7855
7856 pub fn create_figure<const N: usize>(
7865 &mut self,
7866 renderer: &mut Renderer,
7867 atlas_texture_data: FigureSpriteAtlasData,
7868 atlas_size: Vec2<u16>,
7869 (opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
7870 vertex_ranges: [Range<u32>; N],
7871 ) -> FigureModelEntry<N> {
7872 span!(_guard, "create_figure", "FigureColLights::create_figure");
7873 let allocator = &mut self.allocator;
7874 let allocation = allocator
7875 .allocate(guillotiere::Size::new(
7876 atlas_size.x as i32,
7877 atlas_size.y as i32,
7878 ))
7879 .expect("Not yet implemented: allocate new atlas on allocation failure.");
7880 let [atlas_textures] = atlas_texture_data.create_textures(renderer, atlas_size);
7881 let atlas_textures = renderer.figure_bind_atlas_textures(atlas_textures);
7882 let model_len = u32::try_from(opaque.vertices().len())
7883 .expect("The model size for this figure does not fit in a u32!");
7884 let model = renderer.create_model(&opaque);
7885
7886 vertex_ranges.iter().for_each(|range| {
7887 assert!(
7888 range.start <= range.end && range.end <= model_len,
7889 "The provided vertex range for figure mesh {:?} does not fit in the model, which \
7890 is of size {:?}!",
7891 range,
7892 model_len
7893 );
7894 });
7895
7896 FigureModelEntry {
7897 _bounds: bounds,
7898 allocation,
7899 atlas_textures,
7900 lod_vertex_ranges: vertex_ranges,
7901 model: FigureModel { opaque: model },
7902 }
7903 }
7904
7905 pub fn create_terrain<const N: usize>(
7914 &mut self,
7915 renderer: &mut Renderer,
7916 atlas_texture_data: FigureSpriteAtlasData,
7918 atlas_size: Vec2<u16>,
7919 (opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
7920 vertex_ranges: [Range<u32>; N],
7921 sprite_instances: [Vec<SpriteInstance>; SPRITE_LOD_LEVELS],
7922 blocks_of_interest: BlocksOfInterest,
7923 blocks_offset: Vec3<f32>,
7924 ) -> TerrainModelEntry<N> {
7925 span!(_guard, "create_figure", "FigureColLights::create_figure");
7926 let allocator = &mut self.allocator;
7927 let allocation = allocator
7928 .allocate(guillotiere::Size::new(
7929 atlas_size.x as i32,
7930 atlas_size.y as i32,
7931 ))
7932 .expect("Not yet implemented: allocate new atlas on allocation failure.");
7933 let [col_lights] = atlas_texture_data.create_textures(renderer, atlas_size);
7934 let atlas_textures = renderer.figure_bind_atlas_textures(col_lights);
7936 let model_len = u32::try_from(opaque.vertices().len())
7937 .expect("The model size for this figure does not fit in a u32!");
7938 let model = renderer.create_model(&opaque);
7939
7940 vertex_ranges.iter().for_each(|range| {
7941 assert!(
7942 range.start <= range.end && range.end <= model_len,
7943 "The provided vertex range for figure mesh {:?} does not fit in the model, which \
7944 is of size {:?}!",
7945 range,
7946 model_len
7947 );
7948 });
7949
7950 let sprite_instances =
7951 sprite_instances.map(|instances| renderer.create_instances(&instances));
7952
7953 TerrainModelEntry {
7954 _bounds: bounds,
7955 allocation,
7956 atlas_textures,
7957 lod_vertex_ranges: vertex_ranges,
7958 model: FigureModel { opaque: model },
7959 sprite_instances,
7960 blocks_of_interest,
7961 blocks_offset,
7962 }
7963 }
7964
7965 fn make_allocator(renderer: &mut Renderer) -> Result<AtlasAllocator, RenderError> {
7966 let max_texture_size = renderer.max_texture_size();
7967 let atlas_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
7968 let allocator = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions {
7969 small_size_threshold: 32,
7971 large_size_threshold: 256,
7972 ..guillotiere::AllocatorOptions::default()
7973 });
7974 Ok(allocator)
7996 }
7997}
7998
7999pub struct FigureStateMeta {
8000 lantern_offset: Option<anim::vek::Vec3<f32>>,
8001 viewpoint_offset: Option<anim::vek::Vec3<f32>>,
8002 heads: Vec<anim::vek::Vec3<f32>>,
8003 tail: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
8004 pub main_abs_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
8005 pub off_abs_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
8006 mount_transform: anim::vek::Transform<f32, f32, f32>,
8008 mount_world_pos: anim::vek::Vec3<f32>,
8014 state_time: f32,
8015 last_ori: anim::vek::Quaternion<f32>,
8016 lpindex: u8,
8017 can_shadow_sun: bool,
8018 can_occlude_rain: bool,
8019 visible: bool,
8020 last_pos: Option<anim::vek::Vec3<f32>>,
8021 avg_vel: anim::vek::Vec3<f32>,
8022 last_light: f32,
8023 last_glow: (Vec3<f32>, f32),
8024 acc_vel: f32,
8025 bound: pipelines::figure::BoundLocals,
8026}
8027
8028impl FigureStateMeta {
8029 pub fn visible(&self) -> bool { self.visible }
8030
8031 pub fn can_shadow_sun(&self) -> bool {
8032 self.visible || self.can_shadow_sun
8034 }
8035
8036 pub fn can_occlude_rain(&self) -> bool {
8037 self.visible || self.can_occlude_rain
8039 }
8040}
8041
8042pub struct FigureState<S, D = ()> {
8043 meta: FigureStateMeta,
8044 skeleton: S,
8045 pub extra: D,
8046}
8047
8048impl<S, D> Deref for FigureState<S, D> {
8049 type Target = FigureStateMeta;
8050
8051 fn deref(&self) -> &Self::Target { &self.meta }
8052}
8053
8054impl<S, D> DerefMut for FigureState<S, D> {
8055 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.meta }
8056}
8057
8058pub struct FigureUpdateCommonParameters<'a> {
8061 pub entity: Option<EcsEntity>,
8062 pub pos: anim::vek::Vec3<f32>,
8063 pub ori: anim::vek::Quaternion<f32>,
8064 pub scale: f32,
8065 pub mount_transform_pos: Option<(anim::vek::Transform<f32, f32, f32>, anim::vek::Vec3<f32>)>,
8066 pub body: Option<Body>,
8067 pub tools: (Option<ToolKind>, Option<ToolKind>),
8068 pub col: Rgba<f32>,
8069 pub dt: f32,
8070 pub is_player: bool,
8071 pub terrain: Option<&'a Terrain>,
8072 pub ground_vel: Vec3<f32>,
8073}
8074
8075pub trait FigureData: Sized {
8076 fn new(renderer: &mut Renderer) -> Self;
8077
8078 fn update(&mut self, renderer: &mut Renderer, parameters: &FigureUpdateCommonParameters);
8079}
8080
8081impl FigureData for () {
8082 fn new(_renderer: &mut Renderer) {}
8083
8084 fn update(&mut self, _renderer: &mut Renderer, _parameters: &FigureUpdateCommonParameters) {}
8085}
8086
8087impl FigureData for BoundTerrainLocals {
8088 fn new(renderer: &mut Renderer) -> Self {
8089 renderer.create_terrain_bound_locals(&[TerrainLocals::new(
8090 Vec3::zero(),
8091 Quaternion::identity(),
8092 Vec2::zero(),
8093 0.0,
8094 )])
8095 }
8096
8097 fn update(&mut self, renderer: &mut Renderer, parameters: &FigureUpdateCommonParameters) {
8098 renderer.update_consts(self, &[TerrainLocals::new(
8099 parameters.pos,
8100 parameters.ori.into_vec4().into(),
8101 Vec2::zero(),
8102 0.0,
8103 )])
8104 }
8105}
8106
8107impl<S: Skeleton, D: FigureData> FigureState<S, D> {
8108 pub fn new(renderer: &mut Renderer, skeleton: S, body: S::Body) -> Self {
8109 let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
8110 let offsets =
8111 anim::compute_matrices(&skeleton, anim::vek::Mat4::identity(), &mut buf, body);
8112 let bone_consts = figure_bone_data_from_anim(&buf);
8113 Self {
8114 meta: FigureStateMeta {
8115 lantern_offset: offsets.lantern,
8116 viewpoint_offset: offsets.viewpoint,
8117 heads: offsets.heads.clone(),
8118 tail: offsets.tail,
8119 main_abs_trail_points: None,
8120 off_abs_trail_points: None,
8121 mount_transform: offsets.mount_bone,
8122 mount_world_pos: anim::vek::Vec3::zero(),
8123 state_time: 0.0,
8124 last_ori: Ori::default().into(),
8125 lpindex: 0,
8126 visible: false,
8127 can_shadow_sun: false,
8128 can_occlude_rain: false,
8129 last_pos: None,
8130 avg_vel: anim::vek::Vec3::zero(),
8131 last_light: 1.0,
8132 last_glow: (Vec3::zero(), 0.0),
8133 acc_vel: 0.0,
8134 bound: renderer.create_figure_bound_locals(&[FigureLocals::default()], bone_consts),
8135 },
8136 skeleton,
8137 extra: D::new(renderer),
8138 }
8139 }
8140
8141 pub fn update(
8142 &mut self,
8143 renderer: &mut Renderer,
8144 trail_mgr: Option<&mut TrailMgr>,
8145 buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
8146 parameters @ FigureUpdateCommonParameters {
8147 entity,
8148 pos,
8149 ori,
8150 scale,
8151 mount_transform_pos,
8152 body,
8153 tools,
8154 col,
8155 dt,
8156 is_player,
8157 terrain,
8158 ground_vel,
8159 }: &FigureUpdateCommonParameters,
8160 state_animation_rate: f32,
8161 model: Option<&impl ModelEntry>,
8162 skel_body: S::Body,
8166 ) {
8167 span!(_guard, "update", "FigureState::update");
8168
8169 let model = if let Some(model) = model {
8182 model
8183 } else {
8184 self.visible = false;
8185 return;
8186 };
8187
8188 self.last_ori = Lerp::lerp(self.last_ori, *ori, 15.0 * dt).normalized();
8196
8197 self.state_time += dt * state_animation_rate / scale;
8198
8199 let mat = {
8200 let scale_mat = anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(*scale));
8201 if let Some((transform, _)) = *mount_transform_pos {
8202 let rider_offset = anim::vek::Mat4::<f32>::translation_3d(
8212 body.map_or_else(Vec3::zero, |b| b.rider_offset()),
8213 );
8214
8215 let transform = anim::vek::Transform {
8219 orientation: *ori * transform.orientation,
8220 ..transform
8221 };
8222 anim::vek::Mat4::from(transform) * rider_offset * scale_mat
8223 } else {
8224 let ori_mat = anim::vek::Mat4::from(*ori);
8225 ori_mat * scale_mat
8226 }
8227 };
8228
8229 let atlas_offs = model.allocation().rectangle.min;
8230
8231 let (light, glow) = terrain
8232 .map(|t| {
8233 span!(
8234 _guard,
8235 "light_glow",
8236 "FigureState::update (fetch light/glow)"
8237 );
8238 let wpos = Vec3::from(pos.into_array()) + Vec3::unit_z();
8241
8242 let wposi = wpos.map(|e: f32| e.floor() as i32);
8243
8244 (t.light_at_wpos(wposi), t.glow_normal_at_wpos(wpos))
8269 })
8270 .unwrap_or((1.0, (Vec3::zero(), 0.0)));
8271 self.last_light = Lerp::lerp(self.last_light, light, 16.0 * dt);
8275 self.last_glow.0 = Lerp::lerp(self.last_glow.0, glow.0, 16.0 * dt);
8276 self.last_glow.1 = Lerp::lerp(self.last_glow.1, glow.1, 16.0 * dt);
8277
8278 let pos_with_mount_offset = mount_transform_pos.map_or(*pos, |(_, pos)| pos);
8279
8280 let locals = FigureLocals::new(
8281 mat,
8282 col.rgb(),
8283 pos_with_mount_offset,
8284 Vec2::new(atlas_offs.x, atlas_offs.y),
8285 *is_player,
8286 self.last_light,
8287 self.last_glow,
8288 );
8289 renderer.update_consts(&mut self.meta.bound.0, &[locals]);
8290
8291 let offsets = anim::compute_matrices(&self.skeleton, mat, buf, skel_body);
8292
8293 let new_bone_consts = figure_bone_data_from_anim(buf);
8294
8295 renderer.update_consts(&mut self.meta.bound.1, &new_bone_consts[0..S::BONE_COUNT]);
8296 self.lantern_offset = offsets.lantern;
8297 self.viewpoint_offset = offsets.viewpoint;
8298 self.heads.clone_from(&offsets.heads);
8299 self.tail = offsets.tail;
8300 fn handle_weapon_trails(
8302 trail_mgr: &mut TrailMgr,
8303 new_weapon_trail_mat: Option<(anim::vek::Mat4<f32>, anim::TrailSource)>,
8304 old_abs_trail_points: &mut Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
8305 entity: EcsEntity,
8306 is_main_weapon: bool,
8307 pos: anim::vek::Vec3<f32>,
8308 tool: Option<ToolKind>,
8309 ) {
8310 let weapon_offsets = new_weapon_trail_mat.map(|(mat, trail)| {
8311 let (trail_start, trail_end) = trail.relative_offsets(tool);
8312 ((mat * trail_start).xyz(), (mat * trail_end).xyz())
8313 });
8314 let new_abs_trail_points = weapon_offsets.map(|(a, b)| (a + pos, b + pos));
8315 if let (Some((p1, p2)), Some((p4, p3))) = (&old_abs_trail_points, new_abs_trail_points)
8316 {
8317 let trail_mgr_offset = trail_mgr.offset();
8318 let quad_mesh = trail_mgr.entity_mesh_or_insert(entity, is_main_weapon);
8319 let vertex = |p: anim::vek::Vec3<f32>| trail::Vertex {
8320 pos: p.into_array(),
8321 };
8322 let quad = Quad::new(vertex(*p1), vertex(*p2), vertex(p3), vertex(p4));
8323 quad_mesh.replace_quad(trail_mgr_offset * 4, quad);
8324 }
8325 *old_abs_trail_points = new_abs_trail_points;
8326 }
8327
8328 if let (Some(trail_mgr), Some(entity)) = (trail_mgr, entity) {
8329 handle_weapon_trails(
8330 trail_mgr,
8331 offsets.primary_trail_mat,
8332 &mut self.main_abs_trail_points,
8333 *entity,
8334 true,
8335 pos_with_mount_offset,
8336 tools.0,
8337 );
8338 handle_weapon_trails(
8339 trail_mgr,
8340 offsets.secondary_trail_mat,
8341 &mut self.off_abs_trail_points,
8342 *entity,
8343 false,
8344 pos_with_mount_offset,
8345 tools.1,
8346 );
8347 }
8348
8349 self.mount_transform = offsets.mount_bone;
8351 self.mount_world_pos = pos_with_mount_offset;
8352
8353 let smoothing = (5.0 * dt).min(1.0);
8354 if let Some(last_pos) = self.last_pos {
8355 self.avg_vel = (1.0 - smoothing) * self.avg_vel + smoothing * (pos - last_pos) / *dt;
8356 }
8357 self.last_pos = Some(*pos);
8358
8359 if self.avg_vel.magnitude_squared() != 0.0 {
8361 self.acc_vel += (self.avg_vel - *ground_vel).magnitude() * dt / scale;
8362 } else {
8363 self.acc_vel = 0.0;
8364 }
8365 self.extra.update(renderer, parameters);
8366 }
8367
8368 pub fn bound(&self) -> &pipelines::figure::BoundLocals { &self.bound }
8369
8370 pub fn skeleton_mut(&mut self) -> &mut S { &mut self.skeleton }
8371}
8372
8373fn figure_bone_data_from_anim(
8374 mats: &[anim::FigureBoneData; anim::MAX_BONE_COUNT],
8375) -> &[FigureBoneData] {
8376 bytemuck::cast_slice(mats)
8377}