Switch to replicon (#80)
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::{light::NotShadowCaster, prelude::*};
|
||||
use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients};
|
||||
use bevy_sprite3d::Sprite3d;
|
||||
|
||||
#[derive(Component)]
|
||||
@@ -44,7 +45,10 @@ fn on_trigger_arrow(
|
||||
) {
|
||||
let state = trigger.0;
|
||||
|
||||
commands.trigger(PlaySound::Crossbow);
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: PlaySound::Crossbow,
|
||||
});
|
||||
|
||||
let rotation = if let Some(target) = state.target {
|
||||
let t = query_transform
|
||||
|
||||
@@ -6,12 +6,11 @@ use crate::{
|
||||
physics_layers::GameLayer,
|
||||
protocol::GltfSceneRoot,
|
||||
tb_entities::EnemySpawn,
|
||||
utils::{auto_rotate::AutoRotation, commands::CommandExt, global_observer},
|
||||
utils::{auto_rotate::AutoRotation, global_observer},
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
#[cfg(feature = "server")]
|
||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||
use bevy_replicon::prelude::{Replicated, SendMode, ServerTriggerExt, ToClients};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
const MAX_SHOT_AGES: f32 = 15.;
|
||||
@@ -60,7 +59,7 @@ fn on_trigger_missile(
|
||||
let mut transform = Transform::from_translation(state.pos).with_rotation(rotation);
|
||||
transform.translation += transform.forward().as_vec3() * 2.0;
|
||||
|
||||
let mut _projectile = commands.spawn((
|
||||
commands.spawn((
|
||||
Name::new("projectile-missile"),
|
||||
CurverProjectile {
|
||||
time: time.elapsed_secs(),
|
||||
@@ -75,15 +74,13 @@ fn on_trigger_missile(
|
||||
CollisionEventsEnabled,
|
||||
Visibility::default(),
|
||||
transform,
|
||||
Replicated,
|
||||
children![(
|
||||
Transform::from_rotation(Quat::from_rotation_x(PI / 2.).inverse()),
|
||||
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
||||
GltfSceneRoot::Projectile(head.projectile.clone()),
|
||||
),],
|
||||
));
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
_projectile.insert(Replicate::to_clients(NetworkTarget::All));
|
||||
}
|
||||
|
||||
fn enemy_hit(
|
||||
@@ -169,10 +166,13 @@ fn shot_collision(
|
||||
continue;
|
||||
}
|
||||
|
||||
commands.trigger_server(BuildExplosionSprite {
|
||||
pos: shot_pos,
|
||||
pixels_per_meter: 128.,
|
||||
time: 0.01,
|
||||
commands.server_trigger(ToClients {
|
||||
message: BuildExplosionSprite {
|
||||
pos: shot_pos,
|
||||
pixels_per_meter: 128.,
|
||||
time: 0.01,
|
||||
},
|
||||
mode: SendMode::Broadcast,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::{light::NotShadowCaster, prelude::*};
|
||||
use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients};
|
||||
use bevy_sprite3d::Sprite3d;
|
||||
|
||||
#[derive(Component)]
|
||||
@@ -91,7 +92,10 @@ fn on_trigger_gun(
|
||||
) {
|
||||
let state = trigger.0;
|
||||
|
||||
commands.trigger(PlaySound::Gun);
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: PlaySound::Gun,
|
||||
});
|
||||
|
||||
let rotation = if let Some(t) = state
|
||||
.target
|
||||
|
||||
@@ -9,8 +9,7 @@ use crate::{
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
#[cfg(feature = "server")]
|
||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||
use bevy_replicon::prelude::Replicated;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
const MAX_SHOT_AGES: f32 = 15.;
|
||||
@@ -61,7 +60,7 @@ fn on_trigger_missile(
|
||||
let mut transform = Transform::from_translation(state.pos).with_rotation(rotation);
|
||||
transform.translation += transform.forward().as_vec3() * 2.0;
|
||||
|
||||
let mut _projectile = commands.spawn((
|
||||
commands.spawn((
|
||||
Name::new("projectile-missile"),
|
||||
MissileProjectile {
|
||||
time: time.elapsed_secs(),
|
||||
@@ -73,13 +72,16 @@ fn on_trigger_missile(
|
||||
LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()),
|
||||
),
|
||||
Sensor,
|
||||
RigidBody::Kinematic,
|
||||
CollisionEventsEnabled,
|
||||
Visibility::default(),
|
||||
transform,
|
||||
Replicated,
|
||||
children![
|
||||
(
|
||||
Transform::from_rotation(Quat::from_rotation_x(PI / 2.).inverse()),
|
||||
GltfSceneRoot::Projectile("missile".to_string()),
|
||||
Replicated,
|
||||
),
|
||||
(
|
||||
Trail::new(
|
||||
@@ -99,8 +101,6 @@ fn on_trigger_missile(
|
||||
)
|
||||
],
|
||||
));
|
||||
#[cfg(feature = "server")]
|
||||
_projectile.insert(Replicate::to_clients(NetworkTarget::All));
|
||||
}
|
||||
|
||||
fn update(mut query: Query<&mut Transform, With<MissileProjectile>>) {
|
||||
|
||||
@@ -10,21 +10,25 @@ use crate::{
|
||||
loading_assets::GameAssets,
|
||||
physics_layers::GameLayer,
|
||||
protocol::PlaySound,
|
||||
utils::{billboards::Billboard, sprite_3d_animation::AnimationTimer},
|
||||
utils::{billboards::Billboard, explosions::Explosion, sprite_3d_animation::AnimationTimer},
|
||||
};
|
||||
#[cfg(feature = "server")]
|
||||
use crate::{
|
||||
aim::AimTarget, character::CharacterHierarchy, control::ControlState, head::ActiveHead,
|
||||
heads::ActiveHeads, heads_database::HeadsDatabase, player::Player,
|
||||
utils::explosions::Explosion,
|
||||
aim::AimTarget,
|
||||
character::CharacterHierarchy,
|
||||
control::{ControlState, Inputs},
|
||||
head::ActiveHead,
|
||||
heads::ActiveHeads,
|
||||
heads_database::HeadsDatabase,
|
||||
player::Player,
|
||||
protocol::ClientToController,
|
||||
};
|
||||
use bevy::{light::NotShadowCaster, prelude::*};
|
||||
#[cfg(feature = "server")]
|
||||
use bevy_replicon::prelude::FromClient;
|
||||
use bevy_replicon::prelude::{ClientState, SendMode, ServerTriggerExt, ToClients};
|
||||
use bevy_sprite3d::Sprite3d;
|
||||
pub use healing::Healing;
|
||||
#[cfg(feature = "server")]
|
||||
use healing::HealingStateChanged;
|
||||
#[cfg(feature = "server")]
|
||||
use lightyear::prelude::input::native::ActionState;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Reflect, Default, Serialize, Deserialize)]
|
||||
@@ -143,16 +147,16 @@ pub fn plugin(app: &mut App) {
|
||||
.chain()
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
#[cfg(feature = "server")]
|
||||
app.add_systems(
|
||||
FixedUpdate,
|
||||
explode_projectiles.in_set(ExplodingProjectileSet::Explode),
|
||||
explode_projectiles
|
||||
.run_if(in_state(ClientState::Disconnected))
|
||||
.in_set(ExplodingProjectileSet::Explode),
|
||||
);
|
||||
|
||||
global_observer!(app, build_explosion_sprite);
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
fn explode_projectiles(mut commands: Commands, query: Query<(Entity, &ExplodingProjectile)>) {
|
||||
for (shot_entity, projectile) in query.iter() {
|
||||
if let Ok(mut entity) = commands.get_entity(shot_entity) {
|
||||
@@ -161,7 +165,10 @@ fn explode_projectiles(mut commands: Commands, query: Query<(Entity, &ExplodingP
|
||||
continue;
|
||||
}
|
||||
|
||||
commands.trigger(projectile.sound.clone());
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: projectile.sound.clone(),
|
||||
});
|
||||
|
||||
commands.trigger(Explosion {
|
||||
damage: projectile.damage,
|
||||
@@ -172,12 +179,13 @@ fn explode_projectiles(mut commands: Commands, query: Query<(Entity, &ExplodingP
|
||||
|
||||
//TODO: support different impact animations
|
||||
if projectile.animation {
|
||||
use crate::utils::commands::CommandExt;
|
||||
|
||||
commands.trigger_server(BuildExplosionSprite {
|
||||
pos: projectile.position,
|
||||
pixels_per_meter: projectile.anim_pixels_per_meter,
|
||||
time: projectile.anim_time,
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: BuildExplosionSprite {
|
||||
pos: projectile.position,
|
||||
pixels_per_meter: projectile.anim_pixels_per_meter,
|
||||
time: projectile.anim_time,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -186,11 +194,15 @@ fn explode_projectiles(mut commands: Commands, query: Query<(Entity, &ExplodingP
|
||||
#[cfg(feature = "server")]
|
||||
fn on_trigger_state(
|
||||
mut res: ResMut<TriggerStateRes>,
|
||||
player: Query<(&ActiveHead, &ActionState<ControlState>), With<Player>>,
|
||||
players: Query<&ActiveHead, With<Player>>,
|
||||
clients: ClientToController,
|
||||
mut controls: MessageReader<FromClient<ControlState>>,
|
||||
headdb: Res<HeadsDatabase>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
for (player_head, controls) in player.iter() {
|
||||
for controls in controls.read() {
|
||||
let player = clients.get_controller(controls.client_id);
|
||||
let player_head = players.get(player).unwrap();
|
||||
res.active = controls.trigger;
|
||||
if controls.just_triggered {
|
||||
let head_stats = headdb.head_stats(player_head.0);
|
||||
@@ -203,7 +215,7 @@ fn on_trigger_state(
|
||||
fn update(
|
||||
mut res: ResMut<TriggerStateRes>,
|
||||
mut commands: Commands,
|
||||
player_query: Query<(Entity, &AimTarget, &ActionState<ControlState>), With<Player>>,
|
||||
player_query: Query<(Entity, &AimTarget, &Inputs), With<Player>>,
|
||||
mut active_heads: Single<&mut ActiveHeads, With<Player>>,
|
||||
heads_db: Res<HeadsDatabase>,
|
||||
time: Res<Time>,
|
||||
@@ -215,11 +227,14 @@ fn update(
|
||||
};
|
||||
|
||||
if !state.has_ammo() {
|
||||
commands.trigger(PlaySound::Invalid);
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: PlaySound::Invalid,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let Some((player, target, actions)) = player_query.iter().next() else {
|
||||
let Some((player, target, inputs)) = player_query.iter().next() else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -241,7 +256,7 @@ fn update(
|
||||
res.next_trigger_timestamp = time.elapsed_secs() + (1. / head.aps);
|
||||
|
||||
let trigger_state = TriggerData {
|
||||
dir: actions.look_dir,
|
||||
dir: Dir3::try_from(inputs.look_dir).unwrap_or(Dir3::NEG_Z),
|
||||
pos: projectile_origin,
|
||||
target: target.0,
|
||||
target_layer: GameLayer::Npc,
|
||||
@@ -281,11 +296,15 @@ fn update_heal_ability(
|
||||
|
||||
use crate::abilities::healing::HealingState;
|
||||
if res.active {
|
||||
use crate::abilities::healing::HealingStateChanged;
|
||||
|
||||
commands.trigger(HealingStateChanged {
|
||||
state: HealingState::Started,
|
||||
entity: player,
|
||||
});
|
||||
} else {
|
||||
use crate::abilities::healing::HealingStateChanged;
|
||||
|
||||
commands.trigger(HealingStateChanged {
|
||||
state: HealingState::Stopped,
|
||||
entity: player,
|
||||
|
||||
@@ -9,8 +9,7 @@ use crate::{
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
use bevy_ballistic::launch_velocity;
|
||||
#[cfg(feature = "server")]
|
||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||
use bevy_replicon::prelude::{Replicated, SendMode, ServerTriggerExt, ToClients};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Component, Serialize, Deserialize, PartialEq)]
|
||||
@@ -36,7 +35,10 @@ fn on_trigger_thrown(
|
||||
) {
|
||||
let state = trigger.event().0;
|
||||
|
||||
commands.trigger(PlaySound::Throw);
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: PlaySound::Throw,
|
||||
});
|
||||
|
||||
const SPEED: f32 = 35.;
|
||||
|
||||
@@ -57,32 +59,32 @@ fn on_trigger_thrown(
|
||||
//TODO: projectile db?
|
||||
let explosion_animation = !matches!(state.head, 8 | 16);
|
||||
|
||||
let mut projectile = commands.spawn((
|
||||
Transform::from_translation(pos),
|
||||
Name::new("projectile-thrown"),
|
||||
ThrownProjectile {
|
||||
impact_animation: explosion_animation,
|
||||
damage: head.damage,
|
||||
},
|
||||
Collider::sphere(0.4),
|
||||
CollisionLayers::new(
|
||||
LayerMask(GameLayer::Projectile.to_bits()),
|
||||
LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()),
|
||||
),
|
||||
RigidBody::Dynamic,
|
||||
CollisionEventsEnabled,
|
||||
Mass(0.01),
|
||||
LinearVelocity(vel),
|
||||
Visibility::default(),
|
||||
Sensor,
|
||||
));
|
||||
projectile.with_child((
|
||||
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
||||
GltfSceneRoot::Projectile(head.projectile.clone()),
|
||||
));
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
projectile.insert(Replicate::to_clients(NetworkTarget::All));
|
||||
commands
|
||||
.spawn((
|
||||
Transform::from_translation(pos),
|
||||
Name::new("projectile-thrown"),
|
||||
ThrownProjectile {
|
||||
impact_animation: explosion_animation,
|
||||
damage: head.damage,
|
||||
},
|
||||
Collider::sphere(0.4),
|
||||
CollisionLayers::new(
|
||||
LayerMask(GameLayer::Projectile.to_bits()),
|
||||
LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()),
|
||||
),
|
||||
RigidBody::Dynamic,
|
||||
CollisionEventsEnabled,
|
||||
Mass(0.01),
|
||||
LinearVelocity(vel),
|
||||
Visibility::default(),
|
||||
Sensor,
|
||||
Replicated,
|
||||
))
|
||||
.with_child((
|
||||
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
||||
GltfSceneRoot::Projectile(head.projectile.clone()),
|
||||
Replicated,
|
||||
));
|
||||
}
|
||||
|
||||
fn shot_collision(
|
||||
|
||||
Reference in New Issue
Block a user