Skip to content

Commit 604d3af

Browse files
malfuuShatur
andcommitted
Fix ClientComponent insertion not changing visibility (#678)
Co-authored-by: Hennadii Chernyshchyk <genaloner@gmail.com>
1 parent d430d58 commit 604d3af

2 files changed

Lines changed: 71 additions & 20 deletions

File tree

CHANGELOG.md

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

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- Visibility is now properly updated when `VisibilityFilter` and `VisibilityFilter::ClientComponent` are not the same type.
13+
1014
## [0.39.2] - 2026-04-01
1115

1216
### Fixed

src/server/visibility.rs

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ impl AppVisibilityExt for App {
104104

105105
self.add_observer(update_for_new_clients::<F>)
106106
.add_observer(on_insert::<F>)
107+
.add_observer(on_client_insert::<F>)
107108
.add_observer(on_remove::<F>)
108109
.add_observer(on_client_remove::<F>)
109110
}
@@ -135,26 +136,43 @@ fn on_insert<F: VisibilityFilter>(
135136
entities: Query<(Entity, &F), (Without<ClientVisibility>, Allow<Disabled>)>,
136137
mut clients: Query<(Entity, Option<&F::ClientComponent>, &mut ClientVisibility)>,
137138
) {
139+
// `F` and `F::ClientComponent` could be the same,
140+
// so we need to ensure that it was not inserted into a client
141+
if clients.contains(insert.entity) {
142+
return;
143+
}
144+
138145
let bit = registry.bit::<F>();
139-
if let Ok((client, client_component, mut visibility)) = clients.get_mut(insert.entity) {
140-
for (entity, component) in &entities {
141-
let visible = component.is_visible(client, client_component);
142-
debug!(
143-
"evaluating inserted `{}` to client `{client}` for entity `{entity}` to `{visible}`",
144-
ShortName::of::<F>(),
145-
);
146-
visibility.set(entity, bit, visible);
147-
}
148-
} else {
149-
let (entity, component) = entities.get(insert.entity).unwrap();
150-
for (client, client_component, mut visibility) in &mut clients {
151-
let visible = component.is_visible(client, client_component);
152-
debug!(
153-
"evaluating inserted `{}` to entity `{entity}` for client `{client}` to `{visible}`",
154-
ShortName::of::<F>(),
155-
);
156-
visibility.set(insert.entity, bit, visible);
157-
}
146+
let (entity, component) = entities.get(insert.entity).unwrap();
147+
for (client, client_component, mut visibility) in &mut clients {
148+
let visible = component.is_visible(client, client_component);
149+
debug!(
150+
"evaluating inserted `{}` to entity `{entity}` for client `{client}` to `{visible}`",
151+
ShortName::of::<F>(),
152+
);
153+
visibility.set(insert.entity, bit, visible);
154+
}
155+
}
156+
157+
fn on_client_insert<F: VisibilityFilter>(
158+
insert: On<Insert, F::ClientComponent>,
159+
registry: Res<FilterRegistry>,
160+
mut clients: Query<(&F::ClientComponent, &mut ClientVisibility)>,
161+
entities: Query<(Entity, &F), Without<ClientVisibility>>,
162+
) {
163+
let Ok((client_component, mut visibility)) = clients.get_mut(insert.entity) else {
164+
return;
165+
};
166+
167+
let bit = registry.bit::<F>();
168+
for (entity, component) in &entities {
169+
let visible = component.is_visible(insert.entity, Some(client_component));
170+
debug!(
171+
"evaluating inserted `{}` to client `{}` for entity `{entity}` to `{visible}`",
172+
ShortName::of::<F>(),
173+
insert.entity
174+
);
175+
visibility.set(entity, bit, visible);
158176
}
159177
}
160178

@@ -165,7 +183,7 @@ fn on_remove<F: VisibilityFilter>(
165183
) {
166184
// `F` and `F::ClientComponent` could be the same,
167185
// so we need to ensure that it wasn't removed from a client.
168-
if clients.get(remove.entity).is_ok() {
186+
if clients.contains(remove.entity) {
169187
return;
170188
}
171189

@@ -566,6 +584,35 @@ mod tests {
566584
assert!(visibility2.get(entity2).is_hidden(registry));
567585
}
568586

587+
#[test]
588+
fn insert_filter_on_client() {
589+
let mut app = App::new();
590+
app.init_resource::<FilterRegistry>()
591+
.init_resource::<ReplicationRegistry>()
592+
.add_visibility_filter::<SelfFilter>()
593+
.add_visibility_filter::<EntityFilter>();
594+
595+
let entity1 = app.world_mut().spawn(SelfFilter).id();
596+
let entity2 = app.world_mut().spawn(EntityFilter).id();
597+
598+
let client = app.world_mut().spawn(ClientVisibility::default()).id();
599+
600+
let registry = app.world().resource::<FilterRegistry>();
601+
let visibility = app.world().get::<ClientVisibility>(client).unwrap();
602+
603+
assert!(visibility.get(entity1).is_hidden(registry));
604+
assert!(visibility.get(entity2).is_hidden(registry));
605+
606+
app.world_mut()
607+
.entity_mut(client)
608+
.insert((SelfFilter, ClientFilter));
609+
610+
let registry = app.world().resource::<FilterRegistry>();
611+
let visibility = app.world().get::<ClientVisibility>(client).unwrap();
612+
assert!(!visibility.get(entity1).is_hidden(registry));
613+
assert!(!visibility.get(entity2).is_hidden(registry));
614+
}
615+
569616
#[test]
570617
fn remove_filter_from_entity() {
571618
let mut app = App::new();

0 commit comments

Comments
 (0)