Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix player abilities api #517

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions crates/valence_server/src/abilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@

/// Order of execution:
/// 1. `update_game_mode`: Watch [`GameMode`] changes => Send
/// `GameStateChangeS2c` to update the client's gamemode
/// [`GameStateChangeS2c`] to update the client's gamemode

Check failure on line 50 in crates/valence_server/src/abilities.rs

View workflow job for this annotation

GitHub Actions / valence-docs

unresolved link to `GameStateChangeS2c`
///
/// 2. `update_client_player_abilities`: Watch [`PlayerAbilitiesFlags`],
/// - `sync_player_abilities`: Watch
/// [`GameMode`] changes => Update [`PlayerAbilitiesFlags`] according to the
/// [`GameMode`] if there is no change in [`PlayerAbilitiesFlags`]
///
/// - `send_player_abilities`: Watch [`PlayerAbilitiesFlags`],
/// [`FlyingSpeed`] and [`FovModifier`] changes => Send [`PlayerAbilitiesS2c`]
/// to update the client's abilities
///
/// 3. `update_player_abilities`: Watch
/// [`GameMode`] changes => Update [`PlayerAbilitiesFlags`] according to the
/// [`GameMode`]
///
/// 4. `update_server_player_abilities`: Watch
/// - `update_flying_state`: Watch
/// [`UpdatePlayerAbilitiesC2s`] packets => Update [`PlayerAbilitiesFlags`]
/// according to the packet
pub struct AbilitiesPlugin;
Expand All @@ -68,18 +68,15 @@
.add_event::<PlayerStopFlyingEvent>()
.add_systems(
PostUpdate,
(
update_client_player_abilities,
update_player_abilities.before(update_client_player_abilities),
)
(sync_player_abilities, send_player_abilities)
.in_set(UpdateClientsSet)
.after(update_game_mode),
)
.add_systems(EventLoopPreUpdate, update_server_player_abilities);
.add_systems(EventLoopPreUpdate, update_flying_state);
}
}

