mirror of
https://github.com/G2-Games/minecraft_alpha_server.git
synced 2025-04-19 15:22:56 -05:00
Client now gets to near the end of loading in
This commit is contained in:
parent
b43c372cc4
commit
ca67f15d46
6 changed files with 455 additions and 65 deletions
222
Cargo.lock
generated
222
Cargo.lock
generated
|
@ -66,6 +66,27 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base16ct"
|
||||||
|
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]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -114,6 +135,26 @@ dependencies = [
|
||||||
"cfg-if",
|
"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]]
|
[[package]]
|
||||||
name = "env_filter"
|
name = "env_filter"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -147,6 +188,27 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -165,12 +227,33 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.159"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
|
@ -181,10 +264,16 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
name = "minecraft_server_impl"
|
name = "minecraft_server_impl"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"colog",
|
"colog",
|
||||||
"flate2",
|
"flate2",
|
||||||
"log",
|
"log",
|
||||||
|
"md2",
|
||||||
|
"md5",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -196,6 +285,83 @@ dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-derive"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.87"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
@ -225,12 +391,47 @@ version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
@ -369,3 +570,24 @@ name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
|
@ -4,7 +4,13 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base16ct = { version = "0.2.0", features = ["std"] }
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
colog = "1.3.0"
|
colog = "1.3.0"
|
||||||
flate2 = "1.0.34"
|
flate2 = "1.0.34"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
|
md2 = "0.10.2"
|
||||||
|
md5 = "0.7.0"
|
||||||
|
num-derive = "0.4.2"
|
||||||
|
num-traits = "0.2.19"
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
48
src/chunk.rs
48
src/chunk.rs
|
@ -3,10 +3,10 @@ use flate2::write::ZlibEncoder;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
use crate::to_bytes::ToBytes;
|
use crate::byte_ops::ToBytes;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct MapChunk {
|
pub struct MapChunk {
|
||||||
chunk_x: i32,
|
chunk_x: i32,
|
||||||
chunk_y: i16,
|
chunk_y: i16,
|
||||||
chunk_z: i32,
|
chunk_z: i32,
|
||||||
|
@ -17,7 +17,7 @@ struct MapChunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapChunk {
|
impl MapChunk {
|
||||||
fn new(chunk_x: i32, chunk_z: i32, compressed_data: BlockArray) -> Self {
|
pub fn new(chunk_x: i32, chunk_z: i32, compressed_data: BlockArray) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chunk_x,
|
chunk_x,
|
||||||
chunk_y: 0,
|
chunk_y: 0,
|
||||||
|
@ -31,34 +31,35 @@ impl MapChunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct BlockArray {
|
pub struct BlockArray {
|
||||||
compressed_size: i32,
|
compressed_size: i32,
|
||||||
compressed_data: Vec<u8>,
|
compressed_data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockArray {
|
impl BlockArray {
|
||||||
fn new_air() -> Self {
|
pub fn new_air() -> Self {
|
||||||
let mut output_vec = Vec::new();
|
let mut block_vec = Vec::new();
|
||||||
|
|
||||||
for _ in 0..(16 * 127 * 15) {
|
for _ in 0..(16 * 127 * 15) {
|
||||||
output_vec.push(0);
|
block_vec.push(0);
|
||||||
}
|
}
|
||||||
for _ in 0..(16 * 127 * 15) / 2 {
|
for _ in 0..(16 * 127 * 15) / 2 {
|
||||||
output_vec.push(0);
|
block_vec.push(0);
|
||||||
}
|
}
|
||||||
for _ in 0..(16 * 127 * 15) / 2 {
|
for _ in 0..(16 * 127 * 15) / 2 {
|
||||||
output_vec.push(0);
|
block_vec.push(0);
|
||||||
}
|
}
|
||||||
for _ in 0..(16 * 127 * 15) / 2 {
|
for _ in 0..(16 * 127 * 15) / 2 {
|
||||||
output_vec.push(0);
|
block_vec.push(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||||
encoder.write(&output_vec).unwrap();
|
encoder.write(&block_vec).unwrap();
|
||||||
|
let output_buf = encoder.finish().unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
compressed_size: 1,
|
compressed_size: output_buf.len() as i32,
|
||||||
compressed_data: encoder.finish().unwrap(),
|
compressed_data: output_buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +88,9 @@ impl ToBytes for MapChunk {
|
||||||
buffer.write_u8(self.size_y).unwrap();
|
buffer.write_u8(self.size_y).unwrap();
|
||||||
buffer.write_u8(self.size_z).unwrap();
|
buffer.write_u8(self.size_z).unwrap();
|
||||||
|
|
||||||
|
buffer.write_i32::<BE>(self.compressed_data.compressed_size).unwrap();
|
||||||
|
buffer.write_all(&self.compressed_data.compressed_data).unwrap();
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +102,24 @@ pub struct PreChunk {
|
||||||
pub mode: bool, // True to load, False to unload
|
pub mode: bool, // True to load, False to unload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PreChunk {
|
||||||
|
pub fn new_load(x_coord: i32, z_coord: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
x_coord,
|
||||||
|
z_coord,
|
||||||
|
mode: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_unload(x_coord: i32, z_coord: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
x_coord,
|
||||||
|
z_coord,
|
||||||
|
mode: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToBytes for PreChunk {
|
impl ToBytes for PreChunk {
|
||||||
type Bytes = [u8; 9];
|
type Bytes = [u8; 9];
|
||||||
|
|
||||||
|
|
229
src/main.rs
229
src/main.rs
|
@ -1,14 +1,18 @@
|
||||||
mod utils;
|
mod utils;
|
||||||
mod to_bytes;
|
mod byte_ops;
|
||||||
mod chunk;
|
mod chunk;
|
||||||
|
|
||||||
use std::{io::{self, Write}, net::{TcpListener, TcpStream}};
|
use std::{io::{self, Read, Write}, net::{TcpListener, TcpStream}};
|
||||||
|
|
||||||
use chunk::PreChunk;
|
use base16ct::lower::encode_string;
|
||||||
|
use chunk::{BlockArray, MapChunk, PreChunk};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
|
||||||
use to_bytes::ToBytes;
|
use num_derive::FromPrimitive;
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
use byte_ops::ToBytes;
|
||||||
use utils::{MCString, ReadMCString, WriteMCString};
|
use utils::{MCString, ReadMCString, WriteMCString};
|
||||||
|
use rand::random;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -21,71 +25,113 @@ fn main() {
|
||||||
for mut connection in listener.incoming().filter_map(|c| c.ok()) {
|
for mut connection in listener.incoming().filter_map(|c| c.ok()) {
|
||||||
info!("Connected to client @ {}", connection.peer_addr().unwrap());
|
info!("Connected to client @ {}", connection.peer_addr().unwrap());
|
||||||
while let Some(cmd) = connection.read_u8().ok() {
|
while let Some(cmd) = connection.read_u8().ok() {
|
||||||
let command = Command::try_from(cmd);
|
let command = Command::from_u8(cmd);
|
||||||
info!("COMMAND: {command:?}");
|
info!("COMMAND: {command:?} (0x{cmd:02X?})");
|
||||||
handle_command(&mut connection, command.unwrap()).unwrap();
|
handle_command(&mut connection, command.unwrap()).unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
warn!("Lost connection to client");
|
warn!("Lost connection to client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_command(connection: &mut TcpStream, command: Command) -> Result<(), io::Error> {
|
fn handle_command(mut connection: &mut TcpStream, command: Command) -> Result<(), io::Error> {
|
||||||
match command {
|
match command {
|
||||||
Command::KeepAlive => todo!(),
|
Command::KeepAlive => todo!(),
|
||||||
Command::Handshake => {
|
Command::Handshake => {
|
||||||
let username = connection.read_mcstring()?;
|
let username = connection.read_mcstring()?;
|
||||||
info!("Handshake: {username}");
|
let random_number = random::<u128>();
|
||||||
|
let random_hash = encode_string(md5::compute(random_number.to_le_bytes()).as_slice());
|
||||||
|
|
||||||
|
info!("Handshake with {username} successful. Providing hash: {random_hash:?}");
|
||||||
|
|
||||||
connection.write_u8(0x02)?;
|
connection.write_u8(0x02)?;
|
||||||
connection.write_mcstring(&MCString::try_from("-").unwrap())?;
|
connection.write_mcstring(&MCString::try_from(random_hash).unwrap())?;
|
||||||
},
|
},
|
||||||
Command::Login => {
|
Command::Login => {
|
||||||
info!("---");
|
|
||||||
info!("Initiating login");
|
info!("Initiating login");
|
||||||
let protocol_version = connection.read_u32::<BE>()?;
|
let protocol_version = connection.read_u32::<BE>()?;
|
||||||
let username = connection.read_mcstring()?;
|
let username = connection.read_mcstring()?;
|
||||||
let _password = connection.read_mcstring()?;
|
let password = connection.read_mcstring()?;
|
||||||
let _map_seed = connection.read_i64::<BE>()?;
|
let map_seed = connection.read_i64::<BE>()?;
|
||||||
let _dimension = connection.read_i8()?;
|
let dimension = connection.read_i8()?;
|
||||||
|
|
||||||
info!("Protocol Version: {protocol_version}");
|
info!("Protocol Version: {protocol_version}");
|
||||||
info!("Username: {username}");
|
info!("Username: {username}");
|
||||||
|
info!("Password: {password}");
|
||||||
|
info!("Map Seed: {map_seed}");
|
||||||
|
info!("Dimension: {dimension}");
|
||||||
|
|
||||||
let login_packet = ServerLoginPacket {
|
let login_packet = ServerLoginPacket {
|
||||||
entity_id: 1,
|
entity_id: 1200,
|
||||||
unknown1: MCString::default(),
|
unknown1: MCString::default(),
|
||||||
unknown2: MCString::default(),
|
unknown2: MCString::default(),
|
||||||
map_seed: 1715505462032542147,
|
map_seed: 1715505462032542147,
|
||||||
dimension: 0,
|
dimension: 0,
|
||||||
};
|
};
|
||||||
login_packet.write_into(connection)?;
|
connection.write_u8(Command::Login as u8).unwrap();
|
||||||
|
connection.write(&login_packet.to_bytes())?;
|
||||||
|
|
||||||
info!("Responded to auth request");
|
info!("Responded to auth request");
|
||||||
|
|
||||||
let prechunk = PreChunk {
|
for i in 0..7 {
|
||||||
x_coord: 0,
|
for o in 0..7 {
|
||||||
z_coord: 0,
|
let x = (-4 + i) * 16;
|
||||||
mode: true,
|
let z = (-5 + o) * 16;
|
||||||
};
|
|
||||||
|
|
||||||
connection.write_u8(Command::PreChunk as u8)?;
|
connection.write_u8(Command::PreChunk as u8).unwrap();
|
||||||
connection.write_all(&prechunk.to_bytes())?;
|
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_u8(Command::SpawnPosition as u8)?;
|
||||||
|
connection.write_u32::<BE>(0)?;
|
||||||
|
connection.write_u32::<BE>(70)?;
|
||||||
|
connection.write_u32::<BE>(0)?;
|
||||||
|
|
||||||
|
let playerpos = PlayerPositionAndLook {
|
||||||
|
position_x: 0.0,
|
||||||
|
stance: 0.0,
|
||||||
|
position_y: 70.0,
|
||||||
|
position_z: 0.0,
|
||||||
|
yaw: 0.0,
|
||||||
|
pitch: 0.0,
|
||||||
|
on_ground: true,
|
||||||
|
};
|
||||||
|
connection.write_u8(Command::PlayerPositionAndLook as u8)?;
|
||||||
|
connection.write_all(&playerpos.to_bytes())?;
|
||||||
},
|
},
|
||||||
_ => unimplemented!("This command is probably `Server -> Client` only")
|
Command::PlayerPositionAndLook => {
|
||||||
|
let _poslook = PlayerPositionAndLook::from_bytes(&mut connection);
|
||||||
|
}
|
||||||
|
Command::PlayerPosition => {
|
||||||
|
let _pos = PlayerPosition::from_bytes(&mut connection);
|
||||||
|
}
|
||||||
|
c => unimplemented!("This command ({c:?}) is probably `Server -> Client` only")
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[derive(FromPrimitive)]
|
||||||
enum Command {
|
enum Command {
|
||||||
KeepAlive = 0x00,
|
KeepAlive = 0x00,
|
||||||
Login = 0x01,
|
Login = 0x01,
|
||||||
Handshake = 0x02,
|
Handshake = 0x02,
|
||||||
|
ChatMessage = 0x03,
|
||||||
|
TimeUpdate = 0x04,
|
||||||
|
PlayerInventory = 0x05,
|
||||||
|
SpawnPosition = 0x06,
|
||||||
|
UpdateHealth = 0x08,
|
||||||
|
Respawn = 0x09,
|
||||||
|
PlayerPositionAndLook = 0x0D,
|
||||||
|
PlayerPosition = 0x0B,
|
||||||
PreChunk = 0x32,
|
PreChunk = 0x32,
|
||||||
ChunkData = 0x33,
|
MapChunk = 0x33,
|
||||||
Kick = 0xFF,
|
Disconnect = 0xFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -93,24 +139,6 @@ struct CommandError {
|
||||||
_id: u8,
|
_id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for Command {
|
|
||||||
type Error = CommandError;
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
||||||
Ok(match value {
|
|
||||||
0x00 => Self::KeepAlive,
|
|
||||||
0x01 => Self::Login,
|
|
||||||
0x02 => Self::Handshake,
|
|
||||||
0x32 => Self::PreChunk,
|
|
||||||
0x33 => Self::ChunkData,
|
|
||||||
0xFF => Self::Kick,
|
|
||||||
v => return Err(CommandError{
|
|
||||||
_id: v,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ServerLoginPacket {
|
struct ServerLoginPacket {
|
||||||
entity_id: i32,
|
entity_id: i32,
|
||||||
unknown1: MCString,
|
unknown1: MCString,
|
||||||
|
@ -119,14 +147,111 @@ struct ServerLoginPacket {
|
||||||
dimension: i8,
|
dimension: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerLoginPacket {
|
impl ToBytes for ServerLoginPacket {
|
||||||
fn write_into<W: Write>(&self, stream: &mut W) -> Result<(), io::Error> {
|
type Bytes = Vec<u8>;
|
||||||
stream.write_i32::<BE>(self.entity_id)?;
|
|
||||||
stream.write_mcstring(&self.unknown1)?;
|
|
||||||
stream.write_mcstring(&self.unknown2)?;
|
|
||||||
stream.write_i64::<BE>(self.map_seed)?;
|
|
||||||
stream.write_i8(self.dimension)?;
|
|
||||||
|
|
||||||
Ok(())
|
fn to_bytes(self) -> Self::Bytes {
|
||||||
|
let mut out_buf = Vec::new();
|
||||||
|
out_buf.write_i32::<BE>(self.entity_id).unwrap();
|
||||||
|
out_buf.write_mcstring(&self.unknown1).unwrap();
|
||||||
|
out_buf.write_mcstring(&self.unknown2).unwrap();
|
||||||
|
out_buf.write_i64::<BE>(self.map_seed).unwrap();
|
||||||
|
out_buf.write_i8(self.dimension).unwrap();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/utils.rs
15
src/utils.rs
|
@ -23,6 +23,21 @@ impl TryFrom<&str> for MCString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for MCString {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
if value.len() > u16::MAX as usize {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
len: value.len() as u16,
|
||||||
|
chars: value.as_bytes().to_vec(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for MCString {
|
impl Display for MCString {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", String::from_utf8(self.chars.clone()).unwrap())
|
write!(f, "{}", String::from_utf8(self.chars.clone()).unwrap())
|
||||||
|
|
Loading…
Reference in a new issue