Move server to subcommand
This commit is contained in:
parent
c85b9a4bc2
commit
e72f19a814
@ -9,7 +9,7 @@ RUN cargo install cargo-watch --locked --version 8.5.3
|
|||||||
VOLUME /app
|
VOLUME /app
|
||||||
VOLUME /app/.git
|
VOLUME /app/.git
|
||||||
EXPOSE 25565
|
EXPOSE 25565
|
||||||
CMD ["cargo", "watch", "-x", "run"]
|
CMD ["cargo", "watch", "-x", "run -- server"]
|
||||||
|
|
||||||
FROM base AS planner
|
FROM base AS planner
|
||||||
COPY Cargo.toml .
|
COPY Cargo.toml .
|
||||||
@ -36,3 +36,4 @@ COPY --from=builder /app/target/release/composition /app
|
|||||||
EXPOSE 25565
|
EXPOSE 25565
|
||||||
USER composition
|
USER composition
|
||||||
ENTRYPOINT ["tini", "--", "/app/composition"]
|
ENTRYPOINT ["tini", "--", "/app/composition"]
|
||||||
|
CMD [ "server" ]
|
||||||
|
@ -13,6 +13,7 @@ pub static CONFIG: OnceCell<Config> = OnceCell::new();
|
|||||||
/// On program startup, Args::load() should be called to initialize it.
|
/// On program startup, Args::load() should be called to initialize it.
|
||||||
pub static ARGS: OnceCell<Args> = OnceCell::new();
|
pub static ARGS: OnceCell<Args> = OnceCell::new();
|
||||||
static DEFAULT_ARGS: Lazy<Args> = Lazy::new(Args::default);
|
static DEFAULT_ARGS: Lazy<Args> = Lazy::new(Args::default);
|
||||||
|
static DEFAULT_SERVER_ARGS: Lazy<ServerArgs> = Lazy::new(ServerArgs::default);
|
||||||
|
|
||||||
/// Helper function to read a file from a `Path`
|
/// Helper function to read a file from a `Path`
|
||||||
/// and return its bytes as a `Vec<u8>`.
|
/// and return its bytes as a `Vec<u8>`.
|
||||||
@ -99,7 +100,11 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the server icon
|
// Load the server icon
|
||||||
config.server_icon = args.server_icon.clone();
|
config.server_icon = args
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.server_icon.clone())
|
||||||
|
.unwrap_or(DEFAULT_SERVER_ARGS.server_icon.clone());
|
||||||
let server_icon_path = Path::new(&config.server_icon);
|
let server_icon_path = Path::new(&config.server_icon);
|
||||||
|
|
||||||
if server_icon_path.exists() {
|
if server_icon_path.exists() {
|
||||||
@ -156,24 +161,31 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum Subcommand {
|
||||||
|
None,
|
||||||
|
Server,
|
||||||
|
}
|
||||||
|
|
||||||
/// All of the valid command line arguments for the composition binary.
|
/// All of the valid command line arguments for the composition binary.
|
||||||
///
|
///
|
||||||
/// Arguments will always override the config options specified in `composition.toml` or `Config::default()`.
|
/// Arguments will always override the config options specified in `composition.toml` or `Config::default()`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
config_file: PathBuf,
|
config_file: PathBuf,
|
||||||
server_icon: PathBuf,
|
|
||||||
pub log_level: Option<tracing::Level>,
|
pub log_level: Option<tracing::Level>,
|
||||||
pub log_dir: PathBuf,
|
pub log_dir: PathBuf,
|
||||||
|
pub subcommand: Subcommand,
|
||||||
|
server: Option<ServerArgs>,
|
||||||
}
|
}
|
||||||
impl Default for Args {
|
impl Default for Args {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let config = Config::default();
|
|
||||||
Args {
|
Args {
|
||||||
config_file: PathBuf::from("composition.toml"),
|
config_file: PathBuf::from("composition.toml"),
|
||||||
server_icon: config.server_icon,
|
|
||||||
log_level: None,
|
log_level: None,
|
||||||
log_dir: PathBuf::from("logs"),
|
log_dir: PathBuf::from("logs"),
|
||||||
|
subcommand: Subcommand::None,
|
||||||
|
server: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,10 +200,9 @@ impl Args {
|
|||||||
ARGS.set(Self::parse()).expect("could not set ARGS");
|
ARGS.set(Self::parse()).expect("could not set ARGS");
|
||||||
Self::instance()
|
Self::instance()
|
||||||
}
|
}
|
||||||
fn parse() -> Self {
|
fn command() -> clap::Command {
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
clap::Command::new("composition")
|
||||||
let m = clap::Command::new("composition")
|
|
||||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||||
.disable_version_flag(true)
|
.disable_version_flag(true)
|
||||||
.arg(
|
.arg(
|
||||||
@ -215,21 +226,16 @@ impl Args {
|
|||||||
.short('c')
|
.short('c')
|
||||||
.long("config-file")
|
.long("config-file")
|
||||||
.help("Configuration file path")
|
.help("Configuration file path")
|
||||||
|
.global(true)
|
||||||
.value_hint(clap::ValueHint::FilePath)
|
.value_hint(clap::ValueHint::FilePath)
|
||||||
.default_value(OsStr::new(&DEFAULT_ARGS.config_file)),
|
.default_value(OsStr::new(&DEFAULT_ARGS.config_file)),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::new("server-icon")
|
|
||||||
.long("server-icon")
|
|
||||||
.help("Server icon file path")
|
|
||||||
.value_hint(clap::ValueHint::FilePath)
|
|
||||||
.default_value(OsStr::new(&DEFAULT_ARGS.server_icon)),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("log-level")
|
Arg::new("log-level")
|
||||||
.short('l')
|
.short('l')
|
||||||
.long("log-level")
|
.long("log-level")
|
||||||
.help("Set the log level")
|
.help("Set the log level")
|
||||||
|
.global(true)
|
||||||
.conflicts_with("verbose")
|
.conflicts_with("verbose")
|
||||||
.value_name("level")
|
.value_name("level")
|
||||||
.value_parser(["trace", "debug", "info", "warn", "error"]),
|
.value_parser(["trace", "debug", "info", "warn", "error"]),
|
||||||
@ -238,19 +244,30 @@ impl Args {
|
|||||||
Arg::new("log-dir")
|
Arg::new("log-dir")
|
||||||
.long("log-dir")
|
.long("log-dir")
|
||||||
.help("Set the log output directory")
|
.help("Set the log output directory")
|
||||||
|
.global(true)
|
||||||
.value_name("dir")
|
.value_name("dir")
|
||||||
.value_hint(clap::ValueHint::DirPath)
|
.value_hint(clap::ValueHint::DirPath)
|
||||||
.default_value(OsStr::new(&DEFAULT_ARGS.log_dir)),
|
.default_value(OsStr::new(&DEFAULT_ARGS.log_dir)),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.subcommand(
|
||||||
|
clap::Command::new("server")
|
||||||
|
.about("Run composition in server mode")
|
||||||
|
.arg(
|
||||||
|
Arg::new("server-icon")
|
||||||
|
.long("server-icon")
|
||||||
|
.help("Server icon file path")
|
||||||
|
.value_hint(clap::ValueHint::FilePath)
|
||||||
|
.default_value(OsStr::new(&DEFAULT_SERVER_ARGS.server_icon)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn parse() -> Self {
|
||||||
let mut args = Self::default();
|
let mut args = Self::default();
|
||||||
|
let m = Self::command().get_matches();
|
||||||
|
|
||||||
args.config_file = m
|
args.config_file = m
|
||||||
.get_one::<String>("config-file")
|
.get_one::<String>("config-file")
|
||||||
.map_or(args.config_file, PathBuf::from);
|
.map_or(args.config_file, PathBuf::from);
|
||||||
args.server_icon = m
|
|
||||||
.get_one::<String>("server-icon")
|
|
||||||
.map_or(args.server_icon, PathBuf::from);
|
|
||||||
args.log_dir = m
|
args.log_dir = m
|
||||||
.get_one::<String>("log-dir")
|
.get_one::<String>("log-dir")
|
||||||
.map_or(args.log_dir, PathBuf::from);
|
.map_or(args.log_dir, PathBuf::from);
|
||||||
@ -276,6 +293,43 @@ impl Args {
|
|||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match m.subcommand() {
|
||||||
|
Some(("server", m)) => {
|
||||||
|
args.subcommand = Subcommand::Server;
|
||||||
|
let mut server_args = ServerArgs::default();
|
||||||
|
server_args.server_icon = m
|
||||||
|
.get_one::<String>("server-icon")
|
||||||
|
.map_or(server_args.server_icon, PathBuf::from);
|
||||||
|
args.server = Some(server_args);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let _ = Self::command().print_help();
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ServerArgs {
|
||||||
|
server_icon: PathBuf,
|
||||||
|
}
|
||||||
|
impl Default for ServerArgs {
|
||||||
|
fn default() -> Self {
|
||||||
|
let config = Config::default();
|
||||||
|
ServerArgs {
|
||||||
|
server_icon: config.server_icon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ServerArgs {
|
||||||
|
pub fn instance() -> Option<&'static Self> {
|
||||||
|
Args::instance().server.as_ref()
|
||||||
|
}
|
||||||
|
pub fn load() -> Option<&'static Self> {
|
||||||
|
Args::load().server.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
17
src/lib.rs
17
src/lib.rs
@ -1,9 +1,5 @@
|
|||||||
/// Server configuration and cli options.
|
/// Server configuration and cli options.
|
||||||
pub mod config;
|
pub mod config;
|
||||||
/// When managing the server encounters errors.
|
|
||||||
pub(crate) mod error;
|
|
||||||
/// Network operations.
|
|
||||||
pub(crate) mod net;
|
|
||||||
/// The Minecraft protocol implemented in a network-agnostic way.
|
/// The Minecraft protocol implemented in a network-agnostic way.
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
/// The core server implementation.
|
/// The core server implementation.
|
||||||
@ -11,17 +7,18 @@ pub(crate) mod server;
|
|||||||
/// A Minecraft world generator implementation that allows for custom worlds.
|
/// A Minecraft world generator implementation that allows for custom worlds.
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
||||||
use crate::config::Config;
|
use config::Subcommand;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
/// A globally accessible instant of the server's start time.
|
/// A globally accessible instant of the composition's start time.
|
||||||
///
|
///
|
||||||
/// This should be set immediately on startup.
|
/// This should be set immediately on startup.
|
||||||
pub static START_TIME: OnceCell<Instant> = OnceCell::new();
|
pub static START_TIME: OnceCell<Instant> = OnceCell::new();
|
||||||
|
|
||||||
/// Start the server.
|
pub async fn run(command: Subcommand) {
|
||||||
#[tracing::instrument]
|
match command {
|
||||||
pub async fn start_server() -> (server::Server, tokio_util::sync::CancellationToken) {
|
Subcommand::Server => server::Server::run().await,
|
||||||
server::Server::new(format!("0.0.0.0:{}", Config::instance().port)).await
|
Subcommand::None => unreachable!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
22
src/main.rs
22
src/main.rs
@ -36,7 +36,7 @@ pub fn main() {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
// Load the config.
|
// Load the config.
|
||||||
let config = composition::config::Config::load();
|
let config = composition::config::Config::instance();
|
||||||
|
|
||||||
match config.server_threads {
|
match config.server_threads {
|
||||||
Some(1) => {
|
Some(1) => {
|
||||||
@ -58,23 +58,7 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
info!("Starting {} on port {}", config.server_version, config.port);
|
let args = composition::config::Args::instance();
|
||||||
let (mut server, running) = composition::start_server().await;
|
composition::run(args.subcommand).await;
|
||||||
info!(
|
|
||||||
"Done! Start took {:?}",
|
|
||||||
composition::START_TIME.get().unwrap().elapsed()
|
|
||||||
);
|
|
||||||
|
|
||||||
// The main server loop.
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
_ = running.cancelled() => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ = server.update() => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = tokio::time::timeout(std::time::Duration::from_secs(10), server.shutdown()).await;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@ pub mod entities;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
/// Implementation of Minecraft's items and inventories.
|
/// Implementation of Minecraft's items and inventories.
|
||||||
pub mod inventory;
|
pub mod inventory;
|
||||||
/// Useful types for representing the Minecraft protocol.
|
|
||||||
pub mod types;
|
|
||||||
/// Network packets.
|
/// Network packets.
|
||||||
///
|
///
|
||||||
/// The packet naming convention used is "DSIDName" where
|
/// The packet naming convention used is "DSIDName" where
|
||||||
@ -19,6 +17,8 @@ pub mod types;
|
|||||||
pub mod packets;
|
pub mod packets;
|
||||||
/// Useful shared parsing functions.
|
/// Useful shared parsing functions.
|
||||||
pub mod parsing;
|
pub mod parsing;
|
||||||
|
/// Useful types for representing the Minecraft protocol.
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::protocol::types::{Chat, Json, Uuid, VarInt};
|
|
||||||
use crate::protocol::parsing::Parsable;
|
use crate::protocol::parsing::Parsable;
|
||||||
|
use crate::protocol::types::{Chat, Json, Uuid, VarInt};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct CL00Disconnect {
|
pub struct CL00Disconnect {
|
||||||
@ -33,11 +33,14 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, public_key) = u8::parse_vec(data)?;
|
let (data, public_key) = u8::parse_vec(data)?;
|
||||||
let (data, verify_token) = u8::parse_vec(data)?;
|
let (data, verify_token) = u8::parse_vec(data)?;
|
||||||
|
|
||||||
Ok((data, CL01EncryptionRequest {
|
Ok((
|
||||||
server_id,
|
data,
|
||||||
public_key,
|
CL01EncryptionRequest {
|
||||||
verify_token,
|
server_id,
|
||||||
}))
|
public_key,
|
||||||
|
verify_token,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CL01EncryptionRequest| -> Vec<u8> {
|
|packet: &CL01EncryptionRequest| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -66,11 +69,14 @@ impl Parsable for CL02LoginSuccessProperty {
|
|||||||
let (data, name) = String::parse(data)?;
|
let (data, name) = String::parse(data)?;
|
||||||
let (data, value) = String::parse(data)?;
|
let (data, value) = String::parse(data)?;
|
||||||
let (data, signature) = String::parse_optional(data)?;
|
let (data, signature) = String::parse_optional(data)?;
|
||||||
Ok((data, CL02LoginSuccessProperty {
|
Ok((
|
||||||
name,
|
data,
|
||||||
value,
|
CL02LoginSuccessProperty {
|
||||||
signature,
|
name,
|
||||||
}))
|
value,
|
||||||
|
signature,
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
@ -91,11 +97,14 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, username) = String::parse(data)?;
|
let (data, username) = String::parse(data)?;
|
||||||
let (data, properties) = CL02LoginSuccessProperty::parse_vec(data)?;
|
let (data, properties) = CL02LoginSuccessProperty::parse_vec(data)?;
|
||||||
|
|
||||||
Ok((data, CL02LoginSuccess {
|
Ok((
|
||||||
uuid,
|
data,
|
||||||
username,
|
CL02LoginSuccess {
|
||||||
properties,
|
uuid,
|
||||||
}))
|
username,
|
||||||
|
properties,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CL02LoginSuccess| -> Vec<u8> {
|
|packet: &CL02LoginSuccess| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -136,11 +145,14 @@ crate::protocol::packets::packet!(
|
|||||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL04LoginPluginRequest> {
|
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL04LoginPluginRequest> {
|
||||||
let (data, message_id) = VarInt::parse(data)?;
|
let (data, message_id) = VarInt::parse(data)?;
|
||||||
let (data, channel) = String::parse(data)?;
|
let (data, channel) = String::parse(data)?;
|
||||||
Ok((data, CL04LoginPluginRequest {
|
Ok((
|
||||||
message_id,
|
data,
|
||||||
channel,
|
CL04LoginPluginRequest {
|
||||||
data: data.to_vec(),
|
message_id,
|
||||||
}))
|
channel,
|
||||||
|
data: data.to_vec(),
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CL04LoginPluginRequest| -> Vec<u8> {
|
|packet: &CL04LoginPluginRequest| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -29,16 +29,19 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, d) = VarInt::parse(data)?;
|
let (data, d) = VarInt::parse(data)?;
|
||||||
let (data, velocity) = EntityVelocity::parse(data)?;
|
let (data, velocity) = EntityVelocity::parse(data)?;
|
||||||
|
|
||||||
Ok((data, CP00SpawnEntity {
|
Ok((
|
||||||
id,
|
data,
|
||||||
uuid,
|
CP00SpawnEntity {
|
||||||
kind,
|
id,
|
||||||
position,
|
uuid,
|
||||||
rotation,
|
kind,
|
||||||
head_yaw,
|
position,
|
||||||
data: d,
|
rotation,
|
||||||
velocity,
|
head_yaw,
|
||||||
}))
|
data: d,
|
||||||
|
velocity,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CP00SpawnEntity| -> Vec<u8> {
|
|packet: &CP00SpawnEntity| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -67,10 +70,13 @@ crate::protocol::packets::packet!(
|
|||||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP0BChangeDifficulty> {
|
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP0BChangeDifficulty> {
|
||||||
let (data, difficulty) = Difficulty::parse(data)?;
|
let (data, difficulty) = Difficulty::parse(data)?;
|
||||||
let (data, is_locked) = bool::parse(data)?;
|
let (data, is_locked) = bool::parse(data)?;
|
||||||
Ok((data, CP0BChangeDifficulty {
|
Ok((
|
||||||
difficulty,
|
data,
|
||||||
is_locked,
|
CP0BChangeDifficulty {
|
||||||
}))
|
difficulty,
|
||||||
|
is_locked,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CP0BChangeDifficulty| -> Vec<u8> {
|
|packet: &CP0BChangeDifficulty| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -129,12 +135,15 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, location) = Position::parse(data)?;
|
let (data, location) = Position::parse(data)?;
|
||||||
let (data, d) = i32::parse(data)?;
|
let (data, d) = i32::parse(data)?;
|
||||||
let (data, disable_relative_volume) = bool::parse(data)?;
|
let (data, disable_relative_volume) = bool::parse(data)?;
|
||||||
Ok((data, CP21WorldEvent {
|
Ok((
|
||||||
event,
|
data,
|
||||||
location,
|
CP21WorldEvent {
|
||||||
data: d,
|
event,
|
||||||
disable_relative_volume,
|
location,
|
||||||
}))
|
data: d,
|
||||||
|
disable_relative_volume,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CP21WorldEvent| -> Vec<u8> {
|
|packet: &CP21WorldEvent| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -159,10 +168,13 @@ crate::protocol::packets::packet!(
|
|||||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP50SetEntityVelocity> {
|
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP50SetEntityVelocity> {
|
||||||
let (data, entity_id) = VarInt::parse(data)?;
|
let (data, entity_id) = VarInt::parse(data)?;
|
||||||
let (data, entity_velocity) = EntityVelocity::parse(data)?;
|
let (data, entity_velocity) = EntityVelocity::parse(data)?;
|
||||||
Ok((data, CP50SetEntityVelocity {
|
Ok((
|
||||||
entity_id,
|
data,
|
||||||
entity_velocity,
|
CP50SetEntityVelocity {
|
||||||
}))
|
entity_id,
|
||||||
|
entity_velocity,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CP50SetEntityVelocity| -> Vec<u8> {
|
|packet: &CP50SetEntityVelocity| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -187,11 +199,14 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, experience_bar) = f32::parse(data)?;
|
let (data, experience_bar) = f32::parse(data)?;
|
||||||
let (data, total_experience) = VarInt::parse(data)?;
|
let (data, total_experience) = VarInt::parse(data)?;
|
||||||
let (data, level) = VarInt::parse(data)?;
|
let (data, level) = VarInt::parse(data)?;
|
||||||
Ok((data, CP52SetExperience {
|
Ok((
|
||||||
experience_bar,
|
data,
|
||||||
total_experience,
|
CP52SetExperience {
|
||||||
level,
|
experience_bar,
|
||||||
}))
|
total_experience,
|
||||||
|
level,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CP52SetExperience| -> Vec<u8> {
|
|packet: &CP52SetExperience| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -231,16 +246,19 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, has_factor_data) = bool::parse(data)?;
|
let (data, has_factor_data) = bool::parse(data)?;
|
||||||
// TODO: factor_codec
|
// TODO: factor_codec
|
||||||
|
|
||||||
Ok((data, CP68EntityEffect {
|
Ok((
|
||||||
entity_id,
|
data,
|
||||||
effect_id,
|
CP68EntityEffect {
|
||||||
amplifier,
|
entity_id,
|
||||||
duration,
|
effect_id,
|
||||||
is_ambient,
|
amplifier,
|
||||||
show_particles,
|
duration,
|
||||||
show_icon,
|
is_ambient,
|
||||||
has_factor_data,
|
show_particles,
|
||||||
}))
|
show_icon,
|
||||||
|
has_factor_data,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &CP68EntityEffect| -> Vec<u8> {
|
|packet: &CP68EntityEffect| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -3,7 +3,7 @@ pub mod clientbound;
|
|||||||
/// Packets that are heading to the server.
|
/// Packets that are heading to the server.
|
||||||
pub mod serverbound;
|
pub mod serverbound;
|
||||||
|
|
||||||
use crate::protocol::parsing::{VarInt, Parsable};
|
use crate::protocol::parsing::{Parsable, VarInt};
|
||||||
|
|
||||||
/// Alias for a `VarInt`.
|
/// Alias for a `VarInt`.
|
||||||
pub type PacketId = VarInt;
|
pub type PacketId = VarInt;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::protocol::{ClientState, types::VarInt};
|
use crate::protocol::{types::VarInt, ClientState};
|
||||||
use nom::combinator::map_res;
|
use nom::combinator::map_res;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -24,12 +24,15 @@ crate::protocol::packets::packet!(
|
|||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
})(data)?;
|
})(data)?;
|
||||||
|
|
||||||
Ok((data, SH00Handshake {
|
Ok((
|
||||||
protocol_version,
|
data,
|
||||||
server_address,
|
SH00Handshake {
|
||||||
server_port,
|
protocol_version,
|
||||||
next_state,
|
server_address,
|
||||||
}))
|
server_port,
|
||||||
|
next_state,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &SH00Handshake| -> Vec<u8> {
|
|packet: &SH00Handshake| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -16,10 +16,13 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, has_uuid) = bool::parse(data)?;
|
let (data, has_uuid) = bool::parse(data)?;
|
||||||
if has_uuid {
|
if has_uuid {
|
||||||
let (data, uuid) = Uuid::parse(data)?;
|
let (data, uuid) = Uuid::parse(data)?;
|
||||||
Ok((data, SL00LoginStart {
|
Ok((
|
||||||
name,
|
data,
|
||||||
uuid: Some(uuid),
|
SL00LoginStart {
|
||||||
}))
|
name,
|
||||||
|
uuid: Some(uuid),
|
||||||
|
},
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((data, SL00LoginStart { name, uuid: None }))
|
Ok((data, SL00LoginStart { name, uuid: None }))
|
||||||
}
|
}
|
||||||
@ -51,10 +54,13 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, verify_token_len) = VarInt::parse(data)?;
|
let (data, verify_token_len) = VarInt::parse(data)?;
|
||||||
let (data, verify_token) = take(*verify_token_len as usize)(data)?;
|
let (data, verify_token) = take(*verify_token_len as usize)(data)?;
|
||||||
|
|
||||||
Ok((data, SL01EncryptionResponse {
|
Ok((
|
||||||
shared_secret: shared_secret.to_vec(),
|
data,
|
||||||
verify_token: verify_token.to_vec(),
|
SL01EncryptionResponse {
|
||||||
}))
|
shared_secret: shared_secret.to_vec(),
|
||||||
|
verify_token: verify_token.to_vec(),
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &SL01EncryptionResponse| -> Vec<u8> {
|
|packet: &SL01EncryptionResponse| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -81,17 +87,23 @@ crate::protocol::packets::packet!(
|
|||||||
let (data, message_id) = VarInt::parse(data)?;
|
let (data, message_id) = VarInt::parse(data)?;
|
||||||
let (data, successful) = bool::parse(data)?;
|
let (data, successful) = bool::parse(data)?;
|
||||||
if successful {
|
if successful {
|
||||||
Ok((&[], SL02LoginPluginResponse {
|
Ok((
|
||||||
message_id,
|
&[],
|
||||||
successful,
|
SL02LoginPluginResponse {
|
||||||
data: data.to_vec(),
|
message_id,
|
||||||
}))
|
successful,
|
||||||
|
data: data.to_vec(),
|
||||||
|
},
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((data, SL02LoginPluginResponse {
|
Ok((
|
||||||
message_id,
|
data,
|
||||||
successful,
|
SL02LoginPluginResponse {
|
||||||
data: vec![],
|
message_id,
|
||||||
}))
|
successful,
|
||||||
|
data: vec![],
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|packet: &SL02LoginPluginResponse| -> Vec<u8> {
|
|packet: &SL02LoginPluginResponse| -> Vec<u8> {
|
||||||
|
@ -58,10 +58,13 @@ crate::protocol::packets::packet!(
|
|||||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP13SetPlayerPosition> {
|
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP13SetPlayerPosition> {
|
||||||
let (data, position) = EntityPosition::parse(data)?;
|
let (data, position) = EntityPosition::parse(data)?;
|
||||||
let (data, on_ground) = bool::parse(data)?;
|
let (data, on_ground) = bool::parse(data)?;
|
||||||
Ok((data, SP13SetPlayerPosition {
|
Ok((
|
||||||
position,
|
data,
|
||||||
on_ground,
|
SP13SetPlayerPosition {
|
||||||
}))
|
position,
|
||||||
|
on_ground,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &SP13SetPlayerPosition| -> Vec<u8> {
|
|packet: &SP13SetPlayerPosition| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -114,10 +117,13 @@ crate::protocol::packets::packet!(
|
|||||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP15SetPlayerRotation> {
|
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP15SetPlayerRotation> {
|
||||||
let (data, rotation) = EntityRotation::parse(data)?;
|
let (data, rotation) = EntityRotation::parse(data)?;
|
||||||
let (data, on_ground) = bool::parse(data)?;
|
let (data, on_ground) = bool::parse(data)?;
|
||||||
Ok((data, SP15SetPlayerRotation {
|
Ok((
|
||||||
rotation,
|
data,
|
||||||
on_ground,
|
SP15SetPlayerRotation {
|
||||||
}))
|
rotation,
|
||||||
|
on_ground,
|
||||||
|
},
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|packet: &SP15SetPlayerRotation| -> Vec<u8> {
|
|packet: &SP15SetPlayerRotation| -> Vec<u8> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
pub use nom::IResult;
|
pub use nom::IResult;
|
||||||
use nom::{bytes::streaming::{take, take_while_m_n}, number::streaming as nom_nums, combinator::map_res};
|
use nom::{
|
||||||
|
bytes::streaming::{take, take_while_m_n},
|
||||||
|
combinator::map_res,
|
||||||
|
number::streaming as nom_nums,
|
||||||
|
};
|
||||||
|
|
||||||
/// Implementation of the protocol's VarInt type.
|
/// Implementation of the protocol's VarInt type.
|
||||||
///
|
///
|
||||||
@ -317,7 +321,11 @@ impl Parsable for bool {
|
|||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
if *self { vec![0x01] } else { vec![0x00] }
|
if *self {
|
||||||
|
vec![0x01]
|
||||||
|
} else {
|
||||||
|
vec![0x00]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,4 +388,3 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,10 +83,13 @@ mod tests {
|
|||||||
fn get_positions() -> Vec<(Position, Vec<u8>)> {
|
fn get_positions() -> Vec<(Position, Vec<u8>)> {
|
||||||
vec![
|
vec![
|
||||||
// x: 01000110000001110110001100 z: 10110000010101101101001000 y: 001100111111
|
// x: 01000110000001110110001100 z: 10110000010101101101001000 y: 001100111111
|
||||||
(Position::new(18357644, 831, -20882616), vec![
|
(
|
||||||
0b01000110, 0b00000111, 0b01100011, 0b00101100, 0b00010101, 0b10110100, 0b10000011,
|
Position::new(18357644, 831, -20882616),
|
||||||
0b00111111,
|
vec![
|
||||||
]),
|
0b01000110, 0b00000111, 0b01100011, 0b00101100, 0b00010101, 0b10110100,
|
||||||
|
0b10000011, 0b00111111,
|
||||||
|
],
|
||||||
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
|
/// When managing the server encounters errors.
|
||||||
|
pub mod error;
|
||||||
|
/// Network operations.
|
||||||
|
pub mod net;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::Result;
|
|
||||||
use crate::net::{NetworkClient, NetworkClientState};
|
|
||||||
use crate::protocol::ClientState;
|
use crate::protocol::ClientState;
|
||||||
|
use error::Result;
|
||||||
|
use net::{NetworkClient, NetworkClientState};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::net::{TcpListener, ToSocketAddrs};
|
use tokio::net::{TcpListener, ToSocketAddrs};
|
||||||
use tokio::{sync::RwLock, task::JoinHandle};
|
use tokio::{sync::RwLock, task::JoinHandle};
|
||||||
@ -15,6 +20,40 @@ pub struct Server {
|
|||||||
net_tasks_handle: JoinHandle<()>,
|
net_tasks_handle: JoinHandle<()>,
|
||||||
}
|
}
|
||||||
impl Server {
|
impl Server {
|
||||||
|
/// Start the server.
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub async fn run() {
|
||||||
|
let config = crate::config::Config::instance();
|
||||||
|
info!("Starting {} on port {}", config.server_version, config.port);
|
||||||
|
let (mut server, running) = Self::new(format!("0.0.0.0:{}", Config::instance().port)).await;
|
||||||
|
info!(
|
||||||
|
"Done! Start took {:?}",
|
||||||
|
crate::START_TIME.get().unwrap().elapsed()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Spawn the ctrl-c task.
|
||||||
|
let r = running.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::signal::ctrl_c().await.unwrap();
|
||||||
|
info!("Ctrl-C received, shutting down");
|
||||||
|
r.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
// The main server loop.
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
_ = running.cancelled() => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ = server.update() => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match tokio::time::timeout(std::time::Duration::from_secs(10), server.shutdown()).await {
|
||||||
|
Ok(_) => std::process::exit(0),
|
||||||
|
Err(_) => std::process::exit(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn new<A: 'static + ToSocketAddrs + Send + std::fmt::Debug>(
|
pub async fn new<A: 'static + ToSocketAddrs + Send + std::fmt::Debug>(
|
||||||
bind_address: A,
|
bind_address: A,
|
||||||
@ -34,15 +73,6 @@ impl Server {
|
|||||||
net_tasks_handle,
|
net_tasks_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
// let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
|
||||||
let r = running.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
tokio::signal::ctrl_c().await.unwrap();
|
|
||||||
info!("Ctrl-C received, shutting down");
|
|
||||||
r.cancel();
|
|
||||||
// shutdown_tx.send(()).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
(server, running)
|
(server, running)
|
||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
ClientState,
|
packets::{serverbound::SL00LoginStart, GenericPacket},
|
||||||
packets::{GenericPacket, serverbound::SL00LoginStart},
|
|
||||||
parsing::Parsable,
|
parsing::Parsable,
|
||||||
|
ClientState,
|
||||||
};
|
};
|
||||||
use std::{collections::VecDeque, sync::Arc, time::Instant};
|
use std::{collections::VecDeque, sync::Arc, time::Instant};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
@ -6,7 +6,7 @@ pub mod error;
|
|||||||
pub mod generators;
|
pub mod generators;
|
||||||
/// Useful re-exports.
|
/// Useful re-exports.
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::{World, chunks::Chunk};
|
pub use super::{chunks::Chunk, World};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::protocol::{blocks, entities};
|
pub use crate::protocol::{blocks, entities};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user