chunkedge_scoreboard/
components.rs1use std::collections::HashMap;
2
3use bevy_ecs::prelude::*;
4use chunkedge_server::Text;
5use chunkedge_server::entity::EntityLayerId;
6use chunkedge_server::protocol::packets::play::set_display_objective_s2c::ScoreboardPosition;
7use chunkedge_server::protocol::packets::play::set_objective_s2c::{
8 NumberFormat, ObjectiveRenderType,
9};
10use chunkedge_server::text::IntoText;
11use derive_more::{Deref, DerefMut};
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash, Component, Deref)]
19pub struct Objective(pub(crate) String);
20
21impl Objective {
22 pub fn new<N: Into<String>>(name: N) -> Self {
23 let name = name.into();
24 debug_assert!(
25 name.len() <= 16,
26 "Objective name {} is too long ({} > 16)",
27 name,
28 name.len()
29 );
30 Self(name)
31 }
32
33 pub fn name(&self) -> &str {
34 &self.0
35 }
36}
37
38#[derive(Debug, Clone, PartialEq, Component, Deref, DerefMut)]
41pub struct ObjectiveDisplay(pub Text);
42
43#[derive(Component, Clone, PartialEq, Debug, Default)]
45pub struct ObjectiveNumberFormat(pub Option<NumberFormat<'static>>);
46
47#[derive(Debug, Clone, Component, Default)]
49pub struct ObjectiveScores(pub(crate) HashMap<String, i32>);
50
51impl ObjectiveScores {
52 pub fn new() -> Self {
53 Default::default()
54 }
55
56 pub fn with_map<M: Into<HashMap<String, i32>>>(map: M) -> Self {
57 Self(map.into())
58 }
59
60 pub fn get(&self, key: &str) -> Option<&i32> {
61 self.0.get(key)
62 }
63
64 pub fn get_mut(&mut self, key: &str) -> Option<&mut i32> {
65 self.0.get_mut(key)
66 }
67
68 pub fn insert<K: Into<String>>(&mut self, key: K, value: i32) -> Option<i32> {
69 self.0.insert(key.into(), value)
70 }
71}
72
73#[derive(Debug, Clone, Default, PartialEq, Component)]
74pub struct OldObjectiveScores(pub(crate) HashMap<String, i32>);
75
76impl OldObjectiveScores {
77 pub fn diff<'a>(&'a self, scores: &'a ObjectiveScores) -> Vec<&'a str> {
78 let mut diff = Vec::new();
79
80 for (key, value) in &self.0 {
81 if scores.0.get(key) != Some(value) {
82 diff.push(key.as_str());
83 }
84 }
85
86 let new_keys = scores
87 .0
88 .keys()
89 .filter(|key| !self.0.contains_key(key.as_str()))
90 .map(|key| key.as_str());
91
92 let removed_keys = self
93 .0
94 .keys()
95 .filter(|key| !scores.0.contains_key(key.as_str()))
96 .map(|key| key.as_str());
97
98 diff.extend(new_keys);
99 diff.extend(removed_keys);
100 diff
101 }
102}
103
104#[derive(Bundle)]
105pub struct ObjectiveBundle {
106 pub name: Objective,
107 pub display: ObjectiveDisplay,
108 pub render_type: ObjectiveRenderType,
109 pub number_format: ObjectiveNumberFormat,
110 pub scores: ObjectiveScores,
111 pub old_scores: OldObjectiveScores,
112 pub position: ScoreboardPosition,
113 pub layer: EntityLayerId,
114}
115
116impl Default for ObjectiveBundle {
117 fn default() -> Self {
118 Self {
119 name: Objective::new(""),
120 display: ObjectiveDisplay("".into_text()),
121 render_type: Default::default(),
122 number_format: Default::default(),
123 scores: Default::default(),
124 old_scores: Default::default(),
125 position: Default::default(),
126 layer: Default::default(),
127 }
128 }
129}