Skip to content

Commit 406db91

Browse files
committed
Add Scoreboard support
1 parent 5d0bb14 commit 406db91

File tree

6 files changed

+134
-2
lines changed

6 files changed

+134
-2
lines changed

docs/troubleshooting/common_issues.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
**Cause:** The server is currently not calculating hit boxes for blocks, we're working on that.
2020

21-
3. The Server is unresponsive
21+
3. ### The Server is unresponsive
2222

2323
**Issue:** You have to wait before reconnecting or can't do basic things while chunks are loading.
2424

pumpkin-protocol/src/client/play/c_update_objectives.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use pumpkin_core::text::{style::Style, TextComponent};
1+
use pumpkin_core::text::TextComponent;
22
use pumpkin_macros::packet;
33

44
use crate::{ClientPacket, NumberFormat, VarInt};

pumpkin-protocol/src/client/play/c_update_score.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use pumpkin_core::text::TextComponent;
22
use pumpkin_macros::packet;
3+
use serde::Serialize;
34

45
use crate::{NumberFormat, VarInt};
56

7+
#[derive(Serialize)]
68
#[packet(0x61)]
79
pub struct CUpdateScore<'a> {
810
entity_name: &'a str,

pumpkin-protocol/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use bytebuf::{packet_id::Packet, ByteBuffer, DeserializerError};
22
use bytes::Buf;
3+
use pumpkin_core::text::{style::Style, TextComponent};
34
use serde::{Deserialize, Serialize};
45
use std::io::{self, Write};
56
use thiserror::Error;
@@ -245,6 +246,7 @@ pub struct KnownPack<'a> {
245246
pub version: &'a str,
246247
}
247248

249+
#[derive(Serialize)]
248250
pub enum NumberFormat<'a> {
249251
/// Show nothing
250252
Blank,

pumpkin/src/world/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ use pumpkin_protocol::{
1919
ClientPacket, VarInt,
2020
};
2121
use pumpkin_world::level::Level;
22+
use scoreboard::Scoreboard;
2223
use tokio::sync::mpsc;
2324

25+
pub mod scoreboard;
26+
2427
/// Represents a Minecraft world, containing entities, players, and the underlying level data.
2528
///
2629
/// Each dimension (Overworld, Nether, End) typically has its own `World`.
@@ -35,6 +38,7 @@ pub struct World {
3538
pub level: Arc<Mutex<Level>>,
3639
/// A map of active players within the world, keyed by their unique token.
3740
pub current_players: Arc<Mutex<HashMap<usize, Arc<Player>>>>,
41+
pub scoreboard: Mutex<Scoreboard>,
3842
// TODO: entities
3943
}
4044

@@ -43,6 +47,7 @@ impl World {
4347
Self {
4448
level: Arc::new(Mutex::new(level)),
4549
current_players: Arc::new(Mutex::new(HashMap::new())),
50+
scoreboard: Mutex::new(Scoreboard::new()),
4651
}
4752
}
4853

pumpkin/src/world/scoreboard.rs

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use std::collections::HashMap;
2+
3+
use pumpkin_core::text::TextComponent;
4+
use pumpkin_protocol::{
5+
client::play::{CDisplayObjective, CUpdateObjectives, CUpdateScore, RenderType},
6+
NumberFormat, VarInt,
7+
};
8+
9+
use super::World;
10+
11+
pub struct Scoreboard {
12+
objectives: HashMap<String, ScoreboardObjective<'static>>,
13+
// teams: HashMap<String, Team>,
14+
}
15+
16+
impl Default for Scoreboard {
17+
fn default() -> Self {
18+
Self::new()
19+
}
20+
}
21+
22+
impl Scoreboard {
23+
pub fn new() -> Self {
24+
Self {
25+
objectives: HashMap::new(),
26+
}
27+
}
28+
29+
pub fn add_objective(&mut self, world: &World, objective: ScoreboardObjective) {
30+
if self.objectives.contains_key(objective.name) {
31+
// Maybe make this an error ?
32+
log::warn!(
33+
"Tried to create Objective which does already exist, {}",
34+
&objective.name
35+
);
36+
return;
37+
}
38+
world.broadcast_packet_all(&CUpdateObjectives::new(
39+
objective.name,
40+
pumpkin_protocol::client::play::Mode::Add,
41+
objective.display_name,
42+
objective.render_type,
43+
objective.number_format,
44+
));
45+
world.broadcast_packet_all(&CDisplayObjective::new(
46+
pumpkin_protocol::client::play::DisplaySlot::Sidebar,
47+
"test",
48+
));
49+
}
50+
51+
pub fn update_score(&self, world: &World, score: ScoreboardScore) {
52+
if self.objectives.contains_key(score.objective_name) {
53+
log::warn!(
54+
"Tried to place a score into a Objective which does not exist, {}",
55+
&score.objective_name
56+
);
57+
return;
58+
}
59+
world.broadcast_packet_all(&CUpdateScore::new(
60+
score.entity_name,
61+
score.objective_name,
62+
score.value,
63+
score.display_name,
64+
score.number_format,
65+
));
66+
}
67+
68+
// pub fn add_team(&mut self, name: String) {
69+
// if self.teams.contains_key(&name) {
70+
// // Maybe make this an error ?
71+
// log::warn!("Tried to create Team which does already exist, {}", name);
72+
// }
73+
// }
74+
}
75+
76+
pub struct ScoreboardObjective<'a> {
77+
name: &'a str,
78+
display_name: TextComponent<'a>,
79+
render_type: RenderType,
80+
number_format: Option<NumberFormat<'a>>,
81+
}
82+
83+
impl<'a> ScoreboardObjective<'a> {
84+
pub const fn new(
85+
name: &'a str,
86+
display_name: TextComponent<'a>,
87+
render_type: RenderType,
88+
number_format: Option<NumberFormat<'a>>,
89+
) -> Self {
90+
Self {
91+
name,
92+
display_name,
93+
render_type,
94+
number_format,
95+
}
96+
}
97+
}
98+
99+
pub struct ScoreboardScore<'a> {
100+
entity_name: &'a str,
101+
objective_name: &'a str,
102+
value: VarInt,
103+
display_name: Option<TextComponent<'a>>,
104+
number_format: Option<NumberFormat<'a>>,
105+
}
106+
107+
impl<'a> ScoreboardScore<'a> {
108+
pub const fn new(
109+
entity_name: &'a str,
110+
objective_name: &'a str,
111+
value: VarInt,
112+
display_name: Option<TextComponent<'a>>,
113+
number_format: Option<NumberFormat<'a>>,
114+
) -> Self {
115+
Self {
116+
entity_name,
117+
objective_name,
118+
value,
119+
display_name,
120+
number_format,
121+
}
122+
}
123+
}

0 commit comments

Comments
 (0)