use crate::{ abilities::BuildExplosionSprite, animation::AnimationFlags, camera::{CameraArmRotation, CameraTarget}, character::{self, AnimatedCharacter}, control::{ controller_common::{MovementSpeedFactor, PlayerCharacterController}, controls::ControllerSettings, }, global_observer, head::ActiveHead, heads::ActiveHeads, loading_assets::GameAssets, player::{Player, PlayerBodyMesh}, utils::triggers::TriggerAppExt, }; use avian3d::prelude::{AngularVelocity, CollisionLayers, LinearVelocity}; use bevy::prelude::*; use happy_feet::{ grounding::GroundingState, prelude::{ Character, CharacterDrag, CharacterGravity, CharacterMovement, GroundFriction, Grounding, GroundingConfig, KinematicVelocity, MoveInput, SteppingConfig, }, }; use lightyear::prelude::{ ActionsChannel, AppComponentExt, PredictionMode, PredictionRegistrationExt, }; use lightyear_serde::{ SerializationError, reader::ReadInteger, registry::SerializeFns, writer::WriteInteger, }; use serde::{Deserialize, Serialize}; pub fn plugin(app: &mut App) { app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::(); app.register_component::() .add_prediction(PredictionMode::Full) .add_should_rollback(transform_should_rollback); // `Visibility` isn't `(De)Serialize`, so we have to provide custom serde for it. app.register_component_custom_serde::(SerializeFns { serialize: |comp, writer| writer.write_u8(*comp as u8).map_err(SerializationError::Io), deserialize: |reader| { let byte = reader.read_u8().map_err(SerializationError::Io)?; Ok(match byte { 0 => Visibility::Inherited, 1 => Visibility::Hidden, 2 => Visibility::Visible, _ => return Err(SerializationError::InvalidValue), }) }, }); app.replicate_trigger::(); global_observer!(app, spawn_gltf_scene_roots); } fn transform_should_rollback(this: &Transform, that: &Transform) -> bool { this.translation.distance_squared(that.translation) >= 0.01f32.powf(2.) } #[derive(Component, Reflect, Serialize, Deserialize, PartialEq)] #[reflect(Component)] pub enum GltfSceneRoot { Projectile(String), } fn spawn_gltf_scene_roots( trigger: Trigger, mut commands: Commands, gltf_roots: Query<&GltfSceneRoot>, assets: Res, gltfs: Res>, ) -> Result { let root = gltf_roots.get(trigger.target())?; let (gltf, index) = match root { GltfSceneRoot::Projectile(addr) => ( assets.projectiles[format!("{addr}.glb").as_str()].clone(), 0, ), }; let gltf = gltfs.get(&gltf).unwrap(); let scene = gltf.scenes[index].clone(); commands.entity(trigger.target()).insert(SceneRoot(scene)); Ok(()) }