fn update_client_player_abilities(
fn send_player_abilities(
mut clients_query: Query<
(
&mut Client,
Expand All @@ -103,14 +100,22 @@
}
}

/// Sync [`PlayerAbilitiesFlags`] based on [`GameMode`]
///
/// /!\ This system does not trigger change detection on
/// [`PlayerAbilitiesFlags`]
fn update_player_abilities(
fn sync_player_abilities(
mut player_start_flying_event_writer: EventWriter<PlayerStartFlyingEvent>,
mut player_stop_flying_event_writer: EventWriter<PlayerStopFlyingEvent>,
mut client_query: Query<(Entity, &mut PlayerAbilitiesFlags, &GameMode), Changed<GameMode>>,
mut client_query: Query<
(Entity, &mut PlayerAbilitiesFlags, &GameMode, Added<Client>),
Changed<GameMode>,
>,
) {
for (entity, mut mut_flags, gamemode) in client_query.iter_mut() {
for (entity, mut mut_flags, gamemode, new_client) in client_query.iter_mut() {
if mut_flags.is_changed() && !new_client {
continue;
}
let flags = mut_flags.bypass_change_detection();
match gamemode {
GameMode::Creative => {
Expand Down Expand Up @@ -145,7 +150,7 @@

/// /!\ This system does not trigger change detection on
/// [`PlayerAbilitiesFlags`]
fn update_server_player_abilities(
fn update_flying_state(
mut packet_events: EventReader<PacketEvent>,
mut player_start_flying_event_writer: EventWriter<PlayerStartFlyingEvent>,
mut player_stop_flying_event_writer: EventWriter<PlayerStopFlyingEvent>,
Expand Down
29 changes: 28 additions & 1 deletion examples/cow_sphere.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use valence::math::{DQuat, EulerRot};
use valence::message::SendMessage;
use valence::prelude::*;
use valence_server::abilities::PlayerAbilitiesFlags;
use valence_text::color::NamedColor;

type SpherePartBundle = valence::entity::cow::CowEntityBundle;
Expand Down Expand Up @@ -33,6 +34,7 @@
update_sphere,
despawn_disconnected_clients,
display_is_flying,
keep_flying_state,
),
)
.run();
Expand Down Expand Up @@ -99,6 +101,7 @@
SPAWN_POS.z as f64 + 0.5,
]);
*game_mode = GameMode::Creative;
// You can't change abilities here more than the one from the gamemode.
}
}

Expand Down Expand Up @@ -147,10 +150,34 @@
}

fn lerp(a: f64, b: f64, t: f64) -> f64 {
a * (1.0 - t) + b * t

Check warning on line 153 in examples/cow_sphere.rs

View workflow job for this annotation

GitHub Actions / valence-fmt

Diff in /home/runner/work/valence/valence/examples/cow_sphere.rs
}

// Send an actionbar message to all clients when their flying state changes.
/// Demonstrate that is it possible to change the gamemode of a client and keeping abilities.
fn keep_flying_state(
mut sneak_events: EventReader<SneakEvent>,
mut clients: Query<(&mut GameMode, &mut PlayerAbilitiesFlags)>,
) {
for sneak_event in sneak_events.iter() {
if let Ok((mut gamemode, mut abilities)) = clients.get_mut(sneak_event.client) {
if sneak_event.state == SneakState::Stop {
match *gamemode {
GameMode::Creative => {
*gamemode = GameMode::Survival;
abilities.set_allow_flying(true);
abilities.set_flying(true);
}
GameMode::Survival => {
*gamemode = GameMode::Creative;
}
_ => {}
}
}
}
}
}

/// Send an actionbar message to all clients when their flying state changes.
fn display_is_flying(
mut player_start_flying_events: EventReader<PlayerStartFlyingEvent>,
mut player_stop_flying_events: EventReader<PlayerStopFlyingEvent>,
Expand Down
67 changes: 67 additions & 0 deletions website/book/2-common-components/abilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Player Abilities

> Relevant example : [cow_sphere](https://github.com/valence-rs/valence/blob/main/examples/cow_sphere.rs)
> API : [valence::server::abilities](https://valence.rs/rustdoc/valence/abilities/index.html)

---

Player abilities are a set of flags and values that determine some of the client's capabilities and states.

## Components

We have 3 components in this module:

- `PlayerAbilitiesFlags` : A set of flags that determine what a client can do.
- `FovModifier` : A value that determines the client's field of view.
- `FlyingSpeed` : A value that determines the client's flying speed.

### PlayerAbilitiesFlags

Set of 4 flags :

- `invulnerable` : If the player is invulnerable.
- `flying` : If the player is flying.
- `allow_flying` : If the client can toggle flying.
- `instant_break` : If the client can break blocks instantly.

**Note** : Changing the `GameMode` of the client will change some of his abilities, without triggering change detection.
You can bypass them by updating the `PlayerAbilitiesFlags` component at the same time. (Exept at the init of the `Client`)

Check warning on line 28 in website/book/2-common-components/abilities.md

View workflow job for this annotation

GitHub Actions / typos

"Exept" should be "Except" or "Exempt".

<details>
<summary>Example</summary>

```rust
use valence::server::abilities::PlayerAbilitiesFlags;

fn keep_flying_state(
mut sneak_events: EventReader<SneakEvent>,
mut clients: Query<(&mut GameMode, &mut PlayerAbilitiesFlags)>,
) {
for sneak_event in sneak_events.iter() {
if let Ok((mut gamemode, mut abilities)) = clients.get_mut(sneak_event.client) {
if sneak_event.state == SneakState::Stop {
match *gamemode {
GameMode::Creative => {
*gamemode = GameMode::Survival;
abilities.set_allow_flying(true);
abilities.set_flying(true);
}
GameMode::Survival => {
*gamemode = GameMode::Creative;
}
_ => {}
}
}
}
}
}
```

</details>

## Events

We have 2 events in this module:

- `PlayerStartFlyingEvent` : Triggered when the client starts flying.
- `PlayerStopFlyingEvent` : Triggered when the client stops flying.
4 changes: 4 additions & 0 deletions website/book/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@

# Developer Guide

## Common Components

- [Player Abilities](2-common-components/abilities.md)

Loading