Flat world generation works

This commit is contained in:
G2-Games 2024-10-10 16:49:01 -05:00
parent ca67f15d46
commit afd0a48527
5 changed files with 253 additions and 181 deletions

61
Cargo.lock generated
View file

@ -78,15 +78,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.5.0"
@ -135,26 +126,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "env_filter"
version = "0.1.2"
@ -188,16 +159,6 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@ -239,15 +200,6 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "md2"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4f0f3ed25ff4f8d8d102288d92f900efc202661c884cf67dfe4f0d07c43d1f"
dependencies = [
"digest",
]
[[package]]
name = "md5"
version = "0.7.0"
@ -269,7 +221,6 @@ dependencies = [
"colog",
"flate2",
"log",
"md2",
"md5",
"num-derive",
"num-traits",
@ -402,12 +353,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.13"
@ -420,12 +365,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

View file

@ -9,7 +9,6 @@ byteorder = "1.5.0"
colog = "1.3.0"
flate2 = "1.0.34"
log = "0.4.22"
md2 = "0.10.2"
md5 = "0.7.0"
num-derive = "0.4.2"
num-traits = "0.2.19"

View file

@ -62,6 +62,45 @@ impl BlockArray {
compressed_data: output_buf,
}
}
pub fn new_superflat() -> Self {
let mut block_vec = vec![0; 16 * 16 * 128];
for x in 0..16 {
for y in 0..128 {
for z in 0..16 {
let pos = y + (z * (128)) + (x * (128) * (16));
if y == 7 {
block_vec[pos] = BlockType::Grass as u8;
} else if y > 0 && y < 7 {
block_vec[pos] = BlockType::Dirt as u8;
} else if y == 0 {
block_vec[pos] = BlockType::Bedrock as u8;
} else {
block_vec[pos] = 0;
}
}
}
}
for _ in 0..(16 * 128 * 16) / 2 {
block_vec.push(0);
}
for _ in 0..(16 * 128 * 16) / 2 {
block_vec.push(0);
}
for _ in 0..(16 * 128 * 16) / 2 {
block_vec.push(0xFF);
}
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
encoder.write(&block_vec).unwrap();
let output_buf = encoder.finish().unwrap();
Self {
compressed_size: output_buf.len() as i32,
compressed_data: output_buf,
}
}
}
#[repr(u8)]

View file

