my computer is dying

This commit is contained in:
illegitimate-egg 2025-03-01 22:21:19 +00:00
parent d3e6467c6c
commit d98e56d413
11 changed files with 685 additions and 108 deletions

240
Cargo.lock generated
View File

@ -8,18 +8,41 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"const-random",
"getrandom",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -42,6 +65,26 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "crc32fast"
version = "1.4.2"
@ -51,6 +94,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crunchy"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "ctrlc"
version = "3.4.5"
@ -91,6 +140,15 @@ dependencies = [
"wasi",
]
[[package]]
name = "instant"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if",
]
[[package]]
name = "itoa"
version = "1.0.14"
@ -119,15 +177,20 @@ checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
name = "mcrizzledizzle"
version = "0.1.0"
dependencies = [
"colored",
"ctrlc",
"flate2",
"lazy_static",
"log",
"rand",
"regex",
"rhai",
"simple_logger",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.8.5"
@ -149,12 +212,30 @@ dependencies = [
"libc",
]
[[package]]
name = "no-std-compat"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
dependencies = [
"spin",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "num_threads"
version = "0.1.7"
@ -164,21 +245,27 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
dependencies = [
"portable-atomic",
]
[[package]]
name = "portable-atomic"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[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.93"
@ -198,33 +285,61 @@ dependencies = [
]
[[package]]
name = "rand"
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rhai"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce4d759a4729a655ddfdbb3ff6e77fb9eadd902dae12319455557796e435d2a6"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"ahash",
"bitflags",
"instant",
"no-std-compat",
"num-traits",
"once_cell",
"rhai_codegen",
"smallvec",
"smartstring",
"thin-vec",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
name = "rhai_codegen"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
checksum = "a5a11a05ee1ce44058fa3d5961d05194fdbe3ad6b40f904af764d81b86450e6b"
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",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -259,6 +374,35 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "smallvec"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "smartstring"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
dependencies = [
"autocfg",
"static_assertions",
"version_check",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.98"
@ -270,6 +414,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "thin-vec"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b"
[[package]]
name = "time"
version = "0.3.37"
@ -303,12 +453,27 @@ dependencies = [
"time-core",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "unicode-ident"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[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"
@ -460,7 +625,6 @@ version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]

View File

@ -4,13 +4,15 @@ version = "0.1.0"
edition = "2021"
[dependencies]
colored = "2.1.0"
ctrlc = "3.4.5"
flate2 = "1.0.30"
lazy_static = "1.4.0"
log = "0.4.26"
rand = "0.8.5"
regex = "1.11.1"
[dependencies.simple_logger]
version = "5.0.0"
features = ["threads", "nightly"]
[dependencies.rhai]
version = "1.21.0"
features = ["sync"]

82
src/command.rs Normal file
View File

@ -0,0 +1,82 @@
use log::error;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use crate::error::AppError;
use crate::extensions::Extensions;
use crate::player::{Player, SpecialPlayers};
use crate::utils::*;
pub fn handle_command(
stream: &mut TcpStream,
client_number: u8,
players_arc_clone: &Arc<Mutex<[Player; 255]>>,
extensions: &Arc<Extensions>,
command_string: &String,
) -> Result<(), AppError> {
let vectorized_command = command_string.split(" ").collect::<Vec<&str>>();
match vectorized_command[0] {
"kick" => {
let mut players = players_arc_clone
.lock()
.map_err(|e| AppError::MutexPoisoned(e.to_string()))?;
for i in 0..players.len() {
if players[i].id != 255 {
if players[i].username == vectorized_command[1] {
let _ = &mut players[i]
.outgoing_data
.extend_from_slice(&client_disconnect("KICKED!"));
players[i].id = 255;
break;
}
}
}
}
"tp" => {
let players = players_arc_clone
.lock()
.map_err(|e| AppError::MutexPoisoned(e.to_string()))?;
for i in 0..players.len() {
if players[i].id != 255 {
if players[i].username == vectorized_command[1] {
let _ = &mut stream.write(&set_position_and_orientation(
SpecialPlayers::SelfPlayer as u8,
players[i].position_x,
players[i].position_y,
players[i].position_z,
players[i].yaw,
players[i].pitch,
));
break;
}
}
}
}
_ => {
let found = match extensions.run_command(vectorized_command[0].to_string(), client_number) {
Ok(result) => result,
Err(error) => {
error!("Rhai plugin error: {}", error);
let _ = &mut stream.write(&send_chat_message(
SpecialPlayers::SelfPlayer as u8,
"".to_string(),
"&cAn internal error occured while processing this command".to_string(),
));
return Ok(());
}
};
if found {
return Ok(());
}
let _ = &mut stream.write(&send_chat_message(
SpecialPlayers::SelfPlayer as u8,
"".to_string(),
"&cUnkown command!".to_string(),
));
}
}
Ok(())
}

View File

@ -1,16 +1,34 @@
use std::fmt;
use std::num::{ParseIntError, ParseFloatError, TryFromIntError};
use std::sync::PoisonError;
use rhai::EvalAltResult;
#[derive(Debug)]
pub enum AppError {
IoError(std::io::Error),
RegexError(regex::Error),
ParseIntError(ParseIntError),
ParseFloatError(ParseFloatError),
TryFromIntError(TryFromIntError),
RhaiError(Box<EvalAltResult>),
MutexPoisoned(String),
InvalidWorldFile,
// InvalidExtensionVersion,
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AppError::IoError(err) => write!(f, "IO Error: {}", err),
AppError::RegexError(err) => write!(f, "Extension Regex Error: {}", err),
AppError::ParseIntError(err) => write!(f, "Parse int error: {}", err),
AppError::ParseFloatError(err) => write!(f, "Parse float error: {}", err),
AppError::TryFromIntError(err) => write!(f, "Integer conversion error: {}", err),
AppError::RhaiError(err) => write!(f, "Rhai compilation error: {}", err),
AppError::MutexPoisoned(err) => write!(f, "Poisoned mutex: {}", err),
AppError::InvalidWorldFile => write!(f, "Invalid world file"),
// AppError::InvalidExtensionVersion => write!(f, "Invalid extension version"),
}
}
}
@ -20,3 +38,39 @@ impl From<std::io::Error> for AppError {
AppError::IoError(err)
}
}
impl From<regex::Error> for AppError {
fn from(err: regex::Error) -> Self {
AppError::RegexError(err)
}
}
impl From<ParseIntError> for AppError {
fn from(err: ParseIntError) -> Self {
AppError::ParseIntError(err)
}
}
impl From<ParseFloatError> for AppError {
fn from(err: ParseFloatError) -> Self {
AppError::ParseFloatError(err)
}
}
impl From<TryFromIntError> for AppError {
fn from(err: TryFromIntError) -> Self {
AppError::TryFromIntError(err)
}
}
impl From<Box<EvalAltResult>> for AppError {
fn from(err: Box<EvalAltResult>) -> Self {
AppError::RhaiError(err)
}
}
impl<T> From<PoisonError<T>> for AppError {
fn from(err: PoisonError<T>) -> Self {
AppError::MutexPoisoned(err.to_string())
}
}

271
src/extensions.rs Normal file
View File

@ -0,0 +1,271 @@
use log::{error, info};
use regex::Regex;
use rhai::{CustomType, Engine, EvalAltResult, FnPtr, Scope, TypeBuilder, AST};
use std::{
collections::HashMap,
ffi::OsStr,
fs,
path::Path,
sync::{Arc, Mutex},
};
use crate::{error::AppError, player::Player, utils::send_chat_message};
pub struct Extensions {
extensions: Vec<Extension>,
}
impl Extensions {
pub fn run_command(&self, key: String, player: u8) -> Result<bool, AppError> {
// Bool success
for extension in &self.extensions {
if let Some(key_value) = extension.commands.get(&key) {
key_value.call::<()>(&extension.engine, &extension.ast, (player,))?;
return Ok(true);
}
}
Ok(false)
}
}
pub struct Extension {
ast: AST,
engine: Engine,
commands: HashMap<String, FnPtr>,
metadata: ExtensionMetadata,
}
////// BEGIN RHAI DEFINITIONS //////
#[derive(Debug, Clone, Eq, PartialEq, CustomType)]
#[rhai_type(name = "Version", extra = Self::build_extra)]
struct Version {
major: u16,
minor: u16,
patch: u16,
prerelease: String,
build: String,
}
impl Version {
pub fn display(&self) -> String {
let mut base = format!("{}.{}.{}", self.major, self.minor, self.patch);
if !self.prerelease.is_empty() {
base.push_str(&format!("-{}", self.prerelease).to_string());
}
if !self.build.is_empty() {
base.push_str(&format!("+{}", self.build).to_string());
}
base
}
fn parse(version_string: String) -> Result<Self, Box<EvalAltResult>> {
let Ok(re) = Regex::new(
r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$",
) else {
return Err("Failed to create regex".into());
};
let Some(version_parts) = re.captures(&version_string) else {
return Err("Invalid Extension Version".into());
};
let mut prerelease: String = "".to_string();
let mut build: String = "".to_string();
if version_parts.name("prerelease").is_some() {
prerelease = version_parts["prerelease"].to_string();
}
if version_parts.name("buildmetadata").is_some() {
build = version_parts["buildmetadata"].to_string();
}
Ok(Version {
major: version_parts["major"].parse::<u16>().unwrap(),
minor: version_parts["minor"].parse::<u16>().unwrap(),
patch: version_parts["patch"].parse::<u16>().unwrap(),
prerelease,
build,
})
}
fn build_extra(builder: &mut TypeBuilder<Self>) {
// Register constructor function
builder.with_fn("Version", Self::parse);
}
}
#[derive(Debug, Clone, Eq, PartialEq, CustomType)]
#[rhai_type(name = "Metadata", extra = Self::build_extra)]
struct ExtensionMetadata {
name: String,
version: Version,
}
impl ExtensionMetadata {
fn new(name: String, version: Version) -> Self {
Self { name, version }
}
fn build_extra(builder: &mut TypeBuilder<Self>) {
// Register constructor function
builder.with_fn("Metadata", Self::new);
}
}
#[derive(Debug, Clone, CustomType)]
#[rhai_type(name = "Player")]
struct RhaiPlayer {
id: u8,
}
#[derive(Debug, Clone, CustomType)]
#[rhai_type(name = "PlayersWrapper")]
pub struct PlayersWrapper(Arc<Mutex<[Player; 255]>>);
impl PlayersWrapper {
pub fn new(players: Arc<Mutex<[Player; 255]>>) -> Self {
Self(players)
}
pub fn send_message(&self, player: RhaiPlayer, message: String) -> Result<(), Box<EvalAltResult>> {
let mut players = self.0.lock().unwrap();
players[player.id as usize]
.outgoing_data
.extend_from_slice(&send_chat_message(255, "".to_string(), message));
Ok(())
}
}
#[derive(Debug, Clone, CustomType)]
#[rhai_type(name = "Context", extra = Self::build_extra)]
struct Context {
#[rhai_type(skip)]
commands: HashMap<String, FnPtr>,
#[rhai_type(skip)]
players: PlayersWrapper,
}
impl Context {
fn new(players: PlayersWrapper) -> Self {
Self {
commands: HashMap::new(),
players,
}
}
pub fn players(&mut self) -> PlayersWrapper {
self.players.clone()
}
fn register_command(&mut self, name: String, callback: FnPtr) {
self.commands.insert(name, callback);
}
fn build_extra(builder: &mut TypeBuilder<Self>) {
builder.with_fn("Context", Self::new);
builder.with_fn("register_command", Self::register_command);
}
}
////// END RHAI DEFINITIONS //////
impl Extensions {
pub fn init(players: PlayersWrapper) -> Result<Extensions, AppError> {
if !Path::new("./extensions/").exists() {
let _ = fs::create_dir("./extensions/");
}
let extensions_listing = fs::read_dir("./extensions")?;
let mut extensions = Extensions {
extensions: Vec::new(),
};
for extension in extensions_listing {
let extension_path = extension?.path();
if extension_path.extension() != Some(OsStr::new("rhai")) {
break;
}
info!("Loading extension {}", extension_path.display());
let mut engine = Engine::new();
engine.build_type::<Version>();
engine.build_type::<ExtensionMetadata>();
engine.build_type::<RhaiPlayer>();
engine.build_type::<PlayersWrapper>();
engine.build_type::<Context>();
let ast = engine.compile_file(extension_path.clone().into())?;
let mut scope = Scope::new();
let extension_metadata =
match engine.call_fn::<ExtensionMetadata>(&mut scope, &ast, "metadata", ()) {
Ok(result) => result,
Err(error) => {
error!(
"Rhai plugin with path {} missing critical section metadata! {}",
extension_path.display(),
error
);
break;
}
};
let mut current_extension = Extension {
ast,
engine,
commands: HashMap::new(),
metadata: extension_metadata,
};
let ctx = match current_extension.engine.call_fn::<Context>(
&mut scope,
&current_extension.ast,
"init",
(PlayersWrapper::new(players.0.clone()),)
) {
Ok(result) => result,
Err(error) => {
error!(
"Plugin {} failed to init: {}",
current_extension.metadata.name, error
);
break;
}
};
for (key, value) in ctx.commands.iter() {
current_extension
.commands
.insert(key.to_string(), value.clone());
}
info!(
"Loaded {} v{}",
current_extension.metadata.name,
current_extension.metadata.version.display()
);
extensions.extensions.push(current_extension);
}
for extension in &extensions.extensions {
for command_name in extension.commands.keys() {
info!(
"Extension {} v{} has reserved command: {}",
extension.metadata.name,
extension.metadata.version.display(),
command_name
);
}
}
Ok(extensions)
}
}

11
src/extensions/jimmy.rhai Normal file
View File

@ -0,0 +1,11 @@
fn metadata() {
Metadata("jimmy", Version("2.0.0-balls+tweaking"))
}
fn init(players) {
let ctx = Context(players);
ctx.register_command("jimmy", |player| {
players.send_message("He's dead")
});
ctx
}

View File

@ -0,0 +1,10 @@
fn metadata() {
Metadata("ping pong", Version("1.0.0"))
}
fn init() {
let ctx = Context();
ctx.register_command("ping", |player| player.sendMessage("Pong! (you smell)"));
ctx.register_command("test", |player| player.sendMessage("test"));
ctx
}

View File

@ -3,13 +3,16 @@ use simple_logger::SimpleLogger;
use std::net::{SocketAddr, TcpListener};
use std::sync::{Arc, Mutex};
mod command;
mod error;
mod extensions;
mod network;
mod player;
mod utils;
mod world;
use error::AppError;
use extensions::{Extensions, PlayersWrapper};
use network::handle_client;
use player::{Player, SpecialPlayers};
use world::World;
@ -39,15 +42,26 @@ fn run() -> Result<(), AppError> {
ctrlc::set_handler(move || {
println!("");
info!("SAVING");
let _ = World::save(world_arc_clone_main_thread.clone()); // Fortnite save the world
let _ = World::save(world_arc_clone_main_thread.clone()).unwrap(); // Fortnite save the world
std::process::exit(0);
})
.expect("Error handling control C, save on exit will not work");
let extensions = Arc::new(Extensions::init(PlayersWrapper::new(players_arc.clone()))?);
info!("Server listening on {}", 25565);
for stream in listener.incoming() {
let players_arc_clone = Arc::clone(&players_arc);
let world_arc_clone = Arc::clone(&world_arc);
handle_client(stream?, thread_number, players_arc_clone, world_arc_clone);
let extensions_arc_clone = Arc::clone(&extensions);
handle_client(
stream?,
thread_number,
players_arc_clone,
world_arc_clone,
extensions_arc_clone,
);
thread_number = thread_number.wrapping_add(1);
}
Ok(())

View File

@ -1,20 +1,23 @@
use std::net::TcpStream;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use log::{info, warn};
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use std::thread;
use std::thread::sleep;
use std::time::Duration;
use crate::player::{Player, SpecialPlayers, PlayerStatus};
use crate::world::World;
use crate::command::handle_command;
use crate::extensions::Extensions;
use crate::player::{Player, PlayerStatus, SpecialPlayers};
use crate::utils::*;
use crate::world::World;
pub fn handle_client(
mut stream: TcpStream,
client_number: u8,
players_arc_clone: Arc<Mutex<[Player; 255]>>,
world_arc_clone: Arc<Mutex<World>>,
extensions: Arc<Extensions>,
) {
thread::spawn(move || {
info!("Thread initialized with player ID: {}", client_number);
@ -90,7 +93,7 @@ pub fn handle_client(
current_player.pitch = 0;
current_player.operator = true;
bomb_server_details(&mut stream, &current_player, &world_arc_clone);
let _ = bomb_server_details(&mut stream, &current_player, &world_arc_clone);
for i in 0..immediate_join.len() {
if immediate_join[i] {
@ -207,49 +210,13 @@ pub fn handle_client(
// Uh oh, command time
info!("{}", message_string);
let remaning_command = String::from_iter(&message[1..message.len()]);
let vectorized_command = remaning_command.split(" ").collect::<Vec<&str>>();
match vectorized_command[0] {
"kick" => {
let mut players = players_arc_clone.lock().unwrap();
for i in 0..players.len() {
if players[i].id != 255 {
if players[i].username == vectorized_command[1] {
let _ = &mut players[i]
.outgoing_data
.extend_from_slice(&client_disconnect("KICKED!"));
players[i].id = 255;
break;
}
}
}
}
"tp" => {
let players = players_arc_clone.lock().unwrap();
for i in 0..players.len() {
if players[i].id != 255 {
if players[i].username == vectorized_command[1] {
let _ =
&mut stream.write(&set_position_and_orientation(
SpecialPlayers::SelfPlayer as u8,
players[i].position_x,
players[i].position_y,
players[i].position_z,
players[i].yaw,
players[i].pitch,
));
break;
}
}
}
}
_ => {
let _ = &mut stream.write(&send_chat_message(
SpecialPlayers::SelfPlayer as u8,
"".to_string(),
"&cUnkown command!".to_string(),
));
}
}
let _ = handle_command(
&mut stream,
client_number,
&players_arc_clone,
&extensions,
&remaning_command,
);
} else {
let mut players = players_arc_clone.lock().unwrap();
let sender: u8 = players[client_number as usize].id;
@ -344,4 +311,3 @@ pub fn handle_client(
);
});
}

View File

@ -5,6 +5,7 @@ use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use crate::error::AppError;
use crate::World;
use crate::SpecialPlayers;
use crate::Player;
@ -63,17 +64,17 @@ pub fn init_level() -> Vec<u8> {
vec![0x02]
}
pub fn finalize_level(world_arc_clone: &Arc<Mutex<World>>) -> Vec<u8> {
pub fn finalize_level(world_arc_clone: &Arc<Mutex<World>>) -> Result<Vec<u8>, AppError> {
let mut ret_val: Vec<u8> = vec![];
ret_val.push(0x04);
let world_dat = world_arc_clone.lock().unwrap();
let world_dat = world_arc_clone.lock()?;
ret_val.append(&mut stream_write_short(world_dat.size_x).to_vec());
ret_val.append(&mut stream_write_short(world_dat.size_y).to_vec());
ret_val.append(&mut stream_write_short(world_dat.size_z).to_vec());
ret_val
Ok(ret_val)
}
pub fn spawn_player(
@ -140,9 +141,9 @@ pub fn set_position_and_orientation(
ret_val
}
pub fn send_level_data(world_arc_clone: &Arc<Mutex<World>>) -> Vec<u8> {
pub fn send_level_data(world_arc_clone: &Arc<Mutex<World>>) -> Result<Vec<u8>, AppError> {
let mut ret_val: Vec<u8> = vec![];
let mut world_dat = world_arc_clone.lock().unwrap().data.clone();
let mut world_dat = world_arc_clone.lock()?.data.clone();
// Big endian fold lmao
world_dat.insert(0, ((world_dat.len() & 0xFF) >> 0) as u8);
@ -154,7 +155,7 @@ pub fn send_level_data(world_arc_clone: &Arc<Mutex<World>>) -> Vec<u8> {
let mut world_dat_compressor = GzEncoder::new(Vec::new(), Compression::fast());
let _ = world_dat_compressor.write_all(&world_dat);
let world_dat_gzipped = world_dat_compressor.finish().unwrap();
let world_dat_gzipped = world_dat_compressor.finish()?;
let number_of_chunks = ((world_dat_gzipped.len() as f32) / 1024.0_f32).ceil() as usize;
let mut current_chunk = 0;
@ -177,7 +178,7 @@ pub fn send_level_data(world_arc_clone: &Arc<Mutex<World>>) -> Vec<u8> {
percentage = 100;
}
ret_val.push(percentage.try_into().unwrap());
ret_val.push(percentage.try_into()?);
current_chunk += 1;
}
@ -189,7 +190,7 @@ pub fn send_level_data(world_arc_clone: &Arc<Mutex<World>>) -> Vec<u8> {
ret_val.push(0x03);
ret_val.append(&mut stream_write_short(
remaining_chunk_size.try_into().unwrap(),
remaining_chunk_size.try_into()?,
));
let mut remaining_data_buffer = [0u8; 1024];
@ -205,23 +206,23 @@ pub fn send_level_data(world_arc_clone: &Arc<Mutex<World>>) -> Vec<u8> {
"World transmission size: {}KiB",
ret_val.len() as f32 / 1024.0
);
ret_val
Ok(ret_val)
}
pub fn bomb_server_details(
stream: &mut TcpStream,
current_player: &Player,
world_arc_clone: &Arc<Mutex<World>>,
) {
) -> Result<(), AppError> {
let mut compound_data: Vec<u8> = vec![];
compound_data.append(&mut server_identification(current_player.operator));
compound_data.append(&mut init_level());
// info!("Send level data");
compound_data.append(&mut send_level_data(&world_arc_clone)); // Approaching Nirvana - Maw of the beast
compound_data.append(&mut send_level_data(&world_arc_clone)?); // Approaching Nirvana - Maw of the beast
compound_data.append(&mut finalize_level(&world_arc_clone));
compound_data.append(&mut finalize_level(&world_arc_clone)?);
info!("Spawning player: {}", &current_player.username);
compound_data.append(&mut spawn_player(
@ -235,5 +236,6 @@ pub fn bomb_server_details(
));
let _ = stream.write(&compound_data);
Ok(())
}

View File

@ -72,10 +72,11 @@ impl World {
}
}
pub fn save(world_arc_clone: Arc<Mutex<World>>) -> std::io::Result<()> {
pub fn save(world_arc_clone: Arc<Mutex<World>>) -> Result<(), AppError> {
let mut to_write: Vec<u8> = Vec::new();
{
let mut world_dat = world_arc_clone.lock().unwrap();
let mut world_dat = world_arc_clone.lock().map_err(|e| AppError::MutexPoisoned(e.to_string()))?;
to_write.push((world_dat.size_x >> 8) as u8);
to_write.push((world_dat.size_x & 0xFF) as u8);
to_write.push((world_dat.size_y >> 8) as u8);
@ -86,6 +87,6 @@ impl World {
}
let mut file = File::create("world.wrld")?;
file.write_all(&to_write)
Ok(file.write_all(&to_write)?)
}
}