mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added /explosion command
This commit is contained in:
parent
192f5d355f
commit
5b62531da3
@ -4,6 +4,7 @@ use vek::*;
|
||||
|
||||
pub enum Event {
|
||||
LandOnGround { entity: EcsEntity, vel: Vec3<f32> },
|
||||
Explosion { pos: Vec3<f32>, radius: f32 },
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -19,6 +20,10 @@ impl EventBus {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit(&self, event: Event) {
|
||||
self.queue.lock().unwrap().push_front(event);
|
||||
}
|
||||
|
||||
pub fn recv_all(&self) -> impl ExactSizeIterator<Item = Event> {
|
||||
std::mem::replace(self.queue.lock().unwrap().deref_mut(), VecDeque::new()).into_iter()
|
||||
}
|
||||
|
@ -2,32 +2,47 @@ use crate::vol::{ReadVol, Vox};
|
||||
use vek::*;
|
||||
|
||||
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
||||
pub trait RayForEach = FnMut(Vec3<i32>);
|
||||
|
||||
pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>> {
|
||||
pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach> {
|
||||
vol: &'a V,
|
||||
from: Vec3<f32>,
|
||||
to: Vec3<f32>,
|
||||
until: F,
|
||||
for_each: Option<G>,
|
||||
max_iter: usize,
|
||||
ignore_error: bool,
|
||||
}
|
||||
|
||||
impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
||||
impl<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach> Ray<'a, V, F, G> {
|
||||
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
|
||||
Self {
|
||||
vol,
|
||||
from,
|
||||
to,
|
||||
until,
|
||||
for_each: None,
|
||||
max_iter: 100,
|
||||
ignore_error: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn until(self, f: F) -> Ray<'a, V, F> {
|
||||
pub fn until(self, f: F) -> Ray<'a, V, F, G> {
|
||||
Ray { until: f, ..self }
|
||||
}
|
||||
|
||||
pub fn for_each<H: RayForEach>(self, f: H) -> Ray<'a, V, F, H> {
|
||||
Ray {
|
||||
for_each: Some(f),
|
||||
vol: self.vol,
|
||||
from: self.from,
|
||||
to: self.to,
|
||||
until: self.until,
|
||||
max_iter: self.max_iter,
|
||||
ignore_error: self.ignore_error,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
||||
self.max_iter = max_iter;
|
||||
self
|
||||
@ -56,6 +71,11 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
||||
break;
|
||||
}
|
||||
|
||||
// for_each
|
||||
if let Some(g) = &mut self.for_each {
|
||||
g(ipos);
|
||||
}
|
||||
|
||||
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
||||
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
||||
Err(err) if !self.ignore_error => return (dist, Err(err)),
|
||||
|
@ -315,16 +315,15 @@ impl State {
|
||||
.for_each(|(pos, block)| {
|
||||
let _ = terrain.set(*pos, *block);
|
||||
});
|
||||
std::mem::swap(
|
||||
self.ecs.write_resource::<TerrainChanges>().modified_blocks = std::mem::replace(
|
||||
&mut self.ecs.write_resource::<BlockChange>().blocks,
|
||||
&mut self.ecs.write_resource::<TerrainChanges>().modified_blocks,
|
||||
)
|
||||
Default::default(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Clean up the state after a tick.
|
||||
pub fn cleanup(&mut self) {
|
||||
// Clean up data structures from the last tick.
|
||||
self.ecs.write_resource::<TerrainChanges>().clear();
|
||||
self.ecs.write_resource::<BlockChange>().clear();
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,11 @@ pub trait ReadVol: BaseVol {
|
||||
self.get(pos).unwrap()
|
||||
}
|
||||
|
||||
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
|
||||
fn ray(
|
||||
&self,
|
||||
from: Vec3<f32>,
|
||||
to: Vec3<f32>,
|
||||
) -> Ray<Self, fn(&Self::Vox) -> bool, fn(Vec3<i32>)>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ use crate::Server;
|
||||
use chrono::{NaiveTime, Timelike};
|
||||
use common::{
|
||||
comp,
|
||||
event::{Event as GameEvent, EventBus},
|
||||
msg::ServerMsg,
|
||||
npc::{get_npc_name, NpcKind},
|
||||
state::TimeOfDay,
|
||||
@ -147,10 +148,16 @@ lazy_static! {
|
||||
),
|
||||
ChatCommand::new(
|
||||
"lantern",
|
||||
"{} ",
|
||||
"{}",
|
||||
"/lantern : adds/remove light near player",
|
||||
handle_lantern,
|
||||
),
|
||||
ChatCommand::new(
|
||||
"explosion",
|
||||
"{}",
|
||||
"/explosion <radius> : Explodes the ground around you",
|
||||
handle_explosion,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -669,6 +676,22 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_explosion(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
if let Ok(radius) = scan_fmt!(&args, action.arg_fmt, f32) {
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(pos) => server
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<EventBus>()
|
||||
.emit(GameEvent::Explosion { pos: pos.0, radius }),
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(String::from("You have no position!")),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
||||
let ecs = server.state.ecs();
|
||||
|
@ -18,7 +18,7 @@ use common::{
|
||||
event::{Event as GameEvent, EventBus},
|
||||
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
|
||||
net::PostOffice,
|
||||
state::{State, TimeOfDay, Uid},
|
||||
state::{BlockChange, State, TimeOfDay, Uid},
|
||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap},
|
||||
vol::Vox,
|
||||
vol::{ReadVol, VolSize},
|
||||
@ -203,6 +203,8 @@ impl Server {
|
||||
|
||||
/// Handle events coming through via the event bus
|
||||
fn handle_events(&mut self) {
|
||||
let terrain = self.state.ecs().read_resource::<TerrainMap>();
|
||||
let mut block_change = self.state.ecs().write_resource::<BlockChange>();
|
||||
let mut stats = self.state.ecs().write_storage::<comp::Stats>();
|
||||
|
||||
for event in self.state.ecs().read_resource::<EventBus>().recv_all() {
|
||||
@ -215,6 +217,24 @@ impl Server {
|
||||
}
|
||||
}
|
||||
}
|
||||
GameEvent::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();
|
||||
|
||||
let _ = terrain
|
||||
.ray(pos, pos + dir * radius)
|
||||
.until(|_| rand::random::<f32>() < 0.05)
|
||||
.for_each(|pos| block_change.set(pos, Block::empty()))
|
||||
.cast();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,6 +269,9 @@ impl Server {
|
||||
frontend_events.append(&mut self.handle_new_connections()?);
|
||||
frontend_events.append(&mut self.handle_new_messages()?);
|
||||
|
||||
// Handle game events
|
||||
self.handle_events();
|
||||
|
||||
// 4) Tick the client's LocalState.
|
||||
self.state.tick(dt);
|
||||
|
||||
@ -371,9 +394,6 @@ impl Server {
|
||||
self.state.remove_chunk(key);
|
||||
}
|
||||
|
||||
// Handle events
|
||||
self.handle_events();
|
||||
|
||||
// 6) Synchronise clients with the new state of the world.
|
||||
self.sync_clients();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user