From 7e366934854647755243f262320cc10facfa6fc8 Mon Sep 17 00:00:00 2001 From: ElementG9 Date: Mon, 17 Aug 2020 15:55:29 -0600 Subject: [PATCH] things --- .vscode/tasks.json | 17 +++ Cargo.lock | 75 +++++++++---- Cargo.toml | 3 + output.log | 175 ++++++++++++++++++++++++++++++ src/logger.rs | 99 ----------------- src/main.rs | 115 ++++++++++---------- src/network/mod.rs | 84 +++++++++++++++ src/network/packet/mod.rs | 13 +++ src/old_net.rs | 219 -------------------------------------- src/server.rs | 75 +++++++++++++ 10 files changed, 477 insertions(+), 398 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 output.log delete mode 100644 src/logger.rs create mode 100644 src/network/mod.rs create mode 100644 src/network/packet/mod.rs delete mode 100644 src/old_net.rs create mode 100644 src/server.rs diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..10b46b0 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cargo", + "subcommand": "build", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "label": "Rust: cargo build - Composition" + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 3c33ad6..4bf7893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,10 +4,13 @@ name = "Composition" version = "0.1.0" dependencies = [ + "backtrace", "base64", "chrono", "colorful", + "fern", "lazy_static", + "log", "mojang-api", "ozelot", "radix64", @@ -17,9 +20,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c" +checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" dependencies = [ "gimli", ] @@ -30,18 +33,23 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10" -[[package]] -name = "adler32" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" - [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -50,14 +58,14 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" +checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide 0.3.7", + "miniz_oxide", "object", "rustc-demangle", ] @@ -118,6 +126,17 @@ dependencies = [ "time", ] +[[package]] +name = "colored" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +dependencies = [ + "atty", + "lazy_static", + "winapi 0.3.8", +] + [[package]] name = "colorful" version = "0.2.1" @@ -204,6 +223,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "fern" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" +dependencies = [ + "colored", + "log", +] + [[package]] name = "flate2" version = "1.0.16" @@ -213,7 +242,7 @@ dependencies = [ "cfg-if", "crc32fast", "libc", - "miniz_oxide 0.4.0", + "miniz_oxide", ] [[package]] @@ -318,9 +347,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" +checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" [[package]] name = "h2" @@ -341,6 +370,15 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +dependencies = [ + "libc", +] + [[package]] name = "http" version = "0.2.1" @@ -531,15 +569,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - [[package]] name = "miniz_oxide" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 0aa1ec5..664f052 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,6 @@ serde = { version = "1.0.114", features = ["serde_derive"]} base64 = "0.12.3" radix64 = "0.3.0" mojang-api = "0.6.1" +log = "*" +fern = { version = "0.6", features = ["colored"] } +backtrace = "0.3.50" diff --git a/output.log b/output.log new file mode 100644 index 0000000..97c90f9 --- /dev/null +++ b/output.log @@ -0,0 +1,175 @@ + +2020-07-27 11:25:17 [ERROR] - panicked at 'Normal panic', src/main.rs:55:5 +2020-07-27 11:25:18 [ERROR] - panicked at 'Normal panic', src/main.rs:55:5 + 0: backtrace::backtrace::libunwind::trace + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/backtrace/libunwind.rs:95 + backtrace::backtrace::trace_unsynchronized + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/backtrace/mod.rs:66 + 1: backtrace::backtrace::trace + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/backtrace/mod.rs:53 + 2: backtrace::capture::Backtrace::create + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/capture.rs:164 + 3: backtrace::capture::Backtrace::new + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/capture.rs:128 + 4: Composition::main::{{closure}} + at src/main.rs:52 + 5: std::panicking::rust_panic_with_hook + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:475 + 6: std::panicking::begin_panic + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:404 + 7: Composition::main + at src/main.rs:55 + 8: std::rt::lang_start::{{closure}} + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67 + 9: std::rt::lang_start_internal::{{closure}} + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:52 + std::panicking::try::do_call + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:292 + 10: __rust_maybe_catch_panic + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libpanic_unwind/lib.rs:78 + 11: std::panicking::try + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:270 + std::panic::catch_unwind + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panic.rs:394 + std::rt::lang_start_internal + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:51 + 12: std::rt::lang_start + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67 + 13: _main + +2020-07-27 11:26:38 [ERROR] - panicked at 'Normal panic', src/main.rs:54:5 + 0: backtrace::backtrace::libunwind::trace + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/backtrace/libunwind.rs:95 + backtrace::backtrace::trace_unsynchronized + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/backtrace/mod.rs:66 + 1: backtrace::backtrace::trace + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/backtrace/mod.rs:53 + 2: backtrace::capture::Backtrace::create + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/capture.rs:164 + 3: backtrace::capture::Backtrace::new + at /Users/gt/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.50/src/capture.rs:128 + 4: Composition::main::{{closure}} + at src/main.rs:51 + 5: std::panicking::rust_panic_with_hook + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:475 + 6: std::panicking::begin_panic + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:404 + 7: Composition::main + at src/main.rs:54 + 8: std::rt::lang_start::{{closure}} + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67 + 9: std::rt::lang_start_internal::{{closure}} + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:52 + std::panicking::try::do_call + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:292 + 10: __rust_maybe_catch_panic + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libpanic_unwind/lib.rs:78 + 11: std::panicking::try + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:270 + std::panic::catch_unwind + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panic.rs:394 + std::rt::lang_start_internal + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:51 + 12: std::rt::lang_start + at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67 + 13: _main + +2020-07-27 11:30:23 [INFO] - Starting server... +2020-07-27 11:30:46 [INFO] - Starting server... +2020-07-27 11:31:01 [INFO] - Starting server +2020-07-27 11:40:10 [INFO] - Starting server... +2020-07-27 11:40:10 [INFO] - Done! Start took 763.52µs +2020-07-27 11:40:51 [INFO] - Starting server... +2020-07-27 11:40:51 [INFO] - Done! Start took 820.196µs +2020-07-27 11:47:37 [INFO] - Starting server... +2020-07-27 11:47:37 [INFO] - Done! Start took 441.888µs +2020-07-27 12:51:18 [INFO] - Starting server... +2020-07-27 12:51:18 [INFO] - Done! Start took 929.466µs +2020-07-27 13:14:52 [INFO] - Starting server... +2020-07-27 13:14:52 [INFO] - Starting network server... +2020-07-27 13:14:52 [INFO] - Done! Start took 829.689µs +2020-07-27 17:14:52 [INFO] - Starting server... +2020-07-27 17:14:52 [INFO] - Done! Start took 920.073µs +2020-07-27 17:14:52 [INFO] - Starting network... +2020-07-27 17:14:52 [INFO] - [] +2020-07-27 17:14:52 [INFO] - [] +2020-07-27 17:14:52 [INFO] - [] +2020-07-27 17:14:52 [INFO] - [] +2020-07-27 17:14:52 [INFO] - [] +2020-07-27 17:14:52 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:53 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:54 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:55 [INFO] - [] +2020-07-27 17:14:56 [INFO] - [] +2020-07-27 17:14:56 [INFO] - [] +2020-07-27 17:14:56 [INFO] - [] +2020-07-27 17:28:01 [INFO] - Starting server... +2020-07-27 17:28:01 [INFO] - Done! Start took 1.079011ms +2020-07-27 17:28:01 [INFO] - Starting network... +2020-07-27 17:28:32 [INFO] - Starting server... +2020-07-27 17:28:32 [INFO] - Done! Start took 891.237µs +2020-07-27 17:30:03 [INFO] - Starting server... +2020-07-27 17:30:03 [INFO] - Done! Start took 889.43µs +2020-07-27 17:30:39 [INFO] - Starting server... +2020-07-27 17:30:39 [INFO] - Done! Start took 668.524µs +2020-07-27 17:32:13 [DEBUG] - Network received client: NetworkClient { id: 0, state: Handshake, alive: true, stream: BufReader { reader: TcpStream { addr: V4(127.0.0.1:25565), peer: V4(127.0.0.1:58986), fd: 5 }, buffer: 0/8192 }, username: None, packets: [] } +2020-07-27 17:32:13 [DEBUG] - Network received client: NetworkClient { id: 1, state: Handshake, alive: true, stream: BufReader { reader: TcpStream { addr: V4(127.0.0.1:25565), peer: V4(127.0.0.1:58988), fd: 5 }, buffer: 0/8192 }, username: None, packets: [] } +2020-07-27 17:37:57 [INFO] - Starting server... +2020-07-27 17:37:57 [INFO] - Done! Start took 1.007552ms +2020-07-27 18:15:45 [INFO] - Starting server... +2020-07-27 18:15:45 [INFO] - Done! Start took 812.588µs diff --git a/src/logger.rs b/src/logger.rs deleted file mode 100644 index 44381df..0000000 --- a/src/logger.rs +++ /dev/null @@ -1,99 +0,0 @@ -// logger.rs -// author: Garen Tyler -// description: -// A global logger for Composition. -// The Logger struct makes it easy to create useful server logs. - -extern crate chrono; // Used because std::time sucks. -extern crate toml; // Colorful console logging is fun. - -use chrono::prelude::*; -use colorful::{Color, Colorful}; -use std::fs::File; -use std::fs::OpenOptions; -use std::io::prelude::*; - -// Uses chrono::Local to get a timestamp in YYYY-MM-DD HH:MM:SS format, in local time. -pub fn get_timestring() -> String { - Local::now().format("%Y-%m-%d %H:%M:%S").to_string() -} -// Just a helper function to avoid repeating myself. -pub fn log(logtype: &str, logmessage: &str) -> String { - format!("{} [{}] - {}", get_timestring(), logtype, logmessage) -} -// So I can do logger::new("log.txt") instead of logger::Logger::new("log.txt"). -pub fn new(logfile: &str) -> Logger { - Logger::new(logfile) -} - -#[derive(Clone)] -pub struct Logger { - pub logfile: String, -} -impl Logger { - pub fn new(logfile: &str) -> Logger { - Logger { - logfile: logfile.to_owned(), - } - } - // For logging something important, like the server port. - pub fn important(&self, s: &str) { - let l = log("IMPORTANT", s); - println!("{}", l.clone().color(Color::Green)); - self.append(&l); - } - // For everything that doesn't fit into any of the other categories. - pub fn info(&self, s: &str) { - let l = log("INFO", s); - // Not sure whether I want normal logs to be user controlled color or white. - // println!("{}", l.clone().color(Color::White)); - println!("{}", l.clone()); - self.append(&l); - } - // For warnings. - pub fn warn(&self, s: &str) { - let l = log("WARN", s); - println!("{}", l.clone().color(Color::LightYellow)); - self.append(&l); - } - // For errors. - pub fn error(&self, s: &str) { - let l = log("ERROR", s); - println!("{}", l.clone().color(Color::LightRed)); - self.append(&l); - } - // Append to the logfile. - pub fn append(&self, s: &str) { - let a = || -> std::io::Result<()> { - let mut file = OpenOptions::new() - .create(true) - .write(true) - .append(true) - .open(&self.logfile)?; - writeln!(file, "{}", s)?; - Ok(()) - }; - if a().is_err() { - self.logger_error(&format!("Could not write to log file {}", self.logfile)); - } - } - // Clear the logfile. Adds an important note to the file that it was cleared. - pub fn clear(&self) { - if std::fs::remove_file(&self.logfile).is_err() { - self.logger_error(&format!("Could not write to log file {}", self.logfile)); - } - self.important(&format!("Cleared log file {}", self.logfile)); - } - // Read the logfile into a String. - pub fn read(&self) -> std::io::Result { - let mut f = File::open(&self.logfile)?; - let mut buffer = String::new(); - f.read_to_string(&mut buffer)?; - Ok(buffer) - } - // For a critical logger error. This doesn't append to the logfile. - pub fn logger_error(&self, error_message: &str) { - let l = log("ERROR", error_message); - println!("{}", l.clone().color(Color::LightRed)); - } -} diff --git a/src/main.rs b/src/main.rs index 82adf61..f0860f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,72 +1,73 @@ // main.rs // authors: Garen Tyler, Danton Hou // description: -// Main Game loop, config handler. +// Initializes the server, main server loop. #![allow(non_snake_case)] #![allow(non_upper_case_globals)] +#![allow(unused_imports)] -#[macro_use] -extern crate lazy_static; +extern crate backtrace; +extern crate fern; +extern crate log; extern crate serde; -pub mod logger; -pub mod mctypes; -pub mod net; -pub mod protocol; +pub mod network; +pub mod server; + +use backtrace::Backtrace; +use fern::colors::{Color, ColoredLevelConfig}; +use log::{debug, error, info, warn}; +use network::NetworkServer; use serde::{Deserialize, Serialize}; - -lazy_static! { - static ref log: logger::Logger = logger::new("log.txt"); - static ref config: Config = { Config::from_file("composition.toml") }; -} +use server::{Server, ServerConfig}; +use std::sync::mpsc::{self, Receiver, Sender}; +use std::time::{Duration, Instant}; fn main() { - // Start the network thread. - std::thread::spawn(|| { - log.info("Network thread started"); - net::start_listening(); - }); - // Loop the main thread for now. - loop {} -} + // Setup logging. + fern::Dispatch::new() + .format(move |out, message, record| { + out.finish(format_args!( + "{date} [{level}] - {message}", + date = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + // target = record.target(), + level = record.level(), + message = message, + )) + }) + .level(log::LevelFilter::Debug) + .chain(std::io::stdout()) + .chain(fern::log_file("output.log").unwrap()) + .apply() + .unwrap(); -// Not in it's own config module because of name conflicts. -#[derive(Serialize, Deserialize, Debug)] -pub struct Config { - pub port: u16, - pub protocol_version: u16, - pub max_players: u32, - pub motd: String, - pub favicon: Option, -} -impl Config { - pub fn default() -> Config { - Config { - port: 25565, - protocol_version: 578, - max_players: 250, - motd: "Hello world!".to_owned(), - favicon: None, - } - } - pub fn from_file(filename: &str) -> Config { - use std::fs::File; - use std::io::prelude::*; - let a = || -> std::io::Result { - let mut file = File::open(filename)?; - let mut configStr = String::new(); - file.read_to_string(&mut configStr)?; - Ok(toml::from_str(&configStr)?) - }; - if let Ok(c) = a() { - c - } else { - log.warn(&format!( - "Could not load config from {}, using default config.", - filename - )); - Config::default() - } + std::panic::set_hook(Box::new(|panic_info| { + let backtrace = Backtrace::new(); + error!("{}\n{:?}", panic_info.to_string(), backtrace); + })); + + info!("Starting server..."); + let start_time = Instant::now(); + + let config = ServerConfig::from_file("composition.toml"); + let port = config.port; + + // Create the message channels. + let (tx, rx) = mpsc::channel(); + + // Create the server. + let mut server = Server { + config, + receiver: rx, + network: NetworkServer::new(port), + }; + + info!("Done! Start took {:?}", start_time.elapsed()); + + // The main server loop. + loop { + server.update(); // Do the tick. + std::thread::sleep(Duration::from_millis(50)); } } diff --git a/src/network/mod.rs b/src/network/mod.rs new file mode 100644 index 0000000..1f6756b --- /dev/null +++ b/src/network/mod.rs @@ -0,0 +1,84 @@ +// network/mod.rs +// authors: Garen Tyler +// description: +// This module contains the network logic. + +pub mod packet; + +use crate::server::ServerMessage; +use log::{debug, error, info, warn}; +use packet::Packet; +use std::io::BufReader; +use std::net::{TcpListener, TcpStream}; +use std::sync::mpsc::{self, Receiver, Sender}; + +pub struct NetworkServer { + receiver: Receiver, + clients: Vec, +} +impl NetworkServer { + pub fn new(port: u16) -> NetworkServer { + let (tx, rx) = mpsc::channel(); + std::thread::spawn(move || NetworkServer::listen(port, tx)); + NetworkServer { + receiver: rx, + clients: Vec::new(), + } + } + fn listen(port: u16, sender: Sender) { + let listener = TcpListener::bind(&format!("0.0.0.0:{}", port)).unwrap(); + + for (index, stream) in listener.incoming().enumerate() { + let stream = stream.unwrap(); + stream.set_nonblocking(true).unwrap(); + sender + .send(NetworkClient { + // The index will increment after each client making it unique. We'll just use this as the id. + id: index as u32, + stream: BufReader::new(stream), + state: NetworkClientState::Handshake, + packets: Vec::new(), + username: None, + alive: true, + }) + .unwrap(); + } + } + pub fn update(&mut self) { + loop { + match self.receiver.try_recv() { + Ok(client) => self.clients.push(client), + Err(mpsc::TryRecvError::Empty) => break, + Err(mpsc::TryRecvError::Disconnected) => { + panic!("Client receiver channel disconnected!") + } + } + } + // Todo: Update each client + for client in self.clients.iter_mut() { + client.update(); + } + } +} + +#[derive(Debug)] +pub struct NetworkClient { + id: u32, + state: NetworkClientState, + alive: bool, + stream: BufReader, + username: Option, + packets: Vec, +} + +impl NetworkClient { + pub fn update(&mut self) {} +} + +#[derive(PartialEq, Debug)] +pub enum NetworkClientState { + Handshake, + Status, + Login, + Play, +} diff --git a/src/network/packet/mod.rs b/src/network/packet/mod.rs new file mode 100644 index 0000000..c70fc5a --- /dev/null +++ b/src/network/packet/mod.rs @@ -0,0 +1,13 @@ +// network/packet/mod.rs +// authors: Garen Tyler +// description: +// This module contains the packet structs. + +#[derive(Debug)] +pub struct Packet { + kind: PacketType, +} +#[derive(PartialEq, Debug)] +pub enum PacketType { + Handshake, +} diff --git a/src/old_net.rs b/src/old_net.rs deleted file mode 100644 index 9d0e0c7..0000000 --- a/src/old_net.rs +++ /dev/null @@ -1,219 +0,0 @@ -// old_net.rs -// author: Garen Tyler -// description: -// This was the original implementation of net.rs. Only use as a reference. - -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 crate::mctypes::*; -use serde::Serialize; -use serde_json::json; -use std::io::prelude::*; -use std::net::{TcpListener, TcpStream}; -use std::thread; - -pub struct MCPacket { - pub id: MCVarInt, - pub data: Vec, -} -#[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) { - for b in v { - self.data.push(b); - } - } - pub fn to_bytes(&self) -> Vec { - 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," - }) - .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(()) -} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..c696535 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,75 @@ +// server.rs +// author: Garen Tyler +// description: +// Contains the server logic. + +use crate::network::NetworkServer; +use log::{debug, error, info, warn}; +use serde::{Deserialize, Serialize}; +use std::sync::mpsc::{self, Receiver, Sender, TryRecvError}; + +pub struct Server { + pub config: ServerConfig, + pub receiver: Receiver, + pub network: NetworkServer, +} +impl Server { + pub fn update(&mut self) { + // Do a tick. + while let Ok(message) = self.receiver.try_recv() { + debug!("Server received message: {:?}", message); + self.handle_message(message); + } + self.network.update(); + } + fn handle_message(&self, message: ServerMessage) {} + pub fn shutdown(&self) { + unimplemented!(); + } +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct ServerConfig { + pub port: u16, + pub protocol_version: u16, + pub max_players: u32, + pub motd: String, + pub favicon: Option, +} +impl ServerConfig { + pub fn default() -> ServerConfig { + ServerConfig { + port: 25565, + protocol_version: 578, + max_players: 250, + motd: "Hello world!".to_owned(), + favicon: None, + } + } + pub fn from_file(filename: &str) -> ServerConfig { + use std::fs::File; + use std::io::prelude::*; + let a = || -> std::io::Result { + let mut file = File::open(filename)?; + let mut configStr = String::new(); + file.read_to_string(&mut configStr)?; + Ok(toml::from_str(&configStr)?) + }; + if let Ok(c) = a() { + c + } else { + warn!( + "Could not load config from {}, using default config.", + filename + ); + ServerConfig::default() + } + } +} + +#[derive(Debug)] +pub enum BroadcastMessage { + Shutdown, +} +#[derive(Debug)] +pub enum ServerMessage {}