Skip to content

Commit b9ada94

Browse files
committed
Fix replication with visibility policy != VisibilityPolicy::All
Visibility was coupled with a check if a client was just connected. This resulted in a passed test that checks replication of previously spawned entities (it was running with `VisibilityPolicy::All`). But for all other policies the logic was incorrect and led to a crash with "entity should be present after adding component". I decoupled the logic. We now determine if the entity is new to a client by checking if it has a tick. I thinking that we need to rename "change limit" into "init tick" because we use this terminology on client. But it will be a breaking change, so I will leave it for the next release.
1 parent e128056 commit b9ada94

File tree

4 files changed

+23
-34
lines changed

4 files changed

+23
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
## [0.25.1] - 2024-05-16
1111

12+
- Fix replicating previously spawned entities to a newly connected client with visibility policy different from `VisibilityPolicy::All`.
13+
1214
### Fixed
1315

1416
- Fix possible overflow in `Confirmed::contains_any`.

src/server.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -368,21 +368,12 @@ fn collect_changes(
368368
continue;
369369
}
370370

371-
let new_entity = marker_added || visibility == Visibility::Gained;
372-
if new_entity || ticks.is_added(change_tick.last_run(), change_tick.this_run())
371+
if let Some(tick) = client
372+
.get_change_limit(entity.id())
373+
.filter(|_| !marker_added)
374+
.filter(|_| visibility != Visibility::Gained)
375+
.filter(|_| !ticks.is_added(change_tick.last_run(), change_tick.this_run()))
373376
{
374-
init_message.write_component(
375-
&mut shared_bytes,
376-
rule_fns,
377-
component_fns,
378-
&ctx,
379-
replicated_component.fns_id,
380-
component,
381-
)?;
382-
} else {
383-
let tick = client
384-
.get_change_limit(entity.id())
385-
.expect("entity should be present after adding component");
386377
if ticks.is_changed(tick, change_tick.this_run()) {
387378
update_message.write_component(
388379
&mut shared_bytes,
@@ -393,6 +384,15 @@ fn collect_changes(
393384
component,
394385
)?;
395386
}
387+
} else {
388+
init_message.write_component(
389+
&mut shared_bytes,
390+
rule_fns,
391+
component_fns,
392+
&ctx,
393+
replicated_component.fns_id,
394+
component,
395+
)?;
396396
}
397397
}
398398
}

src/server/connected_clients/client_visibility.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ impl ClientVisibility {
2020
/// Creates a new instance based on the preconfigured policy.
2121
pub(super) fn new(policy: VisibilityPolicy) -> Self {
2222
match policy {
23-
VisibilityPolicy::All => Self::with_filter(VisibilityFilter::All {
24-
just_connected: true,
25-
}),
23+
VisibilityPolicy::All => Self::with_filter(VisibilityFilter::All),
2624
VisibilityPolicy::Blacklist => Self::with_filter(VisibilityFilter::Blacklist {
2725
list: Default::default(),
2826
added: Default::default(),
@@ -49,7 +47,7 @@ impl ClientVisibility {
4947
/// `cached_visibility` remains untouched.
5048
pub(super) fn clear(&mut self) {
5149
match &mut self.filter {
52-
VisibilityFilter::All { just_connected } => *just_connected = true,
50+
VisibilityFilter::All => (),
5351
VisibilityFilter::Blacklist {
5452
list,
5553
added,
@@ -76,7 +74,7 @@ impl ClientVisibility {
7674
/// Should be called after each tick.
7775
pub(crate) fn update(&mut self) {
7876
match &mut self.filter {
79-
VisibilityFilter::All { just_connected } => *just_connected = false,
77+
VisibilityFilter::All => (),
8078
VisibilityFilter::Blacklist {
8179
list,
8280
added,
@@ -250,13 +248,7 @@ impl ClientVisibility {
250248
/// Returns visibility of a specific entity.
251249
fn get_visibility_state(&self, entity: Entity) -> Visibility {
252250
match &self.filter {
253-
VisibilityFilter::All { just_connected } => {
254-
if *just_connected {
255-
Visibility::Gained
256-
} else {
257-
Visibility::Visible
258-
}
259-
}
251+
VisibilityFilter::All => Visibility::Visible,
260252
VisibilityFilter::Blacklist { list, .. } => match list.get(&entity) {
261253
Some(BlacklistInfo::QueuedForRemoval) => Visibility::Gained,
262254
Some(BlacklistInfo::Hidden) => Visibility::Hidden,
@@ -273,12 +265,7 @@ impl ClientVisibility {
273265

274266
/// Filter for [`ClientVisibility`] based on [`VisibilityPolicy`].
275267
enum VisibilityFilter {
276-
All {
277-
/// Indicates that the client has just connected to the server.
278-
///
279-
/// If true, then visibility of all entities has been gained.
280-
just_connected: bool,
281-
},
268+
All,
282269
Blacklist {
283270
/// All blacklisted entities and an indicator of whether they are in the queue for deletion
284271
/// at the end of this tick.

tests/visibility.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn blacklist() {
131131
}
132132

133133
#[test]
134-
fn blacklist_despawn() {
134+
fn blacklist_with_despawn() {
135135
let mut server_app = App::new();
136136
let mut client_app = App::new();
137137
for app in [&mut server_app, &mut client_app] {
@@ -250,7 +250,7 @@ fn whitelist() {
250250
}
251251

252252
#[test]
253-
fn whitelist_despawn() {
253+
fn whitelist_with_despawn() {
254254
let mut server_app = App::new();
255255
let mut client_app = App::new();
256256
for app in [&mut server_app, &mut client_app] {

0 commit comments

Comments
 (0)