125 lines
3.8 KiB
Rust
125 lines
3.8 KiB
Rust
use bevy::prelude::*;
|
|
use lightyear::prelude::{input::native::ActionState, *};
|
|
use shared::{
|
|
backpack::{Backpack, backpack_ui::BackpackUiState},
|
|
camera::{CameraArmRotation, CameraTarget},
|
|
cash::CashResource,
|
|
character::AnimatedCharacter,
|
|
control::{ControlState, controller_common::PlayerCharacterController},
|
|
global_observer,
|
|
head::ActiveHead,
|
|
head_drop::HeadDrops,
|
|
heads::{ActiveHeads, HeadChanged, HeadState, heads_ui::UiActiveHeads},
|
|
heads_database::HeadsDatabase,
|
|
hitpoints::{Hitpoints, Kill},
|
|
npc::SpawnCharacter,
|
|
player::{Player, PlayerBodyMesh},
|
|
protocol::{
|
|
PlaySound, PlayerId, channels::UnorderedReliableChannel, events::ClientHeadChanged,
|
|
},
|
|
tb_entities::SpawnPoint,
|
|
};
|
|
|
|
pub fn plugin(app: &mut App) {
|
|
global_observer!(app, on_update_head_mesh);
|
|
}
|
|
|
|
pub fn spawn(
|
|
mut commands: Commands,
|
|
owner: Entity,
|
|
query: Query<&Transform, With<SpawnPoint>>,
|
|
heads_db: Res<HeadsDatabase>,
|
|
) -> Option<Entity> {
|
|
let spawn = query.iter().next()?;
|
|
|
|
let transform = Transform::from_translation(spawn.translation + Vec3::new(0., 3., 0.));
|
|
|
|
let mut player = commands.spawn((
|
|
(
|
|
Name::from("player"),
|
|
Player,
|
|
ActiveHead(0),
|
|
ActiveHeads::new([
|
|
Some(HeadState::new(0, heads_db.as_ref())),
|
|
Some(HeadState::new(3, heads_db.as_ref())),
|
|
Some(HeadState::new(6, heads_db.as_ref())),
|
|
Some(HeadState::new(10, heads_db.as_ref())),
|
|
Some(HeadState::new(9, heads_db.as_ref())),
|
|
]),
|
|
Hitpoints::new(100),
|
|
CashResource::default(),
|
|
CameraTarget,
|
|
transform,
|
|
Visibility::default(),
|
|
PlayerCharacterController,
|
|
PlayerId { id: 0 },
|
|
),
|
|
ActionState::<ControlState>::default(),
|
|
Backpack::default(),
|
|
BackpackUiState::default(),
|
|
UiActiveHeads::default(),
|
|
Replicate::to_clients(NetworkTarget::All),
|
|
PredictionTarget::to_clients(NetworkTarget::All),
|
|
ControlledBy {
|
|
owner,
|
|
lifetime: Lifetime::SessionBased,
|
|
},
|
|
children![(
|
|
Name::new("player-rig"),
|
|
PlayerBodyMesh,
|
|
CameraArmRotation,
|
|
children![AnimatedCharacter::new(0)],
|
|
)],
|
|
));
|
|
player.observe(on_kill);
|
|
|
|
let id = player.id();
|
|
|
|
commands.trigger(PlaySound::Head("angry demonstrator".to_string()));
|
|
commands.trigger(SpawnCharacter(transform.translation));
|
|
|
|
Some(id)
|
|
}
|
|
|
|
fn on_kill(
|
|
trigger: Trigger<Kill>,
|
|
mut commands: Commands,
|
|
mut query: Query<(&Transform, &ActiveHead, &mut ActiveHeads, &mut Hitpoints)>,
|
|
) {
|
|
let Ok((transform, active, mut heads, mut hp)) = query.get_mut(trigger.target()) else {
|
|
return;
|
|
};
|
|
|
|
commands.trigger(HeadDrops::new(transform.translation, active.0));
|
|
|
|
if let Some(new_head) = heads.loose_current() {
|
|
hp.set_health(heads.current().unwrap().health);
|
|
|
|
commands.trigger(HeadChanged(new_head));
|
|
}
|
|
}
|
|
|
|
fn on_update_head_mesh(
|
|
trigger: Trigger<HeadChanged>,
|
|
mut commands: Commands,
|
|
mesh_children: Single<&Children, With<PlayerBodyMesh>>,
|
|
mut sender: Single<&mut TriggerSender<ClientHeadChanged>>,
|
|
animated_characters: Query<&AnimatedCharacter>,
|
|
mut player: Single<&mut ActiveHead, With<Player>>,
|
|
) -> Result {
|
|
let animated_char = mesh_children
|
|
.iter()
|
|
.find(|child| animated_characters.contains(*child))
|
|
.ok_or("tried to update head mesh before AnimatedCharacter was readded")?;
|
|
|
|
player.0 = trigger.0;
|
|
|
|
commands
|
|
.entity(animated_char)
|
|
.insert(AnimatedCharacter::new(trigger.0));
|
|
|
|
sender.trigger::<UnorderedReliableChannel>(ClientHeadChanged(trigger.0 as u64));
|
|
|
|
Ok(())
|
|
}
|