added replicated `SpawnTrail` that acts as a marker and gets picked up by the client to create the visuals.
206 lines
6.7 KiB
Rust
206 lines
6.7 KiB
Rust
use crate::{
|
|
GameState,
|
|
abilities::{BuildExplosionSprite, healing::Healing},
|
|
animation::AnimationFlags,
|
|
backpack::{Backpack, backpack_ui::BackpackUiState},
|
|
camera::{CameraArmRotation, CameraTarget},
|
|
cash::CashResource,
|
|
character::{AnimatedCharacter, HedzCharacter},
|
|
control::{
|
|
ControlState, ControllerSettings, Inputs,
|
|
controller_common::{MovementSpeedFactor, PlayerCharacterController},
|
|
},
|
|
cutscene::StartCutscene,
|
|
global_observer,
|
|
head::ActiveHead,
|
|
heads::{ActiveHeads, heads_ui::UiActiveHeads},
|
|
hitpoints::Hitpoints,
|
|
npc::Npc,
|
|
platforms::ActivePlatform,
|
|
player::{Player, PlayerBodyMesh},
|
|
tick::GameTick,
|
|
utils::{
|
|
auto_rotate::AutoRotation, billboards::Billboard, squish_animation::SquishAnimation,
|
|
trail::SpawnTrail,
|
|
},
|
|
};
|
|
use avian3d::prelude::{
|
|
AngularInertia, AngularVelocity, CenterOfMass, Collider, ColliderDensity, CollisionLayers,
|
|
LinearVelocity, LockedAxes, Mass, Position, RigidBody, Rotation,
|
|
};
|
|
use bevy::{platform::collections::HashMap, prelude::*};
|
|
use bevy_replicon::prelude::{
|
|
AppRuleExt, Channel, ClientEventAppExt, ClientMessageAppExt, 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::<ControlState>(Channel::Unreliable);
|
|
|
|
app.add_client_event::<ClientEnteredPlaying>(Channel::Ordered);
|
|
|
|
app.add_server_message::<messages::DespawnTbMapEntity>(Channel::Unordered)
|
|
.add_server_message::<messages::AssignClientPlayer>(Channel::Unordered);
|
|
|
|
app.add_server_event::<ClientHeadChanged>(Channel::Unordered)
|
|
.add_server_event::<BuildExplosionSprite>(Channel::Unreliable)
|
|
.add_server_event::<StartCutscene>(Channel::Ordered)
|
|
.add_server_event::<events::PlaySound>(Channel::Unreliable)
|
|
.add_server_event::<events::SetGameTick>(Channel::Ordered);
|
|
|
|
app.register_type::<PlayerId>();
|
|
app.register_type::<TbMapEntityId>();
|
|
app.register_type::<TbMapIdCounter>();
|
|
app.register_type::<TbMapEntityMapping>();
|
|
|
|
app.init_resource::<PlayerIdMap>();
|
|
app.init_resource::<TbMapIdCounter>();
|
|
app.init_resource::<TbMapEntityMapping>();
|
|
|
|
app.replicate::<ChildOf>();
|
|
app.sync_related_entities::<ChildOf>();
|
|
|
|
app.replicate::<components::GltfSceneRoot>()
|
|
.replicate_once::<components::PlayerId>()
|
|
.replicate::<components::TbMapEntityId>()
|
|
.replicate::<ActiveHead>()
|
|
.replicate::<ActiveHeads>()
|
|
.replicate::<ActivePlatform>()
|
|
.replicate::<AnimatedCharacter>()
|
|
.replicate::<AnimationFlags>()
|
|
.replicate_once::<AutoRotation>()
|
|
.replicate::<Backpack>()
|
|
.replicate::<BackpackUiState>()
|
|
.replicate::<Billboard>()
|
|
.replicate_once::<CameraArmRotation>()
|
|
.replicate_once::<CameraTarget>()
|
|
.replicate::<CashResource>()
|
|
.replicate_once::<HedzCharacter>()
|
|
.replicate_once::<Healing>()
|
|
.replicate::<Hitpoints>()
|
|
.replicate::<Inputs>()
|
|
.replicate::<Name>()
|
|
.replicate_once::<Player>()
|
|
.replicate_once::<PlayerBodyMesh>()
|
|
.replicate_once::<Npc>()
|
|
.replicate::<SquishAnimation>()
|
|
.replicate_once::<Transform>()
|
|
.replicate_once::<SpawnTrail>()
|
|
.replicate::<UiActiveHeads>()
|
|
.replicate_as::<Visibility, SerVisibility>();
|
|
|
|
// Physics components
|
|
app.replicate::<AngularInertia>()
|
|
.replicate::<AngularVelocity>()
|
|
.replicate::<CenterOfMass>()
|
|
.replicate_filtered_as::<Collider, NetworkedCollider, Without<SkipReplicateColliders>>()
|
|
.replicate::<ColliderDensity>()
|
|
.replicate::<CollisionLayers>()
|
|
.replicate::<LinearVelocity>()
|
|
.replicate::<LockedAxes>()
|
|
.replicate::<Mass>()
|
|
.replicate::<Position>()
|
|
.replicate::<RigidBody>()
|
|
.replicate::<Rotation>();
|
|
|
|
// Character controller components
|
|
app.replicate::<CharacterDrag>()
|
|
.replicate::<CharacterGravity>()
|
|
.replicate::<CharacterMovement>()
|
|
.replicate::<ControllerSettings>()
|
|
.replicate::<GroundFriction>()
|
|
.replicate::<Grounding>()
|
|
.replicate::<GroundingConfig>()
|
|
.replicate::<GroundingState>()
|
|
.replicate::<KinematicVelocity>()
|
|
.replicate::<MoveInput>()
|
|
.replicate::<MovementSpeedFactor>()
|
|
.replicate_once::<PlayerCharacterController>()
|
|
.replicate::<SteppingConfig>();
|
|
|
|
app.add_systems(
|
|
OnEnter(GameState::MapLoading),
|
|
|mut counter: ResMut<TbMapIdCounter>| counter.reset(),
|
|
);
|
|
|
|
global_observer!(app, set_game_tick);
|
|
global_observer!(app, components::spawn_gltf_scene_roots);
|
|
}
|
|
|
|
fn set_game_tick(on: On<SetGameTick>, mut tick: ResMut<GameTick>) {
|
|
tick.0 = on.event().0;
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
enum SerVisibility {
|
|
Inherited,
|
|
Hidden,
|
|
Visible,
|
|
}
|
|
|
|
impl From<Visibility> for SerVisibility {
|
|
fn from(value: Visibility) -> Self {
|
|
match value {
|
|
Visibility::Inherited => Self::Inherited,
|
|
Visibility::Hidden => Self::Hidden,
|
|
Visibility::Visible => Self::Visible,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<SerVisibility> 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<u64, Entity>);
|
|
|
|
#[derive(Component)]
|
|
#[relationship(relationship_target = ClientOwns)]
|
|
pub struct OwnedByClient(pub Entity);
|
|
|
|
#[derive(Component)]
|
|
#[relationship_target(relationship = OwnedByClient, linked_spawn)]
|
|
pub struct ClientOwns(Entity);
|