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