mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
chore: add uuid to world
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
use std::fmt::Formatter;
|
||||
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
|
||||
use crate::{
|
||||
VarInt,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
ser::{NetworkWriteExt, ReadingError, WritingError},
|
||||
};
|
||||
use serde::{
|
||||
Deserializer, Serialize,
|
||||
de::{self, Visitor},
|
||||
ser::Serializer,
|
||||
};
|
||||
use serde::{Serialize, ser::Serializer};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Velocity(pub Vector3<f64>);
|
||||
@@ -58,6 +64,52 @@ impl Velocity {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read<R: std::io::Read>(reader: &mut R) -> Result<Self, ReadingError> {
|
||||
let mut low_16 = [0u8; 2];
|
||||
reader
|
||||
.read_exact(&mut low_16)
|
||||
.map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
|
||||
if low_16[0] == 0 && low_16[1] == 0 {
|
||||
return Ok(Self(Vector3::new(0.0, 0.0, 0.0)));
|
||||
}
|
||||
|
||||
let mut mid_32 = [0u8; 4];
|
||||
reader
|
||||
.read_exact(&mut mid_32)
|
||||
.map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
|
||||
let low = u16::from_le_bytes(low_16) as i64;
|
||||
let mid = i32::from_be_bytes(mid_32) as i64;
|
||||
let packed_data = low | (mid << 16);
|
||||
|
||||
let header = packed_data & 0x07;
|
||||
let is_extended = (header & 4) != 0;
|
||||
|
||||
let scale_factor = if is_extended {
|
||||
let scale_tail = VarInt::decode(reader)?;
|
||||
((scale_tail.0 as i64) << 2) | (header & 3)
|
||||
} else {
|
||||
header & 3
|
||||
};
|
||||
|
||||
if scale_factor == 0 && !is_extended {
|
||||
return Ok(Self(Vector3::new(0.0, 0.0, 0.0)));
|
||||
}
|
||||
|
||||
let q_x = (packed_data >> 3) & 0x7FFF;
|
||||
let q_y = (packed_data >> 18) & 0x7FFF;
|
||||
let q_z = (packed_data >> 33) & 0x7FFF;
|
||||
|
||||
let scale = scale_factor as f64;
|
||||
|
||||
Ok(Self(Vector3::new(
|
||||
from_long(q_x, scale),
|
||||
from_long(q_y, scale),
|
||||
from_long(q_z, scale),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_VELOCITY_CLAMP: f64 = 1.717_986_918_3E10;
|
||||
@@ -79,6 +131,12 @@ fn to_long(value: f64) -> i64 {
|
||||
((value.mul_add(0.5, 0.5) * MAX_15_BIT_VALUE).round() as i64).clamp(0, 32766)
|
||||
}
|
||||
|
||||
fn from_long(quantized: i64, scale: f64) -> f64 {
|
||||
// Reverse: ((v * 0.5 + 0.5) * 32766) -> v
|
||||
let normalized = (quantized as f64 / MAX_15_BIT_VALUE) - 0.5;
|
||||
(normalized / 0.5) * scale
|
||||
}
|
||||
|
||||
impl Serialize for Velocity {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut buf = Vec::new();
|
||||
@@ -86,3 +144,30 @@ impl Serialize for Velocity {
|
||||
serializer.serialize_bytes(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> de::Deserialize<'de> for Velocity {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct VelocityVisitor;
|
||||
|
||||
impl Visitor<'_> for VelocityVisitor {
|
||||
type Value = Velocity;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a byte array representing bit-packed velocity")
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let mut cursor = std::io::Cursor::new(v);
|
||||
Velocity::read(&mut cursor).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_bytes(VelocityVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_MOTION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{VarInt, codec::velocity::Velocity};
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{VarInt, codec::velocity::Velocity};
|
||||
///
|
||||
/// This packet informs the client of a sudden change in an entity's movement,
|
||||
/// such as knockback from an attack, explosions, or being launched by a piston.
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[java_packet(PLAY_SET_ENTITY_MOTION)]
|
||||
pub struct CEntityVelocity {
|
||||
/// The Entity ID of the entity whose velocity is being set
|
||||
|
||||
@@ -2,7 +2,7 @@ use pumpkin_data::packet::clientbound::PLAY_LOGIN;
|
||||
use pumpkin_util::{math::position::BlockPos, resource_location::ResourceLocation};
|
||||
|
||||
use pumpkin_macros::java_packet;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@@ -12,14 +12,14 @@ use crate::VarInt;
|
||||
/// This is one of the largest and most important packets in the protocol. It
|
||||
/// initializes the player's world view, dimension settings, and local game
|
||||
/// rules. Once received, the client begins rendering the world.
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[java_packet(PLAY_LOGIN)]
|
||||
pub struct CLogin<'a> {
|
||||
pub struct CLogin {
|
||||
/// The unique ID assigned to the player for the current session.
|
||||
pub entity_id: i32,
|
||||
pub is_hardcore: bool,
|
||||
/// A list of all dimensions present on the server (e.g., overworld, nether, end).
|
||||
pub dimension_names: &'a [ResourceLocation],
|
||||
pub dimension_names: Vec<ResourceLocation>,
|
||||
pub max_players: VarInt,
|
||||
/// The number of chunks the client will render in each direction.
|
||||
pub view_distance: VarInt,
|
||||
@@ -52,14 +52,14 @@ pub struct CLogin<'a> {
|
||||
pub enforce_secure_chat: bool,
|
||||
}
|
||||
|
||||
impl<'a> CLogin<'a> {
|
||||
impl CLogin {
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
#[expect(clippy::fn_params_excessive_bools)]
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
entity_id: i32,
|
||||
is_hardcore: bool,
|
||||
dimension_names: &'a [ResourceLocation],
|
||||
dimension_names: Vec<ResourceLocation>,
|
||||
max_players: VarInt,
|
||||
view_distance: VarInt,
|
||||
simulated_distance: VarInt,
|
||||
|
||||
@@ -165,6 +165,8 @@ impl PumpkinError for GetBlockError {
|
||||
/// - Stores and tracks active `Player` entities within the world.
|
||||
/// - Provides a central hub for interacting with the world's entities and environment.
|
||||
pub struct World {
|
||||
/// Represents the World's Unique Identifier
|
||||
pub uuid: Uuid,
|
||||
/// The underlying level, responsible for chunk management and terrain generation.
|
||||
pub level: Arc<Level>,
|
||||
pub level_info: Arc<ArcSwap<LevelData>>,
|
||||
@@ -197,6 +199,14 @@ pub struct World {
|
||||
pub portal_poi: Mutex<portal::PortalPoiStorage>,
|
||||
}
|
||||
|
||||
impl PartialEq for World {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.uuid == other.uuid
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for World {}
|
||||
|
||||
impl World {
|
||||
#[must_use]
|
||||
pub fn load(
|
||||
@@ -213,6 +223,7 @@ impl World {
|
||||
let portal_poi = portal::PortalPoiStorage::new(&level.level_folder.root_folder);
|
||||
|
||||
Self {
|
||||
uuid: Uuid::new_v4(),
|
||||
level,
|
||||
level_info,
|
||||
players: ArcSwap::new(Arc::new(Vec::new())),
|
||||
@@ -1445,7 +1456,7 @@ impl World {
|
||||
.send_packet_now(&CLogin::new(
|
||||
entity_id,
|
||||
base_config.hardcore,
|
||||
&dimensions,
|
||||
dimensions,
|
||||
base_config.max_players.try_into().unwrap(),
|
||||
base_config.view_distance.get().into(), // TODO: view distance
|
||||
base_config.simulation_distance.get().into(), // TODO: sim view dinstance
|
||||
|
||||
Reference in New Issue
Block a user