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