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