Dynamic chunk loading
This commit is contained in:
parent
2085307a44
commit
5c0dffbf9d
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1959,6 +1959,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2034,6 +2035,7 @@ dependencies = [
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-core",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod gamemode;
|
||||
pub mod math;
|
||||
pub mod random;
|
||||
pub mod text;
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use pumpkin_protocol::position::WorldPosition;
|
||||
use pumpkin_world::vector3::Vector3;
|
||||
use super::{position::WorldPosition, vector3::Vector3};
|
||||
|
||||
pub struct BoundingBox {
|
||||
pub min_x: f64,
|
||||
@ -38,6 +37,6 @@ impl BoundingBox {
|
||||
let d = f64::max(f64::max(self.min_x - pos.x, pos.x - self.max_x), 0.0);
|
||||
let e = f64::max(f64::max(self.min_y - pos.y, pos.y - self.max_y), 0.0);
|
||||
let f = f64::max(f64::max(self.min_z - pos.z, pos.z - self.max_z), 0.0);
|
||||
super::math::squared_magnitude(d, e, f)
|
||||
super::squared_magnitude(d, e, f)
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,8 @@
|
||||
pub mod boundingbox;
|
||||
pub mod position;
|
||||
pub mod vector2;
|
||||
pub mod vector3;
|
||||
|
||||
pub fn wrap_degrees(var: f32) -> f32 {
|
||||
let mut var1 = var % 360.0;
|
||||
if var1 >= 180.0 {
|
||||
@ -14,3 +19,9 @@ pub fn wrap_degrees(var: f32) -> f32 {
|
||||
pub fn squared_magnitude(a: f64, b: f64, c: f64) -> f64 {
|
||||
a * a + b * b + c * c
|
||||
}
|
||||
|
||||
/// Converts a world coordinate to the corresponding chunk-section coordinate.
|
||||
// TODO: This proberbly should place not here
|
||||
pub fn get_section_cord(coord: i32) -> i32 {
|
||||
coord >> 4
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
use pumpkin_world::vector3::Vector3;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::vector3::Vector3;
|
||||
|
||||
/// Aka Block Position
|
||||
pub struct WorldPosition(pub Vector3<i32>);
|
||||
|
||||
impl Serialize for WorldPosition {
|
||||
@ -4,5 +4,7 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
pumpkin-core = { path = "../pumpkin-core"}
|
||||
|
||||
num-traits = "0.2"
|
||||
num-derive = "0.4"
|
||||
@ -1,5 +1,8 @@
|
||||
use entity_type::EntityType;
|
||||
use pose::EntityPose;
|
||||
use pumpkin_core::math::{
|
||||
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
|
||||
};
|
||||
|
||||
pub mod entity_type;
|
||||
pub mod pose;
|
||||
@ -9,12 +12,10 @@ pub type EntityId = i32;
|
||||
pub struct Entity {
|
||||
pub entity_id: EntityId,
|
||||
pub entity_type: EntityType,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
pub lastx: f64,
|
||||
pub lasty: f64,
|
||||
pub lastz: f64,
|
||||
pub pos: Vector3<f64>,
|
||||
pub block_pos: WorldPosition,
|
||||
pub chunk_pos: Vector2<i32>,
|
||||
|
||||
pub yaw: f32,
|
||||
pub head_yaw: f32,
|
||||
pub pitch: f32,
|
||||
@ -28,12 +29,9 @@ impl Entity {
|
||||
Self {
|
||||
entity_id,
|
||||
entity_type,
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
lastx: 0.0,
|
||||
lasty: 0.0,
|
||||
lastz: 0.0,
|
||||
pos: Vector3::new(0.0, 0.0, 0.0),
|
||||
block_pos: WorldPosition(Vector3::new(0, 0, 0)),
|
||||
chunk_pos: Vector2::new(0, 0),
|
||||
yaw: 0.0,
|
||||
head_yaw: 0.0,
|
||||
pitch: 0.0,
|
||||
@ -41,4 +39,25 @@ impl Entity {
|
||||
pose: EntityPose::Standing,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pos(&mut self, x: f64, y: f64, z: f64) {
|
||||
if self.pos.x != x || self.pos.y != y || self.pos.z != z {
|
||||
self.pos = Vector3::new(x, y, z);
|
||||
let i = x.floor() as i32;
|
||||
let j = y.floor() as i32;
|
||||
let k = z.floor() as i32;
|
||||
|
||||
let block_pos = self.block_pos.0;
|
||||
if i != block_pos.x || j != block_pos.y || k != block_pos.z {
|
||||
self.block_pos = WorldPosition(Vector3::new(i, j, k));
|
||||
|
||||
if get_section_cord(i) != self.chunk_pos.x
|
||||
|| get_section_cord(k) != self.chunk_pos.z
|
||||
{
|
||||
self.chunk_pos =
|
||||
Vector2::new(get_section_cord(block_pos.x), get_section_cord(block_pos.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use bytes::BufMut;
|
||||
use serde::{
|
||||
de::{self, DeserializeOwned, SeqAccess, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
@ -22,19 +23,16 @@ impl Serialize for VarInt {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut val = self.0;
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
for _ in 0..5 {
|
||||
let mut b: u8 = val as u8 & 0b01111111;
|
||||
val >>= 7;
|
||||
if val != 0 {
|
||||
b |= 0b10000000;
|
||||
}
|
||||
buf.push(b);
|
||||
if val == 0 {
|
||||
break;
|
||||
}
|
||||
let mut value = self.0 as u32;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use pumpkin_core::math::position::WorldPosition;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{position::WorldPosition, VarInt};
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x06)]
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use pumpkin_core::math::position::WorldPosition;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{position::WorldPosition, VarInt};
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x09)]
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use pumpkin_core::math::position::WorldPosition;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{position::WorldPosition, VarInt};
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x2B)]
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use pumpkin_core::math::position::WorldPosition;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::position::WorldPosition;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x28)]
|
||||
pub struct CWorldEvent<'a> {
|
||||
|
||||
@ -8,7 +8,6 @@ pub mod bytebuf;
|
||||
pub mod client;
|
||||
pub mod packet_decoder;
|
||||
pub mod packet_encoder;
|
||||
pub mod position;
|
||||
pub mod server;
|
||||
pub mod slot;
|
||||
pub mod uuid;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use num_derive::FromPrimitive;
|
||||
use pumpkin_core::math::position::WorldPosition;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
use crate::{position::WorldPosition, VarInt};
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[packet(0x24)]
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use pumpkin_core::math::position::WorldPosition;
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{position::WorldPosition, VarInt};
|
||||
use crate::VarInt;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[packet(0x38)]
|
||||
|
||||
@ -4,7 +4,9 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
# fastanvil = "0.31"
|
||||
pumpkin-core = { path = "../pumpkin-core"}
|
||||
|
||||
|
||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||
fastsnbt = "0.2"
|
||||
tokio.workspace = true
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use crate::vector3::Vector3;
|
||||
use num_derive::FromPrimitive;
|
||||
|
||||
pub mod block_id;
|
||||
mod block_registry;
|
||||
|
||||
pub use block_id::BlockId;
|
||||
use pumpkin_core::math::vector3::Vector3;
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum BlockFace {
|
||||
|
||||
@ -3,13 +3,13 @@ use std::collections::HashMap;
|
||||
use std::ops::Index;
|
||||
|
||||
use fastnbt::LongArray;
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
block::BlockId,
|
||||
coordinates::{ChunkRelativeBlockCoordinates, Height},
|
||||
level::{ChunkNotGeneratedError, WorldError},
|
||||
vector2::Vector2,
|
||||
WORLD_HEIGHT,
|
||||
};
|
||||
|
||||
|
||||
@ -2,9 +2,10 @@ use std::ops::Deref;
|
||||
|
||||
use derive_more::derive::{AsMut, AsRef, Display, Into};
|
||||
use num_traits::{PrimInt, Signed, Unsigned};
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{vector2::Vector2, WORLD_LOWEST_Y, WORLD_MAX_Y};
|
||||
use crate::{WORLD_LOWEST_Y, WORLD_MAX_Y};
|
||||
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, AsRef, AsMut, Into, Display,
|
||||
|
||||
83
pumpkin-world/src/cylindrical_chunk_iterator.rs
Normal file
83
pumpkin-world/src/cylindrical_chunk_iterator.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Cylindrical {
|
||||
pub center: Vector2<i32>,
|
||||
pub view_distance: i32,
|
||||
}
|
||||
|
||||
impl Cylindrical {
|
||||
pub fn new(center: Vector2<i32>, view_distance: i32) -> Self {
|
||||
Self {
|
||||
center,
|
||||
view_distance,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn for_each_changed_chunk(
|
||||
old_cylindrical: Cylindrical,
|
||||
new_cylindrical: Cylindrical,
|
||||
mut newly_included: impl FnMut(Vector2<i32>),
|
||||
just_removed: impl FnMut(Vector2<i32>),
|
||||
ignore: bool,
|
||||
) {
|
||||
let min_x = old_cylindrical.get_left().min(new_cylindrical.get_left());
|
||||
let max_x = old_cylindrical.get_right().max(new_cylindrical.get_right());
|
||||
let min_z = old_cylindrical
|
||||
.get_bottom()
|
||||
.min(new_cylindrical.get_bottom());
|
||||
let max_z = old_cylindrical.get_top().max(new_cylindrical.get_top());
|
||||
|
||||
for x in min_x..=max_x {
|
||||
for z in min_z..=max_z {
|
||||
// TODO
|
||||
// let old_is_within = if ignore {
|
||||
// false
|
||||
// } else {
|
||||
// old_cylindrical.is_within_distance(x, z)
|
||||
// };
|
||||
// let new_is_within = if ignore {
|
||||
// true
|
||||
// } else {
|
||||
// new_cylindrical.is_within_distance(x, z)
|
||||
// };
|
||||
|
||||
// if old_is_within != new_is_within {
|
||||
// if new_is_within {
|
||||
newly_included(Vector2::new(x, z));
|
||||
// } else {
|
||||
// dbg!("aa");
|
||||
// just_removed(Vector2::new(x, z));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_left(&self) -> i32 {
|
||||
self.center.x - self.view_distance - 1
|
||||
}
|
||||
|
||||
fn get_bottom(&self) -> i32 {
|
||||
self.center.z - self.view_distance - 1
|
||||
}
|
||||
|
||||
fn get_right(&self) -> i32 {
|
||||
self.center.x + self.view_distance + 1
|
||||
}
|
||||
|
||||
fn get_top(&self) -> i32 {
|
||||
self.center.z + self.view_distance + 1
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn is_within_distance(&self, x: i32, z: i32) -> bool {
|
||||
let max_dist_squared = self.view_distance * self.view_distance;
|
||||
let max_dist = self.view_distance as i64;
|
||||
let dist_x = (x - self.center.x).abs().max(0) - (1);
|
||||
let dist_z = (z - self.center.z).abs().max(0) - (1);
|
||||
let dist_squared = dist_x.pow(2) + (max_dist.min(dist_z as i64) as i32).pow(2);
|
||||
dist_squared < max_dist_squared
|
||||
}
|
||||
}
|
||||
@ -8,13 +8,13 @@ use std::{
|
||||
|
||||
use flate2::{bufread::ZlibDecoder, read::GzDecoder};
|
||||
use itertools::Itertools;
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
use rayon::prelude::*;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::{
|
||||
chunk::ChunkData,
|
||||
vector2::Vector2,
|
||||
world_gen::{get_world_gen, Seed, WorldGenerator},
|
||||
};
|
||||
|
||||
|
||||
@ -2,13 +2,11 @@ pub mod biome;
|
||||
pub mod block;
|
||||
pub mod chunk;
|
||||
pub mod coordinates;
|
||||
pub mod cylindrical_chunk_iterator;
|
||||
pub mod dimension;
|
||||
pub mod global_registry;
|
||||
pub mod item;
|
||||
pub mod level;
|
||||
pub mod radial_chunk_iterator;
|
||||
pub mod vector2;
|
||||
pub mod vector3;
|
||||
mod world_gen;
|
||||
|
||||
pub const WORLD_HEIGHT: usize = 384;
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
use crate::vector2::Vector2;
|
||||
|
||||
pub struct RadialIterator {
|
||||
radius: u32,
|
||||
direction: usize,
|
||||
current: Vector2<i32>,
|
||||
step_size: i32,
|
||||
steps_taken: u32,
|
||||
steps_in_direction: i32,
|
||||
}
|
||||
|
||||
impl RadialIterator {
|
||||
pub fn new(radius: u32) -> Self {
|
||||
RadialIterator {
|
||||
radius,
|
||||
direction: 0,
|
||||
current: Vector2::new(0, 0),
|
||||
step_size: 1,
|
||||
steps_taken: 0,
|
||||
steps_in_direction: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for RadialIterator {
|
||||
type Item = Vector2<i32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.steps_taken >= self.radius * self.radius * 4 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let result = self.current;
|
||||
|
||||
self.steps_in_direction += 1;
|
||||
|
||||
// Move in the current direction
|
||||
match self.direction {
|
||||
0 => self.current.x += 1, // East
|
||||
1 => self.current.z += 1, // North
|
||||
2 => self.current.x -= 1, // West
|
||||
3 => self.current.z -= 1, // South
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.steps_in_direction >= self.step_size {
|
||||
self.direction = (self.direction + 1) % 4;
|
||||
self.steps_in_direction = 0;
|
||||
|
||||
// Increase step size after completing two directions
|
||||
if self.direction == 0 || self.direction == 2 {
|
||||
self.step_size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.steps_taken += 1;
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
use static_assertions::assert_obj_safe;
|
||||
|
||||
use crate::biome::Biome;
|
||||
use crate::block::BlockId;
|
||||
use crate::chunk::ChunkData;
|
||||
use crate::coordinates::{BlockCoordinates, XZBlockCoordinates};
|
||||
use crate::vector2::Vector2;
|
||||
use crate::world_gen::Seed;
|
||||
|
||||
pub trait GeneratorInit {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
|
||||
use crate::{
|
||||
chunk::{ChunkBlocks, ChunkData},
|
||||
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
|
||||
vector2::Vector2,
|
||||
WORLD_LOWEST_Y, WORLD_MAX_Y,
|
||||
};
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ mod client_packet;
|
||||
mod container;
|
||||
pub mod player_packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PlayerConfig {
|
||||
pub locale: String, // 16
|
||||
pub view_distance: i8,
|
||||
|
||||
@ -4,11 +4,15 @@ use crate::{
|
||||
commands::{handle_command, CommandSender},
|
||||
entity::player::{ChatMode, Hand, Player},
|
||||
server::Server,
|
||||
util::math::wrap_degrees,
|
||||
world::player_chunker,
|
||||
};
|
||||
use num_traits::FromPrimitive;
|
||||
use pumpkin_config::ADVANCED_CONFIG;
|
||||
use pumpkin_core::{text::TextComponent, GameMode};
|
||||
use pumpkin_core::{
|
||||
math::{position::WorldPosition, wrap_degrees},
|
||||
text::TextComponent,
|
||||
GameMode,
|
||||
};
|
||||
use pumpkin_entity::EntityId;
|
||||
use pumpkin_inventory::WindowType;
|
||||
use pumpkin_protocol::server::play::{SCloseContainer, SSetPlayerGround, SUseItem};
|
||||
@ -18,7 +22,6 @@ use pumpkin_protocol::{
|
||||
CHeadRot, CHurtAnimation, CPingResponse, CPlayerChatMessage, CUpdateEntityPos,
|
||||
CUpdateEntityPosRot, CUpdateEntityRot, CWorldEvent, FilterType,
|
||||
},
|
||||
position::WorldPosition,
|
||||
server::play::{
|
||||
Action, ActionType, SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport,
|
||||
SInteract, SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition,
|
||||
@ -46,9 +49,7 @@ impl Player {
|
||||
if let Some((id, position)) = self.awaiting_teleport.as_ref() {
|
||||
if id == &confirm_teleport.teleport_id {
|
||||
// we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported
|
||||
self.entity.x = position.x;
|
||||
self.entity.y = position.y;
|
||||
self.entity.z = position.z;
|
||||
self.entity.set_pos(position.x, position.y, position.z);
|
||||
|
||||
self.awaiting_teleport = None;
|
||||
} else {
|
||||
@ -75,21 +76,24 @@ impl Player {
|
||||
return;
|
||||
}
|
||||
let entity = &mut self.entity;
|
||||
entity.lastx = entity.x;
|
||||
entity.lasty = entity.y;
|
||||
entity.lastz = entity.z;
|
||||
entity.x = Self::clamp_horizontal(position.x);
|
||||
entity.y = Self::clamp_vertical(position.feet_y);
|
||||
entity.z = Self::clamp_horizontal(position.z);
|
||||
self.lastx = entity.pos.x;
|
||||
self.lasty = entity.pos.y;
|
||||
self.lastz = entity.pos.z;
|
||||
entity.set_pos(
|
||||
Self::clamp_horizontal(position.x),
|
||||
Self::clamp_vertical(position.feet_y),
|
||||
Self::clamp_horizontal(position.z),
|
||||
);
|
||||
// TODO: teleport when moving > 8 block
|
||||
|
||||
// send new position to all other players
|
||||
let on_ground = self.on_ground;
|
||||
let entity_id = entity.entity_id;
|
||||
let (x, lastx) = (entity.x, entity.lastx);
|
||||
let (y, lasty) = (entity.y, entity.lasty);
|
||||
let (z, lastz) = (entity.z, entity.lastz);
|
||||
let world = self.world.lock().await;
|
||||
let (x, lastx) = (entity.pos.x, self.lastx);
|
||||
let (y, lasty) = (entity.pos.y, self.lasty);
|
||||
let (z, lastz) = (entity.pos.z, self.lastz);
|
||||
let world = self.world.clone();
|
||||
let world = world.lock().await;
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
&CUpdateEntityPos::new(
|
||||
@ -100,6 +104,7 @@ impl Player {
|
||||
on_ground,
|
||||
),
|
||||
);
|
||||
player_chunker::update_position(&world, self).await;
|
||||
}
|
||||
|
||||
pub async fn handle_position_rotation(
|
||||
@ -120,25 +125,28 @@ impl Player {
|
||||
}
|
||||
let entity = &mut self.entity;
|
||||
|
||||
entity.lastx = entity.x;
|
||||
entity.lasty = entity.y;
|
||||
entity.lastz = entity.z;
|
||||
entity.x = Self::clamp_horizontal(position_rotation.x);
|
||||
entity.y = Self::clamp_vertical(position_rotation.feet_y);
|
||||
entity.z = Self::clamp_horizontal(position_rotation.z);
|
||||
self.lastx = entity.pos.x;
|
||||
self.lasty = entity.pos.y;
|
||||
self.lastz = entity.pos.z;
|
||||
entity.set_pos(
|
||||
Self::clamp_horizontal(position_rotation.x),
|
||||
Self::clamp_vertical(position_rotation.feet_y),
|
||||
Self::clamp_horizontal(position_rotation.z),
|
||||
);
|
||||
entity.yaw = wrap_degrees(position_rotation.yaw) % 360.0;
|
||||
entity.pitch = wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0;
|
||||
|
||||
// send new position to all other players
|
||||
let on_ground = self.on_ground;
|
||||
let entity_id = entity.entity_id;
|
||||
let (x, lastx) = (entity.x, entity.lastx);
|
||||
let (y, lasty) = (entity.y, entity.lasty);
|
||||
let (z, lastz) = (entity.z, entity.lastz);
|
||||
let (x, lastx) = (entity.pos.x, self.lastx);
|
||||
let (y, lasty) = (entity.pos.y, self.lasty);
|
||||
let (z, lastz) = (entity.pos.z, self.lastz);
|
||||
let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0);
|
||||
let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0);
|
||||
// let head_yaw = (entity.head_yaw * 256.0 / 360.0).floor();
|
||||
let world = self.world.lock().await;
|
||||
let world = self.world.clone();
|
||||
let world = world.lock().await;
|
||||
|
||||
world.broadcast_packet(
|
||||
&[&self.client.token],
|
||||
@ -156,6 +164,8 @@ impl Player {
|
||||
&[&self.client.token],
|
||||
&CHeadRot::new(entity_id.into(), yaw as u8),
|
||||
);
|
||||
|
||||
player_chunker::update_position(&world, self).await;
|
||||
}
|
||||
|
||||
pub async fn handle_rotation(&mut self, _server: &mut Server, rotation: SPlayerRotation) {
|
||||
@ -299,7 +309,7 @@ impl Player {
|
||||
Hand::from_i32(client_information.main_hand.into()),
|
||||
ChatMode::from_i32(client_information.chat_mode.into()),
|
||||
) {
|
||||
self.client.config = Some(PlayerConfig {
|
||||
self.config = PlayerConfig {
|
||||
locale: client_information.locale,
|
||||
view_distance: client_information.view_distance,
|
||||
chat_mode,
|
||||
@ -308,7 +318,7 @@ impl Player {
|
||||
main_hand,
|
||||
text_filtering: client_information.text_filtering,
|
||||
server_listing: client_information.server_listing,
|
||||
});
|
||||
};
|
||||
} else {
|
||||
self.kick(TextComponent::text("Invalid hand or chat type"))
|
||||
}
|
||||
|
||||
@ -2,7 +2,11 @@ use std::sync::Arc;
|
||||
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::ToPrimitive;
|
||||
use pumpkin_core::{text::TextComponent, GameMode};
|
||||
use pumpkin_core::{
|
||||
math::{boundingbox::BoundingBox, position::WorldPosition, vector3::Vector3},
|
||||
text::TextComponent,
|
||||
GameMode,
|
||||
};
|
||||
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, Entity, EntityId};
|
||||
use pumpkin_inventory::player::PlayerInventory;
|
||||
use pumpkin_protocol::{
|
||||
@ -11,7 +15,6 @@ use pumpkin_protocol::{
|
||||
CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSetEntityMetadata,
|
||||
CSyncPlayerPosition, CSystemChatMessage, Metadata, PlayerAction,
|
||||
},
|
||||
position::WorldPosition,
|
||||
server::play::{
|
||||
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
|
||||
SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation,
|
||||
@ -20,12 +23,10 @@ use pumpkin_protocol::{
|
||||
},
|
||||
ConnectionState, RawPacket, ServerPacket, VarInt,
|
||||
};
|
||||
use pumpkin_world::vector3::Vector3;
|
||||
|
||||
use crate::{
|
||||
client::{authentication::GameProfile, Client},
|
||||
client::{authentication::GameProfile, Client, PlayerConfig},
|
||||
server::Server,
|
||||
util::boundingbox::BoundingBox,
|
||||
world::World,
|
||||
};
|
||||
|
||||
@ -55,6 +56,7 @@ pub struct Player {
|
||||
pub gameprofile: GameProfile,
|
||||
pub client: Client,
|
||||
pub entity: Entity,
|
||||
pub config: PlayerConfig,
|
||||
// TODO: Put this into entity
|
||||
pub world: Arc<tokio::sync::Mutex<World>>,
|
||||
/// Current gamemode
|
||||
@ -67,6 +69,9 @@ pub struct Player {
|
||||
/// send `send_abilties_update` when changed
|
||||
pub abilities: PlayerAbilities,
|
||||
|
||||
pub lastx: f64,
|
||||
pub lasty: f64,
|
||||
pub lastz: f64,
|
||||
// Client side value, Should be not trusted
|
||||
pub on_ground: bool,
|
||||
|
||||
@ -82,6 +87,8 @@ pub struct Player {
|
||||
pub teleport_id_count: i32,
|
||||
// Current awaiting teleport id and location, None if did not teleport
|
||||
pub awaiting_teleport: Option<(VarInt, Vector3<f64>)>,
|
||||
|
||||
pub watched_section: Vector3<i32>,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
@ -103,8 +110,9 @@ impl Player {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let config = client.config.clone().unwrap_or_default();
|
||||
Self {
|
||||
config,
|
||||
gameprofile,
|
||||
client,
|
||||
entity: Entity::new(entity_id, EntityType::Player, 1.62),
|
||||
@ -123,6 +131,10 @@ impl Player {
|
||||
teleport_id_count: 0,
|
||||
abilities: PlayerAbilities::default(),
|
||||
gamemode,
|
||||
watched_section: Vector3::new(0, 0, 0),
|
||||
lastx: 0.0,
|
||||
lasty: 0.0,
|
||||
lastz: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,11 +197,11 @@ impl Player {
|
||||
assert!(self.sneaking != sneaking);
|
||||
self.sneaking = sneaking;
|
||||
self.set_flag(Self::SNEAKING_FLAG_INDEX, sneaking).await;
|
||||
if sneaking {
|
||||
self.set_pose(EntityPose::Crouching).await;
|
||||
} else {
|
||||
self.set_pose(EntityPose::Standing).await;
|
||||
}
|
||||
// if sneaking {
|
||||
// self.set_pose(EntityPose::Crouching).await;
|
||||
// } else {
|
||||
// self.set_pose(EntityPose::Standing).await;
|
||||
// }
|
||||
}
|
||||
|
||||
pub async fn set_sprinting(&mut self, sprinting: bool) {
|
||||
@ -242,12 +254,10 @@ impl Player {
|
||||
self.teleport_id_count = 0;
|
||||
}
|
||||
let entity = &mut self.entity;
|
||||
entity.x = x;
|
||||
entity.y = y;
|
||||
entity.z = z;
|
||||
entity.lastx = x;
|
||||
entity.lasty = y;
|
||||
entity.lastz = z;
|
||||
entity.set_pos(x, y, z);
|
||||
self.lastx = x;
|
||||
self.lasty = y;
|
||||
self.lastz = z;
|
||||
entity.yaw = yaw;
|
||||
entity.pitch = pitch;
|
||||
self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z)));
|
||||
@ -274,9 +284,9 @@ impl Player {
|
||||
let d = self.block_interaction_range() + additional_range;
|
||||
let box_pos = BoundingBox::from_block(pos);
|
||||
box_pos.squared_magnitude(Vector3 {
|
||||
x: self.entity.x,
|
||||
y: self.entity.y + self.entity.standing_eye_height as f64,
|
||||
z: self.entity.z,
|
||||
x: self.entity.pos.x,
|
||||
y: self.entity.pos.y + self.entity.standing_eye_height as f64,
|
||||
z: self.entity.pos.z,
|
||||
}) < d * d
|
||||
}
|
||||
|
||||
@ -441,13 +451,13 @@ impl Player {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
#[derive(FromPrimitive, Clone)]
|
||||
pub enum Hand {
|
||||
Main,
|
||||
Off,
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
#[derive(FromPrimitive, Clone)]
|
||||
pub enum ChatMode {
|
||||
Enabled,
|
||||
CommandsOnly,
|
||||
|
||||
@ -1,2 +1 @@
|
||||
pub mod boundingbox;
|
||||
pub mod math;
|
||||
|
||||
|
||||
@ -4,23 +4,25 @@ use std::{
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
};
|
||||
|
||||
pub mod player_chunker;
|
||||
|
||||
use mio::Token;
|
||||
use num_traits::ToPrimitive;
|
||||
use pumpkin_config::BasicConfiguration;
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
use pumpkin_entity::{entity_type::EntityType, EntityId};
|
||||
use pumpkin_protocol::{
|
||||
client::play::{
|
||||
CCenterChunk, CChunkData, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate,
|
||||
CRemoveEntities, CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, Metadata,
|
||||
PlayerAction,
|
||||
CChunkData, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, CRemoveEntities,
|
||||
CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, Metadata, PlayerAction,
|
||||
},
|
||||
uuid::UUID,
|
||||
ClientPacket, VarInt,
|
||||
};
|
||||
use pumpkin_world::{level::Level, radial_chunk_iterator::RadialIterator};
|
||||
use pumpkin_world::level::Level;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::entity::player::Player;
|
||||
use crate::{client::Client, entity::player::Player};
|
||||
|
||||
pub struct World {
|
||||
pub level: Arc<Mutex<Level>>,
|
||||
@ -90,7 +92,7 @@ impl World {
|
||||
// TODO: this is for debug purpose, remove later
|
||||
player
|
||||
.client
|
||||
.send_packet(&CPlayerAbilities::new(0x02, 0.1, 0.1));
|
||||
.send_packet(&CPlayerAbilities::new(0x02, 0.4, 0.1));
|
||||
|
||||
// teleport
|
||||
let x = 10.0;
|
||||
@ -191,12 +193,12 @@ impl World {
|
||||
existing_player.entity_id().into(),
|
||||
UUID(gameprofile.id),
|
||||
(EntityType::Player as i32).into(),
|
||||
entity.x,
|
||||
entity.y,
|
||||
entity.z,
|
||||
entity.pos.x,
|
||||
entity.pos.y,
|
||||
entity.pos.z,
|
||||
entity.yaw,
|
||||
entity.pitch,
|
||||
entity.pitch,
|
||||
entity.head_yaw,
|
||||
0.into(),
|
||||
0.0,
|
||||
0.0,
|
||||
@ -214,26 +216,28 @@ impl World {
|
||||
self.broadcast_packet(&[&player.client.token], &packet)
|
||||
}
|
||||
|
||||
self.spawn_test_chunk(player, base_config.view_distance as u32)
|
||||
.await;
|
||||
// Spawn in inital chunks
|
||||
player_chunker::player_join(self, player).await;
|
||||
}
|
||||
|
||||
async fn spawn_test_chunk(&self, player: &mut Player, distance: u32) {
|
||||
async fn spawn_world_chunks(
|
||||
&self,
|
||||
client: &mut Client,
|
||||
chunks: Vec<Vector2<i32>>,
|
||||
distance: i32,
|
||||
) {
|
||||
let inst = std::time::Instant::now();
|
||||
let (sender, mut chunk_receiver) = mpsc::channel(distance as usize);
|
||||
|
||||
let chunks: Vec<_> = RadialIterator::new(distance).collect();
|
||||
let level = self.level.clone();
|
||||
tokio::spawn(async move {
|
||||
level.lock().unwrap().fetch_chunks(&chunks, sender);
|
||||
});
|
||||
|
||||
player.client.send_packet(&CCenterChunk {
|
||||
chunk_x: 0.into(),
|
||||
chunk_z: 0.into(),
|
||||
});
|
||||
|
||||
while let Some(chunk_data) = chunk_receiver.recv().await {
|
||||
if client.closed {
|
||||
return;
|
||||
}
|
||||
// dbg!(chunk_pos);
|
||||
let chunk_data = match chunk_data {
|
||||
Ok(d) => d,
|
||||
@ -252,10 +256,9 @@ impl World {
|
||||
len / (1024 * 1024)
|
||||
);
|
||||
}
|
||||
player.client.send_packet(&CChunkData(&chunk_data));
|
||||
client.send_packet(&CChunkData(&chunk_data));
|
||||
}
|
||||
let t = inst.elapsed();
|
||||
dbg!("DONE", t);
|
||||
dbg!("DONE CHUNKS", inst.elapsed());
|
||||
}
|
||||
|
||||
/// TODO: This definitly should be in world
|
||||
@ -283,12 +286,10 @@ impl World {
|
||||
// todo: put this into the entitiy struct
|
||||
let id = player.entity_id();
|
||||
let uuid = player.gameprofile.id;
|
||||
dbg!("1");
|
||||
self.broadcast_packet(
|
||||
&[&player.client.token],
|
||||
&CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]),
|
||||
);
|
||||
dbg!("2");
|
||||
self.broadcast_packet(&[&player.client.token], &CRemoveEntities::new(&[id.into()]))
|
||||
}
|
||||
}
|
||||
|
||||
102
pumpkin/src/world/player_chunker.rs
Normal file
102
pumpkin/src/world/player_chunker.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use pumpkin_config::BASIC_CONFIG;
|
||||
use pumpkin_core::math::{
|
||||
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
|
||||
};
|
||||
use pumpkin_protocol::client::play::{CCenterChunk, CUnloadChunk};
|
||||
use pumpkin_world::cylindrical_chunk_iterator::Cylindrical;
|
||||
|
||||
use crate::entity::player::Player;
|
||||
|
||||
use super::World;
|
||||
|
||||
fn get_view_distance(player: &Player) -> i8 {
|
||||
player
|
||||
.config
|
||||
.view_distance
|
||||
.clamp(2, BASIC_CONFIG.view_distance as i8)
|
||||
}
|
||||
|
||||
pub async fn player_join(world: &World, player: &mut Player) {
|
||||
let new_watched = chunk_section_from_pos(&player.entity.block_pos);
|
||||
player.watched_section = new_watched;
|
||||
let chunk_pos = player.entity.chunk_pos;
|
||||
player.client.send_packet(&CCenterChunk {
|
||||
chunk_x: chunk_pos.x.into(),
|
||||
chunk_z: chunk_pos.z.into(),
|
||||
});
|
||||
let view_distance = get_view_distance(player) as i32;
|
||||
dbg!(view_distance);
|
||||
let old_cylindrical = Cylindrical::new(
|
||||
Vector2::new(player.watched_section.x, player.watched_section.z),
|
||||
view_distance,
|
||||
);
|
||||
let new_cylindrical = Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance);
|
||||
let mut loading_chunks = Vec::new();
|
||||
Cylindrical::for_each_changed_chunk(
|
||||
old_cylindrical,
|
||||
new_cylindrical,
|
||||
|chunk_pos| {
|
||||
loading_chunks.push(chunk_pos);
|
||||
},
|
||||
|chunk_pos| {
|
||||
player
|
||||
.client
|
||||
.send_packet(&CUnloadChunk::new(chunk_pos.x, chunk_pos.z));
|
||||
},
|
||||
true,
|
||||
);
|
||||
if !loading_chunks.is_empty() {
|
||||
world
|
||||
.spawn_world_chunks(&mut player.client, loading_chunks, view_distance)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_position(world: &World, player: &mut Player) {
|
||||
let current_watched = player.watched_section;
|
||||
let new_watched = chunk_section_from_pos(&player.entity.block_pos);
|
||||
if current_watched != new_watched {
|
||||
let chunk_pos = player.entity.chunk_pos;
|
||||
player.client.send_packet(&CCenterChunk {
|
||||
chunk_x: chunk_pos.x.into(),
|
||||
chunk_z: chunk_pos.z.into(),
|
||||
});
|
||||
|
||||
let view_distance = get_view_distance(player) as i32;
|
||||
let old_cylindrical = Cylindrical::new(
|
||||
Vector2::new(player.watched_section.x, player.watched_section.z),
|
||||
view_distance,
|
||||
);
|
||||
let new_cylindrical =
|
||||
Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance);
|
||||
player.watched_section = new_watched;
|
||||
let mut loading_chunks = Vec::new();
|
||||
Cylindrical::for_each_changed_chunk(
|
||||
old_cylindrical,
|
||||
new_cylindrical,
|
||||
|chunk_pos| {
|
||||
loading_chunks.push(chunk_pos);
|
||||
},
|
||||
|chunk_pos| {
|
||||
player
|
||||
.client
|
||||
.send_packet(&CUnloadChunk::new(chunk_pos.x, chunk_pos.z));
|
||||
},
|
||||
false,
|
||||
);
|
||||
if !loading_chunks.is_empty() {
|
||||
world
|
||||
.spawn_world_chunks(&mut player.client, loading_chunks, view_distance)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn chunk_section_from_pos(block_pos: &WorldPosition) -> Vector3<i32> {
|
||||
let block_pos = block_pos.0;
|
||||
Vector3::new(
|
||||
get_section_cord(block_pos.x),
|
||||
get_section_cord(block_pos.y),
|
||||
get_section_cord(block_pos.z),
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user