mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Sync entities for group members regardless of distance.
This makes them visible on the map and makes their health visible on the left.
This commit is contained in:
parent
287a1a9b94
commit
8242a49681
@ -50,6 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- You can now block and parry with melee weapons
|
- You can now block and parry with melee weapons
|
||||||
- Lift is now calculated for gliders based on dimensions (currently same for all)
|
- Lift is now calculated for gliders based on dimensions (currently same for all)
|
||||||
- Specific music tracks can now play exclusively in towns.
|
- Specific music tracks can now play exclusively in towns.
|
||||||
|
- Group members are now visible on the map regardless of distance.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use tracing::{error, warn};
|
|||||||
// - clients don't know which pets are theirs (could be easy to solve by
|
// - clients don't know which pets are theirs (could be easy to solve by
|
||||||
// putting owner uid in Role::Pet)
|
// putting owner uid in Role::Pet)
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq, Serialize, Deserialize)]
|
||||||
pub struct Group(u32);
|
pub struct Group(u32);
|
||||||
|
|
||||||
// TODO: Hack
|
// TODO: Hack
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
Tick,
|
Tick,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{Collider, ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
|
comp::{Collider, ForceUpdate, Group, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
region::{Event as RegionEvent, RegionMap},
|
region::{Event as RegionEvent, RegionMap},
|
||||||
resources::{PlayerPhysicsSettings, TimeOfDay},
|
resources::{PlayerPhysicsSettings, TimeOfDay},
|
||||||
@ -15,8 +15,9 @@ use common::{
|
|||||||
};
|
};
|
||||||
use common_ecs::{Job, Origin, Phase, System};
|
use common_ecs::{Job, Origin, Phase, System};
|
||||||
use common_net::{msg::ServerGeneral, sync::CompSyncPackage};
|
use common_net::{msg::ServerGeneral, sync::CompSyncPackage};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage};
|
use specs::{Entities, Entity, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// This system will send physics updates to the client
|
/// This system will send physics updates to the client
|
||||||
@ -37,6 +38,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
ReadStorage<'a, RegionSubscription>,
|
ReadStorage<'a, RegionSubscription>,
|
||||||
ReadStorage<'a, Presence>,
|
ReadStorage<'a, Presence>,
|
||||||
ReadStorage<'a, Collider>,
|
ReadStorage<'a, Collider>,
|
||||||
|
ReadStorage<'a, Group>,
|
||||||
WriteStorage<'a, Last<Pos>>,
|
WriteStorage<'a, Last<Pos>>,
|
||||||
WriteStorage<'a, Last<Vel>>,
|
WriteStorage<'a, Last<Vel>>,
|
||||||
WriteStorage<'a, Last<Ori>>,
|
WriteStorage<'a, Last<Ori>>,
|
||||||
@ -70,6 +72,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
subscriptions,
|
subscriptions,
|
||||||
presences,
|
presences,
|
||||||
colliders,
|
colliders,
|
||||||
|
groups,
|
||||||
mut last_pos,
|
mut last_pos,
|
||||||
mut last_vel,
|
mut last_vel,
|
||||||
mut last_ori,
|
mut last_ori,
|
||||||
@ -86,11 +89,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
) {
|
) {
|
||||||
let tick = tick.0;
|
let tick = tick.0;
|
||||||
// To send entity updates
|
// To send entity updates
|
||||||
// 1. Iterate through regions
|
// 1. Build an efficient index for group membership
|
||||||
// 2. Iterate through region subscribers (ie clients)
|
// 2. Iterate through regions
|
||||||
|
// 3. Iterate through region subscribers (ie clients)
|
||||||
// - Collect a list of entity ids for clients who are subscribed to this
|
// - Collect a list of entity ids for clients who are subscribed to this
|
||||||
// region (hash calc to check each)
|
// region (hash calc to check each)
|
||||||
// 3. Iterate through events from that region
|
// 4. Iterate through events from that region
|
||||||
// - For each entity entered event, iterate through the client list and
|
// - For each entity entered event, iterate through the client list and
|
||||||
// check if they are subscribed to the source (hash calc per subscribed
|
// 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
|
// client per entity event), if not subscribed to the source send a entity
|
||||||
@ -98,9 +102,18 @@ impl<'a> System<'a> for Sys {
|
|||||||
// - For each entity left event, iterate through the client list and check
|
// - For each entity left event, iterate through the client list and check
|
||||||
// if they are subscribed to the destination (hash calc per subscribed
|
// if they are subscribed to the destination (hash calc per subscribed
|
||||||
// client per entity event)
|
// client per entity event)
|
||||||
// 4. Iterate through entities in that region
|
// 5. Iterate through clients in that region
|
||||||
// 5. Inform clients of the component changes for that entity
|
// 6. Inform clients of component changes for group members
|
||||||
// - Throttle update rate base on distance to each client
|
// 7. Inform clients of the component changes for each entity within the region
|
||||||
|
// - Throttle update rate base on distance to each entity
|
||||||
|
|
||||||
|
// Build group index
|
||||||
|
let mut group_index: HashMap<Group, Vec<Entity>> = HashMap::new();
|
||||||
|
// Only allocate for entities with clients, to avoid adding NPC groups to the
|
||||||
|
// index
|
||||||
|
for (entity, group, _) in (&entities, &groups, &clients).join() {
|
||||||
|
group_index.entry(*group).or_default().push(entity);
|
||||||
|
}
|
||||||
|
|
||||||
// Sync physics
|
// Sync physics
|
||||||
// via iterating through regions
|
// via iterating through regions
|
||||||
@ -113,11 +126,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
presences.maybe(),
|
presences.maybe(),
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
&positions,
|
&positions,
|
||||||
|
groups.maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter_map(|(client, entity, presence, subscription, pos)| {
|
.filter_map(|(client, entity, presence, subscription, pos, group)| {
|
||||||
if presence.is_some() && subscription.regions.contains(&key) {
|
if presence.is_some() && subscription.regions.contains(&key) {
|
||||||
Some((client, &subscription.regions, entity, *pos))
|
Some((client, &subscription.regions, entity, *pos, group))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -145,7 +159,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
let create_msg = ServerGeneral::CreateEntity(pkg);
|
let create_msg = ServerGeneral::CreateEntity(pkg);
|
||||||
for (client, regions, client_entity, _) in &mut subscribers {
|
for (client, regions, client_entity, _, _) in &mut subscribers {
|
||||||
if maybe_key
|
if maybe_key
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|key| !regions.contains(key))
|
.map(|key| !regions.contains(key))
|
||||||
@ -161,7 +175,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
RegionEvent::Left(id, maybe_key) => {
|
RegionEvent::Left(id, maybe_key) => {
|
||||||
// Lookup UID for entity
|
// Lookup UID for entity
|
||||||
if let Some(&uid) = uids.get(entities.entity(*id)) {
|
if let Some(&uid) = uids.get(entities.entity(*id)) {
|
||||||
for (client, regions, _, _) in &mut subscribers {
|
for (client, regions, _, _, _) in &mut subscribers {
|
||||||
if maybe_key
|
if maybe_key
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|key| !regions.contains(key))
|
.map(|key| !regions.contains(key))
|
||||||
@ -187,7 +201,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
// We lazily initializethe the synchronization messages in case there are no
|
// We lazily initializethe the synchronization messages in case there are no
|
||||||
// clients.
|
// clients.
|
||||||
let mut entity_comp_sync = Either::Left((entity_sync_package, comp_sync_package));
|
let mut entity_comp_sync = Either::Left((entity_sync_package, comp_sync_package));
|
||||||
for (client, _, _, _) in &mut subscribers {
|
for (client, _, _, _, _) in &mut subscribers {
|
||||||
let msg =
|
let msg =
|
||||||
entity_comp_sync.right_or_else(|(entity_sync_package, comp_sync_package)| {
|
entity_comp_sync.right_or_else(|(entity_sync_package, comp_sync_package)| {
|
||||||
(
|
(
|
||||||
@ -202,21 +216,42 @@ impl<'a> System<'a> for Sys {
|
|||||||
entity_comp_sync = Either::Right(msg);
|
entity_comp_sync = Either::Right(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (client, _, client_entity, client_pos) in &mut subscribers {
|
for (client, _, client_entity, client_pos, client_group) in &mut subscribers {
|
||||||
let mut comp_sync_package = CompSyncPackage::new();
|
let mut comp_sync_package = CompSyncPackage::new();
|
||||||
|
|
||||||
for (_, entity, &uid, (&pos, last_pos), vel, ori, force_update, collider) in (
|
// Unconditionally send updates for group members, even outside the region.
|
||||||
region.entities(),
|
// Uses `get` instead of `join` to avoid O(n^2) behavior.
|
||||||
&entities,
|
if let Some(members) = client_group.and_then(|g| group_index.get(g)) {
|
||||||
&uids,
|
for entity in members.iter() {
|
||||||
(&positions, last_pos.mask().maybe()),
|
if let Some(package) = tracked_comps.create_entity_package(
|
||||||
(&velocities, last_vel.mask().maybe()).maybe(),
|
*entity,
|
||||||
(&orientations, last_vel.mask().maybe()).maybe(),
|
positions.get(*entity).copied(),
|
||||||
force_updates.mask().maybe(),
|
velocities.get(*entity).copied(),
|
||||||
colliders.maybe(),
|
orientations.get(*entity).copied(),
|
||||||
)
|
) {
|
||||||
.join()
|
client.send_fallible(ServerGeneral::CreateEntity(package));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, entity, &uid, (&pos, last_pos), vel, ori, force_update, collider, group) in
|
||||||
|
(
|
||||||
|
region.entities(),
|
||||||
|
&entities,
|
||||||
|
&uids,
|
||||||
|
(&positions, last_pos.mask().maybe()),
|
||||||
|
(&velocities, last_vel.mask().maybe()).maybe(),
|
||||||
|
(&orientations, last_vel.mask().maybe()).maybe(),
|
||||||
|
force_updates.mask().maybe(),
|
||||||
|
colliders.maybe(),
|
||||||
|
groups.maybe(),
|
||||||
|
)
|
||||||
|
.join()
|
||||||
{
|
{
|
||||||
|
// Skip sending group updates here, since we sent them in the previous loop
|
||||||
|
if client_group.is_some() && *client_group == group {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Decide how regularly to send physics updates.
|
// Decide how regularly to send physics updates.
|
||||||
let send_now = if client_entity == &entity {
|
let send_now = if client_entity == &entity {
|
||||||
let player_physics_setting = players
|
let player_physics_setting = players
|
||||||
|
Loading…
Reference in New Issue
Block a user