Always sync components for a client's entity even if it has no position

or has sync_me false in `Presence`.
This commit is contained in:
Imbris 2023-06-04 14:21:42 -04:00
parent ba7d7481d7
commit 997babca18
3 changed files with 42 additions and 17 deletions

View File

@ -269,6 +269,28 @@ impl RegionMap {
None
}
/// Checks if this entity is located in the `RegionMap` using the provided
/// position to limit which regions are checked.
///
/// May produce false negatives (e.g. if for some reason the entity is not
/// in a region near the provided position).
pub fn in_region_map_relaxed(&self, entity: specs::Entity, pos: Vec3<f32>) -> bool {
let id = entity.id();
let pos = pos.map(|e| e as i32);
// Compute key for most likely region
let key = Self::pos_key(pos);
if let Some(region) = self.regions.get(&key) && region.entities().contains(id) { return true }
// Get the base of the four nearest regions.
let quad_base = Self::pos_key(pos - (REGION_SIZE / 2) as i32);
[(0, 0), (0, 1), (1, 0), (1, 1)]
.iter()
.map(|&offset| Vec2::<i32>::from(offset) + quad_base)
// skip key we already checked
.any(|k| k != key && self.regions.get(&key).is_some_and(|r| r.entities().contains(id)))
}
fn key_index(&self, key: Vec2<i32>) -> Option<usize> {
self.regions.get_full(&key).map(|(i, _, _)| i)
}

View File

@ -362,8 +362,6 @@ impl<'a> System<'a> for Sys {
}
}
// TODO: Sync clients that don't have a position?
// Sync inventories
for (inventory, update, client) in (inventories, &mut inventory_updates, &clients).join() {
client.send_fallible(ServerGeneral::InventoryUpdate(
@ -372,18 +370,19 @@ impl<'a> System<'a> for Sys {
));
}
// TODO: this seems like the ideal spot to sync other components for clients
// that don't have a position or otherwise aren't included in the regions that
// the client is subscribed to...
//
// Maybe we can pass a bool into `create_sync_from_client_package`... renamed it
// to create_sync_package_for_client_entity(?)
// create_client_sync_package(?)
//
// Sync components that are only synced for the client's own entity.
for (entity, client) in (&entities, &clients).join() {
let comp_sync_package =
trackers.create_sync_from_client_package(&tracked_storages, entity);
for (entity, client, maybe_pos) in (&entities, &clients, positions.maybe()).join() {
// Include additional components for clients that aren't in a region (e.g. due
// to having no position or have sync_me as `false`) since those
// won't be synced above.
let include_all_comps =
!maybe_pos.is_some_and(|pos| region_map.in_region_map_relaxed(entity, pos.0));
let comp_sync_package = trackers.create_sync_from_client_package(
&tracked_storages,
entity,
include_all_comps,
);
if !comp_sync_package.is_empty() {
client.send_fallible(ServerGeneral::CompSync(
comp_sync_package,

View File

@ -231,10 +231,14 @@ macro_rules! trackers {
/// Create sync package for components that are only synced for the client's entity.
///
/// This can optionally include components that are synced "for any entity" for cases
/// where other mechanisms don't sync those components.
pub fn create_sync_from_client_package(
&self,
comps: &TrackedStorages,
entity: specs::Entity,
include_all_comps: bool,
) -> CompSyncPackage<EcsCompPacket> {
// TODO: this type repeats the entity uid for each component but
// we know they will all be the same here, using it for now for
@ -249,10 +253,10 @@ macro_rules! trackers {
};
$(
if matches!(
<$component_type as NetSync>::SYNC_FROM,
SyncFrom::ClientEntity,
) {
if match <$component_type as NetSync>::SYNC_FROM {
SyncFrom::ClientEntity => true,
SyncFrom::AnyEntity => include_all_comps,
} {
comp_sync_package.add_component_update(
&self.$component_name,
&comps.$component_name,