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