Added outcome system, sound effects

This commit is contained in:
Joshua Barretto
2020-07-31 18:16:20 +01:00
committed by scott-c
parent 3f7667352d
commit 7c31baef6f
11 changed files with 104 additions and 20 deletions

View File

@ -30,6 +30,7 @@ use common::{
sync::{Uid, UidAllocator, WorldSyncExt}, sync::{Uid, UidAllocator, WorldSyncExt},
terrain::{block::Block, TerrainChunk, TerrainChunkSize}, terrain::{block::Block, TerrainChunk, TerrainChunkSize},
vol::RectVolSize, vol::RectVolSize,
outcome::Outcome,
}; };
use futures_executor::block_on; use futures_executor::block_on;
use futures_timer::Delay; use futures_timer::Delay;
@ -66,6 +67,7 @@ pub enum Event {
InventoryUpdated(InventoryUpdateEvent), InventoryUpdated(InventoryUpdateEvent),
Notification(Notification), Notification(Notification),
SetViewDistance(u32), SetViewDistance(u32),
Outcome(Outcome),
} }
pub struct Client { pub struct Client {
@ -1229,6 +1231,9 @@ impl Client {
self.view_distance = Some(vd); self.view_distance = Some(vd);
frontend_events.push(Event::SetViewDistance(vd)); frontend_events.push(Event::SetViewDistance(vd));
}, },
ServerMsg::Outcomes(outcomes) => frontend_events.extend(outcomes
.into_iter()
.map(Event::Outcome)),
} }
} }
} }

View File

@ -24,6 +24,7 @@ pub mod generation;
pub mod loadout_builder; pub mod loadout_builder;
pub mod msg; pub mod msg;
pub mod npc; pub mod npc;
pub mod outcome;
pub mod path; pub mod path;
pub mod ray; pub mod ray;
pub mod recipe; pub mod recipe;

View File

