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