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