Skip to content

Commit

Permalink
Added Worldborder (#202)
Browse files Browse the repository at this point in the history
* Added packets

* Created worldborder struct

* Added worldborder command

* Improved worldborder command

Added messages to worldborder command
Removed all .unwrap()
Created consumer for command

* Fixed small issue

/worldborder add wasn't working properly
  • Loading branch information
Alvsch authored Oct 27, 2024
1 parent 2add205 commit 5507b20
Show file tree
Hide file tree
Showing 18 changed files with 1,118 additions and 105 deletions.
58 changes: 57 additions & 1 deletion pumpkin-protocol/src/bytebuf/packet_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer,
};

use crate::{BitSet, ClientPacket, ServerPacket, VarInt, VarIntType};
use crate::{BitSet, ClientPacket, ServerPacket, VarInt, VarIntType, VarLong};

use super::{deserializer, serializer, ByteBuffer, DeserializerError};

Expand Down Expand Up @@ -74,6 +74,62 @@ impl<'de> Deserialize<'de> for VarInt {
}
}

impl Serialize for VarLong {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut value = self.0 as u64;
let mut buf = Vec::new();

while value > 0x7F {
buf.put_u8(value as u8 | 0x80);
value >>= 7;
}

buf.put_u8(value as u8);

serializer.serialize_bytes(&buf)
}
}

impl<'de> Deserialize<'de> for VarLong {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct VarLongVisitor;

impl<'de> Visitor<'de> for VarLongVisitor {
type Value = VarLong;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid VarInt encoded in a byte sequence")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut val = 0;
for i in 0..VarLong::MAX_SIZE {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (i64::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(VarLong(val));
}
} else {
break;
}
}
Err(de::Error::custom("VarInt was too large"))
}
}

deserializer.deserialize_seq(VarLongVisitor)
}
}

pub trait ClientPacketID {
const PACKET_ID: VarIntType;
}
Expand Down
44 changes: 44 additions & 0 deletions pumpkin-protocol/src/client/play/c_initialize_world_border.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use pumpkin_macros::client_packet;
use serde::Serialize;

use crate::{VarInt, VarLong};

use super::ClientboundPlayPackets;

#[derive(Serialize)]
#[client_packet(ClientboundPlayPackets::InitializeWorldBorder as i32)]
pub struct CInitializeWorldBorder {
x: f64,
z: f64,
old_diameter: f64,
new_diameter: f64,
speed: VarLong,
portal_teleport_boundary: VarInt,
warning_blocks: VarInt,
warning_time: VarInt,
}

impl CInitializeWorldBorder {
#[expect(clippy::too_many_arguments)]
pub fn new(
x: f64,
z: f64,
old_diameter: f64,
new_diameter: f64,
speed: VarLong,
portal_teleport_boundary: VarInt,
warning_blocks: VarInt,
warning_time: VarInt,
) -> Self {
Self {
x,
z,
old_diameter,
new_diameter,
speed,
portal_teleport_boundary,
warning_blocks,
warning_time,
}
}
}
17 changes: 17 additions & 0 deletions pumpkin-protocol/src/client/play/c_set_border_center.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use pumpkin_macros::client_packet;
use serde::Serialize;

use super::ClientboundPlayPackets;

#[derive(Serialize)]
#[client_packet(ClientboundPlayPackets::WorldBorderCenter as i32)]
pub struct CSetBorderCenter {
x: f64,
z: f64,
}

impl CSetBorderCenter {
pub fn new(x: f64, z: f64) -> Self {
Self { x, z }
}
}
24 changes: 24 additions & 0 deletions pumpkin-protocol/src/client/play/c_set_border_lerp_size.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use pumpkin_macros::client_packet;
use serde::Serialize;

use crate::VarLong;

use super::ClientboundPlayPackets;

#[derive(Serialize)]
#[client_packet(ClientboundPlayPackets::WorldBorderLerpSize as i32)]
pub struct CSetBorderLerpSize {
old_diameter: f64,
new_diameter: f64,
speed: VarLong,
}

impl CSetBorderLerpSize {
pub fn new(old_diameter: f64, new_diameter: f64, speed: VarLong) -> Self {
Self {
old_diameter,
new_diameter,
speed,
}
}
}
16 changes: 16 additions & 0 deletions pumpkin-protocol/src/client/play/c_set_border_size.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use pumpkin_macros::client_packet;
use serde::Serialize;

use super::ClientboundPlayPackets;

#[derive(Serialize)]
#[client_packet(ClientboundPlayPackets::WorldBorderSize as i32)]
pub struct CSetBorderSize {
diameter: f64,
}

impl CSetBorderSize {
pub fn new(diameter: f64) -> Self {
Self { diameter }
}
}
18 changes: 18 additions & 0 deletions pumpkin-protocol/src/client/play/c_set_border_warning_delay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use pumpkin_macros::client_packet;
use serde::Serialize;

use crate::VarInt;

use super::ClientboundPlayPackets;

#[derive(Serialize)]
#[client_packet(ClientboundPlayPackets::WorldBorderWarningDelay as i32)]
pub struct CSetBorderWarningDelay {
warning_time: VarInt,
}

impl CSetBorderWarningDelay {
pub fn new(warning_time: VarInt) -> Self {
Self { warning_time }
}
}
18 changes: 18 additions & 0 deletions pumpkin-protocol/src/client/play/c_set_border_warning_distance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use pumpkin_macros::client_packet;
use serde::Serialize;

