mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'timo-dont-send-nothing-changed' into 'master'
Don't send empty physics updates and fix commands See merge request veloren/veloren!380
This commit is contained in:
commit
35bf253081
@ -398,24 +398,27 @@ impl Client {
|
||||
ServerMsg::EcsSync(sync_package) => {
|
||||
self.state.ecs_mut().sync_with_package(sync_package)
|
||||
}
|
||||
ServerMsg::EntityPhysics {
|
||||
ServerMsg::EntityPos { entity, pos } => {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(entity) {
|
||||
self.state.write_component(entity, pos);
|
||||
}
|
||||
}
|
||||
ServerMsg::EntityVel { entity, vel } => {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(entity) {
|
||||
self.state.write_component(entity, vel);
|
||||
}
|
||||
}
|
||||
ServerMsg::EntityOri { entity, ori } => {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(entity) {
|
||||
self.state.write_component(entity, ori);
|
||||
}
|
||||
}
|
||||
ServerMsg::EntityActionState {
|
||||
entity,
|
||||
pos,
|
||||
vel,
|
||||
ori,
|
||||
action_state,
|
||||
} => {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(entity) {
|
||||
self.state.write_component(entity, pos);
|
||||
if let Some(v) = vel {
|
||||
self.state.write_component(entity, v);
|
||||
};
|
||||
if let Some(o) = ori {
|
||||
self.state.write_component(entity, o);
|
||||
};
|
||||
if let Some(a_s) = action_state {
|
||||
self.state.write_component(entity, a_s);
|
||||
}
|
||||
self.state.write_component(entity, action_state);
|
||||
}
|
||||
}
|
||||
ServerMsg::TerrainChunkUpdate { key, chunk } => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ActionState {
|
||||
pub moving: bool,
|
||||
pub on_ground: bool,
|
||||
|
15
common/src/comp/last.rs
Normal file
15
common/src/comp/last.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use specs::{Component, VecStorage};
|
||||
use std::{fmt::Debug, marker::Send, ops::Deref};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub struct Last<C: Component + PartialEq>(pub C);
|
||||
|
||||
impl<C: Component + Send + Sync + PartialEq> Component for Last<C> {
|
||||
type Storage = VecStorage<Self>;
|
||||
}
|
||||
|
||||
impl<C: Component + PartialEq> PartialEq<C> for Last<C> {
|
||||
fn eq(&self, other: &C) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ mod body;
|
||||
mod controller;
|
||||
mod inputs;
|
||||
mod inventory;
|
||||
mod last;
|
||||
mod phys;
|
||||
mod player;
|
||||
mod stats;
|
||||
@ -20,6 +21,7 @@ pub use inputs::{
|
||||
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
||||
};
|
||||
pub use inventory::{item, Inventory};
|
||||
pub use last::Last;
|
||||
pub use phys::{ForceUpdate, Ori, Pos, Vel};
|
||||
pub use player::Player;
|
||||
pub use stats::{Dying, Exp, HealthSource, Level, Stats};
|
||||
|
@ -2,7 +2,7 @@ use specs::{Component, NullStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
// Position
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Pos(pub Vec3<f32>);
|
||||
|
||||
impl Component for Pos {
|
||||
@ -10,7 +10,7 @@ impl Component for Pos {
|
||||
}
|
||||
|
||||
// Velocity
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Vel(pub Vec3<f32>);
|
||||
|
||||
impl Component for Vel {
|
||||
@ -18,7 +18,7 @@ impl Component for Vel {
|
||||
}
|
||||
|
||||
// Orientation
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Ori(pub Vec3<f32>);
|
||||
|
||||
impl Component for Ori {
|
||||
@ -26,7 +26,7 @@ impl Component for Ori {
|
||||
}
|
||||
|
||||
// ForceUpdate
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ForceUpdate;
|
||||
|
||||
impl Component for ForceUpdate {
|
||||
|
@ -39,12 +39,21 @@ pub enum ServerMsg {
|
||||
},
|
||||
SetPlayerEntity(u64),
|
||||
EcsSync(sphynx::SyncPackage<EcsCompPacket, EcsResPacket>),
|
||||
EntityPhysics {
|
||||
EntityPos {
|
||||
entity: u64,
|
||||
pos: comp::Pos,
|
||||
vel: Option<comp::Vel>,
|
||||
ori: Option<comp::Ori>,
|
||||
action_state: Option<comp::ActionState>,
|
||||
},
|
||||
EntityVel {
|
||||
entity: u64,
|
||||
vel: comp::Vel,
|
||||
},
|
||||
EntityOri {
|
||||
entity: u64,
|
||||
ori: comp::Ori,
|
||||
},
|
||||
EntityActionState {
|
||||
entity: u64,
|
||||
action_state: comp::ActionState,
|
||||
},
|
||||
TerrainChunkUpdate {
|
||||
key: Vec2<i32>,
|
||||
|
@ -190,7 +190,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
}
|
||||
|
||||
// Try getting messages from the send channel.
|
||||
for _ in 0..100 {
|
||||
for _ in 0..1000 {
|
||||
match send_rx.try_recv() {
|
||||
Ok(send_msg) => {
|
||||
// Serialize message
|
||||
@ -225,7 +225,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
}
|
||||
|
||||
// Try sending bytes through the TCP stream.
|
||||
for _ in 0..100 {
|
||||
for _ in 0..1000 {
|
||||
match outgoing_chunks.pop_front() {
|
||||
Some(mut chunk) => match stream.write(&chunk) {
|
||||
Ok(n) if n == chunk.len() => {}
|
||||
@ -249,7 +249,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
}
|
||||
|
||||
// Try receiving bytes from the TCP stream.
|
||||
for _ in 0..100 {
|
||||
for _ in 0..1000 {
|
||||
let mut buf = [0; 4096];
|
||||
|
||||
match stream.read(&mut buf) {
|
||||
@ -265,7 +265,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
}
|
||||
|
||||
// Try turning bytes into messages.
|
||||
for _ in 0..100 {
|
||||
for _ in 0..1000 {
|
||||
match incoming_buf.get(0..9) {
|
||||
Some(len_bytes) => {
|
||||
let len =
|
||||
|
@ -125,36 +125,45 @@ impl State {
|
||||
|
||||
// Create a new Sphynx ECS world.
|
||||
fn setup_sphynx_world(ecs: &mut sphynx::World<EcsCompPacket, EcsResPacket>) {
|
||||
// Register server->client synced components.
|
||||
// Register server -> all clients synced components.
|
||||
ecs.register_synced::<comp::Body>();
|
||||
ecs.register_synced::<comp::Player>();
|
||||
ecs.register_synced::<comp::Stats>();
|
||||
ecs.register_synced::<comp::CanBuild>();
|
||||
ecs.register_synced::<comp::LightEmitter>();
|
||||
|
||||
// Register components synced by other means
|
||||
// Register components send from clients -> server
|
||||
ecs.register::<comp::Controller>();
|
||||
|
||||
// Register components send directly from server -> all but one client
|
||||
ecs.register::<comp::ActionState>();
|
||||
|
||||
// Register components synced from client -> server -> all other clients
|
||||
ecs.register::<comp::Pos>();
|
||||
ecs.register::<comp::Vel>();
|
||||
ecs.register::<comp::Ori>();
|
||||
ecs.register::<comp::MoveDir>();
|
||||
ecs.register::<comp::OnGround>();
|
||||
ecs.register::<comp::Controller>();
|
||||
ecs.register::<comp::Attacking>();
|
||||
ecs.register::<comp::Wielding>();
|
||||
ecs.register::<comp::Rolling>();
|
||||
ecs.register::<comp::Gliding>();
|
||||
ecs.register::<comp::ActionState>();
|
||||
|
||||
// Register client-local components
|
||||
ecs.register::<comp::AnimationInfo>();
|
||||
ecs.register::<comp::Jumping>();
|
||||
|
||||
// Register server-local components
|
||||
ecs.register::<comp::Last<comp::Pos>>();
|
||||
ecs.register::<comp::Last<comp::Vel>>();
|
||||
ecs.register::<comp::Last<comp::Ori>>();
|
||||
ecs.register::<comp::Last<comp::ActionState>>();
|
||||
ecs.register::<comp::Agent>();
|
||||
ecs.register::<comp::Respawning>();
|
||||
ecs.register::<comp::Dying>();
|
||||
ecs.register::<comp::ForceUpdate>();
|
||||
ecs.register::<comp::Inventory>();
|
||||
// Controller effects
|
||||
ecs.register::<comp::MoveDir>();
|
||||
ecs.register::<comp::OnGround>();
|
||||
ecs.register::<comp::Attacking>();
|
||||
ecs.register::<comp::Wielding>();
|
||||
ecs.register::<comp::Rolling>();
|
||||
ecs.register::<comp::Gliding>();
|
||||
|
||||
// Register synced resources used by the ECS.
|
||||
ecs.add_resource_synced(TimeOfDay(0.0));
|
||||
|
@ -46,7 +46,7 @@ impl<'a> System<'a> for Sys {
|
||||
Vec2::from(pos.0 - tgt_pos).normalized()
|
||||
} else {
|
||||
Vec2::zero()
|
||||
};
|
||||
} * -10.0;
|
||||
}
|
||||
_ => controller.move_dir = Vec2::zero(),
|
||||
}
|
||||
|
@ -155,10 +155,7 @@ lazy_static! {
|
||||
}
|
||||
|
||||
fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let (opt_x, opt_y, opt_z) = scan_fmt_some!(&args, action.arg_fmt, f32, f32, f32);
|
||||
|
||||
match (opt_x, opt_y, opt_z) {
|
||||
(Some(x), Some(y), Some(z)) => {
|
||||
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(current_pos) => {
|
||||
server
|
||||
@ -172,39 +169,29 @@ fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string))),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let (mut opt_x, mut opt_y, mut opt_z) = (None, None, None);
|
||||
|
||||
if let Ok((opt_x1, opt_y1, opt_z1)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
||||
opt_x = Some(opt_x1);
|
||||
opt_y = Some(opt_y1);
|
||||
opt_z = Some(opt_z1);
|
||||
}
|
||||
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(_pos) => match (opt_x, opt_y, opt_z) {
|
||||
(Some(x), Some(y), Some(z)) => {
|
||||
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
||||
if server
|
||||
.state
|
||||
.read_component_cloned::<comp::Pos>(entity)
|
||||
.is_some()
|
||||
{
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::Pos(Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::ForceUpdate);
|
||||
}
|
||||
_ => server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string))),
|
||||
},
|
||||
None => {
|
||||
} else {
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(String::from("You don't have any position!")),
|
||||
ServerMsg::private(String::from("You don't have a position!")),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,13 +205,13 @@ fn handle_kill(server: &mut Server, entity: EcsEntity, _args: String, _action: &
|
||||
}
|
||||
|
||||
fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let time = scan_fmt!(&args, action.arg_fmt, String);
|
||||
let time = scan_fmt_some!(&args, action.arg_fmt, String);
|
||||
let new_time = match time.as_ref().map(|s| s.as_str()) {
|
||||
Ok("night") => NaiveTime::from_hms(0, 0, 0),
|
||||
Ok("dawn") => NaiveTime::from_hms(5, 0, 0),
|
||||
Ok("day") => NaiveTime::from_hms(12, 0, 0),
|
||||
Ok("dusk") => NaiveTime::from_hms(17, 0, 0),
|
||||
Ok(n) => match n.parse() {
|
||||
Some("night") => NaiveTime::from_hms(0, 0, 0),
|
||||
Some("dawn") => NaiveTime::from_hms(5, 0, 0),
|
||||
Some("day") => NaiveTime::from_hms(12, 0, 0),
|
||||
Some("dusk") => NaiveTime::from_hms(17, 0, 0),
|
||||
Some(n) => match n.parse() {
|
||||
Ok(n) => n,
|
||||
Err(_) => match NaiveTime::parse_from_str(n, "%H:%M") {
|
||||
Ok(time) => time,
|
||||
@ -237,7 +224,7 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
}
|
||||
},
|
||||
},
|
||||
Err(_) => {
|
||||
None => {
|
||||
let time_in_seconds = server.state.ecs_mut().read_resource::<TimeOfDay>().0;
|
||||
let current_time = NaiveTime::from_num_seconds_from_midnight(time_in_seconds as u32, 0);
|
||||
server.clients.notify(
|
||||
@ -264,51 +251,45 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
}
|
||||
|
||||
fn handle_health(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let opt_hp = scan_fmt!(&args, action.arg_fmt, u32);
|
||||
|
||||
match server
|
||||
if let Ok(hp) = scan_fmt!(&args, action.arg_fmt, u32) {
|
||||
if let Some(stats) = server
|
||||
.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Stats>()
|
||||
.get_mut(entity)
|
||||
{
|
||||
Some(stats) => match opt_hp {
|
||||
Ok(hp) => stats.health.set_to(hp, comp::HealthSource::Command),
|
||||
Err(_) => {
|
||||
stats.health.set_to(hp, comp::HealthSource::Command);
|
||||
} else {
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(String::from("You have no position.")),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(String::from("You must specify health amount!")),
|
||||
);
|
||||
}
|
||||
},
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(String::from("You have no position.")),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
|
||||
match opt_alias {
|
||||
Ok(alias) => {
|
||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
||||
server
|
||||
.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Player>()
|
||||
.get_mut(entity)
|
||||
.map(|player| player.alias = alias);
|
||||
}
|
||||
Err(_) => server
|
||||
} else {
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string))),
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string)));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
|
||||
match opt_alias {
|
||||
Ok(alias) => {
|
||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
||||
let ecs = server.state.ecs();
|
||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||
.join()
|
||||
@ -323,10 +304,7 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
|
||||
}
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(format!(
|
||||
"Unable to teleport to player '{}'!",
|
||||
alias
|
||||
)),
|
||||
ServerMsg::private(format!("Unable to teleport to player '{}'!", alias)),
|
||||
),
|
||||
},
|
||||
None => {
|
||||
@ -345,19 +323,18 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
|
||||
.notify(entity, ServerMsg::private(format!("You have no position!")));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => server
|
||||
} else {
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string))),
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string)));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
match scan_fmt!(&args, action.arg_fmt, String, NpcKind, String) {
|
||||
Ok((opt_align, id, opt_amount)) => {
|
||||
match scan_fmt_some!(&args, action.arg_fmt, String, NpcKind, String) {
|
||||
(Some(opt_align), Some(id), opt_amount) => {
|
||||
if let Some(agent) = alignment_to_agent(&opt_align, entity) {
|
||||
let _objtype = scan_fmt!(&args, action.arg_fmt, String);
|
||||
let amount = Some(opt_amount)
|
||||
let amount = opt_amount
|
||||
.map_or(Some(1), |a| a.parse().ok())
|
||||
.and_then(|a| if a > 0 { Some(a) } else { None })
|
||||
.unwrap();
|
||||
@ -390,7 +367,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
_ => {
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string)));
|
||||
@ -638,7 +615,7 @@ fn handle_light(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
}
|
||||
|
||||
fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let opt_s = scan_fmt!(&args, action.arg_fmt, f32);
|
||||
let opt_s = scan_fmt_some!(&args, action.arg_fmt, f32);
|
||||
|
||||
if server
|
||||
.state
|
||||
@ -646,7 +623,7 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
|
||||
.get(entity)
|
||||
.is_some()
|
||||
{
|
||||
if let Ok(s) = opt_s {
|
||||
if let Some(s) = opt_s {
|
||||
if let Some(light) = server
|
||||
.state
|
||||
.ecs()
|
||||
@ -680,7 +657,7 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
|
||||
comp::LightEmitter {
|
||||
offset: Vec3::new(0.5, 0.2, 0.8),
|
||||
col: Rgb::new(1.0, 0.75, 0.3),
|
||||
strength: if let Ok(s) = opt_s { s.max(0.0) } else { 6.0 },
|
||||
strength: if let Some(s) = opt_s { s.max(0.0) } else { 6.0 },
|
||||
},
|
||||
);
|
||||
|
||||
@ -692,25 +669,21 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
|
||||
}
|
||||
|
||||
fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
|
||||
match opt_alias {
|
||||
Ok(alias) => {
|
||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
||||
let ecs = server.state.ecs();
|
||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||
let msg = &args[alias.len()..args.len()];
|
||||
if let Some(player) = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||
.join()
|
||||
.find(|(_, player)| player.alias == alias)
|
||||
.map(|(entity, _)| entity);
|
||||
let msg = &args[alias.len()..args.len()];
|
||||
match opt_player {
|
||||
Some(player) => {
|
||||
.map(|(entity, _)| entity)
|
||||
{
|
||||
if player != entity {
|
||||
if msg.len() > 1 {
|
||||
let opt_name = ecs
|
||||
if let Some(name) = ecs
|
||||
.read_storage::<comp::Player>()
|
||||
.get(entity)
|
||||
.map(|s| s.alias.clone());
|
||||
match opt_name {
|
||||
Some(name) => {
|
||||
.map(|s| s.alias.clone())
|
||||
{
|
||||
server.clients.notify(
|
||||
player,
|
||||
ServerMsg::tell(format!("[{}] tells you:{}", name, msg)),
|
||||
@ -719,14 +692,12 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
entity,
|
||||
ServerMsg::tell(format!("You tell [{}]:{}", alias, msg)),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
} else {
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(String::from("Failed to send message.")),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
server.clients.notify(
|
||||
entity,
|
||||
@ -739,17 +710,15 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
ServerMsg::private(format!("You can't /tell yourself.")),
|
||||
);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
} else {
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::private(format!("Player '{}' not found!", alias)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => server
|
||||
} else {
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string))),
|
||||
.notify(entity, ServerMsg::private(String::from(action.help_string)));
|
||||
}
|
||||
}
|
||||
|
@ -71,13 +71,11 @@ pub struct Server {
|
||||
|
||||
impl Server {
|
||||
/// Create a new `Server` bound to the default socket.
|
||||
#[allow(dead_code)]
|
||||
pub fn new(settings: ServerSettings) -> Result<Self, Error> {
|
||||
Self::bind(settings.address, settings)
|
||||
}
|
||||
|
||||
/// Create a new server bound to the given socket.
|
||||
#[allow(dead_code)]
|
||||
pub fn bind<A: Into<SocketAddr>>(addrs: A, settings: ServerSettings) -> Result<Self, Error> {
|
||||
let (chunk_tx, chunk_rx) = mpsc::channel();
|
||||
|
||||
@ -114,31 +112,26 @@ impl Server {
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn with_thread_pool(mut self, thread_pool: ThreadPool) -> Self {
|
||||
self.thread_pool = thread_pool;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a reference to the server's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state(&self) -> &State {
|
||||
&self.state
|
||||
}
|
||||
/// Get a mutable reference to the server's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state_mut(&mut self) -> &mut State {
|
||||
&mut self.state
|
||||
}
|
||||
|
||||
/// Get a reference to the server's world.
|
||||
#[allow(dead_code)]
|
||||
pub fn world(&self) -> &World {
|
||||
&self.world
|
||||
}
|
||||
|
||||
/// Build a non-player character.
|
||||
#[allow(dead_code)]
|
||||
pub fn create_npc(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
@ -159,7 +152,6 @@ impl Server {
|
||||
}
|
||||
|
||||
/// Build a static object entity
|
||||
#[allow(dead_code)]
|
||||
pub fn create_object(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
@ -207,7 +199,6 @@ impl Server {
|
||||
}
|
||||
|
||||
/// Execute a single server tick, handle input and update the game state by the given duration.
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(&mut self, _input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||
// This tick function is the centre of the Veloren universe. Most server-side things are
|
||||
// managed from here, and as such it's important that it stays organised. Please consult
|
||||
@ -381,7 +372,6 @@ impl Server {
|
||||
}
|
||||
|
||||
/// Clean up the server after a tick.
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup(&mut self) {
|
||||
// Cleanup the local state
|
||||
self.state.cleanup();
|
||||
@ -687,23 +677,38 @@ impl Server {
|
||||
// Save player metadata (for example the username).
|
||||
state.write_component(entity, player);
|
||||
|
||||
// Sync physics
|
||||
// Sync physics of all entities
|
||||
for (&uid, &pos, vel, ori, action_state) in (
|
||||
&state.ecs().read_storage::<Uid>(),
|
||||
&state.ecs().read_storage::<comp::Pos>(),
|
||||
&state.ecs().read_storage::<comp::Pos>(), // We assume all these entities have a position
|
||||
state.ecs().read_storage::<comp::Vel>().maybe(),
|
||||
state.ecs().read_storage::<comp::Ori>().maybe(),
|
||||
state.ecs().read_storage::<comp::ActionState>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
client.notify(ServerMsg::EntityPhysics {
|
||||
client.notify(ServerMsg::EntityPos {
|
||||
entity: uid.into(),
|
||||
pos,
|
||||
vel: vel.copied(),
|
||||
ori: ori.copied(),
|
||||
action_state: action_state.copied(),
|
||||
});
|
||||
if let Some(vel) = vel.copied() {
|
||||
client.notify(ServerMsg::EntityVel {
|
||||
entity: uid.into(),
|
||||
vel,
|
||||
});
|
||||
}
|
||||
if let Some(ori) = ori.copied() {
|
||||
client.notify(ServerMsg::EntityOri {
|
||||
entity: uid.into(),
|
||||
ori,
|
||||
});
|
||||
}
|
||||
if let Some(action_state) = action_state.copied() {
|
||||
client.notify(ServerMsg::EntityActionState {
|
||||
entity: uid.into(),
|
||||
action_state,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the client its request was successful.
|
||||
@ -716,8 +721,9 @@ impl Server {
|
||||
self.clients
|
||||
.notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package()));
|
||||
|
||||
// TODO: Move this into some new method like `handle_sys_outputs` right after ticking the world
|
||||
// Handle deaths.
|
||||
let ecs = &self.state.ecs();
|
||||
let ecs = self.state.ecs_mut();
|
||||
let clients = &mut self.clients;
|
||||
let todo_kill = (&ecs.entities(), &ecs.read_storage::<comp::Dying>())
|
||||
.join()
|
||||
@ -774,20 +780,17 @@ impl Server {
|
||||
// Actually kill them
|
||||
for entity in todo_kill {
|
||||
if let Some(client) = self.clients.get_mut(&entity) {
|
||||
self.state.write_component(entity, comp::Vel(Vec3::zero()));
|
||||
self.state.write_component(entity, comp::ForceUpdate);
|
||||
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 _ = self.state.ecs_mut().delete_entity_synced(entity);
|
||||
let _ = ecs.delete_entity_synced(entity);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle respawns
|
||||
let todo_respawn = (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Respawning>(),
|
||||
)
|
||||
let todo_respawn = (&ecs.entities(), &ecs.read_storage::<comp::Respawning>())
|
||||
.join()
|
||||
.map(|(entity, _)| entity)
|
||||
.collect::<Vec<EcsEntity>>();
|
||||
@ -795,64 +798,76 @@ impl Server {
|
||||
for entity in todo_respawn {
|
||||
if let Some(client) = self.clients.get_mut(&entity) {
|
||||
client.allow_state(ClientState::Character);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Stats>()
|
||||
ecs.write_storage::<comp::Stats>()
|
||||
.get_mut(entity)
|
||||
.map(|stats| stats.revive());
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Pos>()
|
||||
ecs.write_storage::<comp::Pos>()
|
||||
.get_mut(entity)
|
||||
.map(|pos| pos.0.z += 20.0);
|
||||
self.state.write_component(entity, comp::ForceUpdate);
|
||||
let _ = ecs.write_storage().insert(entity, comp::ForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
// Sync physics
|
||||
for (entity, &uid, &pos, vel, ori, action_state, force_update) in (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<Uid>(),
|
||||
&self.state.ecs().read_storage::<comp::Pos>(),
|
||||
self.state.ecs().read_storage::<comp::Vel>().maybe(),
|
||||
self.state.ecs().read_storage::<comp::Ori>().maybe(),
|
||||
self.state.ecs().read_storage::<comp::ActionState>().maybe(),
|
||||
self.state.ecs().read_storage::<comp::ForceUpdate>().maybe(),
|
||||
for (entity, &uid, &pos, force_update) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Uid>(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
ecs.read_storage::<comp::ForceUpdate>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let msg = ServerMsg::EntityPhysics {
|
||||
entity: uid.into(),
|
||||
pos,
|
||||
vel: vel.copied(),
|
||||
ori: ori.copied(),
|
||||
action_state: action_state.copied(),
|
||||
};
|
||||
|
||||
let state = &self.state;
|
||||
let clients = &mut self.clients;
|
||||
|
||||
let in_vd = |entity| {
|
||||
// Get client position.
|
||||
let client_pos = match state.ecs().read_storage::<comp::Pos>().get(entity) {
|
||||
Some(pos) => pos.0,
|
||||
None => return false,
|
||||
};
|
||||
// Get client view distance
|
||||
let client_vd = match state.ecs().read_storage::<comp::Player>().get(entity) {
|
||||
Some(comp::Player {
|
||||
view_distance: Some(vd),
|
||||
..
|
||||
}) => *vd,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
(pos.0 - client_pos)
|
||||
if let (Some(client_pos), Some(client_vd)) = (
|
||||
ecs.read_storage::<comp::Pos>().get(entity),
|
||||
ecs.read_storage::<comp::Player>()
|
||||
.get(entity)
|
||||
.map(|pl| pl.view_distance)
|
||||
.and_then(|v| v),
|
||||
) {
|
||||
{
|
||||
// Check if the entity is in the client's range
|
||||
(pos.0 - client_pos.0)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
(d.abs() as u32 / sz).checked_sub(2).unwrap_or(0)
|
||||
})
|
||||
.magnitude_squared()
|
||||
< client_vd.pow(2)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let mut last_pos = ecs.write_storage::<comp::Last<comp::Pos>>();
|
||||
let mut last_vel = ecs.write_storage::<comp::Last<comp::Vel>>();
|
||||
let mut last_ori = ecs.write_storage::<comp::Last<comp::Ori>>();
|
||||
let mut last_action_state = ecs.write_storage::<comp::Last<comp::ActionState>>();
|
||||
|
||||
if let (
|
||||
Some(client_pos),
|
||||
Some(client_vel),
|
||||
Some(client_ori),
|
||||
Some(client_action_state),
|
||||
) = (
|
||||
ecs.read_storage::<comp::Pos>().get(entity),
|
||||
ecs.read_storage::<comp::Vel>().get(entity),
|
||||
ecs.read_storage::<comp::Ori>().get(entity),
|
||||
ecs.read_storage::<comp::ActionState>().get(entity),
|
||||
) {
|
||||
// If nothing changed...
|
||||
if last_pos
|
||||
.get(entity)
|
||||
.map(|&l| l != *client_pos)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = last_pos.insert(entity, comp::Last(*client_pos));
|
||||
|
||||
let msg = ServerMsg::EntityPos {
|
||||
entity: uid.into(),
|
||||
pos: *client_pos,
|
||||
};
|
||||
|
||||
match force_update {
|
||||
@ -861,6 +876,62 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
if last_vel
|
||||
.get(entity)
|
||||
.map(|&l| l != *client_vel)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = last_vel.insert(entity, comp::Last(*client_vel));
|
||||
|
||||
let msg = ServerMsg::EntityVel {
|
||||
entity: uid.into(),
|
||||
vel: *client_vel,
|
||||
};
|
||||
|
||||
match force_update {
|
||||
Some(_) => clients.notify_ingame_if(msg, in_vd),
|
||||
None => clients.notify_ingame_if_except(entity, msg, in_vd),
|
||||
}
|
||||
}
|
||||
|
||||
if last_ori
|
||||
.get(entity)
|
||||
.map(|&l| l != *client_ori)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = last_ori.insert(entity, comp::Last(*client_ori));
|
||||
|
||||
let msg = ServerMsg::EntityOri {
|
||||
entity: uid.into(),
|
||||
ori: *client_ori,
|
||||
};
|
||||
|
||||
match force_update {
|
||||
Some(_) => clients.notify_ingame_if(msg, in_vd),
|
||||
None => clients.notify_ingame_if_except(entity, msg, in_vd),
|
||||
}
|
||||
}
|
||||
|
||||
if last_action_state
|
||||
.get(entity)
|
||||
.map(|&l| l != *client_action_state)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = last_action_state.insert(entity, comp::Last(*client_action_state));
|
||||
|
||||
let msg = ServerMsg::EntityActionState {
|
||||
entity: uid.into(),
|
||||
action_state: *client_action_state,
|
||||
};
|
||||
|
||||
match force_update {
|
||||
Some(_) => clients.notify_ingame_if(msg, in_vd),
|
||||
None => clients.notify_ingame_if_except(entity, msg, in_vd),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all force flags.
|
||||
self.state
|
||||
.ecs_mut()
|
||||
|
Loading…
Reference in New Issue
Block a user