diff --git a/src/main.rs b/src/main.rs index 5518761..af97119 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,16 +17,13 @@ * . */ -use std::{ - fs::OpenOptions, - sync::{Arc, LazyLock}, - time::Duration, -}; +use std::{fs::OpenOptions, sync::Arc}; use color_eyre::eyre::Result; +use net::cache::WorldCache; use server::Server; use tracing_subscriber::{layer::SubscriberExt, prelude::*, EnvFilter}; -use world::{blocks::ALL_BLOCKS, cache::WorldCache, read_world}; +use world::{blocks::ALL_BLOCKS, read_world}; #[macro_use] extern crate tracing; diff --git a/src/net/cache.rs b/src/net/cache.rs new file mode 100644 index 0000000..477131c --- /dev/null +++ b/src/net/cache.rs @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Andrew Brower. + * This file is part of Crawlspace. + * + * Crawlspace is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Crawlspace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Crawlspace. If not, see + * . + */ + +use std::cmp::Ordering; + +use crate::{ + protocol::{ + datatypes::VarInt, + packets::{ + login::registry::{AllRegistries, DimensionType, Registry}, + play::ChunkDataUpdateLightC, + }, + Encoder, + }, + world::World, +}; + +#[derive(Debug)] +pub struct WorldCache { + pub encoded: Vec>, +} + +impl From for WorldCache { + fn from(world: World) -> Self { + let mut chunks = world.0.iter().collect::>(); + + chunks.sort_by(|((ax, az), _), ((bx, bz), _)| { + if (ax + az) > (bx + bz) { + Ordering::Greater + } else { + Ordering::Less + } + }); + + let chunks = chunks + .iter() + .map(|(_, c)| ChunkDataUpdateLightC::from(*c)) + .collect::>>(); + + let mut encoder = Encoder::new(); + let mut encoded = Vec::with_capacity(chunks.len()); + + chunks.iter().for_each(|chunk| { + encoder + .append_packet(chunk) + .expect("Failed to append packet to encoder"); + encoded.push(encoder.take().to_vec()); + }); + + Self { encoded } + } +} + +#[derive(Debug)] +pub struct RegistryCache { + pub encoded: Vec, + pub the_end_id: VarInt, +} + +impl From<&AllRegistries> for RegistryCache { + fn from(registry: &AllRegistries) -> Self { + let mut encoder = Encoder::new(); + + let dimensions = Registry::from(registry.dimension_type.clone()); + encoder + .append_packet(&Registry::from(registry.trim_material.clone())) + .expect("Failed to encode trim material"); + encoder + .append_packet(&Registry::from(registry.trim_pattern.clone())) + .expect("Failed to encode trim pattern"); + encoder + .append_packet(&Registry::from(registry.banner_pattern.clone())) + .expect("Failed to encode banner pattern"); + encoder + .append_packet(&Registry::from(registry.biome.clone())) + .expect("Failed to encode biome"); + encoder + .append_packet(&Registry::from(registry.chat_type.clone())) + .expect("Failed to encode chat type"); + encoder + .append_packet(&Registry::from(registry.damage_type.clone())) + .expect("Failed to encode damage type"); + encoder + .append_packet(&dimensions) + .expect("Failed to encode dimensions"); + encoder + .append_packet(&Registry::from(registry.wolf_variant.clone())) + .expect("Failed to encode wolf variants"); + encoder + .append_packet(&Registry::from(registry.painting_variant.clone())) + .expect("Failed to encode painting variants"); + + Self { + encoded: encoder.take().to_vec(), + the_end_id: VarInt(dimensions.index_of("minecraft:the_end")), + } + } +} diff --git a/src/net/mod.rs b/src/net/mod.rs index d149028..5ffdc21 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -21,9 +21,11 @@ use color_eyre::eyre::Result; use player::SharedPlayer; use tokio::net::TcpListener; -mod io; +pub mod cache; pub mod player; +mod io; + use crate::CrawlState; #[cfg(feature = "lan")] diff --git a/src/net/player.rs b/src/net/player.rs index 0a5de98..14fda98 100644 --- a/src/net/player.rs +++ b/src/net/player.rs @@ -38,12 +38,11 @@ use crate::{ packets::{ login::*, play::{ - ChunkDataUpdateLightC, ConfirmTeleportS, GameEvent, GameEventC, Gamemode, - KeepAliveC, LoginPlayC, PlayerInfoUpdateC, PlayerStatus, SetCenterChunkC, - SynchronisePositionC, + ConfirmTeleportS, GameEvent, GameEventC, Gamemode, KeepAliveC, LoginPlayC, + PlayerInfoUpdateC, PlayerStatus, SetCenterChunkC, SynchronisePositionC, }, }, - PacketState, Property, + PacketState, }, CrawlState, }; @@ -64,14 +63,11 @@ pub struct Player { uuid: RwLock>, tp_state: Mutex, - - // FIXME: uh - the_end_id: Mutex, } #[derive(Debug)] enum TeleportState { - Pending(i32, time::Instant), + Pending(i32), Clear, } @@ -96,8 +92,6 @@ impl SharedPlayer { packet_state: RwLock::new(PacketState::Handshaking), tp_state: Mutex::new(TeleportState::Clear), - - the_end_id: Mutex::new(0), })) } @@ -240,28 +234,7 @@ impl SharedPlayer { // TODO: maybe(?) actually handle this io.rx::().await?; - let registry = &*registry::ALL_REGISTRIES; - let dimensions = Registry::from(registry.dimension_type.clone()); - io.tx(&Registry::from(registry.trim_material.clone())) - .await?; - io.tx(&Registry::from(registry.trim_pattern.clone())) - .await?; - io.tx(&Registry::from(registry.banner_pattern.clone())) - .await?; - io.tx(&Registry::from(registry.biome.clone())).await?; - io.tx(&Registry::from(registry.chat_type.clone())).await?; - io.tx(&Registry::from(registry.damage_type.clone())).await?; - io.tx(&dimensions) - .await?; - io.tx(&Registry::from(registry.wolf_variant.clone())) - .await?; - io.tx(&Registry::from(registry.painting_variant.clone())) - .await?; - - { - let mut the_end_id = self.0.the_end_id.lock().await; - *the_end_id = dimensions.index_of("minecraft:the_end"); - } + io.tx_raw(&state.registry_cache.encoded).await?; io.tx(&FinishConfigurationC).await?; io.rx::().await?; @@ -291,11 +264,6 @@ impl SharedPlayer { let max_players: i32 = state.max_players.try_into().unwrap_or(50); - let the_end_id = { - let the_end_id = self.0.the_end_id.lock().await; - *the_end_id - }; - let login = LoginPlayC { entity_id: self.0.id as i32, is_hardcore: false, @@ -306,7 +274,7 @@ impl SharedPlayer { reduced_debug_info: !cfg!(debug_assertions), enable_respawn_screen: false, do_limited_crafting: false, - dimension_type: VarInt(the_end_id), + dimension_type: state.registry_cache.the_end_id, dimension_name: Bounded::<&'static str>("minecraft:the_end"), hashed_seed: 0, gamemode: Gamemode::Creative, @@ -384,7 +352,7 @@ impl SharedPlayer { let tp_state = self.0.tp_state.lock().await; match *tp_state { TeleportState::Clear => Err(TeleportError::Unexpected), - TeleportState::Pending(expected, _) => match id == expected { + TeleportState::Pending(expected) => match id == expected { true => Ok(()), false => Err(TeleportError::WrongId(expected, id)), }, @@ -410,7 +378,7 @@ impl SharedPlayer { { let mut tp_state = self.0.tp_state.lock().await; // player will be given 5 (FIVE) SECONDS TO ACK!!!!! - *tp_state = TeleportState::Pending(tp.id, time::Instant::now()); + *tp_state = TeleportState::Pending(tp.id); } io.tx(&tp).await?; diff --git a/src/protocol/packets/login/registry/dimension.rs b/src/protocol/packets/login/registry/dimension.rs index 501bdbc..d52d1de 100644 --- a/src/protocol/packets/login/registry/dimension.rs +++ b/src/protocol/packets/login/registry/dimension.rs @@ -17,13 +17,11 @@ * . */ -use std::sync::LazyLock; use serde::{Deserialize, Serialize}; -use crate::protocol::datatypes::VarInt; -use super::{RegistryItem, ALL_REGISTRIES}; +use super::RegistryItem; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DimensionType { diff --git a/src/protocol/packets/login/registry/mod.rs b/src/protocol/packets/login/registry/mod.rs index 0dd4862..0aec76f 100644 --- a/src/protocol/packets/login/registry/mod.rs +++ b/src/protocol/packets/login/registry/mod.rs @@ -50,12 +50,17 @@ pub static ALL_REGISTRIES: LazyLock = LazyLock::new(|| { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Registry { registry_id: String, - entries: Vec>, + pub entries: Vec>, } impl Registry { pub fn index_of(&self, id: &str) -> i32 { - self.entries.iter().position(|e| e.id == id).unwrap_or_else(|| panic!("Element {id} should be in registry {}!", self.registry_id)).try_into().unwrap() + self.entries + .iter() + .position(|e| e.id == id) + .unwrap_or_else(|| panic!("Element {id} should be in registry {}!", self.registry_id)) + .try_into() + .unwrap() } } diff --git a/src/protocol/packets/play/keepalive.rs b/src/protocol/packets/play/keepalive.rs index b77ac7f..5d28e21 100644 --- a/src/protocol/packets/play/keepalive.rs +++ b/src/protocol/packets/play/keepalive.rs @@ -33,6 +33,7 @@ impl Encode for KeepAliveC { } #[derive(Debug)] +#[expect(unused)] pub struct KeepAliveS(i64); impl Packet for KeepAliveS { diff --git a/src/protocol/packets/play/status.rs b/src/protocol/packets/play/status.rs index 4d404c1..f356049 100644 --- a/src/protocol/packets/play/status.rs +++ b/src/protocol/packets/play/status.rs @@ -109,6 +109,7 @@ impl PlayerAction<'_> { } } +#[allow(unused)] impl<'a> PlayerStatus<'a> { pub fn for_player(player: Uuid) -> Self { Self { diff --git a/src/protocol/packets/play/teleport.rs b/src/protocol/packets/play/teleport.rs index 34e61cf..e5a17e6 100644 --- a/src/protocol/packets/play/teleport.rs +++ b/src/protocol/packets/play/teleport.rs @@ -34,6 +34,7 @@ pub struct SynchronisePositionC { pub id: i32, } +#[allow(unused)] mod flags { pub const X: i8 = 0x01; pub const Y: i8 = 0x02; @@ -42,6 +43,7 @@ mod flags { pub const X_ROT: i8 = 0x10; } +#[allow(unused)] impl SynchronisePositionC { pub fn new(x: f64, y: f64, z: f64, yaw: f32, pitch: f32) -> Self { Self { diff --git a/src/protocol/packets/play/world.rs b/src/protocol/packets/play/world.rs index 0cb31d8..d407762 100644 --- a/src/protocol/packets/play/world.rs +++ b/src/protocol/packets/play/world.rs @@ -20,15 +20,14 @@ use std::collections::HashMap; use bit_vec::BitVec; -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use fastnbt::SerOpts; -use serde::Serialize; use crate::{ - protocol::{datatypes::VarInt, packets::login::registry::Registry, Encode, Packet}, + protocol::{datatypes::VarInt, Encode, Packet}, world::{ self, - blocks::{BlockState, Blocks, ALL_BLOCKS}, + blocks::BlockState, }, }; diff --git a/src/server/mod.rs b/src/server/mod.rs index b8c75a8..de9c1d9 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -19,15 +19,12 @@ pub mod ticker; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use color_eyre::eyre::Result; -use tokio::time; use crate::{ - net::player::SharedPlayer, - protocol::packets::play::ChunkDataUpdateLightC, - world::{cache::WorldCache, World}, + net::{cache::WorldCache, player::SharedPlayer}, CrawlState, }; @@ -68,7 +65,7 @@ impl Server { let mut io = player.0.io.lock().await; for packet in world_cache.encoded.iter() { - io.tx_raw(packet.as_slice()).await?; + io.tx_raw(packet).await?; } Ok(()) diff --git a/src/state.rs b/src/state.rs index 02788a6..7795a1b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -22,7 +22,10 @@ use std::sync::{atomic::AtomicUsize, Arc}; use tokio::sync::{mpsc, Mutex, Semaphore}; use tokio_util::sync::CancellationToken; -use crate::net::player::SharedPlayer; +use crate::{ + net::{cache::RegistryCache, player::SharedPlayer}, + protocol::packets::login::registry::ALL_REGISTRIES, +}; #[derive(Debug)] pub struct State { @@ -33,6 +36,8 @@ pub struct State { pub version_number: i32, pub port: u16, + pub registry_cache: RegistryCache, + pub player_send: mpsc::Sender, pub player_recv: Mutex>, @@ -67,6 +72,8 @@ impl State { version_number: version_number.to_owned(), port, + registry_cache: RegistryCache::from(&*ALL_REGISTRIES), + player_send, player_recv: Mutex::new(player_recv), diff --git a/src/world/cache.rs b/src/world/cache.rs deleted file mode 100644 index 74d6fc6..0000000 --- a/src/world/cache.rs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2024 Andrew Brower. - * This file is part of Crawlspace. - * - * Crawlspace is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Crawlspace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with Crawlspace. If not, see - * . - */ - -use std::{cmp::Ordering, ops::Deref}; - -use crate::protocol::{packets::play::ChunkDataUpdateLightC, Encode, Encoder}; - -use super::World; - -#[derive(Debug)] -pub struct WorldCache { - pub encoded: Vec>, -} - -impl From for WorldCache { - fn from(world: World) -> Self { - let mut chunks = world.0.iter().collect::>(); - - chunks.sort_by(|((ax, az), _), ((bx, bz), _)| { - if (ax + az) > (bx + bz) { - Ordering::Greater - } else { - Ordering::Less - } - }); - - let chunks = chunks - .iter() - .map(|(_, c)| ChunkDataUpdateLightC::from(*c)) - .collect::>>(); - - let mut encoder = Encoder::new(); - let mut encoded = Vec::with_capacity(chunks.len()); - - chunks.iter().for_each(|chunk| { - encoder - .append_packet(chunk) - .expect("Failed to append packet to encoder"); - encoded.push(encoder.take().to_vec()); - }); - - Self { encoded } - } -} diff --git a/src/world/mod.rs b/src/world/mod.rs index 85852e6..93d2eb9 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -24,7 +24,6 @@ use fastanvil::Region; use serde::Deserialize; pub mod blocks; -pub mod cache; #[derive(Clone, Debug)] pub struct World(pub HashMap<(i32, i32), Chunk>); @@ -32,17 +31,17 @@ pub struct World(pub HashMap<(i32, i32), Chunk>); #[derive(Clone, Debug, Deserialize)] pub struct Chunk { #[serde(rename = "DataVersion")] - pub data_version: i32, + pub _data_version: i32, #[serde(rename = "xPos")] pub x_pos: i32, #[serde(rename = "zPos")] pub z_pos: i32, #[serde(rename = "yPos")] - pub y_pos: i32, + pub _y_pos: i32, #[serde(rename = "Status")] - pub status: ChunkStatus, + pub _status: ChunkStatus, #[serde(rename = "LastUpdate")] - pub last_update: f64, + pub _last_update: f64, pub sections: Vec
, } @@ -79,11 +78,12 @@ pub struct Section { #[serde(rename = "Y")] pub y: i32, pub block_states: BlockStates, - pub biomes: Biomes, + #[serde(rename = "biomes")] + pub _biomes: Biomes, #[serde(rename = "BlockLight")] - pub block_light: Option, + pub _block_light: Option, #[serde(rename = "SkyLight")] - pub sky_light: Option, + pub _sky_light: Option, } #[derive(Clone, Debug, Deserialize)] @@ -102,8 +102,10 @@ pub struct Block { #[derive(Clone, Debug, Deserialize)] pub struct Biomes { - pub palette: Vec, - pub data: Option, + #[serde(rename = "palette")] + pub _palette: Vec, + #[serde(rename = "data")] + pub _data: Option, } pub fn read_world(path: &str) -> Result {