Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

World Loading (woohoo) #28

Merged
merged 5 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
309 changes: 115 additions & 194 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions pumpkin-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition.workspace = true

[dependencies]
pumpkin-macros = { path = "../pumpkin-macros" }
pumpkin-world = { path = "../pumpkin-world" }
pumpkin-text = { path = "../pumpkin-text" }

bytes = "1.7"
Expand All @@ -26,3 +27,5 @@ num-derive = "0.4"
aes = "0.8.4"
cfb8 = "0.8.1"
take_mut = "0.2.2"
itertools = "0.13.0"
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
12 changes: 11 additions & 1 deletion pumpkin-protocol/src/bytebuf/packet_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer,
};

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

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

impl Serialize for BitSet {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// TODO: make this right
(self.0.clone(), self.1.clone()).serialize(serializer)
}
}

impl Serialize for VarInt {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down
10 changes: 10 additions & 0 deletions pumpkin-protocol/src/client/play/c_center_chunk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use pumpkin_macros::packet;

use crate::VarInt;

#[derive(serde::Serialize)]
#[packet(0x54)]
pub struct CCenterChunk {
pub chunk_x: VarInt,
pub chunk_z: VarInt
}
134 changes: 134 additions & 0 deletions pumpkin-protocol/src/client/play/c_chunk_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use std::collections::HashMap;

use crate::{bytebuf::ByteBuffer, BitSet, ClientPacket, VarInt};
use fastnbt::LongArray;
use itertools::Itertools;
use pumpkin_macros::packet;
use pumpkin_world::{chunk::ChunkData, DIRECT_PALETTE_BITS};

#[packet(0x27)]
pub struct CChunkData<'a>(pub &'a ChunkData);

impl<'a> ClientPacket for CChunkData<'a> {
fn write(&self, buf: &mut crate::bytebuf::ByteBuffer) {
// Chunk X
buf.put_i32(self.0.position.0);
// Chunk Z
buf.put_i32(self.0.position.1);

let heightmap_nbt =
fastnbt::to_bytes_with_opts(&self.0.heightmaps, fastnbt::SerOpts::network_nbt())
.unwrap();
// Heightmaps
buf.put_slice(&heightmap_nbt);

let mut data_buf = ByteBuffer::empty();
self.0
.blocks
.iter()
.chunks(16 * 16 * 16)
.into_iter()
.for_each(|chunk| {
let chunk = chunk.collect_vec();
let block_count = chunk
.iter()
.filter(|block| ***block != 0 && ***block != 12959 && ***block != 12958)
.count() as i16;
// Block count
data_buf.put_i16(block_count);
//// Block states

let palette = chunk.clone().into_iter().dedup().collect_vec();
// TODO: make dynamic block_size work
// TODO: make direct block_size work
enum PaletteType {
Indirect(u32),
Direct,
}
let palette_type = {
let palette_bit_len = 64 - (palette.len() as i64 - 1).leading_zeros();
if palette_bit_len > 8 {
PaletteType::Direct
} else if palette_bit_len > 3 {
PaletteType::Indirect(palette_bit_len)
} else {
PaletteType::Indirect(4)
}
// TODO: fix indirect palette to work correctly
// PaletteType::Direct
};

let mut block_data_array = Vec::new();
match palette_type {
PaletteType::Indirect(block_size) => {
// Bits per entry
data_buf.put_u8(block_size as u8);
// Palette length
data_buf.put_var_int(&VarInt(palette.len() as i32));
let mut palette_map = HashMap::new();
palette.iter().enumerate().for_each(|(i, id)| {
palette_map.insert(**id, i);
// Palette
data_buf.put_var_int(&VarInt(**id as i32));
});
for block_clump in chunk.chunks(64 / block_size as usize) {
let mut out_long: i64 = 0;
for block in block_clump.iter().rev() {
let index = palette_map
.get(*block)
.expect("Its just got added, ofc it should be there");
out_long = out_long << block_size | (*index as i64);
}
block_data_array.push(out_long);
}
}
PaletteType::Direct => {
// Bits per entry
data_buf.put_u8(DIRECT_PALETTE_BITS as u8);
for block_clump in chunk.chunks(64 / DIRECT_PALETTE_BITS as usize) {
let mut out_long: i64 = 0;
for block in block_clump.iter().rev() {
out_long = out_long << DIRECT_PALETTE_BITS | (**block as i64);
}
block_data_array.push(out_long);
}
}
}

// Data array length
// TODO: precompute this and omit making the `block_data_array`
data_buf.put_var_int(&VarInt(block_data_array.len() as i32));
// Data array
for data_int in block_data_array {
data_buf.put_i64(data_int);
}

//// Biomes
// TODO: make biomes work
data_buf.put_u8(0);
data_buf.put_var_int(&VarInt(0));
data_buf.put_var_int(&VarInt(0));
});

// Size
buf.put_var_int(&VarInt(data_buf.buf().len() as i32));
// Data
buf.put_slice(&data_buf.buf());

// TODO: block entities
buf.put_var_int(&VarInt(0));

// TODO
buf.put_bit_set(&BitSet(VarInt(1), vec![0]));
buf.put_bit_set(&BitSet(VarInt(1), vec![0]));
buf.put_bit_set(&BitSet(VarInt(1), vec![0]));
buf.put_bit_set(&BitSet(VarInt(1), vec![0]));
// buf.put_bit_set(&BitSet(VarInt(0), vec![]));
// buf.put_bit_set(&BitSet(VarInt(0), vec![]));
// buf.put_bit_set(&BitSet(VarInt(0), vec![]));
// buf.put_bit_set(&BitSet(VarInt(0), vec![]));

buf.put_var_int(&VarInt(0));
buf.put_var_int(&VarInt(0));
}
}
4 changes: 4 additions & 0 deletions pumpkin-protocol/src/client/play/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod c_center_chunk;
mod c_actionbar;
mod c_change_difficulty;
mod c_chunk_data;
mod c_chunk_data_update_light;
mod c_disguised_chat_message;
mod c_entity_animation;
Expand All @@ -25,8 +27,10 @@ mod c_update_entity_pos;
mod c_update_entity_rot;
mod player_action;

pub use c_center_chunk::*;
pub use c_actionbar::*;
pub use c_change_difficulty::*;
pub use c_chunk_data::*;
pub use c_chunk_data_update_light::*;
pub use c_disguised_chat_message::*;
pub use c_entity_animation::*;
Expand Down
2 changes: 1 addition & 1 deletion pumpkin-protocol/src/packet_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl PacketEncoder {
.encode(&mut writer)
.map_err(|_| PacketError::EncodeID)?;
packet.write(&mut packet_buf);

writer
.write(packet_buf.buf())
.map_err(|_| PacketError::EncodeFailedWrite)?;
Expand Down
12 changes: 9 additions & 3 deletions pumpkin-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ version.workspace = true
edition.workspace = true

[dependencies]
pumpkin-protocol = { path = "../pumpkin-protocol"}
fastanvil = "0.31"
# fastanvil = "0.31"
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
fastsnbt = "0.2"
tokio.workspace = true
tokio.workspace = true
itertools = "0.13.0"
thiserror = "1.0.63"
futures = "0.3.30"
flate2 = "1.0.31"
serde = { version = "1.0.205", features = ["derive"] }
lazy_static = "1.5.0"
serde_json = "1.0.122"
Loading