Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
Merge branch 'light-updates' into tracing-system
Browse files Browse the repository at this point in the history
  • Loading branch information
DimitriTimoz committed Dec 24, 2023
2 parents 2eb5b4d + 34d2e14 commit a610fdf
Show file tree
Hide file tree
Showing 15 changed files with 1,341 additions and 126 deletions.
13 changes: 13 additions & 0 deletions minecraft-positions/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod shards;

use std::ops::{AddAssign, Add};

pub use minecraft_protocol::packets::Position as NetworkPosition;

#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
Expand Down Expand Up @@ -175,6 +177,17 @@ pub struct ChunkColumnPosition {
pub cz: i32,
}

impl Add<ChunkColumnPosition> for ChunkColumnPosition {
type Output = ChunkColumnPosition;

fn add(self, rhs: ChunkColumnPosition) -> Self::Output {
ChunkColumnPosition {
cx: self.cx + rhs.cx,
cz: self.cz + rhs.cz,
}
}
}

impl ChunkColumnPosition {
pub fn chunk(&self, cy: i32) -> ChunkPosition {
ChunkPosition {
Expand Down
5 changes: 4 additions & 1 deletion minecraft-positions/src/shards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use crate::*;

impl ChunkColumnPosition {
pub fn shard(&self, shard_count: usize) -> usize {
(self.cx + self.cz).unsigned_abs() as usize % shard_count
const REGION_SIZE: i32 = 8;
let region_x = self.cx.div_euclid(REGION_SIZE);
let region_z = self.cz.div_euclid(REGION_SIZE);
(region_x + region_z).unsigned_abs() as usize % shard_count
}
}
7 changes: 7 additions & 0 deletions minecraft-protocol/build/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ pub enum Item {{
{variants}
}}
impl Default for Item {{
#[inline]
fn default() -> Self {{
Item::Air
}}
}}
impl Item {{
#[inline]
pub fn from_id(id: u32) -> Option<Item> {{
Expand Down
10 changes: 5 additions & 5 deletions minecraft-protocol/src/components/chunk.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{nbt::NbtTag, *, components::blocks::BlockEntity};
use crate::{nbt::NbtTag, *, components::blocks::BlockEntity, packets::serializer::BitSet};

/// A complex data structure including block data and optionally entities of a chunk.
///
Expand All @@ -24,19 +24,19 @@ pub struct ChunkData<'a> {
/// BitSet containing bits for each section in the world + 2.
/// Each set bit indicates that the corresponding 16×16×16 chunk section has data in the Sky Light array below.
/// The least significant bit is for blocks 16 blocks to 1 block below the min world height (one section below the world), while the most significant bit covers blocks 1 to 16 blocks above the max world height (one section above the world).
pub sky_light_mask: Array<'a, u64, VarInt>,
pub sky_light_mask: BitSet<'a>,
/// BitSet containing bits for each section in the world + 2.
/// Each set bit indicates that the corresponding 16×16×16 chunk section has data in the Block Light array below.
/// The order of bits is the same as in Sky Light Mask.
pub block_light_mask: Array<'a, u64, VarInt>,
pub block_light_mask: BitSet<'a>,
/// BitSet containing bits for each section in the world + 2.
/// Each set bit indicates that the corresponding 16×16×16 chunk section has data in the Block Light array below.
/// The order of bits is the same as in Sky Light Mask.
pub empty_sky_light_mask: Array<'a, u64, VarInt>,
pub empty_sky_light_mask: BitSet<'a>,
/// BitSet containing bits for each section in the world + 2.
/// Each set bit indicates that the corresponding 16×16×16 chunk section has data in the Block Light array below.
/// The order of bits is the same as in Sky Light Mask.
pub empty_block_light_mask: Array<'a, u64, VarInt>,
pub empty_block_light_mask: BitSet<'a>,
/// Length should match the number of bits set in Sky Light Mask.
/// Each entry is an array of 2048 bytes.
/// There is 1 array for each bit set to true in the sky light mask, starting with the lowest value. Half a byte per light value. Indexed ((y<<8) | (z<<4) | x) / 2
Expand Down
2 changes: 1 addition & 1 deletion minecraft-protocol/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ pub mod slots;
pub mod sound;
pub mod tags;
pub mod teams;
pub mod trades;
pub mod trades;
2 changes: 1 addition & 1 deletion minecraft-protocol/src/components/slots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub struct Slot {
}

#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug, Clone, MinecraftPacketPart)]
#[derive(Debug, Clone, Default, MinecraftPacketPart)]
pub struct SlotItem {
/// The [item](crate::ids::items::Item).
/// Item IDs are distinct from [block IDs](crate::ids::blocks::Block); see [crate::ids] for more information.
Expand Down
6 changes: 6 additions & 0 deletions minecraft-protocol/src/nbt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ pub enum NbtTag {
RootCompound(String, HashMap<String, NbtTag>),
}

impl Default for NbtTag {
fn default() -> Self {
NbtTag::Null
}
}

impl NbtTag {
#[inline]
pub fn is_null(&self) -> bool {
Expand Down
16 changes: 14 additions & 2 deletions minecraft-protocol/src/packets/play_clientbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,20 @@ pub enum ClientboundPacket<'a> {

/// Updates light levels for a chunk
UpdateLight {
/// TODO: parse this
data: RawBytes<'a>,
/// Chunk coordinate (block coordinate divided by 16, rounded down)
cx: VarInt,
/// Chunk coordinate (block coordinate divided by 16, rounded down)
cz: VarInt,
/// BitSet containing bits for each section in the world + 2. Each set bit indicates that the corresponding 16×16×16 chunk section has data in the Sky Light array below. The least significant bit is for blocks 16 blocks to 1 block below the min world height (one section below the world), while the most significant bit covers blocks 1 to 16 blocks above the max world height (one section above the world).
sky_light_mask: BitSet<'a>,
/// BitSet containing bits for each section in the world + 2. Each set bit indicates that the corresponding 16×16×16 chunk section has data in the Block Light array below. The order of bits is the same as in Sky Light Mask.
block_light_mask: BitSet<'a>,
/// BitSet containing bits for each section in the world + 2. Each set bit indicates that the corresponding 16×16×16 chunk section has all zeros for its Sky Light data. The order of bits is the same as in Sky Light Mask.
empty_sky_light_mask: BitSet<'a>,
/// BitSet containing bits for each section in the world + 2. Each set bit indicates that the corresponding 16×16×16 chunk section has all zeros for its Block Light data. The order of bits is the same as in Sky Light Mask.
empty_block_light_mask: BitSet<'a>,
sky_light_arrays: Array<'a, Array<'a, u8, VarInt>, VarInt>,
block_light_arrays: Array<'a, Array<'a, u8, VarInt>, VarInt>,
},

/// See [Protocol Encryption](https://wiki.vg/Protocol_Encryption) for information on logging in.
Expand Down
58 changes: 24 additions & 34 deletions minecraft-server/src/entities/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ impl Handler<Player> {
if loaded_chunks_after == player.loaded_chunks { return (None, EntityChanges::nothing()) };
let mut newly_loaded_chunks: Vec<_> = loaded_chunks_after.difference(&player.loaded_chunks).cloned().collect();
let unloaded_chunks: Vec<_> = player.loaded_chunks.difference(&loaded_chunks_after).cloned().collect();
for skipped in newly_loaded_chunks.iter().skip(50) {
for skipped in newly_loaded_chunks.iter().skip(2) {
loaded_chunks_after.remove(skipped);
}
newly_loaded_chunks.truncate(50);
newly_loaded_chunks.truncate(2);
let uuid = player.info.uuid;
player.loaded_chunks = loaded_chunks_after.clone();
(Some((loaded_chunks_after, newly_loaded_chunks, unloaded_chunks, uuid)), EntityChanges::other())
Expand All @@ -129,39 +129,17 @@ impl Handler<Player> {
self.world.update_loaded_chunks(uuid, loaded_chunks_after).await;

// Send the chunks to the client
let mut heightmaps = HashMap::new();
heightmaps.insert(String::from("MOTION_BLOCKING"), NbtTag::LongArray(vec![0; 37]));
let heightmaps = NbtTag::Compound(heightmaps);
let mut chunks = Vec::new();
for newly_loaded_chunk in newly_loaded_chunks {
let mut column = Vec::new();
for cy in -4..20 {
let chunk = self.world.get_network_chunk(newly_loaded_chunk.chunk(cy)).await.unwrap_or_else(|| {
error!("Chunk not loaded: {newly_loaded_chunk:?}");
NetworkChunk { // TODO hard error
block_count: 0,
blocks: PalettedData::Single { value: 0 },
biomes: PalettedData::Single { value: 4 },
}
});
column.push(chunk);
}
let serialized: Vec<u8> = NetworkChunk::into_data(column).unwrap();
let chunk_data = PlayClientbound::ChunkData {
value: ChunkData {
chunk_x: newly_loaded_chunk.cx,
chunk_z: newly_loaded_chunk.cz,
heightmaps: heightmaps.clone(),
data: Array::from(serialized.clone()),
block_entities: Array::default(),
sky_light_mask: Array::default(),
block_light_mask: Array::default(),
empty_sky_light_mask: Array::default(),
empty_block_light_mask: Array::default(),
sky_light: Array::default(),
block_light: Array::default(),
}
};
self.send_packet(chunk_data).await;
let chunk = self.world.get_network_chunk_column_data(newly_loaded_chunk.clone()).await.unwrap_or_else(|| {
error!("Chunk not loaded: {newly_loaded_chunk:?}");
panic!("Chunk not loaded: {newly_loaded_chunk:?}");
});
chunks.push(chunk);
}

for chunk in chunks {
self.send_raw_packet(chunk).await;
}

// Tell the client to unload chunks
Expand All @@ -188,6 +166,18 @@ impl Handler<Player> {
}

#[instrument(skip_all)]
async fn send_raw_packet(&self, packet: Vec<u8>) {
let packets_sent = self.mutate(|player| {
player.packets_sent += 1;
(player.packets_sent, EntityChanges::other())
}).await.unwrap_or(0);
if packets_sent > 500 {
warn!("Many packets sent ({packets_sent})");
}
let Some(packet_sender) = self.observe(|player| player.packet_sender.clone()).await else {return};
packet_sender.send(packet).await.unwrap();
}

async fn on_server_message(self, message: ServerMessage) {
use ServerMessage::*;
match message {
Expand Down
43 changes: 9 additions & 34 deletions minecraft-server/src/player_handler/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ pub async fn handshake(stream: &mut TcpStream, logged_in_player_info: LoggedInPl
debug!("ChunkBatchStart sent");

let change_receiver = world.add_loader(logged_in_player_info.uuid).await;
// TODO: Move chunk loading
let mut loaded_chunks = HashSet::new();
for cx in -3..=3 {
for cz in -3..=3 {
Expand All @@ -317,43 +318,18 @@ pub async fn handshake(stream: &mut TcpStream, logged_in_player_info: LoggedInPl
}
world.update_loaded_chunks(logged_in_player_info.uuid, loaded_chunks).await;

let mut heightmaps = HashMap::new();
heightmaps.insert(String::from("MOTION_BLOCKING"), NbtTag::LongArray(vec![0; 37]));
let heightmaps = NbtTag::Compound(heightmaps);


for cx in -3..=3 {
for cz in -3..=3 {
let mut column = Vec::new();
for cy in -4..20 {
let chunk = world.get_network_chunk(ChunkPosition { cx, cy, cz }).await.unwrap_or_else(|| {
error!("Chunk not loaded: {cx} {cy} {cz}");
NetworkChunk { // TODO hard error
block_count: 0,
blocks: PalettedData::Single { value: 0 },
biomes: PalettedData::Single { value: 4 },
}
});
column.push(chunk);
}
let serialized: Vec<u8> = NetworkChunk::into_data(column).unwrap();
let chunk_data = PlayClientbound::ChunkData {
value: ChunkData {
chunk_x: cx,
chunk_z: cz,
heightmaps: heightmaps.clone(),
data: Array::from(serialized.clone()),
block_entities: Array::default(),
sky_light_mask: Array::default(),
block_light_mask: Array::default(),
empty_sky_light_mask: Array::default(),
empty_block_light_mask: Array::default(),
sky_light: Array::default(),
block_light: Array::default(),
}
};
send_packet(stream, chunk_data).await;
let chunk_column = world.get_network_chunk_column_data(ChunkColumnPosition { cx, cz }).await.unwrap_or_else(|| {
error!("Chunk not loaded: {cx} {cz}");
panic!("Chunk not loaded: {cx} {cz}");
});

send_packet_raw(stream, &chunk_column).await;
}
}

debug!("ChunkData sent");

// Chunk batch end
Expand All @@ -369,7 +345,6 @@ pub async fn handshake(stream: &mut TcpStream, logged_in_player_info: LoggedInPl
return Err(());
};
debug!("ChunkBatchAcknoledgement received");

Ok((PlayerInfo {
addr: logged_in_player_info.addr,
username: logged_in_player_info.username,
Expand Down
Loading

0 comments on commit a610fdf

Please sign in to comment.