-
-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Description Hey, I started working on this issue #337. ### So far: - I created a crate "**valence_boss_bar**" and I moved this packet there https://github.com/valence-rs/valence/blob/2ed5a8840da244d8f1f91f1df43750664952be46/crates/valence_core/src/protocol/packet.rs#L612 - I initialized the plugin and added a system that removes the players when a boss bar is despawned. - I created/moved the boss bar components (BossBarTitle, BossBarHealth, BossBarStyle, BossBarFlags and BossBarViewers) - I added systems that handle the update of boss bar attributes and player disconnection - I documented the code - I made unit tests ### Playground I've tested the API in playground and it works fine. https://github.com/valence-rs/valence/assets/29759371/5661873b-c3a7-4a5d-b9e6-6c739bef4c2f --------- Co-authored-by: pepperoni21 <[email protected]>
- Loading branch information
1 parent
26d082c
commit 0f3e6f2
Showing
13 changed files
with
761 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,4 +23,5 @@ graph TD | |
entity --> block | ||
advancement --> client | ||
world_border --> client | ||
boss_bar --> client | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
name = "valence_boss_bar" | ||
description = "Boss bar API for Valence" | ||
readme = "README.md" | ||
keywords = ["minecraft", "bossbar", "api"] | ||
documentation.workspace = true | ||
version.workspace = true | ||
edition.workspace = true | ||
|
||
[dependencies] | ||
valence_core.workspace = true | ||
valence_network.workspace = true | ||
valence_entity.workspace = true | ||
valence_client.workspace = true | ||
uuid.workspace = true | ||
bitfield-struct.workspace = true | ||
bevy_app.workspace = true | ||
bevy_ecs.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# valence_boss_bar | ||
|
||
Manages Minecraft's boss bar which is the bar seen at the top of the screen when a boss mob is present. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use std::collections::BTreeSet; | ||
|
||
use bevy_ecs::prelude::{Bundle, Component, Entity}; | ||
use bitfield_struct::bitfield; | ||
use valence_core::protocol::{Decode, Encode}; | ||
use valence_core::text::Text; | ||
use valence_core::uuid::UniqueId; | ||
|
||
/// The bundle of components that make up a boss bar. | ||
#[derive(Bundle)] | ||
pub struct BossBarBundle { | ||
pub id: UniqueId, | ||
pub title: BossBarTitle, | ||
pub health: BossBarHealth, | ||
pub style: BossBarStyle, | ||
pub flags: BossBarFlags, | ||
pub viewers: BossBarViewers, | ||
} | ||
|
||
impl BossBarBundle { | ||
pub fn new( | ||
title: Text, | ||
color: BossBarColor, | ||
division: BossBarDivision, | ||
flags: BossBarFlags, | ||
) -> BossBarBundle { | ||
BossBarBundle { | ||
id: UniqueId::default(), | ||
title: BossBarTitle(title), | ||
health: BossBarHealth(1.0), | ||
style: BossBarStyle { color, division }, | ||
flags, | ||
viewers: BossBarViewers::default(), | ||
} | ||
} | ||
} | ||
|
||
/// The title of a boss bar. | ||
#[derive(Component, Clone)] | ||
pub struct BossBarTitle(pub Text); | ||
|
||
/// The health of a boss bar. | ||
#[derive(Component)] | ||
pub struct BossBarHealth(pub f32); | ||
|
||
/// The style of a boss bar. This includes the color and division of the boss | ||
/// bar. | ||
#[derive(Component)] | ||
pub struct BossBarStyle { | ||
pub color: BossBarColor, | ||
pub division: BossBarDivision, | ||
} | ||
|
||
/// The color of a boss bar. | ||
#[derive(Component, Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)] | ||
pub enum BossBarColor { | ||
Pink, | ||
Blue, | ||
Red, | ||
Green, | ||
Yellow, | ||
Purple, | ||
White, | ||
} | ||
|
||
/// The division of a boss bar. | ||
#[derive(Component, Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)] | ||
pub enum BossBarDivision { | ||
NoDivision, | ||
SixNotches, | ||
TenNotches, | ||
TwelveNotches, | ||
TwentyNotches, | ||
} | ||
|
||
/// The flags of a boss bar (darken sky, dragon bar, create fog). | ||
#[bitfield(u8)] | ||
#[derive(Component, PartialEq, Eq, Encode, Decode)] | ||
pub struct BossBarFlags { | ||
pub darken_sky: bool, | ||
pub dragon_bar: bool, | ||
pub create_fog: bool, | ||
#[bits(5)] | ||
_pad: u8, | ||
} | ||
|
||
/// The viewers of a boss bar. | ||
#[derive(Component, Default)] | ||
pub struct BossBarViewers { | ||
/// The current viewers of the boss bar. It is the list that should be | ||
/// updated. | ||
pub viewers: BTreeSet<Entity>, | ||
/// The viewers of the last tick in order to determine which viewers have | ||
/// been added and removed. | ||
pub(crate) old_viewers: BTreeSet<Entity>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
#![doc = include_str!("../README.md")] | ||
#![allow(clippy::type_complexity)] | ||
#![deny( | ||
rustdoc::broken_intra_doc_links, | ||
rustdoc::private_intra_doc_links, | ||
rustdoc::missing_crate_level_docs, | ||
rustdoc::invalid_codeblock_attributes, | ||
rustdoc::invalid_rust_codeblocks, | ||
rustdoc::bare_urls, | ||
rustdoc::invalid_html_tags | ||
)] | ||
#![warn( | ||
trivial_casts, | ||
trivial_numeric_casts, | ||
unused_lifetimes, | ||
unused_import_braces, | ||
unreachable_pub, | ||
clippy::dbg_macro | ||
)] | ||
|
||
use std::borrow::Cow; | ||
|
||
use bevy_app::CoreSet::PostUpdate; | ||
use bevy_app::Plugin; | ||
use bevy_ecs::prelude::Entity; | ||
use bevy_ecs::query::{Added, Changed, With}; | ||
use bevy_ecs::schedule::{IntoSystemConfig, IntoSystemConfigs}; | ||
use bevy_ecs::system::Query; | ||
use packet::{BossBarAction, BossBarS2c}; | ||
use valence_client::{Client, FlushPacketsSet}; | ||
use valence_core::despawn::Despawned; | ||
use valence_core::protocol::encode::WritePacket; | ||
use valence_core::uuid::UniqueId; | ||
|
||
mod components; | ||
pub use components::*; | ||
|
||
pub mod packet; | ||
|
||
pub struct BossBarPlugin; | ||
|
||
impl Plugin for BossBarPlugin { | ||
fn build(&self, app: &mut bevy_app::App) { | ||
app.add_systems( | ||
( | ||
boss_bar_title_update, | ||
boss_bar_health_update, | ||
boss_bar_style_update, | ||
boss_bar_flags_update, | ||
boss_bar_viewers_update, | ||
boss_bar_despawn, | ||
client_disconnection.before(boss_bar_viewers_update), | ||
) | ||
.before(FlushPacketsSet) | ||
.in_base_set(PostUpdate), | ||
); | ||
} | ||
} | ||
|
||
/// System that sends a bossbar update title packet to all viewers of a boss bar | ||
/// that has had its title updated. | ||
fn boss_bar_title_update( | ||
boss_bars: Query<(&UniqueId, &BossBarTitle, &BossBarViewers), Changed<BossBarTitle>>, | ||
mut clients: Query<&mut Client>, | ||
) { | ||
for (id, title, boss_bar_viewers) in boss_bars.iter() { | ||
for viewer in boss_bar_viewers.viewers.iter() { | ||
if let Ok(mut client) = clients.get_mut(*viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::UpdateTitle(Cow::Borrowed(&title.0)), | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// System that sends a bossbar update health packet to all viewers of a boss | ||
/// bar that has had its health updated. | ||
fn boss_bar_health_update( | ||
boss_bars: Query<(&UniqueId, &BossBarHealth, &BossBarViewers), Changed<BossBarHealth>>, | ||
mut clients: Query<&mut Client>, | ||
) { | ||
for (id, health, boss_bar_viewers) in boss_bars.iter() { | ||
for viewer in boss_bar_viewers.viewers.iter() { | ||
if let Ok(mut client) = clients.get_mut(*viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::UpdateHealth(health.0), | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// System that sends a bossbar update style packet to all viewers of a boss bar | ||
/// that has had its style updated. | ||
fn boss_bar_style_update( | ||
boss_bars: Query<(&UniqueId, &BossBarStyle, &BossBarViewers), Changed<BossBarStyle>>, | ||
mut clients: Query<&mut Client>, | ||
) { | ||
for (id, style, boss_bar_viewers) in boss_bars.iter() { | ||
for viewer in boss_bar_viewers.viewers.iter() { | ||
if let Ok(mut client) = clients.get_mut(*viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::UpdateStyle(style.color, style.division), | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// System that sends a bossbar update flags packet to all viewers of a boss bar | ||
/// that has had its flags updated. | ||
fn boss_bar_flags_update( | ||
boss_bars: Query<(&UniqueId, &BossBarFlags, &BossBarViewers), Changed<BossBarFlags>>, | ||
mut clients: Query<&mut Client>, | ||
) { | ||
for (id, flags, boss_bar_viewers) in boss_bars.iter() { | ||
for viewer in boss_bar_viewers.viewers.iter() { | ||
if let Ok(mut client) = clients.get_mut(*viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::UpdateFlags(*flags), | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// System that sends a bossbar add/remove packet to all viewers of a boss bar | ||
/// that just have been added/removed. | ||
fn boss_bar_viewers_update( | ||
mut boss_bars: Query< | ||
( | ||
&UniqueId, | ||
&BossBarTitle, | ||
&BossBarHealth, | ||
&BossBarStyle, | ||
&BossBarFlags, | ||
&mut BossBarViewers, | ||
), | ||
Changed<BossBarViewers>, | ||
>, | ||
mut clients: Query<&mut Client>, | ||
) { | ||
for (id, title, health, style, flags, mut boss_bar_viewers) in boss_bars.iter_mut() { | ||
let old_viewers = &boss_bar_viewers.old_viewers; | ||
let current_viewers = &boss_bar_viewers.viewers; | ||
|
||
for &added_viewer in current_viewers.difference(old_viewers) { | ||
if let Ok(mut client) = clients.get_mut(added_viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::Add { | ||
title: Cow::Borrowed(&title.0), | ||
health: health.0, | ||
color: style.color, | ||
division: style.division, | ||
flags: *flags, | ||
}, | ||
}); | ||
} | ||
} | ||
|
||
for &removed_viewer in old_viewers.difference(current_viewers) { | ||
if let Ok(mut client) = clients.get_mut(removed_viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::Remove, | ||
}); | ||
} | ||
} | ||
|
||
boss_bar_viewers.old_viewers = boss_bar_viewers.viewers.clone(); | ||
} | ||
} | ||
|
||
/// System that sends a bossbar remove packet to all viewers of a boss bar that | ||
/// has been despawned. | ||
fn boss_bar_despawn( | ||
mut boss_bars: Query<(&UniqueId, &BossBarViewers), Added<Despawned>>, | ||
mut clients: Query<&mut Client>, | ||
) { | ||
for (id, viewers) in boss_bars.iter_mut() { | ||
for viewer in viewers.viewers.iter() { | ||
if let Ok(mut client) = clients.get_mut(*viewer) { | ||
client.write_packet(&BossBarS2c { | ||
id: id.0, | ||
action: BossBarAction::Remove, | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// System that removes a client from the viewers of its boss bars when it | ||
/// disconnects. | ||
fn client_disconnection( | ||
disconnected_clients: Query<Entity, (With<Client>, Added<Despawned>)>, | ||
mut boss_bars_viewers: Query<&mut BossBarViewers>, | ||
) { | ||
for entity in disconnected_clients.iter() { | ||
for mut boss_bar_viewers in boss_bars_viewers.iter_mut() { | ||
boss_bar_viewers.viewers.remove(&entity); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use std::borrow::Cow; | ||
|
||
use uuid::Uuid; | ||
use valence_core::protocol::{packet_id, Decode, Encode, Packet}; | ||
use valence_core::text::Text; | ||
|
||
use crate::components::{BossBarColor, BossBarDivision, BossBarFlags}; | ||
|
||
#[derive(Clone, Debug, Encode, Decode, Packet)] | ||
#[packet(id = packet_id::BOSS_BAR_S2C)] | ||
pub struct BossBarS2c<'a> { | ||
pub id: Uuid, | ||
pub action: BossBarAction<'a>, | ||
} | ||
|
||
#[derive(Clone, PartialEq, Debug, Encode, Decode)] | ||
pub enum BossBarAction<'a> { | ||
Add { | ||
title: Cow<'a, Text>, | ||
health: f32, | ||
color: BossBarColor, | ||
division: BossBarDivision, | ||
flags: BossBarFlags, | ||
}, | ||
Remove, | ||
UpdateHealth(f32), | ||
UpdateTitle(Cow<'a, Text>), | ||
UpdateStyle(BossBarColor, BossBarDivision), | ||
UpdateFlags(BossBarFlags), | ||
} |
Oops, something went wrong.