use crate::VarInt;

use super::ClientboundPlayPackets;

#[derive(Serialize)]
#[client_packet(ClientboundPlayPackets::WorldBorderWarningReach as i32)]
pub struct CSetBorderWarningDistance {
warning_blocks: VarInt,
}

impl CSetBorderWarningDistance {
pub fn new(warning_blocks: VarInt) -> Self {
Self { warning_blocks }
}
}
12 changes: 12 additions & 0 deletions pumpkin-protocol/src/client/play/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod c_entity_velocity;
mod c_game_event;
mod c_head_rot;
mod c_hurt_animation;
mod c_initialize_world_border;
mod c_keep_alive;
mod c_login;
mod c_open_screen;
Expand All @@ -28,6 +29,11 @@ mod c_player_info_update;
mod c_player_remove;
mod c_remove_entities;
mod c_reset_score;
mod c_set_border_center;
mod c_set_border_lerp_size;
mod c_set_border_size;
mod c_set_border_warning_delay;
mod c_set_border_warning_distance;
mod c_set_container_content;
mod c_set_container_property;
mod c_set_container_slot;
Expand Down Expand Up @@ -67,6 +73,7 @@ pub use c_entity_velocity::*;
pub use c_game_event::*;
pub use c_head_rot::*;
pub use c_hurt_animation::*;
pub use c_initialize_world_border::*;
pub use c_keep_alive::*;
pub use c_login::*;
pub use c_open_screen::*;
Expand All @@ -79,6 +86,11 @@ pub use c_player_info_update::*;
pub use c_player_remove::*;
pub use c_remove_entities::*;
pub use c_reset_score::*;
pub use c_set_border_center::*;
pub use c_set_border_lerp_size::*;
pub use c_set_border_size::*;
pub use c_set_border_warning_delay::*;
pub use c_set_border_warning_distance::*;
pub use c_set_container_content::*;
pub use c_set_container_property::*;
pub use c_set_container_slot::*;
Expand Down
109 changes: 6 additions & 103 deletions pumpkin-protocol/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use bytebuf::{packet_id::ClientPacketID, ByteBuffer, DeserializerError};
use bytes::Buf;
use pumpkin_core::text::{style::Style, TextComponent};
use serde::{Deserialize, Serialize};
use std::io::{self, Write};
use thiserror::Error;

pub mod bytebuf;
Expand All @@ -12,6 +10,12 @@ pub mod packet_encoder;
pub mod server;
pub mod slot;

mod var_int;
pub use var_int::*;

mod var_long;
pub use var_long::*;

/// To current Minecraft protocol
/// Don't forget to change this when porting
pub const CURRENT_MC_PROTOCOL: u32 = 768;
Expand All @@ -26,107 +30,6 @@ pub type FixedBitSet = bytes::Bytes;

pub struct BitSet<'a>(pub VarInt, pub &'a [i64]);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VarInt(pub VarIntType);

impl VarInt {
/// The maximum number of bytes a `VarInt` could occupy when read from and
/// written to the Minecraft protocol.
pub const MAX_SIZE: usize = 5;

/// Returns the exact number of bytes this varint will write when
/// [`Encode::encode`] is called, assuming no error occurs.
pub const fn written_size(self) -> usize {
match self.0 {
0 => 1,
n => (31 - n.leading_zeros() as usize) / 7 + 1,
}
}

pub fn decode_partial(r: &mut &[u8]) -> Result<i32, VarIntDecodeError> {
let mut val = 0;
for i in 0..Self::MAX_SIZE {
if !r.has_remaining() {
return Err(VarIntDecodeError::Incomplete);
}
let byte = r.get_u8();
val |= (i32::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(val);
}
}

Err(VarIntDecodeError::TooLarge)
}

pub fn encode(&self, mut w: impl Write) -> Result<(), io::Error> {
let mut x = self.0 as u64;
loop {
let byte = (x & 0x7F) as u8;
x >>= 7;
if x == 0 {
w.write_all(&[byte])?;
break;
}
w.write_all(&[byte | 0x80])?;
}
Ok(())
}

pub fn decode(r: &mut &[u8]) -> Result<Self, VarIntDecodeError> {
let mut val = 0;
for i in 0..Self::MAX_SIZE {
if !r.has_remaining() {
return Err(VarIntDecodeError::Incomplete);
}
let byte = r.get_u8();
val |= (i32::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(VarInt(val));
}
}
Err(VarIntDecodeError::TooLarge)
}
}

impl From<i32> for VarInt {
fn from(value: i32) -> Self {
VarInt(value)
}
}

impl From<u32> for VarInt {
fn from(value: u32) -> Self {
VarInt(value as i32)
}
}

impl From<u8> for VarInt {
fn from(value: u8) -> Self {
VarInt(value as i32)
}
}

impl From<usize> for VarInt {
fn from(value: usize) -> Self {
VarInt(value as i32)
}
}

impl From<VarInt> for i32 {
fn from(value: VarInt) -> Self {
value.0
}
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)]
pub enum VarIntDecodeError {
#[error("incomplete VarInt decode")]
Incomplete,
#[error("VarInt is too large")]
TooLarge,
}

#[derive(Error, Debug)]
pub enum PacketError {
#[error("failed to decode packet ID")]
Expand Down
Loading

0 comments on commit 5507b20

Please sign in to comment.