Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutiplayer: sync laser trails #768

Merged
merged 1 commit into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/combat/src/laser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use parry3d::query::Ray;
use crate::{
health::{HealthSet, LocalUpdateHealthEvent},
sightline::LineOfSight,
trail::TrailEvent,
trail::LocalLaserTrailEvent,
AttackingSet,
};

Expand Down Expand Up @@ -80,13 +80,13 @@ fn fire(
mut fires: EventReader<LaserFireEvent>,
sightline: LineOfSight,
mut health: EventWriter<LocalUpdateHealthEvent>,
mut trail: EventWriter<TrailEvent>,
mut trail: EventWriter<LocalLaserTrailEvent>,
mut start_sound: EventWriter<PlaySpatialAudioEvent>,
) {
for fire in fires.iter() {
let observation = sightline.sight(fire.ray(), fire.max_toi(), fire.attacker());

trail.send(TrailEvent::new(Ray::new(
trail.send(LocalLaserTrailEvent::new(Ray::new(
fire.ray().origin,
observation.toi() * fire.ray().dir,
)));
Expand Down
73 changes: 59 additions & 14 deletions crates/combat/src/trail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ use bevy::{
},
},
};
use de_core::{cleanup::DespawnOnGameExit, gamestate::GameState, state::AppState};
use de_core::{
cleanup::DespawnOnGameExit, gamestate::GameState, gconfig::GameConfig, state::AppState,
};
use de_messages::{NetProjectile, ToPlayers};
use de_multiplayer::{MessagesSet, NetRecvProjectileEvent, ToPlayersEvent};
use parry3d::query::Ray;

const TRAIL_LIFESPAN: Duration = Duration::from_millis(500);
Expand All @@ -22,20 +26,29 @@ pub(crate) struct TrailPlugin;
impl Plugin for TrailPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(MaterialPlugin::<TrailMaterial>::default())
.add_event::<TrailEvent>()
.add_event::<LocalLaserTrailEvent>()
.add_event::<LaserTrailEvent>()
.add_systems(OnEnter(AppState::InGame), setup)
.add_systems(OnExit(AppState::InGame), cleanup)
.add_systems(
PostUpdate,
(spawn, update).run_if(in_state(GameState::Playing)),
(
local_laser_trail
.before(MessagesSet::SendMessages)
.before(laser_trail),
remote_laser_trail.before(laser_trail),
laser_trail,
update,
)
.run_if(in_state(GameState::Playing)),
);
}
}

#[derive(Event)]
pub(crate) struct TrailEvent(Ray);
pub(crate) struct LocalLaserTrailEvent(Ray);

impl TrailEvent {
impl LocalLaserTrailEvent {
/// Send this event to spawn a new trail. The trail will automatically fade
/// out and disappear.
///
Expand All @@ -46,12 +59,11 @@ impl TrailEvent {
pub(crate) fn new(ray: Ray) -> Self {
Self(ray)
}

fn ray(&self) -> &Ray {
&self.0
}
}

#[derive(Event)]
struct LaserTrailEvent(Ray);

#[derive(Resource)]
struct MeshHandle(Handle<Mesh>);

Expand Down Expand Up @@ -104,12 +116,45 @@ impl Material for TrailMaterial {
}
}

fn spawn(
fn local_laser_trail(
config: Res<GameConfig>,
mut in_events: EventReader<LocalLaserTrailEvent>,
mut out_events: EventWriter<LaserTrailEvent>,
mut net_events: EventWriter<ToPlayersEvent>,
) {
for event in in_events.iter() {
out_events.send(LaserTrailEvent(event.0));

if config.multiplayer() {
net_events.send(ToPlayersEvent::new(ToPlayers::Projectile(
NetProjectile::Laser {
origin: event.0.origin.into(),
direction: event.0.dir.into(),
},
)));
}
}
}

fn remote_laser_trail(
mut in_events: EventReader<NetRecvProjectileEvent>,
mut out_events: EventWriter<LaserTrailEvent>,
) {
for event in in_events.iter() {
match **event {
NetProjectile::Laser { origin, direction } => {
out_events.send(LaserTrailEvent(Ray::new(origin.into(), direction.into())));
}
}
}
}

fn laser_trail(
mut commands: Commands,
mut materials: ResMut<Assets<TrailMaterial>>,
time: Res<Time>,
mesh: Res<MeshHandle>,
mut events: EventReader<TrailEvent>,
mut events: EventReader<LaserTrailEvent>,
) {
for event in events.iter() {
let material = materials.add(TrailMaterial::new(time.elapsed_seconds_wrapped()));
Expand All @@ -119,9 +164,9 @@ fn spawn(
mesh: mesh.0.clone(),
material,
transform: Transform {
translation: event.ray().origin.into(),
rotation: Quat::from_rotation_arc(Vec3::X, event.ray().dir.normalize().into()),
scale: Vec3::new(event.ray().dir.norm(), 1., 1.),
translation: event.0.origin.into(),
rotation: Quat::from_rotation_arc(Vec3::X, event.0.dir.normalize().into()),
scale: Vec3::new(event.0.dir.norm(), 1., 1.),
},
..Default::default()
},
Expand Down
2 changes: 1 addition & 1 deletion crates/messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
pub use game::{FromGame, JoinError, Readiness, ToGame};
pub use players::{
BorrowedFromPlayers, ChatMessage, ChatMessageError, EntityNet, FromPlayers, HealthDelta,
NetEntityIndex, ToPlayers, MAX_CHAT_LEN,
NetEntityIndex, NetProjectile, ToPlayers, MAX_CHAT_LEN,
};
pub use server::{FromServer, GameOpenError, ToServer};

Expand Down
4 changes: 4 additions & 0 deletions crates/messages/src/players/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use de_types::{objects::ActiveObjectType, player::Player};
pub use entity::{EntityNet, NetEntityIndex};
pub use geom::{TransformNet, Vec2Net, Vec3Net, Vec4Net};
pub use path::{PathError, PathNet};
pub use projectile::NetProjectile;

mod chat;
mod entity;
mod geom;
mod path;
mod projectile;

/// Messages to be sent by a player/client or occasionally the game server to
/// other players.
Expand Down Expand Up @@ -85,6 +87,8 @@ pub enum ToPlayers {
entity: EntityNet,
delta: HealthDelta,
},
/// Some kind of projectile was spawned (e.g. rocket, laser trail).
Projectile(NetProjectile),
}

#[derive(Debug, Encode, Decode)]
Expand Down
12 changes: 12 additions & 0 deletions crates/messages/src/players/projectile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use bincode::{Decode, Encode};

use crate::players::Vec3Net;

#[derive(Clone, Copy, Debug, Encode, Decode)]
pub enum NetProjectile {
Laser {
origin: Vec3Net,
/// End of the trail lies at `origin + direction`.
direction: Vec3Net,
},
}
3 changes: 2 additions & 1 deletion crates/multiplayer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ pub use crate::{
netstate::NetState,
playermsg::{
GameNetSet, NetEntities, NetEntityCommands, NetRecvDespawnActiveEvent, NetRecvHealthEvent,
NetRecvSetPathEvent, NetRecvSpawnActiveEvent, NetRecvTransformEvent,
NetRecvProjectileEvent, NetRecvSetPathEvent, NetRecvSpawnActiveEvent,
NetRecvTransformEvent,
},
};
use crate::{netstate::NetStatePlugin, network::NetworkPlugin};
Expand Down
1 change: 1 addition & 0 deletions crates/multiplayer/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ impl ToMessage for ToPlayersEvent {
ToPlayers::SetPath { .. } => Reliability::SemiOrdered,
ToPlayers::Transform { .. } => Reliability::Unreliable,
ToPlayers::ChangeHealth { .. } => Reliability::SemiOrdered,
ToPlayers::Projectile(_) => Reliability::Unreliable,
}
}

Expand Down
10 changes: 9 additions & 1 deletion crates/multiplayer/src/playermsg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bevy::{
prelude::*,
};
use de_core::{gconfig::GameConfig, schedule::PreMovement, state::AppState};
use de_messages::{EntityNet, NetEntityIndex, ToPlayers};
use de_messages::{EntityNet, NetEntityIndex, NetProjectile, ToPlayers};
use de_types::{objects::ActiveObjectType, path::Path, player::Player};

use crate::messages::{FromPlayersEvent, MessagesSet};
Expand All @@ -19,6 +19,7 @@ impl Plugin for PlayerMsgPlugin {
.add_event::<NetRecvHealthEvent>()
.add_event::<NetRecvTransformEvent>()
.add_event::<NetRecvSetPathEvent>()
.add_event::<NetRecvProjectileEvent>()
.add_systems(OnEnter(AppState::InGame), setup)
.add_systems(OnExit(AppState::InGame), cleanup)
.add_systems(
Expand Down Expand Up @@ -166,6 +167,9 @@ impl NetRecvSetPathEvent {
}
}

#[derive(Event, Deref)]
pub struct NetRecvProjectileEvent(NetProjectile);

#[derive(SystemParam)]
pub struct NetEntities<'w> {
config: Res<'w, GameConfig>,
Expand Down Expand Up @@ -356,6 +360,7 @@ fn recv_messages(
mut path_events: EventWriter<NetRecvSetPathEvent>,
mut transform_events: EventWriter<NetRecvTransformEvent>,
mut health_events: EventWriter<NetRecvHealthEvent>,
mut projectile_events: EventWriter<NetRecvProjectileEvent>,
) {
for input in inputs.iter() {
match input.message() {
Expand Down Expand Up @@ -404,6 +409,9 @@ fn recv_messages(

health_events.send(NetRecvHealthEvent::new(local, delta.into()));
}
ToPlayers::Projectile(projectile) => {
projectile_events.send(NetRecvProjectileEvent(*projectile));
}
_ => (),
}
}
Expand Down