2019-11-04 00:57:36 +00:00
|
|
|
use super::{
|
2019-12-18 05:22:52 +00:00
|
|
|
sentinel::{DeletedEntities, ReadTrackers, TrackedComps},
|
2019-11-04 00:57:36 +00:00
|
|
|
SysTimer,
|
|
|
|
};
|
2019-10-15 04:06:14 +00:00
|
|
|
use crate::{
|
|
|
|
client::{Client, RegionSubscription},
|
|
|
|
Tick,
|
|
|
|
};
|
|
|
|
use common::{
|
2020-08-06 16:41:43 +00:00
|
|
|
comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
|
2020-10-07 10:31:49 +00:00
|
|
|
msg::{ServerGeneral, ServerInGame},
|
2020-07-31 17:16:20 +00:00
|
|
|
outcome::Outcome,
|
2019-10-15 04:06:14 +00:00
|
|
|
region::{Event as RegionEvent, RegionMap},
|
2020-08-29 06:39:16 +00:00
|
|
|
span,
|
2019-12-18 05:22:52 +00:00
|
|
|
state::TimeOfDay,
|
2020-03-18 21:00:07 +00:00
|
|
|
sync::{CompSyncPackage, Uid},
|
2020-07-31 17:16:20 +00:00
|
|
|
terrain::TerrainChunkSize,
|
2020-08-06 16:41:43 +00:00
|
|
|
vol::RectVolSize,
|
2019-10-15 04:06:14 +00:00
|
|
|
};
|
|
|
|
use specs::{
|
2019-10-20 07:20:21 +00:00
|
|
|
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
|
2019-10-15 04:06:14 +00:00
|
|
|
};
|
2020-07-31 17:16:20 +00:00
|
|
|
use vek::*;
|
2019-10-15 04:06:14 +00:00
|
|
|
|
|
|
|
/// This system will send physics updates to the client
|
|
|
|
pub struct Sys;
|
|
|
|
impl<'a> System<'a> for Sys {
|
2020-06-10 19:47:36 +00:00
|
|
|
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
2019-10-15 04:06:14 +00:00
|
|
|
type SystemData = (
|
|
|
|
Entities<'a>,
|
|
|
|
Read<'a, Tick>,
|
2019-12-18 05:22:52 +00:00
|
|
|
ReadExpect<'a, TimeOfDay>,
|
2019-10-15 04:06:14 +00:00
|
|
|
ReadExpect<'a, RegionMap>,
|
2019-10-20 07:20:21 +00:00
|
|
|
Write<'a, SysTimer<Self>>,
|
2019-10-15 04:06:14 +00:00
|
|
|
ReadStorage<'a, Uid>,
|
|
|
|
ReadStorage<'a, Pos>,
|
|
|
|
ReadStorage<'a, Vel>,
|
|
|
|
ReadStorage<'a, Ori>,
|
|
|
|
ReadStorage<'a, Inventory>,
|
|
|
|
ReadStorage<'a, RegionSubscription>,
|
2020-07-31 17:16:20 +00:00
|
|
|
ReadStorage<'a, Player>,
|
2019-10-15 04:06:14 +00:00
|
|
|
WriteStorage<'a, Last<Pos>>,
|
|
|
|
WriteStorage<'a, Last<Vel>>,
|
|
|
|
WriteStorage<'a, Last<Ori>>,
|
|
|
|
WriteStorage<'a, Client>,
|
|
|
|
WriteStorage<'a, ForceUpdate>,
|
|
|
|
WriteStorage<'a, InventoryUpdate>,
|
2019-11-29 06:04:37 +00:00
|
|
|
Write<'a, DeletedEntities>,
|
2020-07-31 17:16:20 +00:00
|
|
|
Write<'a, Vec<Outcome>>,
|
2019-11-04 00:57:36 +00:00
|
|
|
TrackedComps<'a>,
|
|
|
|
ReadTrackers<'a>,
|
2019-10-15 04:06:14 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
fn run(
|
|
|
|
&mut self,
|
|
|
|
(
|
|
|
|
entities,
|
|
|
|
tick,
|
2019-12-18 05:22:52 +00:00
|
|
|
time_of_day,
|
2019-10-15 04:06:14 +00:00
|
|
|
region_map,
|
2019-10-20 07:20:21 +00:00
|
|
|
mut timer,
|
2019-10-15 04:06:14 +00:00
|
|
|
uids,
|
|
|
|
positions,
|
|
|
|
velocities,
|
|
|
|
orientations,
|
|
|
|
inventories,
|
|
|
|
subscriptions,
|
2020-07-31 17:16:20 +00:00
|
|
|
players,
|
2019-10-15 04:06:14 +00:00
|
|
|
mut last_pos,
|
|
|
|
mut last_vel,
|
|
|
|
mut last_ori,
|
|
|
|
mut clients,
|
|
|
|
mut force_updates,
|
|
|
|
mut inventory_updates,
|
2019-11-29 06:04:37 +00:00
|
|
|
mut deleted_entities,
|
2020-07-31 17:16:20 +00:00
|
|
|
mut outcomes,
|
2019-11-04 00:57:36 +00:00
|
|
|
tracked_comps,
|
2019-11-29 06:04:37 +00:00
|
|
|
trackers,
|
2019-10-15 04:06:14 +00:00
|
|
|
): Self::SystemData,
|
|
|
|
) {
|
2020-09-07 04:59:16 +00:00
|
|
|
span!(_guard, "run", "entity_sync::Sys::run");
|
2019-10-20 07:20:21 +00:00
|
|
|
timer.start();
|
|
|
|
|
2019-10-15 04:06:14 +00:00
|
|
|
let tick = tick.0;
|
|
|
|
// To send entity updates
|
|
|
|
// 1. Iterate through regions
|
|
|
|
// 2. Iterate through region subscribers (ie clients)
|
2020-02-01 20:39:39 +00:00
|
|
|
// - Collect a list of entity ids for clients who are subscribed to this
|
|
|
|
// region (hash calc to check each)
|
2019-10-15 04:06:14 +00:00
|
|
|
// 3. Iterate through events from that region
|
2020-02-01 20:39:39 +00:00
|
|
|
// - For each entity entered event, iterate through the client list and
|
|
|
|
// check if they are subscribed to the source (hash calc per subscribed
|
|
|
|
// client per entity event), if not subscribed to the source send a entity
|
|
|
|
// creation message to that client
|
|
|
|
// - For each entity left event, iterate through the client list and check
|
|
|
|
// if they are subscribed to the destination (hash calc per subscribed
|
|
|
|
// client per entity event)
|
2019-10-15 04:06:14 +00:00
|
|
|
// 4. Iterate through entities in that region
|
|
|
|
// 5. Inform clients of the component changes for that entity
|
|
|
|
// - Throttle update rate base on distance to each client
|
|
|
|
|
|
|
|
// Sync physics
|
|
|
|
// via iterating through regions
|
|
|
|
for (key, region) in region_map.iter() {
|
2020-02-01 20:39:39 +00:00
|
|
|
// Assemble subscriber list for this region by iterating through clients and
|
|
|
|
// checking if they are subscribed to this region
|
2019-10-15 04:06:14 +00:00
|
|
|
let mut subscribers = (&mut clients, &entities, &subscriptions, &positions)
|
|
|
|
.join()
|
|
|
|
.filter_map(|(client, entity, subscription, pos)| {
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
if client.in_game.is_some() && subscription.regions.contains(&key) {
|
2019-10-15 04:06:14 +00:00
|
|
|
Some((client, &subscription.regions, entity, *pos))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for event in region.events() {
|
|
|
|
match event {
|
2019-10-25 05:35:15 +00:00
|
|
|
RegionEvent::Entered(id, maybe_key) => {
|
2019-11-29 06:04:37 +00:00
|
|
|
// Don't process newly created entities here (redundant network messages)
|
|
|
|
if trackers.uid.inserted().contains(*id) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-25 05:35:15 +00:00
|
|
|
let entity = entities.entity(*id);
|
2020-03-20 14:45:36 +00:00
|
|
|
if let Some((_uid, pos, vel, ori)) = uids.get(entity).and_then(|uid| {
|
2020-03-18 21:00:07 +00:00
|
|
|
positions.get(entity).map(|pos| {
|
|
|
|
(uid, pos, velocities.get(entity), orientations.get(entity))
|
2019-10-25 05:35:15 +00:00
|
|
|
})
|
2020-03-18 21:00:07 +00:00
|
|
|
}) {
|
2020-10-07 10:31:49 +00:00
|
|
|
let create_msg =
|
|
|
|
ServerGeneral::CreateEntity(tracked_comps.create_entity_package(
|
2020-03-18 21:00:07 +00:00
|
|
|
entity,
|
|
|
|
Some(*pos),
|
|
|
|
vel.copied(),
|
|
|
|
ori.copied(),
|
2020-10-07 10:31:49 +00:00
|
|
|
));
|
2019-10-26 02:00:30 +00:00
|
|
|
for (client, regions, client_entity, _) in &mut subscribers {
|
2019-10-25 05:35:15 +00:00
|
|
|
if maybe_key
|
|
|
|
.as_ref()
|
|
|
|
.map(|key| !regions.contains(key))
|
|
|
|
.unwrap_or(true)
|
2019-11-04 00:57:36 +00:00
|
|
|
// Client doesn't need to know about itself
|
2019-10-26 02:00:30 +00:00
|
|
|
&& *client_entity != entity
|
2019-10-25 05:35:15 +00:00
|
|
|
{
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
client.send_msg(create_msg.clone());
|
2019-10-25 05:35:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-10-15 04:06:14 +00:00
|
|
|
RegionEvent::Left(id, maybe_key) => {
|
|
|
|
// Lookup UID for entity
|
|
|
|
if let Some(&uid) = uids.get(entities.entity(*id)) {
|
|
|
|
for (client, regions, _, _) in &mut subscribers {
|
2019-10-25 05:35:15 +00:00
|
|
|
if maybe_key
|
2019-10-15 04:06:14 +00:00
|
|
|
.as_ref()
|
2019-10-25 05:35:15 +00:00
|
|
|
.map(|key| !regions.contains(key))
|
|
|
|
.unwrap_or(true)
|
2019-10-15 04:06:14 +00:00
|
|
|
{
|
2020-10-07 10:31:49 +00:00
|
|
|
client.send_msg(ServerGeneral::DeleteEntity(uid));
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-04 00:57:36 +00:00
|
|
|
// Sync tracked components
|
2019-11-29 06:04:37 +00:00
|
|
|
// Get deleted entities in this region from DeletedEntities
|
2020-03-18 21:00:07 +00:00
|
|
|
let (entity_sync_package, comp_sync_package) = trackers.create_sync_packages(
|
|
|
|
&tracked_comps,
|
|
|
|
region.entities(),
|
|
|
|
deleted_entities
|
|
|
|
.take_deleted_in_region(key)
|
2020-06-11 18:44:03 +00:00
|
|
|
.unwrap_or_default(),
|
2019-11-04 00:57:36 +00:00
|
|
|
);
|
2020-10-07 10:31:49 +00:00
|
|
|
let entity_sync_msg = ServerGeneral::EntitySync(entity_sync_package);
|
|
|
|
let comp_sync_msg = ServerGeneral::CompSync(comp_sync_package);
|
2020-03-18 21:00:07 +00:00
|
|
|
subscribers.iter_mut().for_each(move |(client, _, _, _)| {
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
client.send_msg(entity_sync_msg.clone());
|
|
|
|
client.send_msg(comp_sync_msg.clone());
|
2020-03-18 21:00:07 +00:00
|
|
|
});
|
2019-10-15 04:06:14 +00:00
|
|
|
|
2020-10-07 10:31:49 +00:00
|
|
|
let mut send_msg = |msg: ServerGeneral,
|
2019-11-04 00:57:36 +00:00
|
|
|
entity: EcsEntity,
|
|
|
|
pos: Pos,
|
|
|
|
force_update: Option<&ForceUpdate>,
|
|
|
|
throttle: bool| {
|
|
|
|
for (client, _, client_entity, client_pos) in &mut subscribers {
|
2020-03-18 21:00:07 +00:00
|
|
|
if if client_entity == &entity {
|
2019-11-29 06:04:37 +00:00
|
|
|
// Don't send client physics updates about itself unless force update is set
|
|
|
|
force_update.is_some()
|
2019-11-04 00:57:36 +00:00
|
|
|
} else if !throttle {
|
2020-03-18 21:00:07 +00:00
|
|
|
// Send the message if not throttling
|
2019-11-04 00:57:36 +00:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
// Throttle update rate based on distance to client
|
|
|
|
let distance_sq = client_pos.0.distance_squared(pos.0);
|
2020-03-18 21:00:07 +00:00
|
|
|
let id_staggered_tick = tick + entity.id() as u64;
|
2019-11-04 00:57:36 +00:00
|
|
|
// More entities farther away so checks start there
|
|
|
|
if distance_sq > 300.0f32.powi(2) {
|
2020-03-18 21:00:07 +00:00
|
|
|
id_staggered_tick % 32 == 0
|
2019-11-04 00:57:36 +00:00
|
|
|
} else if distance_sq > 250.0f32.powi(2) {
|
2020-03-18 21:00:07 +00:00
|
|
|
id_staggered_tick % 16 == 0
|
2019-11-04 00:57:36 +00:00
|
|
|
} else if distance_sq > 200.0f32.powi(2) {
|
2020-03-18 21:00:07 +00:00
|
|
|
id_staggered_tick % 8 == 0
|
2019-11-04 00:57:36 +00:00
|
|
|
} else if distance_sq > 150.0f32.powi(2) {
|
2020-03-18 21:00:07 +00:00
|
|
|
id_staggered_tick % 4 == 0
|
2019-11-04 00:57:36 +00:00
|
|
|
} else if distance_sq > 100.0f32.powi(2) {
|
2020-03-18 21:00:07 +00:00
|
|
|
id_staggered_tick % 2 == 0
|
2019-11-04 00:57:36 +00:00
|
|
|
} else {
|
|
|
|
true // Closer than 100 blocks
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
2020-03-18 21:00:07 +00:00
|
|
|
} {
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
client.send_msg(msg.clone());
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
2019-11-04 00:57:36 +00:00
|
|
|
}
|
|
|
|
};
|
2019-10-15 04:06:14 +00:00
|
|
|
|
2019-11-04 00:57:36 +00:00
|
|
|
// Sync physics components
|
2020-03-18 21:00:07 +00:00
|
|
|
for (_, entity, &uid, &pos, maybe_vel, maybe_ori, force_update) in (
|
2019-10-15 04:06:14 +00:00
|
|
|
region.entities(),
|
|
|
|
&entities,
|
|
|
|
&uids,
|
|
|
|
&positions,
|
|
|
|
velocities.maybe(),
|
|
|
|
orientations.maybe(),
|
|
|
|
force_updates.maybe(),
|
|
|
|
)
|
|
|
|
.join()
|
|
|
|
{
|
2020-03-18 21:00:07 +00:00
|
|
|
let mut comp_sync_package = CompSyncPackage::new();
|
|
|
|
let mut throttle = true;
|
2020-08-25 12:21:25 +00:00
|
|
|
// TODO: An entity that stopped moving on a tick that it wasn't sent to the
|
|
|
|
// player will never have its position updated
|
2020-03-18 21:00:07 +00:00
|
|
|
match last_pos.get(entity).map(|&l| l.0 != pos) {
|
|
|
|
Some(false) => {},
|
|
|
|
Some(true) => {
|
|
|
|
let _ = last_pos.insert(entity, Last(pos));
|
|
|
|
comp_sync_package.comp_modified(uid, pos);
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
let _ = last_pos.insert(entity, Last(pos));
|
|
|
|
throttle = false;
|
|
|
|
comp_sync_package.comp_inserted(uid, pos);
|
|
|
|
},
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(&vel) = maybe_vel {
|
2020-03-18 21:00:07 +00:00
|
|
|
match last_vel.get(entity).map(|&l| l.0 != vel) {
|
|
|
|
Some(false) => {},
|
|
|
|
Some(true) => {
|
|
|
|
let _ = last_vel.insert(entity, Last(vel));
|
|
|
|
comp_sync_package.comp_modified(uid, vel);
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
let _ = last_vel.insert(entity, Last(vel));
|
|
|
|
throttle = false;
|
|
|
|
comp_sync_package.comp_inserted(uid, vel);
|
|
|
|
},
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
2020-03-18 21:00:07 +00:00
|
|
|
} else if last_vel.remove(entity).is_some() {
|
|
|
|
// Send removal message if Vel was removed
|
|
|
|
// Note: we don't have to handle this for position because the entity will be
|
|
|
|
// removed from the client by the region system
|
|
|
|
throttle = false;
|
|
|
|
comp_sync_package.comp_removed::<Vel>(uid);
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(&ori) = maybe_ori {
|
2020-03-18 21:00:07 +00:00
|
|
|
match last_ori.get(entity).map(|&l| l.0 != ori) {
|
|
|
|
Some(false) => {},
|
|
|
|
Some(true) => {
|
|
|
|
let _ = last_ori.insert(entity, Last(ori));
|
|
|
|
comp_sync_package.comp_modified(uid, ori);
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
let _ = last_ori.insert(entity, Last(ori));
|
|
|
|
throttle = false;
|
|
|
|
comp_sync_package.comp_inserted(uid, ori);
|
|
|
|
},
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
2020-03-18 21:00:07 +00:00
|
|
|
} else if last_ori.remove(entity).is_some() {
|
|
|
|
// Send removal message if Ori was removed
|
|
|
|
throttle = false;
|
|
|
|
comp_sync_package.comp_removed::<Ori>(uid);
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 21:00:07 +00:00
|
|
|
send_msg(
|
2020-10-07 10:31:49 +00:00
|
|
|
ServerGeneral::CompSync(comp_sync_package),
|
2020-03-18 21:00:07 +00:00
|
|
|
entity,
|
|
|
|
pos,
|
|
|
|
force_update,
|
|
|
|
throttle,
|
|
|
|
);
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
// Handle entity deletion in regions that don't exist in RegionMap
|
|
|
|
// (theoretically none)
|
2019-11-29 06:04:37 +00:00
|
|
|
for (region_key, deleted) in deleted_entities.take_remaining_deleted() {
|
|
|
|
for client in
|
|
|
|
(&mut clients, &subscriptions)
|
|
|
|
.join()
|
|
|
|
.filter_map(|(client, subscription)| {
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
if client.in_game.is_some() && subscription.regions.contains(®ion_key) {
|
2019-11-29 06:04:37 +00:00
|
|
|
Some(client)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
{
|
|
|
|
for uid in &deleted {
|
2020-10-07 10:31:49 +00:00
|
|
|
client.send_msg(ServerGeneral::DeleteEntity(Uid(*uid)));
|
2019-11-29 06:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-04 00:57:36 +00:00
|
|
|
// TODO: Sync clients that don't have a position?
|
|
|
|
|
2019-10-15 04:06:14 +00:00
|
|
|
// Sync inventories
|
2020-03-04 10:09:48 +00:00
|
|
|
for (client, inventory, update) in (&mut clients, &inventories, &inventory_updates).join() {
|
2020-10-07 10:31:49 +00:00
|
|
|
client.send_msg(ServerInGame::InventoryUpdate(
|
2020-03-04 10:09:48 +00:00
|
|
|
inventory.clone(),
|
|
|
|
update.event(),
|
|
|
|
));
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
|
2020-07-31 17:16:20 +00:00
|
|
|
// Sync outcomes
|
|
|
|
for (client, player, pos) in (&mut clients, &players, positions.maybe()).join() {
|
2020-08-06 16:41:43 +00:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
};
|
2020-07-31 17:16:20 +00:00
|
|
|
|
|
|
|
let outcomes = outcomes
|
|
|
|
.iter()
|
|
|
|
.filter(|o| o.get_pos().and_then(&is_near).unwrap_or(true))
|
|
|
|
.cloned()
|
|
|
|
.collect::<Vec<_>>();
|
2020-08-17 09:08:11 +00:00
|
|
|
if !outcomes.is_empty() {
|
2020-10-07 10:31:49 +00:00
|
|
|
client.send_msg(ServerInGame::Outcomes(outcomes));
|
2020-07-31 17:16:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
outcomes.clear();
|
|
|
|
|
2019-10-15 04:06:14 +00:00
|
|
|
// Remove all force flags.
|
|
|
|
force_updates.clear();
|
|
|
|
inventory_updates.clear();
|
2019-10-20 07:20:21 +00:00
|
|
|
|
2019-11-04 00:57:36 +00:00
|
|
|
// Sync resources
|
2020-02-01 20:39:39 +00:00
|
|
|
// TODO: doesn't really belong in this system (rename system or create another
|
|
|
|
// system?)
|
2020-10-07 10:31:49 +00:00
|
|
|
let tof_msg = ServerGeneral::TimeOfDay(*time_of_day);
|
2019-11-04 00:57:36 +00:00
|
|
|
for client in (&mut clients).join() {
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
client.send_msg(tof_msg.clone());
|
2019-11-04 00:57:36 +00:00
|
|
|
}
|
|
|
|
|
2019-10-20 07:20:21 +00:00
|
|
|
timer.end();
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
}
|