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