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