diff --git a/common/src/event.rs b/common/src/event.rs index a5ed0840fb..b655b645bd 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -22,6 +22,7 @@ pub enum ServerEvent { cause: comp::HealthSource, }, Respawn(EcsEntity), + Shoot(EcsEntity), } pub struct EventBus<E> { diff --git a/server/src/lib.rs b/server/src/lib.rs index 0eba3c5ff5..5cb1b69d43 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -87,7 +87,9 @@ impl Server { state .ecs_mut() .add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 512.0))); - state.ecs_mut().add_resource(EventBus::<ServerEvent>::default()); + state + .ecs_mut() + .add_resource(EventBus::<ServerEvent>::default()); // Set starting time for the server. state.ecs_mut().write_resource::<TimeOfDay>().0 = settings.start_time; @@ -176,6 +178,22 @@ impl Server { //.with(comp::LightEmitter::default()) } + /// Build a projectile + pub fn create_projectile( + state: &mut State, + pos: comp::Pos, + vel: comp::Vel, + body: comp::Body, + ) -> EcsEntityBuilder { + state + .ecs_mut() + .create_entity_synced() + .with(pos) + .with(vel) + .with(comp::Ori(Vec3::unit_y())) + .with(body) + } + pub fn create_player_character( state: &mut State, entity: EcsEntity, @@ -215,70 +233,95 @@ impl Server { /// Handle events coming through via the event bus fn handle_events(&mut self) { - let clients = &mut self.clients; - - let events = self.state.ecs().read_resource::<EventBus<ServerEvent>>().recv_all(); + let events = self + .state + .ecs() + .read_resource::<EventBus<ServerEvent>>() + .recv_all(); for event in events { - let ecs = self.state.ecs_mut(); - let mut todo_remove = None; - { - let terrain = ecs.read_resource::<TerrainMap>(); - let mut block_change = ecs.write_resource::<BlockChange>(); - let mut stats = ecs.write_storage::<comp::Stats>(); - let mut positions = ecs.write_storage::<comp::Pos>(); - let mut velocities = ecs.write_storage::<comp::Vel>(); - let mut force_updates = ecs.write_storage::<comp::ForceUpdate>(); + let state = &mut self.state; + let clients = &mut self.clients; - match event { - ServerEvent::LandOnGround { entity, vel } => { - if let Some(stats) = stats.get_mut(entity) { - let falldmg = (vel.z / 1.5 + 10.0) as i32; - if falldmg < 0 { - stats.health.change_by(falldmg, comp::HealthSource::World); - } + match event { + ServerEvent::LandOnGround { entity, vel } => { + if let Some(stats) = state + .ecs_mut() + .write_storage::<comp::Stats>() + .get_mut(entity) + { + let falldmg = (vel.z / 1.5 + 10.0) as i32; + if falldmg < 0 { + stats.health.change_by(falldmg, comp::HealthSource::World); } } - ServerEvent::Explosion { pos, radius } => { - const RAYS: usize = 500; + } - for _ in 0..RAYS { - let dir = Vec3::new( - rand::random::<f32>() - 0.5, - rand::random::<f32>() - 0.5, - rand::random::<f32>() - 0.5, - ) - .normalized(); + ServerEvent::Explosion { pos, radius } => { + const RAYS: usize = 500; - let _ = terrain - .ray(pos, pos + dir * radius) - .until(|_| rand::random::<f32>() < 0.05) - .for_each(|pos| block_change.set(pos, Block::empty())) - .cast(); - } + for _ in 0..RAYS { + let dir = Vec3::new( + rand::random::<f32>() - 0.5, + rand::random::<f32>() - 0.5, + rand::random::<f32>() - 0.5, + ) + .normalized(); + + let ecs = state.ecs_mut(); + let mut block_change = ecs.write_resource::<BlockChange>(); + + let _ = ecs + .read_resource::<TerrainMap>() + .ray(pos, pos + dir * radius) + .until(|_| rand::random::<f32>() < 0.05) + .for_each(|pos| block_change.set(pos, Block::empty())) + .cast(); } - ServerEvent::Die { entity, cause } => { - // Chat message - if let Some(player) = ecs.read_storage::<comp::Player>().get(entity) { - let msg = if let comp::HealthSource::Attack { by } = cause { - ecs.entity_from_uid(by.into()).and_then(|attacker| { - ecs.read_storage::<comp::Player>().get(attacker).map( - |attacker_alias| { - format!( - "{} was killed by {}", - &player.alias, &attacker_alias.alias - ) - }, - ) - }) - } else { - None - } - .unwrap_or(format!("{} died", &player.alias)); + } - clients.notify_registered(ServerMsg::kill(msg)); + ServerEvent::Shoot(entity) => { + let pos = state + .ecs() + .read_storage::<comp::Pos>() + .get(entity) + .unwrap() + .0; + Self::create_projectile( + state, + comp::Pos(pos), + comp::Vel(Vec3::new(0.0, 100.0, 3.0)), + comp::Body::Object(comp::object::Body::Bomb), + ) + .build(); + } + + ServerEvent::Die { entity, cause } => { + let ecs = state.ecs_mut(); + // Chat message + if let Some(player) = ecs.read_storage::<comp::Player>().get(entity) { + let msg = if let comp::HealthSource::Attack { by } = cause { + ecs.entity_from_uid(by.into()).and_then(|attacker| { + ecs.read_storage::<comp::Player>().get(attacker).map( + |attacker_alias| { + format!( + "{} was killed by {}", + &player.alias, &attacker_alias.alias + ) + }, + ) + }) + } else { + None } + .unwrap_or(format!("{} died", &player.alias)); + clients.notify_registered(ServerMsg::kill(msg)); + } + + { // Give EXP to the client + let mut stats = ecs.write_storage::<comp::Stats>(); + if let Some(entity_stats) = stats.get(entity).cloned() { if let comp::HealthSource::Attack { by } = cause { ecs.entity_from_uid(by.into()).map(|attacker| { @@ -292,29 +335,37 @@ impl Server { }); } } - - if let Some(client) = clients.get_mut(&entity) { - let _ = velocities.insert(entity, comp::Vel(Vec3::zero())); - let _ = force_updates.insert(entity, comp::ForceUpdate); - client.force_state(ClientState::Dead); - } else { - todo_remove = Some(entity.clone()); - } } - ServerEvent::Respawn(entity) => { - // Only clients can respawn - if let Some(client) = clients.get_mut(&entity) { - client.allow_state(ClientState::Character); - stats.get_mut(entity).map(|stats| stats.revive()); - positions.get_mut(entity).map(|pos| pos.0.z += 20.0); - let _ = force_updates.insert(entity, comp::ForceUpdate); - } + + if let Some(client) = clients.get_mut(&entity) { + let _ = ecs.write_storage().insert(entity, comp::Vel(Vec3::zero())); + let _ = ecs.write_storage().insert(entity, comp::ForceUpdate); + client.force_state(ClientState::Dead); + } else { + let _ = state.ecs_mut().delete_entity_synced(entity); } } - } - if let Some(entity) = todo_remove { - let _ = ecs.delete_entity_synced(entity); + ServerEvent::Respawn(entity) => { + // Only clients can respawn + if let Some(client) = clients.get_mut(&entity) { + client.allow_state(ClientState::Character); + state + .ecs_mut() + .write_storage::<comp::Stats>() + .get_mut(entity) + .map(|stats| stats.revive()); + state + .ecs_mut() + .write_storage::<comp::Pos>() + .get_mut(entity) + .map(|pos| pos.0.z += 20.0); + let _ = state + .ecs_mut() + .write_storage() + .insert(entity, comp::ForceUpdate); + } + } } } }