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