@ -2,6 +2,7 @@ use super::{ClientState, EcsCompPacket};
use crate::{ use crate::{
character::CharacterItem, character::CharacterItem,
comp, comp,
outcome::Outcome,
recipe::RecipeBook, recipe::RecipeBook,
state, sync, state, sync,
sync::Uid, sync::Uid,
@ -120,6 +121,7 @@ pub enum ServerMsg {
/// Send a popup notification such as "Waypoint Saved" /// Send a popup notification such as "Waypoint Saved"
Notification(Notification), Notification(Notification),
SetViewDistance(u32), SetViewDistance(u32),
Outcomes(Vec<Outcome>),
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]

30
common/src/outcome.rs Normal file
View File

@ -0,0 +1,30 @@
use crate::comp;
use serde::{Deserialize, Serialize};
use vek::*;
/// An outcome represents the final result of an instantaneous event. It implies that said event has
/// already occurred. It is not a request for that event to occur, nor is it something that may be
/// cancelled or otherwise altered. Its primary purpose is to act as something for frontends (both
/// server and client) to listen to in order to receive feedback about events in the world.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Outcome {
Explosion {
pos: Vec3<f32>,
power: f32,
},
ProjectileShot {
pos: Vec3<f32>,
body: comp::Body,
vel: Vec3<f32>,
},
}
impl Outcome {
pub fn get_pos(&self) -> Option<Vec3<f32>> {
match self {
Outcome::Explosion { pos, .. } => Some(*pos),
Outcome::ProjectileShot { pos, .. } => Some(*pos),
}
}
}

View File

@ -5,6 +5,7 @@ use common::{
Projectile, Scale, Stats, Vel, WaypointArea, Projectile, Scale, Stats, Vel, WaypointArea,
}, },
util::Dir, util::Dir,
outcome::Outcome,
}; };
use specs::{Builder, Entity as EcsEntity, WorldExt}; use specs::{Builder, Entity as EcsEntity, WorldExt};
use vek::{Rgb, Vec3}; use vek::{Rgb, Vec3};
@ -89,10 +90,15 @@ pub fn handle_shoot(
.expect("Failed to fetch entity") .expect("Failed to fetch entity")
.0; .0;
let vel = *dir * 100.0;
// Add an outcome
state.ecs().write_resource::<Vec<Outcome>>().push(Outcome::ProjectileShot { pos, body, vel });
// TODO: Player height // TODO: Player height
pos.z += 1.2; pos.z += 1.2;
let mut builder = state.create_projectile(Pos(pos), Vel(*dir * 100.0), body, projectile); let mut builder = state.create_projectile(Pos(pos), Vel(vel), body, projectile);
if let Some(light) = light { if let Some(light) = light {
builder = builder.with(light) builder = builder.with(light)
} }

View File

@ -6,6 +6,7 @@ use common::{
HealthChange, HealthSource, Player, Pos, Stats, HealthChange, HealthSource, Player, Pos, Stats,
}, },
msg::{PlayerListUpdate, ServerMsg}, msg::{PlayerListUpdate, ServerMsg},
outcome::Outcome,
state::BlockChange, state::BlockChange,
sync::{Uid, UidAllocator, WorldSyncExt}, sync::{Uid, UidAllocator, WorldSyncExt},
sys::combat::BLOCK_ANGLE, sys::combat::BLOCK_ANGLE,
@ -277,25 +278,16 @@ pub fn handle_respawn(server: &Server, entity: EcsEntity) {
} }
} }
pub fn handle_explosion( pub fn handle_explosion(server: &Server, pos: Vec3<f32>, power: f32, owner: Option<Uid>) {
server: &Server,
pos: Vec3<f32>,
power: f32,
owner: Option<Uid>,
friendly_damage: bool,
) {
// Go through all other entities
let hit_range = 3.0 * power;
let ecs = &server.state.ecs(); let ecs = &server.state.ecs();
let owner_entity = owner.and_then(|uid| { // Add an outcome
ecs.read_resource::<UidAllocator>() ecs.write_resource::<Vec<Outcome>>()
.retrieve_entity_internal(uid.into()) .push(Outcome::Explosion { pos, power });
});
let groups = ecs.read_storage::<comp::Group>();
for (entity_b, pos_b, ori_b, character_b, stats_b, loadout_b) in ( // Go through all other entities
&ecs.entities(), let hit_range = 3.0 * power;
for (pos_b, ori_b, character_b, stats_b, loadout_b) in (
&ecs.read_storage::<comp::Pos>(), &ecs.read_storage::<comp::Pos>(),
&ecs.read_storage::<comp::Ori>(), &ecs.read_storage::<comp::Ori>(),
ecs.read_storage::<comp::CharacterState>().maybe(), ecs.read_storage::<comp::CharacterState>().maybe(),

View File

@ -34,6 +34,7 @@ use common::{
comp::{self, ChatType}, comp::{self, ChatType},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
msg::{ClientState, ServerInfo, ServerMsg}, msg::{ClientState, ServerInfo, ServerMsg},
outcome::Outcome,
recipe::default_recipe_book, recipe::default_recipe_book,
state::{State, TimeOfDay}, state::{State, TimeOfDay},
sync::WorldSyncExt, sync::WorldSyncExt,
@ -118,6 +119,7 @@ impl Server {
state state
.ecs_mut() .ecs_mut()
.insert(comp::AdminList(settings.admins.clone())); .insert(comp::AdminList(settings.admins.clone()));
state.ecs_mut().insert(Vec::<Outcome>::new());
// System timers for performance monitoring // System timers for performance monitoring
state.ecs_mut().insert(sys::EntitySyncTimer::default()); state.ecs_mut().insert(sys::EntitySyncTimer::default());

View File

@ -7,15 +7,19 @@ use crate::{
Tick, Tick,
}; };
use common::{ use common::{
comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Pos, Vel}, comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Pos, Vel, Player},
msg::ServerMsg, msg::ServerMsg,
outcome::Outcome,
region::{Event as RegionEvent, RegionMap}, region::{Event as RegionEvent, RegionMap},
state::TimeOfDay, state::TimeOfDay,
sync::{CompSyncPackage, Uid}, sync::{CompSyncPackage, Uid},
vol::RectVolSize,
terrain::TerrainChunkSize,
}; };
use specs::{ use specs::{
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage, Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
}; };
use vek::*;
/// This system will send physics updates to the client /// This system will send physics updates to the client
pub struct Sys; pub struct Sys;
@ -33,6 +37,7 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Ori>, ReadStorage<'a, Ori>,
ReadStorage<'a, Inventory>, ReadStorage<'a, Inventory>,
ReadStorage<'a, RegionSubscription>, ReadStorage<'a, RegionSubscription>,
ReadStorage<'a, Player>,
WriteStorage<'a, Last<Pos>>, WriteStorage<'a, Last<Pos>>,
WriteStorage<'a, Last<Vel>>, WriteStorage<'a, Last<Vel>>,
WriteStorage<'a, Last<Ori>>, WriteStorage<'a, Last<Ori>>,
@ -40,6 +45,7 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, ForceUpdate>, WriteStorage<'a, ForceUpdate>,
WriteStorage<'a, InventoryUpdate>, WriteStorage<'a, InventoryUpdate>,
Write<'a, DeletedEntities>, Write<'a, DeletedEntities>,
Write<'a, Vec<Outcome>>,
TrackedComps<'a>, TrackedComps<'a>,
ReadTrackers<'a>, ReadTrackers<'a>,
); );
@ -58,6 +64,7 @@ impl<'a> System<'a> for Sys {
orientations, orientations,
inventories, inventories,
subscriptions, subscriptions,
players,
mut last_pos, mut last_pos,
mut last_vel, mut last_vel,
mut last_ori, mut last_ori,
@ -65,6 +72,7 @@ impl<'a> System<'a> for Sys {
mut force_updates, mut force_updates,
mut inventory_updates, mut inventory_updates,
mut deleted_entities, mut deleted_entities,
mut outcomes,
tracked_comps, tracked_comps,
trackers, trackers,
): Self::SystemData, ): Self::SystemData,
@ -316,6 +324,22 @@ impl<'a> System<'a> for Sys {
)); ));
} }
// Sync outcomes
for (client, player, pos) in (&mut clients, &players, positions.maybe()).join() {
let is_near = |o_pos: Vec3<f32>| pos
.zip_with(player.view_distance, |pos, vd| pos.0.xy().distance_squared(o_pos.xy()) < (vd as f32 * TerrainChunkSize::RECT_SIZE.x as f32).powf(2.0));
let outcomes = outcomes
.iter()
.filter(|o| o.get_pos().and_then(&is_near).unwrap_or(true))
.cloned()
.collect::<Vec<_>>();
if outcomes.len() > 0 {
client.notify(ServerMsg::Outcomes(outcomes));
}
}
outcomes.clear();
// Remove all force flags. // Remove all force flags.
force_updates.clear(); force_updates.clear();
inventory_updates.clear(); inventory_updates.clear();

