save up to play / status
This commit is contained in:
parent
ac3c3b0339
commit
ef86b059c5
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target/
|
394
Cargo.lock
generated
Normal file
394
Cargo.lock
generated
Normal file
@ -0,0 +1,394 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "Composition"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ozelot",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "762e34611d2d5233a506a79072be944fddd057db2f18e04c0d6fa79e3fd466fd"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"socket2",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.31+curl-7.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcd62757cc4f5ab9404bc6ca9f0ae447e729a1403948ce5106bd588ceac6a3b0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crc32fast",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netbuf"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f41e95a536af3c11c6dcf16f30b8319aad291049e67c8aa4701f69f11761a9db"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7410fef80af8ac071d4f63755c0ab89ac3df0fd1ea91f1d1f37cf5cec4395990"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ozelot"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea00748638603838e4c5907d8d10449ee9a7e548667af7c20c684888006f6657"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"curl",
|
||||
"error-chain",
|
||||
"flate2",
|
||||
"netbuf",
|
||||
"openssl",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f14a640819f79b72a710c0be059dce779f9339ae046c8bef12c361d56702146f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "Composition"
|
||||
version = "0.1.0"
|
||||
authors = ["ElementG9 <garentyler@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0.110"
|
||||
serde_json = "1.0.53"
|
||||
ozelot = "0.9.0"
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 ElementG9
|
||||
Copyright (c) 2020 Garen Tyler
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
17
src/main.rs
Normal file
17
src/main.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub static DEBUG_LOGGING: bool = true;
|
||||
pub static SERVER_VERSION: &str = "1.15.2";
|
||||
pub static SERVER_PROTOCOL_VERSION: usize = 578;
|
||||
pub static SERVER_MOTD: &str = "ligma balls";
|
||||
|
||||
// mod net;
|
||||
// mod mctypes;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
// Listener loops forever.
|
||||
// net::start_listener().expect("could not start listener");
|
||||
// println!("Stopping server");
|
||||
use std::{io::prelude::*, net::TcpStream};
|
||||
let mut stream = TcpStream::connect("206.189.67.44:25565")?;
|
||||
}
|
432
src/mctypes.rs
Normal file
432
src/mctypes.rs
Normal file
@ -0,0 +1,432 @@
|
||||
use std::io::prelude::*;
|
||||
use std::net::TcpStream;
|
||||
|
||||
pub fn read_byte(t: &mut TcpStream) -> std::io::Result<u8> {
|
||||
let mut buffer = [0u8; 1];
|
||||
t.read_exact(&mut buffer)?;
|
||||
Ok(buffer[0])
|
||||
}
|
||||
pub fn get_bytes(v: Vec<u8>, l: usize) -> Box<[u8]> {
|
||||
use std::collections::VecDeque;
|
||||
let mut v = VecDeque::from(v);
|
||||
while v.len() > l {
|
||||
v.pop_front();
|
||||
}
|
||||
while v.len() < l {
|
||||
v.push_front(0u8);
|
||||
}
|
||||
let mut a = Vec::new();
|
||||
for b in v {
|
||||
a.push(b);
|
||||
}
|
||||
a.into_boxed_slice()
|
||||
}
|
||||
pub fn io_error(s: &str) -> std::io::Error {
|
||||
use std::io::{Error, ErrorKind};
|
||||
Error::new(ErrorKind::Other, s)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum MCBoolean {
|
||||
True,
|
||||
False,
|
||||
}
|
||||
impl From<bool> for MCBoolean {
|
||||
fn from(v: bool) -> MCBoolean {
|
||||
if v {
|
||||
MCBoolean::True
|
||||
} else {
|
||||
MCBoolean::False
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCBoolean {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCBoolean> {
|
||||
let b = read_byte(t)?;
|
||||
Ok(MCBoolean::from_bytes(vec![b]))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCBoolean {
|
||||
if get_bytes(v, 1)[0] == 0x01 {
|
||||
MCBoolean::True
|
||||
} else {
|
||||
MCBoolean::False
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
MCBoolean::True => vec![0x01],
|
||||
MCBoolean::False => vec![0x00],
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCByte {
|
||||
pub value: i8 // -128 to 127
|
||||
}
|
||||
impl From<i8> for MCByte {
|
||||
fn from(v: i8) -> MCByte {
|
||||
MCByte {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCByte {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCByte> {
|
||||
Ok(MCByte::from_bytes(vec![read_byte(t)?]))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCByte {
|
||||
MCByte {
|
||||
value: get_bytes(v, 1)[0] as i8
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCUnsignedByte {
|
||||
pub value: u8 // 0 to 255
|
||||
}
|
||||
impl From<u8> for MCUnsignedByte {
|
||||
fn from(v: u8) -> MCUnsignedByte {
|
||||
MCUnsignedByte {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCUnsignedByte {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCUnsignedByte> {
|
||||
Ok(MCUnsignedByte::from_bytes(vec![read_byte(t)?]))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCUnsignedByte {
|
||||
MCUnsignedByte {
|
||||
value: get_bytes(v, 1)[0]
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCShort {
|
||||
pub value: i16 // -32768 to 32767
|
||||
}
|
||||
impl From<i16> for MCShort {
|
||||
fn from(v: i16) -> MCShort {
|
||||
MCShort {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCShort {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCShort> {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.push(read_byte(t)?); // MSD
|
||||
bytes.push(read_byte(t)?); // LSD
|
||||
Ok(MCShort::from_bytes(bytes))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCShort {
|
||||
let mut a = [0u8; 2];
|
||||
a.copy_from_slice(&get_bytes(v, 2));
|
||||
MCShort {
|
||||
value: i16::from_be_bytes(a)
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCUnsignedShort {
|
||||
pub value: u16 // 0 to 65535
|
||||
}
|
||||
impl From<u16> for MCUnsignedShort {
|
||||
fn from(v: u16) -> MCUnsignedShort {
|
||||
MCUnsignedShort {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCUnsignedShort {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCUnsignedShort> {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.push(read_byte(t)?); // MSD
|
||||
bytes.push(read_byte(t)?); // LSD
|
||||
Ok(MCUnsignedShort::from_bytes(bytes))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCUnsignedShort {
|
||||
let mut a = [0u8; 2];
|
||||
a.copy_from_slice(&get_bytes(v, 2));
|
||||
MCUnsignedShort {
|
||||
value: u16::from_be_bytes(a)
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCInt {
|
||||
pub value: i32 // -2147483648 to 2147483647
|
||||
}
|
||||
impl From<i32> for MCInt {
|
||||
fn from(v: i32) -> MCInt {
|
||||
MCInt {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCInt {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCInt> {
|
||||
let mut bytes = Vec::new();
|
||||
for _ in 0..4 {
|
||||
bytes.push(read_byte(t)?);
|
||||
}
|
||||
Ok(MCInt::from_bytes(bytes))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCInt {
|
||||
let mut a = [0u8; 4];
|
||||
a.copy_from_slice(&get_bytes(v, 4));
|
||||
MCInt {
|
||||
value: i32::from_be_bytes(a)
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCLong {
|
||||
pub value: i64 // -9223372036854775808 to 9223372036854775807
|
||||
}
|
||||
impl From<i64> for MCLong {
|
||||
fn from(v: i64) -> MCLong {
|
||||
MCLong {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCLong {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCLong> {
|
||||
let mut bytes = Vec::new();
|
||||
for _ in 0..8 {
|
||||
bytes.push(read_byte(t)?);
|
||||
}
|
||||
Ok(MCLong::from_bytes(bytes))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCLong {
|
||||
let mut a = [0u8; 8];
|
||||
a.copy_from_slice(&get_bytes(v, 8));
|
||||
MCLong {
|
||||
value: i64::from_be_bytes(a)
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCFloat {
|
||||
pub value: f32 // 32-bit floating point number
|
||||
}
|
||||
impl From<f32> for MCFloat {
|
||||
fn from(v: f32) -> MCFloat {
|
||||
MCFloat {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCFloat {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCFloat> {
|
||||
let mut bytes = Vec::new();
|
||||
for _ in 0..4 {
|
||||
bytes.push(read_byte(t)?);
|
||||
}
|
||||
Ok(MCFloat::from_bytes(bytes))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCFloat {
|
||||
let mut a = [0u8; 4];
|
||||
a.copy_from_slice(&get_bytes(v, 4));
|
||||
MCFloat {
|
||||
value: f32::from_be_bytes(a)
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCDouble {
|
||||
pub value: f64 // 64-bit floating point number
|
||||
}
|
||||
impl From<f64> for MCDouble {
|
||||
fn from(v: f64) -> MCDouble {
|
||||
MCDouble {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCDouble {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCDouble> {
|
||||
let mut bytes = Vec::new();
|
||||
for _ in 0..8 {
|
||||
bytes.push(read_byte(t)?);
|
||||
}
|
||||
Ok(MCDouble::from_bytes(bytes))
|
||||
}
|
||||
pub fn from_bytes(v: Vec<u8>) -> MCDouble {
|
||||
let mut a = [0u8; 8];
|
||||
a.copy_from_slice(&get_bytes(v, 8));
|
||||
MCDouble {
|
||||
value: f64::from_be_bytes(a)
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
self.value.to_be_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MCVarInt {
|
||||
pub value: i32 // Variable length 32-bit integer
|
||||
}
|
||||
impl From<i32> for MCVarInt {
|
||||
fn from(v: i32) -> MCVarInt {
|
||||
MCVarInt {
|
||||
value: v
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCVarInt {
|
||||
pub fn new(i: i32) -> MCVarInt {
|
||||
MCVarInt {
|
||||
value: i
|
||||
}
|
||||
}
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCVarInt> {
|
||||
let mut numRead = 0;
|
||||
let mut result = 0i32;
|
||||
let mut read = 0u8;
|
||||
let mut run_once = false;
|
||||
while (read & 0b10000000) != 0 || !run_once {
|
||||
run_once = true;
|
||||
read = read_byte(t)?;
|
||||
let value = (read & 0b01111111) as i32;
|
||||
result |= value << (7 * numRead);
|
||||
numRead += 1;
|
||||
if numRead > 5 {
|
||||
return Err(io_error("MCVarInt is too big"));
|
||||
}
|
||||
}
|
||||
Ok(MCVarInt {
|
||||
value: result
|
||||
})
|
||||
}
|
||||
pub fn from_bytes(_: Vec<u8>) -> MCVarInt {
|
||||
panic!("Cannot construct MCVarInt from raw bytes");
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut value = self.value.clone();
|
||||
let mut run_once = false;
|
||||
let mut out: Vec<u8> = Vec::new();
|
||||
while value != 0 || !run_once {
|
||||
run_once = true;
|
||||
let mut temp: u8 = (value & 0b01111111) as u8;
|
||||
value >>= 7;
|
||||
if value != 0 {
|
||||
temp |= 0b10000000;
|
||||
}
|
||||
out.push(temp);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for MCVarInt {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct MCString {
|
||||
pub value: String
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCString {
|
||||
pub fn from_stream(t: &mut TcpStream) -> std::io::Result<MCString> {
|
||||
let length = MCVarInt::from_stream(t)?.value as u32;
|
||||
let mut bytes = Vec::new();
|
||||
for _ in 0..length {
|
||||
bytes.push(read_byte(t)?);
|
||||
}
|
||||
let value = String::from_utf8(bytes);
|
||||
if value.is_ok() {
|
||||
Ok(MCString {
|
||||
value: value.unwrap()
|
||||
})
|
||||
} else {
|
||||
return Err(io_error("MCString contains invalid utf-8"));
|
||||
}
|
||||
}
|
||||
pub fn from_bytes(_: Vec<u8>) -> MCString {
|
||||
panic!("Cannot construct MCVarInt from raw bytes");
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
let length = MCVarInt {
|
||||
value: self.value.len() as i32
|
||||
};
|
||||
for b in length.to_bytes() {
|
||||
out.push(b);
|
||||
}
|
||||
for b in self.value.clone().into_bytes() {
|
||||
out.push(b);
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
impl From<&str> for MCString {
|
||||
fn from(s: &str) -> MCString {
|
||||
MCString {
|
||||
value: s.to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<String> for MCString {
|
||||
fn from(s: String) -> MCString {
|
||||
MCString {
|
||||
value: s.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Clone for MCString {
|
||||
fn clone(&self) -> Self {
|
||||
MCString {
|
||||
value: self.value.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for MCString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "\"{}\" ({} chars)", self.value, self.value.len())
|
||||
}
|
||||
}
|
217
src/net.rs
Normal file
217
src/net.rs
Normal file
@ -0,0 +1,217 @@
|
||||
pub static SERVER_LISTENER_ADDRESS: &str = "127.0.0.1:25565";
|
||||
pub static SOCKET_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
use std::io::prelude::*;
|
||||
use std::net::{TcpStream, TcpListener};
|
||||
use std::thread;
|
||||
use crate::mctypes::*;
|
||||
|
||||
pub struct MCPacket {
|
||||
pub id: MCVarInt,
|
||||
pub data: Vec<u8>
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl MCPacket {
|
||||
pub fn read_header(t: &mut TcpStream) -> std::io::Result<(MCVarInt, MCVarInt)> {
|
||||
let length = MCVarInt::from_stream(t)?;
|
||||
let id = MCVarInt::from_stream(t)?;
|
||||
Ok((length, id))
|
||||
}
|
||||
pub fn new(id: u8) -> MCPacket {
|
||||
MCPacket {
|
||||
id: MCVarInt::new(id as i32),
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn write(&mut self, v: Vec<u8>) {
|
||||
for b in v {
|
||||
self.data.push(b);
|
||||
}
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
for b in MCVarInt::new((
|
||||
self.id.to_bytes().len() +
|
||||
self.data.len()
|
||||
) as i32).to_bytes() {
|
||||
bytes.push(b);
|
||||
}
|
||||
for b in self.id.to_bytes() {
|
||||
bytes.push(b);
|
||||
}
|
||||
for b in &self.data {
|
||||
bytes.push(*b);
|
||||
}
|
||||
bytes
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum GameState {
|
||||
Handshake,
|
||||
Status,
|
||||
Login,
|
||||
Play,
|
||||
Closed
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub struct GameConnection {
|
||||
pub stream: TcpStream,
|
||||
pub state: GameState,
|
||||
}
|
||||
|
||||
pub fn start_listener() -> std::io::Result<()> {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Started listener at {}", SERVER_LISTENER_ADDRESS);
|
||||
}
|
||||
let listener = TcpListener::bind(SERVER_LISTENER_ADDRESS)?;
|
||||
// Spawn a new thread for each connection.
|
||||
for stream in listener.incoming() {
|
||||
let stream = stream?;
|
||||
thread::Builder::new().name(format!("GameConnection {}", stream.peer_addr().unwrap())).spawn(move || -> std::io::Result<()> {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Client connected at {}", stream.peer_addr().unwrap());
|
||||
}
|
||||
stream
|
||||
.set_read_timeout(Some(SOCKET_TIMEOUT))
|
||||
.expect("set_read_timeout call failed");
|
||||
stream
|
||||
.set_write_timeout(Some(SOCKET_TIMEOUT))
|
||||
.expect("set_write_timeout call failed");
|
||||
handle_client(GameConnection {
|
||||
stream: stream,
|
||||
state: GameState::Handshake,
|
||||
})?;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn handle_client(mut gc: GameConnection) -> std::io::Result<()> {
|
||||
loop {
|
||||
let (packet_length, packet_id) = MCPacket::read_header(&mut gc.stream)?;
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Packet Length: {}, Packet ID: {}", packet_length.value, packet_id.value);
|
||||
}
|
||||
match gc.state {
|
||||
GameState::Handshake => {
|
||||
match packet_id.value {
|
||||
0x00 => {
|
||||
handshake(&mut gc)?;
|
||||
},
|
||||
_ => {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Unknown packet id {} in Handshake", packet_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
GameState::Login => {
|
||||
match packet_id.value {
|
||||
0x00 => {
|
||||
login(&mut gc)?;
|
||||
},
|
||||
_ => {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Unknown packet id {} in Login", packet_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
GameState::Status => {
|
||||
match packet_id.value {
|
||||
0x00 => {
|
||||
// Send a response packet.
|
||||
let mut packet = MCPacket::new(0x00);
|
||||
let json_response = json!({
|
||||
"version": {
|
||||
"name": crate::SERVER_VERSION,
|
||||
"protocol": crate::SERVER_PROTOCOL_VERSION
|
||||
},
|
||||
"players": {
|
||||
"max": 100,
|
||||
"online": 5,
|
||||
"sample": [
|
||||
{
|
||||
"name": "thinkofdeath",
|
||||
"id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"text": crate::SERVER_MOTD
|
||||
}
|
||||
// No favicon for now.
|
||||
// "favicon": "data:image/png;base64,<data>"
|
||||
}).to_string();
|
||||
packet.write(MCVarInt::new(json_response.len() as i32).to_bytes());
|
||||
packet.write(MCString::from(json_response.clone()).to_bytes());
|
||||
gc.stream.write(&packet.to_bytes())?;
|
||||
println!("=== SENT SERVER RESPONSE ===\n{}", json_response);
|
||||
},
|
||||
_ => {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Unknown packet id {} in Status", packet_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Unknown gamestate {:?}", gc.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn handshake(gc: &mut GameConnection) -> std::io::Result<()> {
|
||||
// C->S Handshake
|
||||
let protocol_version = MCVarInt::from_stream(&mut gc.stream)?;
|
||||
let server_address = MCString::from_stream(&mut gc.stream)?;
|
||||
let server_port = MCUnsignedShort::from_stream(&mut gc.stream)?;
|
||||
let next_state = match MCVarInt::from_stream(&mut gc.stream)?.value {
|
||||
1 => GameState::Status,
|
||||
2 => GameState::Login,
|
||||
_ => {
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Unknown next_state in handshake");
|
||||
}
|
||||
GameState::Handshake
|
||||
}
|
||||
};
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Handshake: Protocol Version: {}, Server Address: {}:{}, Next State: {:?}",
|
||||
protocol_version.value,
|
||||
server_address.value,
|
||||
server_port.value,
|
||||
next_state
|
||||
);
|
||||
}
|
||||
gc.state = next_state;
|
||||
Ok(())
|
||||
}
|
||||
pub fn login(gc: &mut GameConnection) -> std::io::Result<()> {
|
||||
// C->S Login Start
|
||||
let player_username = MCString::from_stream(&mut gc.stream)?;
|
||||
if crate::DEBUG_LOGGING {
|
||||
println!("Login: Player Username: {}", player_username);
|
||||
}
|
||||
// S->C Encryption Request
|
||||
// C->S Encryption Response
|
||||
// S->C Set Compression
|
||||
// S->C Login Success
|
||||
let mut login_success = MCPacket::new(0x02);
|
||||
login_success.write(MCString::from("00000000-0000-0000-0000-000000000000").to_bytes()); // UUID
|
||||
login_success.write(player_username.to_bytes());
|
||||
gc.stream.write(&login_success.to_bytes())?;
|
||||
// Move to Play state
|
||||
gc.state = GameState::Play;
|
||||
play(gc)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn play(gc: &mut GameConnection) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user