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/.git
|
||||
EXPOSE 25565
|
||||
CMD ["cargo", "watch", "-x", "run"]
|
||||
CMD ["cargo", "watch", "-x", "run -- server"]
|
||||
|
||||
FROM base AS planner
|
||||
COPY Cargo.toml .
|
||||
@ -36,3 +36,4 @@ COPY --from=builder /app/target/release/composition /app
|
||||
EXPOSE 25565
|
||||
USER 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.
|
||||
pub static ARGS: OnceCell<Args> = OnceCell::new();
|
||||
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`
|
||||
/// and return its bytes as a `Vec<u8>`.
|
||||
@ -99,7 +100,11 @@ impl Config {
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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.
|
||||
///
|
||||
/// Arguments will always override the config options specified in `composition.toml` or `Config::default()`.
|
||||
#[derive(Debug)]
|
||||
pub struct Args {
|
||||
config_file: PathBuf,
|
||||
server_icon: PathBuf,
|
||||
pub log_level: Option<tracing::Level>,
|
||||
pub log_dir: PathBuf,
|
||||
pub subcommand: Subcommand,
|
||||
server: Option<ServerArgs>,
|
||||
}
|
||||
impl Default for Args {
|
||||
fn default() -> Self {
|
||||
let config = Config::default();
|
||||
Args {
|
||||
config_file: PathBuf::from("composition.toml"),
|
||||
server_icon: config.server_icon,
|
||||
log_level: None,
|
||||
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");
|
||||
Self::instance()
|
||||
}
|
||||
fn parse() -> Self {
|
||||
fn command() -> clap::Command {
|
||||
use std::ffi::OsStr;
|
||||
|
||||
let m = clap::Command::new("composition")
|
||||
clap::Command::new("composition")
|
||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||
.disable_version_flag(true)
|
||||
.arg(
|
||||
@ -215,21 +226,16 @@ impl Args {
|
||||
.short('c')
|
||||
.long("config-file")
|
||||
.help("Configuration file path")
|
||||
.global(true)
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.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::new("log-level")
|
||||
.short('l')
|
||||
.long("log-level")
|
||||
.help("Set the log level")
|
||||
.global(true)
|
||||
.conflicts_with("verbose")
|
||||
.value_name("level")
|
||||
.value_parser(["trace", "debug", "info", "warn", "error"]),
|
||||
@ -238,19 +244,30 @@ impl Args {
|
||||
Arg::new("log-dir")
|
||||
.long("log-dir")
|
||||
.help("Set the log output directory")
|
||||
.global(true)
|
||||
.value_name("dir")
|
||||
.value_hint(clap::ValueHint::DirPath)
|
||||
.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 m = Self::command().get_matches();
|
||||
|
||||
args.config_file = m
|
||||
.get_one::<String>("config-file")
|
||||
.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
|
||||
.get_one::<String>("log-dir")
|
||||
.map_or(args.log_dir, PathBuf::from);
|
||||
@ -276,6 +293,43 @@ impl Args {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#[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.
|
||||
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.
|
||||
pub mod protocol;
|
||||
/// The core server implementation.
|
||||
@ -11,17 +7,18 @@ pub(crate) mod server;
|
||||
/// A Minecraft world generator implementation that allows for custom worlds.
|
||||
pub mod world;
|
||||
|
||||
use crate::config::Config;
|
||||
use config::Subcommand;
|
||||
use once_cell::sync::OnceCell;
|
||||
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.
|
||||
pub static START_TIME: OnceCell<Instant> = OnceCell::new();
|
||||
|
||||
/// Start the server.
|
||||
#[tracing::instrument]
|
||||
pub async fn start_server() -> (server::Server, tokio_util::sync::CancellationToken) {
|
||||
server::Server::new(format!("0.0.0.0:{}", Config::instance().port)).await
|
||||
pub async fn run(command: Subcommand) {
|
||||
match command {
|
||||
Subcommand::Server => server::Server::run().await,
|
||||
Subcommand::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
22
src/main.rs
22
src/main.rs
@ -36,7 +36,7 @@ pub fn main() {
|
||||
.init();
|
||||
|
||||
// Load the config.
|
||||
let config = composition::config::Config::load();
|
||||
let config = composition::config::Config::instance();
|
||||
|
||||
match config.server_threads {
|
||||
Some(1) => {
|
||||
@ -58,23 +58,7 @@ pub fn main() {
|
||||
}
|
||||
.unwrap()
|
||||
.block_on(async move {
|
||||
info!("Starting {} on port {}", config.server_version, config.port);
|
||||
let (mut server, running) = composition::start_server().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;
|
||||
let args = composition::config::Args::instance();
|
||||
composition::run(args.subcommand).await;
|
||||
});
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ pub mod entities;
|
||||
pub mod error;
|
||||
/// Implementation of Minecraft's items and inventories.
|
||||
pub mod inventory;
|
||||
/// Useful types for representing the Minecraft protocol.
|
||||
pub mod types;
|
||||
/// Network packets.
|
||||
///
|
||||
/// The packet naming convention used is "DSIDName" where
|
||||
@ -19,6 +17,8 @@ pub mod types;
|
||||
pub mod packets;
|
||||
/// Useful shared parsing functions.
|
||||
pub mod parsing;
|
||||
/// Useful types for representing the Minecraft protocol.
|
||||
pub mod types;
|
||||
|
||||
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::types::{Chat, Json, Uuid, VarInt};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CL00Disconnect {
|
||||
@ -33,11 +33,14 @@ crate::protocol::packets::packet!(
|
||||
let (data, public_key) = u8::parse_vec(data)?;
|
||||
let (data, verify_token) = u8::parse_vec(data)?;
|
||||
|
||||
Ok((data, CL01EncryptionRequest {
|
||||
Ok((
|
||||
data,
|
||||
CL01EncryptionRequest {
|
||||
server_id,
|
||||
public_key,
|
||||
verify_token,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CL01EncryptionRequest| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -66,11 +69,14 @@ impl Parsable for CL02LoginSuccessProperty {
|
||||
let (data, name) = String::parse(data)?;
|
||||
let (data, value) = String::parse(data)?;
|
||||
let (data, signature) = String::parse_optional(data)?;
|
||||
Ok((data, CL02LoginSuccessProperty {
|
||||
Ok((
|
||||
data,
|
||||
CL02LoginSuccessProperty {
|
||||
name,
|
||||
value,
|
||||
signature,
|
||||
}))
|
||||
},
|
||||
))
|
||||
}
|
||||
#[tracing::instrument]
|
||||
fn serialize(&self) -> Vec<u8> {
|
||||
@ -91,11 +97,14 @@ crate::protocol::packets::packet!(
|
||||
let (data, username) = String::parse(data)?;
|
||||
let (data, properties) = CL02LoginSuccessProperty::parse_vec(data)?;
|
||||
|
||||
Ok((data, CL02LoginSuccess {
|
||||
Ok((
|
||||
data,
|
||||
CL02LoginSuccess {
|
||||
uuid,
|
||||
username,
|
||||
properties,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CL02LoginSuccess| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -136,11 +145,14 @@ crate::protocol::packets::packet!(
|
||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL04LoginPluginRequest> {
|
||||
let (data, message_id) = VarInt::parse(data)?;
|
||||
let (data, channel) = String::parse(data)?;
|
||||
Ok((data, CL04LoginPluginRequest {
|
||||
Ok((
|
||||
data,
|
||||
CL04LoginPluginRequest {
|
||||
message_id,
|
||||
channel,
|
||||
data: data.to_vec(),
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CL04LoginPluginRequest| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
|
@ -29,7 +29,9 @@ crate::protocol::packets::packet!(
|
||||
let (data, d) = VarInt::parse(data)?;
|
||||
let (data, velocity) = EntityVelocity::parse(data)?;
|
||||
|
||||
Ok((data, CP00SpawnEntity {
|
||||
Ok((
|
||||
data,
|
||||
CP00SpawnEntity {
|
||||
id,
|
||||
uuid,
|
||||
kind,
|
||||
@ -38,7 +40,8 @@ crate::protocol::packets::packet!(
|
||||
head_yaw,
|
||||
data: d,
|
||||
velocity,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CP00SpawnEntity| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -67,10 +70,13 @@ crate::protocol::packets::packet!(
|
||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP0BChangeDifficulty> {
|
||||
let (data, difficulty) = Difficulty::parse(data)?;
|
||||
let (data, is_locked) = bool::parse(data)?;
|
||||
Ok((data, CP0BChangeDifficulty {
|
||||
Ok((
|
||||
data,
|
||||
CP0BChangeDifficulty {
|
||||
difficulty,
|
||||
is_locked,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CP0BChangeDifficulty| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -129,12 +135,15 @@ crate::protocol::packets::packet!(
|
||||
let (data, location) = Position::parse(data)?;
|
||||
let (data, d) = i32::parse(data)?;
|
||||
let (data, disable_relative_volume) = bool::parse(data)?;
|
||||
Ok((data, CP21WorldEvent {
|
||||
Ok((
|
||||
data,
|
||||
CP21WorldEvent {
|
||||
event,
|
||||
location,
|
||||
data: d,
|
||||
disable_relative_volume,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CP21WorldEvent| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -159,10 +168,13 @@ crate::protocol::packets::packet!(
|
||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP50SetEntityVelocity> {
|
||||
let (data, entity_id) = VarInt::parse(data)?;
|
||||
let (data, entity_velocity) = EntityVelocity::parse(data)?;
|
||||
Ok((data, CP50SetEntityVelocity {
|
||||
Ok((
|
||||
data,
|
||||
CP50SetEntityVelocity {
|
||||
entity_id,
|
||||
entity_velocity,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CP50SetEntityVelocity| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -187,11 +199,14 @@ crate::protocol::packets::packet!(
|
||||
let (data, experience_bar) = f32::parse(data)?;
|
||||
let (data, total_experience) = VarInt::parse(data)?;
|
||||
let (data, level) = VarInt::parse(data)?;
|
||||
Ok((data, CP52SetExperience {
|
||||
Ok((
|
||||
data,
|
||||
CP52SetExperience {
|
||||
experience_bar,
|
||||
total_experience,
|
||||
level,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CP52SetExperience| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -231,7 +246,9 @@ crate::protocol::packets::packet!(
|
||||
let (data, has_factor_data) = bool::parse(data)?;
|
||||
// TODO: factor_codec
|
||||
|
||||
Ok((data, CP68EntityEffect {
|
||||
Ok((
|
||||
data,
|
||||
CP68EntityEffect {
|
||||
entity_id,
|
||||
effect_id,
|
||||
amplifier,
|
||||
@ -240,7 +257,8 @@ crate::protocol::packets::packet!(
|
||||
show_particles,
|
||||
show_icon,
|
||||
has_factor_data,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &CP68EntityEffect| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
|
@ -3,7 +3,7 @@ pub mod clientbound;
|
||||
/// Packets that are heading to the server.
|
||||
pub mod serverbound;
|
||||
|
||||
use crate::protocol::parsing::{VarInt, Parsable};
|
||||
use crate::protocol::parsing::{Parsable, VarInt};
|
||||
|
||||
/// Alias for a `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;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -24,12 +24,15 @@ crate::protocol::packets::packet!(
|
||||
_ => Err(()),
|
||||
})(data)?;
|
||||
|
||||
Ok((data, SH00Handshake {
|
||||
Ok((
|
||||
data,
|
||||
SH00Handshake {
|
||||
protocol_version,
|
||||
server_address,
|
||||
server_port,
|
||||
next_state,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &SH00Handshake| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
|
@ -16,10 +16,13 @@ crate::protocol::packets::packet!(
|
||||
let (data, has_uuid) = bool::parse(data)?;
|
||||
if has_uuid {
|
||||
let (data, uuid) = Uuid::parse(data)?;
|
||||
Ok((data, SL00LoginStart {
|
||||
Ok((
|
||||
data,
|
||||
SL00LoginStart {
|
||||
name,
|
||||
uuid: Some(uuid),
|
||||
}))
|
||||
},
|
||||
))
|
||||
} else {
|
||||
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) = take(*verify_token_len as usize)(data)?;
|
||||
|
||||
Ok((data, SL01EncryptionResponse {
|
||||
Ok((
|
||||
data,
|
||||
SL01EncryptionResponse {
|
||||
shared_secret: shared_secret.to_vec(),
|
||||
verify_token: verify_token.to_vec(),
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &SL01EncryptionResponse| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -81,17 +87,23 @@ crate::protocol::packets::packet!(
|
||||
let (data, message_id) = VarInt::parse(data)?;
|
||||
let (data, successful) = bool::parse(data)?;
|
||||
if successful {
|
||||
Ok((&[], SL02LoginPluginResponse {
|
||||
Ok((
|
||||
&[],
|
||||
SL02LoginPluginResponse {
|
||||
message_id,
|
||||
successful,
|
||||
data: data.to_vec(),
|
||||
}))
|
||||
},
|
||||
))
|
||||
} else {
|
||||
Ok((data, SL02LoginPluginResponse {
|
||||
Ok((
|
||||
data,
|
||||
SL02LoginPluginResponse {
|
||||
message_id,
|
||||
successful,
|
||||
data: vec![],
|
||||
}))
|
||||
},
|
||||
))
|
||||
}
|
||||
},
|
||||
|packet: &SL02LoginPluginResponse| -> Vec<u8> {
|
||||
|
@ -58,10 +58,13 @@ crate::protocol::packets::packet!(
|
||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP13SetPlayerPosition> {
|
||||
let (data, position) = EntityPosition::parse(data)?;
|
||||
let (data, on_ground) = bool::parse(data)?;
|
||||
Ok((data, SP13SetPlayerPosition {
|
||||
Ok((
|
||||
data,
|
||||
SP13SetPlayerPosition {
|
||||
position,
|
||||
on_ground,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &SP13SetPlayerPosition| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
@ -114,10 +117,13 @@ crate::protocol::packets::packet!(
|
||||
|data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP15SetPlayerRotation> {
|
||||
let (data, rotation) = EntityRotation::parse(data)?;
|
||||
let (data, on_ground) = bool::parse(data)?;
|
||||
Ok((data, SP15SetPlayerRotation {
|
||||
Ok((
|
||||
data,
|
||||
SP15SetPlayerRotation {
|
||||
rotation,
|
||||
on_ground,
|
||||
}))
|
||||
},
|
||||
))
|
||||
},
|
||||
|packet: &SP15SetPlayerRotation| -> Vec<u8> {
|
||||
let mut output = vec![];
|
||||
|
@ -1,5 +1,9 @@
|
||||
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.
|
||||
///
|
||||
@ -317,7 +321,11 @@ impl Parsable for bool {
|
||||
}
|
||||
#[tracing::instrument]
|
||||
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>)> {
|
||||
vec![
|
||||
// x: 01000110000001110110001100 z: 10110000010101101101001000 y: 001100111111
|
||||
(Position::new(18357644, 831, -20882616), vec![
|
||||
0b01000110, 0b00000111, 0b01100011, 0b00101100, 0b00010101, 0b10110100, 0b10000011,
|
||||
0b00111111,
|
||||
]),
|
||||
(
|
||||
Position::new(18357644, 831, -20882616),
|
||||
vec![
|
||||
0b01000110, 0b00000111, 0b01100011, 0b00101100, 0b00010101, 0b10110100,
|
||||
0b10000011, 0b00111111,
|
||||
],
|
||||
),
|
||||
]
|
||||
}
|
||||
#[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::error::Result;
|
||||
use crate::net::{NetworkClient, NetworkClientState};
|
||||
use crate::protocol::ClientState;
|
||||
use error::Result;
|
||||
use net::{NetworkClient, NetworkClientState};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::{TcpListener, ToSocketAddrs};
|
||||
use tokio::{sync::RwLock, task::JoinHandle};
|
||||
@ -15,6 +20,40 @@ pub struct Server {
|
||||
net_tasks_handle: JoinHandle<()>,
|
||||
}
|
||||
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]
|
||||
pub async fn new<A: 'static + ToSocketAddrs + Send + std::fmt::Debug>(
|
||||
bind_address: A,
|
||||
@ -34,15 +73,6 @@ impl Server {
|
||||
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)
|
||||
}
|
||||
#[tracing::instrument]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::protocol::{
|
||||
ClientState,
|
||||
packets::{GenericPacket, serverbound::SL00LoginStart},
|
||||
packets::{serverbound::SL00LoginStart, GenericPacket},
|
||||
parsing::Parsable,
|
||||
ClientState,
|
||||
};
|
||||
use std::{collections::VecDeque, sync::Arc, time::Instant};
|
||||
use tokio::io::AsyncWriteExt;
|
@ -6,7 +6,7 @@ pub mod error;
|
||||
pub mod generators;
|
||||
/// Useful re-exports.
|
||||
pub mod prelude {
|
||||
pub use super::{World, chunks::Chunk};
|
||||
pub use super::{chunks::Chunk, World};
|
||||
}
|
||||
|
||||
pub use crate::protocol::{blocks, entities};
|
||||
|
Loading…
x
Reference in New Issue
Block a user