Skip to content

Commit 6da2c3e

Browse files
committed
Accept client entity in is_visible
Useful to express filters like `Owner`.
1 parent 82f745c commit 6da2c3e

8 files changed

Lines changed: 104 additions & 30 deletions

File tree

CHANGELOG.md

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

1717
### Changed
1818

19-
- In `VisibilityFilter::is_visible` the second argument is now wrapped in an `Option`, and the arguments have been swapped: `self` is now the entity component, and the client component is the second argument.
20-
- `VisibilityFilter` now has a `ClientComponent` associated type, which allows using a different component for client entities. Set it to `Self` to preserve the old behavior.
19+
- `VisibilityFilter` now allows expressing more complex rules:
20+
- A new `ClientComponent` associated type allows specifying a different component for client entities. Use `Self` to preserve the previous behavior.
21+
- In `is_visible`, `self` now refers to the entity component, and the client component is passed into the function.
22+
- The passed component is now wrapped in an `Option` to allow customizing behavior when the component on the client is missing.
23+
- `is_visible` now accepts the client entity.
2124
- `AuthorizedClient` and `ConnectedClient` now immutable.
2225
- `ClientStats` now represents only current client statistics. Use the `ConnectedClientStats` component for connected client statistics on the server.
2326
- `ConditionerConfig` now represents configuration only for a connected client on the server. Use the `GlobalConditionerConfig` resource for global server or client configuration.

example_backend/examples/authoritative_rts.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,11 @@ impl VisibilityFilter for Team {
750750
type ClientComponent = Self;
751751
type Scope = SingleComponent<Command>;
752752

753-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
753+
fn is_visible(
754+
&self,
755+
_client: Entity,
756+
client_component: Option<&Self::ClientComponent>,
757+
) -> bool {
754758
client_component.is_some_and(|c| self == c)
755759
}
756760
}