View File

@ -93,6 +93,7 @@ use common::{
}, },
event::EventBus, event::EventBus,
state::State, state::State,
outcome::Outcome,
}; };
use event_mapper::SfxEventMapper; use event_mapper::SfxEventMapper;
use hashbrown::HashMap; use hashbrown::HashMap;
@ -188,6 +189,18 @@ impl From<&InventoryUpdateEvent> for SfxEvent {
} }
} }
impl TryFrom<Outcome> for SfxEventItem {
type Error = ();
fn try_from(outcome: Outcome) -> Result<Self, Self::Error> {
match outcome {
Outcome::Explosion { pos, power } => Ok(Self::new(SfxEvent::GliderOpen, Some(pos), Some((power / 10.0).min(1.0)))),
Outcome::ProjectileShot { pos, .. } => Ok(Self::new(SfxEvent::GliderOpen, Some(pos), None)),
_ => Err(()),
}
}
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct SfxTriggerItem { pub struct SfxTriggerItem {
pub files: Vec<String>, pub files: Vec<String>,

View File

@ -26,7 +26,7 @@ use common::{
vol::ReadVol, vol::ReadVol,
}; };
use specs::{Join, WorldExt}; use specs::{Join, WorldExt};
use std::{cell::RefCell, rc::Rc, time::Duration}; use std::{cell::RefCell, rc::Rc, time::Duration, convert::TryFrom};
use tracing::{error, info}; use tracing::{error, info};
use vek::*; use vek::*;
@ -158,6 +158,15 @@ impl SessionState {
global_state.settings.graphics.view_distance = vd; global_state.settings.graphics.view_distance = vd;
global_state.settings.save_to_file_warn(); global_state.settings.save_to_file_warn();
}, },
client::Event::Outcome(outcome) => {
if let Ok(sfx_event_item) = SfxEventItem::try_from(outcome) {
client
.state()
.ecs()
.read_resource::<EventBus<SfxEventItem>>()
.emit_now(sfx_event_item);
}
},
} }
} }