@ -1,8 +1,9 @@
mod utils;
mod byte_ops;
mod chunk;
mod position;
use std::{io::{self, Read, Write}, net::{TcpListener, TcpStream}};
use std::{cell::LazyCell, io::{self, Write}, net::{TcpListener, TcpStream}};
use base16ct::lower::encode_string;
use chunk::{BlockArray, MapChunk, PreChunk};
@ -11,9 +12,23 @@ use byteorder::{ReadBytesExt, WriteBytesExt, BE};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use byte_ops::ToBytes;
use position::{PlayerLook, PlayerPosition, PlayerPositionAndLook};
use utils::{MCString, ReadMCString, WriteMCString};
use rand::random;
const CHUNKS: LazyCell<Vec<MapChunk>> = LazyCell::new(|| {
let mut mapchunk = Vec::new();
for i in -10..10 {
for o in -10..10 {
let x = i * 16;
let z = o * 16;
mapchunk.push(MapChunk::new(x, z, BlockArray::new_superflat()));
}
}
mapchunk
});
fn main() {
colog::default_builder()
@ -26,7 +41,9 @@ fn main() {
info!("Connected to client @ {}", connection.peer_addr().unwrap());
while let Some(cmd) = connection.read_u8().ok() {
let command = Command::from_u8(cmd);
if command.is_none() {
info!("COMMAND: {command:?} (0x{cmd:02X?})");
}
handle_command(&mut connection, command.unwrap()).unwrap();
}
warn!("Lost connection to client");
@ -35,7 +52,6 @@ fn main() {
fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<(), io::Error> {
match command {
Command::KeepAlive => todo!(),
Command::Handshake => {
let username = connection.read_mcstring()?;
let random_number = random::<u128>();
@ -61,10 +77,10 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
info!("Dimension: {dimension}");
let login_packet = ServerLoginPacket {
entity_id: 1200,
entity_id: 1,
unknown1: MCString::default(),
unknown2: MCString::default(),
map_seed: 1715505462032542147,
map_seed: 0,
dimension: 0,
};
connection.write_u8(Command::Login as u8).unwrap();
@ -72,16 +88,16 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
info!("Responded to auth request");
for i in 0..7 {
for o in 0..7 {
let x = (-4 + i) * 16;
let z = (-5 + o) * 16;
for i in -10..10 {
for o in -10..10 {
let x = i * 16;
let z = o * 16;
connection.write_u8(Command::PreChunk as u8).unwrap();
connection.write_all(&PreChunk::new_load(x, z).to_bytes()).unwrap();
connection.write_u8(Command::MapChunk as u8)?;
connection.write_all(&MapChunk::new(x, z, BlockArray::new_air()).to_bytes())?;
connection.write_all(&MapChunk::new(x, z, BlockArray::new_superflat()).to_bytes())?;
}
}
@ -91,29 +107,74 @@ fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<()
connection.write_u32::<BE>(0)?;
let playerpos = PlayerPositionAndLook {
position_x: 0.0,
position: PlayerPosition {
position_x: 1.0,
stance: 0.0,
position_y: 70.0,
position_z: 0.0,
position_y: 9.63,
position_z: 1.0,
},
look: PlayerLook {
yaw: 0.0,
pitch: 0.0,
on_ground: true,
},
};
connection.write_u8(Command::PlayerPositionAndLook as u8)?;
connection.write_all(&playerpos.to_bytes())?;
},
Command::PlayerPositionAndLook => {
let _poslook = PlayerPositionAndLook::from_bytes(&mut connection);
Command::ChatMessage => {
info!("Chat Message Recieved: {}", connection.read_mcstring().unwrap());
}
Command::Player => {
connection.read_u8()?;
},
Command::PlayerLook => {
let _look = PlayerLook::from_bytes(&mut connection);
}
Command::PlayerPosition => {
let _pos = PlayerPosition::from_bytes(&mut connection);
}
Command::PlayerPositionAndLook => {
let _poslook = PlayerPositionAndLook::from_bytes(&mut connection);
}
Command::PlayerDigging => {
let status = DiggingStatus::from_u8(connection.read_u8()?).unwrap();
let pos_x = connection.read_i32::<BE>()?;
let pos_y = connection.read_u8()?;
let pos_z = connection.read_i32::<BE>()?;
let face = connection.read_u8()?;
}
Command::ArmAnimation => {
let eid = connection.read_i32::<BE>()?;
let animate = connection.read_u8()? != 0;
}
Command::Disconnect => {
let disconnect_string = connection.read_mcstring()?;
info!("Disconnecting client: {disconnect_string}");
connection.shutdown(std::net::Shutdown::Both)?;
}
Command::KeepAlive => {
let _ = connection.write_u8(0x00);
// TODO: Feed keepalive watchdog for client
}
Command::UpdateHealth => {
connection.read_u8()?;
}
c => unimplemented!("This command ({c:?}) is probably `Server -> Client` only")
}
Ok(())
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
#[derive(FromPrimitive)]
enum DiggingStatus {
StartedDigging = 0,
Digging = 1,
StoppedDigging = 2,
BlockBroken = 3,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
#[derive(FromPrimitive)]
@ -127,18 +188,17 @@ enum Command {
SpawnPosition = 0x06,
UpdateHealth = 0x08,
Respawn = 0x09,
PlayerPositionAndLook = 0x0D,
Player = 0x0A,
PlayerPosition = 0x0B,
PlayerLook = 0x0C,
PlayerPositionAndLook = 0x0D,
PlayerDigging = 0x0E,
ArmAnimation = 0x12,
PreChunk = 0x32,
MapChunk = 0x33,
Disconnect = 0xFF,
}
#[derive(Debug, Clone, Copy)]
struct CommandError {
_id: u8,
}
struct ServerLoginPacket {
entity_id: i32,
unknown1: MCString,
@ -161,97 +221,3 @@ impl ToBytes for ServerLoginPacket {
out_buf
}
}
#[derive(Debug, Clone, Copy)]
struct PlayerPositionAndLook {
position_x: f64,
stance: f64,
position_y: f64,
position_z: f64,
yaw: f32,
pitch: f32,
on_ground: bool,
}
impl ToBytes for PlayerPositionAndLook {
type Bytes = Vec<u8>;
fn to_bytes(self) -> Self::Bytes {
let mut out_buf = Vec::new();
out_buf.write_f64::<BE>(self.position_x).unwrap();
out_buf.write_f64::<BE>(self.stance).unwrap();
out_buf.write_f64::<BE>(self.position_y).unwrap();
out_buf.write_f64::<BE>(self.position_z).unwrap();
out_buf.write_f32::<BE>(self.yaw).unwrap();
out_buf.write_f32::<BE>(self.pitch).unwrap();
out_buf.write_u8(self.on_ground as u8).unwrap();
out_buf
}
}
impl PlayerPositionAndLook {
fn from_bytes<R: Read>(stream: &mut R) -> Self {
let position_x = stream.read_f64::<BE>().unwrap();
let position_y = stream.read_f64::<BE>().unwrap();
let stance = stream.read_f64::<BE>().unwrap();
let position_z = stream.read_f64::<BE>().unwrap();
let yaw = stream.read_f32::<BE>().unwrap();
let pitch = stream.read_f32::<BE>().unwrap();
let on_ground = stream.read_u8().unwrap() != 0;
Self {
position_x,
stance,
position_y,
position_z,
yaw,
pitch,
on_ground
}
}
}
#[derive(Debug, Clone, Copy)]
struct PlayerPosition {
position_x: f64,
position_y: f64,
stance: f64,
position_z: f64,
on_ground: bool,
}
impl ToBytes for PlayerPosition {
type Bytes = Vec<u8>;
fn to_bytes(self) -> Self::Bytes {
let mut out_buf = Vec::new();
out_buf.write_f64::<BE>(self.position_x).unwrap();
out_buf.write_f64::<BE>(self.position_y).unwrap();
out_buf.write_f64::<BE>(self.stance).unwrap();
out_buf.write_f64::<BE>(self.position_z).unwrap();
out_buf.write_u8(self.on_ground as u8).unwrap();
out_buf
}
}
impl PlayerPosition {
fn from_bytes<R: Read>(stream: &mut R) -> Self {
let position_x = stream.read_f64::<BE>().unwrap();
let position_y = stream.read_f64::<BE>().unwrap();
let stance = stream.read_f64::<BE>().unwrap();
let position_z = stream.read_f64::<BE>().unwrap();
let on_ground = stream.read_u8().unwrap() != 0;
Self {
position_x,
stance,
position_y,
position_z,
on_ground
}
}
}

129
src/position.rs Normal file
View file

@ -0,0 +1,129 @@
use std::io::Read;
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
use crate::byte_ops::ToBytes;
#[derive(Debug, Clone, Copy)]
pub struct PlayerPositionAndLook {
pub position: PlayerPosition,
pub look: PlayerLook,
}
impl ToBytes for PlayerPositionAndLook {
type Bytes = Vec<u8>;
fn to_bytes(self) -> Self::Bytes {
let mut out_buf = Vec::new();
out_buf.write_f64::<BE>(self.position.position_x).unwrap();
out_buf.write_f64::<BE>(self.position.position_y).unwrap();
out_buf.write_f64::<BE>(self.position.stance).unwrap();
out_buf.write_f64::<BE>(self.position.position_z).unwrap();
out_buf.write_f32::<BE>(self.look.yaw).unwrap();
out_buf.write_f32::<BE>(self.look.pitch).unwrap();
out_buf.write_u8(true as u8).unwrap();
out_buf
}
}
impl PlayerPositionAndLook {
pub fn from_bytes<R: Read>(stream: &mut R) -> Self {
let position_x = stream.read_f64::<BE>().unwrap();
let position_y = stream.read_f64::<BE>().unwrap();
let stance = stream.read_f64::<BE>().unwrap();
let position_z = stream.read_f64::<BE>().unwrap();
let yaw = stream.read_f32::<BE>().unwrap();
let pitch = stream.read_f32::<BE>().unwrap();
let _on_ground = stream.read_u8().unwrap();
Self {
position: PlayerPosition {
position_x,
stance,
position_y,
position_z,
},
look: PlayerLook {
yaw,
pitch,
},
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PlayerPosition {
pub position_x: f64,
pub position_y: f64,
pub stance: f64,
pub position_z: f64,
}
impl ToBytes for PlayerPosition {
type Bytes = Vec<u8>;
fn to_bytes(self) -> Self::Bytes {
let mut out_buf = Vec::new();
out_buf.write_f64::<BE>(self.position_x).unwrap();
out_buf.write_f64::<BE>(self.position_y).unwrap();
out_buf.write_f64::<BE>(self.stance).unwrap();
out_buf.write_f64::<BE>(self.position_z).unwrap();
out_buf.write_u8(1).unwrap();
out_buf
}
}
impl PlayerPosition {
pub fn from_bytes<R: Read>(stream: &mut R) -> Self {
let position_x = stream.read_f64::<BE>().unwrap();
let position_y = stream.read_f64::<BE>().unwrap();
let stance = stream.read_f64::<BE>().unwrap();
let position_z = stream.read_f64::<BE>().unwrap();
let _on_ground = stream.read_u8().unwrap() != 0;
Self {
position_x,
stance,
position_y,
position_z,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PlayerLook {
pub yaw: f32,
pub pitch: f32,
}
impl ToBytes for PlayerLook {
type Bytes = Vec<u8>;
fn to_bytes(self) -> Self::Bytes {
let mut out_buf = Vec::new();
out_buf.write_f32::<BE>(self.yaw).unwrap();
out_buf.write_f32::<BE>(self.pitch).unwrap();
out_buf.write_u8(1).unwrap();
out_buf
}
}
impl PlayerLook {
pub fn from_bytes<R: Read>(stream: &mut R) -> Self {
let yaw = stream.read_f32::<BE>().unwrap();
let pitch = stream.read_f32::<BE>().unwrap();
let _on_ground = stream.read_u8().unwrap() != 0;
Self {
yaw,
pitch,
}
}
}