src/server/visibility.rs

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub trait AppVisibilityExt {
8080
type ClientComponent = Self;
8181
type Scope = Entity;
8282
83-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
83+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
8484
client_component.is_some_and(|c| self == c)
8585
}
8686
}
@@ -116,7 +116,7 @@ fn update_for_new_clients<F: VisibilityFilter>(
116116
if let Ok(mut visibility) = clients.get_mut(insert.entity) {
117117
let bit = registry.bit::<F>();
118118
for (entity, component) in &entities {
119-
let visible = component.is_visible(None);
119+
let visible = component.is_visible(insert.entity, None);
120120
debug!(
121121
"evaluating missing `{}` for new client `{}` for entity `{entity}` to `{visible}`",
122122
ShortName::of::<F>(),
@@ -136,7 +136,7 @@ fn on_insert<F: VisibilityFilter>(
136136
let bit = registry.bit::<F>();
137137
if let Ok((client, client_component, mut visibility)) = clients.get_mut(insert.entity) {
138138
for (entity, component) in &entities {
139-
let visible = component.is_visible(client_component);
139+
let visible = component.is_visible(client, client_component);
140140
debug!(
141141
"evaluating inserted `{}` to client `{client}` for entity `{entity}` to `{visible}`",
142142
ShortName::of::<F>(),
@@ -146,7 +146,7 @@ fn on_insert<F: VisibilityFilter>(
146146
} else {
147147
let (entity, component) = entities.get(insert.entity).unwrap();
148148
for (client, client_component, mut visibility) in &mut clients {
149-
let visible = component.is_visible(client_component);
149+
let visible = component.is_visible(client, client_component);
150150
debug!(
151151
"evaluating inserted `{}` to entity `{entity}` for client `{client}` to `{visible}`",
152152
ShortName::of::<F>(),
@@ -190,7 +190,7 @@ fn on_client_remove<F: VisibilityFilter>(
190190

191191
let bit = registry.bit::<F>();
192192
for (entity, component) in &entities {
193-
let visible = component.is_visible(None);
193+
let visible = component.is_visible(remove.entity, None);
194194
debug!(
195195
"evaluating removed `{}` from client `{}` for entity `{entity}` to `{visible}`",
196196
ShortName::of::<F>(),
@@ -226,7 +226,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
226226
type ClientComponent = Moderator;
227227
type Scope = Entity;
228228
229-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
229+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
230230
// Only moderators can see entities with sensitive information.
231231
client_component.is_some()
232232
}
@@ -246,7 +246,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
246246
type ClientComponent = Self;
247247
type Scope = Entity;
248248
249-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
249+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
250250
// Visible only if the client also has `SpectatorOnly`.
251251
client_component.is_some()
252252
}
@@ -276,7 +276,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
276276
/// type ClientComponent = Self;
277277
/// type Scope = Entity;
278278
///
279-
/// fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
279+
/// fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
280280
/// client_component.is_some_and(|c| self == c)
281281
/// }
282282
/// }
@@ -295,7 +295,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
295295
/// type ClientComponent = Self;
296296
/// type Scope = SingleComponent<Health>;
297297
///
298-
/// fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
298+
/// fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
299299
/// client_component.is_some_and(|c| self == c)
300300
/// }
301301
/// }
@@ -317,7 +317,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
317317
/// type ClientComponent = Self;
318318
/// type Scope = (Health, Stats);
319319
///
320-
/// fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
320+
/// fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
321321
/// client_component.is_some_and(|c| self == c)
322322
/// }
323323
/// }
@@ -352,7 +352,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
352352
type ClientComponent = Self;
353353
type Scope = Entity;
354354
355-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
355+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
356356
client_component.is_some()
357357
}
358358
}
@@ -375,7 +375,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
375375
type ClientComponent = Unit;
376376
type Scope = Entity;
377377
378-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
378+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
379379
// Blind clients cannot see units.
380380
client_component.is_none()
381381
}
@@ -395,7 +395,7 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
395395
type ClientComponent = Self;
396396
type Scope = Entity;
397397
398-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
398+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
399399
// Visible if the client belongs to the same team.
400400
client_component.is_some_and(|c| self == c)
401401
}
@@ -424,13 +424,32 @@ pub trait VisibilityFilter: Component<Mutability = Immutable> {
424424
type ClientComponent = Self;
425425
type Scope = Entity;
426426
427-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
427+
fn is_visible(&self, _client: Entity, client_component: Option<&Self::ClientComponent>) -> bool {
428428
client_component.is_some_and(|&c| self.contains(c))
429429
}
430430
}
431431
```
432+
433+
Visible if the component references the client entity:
434+
435+
```
436+
# use bevy::prelude::*;
437+
# use bevy_replicon::prelude::*;
438+
#[derive(Component, PartialEq)]
439+
#[component(immutable)]
440+
struct Owner(Entity);
441+
442+
impl VisibilityFilter for Owner {
443+
type ClientComponent = AuthorizedClient; // All clients authorized for replication have this component.
444+
type Scope = Entity;
445+
446+
fn is_visible(&self, client: Entity, _client_component: Option<&Self::ClientComponent>) -> bool {
447+
self.0 == client
448+
}
449+
}
450+
```
432451
*/
433-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool;
452+
fn is_visible(&self, client: Entity, client_component: Option<&Self::ClientComponent>) -> bool;
434453
}
435454

436455
/// Associates the type with a visibility scope.
@@ -642,7 +661,11 @@ mod tests {
642661
type ClientComponent = Self;
643662
type Scope = Entity;
644663

645-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
664+
fn is_visible(
665+
&self,
666+
_client: Entity,
667+
client_component: Option<&Self::ClientComponent>,
668+
) -> bool {
646669
client_component.is_some()
647670
}
648671
}
@@ -655,7 +678,11 @@ mod tests {
655678
type ClientComponent = ClientFilter;
656679
type Scope = Entity;
657680

658-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
681+
fn is_visible(
682+
&self,
683+
_client: Entity,
684+
client_component: Option<&Self::ClientComponent>,
685+
) -> bool {
659686
client_component.is_some()
660687
}
661688
}

src/server/visibility/registry.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,11 @@ mod tests {
223223
type ClientComponent = Self;
224224
type Scope = Entity;
225225

226-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
226+
fn is_visible(
227+
&self,
228+
_client: Entity,
229+
client_component: Option<&Self::ClientComponent>,
230+
) -> bool {
227231
client_component.is_some()
228232
}
229233
}
@@ -236,7 +240,11 @@ mod tests {
236240
type ClientComponent = Self;
237241
type Scope = SingleComponent<A>;
238242

239-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
243+
fn is_visible(
244+
&self,
245+
_client: Entity,
246+
client_component: Option<&Self::ClientComponent>,
247+
) -> bool {
240248
client_component.is_some()
241249
}
242250
}
@@ -249,7 +257,11 @@ mod tests {
249257
type ClientComponent = Self;
250258
type Scope = (A, B);
251259

252-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
260+
fn is_visible(
261+
&self,
262+
_client: Entity,
263+
client_component: Option<&Self::ClientComponent>,
264+
) -> bool {
253265
client_component.is_some()
254266
}
255267
}

tests/despawn.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,11 @@ impl VisibilityFilter for EntityVisibility {
328328
type ClientComponent = Self;
329329
type Scope = Entity;
330330

331-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
331+
fn is_visible(
332+
&self,
333+
_client: Entity,
334+
client_component: Option<&Self::ClientComponent>,
335+
) -> bool {
332336
client_component.is_some()
333337
}
334338
}
@@ -341,7 +345,11 @@ impl VisibilityFilter for ComponentVisibility {
341345
type ClientComponent = Self;
342346
type Scope = SingleComponent<TestComponent>;
343347

344-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
348+
fn is_visible(
349+
&self,
350+
_client: Entity,
351+
client_component: Option<&Self::ClientComponent>,
352+
) -> bool {
345353
client_component.is_some()
346354
}
347355
}

tests/insertion.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,11 @@ impl VisibilityFilter for EntityVisibility {
802802
type ClientComponent = Self;
803803
type Scope = Entity;
804804

805-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
805+
fn is_visible(
806+
&self,
807+
_client: Entity,
808+
client_component: Option<&Self::ClientComponent>,
809+
) -> bool {
806810
client_component.is_some()
807811
}
808812
}
@@ -815,7 +819,11 @@ impl VisibilityFilter for ComponentVisibility {
815819
type ClientComponent = Self;
816820
type Scope = SingleComponent<A>;
817821

818-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
822+
fn is_visible(
823+
&self,
824+
_client: Entity,
825+
client_component: Option<&Self::ClientComponent>,
826+
) -> bool {
819827
client_component.is_some()
820828
}
821829
}

tests/removal.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,11 @@ impl VisibilityFilter for EntityVisibility {
640640
type ClientComponent = Self;
641641
type Scope = Entity;
642642

643-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
643+
fn is_visible(
644+
&self,
645+
_client: Entity,
646+
client_component: Option<&Self::ClientComponent>,
647+
) -> bool {
644648
client_component.is_some()
645649
}
646650
}
@@ -653,7 +657,11 @@ impl VisibilityFilter for ComponentVisibility {
653657
type ClientComponent = Self;
654658
type Scope = SingleComponent<A>;
655659

656-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
660+
fn is_visible(
661+
&self,
662+
_client: Entity,
663+
client_component: Option<&Self::ClientComponent>,
664+
) -> bool {
657665
client_component.is_some()
658666
}
659667
}

tests/spawn.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,11 @@ impl VisibilityFilter for EntityVisibility {
583583
type ClientComponent = Self;
584584
type Scope = Entity;
585585

586-
fn is_visible(&self, client_component: Option<&Self::ClientComponent>) -> bool {
586+
fn is_visible(
587+
&self,
588+
_client: Entity,
589+
client_component: Option<&Self::ClientComponent>,
590+
) -> bool {
587591
client_component.is_some()
588592
}
589593
}

0 commit comments

Comments
 (0)