my computer is dying
This commit is contained in:
parent
d3e6467c6c
commit
d98e56d413
240
Cargo.lock
generated
240
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
||||
|
@ -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
82
src/command.rs
Normal 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(())
|
||||
}
|
54
src/error.rs
54
src/error.rs
@ -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
271
src/extensions.rs
Normal 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,
|
||||
¤t_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
11
src/extensions/jimmy.rhai
Normal 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
|
||||
}
|
10
src/extensions/ping-pong.rhai
Normal file
10
src/extensions/ping-pong.rhai
Normal 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
|
||||
}
|
18
src/main.rs
18
src/main.rs
@ -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(())
|
||||
|
@ -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, ¤t_player, &world_arc_clone);
|
||||
let _ = bomb_server_details(&mut stream, ¤t_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(
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
26
src/utils.rs
26
src/utils.rs
@ -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: {}", ¤t_player.username);
|
||||
compound_data.append(&mut spawn_player(
|
||||
@ -235,5 +236,6 @@ pub fn bomb_server_details(
|
||||
));
|
||||
|
||||
let _ = stream.write(&compound_data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -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)?)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user