mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added outcome system, sound effects
This commit is contained in:
parent
3f7667352d
commit
7c31baef6f
@ -132,4 +132,4 @@ void main() {
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ use common::{
|
||||
sync::{Uid, UidAllocator, WorldSyncExt},
|
||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize},
|
||||
vol::RectVolSize,
|
||||
outcome::Outcome,
|
||||
};
|
||||
use futures_executor::block_on;
|
||||
use futures_timer::Delay;
|
||||
@ -66,6 +67,7 @@ pub enum Event {
|
||||
InventoryUpdated(InventoryUpdateEvent),
|
||||
Notification(Notification),
|
||||
SetViewDistance(u32),
|
||||
Outcome(Outcome),
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
@ -1229,6 +1231,9 @@ impl Client {
|
||||
self.view_distance = Some(vd);
|
||||
frontend_events.push(Event::SetViewDistance(vd));
|
||||
},
|
||||
ServerMsg::Outcomes(outcomes) => frontend_events.extend(outcomes
|
||||
.into_iter()
|
||||
.map(Event::Outcome)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ pub mod generation;
|
||||
pub mod loadout_builder;
|
||||
pub mod msg;
|
||||
pub mod npc;
|
||||
pub mod outcome;
|
||||
pub mod path;
|
||||
pub mod ray;
|
||||
pub mod recipe;
|
||||
|
@ -2,6 +2,7 @@ use super::{ClientState, EcsCompPacket};
|
||||
use crate::{
|
||||
character::CharacterItem,
|
||||
comp,
|
||||
outcome::Outcome,
|
||||
recipe::RecipeBook,
|
||||
state, sync,
|
||||
sync::Uid,
|
||||
@ -120,6 +121,7 @@ pub enum ServerMsg {
|
||||
/// Send a popup notification such as "Waypoint Saved"
|
||||
Notification(Notification),
|
||||
SetViewDistance(u32),
|
||||
Outcomes(Vec<Outcome>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
30
common/src/outcome.rs
Normal file
30
common/src/outcome.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ use common::{
|
||||
Projectile, Scale, Stats, Vel, WaypointArea,
|
||||
},
|
||||
util::Dir,
|
||||
outcome::Outcome,
|
||||
};
|
||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
use vek::{Rgb, Vec3};
|
||||
@ -89,10 +90,15 @@ pub fn handle_shoot(
|
||||
.expect("Failed to fetch entity")
|
||||
.0;
|
||||
|
||||
let vel = *dir * 100.0;
|
||||
|
||||
// Add an outcome
|
||||
state.ecs().write_resource::<Vec<Outcome>>().push(Outcome::ProjectileShot { pos, body, vel });
|
||||
|
||||
// TODO: Player height
|
||||
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 {
|
||||
builder = builder.with(light)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use common::{
|
||||
HealthChange, HealthSource, Player, Pos, Stats,
|
||||
},
|
||||
msg::{PlayerListUpdate, ServerMsg},
|
||||
outcome::Outcome,
|
||||
state::BlockChange,
|
||||
sync::{Uid, UidAllocator, WorldSyncExt},
|
||||
sys::combat::BLOCK_ANGLE,
|
||||
@ -277,25 +278,16 @@ pub fn handle_respawn(server: &Server, entity: EcsEntity) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_explosion(
|
||||
server: &Server,
|
||||
pos: Vec3<f32>,
|
||||
power: f32,
|
||||
owner: Option<Uid>,
|
||||
friendly_damage: bool,
|
||||
) {
|
||||
// Go through all other entities
|
||||
let hit_range = 3.0 * power;
|
||||
pub fn handle_explosion(server: &Server, pos: Vec3<f32>, power: f32, owner: Option<Uid>) {
|
||||
let ecs = &server.state.ecs();
|
||||
|
||||
let owner_entity = owner.and_then(|uid| {
|
||||
ecs.read_resource::<UidAllocator>()
|
||||
.retrieve_entity_internal(uid.into())
|
||||
});
|
||||
let groups = ecs.read_storage::<comp::Group>();
|
||||
// Add an outcome
|
||||
ecs.write_resource::<Vec<Outcome>>()
|
||||
.push(Outcome::Explosion { pos, power });
|
||||
|
||||
for (entity_b, pos_b, ori_b, character_b, stats_b, loadout_b) in (
|
||||
&ecs.entities(),
|
||||
// Go through all other 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::Ori>(),
|
||||
ecs.read_storage::<comp::CharacterState>().maybe(),
|
||||
|
@ -34,6 +34,7 @@ use common::{
|
||||
comp::{self, ChatType},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{ClientState, ServerInfo, ServerMsg},
|
||||
outcome::Outcome,
|
||||
recipe::default_recipe_book,
|
||||
state::{State, TimeOfDay},
|
||||
sync::WorldSyncExt,
|
||||
@ -118,6 +119,7 @@ impl Server {
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(comp::AdminList(settings.admins.clone()));
|
||||
state.ecs_mut().insert(Vec::<Outcome>::new());
|
||||
|
||||
// System timers for performance monitoring
|
||||
state.ecs_mut().insert(sys::EntitySyncTimer::default());
|
||||
|
@ -7,15 +7,19 @@ use crate::{
|
||||
Tick,
|
||||
};
|
||||
use common::{
|
||||
comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Pos, Vel},
|
||||
comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Pos, Vel, Player},
|
||||
msg::ServerMsg,
|
||||
outcome::Outcome,
|
||||
region::{Event as RegionEvent, RegionMap},
|
||||
state::TimeOfDay,
|
||||
sync::{CompSyncPackage, Uid},
|
||||
vol::RectVolSize,
|
||||
terrain::TerrainChunkSize,
|
||||
};
|
||||
use specs::{
|
||||
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// This system will send physics updates to the client
|
||||
pub struct Sys;
|
||||
@ -33,6 +37,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Ori>,
|
||||
ReadStorage<'a, Inventory>,
|
||||
ReadStorage<'a, RegionSubscription>,
|
||||
ReadStorage<'a, Player>,
|
||||
WriteStorage<'a, Last<Pos>>,
|
||||
WriteStorage<'a, Last<Vel>>,
|
||||
WriteStorage<'a, Last<Ori>>,
|
||||
@ -40,6 +45,7 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
WriteStorage<'a, InventoryUpdate>,
|
||||
Write<'a, DeletedEntities>,
|
||||
Write<'a, Vec<Outcome>>,
|
||||
TrackedComps<'a>,
|
||||
ReadTrackers<'a>,
|
||||
);
|
||||
@ -58,6 +64,7 @@ impl<'a> System<'a> for Sys {
|
||||
orientations,
|
||||
inventories,
|
||||
subscriptions,
|
||||
players,
|
||||
mut last_pos,
|
||||
mut last_vel,
|
||||
mut last_ori,
|
||||
@ -65,6 +72,7 @@ impl<'a> System<'a> for Sys {
|
||||
mut force_updates,
|
||||
mut inventory_updates,
|
||||
mut deleted_entities,
|
||||
mut outcomes,
|
||||
tracked_comps,
|
||||
trackers,
|
||||
): 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.
|
||||
force_updates.clear();
|
||||
inventory_updates.clear();
|
||||
|
@ -93,6 +93,7 @@ use common::{
|
||||
},
|
||||
event::EventBus,
|
||||
state::State,
|
||||
outcome::Outcome,
|
||||
};
|
||||
use event_mapper::SfxEventMapper;
|
||||
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)]
|
||||
pub struct SfxTriggerItem {
|
||||
pub files: Vec<String>,
|
||||
|
@ -26,7 +26,7 @@ use common::{
|
||||
vol::ReadVol,
|
||||
};
|
||||
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 vek::*;
|
||||
|
||||
@ -158,6 +158,15 @@ impl SessionState {
|
||||
global_state.settings.graphics.view_distance = vd;
|
||||
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);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user