use crate::{ GameState, abilities::{ BuildExplosionSprite, curver::CurverProjectile, healing::Healing, thrown::ThrownProjectile, }, animation::AnimationFlags, backpack::{Backpack, BackpackSwapEvent}, camera::{CameraArmRotation, CameraTarget}, cash::{Cash, CashInventory}, character::{AnimatedCharacter, HedzCharacter}, control::{ CashHealPressed, ClientInputs, ControllerSettings, Inputs, SelectLeftPressed, SelectRightPressed, controller_common::{MovementSpeedFactor, PlayerCharacterController}, }, cutscene::StartCutscene, global_observer, head::ActiveHead, heads::ActiveHeads, hitpoints::Hitpoints, npc::Npc, platforms::ActivePlatform, player::{Player, PlayerBodyMesh}, tick::GameTick, utils::{ Billboard, auto_rotate::AutoRotation, squish_animation::SquishAnimation, trail::SpawnTrail, }, }; use avian3d::prelude::{ AngularInertia, AngularVelocity, CenterOfMass, Collider, ColliderDensity, CollisionLayers, LinearVelocity, LockedAxes, Mass, Position, RigidBody, Rotation, }; use bevy::{ecs::system::SystemParam, platform::collections::HashMap, prelude::*}; use bevy_replicon::prelude::{ AppRuleExt, Channel, ClientEventAppExt, ClientMessageAppExt, ClientState, ServerEventAppExt, ServerMessageAppExt, SyncRelatedAppExt, }; pub use components::*; pub use events::*; use happy_feet::{ grounding::GroundingState, prelude::{ CharacterDrag, CharacterGravity, CharacterMovement, GroundFriction, Grounding, GroundingConfig, KinematicVelocity, MoveInput, SteppingConfig, }, }; use serde::{Deserialize, Serialize}; pub mod components; pub mod events; pub mod messages; pub fn plugin(app: &mut App) { app.add_client_message::(Channel::Unreliable) .add_client_message::(Channel::Ordered) .add_client_message::(Channel::Ordered) .add_client_message::(Channel::Ordered); app.add_client_event::(Channel::Ordered) .add_client_event::(Channel::Ordered); app.add_server_message::(Channel::Unordered) .add_server_message::(Channel::Unordered); app.add_server_event::(Channel::Unordered) .add_server_event::(Channel::Unreliable) .add_server_event::(Channel::Ordered) .add_server_event::(Channel::Unreliable) .add_server_event::(Channel::Ordered); app.register_type::(); app.register_type::(); app.register_type::(); app.register_type::(); app.init_resource::(); app.init_resource::(); app.init_resource::(); app.init_resource::(); app.replicate::(); app.sync_related_entities::(); app.replicate_once::() .replicate_once::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate_once::() .replicate::() .replicate::() .replicate_once::() .replicate_once::() .replicate::() .replicate_once::() .replicate_once::() .replicate::() .replicate::() .replicate::() .replicate_once::() .replicate_once::() .replicate_once::() .replicate::() .replicate_once::() .replicate_once::() .replicate_once::() .replicate_as::(); app.replicate_once::() .replicate_once::(); // Physics components app.replicate::() .replicate::() .replicate::() .replicate_filtered_as::>() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::(); // Character controller components app.replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate::() .replicate_once::() .replicate::(); app.add_systems( OnEnter(GameState::MapLoading), |mut counter: ResMut| counter.reset(), ); global_observer!(app, set_game_tick); global_observer!(app, components::spawn_gltf_scene_roots); } #[derive(SystemParam)] pub struct NetworkEnv<'w> { client_state: Res<'w, State>, } impl NetworkEnv<'_> { /// Returns true if this process is currently responsible for being the server/host/"source of truth". /// May change over time. pub fn is_server(&self) -> bool { matches!(**self.client_state, ClientState::Disconnected) } } pub fn is_server(env: NetworkEnv) -> bool { env.is_server() } fn set_game_tick(on: On, mut tick: ResMut) { tick.0 = on.event().0; } #[derive(Serialize, Deserialize)] enum SerVisibility { Inherited, Hidden, Visible, } impl From for SerVisibility { fn from(value: Visibility) -> Self { match value { Visibility::Inherited => Self::Inherited, Visibility::Hidden => Self::Hidden, Visibility::Visible => Self::Visible, } } } impl From for Visibility { fn from(value: SerVisibility) -> Self { match value { SerVisibility::Inherited => Self::Inherited, SerVisibility::Hidden => Self::Hidden, SerVisibility::Visible => Self::Visible, } } } /// A global allocator for `TbMapEntityId` values. Should be reset when a map begins loading. #[derive(Resource, Reflect, Default)] #[reflect(Resource)] pub struct TbMapIdCounter(u64); impl TbMapIdCounter { pub fn reset(&mut self) { self.0 = 0; } pub fn alloc(&mut self) -> TbMapEntityId { let id = self.0; self.0 += 1; TbMapEntityId { id } } } /// A mapping from TbMapEntityId to clientside map entity. When the serverside is spawned and the client's /// components migrated to it, or the clientside is despawned because the serverside is already despawned, /// the Id entry is removed from this mapping. #[derive(Resource, Reflect, Default, Deref, DerefMut)] #[reflect(Resource)] pub struct TbMapEntityMapping(pub HashMap); #[derive(Component)] #[relationship(relationship_target = ClientOwns)] pub struct OwnedByClient(pub Entity); #[derive(Component)] #[relationship_target(relationship = OwnedByClient, linked_spawn)] pub struct ClientOwns(Entity);