Add Scoreboard support

This commit is contained in:
Snowiiii 2024-10-18 18:22:24 +02:00
parent 5d0bb14a85
commit 406db91f06
6 changed files with 134 additions and 2 deletions

View File

@ -18,7 +18,7 @@
**Cause:** The server is currently not calculating hit boxes for blocks, we're working on that.
3. The Server is unresponsive
3. ### The Server is unresponsive
**Issue:** You have to wait before reconnecting or can't do basic things while chunks are loading.

View File

@ -1,4 +1,4 @@
use pumpkin_core::text::{style::Style, TextComponent};
use pumpkin_core::text::TextComponent;
use pumpkin_macros::packet;
use crate::{ClientPacket, NumberFormat, VarInt};

View File

@ -1,8 +1,10 @@
use pumpkin_core::text::TextComponent;
use pumpkin_macros::packet;
use serde::Serialize;
use crate::{NumberFormat, VarInt};
#[derive(Serialize)]
#[packet(0x61)]
pub struct CUpdateScore<'a> {
entity_name: &'a str,

View File

@ -1,5 +1,6 @@
use bytebuf::{packet_id::Packet, ByteBuffer, DeserializerError};
use bytes::Buf;
use pumpkin_core::text::{style::Style, TextComponent};
use serde::{Deserialize, Serialize};
use std::io::{self, Write};
use thiserror::Error;
@ -245,6 +246,7 @@ pub struct KnownPack<'a> {
pub version: &'a str,
}
#[derive(Serialize)]
pub enum NumberFormat<'a> {
/// Show nothing
Blank,

View File

@ -19,8 +19,11 @@ use pumpkin_protocol::{
ClientPacket, VarInt,
};
use pumpkin_world::level::Level;
use scoreboard::Scoreboard;
use tokio::sync::mpsc;
pub mod scoreboard;
/// Represents a Minecraft world, containing entities, players, and the underlying level data.
///
/// Each dimension (Overworld, Nether, End) typically has its own `World`.
@ -35,6 +38,7 @@ pub struct World {
pub level: Arc<Mutex<Level>>,
/// A map of active players within the world, keyed by their unique token.
pub current_players: Arc<Mutex<HashMap<usize, Arc<Player>>>>,
pub scoreboard: Mutex<Scoreboard>,
// TODO: entities
}
@ -43,6 +47,7 @@ impl World {
Self {
level: Arc::new(Mutex::new(level)),
current_players: Arc::new(Mutex::new(HashMap::new())),
scoreboard: Mutex::new(Scoreboard::new()),
}
}

View File

@ -0,0 +1,123 @@
use std::collections::HashMap;
use pumpkin_core::text::TextComponent;
use pumpkin_protocol::{
client::play::{CDisplayObjective, CUpdateObjectives, CUpdateScore, RenderType},
NumberFormat, VarInt,
};
use super::World;
pub struct Scoreboard {
objectives: HashMap<String, ScoreboardObjective<'static>>,
// teams: HashMap<String, Team>,
}
impl Default for Scoreboard {
fn default() -> Self {
Self::new()
}
}
impl Scoreboard {
pub fn new() -> Self {
Self {
objectives: HashMap::new(),
}
}
pub fn add_objective(&mut self, world: &World, objective: ScoreboardObjective) {
if self.objectives.contains_key(objective.name) {
// Maybe make this an error ?
log::warn!(
"Tried to create Objective which does already exist, {}",
&objective.name
);
return;
}
world.broadcast_packet_all(&CUpdateObjectives::new(
objective.name,
pumpkin_protocol::client::play::Mode::Add,
objective.display_name,
objective.render_type,
objective.number_format,
));
world.broadcast_packet_all(&CDisplayObjective::new(
pumpkin_protocol::client::play::DisplaySlot::Sidebar,
"test",
));
}
pub fn update_score(&self, world: &World, score: ScoreboardScore) {
if self.objectives.contains_key(score.objective_name) {
log::warn!(
"Tried to place a score into a Objective which does not exist, {}",
&score.objective_name
);
return;
}
world.broadcast_packet_all(&CUpdateScore::new(
score.entity_name,
score.objective_name,
score.value,
score.display_name,
score.number_format,
));
}
// pub fn add_team(&mut self, name: String) {
// if self.teams.contains_key(&name) {
// // Maybe make this an error ?
// log::warn!("Tried to create Team which does already exist, {}", name);
// }
// }
}
pub struct ScoreboardObjective<'a> {
name: &'a str,
display_name: TextComponent<'a>,
render_type: RenderType,
number_format: Option<NumberFormat<'a>>,
}
impl<'a> ScoreboardObjective<'a> {
pub const fn new(
name: &'a str,
display_name: TextComponent<'a>,
render_type: RenderType,
number_format: Option<NumberFormat<'a>>,
) -> Self {
Self {
name,
display_name,
render_type,
number_format,
}
}
}
pub struct ScoreboardScore<'a> {
entity_name: &'a str,
objective_name: &'a str,
value: VarInt,
display_name: Option<TextComponent<'a>>,
number_format: Option<NumberFormat<'a>>,
}
impl<'a> ScoreboardScore<'a> {
pub const fn new(
entity_name: &'a str,
objective_name: &'a str,
value: VarInt,
display_name: Option<TextComponent<'a>>,
number_format: Option<NumberFormat<'a>>,
) -> Self {
Self {
entity_name,
objective_name,
value,
display_name,
number_format,
}
}
}