2022-07-14 23:18:20 -07:00
|
|
|
//! The heart of the server.
|
|
|
|
|
2022-04-14 14:55:45 -07:00
|
|
|
use std::error::Error;
|
|
|
|
use std::iter::FusedIterator;
|
2022-10-22 04:50:13 +02:00
|
|
|
use std::net::{IpAddr, SocketAddr};
|
2022-05-16 02:36:14 -07:00
|
|
|
use std::sync::atomic::{AtomicI64, Ordering};
|
2022-06-30 13:22:08 -07:00
|
|
|
use std::sync::{Arc, Mutex};
|
2022-04-14 14:55:45 -07:00
|
|
|
use std::time::{Duration, Instant};
|
2022-07-06 18:27:59 -07:00
|
|
|
use std::{io, thread};
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-10-22 04:50:13 +02:00
|
|
|
use anyhow::{ensure, Context};
|
2022-04-14 14:55:45 -07:00
|
|
|
use flume::{Receiver, Sender};
|
2022-11-01 03:11:51 -07:00
|
|
|
pub(crate) use packet_controller::PlayPacketController;
|
2022-04-14 14:55:45 -07:00
|
|
|
use rand::rngs::OsRng;
|
|
|
|
use rayon::iter::ParallelIterator;
|
2022-10-22 04:50:13 +02:00
|
|
|
use reqwest::Client as HttpClient;
|
|
|
|
use rsa::{PublicKeyParts, RsaPrivateKey};
|
2022-04-14 14:55:45 -07:00
|
|
|
use serde_json::{json, Value};
|
|
|
|
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
|
|
|
use tokio::net::{TcpListener, TcpStream};
|
|
|
|
use tokio::runtime::{Handle, Runtime};
|
2022-11-01 03:11:51 -07:00
|
|
|
use tokio::sync::Semaphore;
|
2022-04-14 14:55:45 -07:00
|
|
|
use uuid::Uuid;
|
2022-09-23 04:51:26 -07:00
|
|
|
use valence_nbt::{compound, Compound, List};
|
2022-11-13 06:10:42 -08:00
|
|
|
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
|
|
|
use valence_protocol::packets::c2s::handshake::HandshakeOwned;
|
|
|
|
use valence_protocol::packets::c2s::login::LoginStart;
|
|
|
|
use valence_protocol::packets::c2s::status::{PingRequest, StatusRequest};
|
|
|
|
use valence_protocol::packets::s2c::login::{DisconnectLogin, LoginSuccess, SetCompression};
|
|
|
|
use valence_protocol::packets::s2c::status::{PingResponse, StatusResponse};
|
|
|
|
use valence_protocol::types::HandshakeNextState;
|
|
|
|
use valence_protocol::username::Username;
|
|
|
|
use valence_protocol::var_int::VarInt;
|
|
|
|
use valence_protocol::{ident, MINECRAFT_VERSION, PROTOCOL_VERSION};
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-09-23 04:51:26 -07:00
|
|
|
use crate::biome::{validate_biomes, Biome, BiomeId};
|
2022-07-06 18:27:59 -07:00
|
|
|
use crate::client::{Client, Clients};
|
2022-10-22 04:50:13 +02:00
|
|
|
use crate::config::{Config, ConnectionMode, ServerListPing};
|
2022-09-23 04:51:26 -07:00
|
|
|
use crate::dimension::{validate_dimensions, Dimension, DimensionId};
|
2022-07-06 18:27:59 -07:00
|
|
|
use crate::entity::Entities;
|
2022-10-15 22:47:02 -04:00
|
|
|
use crate::inventory::Inventories;
|
2022-08-09 14:44:04 -07:00
|
|
|
use crate::player_list::PlayerLists;
|
2022-06-28 18:29:29 -07:00
|
|
|
use crate::player_textures::SignedPlayerTextures;
|
2022-11-01 03:11:51 -07:00
|
|
|
use crate::server::packet_controller::InitialPacketController;
|
2022-05-16 02:36:14 -07:00
|
|
|
use crate::world::Worlds;
|
2022-11-13 06:10:42 -08:00
|
|
|
use crate::Ticks;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
mod byte_channel;
|
2022-10-22 04:50:13 +02:00
|
|
|
mod login;
|
2022-11-01 03:11:51 -07:00
|
|
|
mod packet_controller;
|
2022-10-22 04:50:13 +02:00
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Contains the entire state of a running Minecraft server, accessible from
|
|
|
|
/// within the [update](crate::config::Config::update) loop.
|
2022-07-15 20:40:39 -07:00
|
|
|
pub struct Server<C: Config> {
|
2022-07-27 19:21:11 -07:00
|
|
|
/// Custom state.
|
|
|
|
pub state: C::ServerState,
|
2022-07-11 05:08:02 -07:00
|
|
|
/// A handle to this server's [`SharedServer`].
|
2022-07-15 20:40:39 -07:00
|
|
|
pub shared: SharedServer<C>,
|
2022-09-02 00:06:45 -07:00
|
|
|
/// All of the clients on the server.
|
2022-07-15 20:40:39 -07:00
|
|
|
pub clients: Clients<C>,
|
2022-09-02 00:06:45 -07:00
|
|
|
/// All of entities on the server.
|
2022-07-15 20:40:39 -07:00
|
|
|
pub entities: Entities<C>,
|
2022-09-02 00:06:45 -07:00
|
|
|
/// All of the worlds on the server.
|
2022-07-15 20:40:39 -07:00
|
|
|
pub worlds: Worlds<C>,
|
2022-09-02 00:06:45 -07:00
|
|
|
/// All of the player lists on the server.
|
2022-08-09 14:44:04 -07:00
|
|
|
pub player_lists: PlayerLists<C>,
|
2022-10-15 22:47:02 -04:00
|
|
|
pub inventories: Inventories,
|
2022-07-03 15:31:24 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// A handle to a Minecraft server containing the subset of functionality which
|
2022-11-01 03:11:51 -07:00
|
|
|
/// is accessible outside the [update] loop.
|
2022-07-11 05:08:02 -07:00
|
|
|
///
|
|
|
|
/// `SharedServer`s are internally refcounted and can
|
|
|
|
/// be shared between threads.
|
|
|
|
///
|
|
|
|
/// [update]: crate::config::Config::update
|
2022-07-15 20:40:39 -07:00
|
|
|
pub struct SharedServer<C: Config>(Arc<SharedServerInner<C>>);
|
|
|
|
|
|
|
|
impl<C: Config> Clone for SharedServer<C> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self(self.0.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SharedServerInner<C: Config> {
|
|
|
|
cfg: C,
|
2022-04-14 14:55:45 -07:00
|
|
|
address: SocketAddr,
|
2022-04-30 18:01:41 -07:00
|
|
|
tick_rate: Ticks,
|
2022-10-22 04:50:13 +02:00
|
|
|
connection_mode: ConnectionMode,
|
2022-04-30 05:06:20 -07:00
|
|
|
max_connections: usize,
|
2022-11-01 03:11:51 -07:00
|
|
|
incoming_capacity: usize,
|
|
|
|
outgoing_capacity: usize,
|
2022-11-09 18:30:44 -08:00
|
|
|
/// The tokio handle used by the server.
|
2022-04-14 14:55:45 -07:00
|
|
|
tokio_handle: Handle,
|
2022-11-09 18:30:44 -08:00
|
|
|
/// Holding a runtime handle is not enough to keep tokio working. We need
|
|
|
|
/// to store the runtime here so we don't drop it.
|
2022-04-30 05:06:20 -07:00
|
|
|
_tokio_runtime: Option<Runtime>,
|
2022-04-14 14:55:45 -07:00
|
|
|
dimensions: Vec<Dimension>,
|
|
|
|
biomes: Vec<Biome>,
|
2022-09-23 04:51:26 -07:00
|
|
|
/// Contains info about dimensions, biomes, and chats.
|
|
|
|
/// Sent to all clients when joining.
|
|
|
|
registry_codec: Compound,
|
2022-04-14 14:55:45 -07:00
|
|
|
/// The instant the server was started.
|
|
|
|
start_instant: Instant,
|
2022-05-16 02:36:14 -07:00
|
|
|
/// Receiver for new clients past the login stage.
|
|
|
|
new_clients_rx: Receiver<NewClientMessage>,
|
|
|
|
new_clients_tx: Sender<NewClientMessage>,
|
|
|
|
/// Incremented on every game tick.
|
|
|
|
tick_counter: AtomicI64,
|
2022-04-14 14:55:45 -07:00
|
|
|
/// A semaphore used to limit the number of simultaneous connections to the
|
|
|
|
/// server. Closing this semaphore stops new connections.
|
|
|
|
connection_sema: Arc<Semaphore>,
|
|
|
|
/// The result that will be returned when the server is shut down.
|
|
|
|
shutdown_result: Mutex<Option<ShutdownResult>>,
|
|
|
|
/// The RSA keypair used for encryption with clients.
|
|
|
|
rsa_key: RsaPrivateKey,
|
|
|
|
/// The public part of `rsa_key` encoded in DER, which is an ASN.1 format.
|
|
|
|
/// This is sent to clients during the authentication process.
|
|
|
|
public_key_der: Box<[u8]>,
|
|
|
|
/// For session server requests.
|
|
|
|
http_client: HttpClient,
|
|
|
|
}
|
|
|
|
|
2022-04-30 05:06:20 -07:00
|
|
|
/// Contains information about a new client.
|
2022-11-01 03:11:51 -07:00
|
|
|
#[non_exhaustive]
|
2022-04-14 14:55:45 -07:00
|
|
|
pub struct NewClientData {
|
2022-07-14 23:18:20 -07:00
|
|
|
/// The UUID of the new client.
|
2022-04-14 14:55:45 -07:00
|
|
|
pub uuid: Uuid,
|
2022-07-14 23:18:20 -07:00
|
|
|
/// The username of the new client.
|
2022-10-22 20:17:06 -07:00
|
|
|
pub username: Username<String>,
|
2022-07-14 23:18:20 -07:00
|
|
|
/// The new client's player textures. May be `None` if the client does not
|
|
|
|
/// have a skin or cape.
|
2022-06-28 18:29:29 -07:00
|
|
|
pub textures: Option<SignedPlayerTextures>,
|
2022-07-14 23:18:20 -07:00
|
|
|
/// The remote address of the new client.
|
2022-10-22 04:50:13 +02:00
|
|
|
pub remote_addr: IpAddr,
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
struct NewClientMessage {
|
|
|
|
ncd: NewClientData,
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl: PlayPacketController,
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// The result type returned from [`start_server`].
|
|
|
|
pub type ShutdownResult = Result<(), Box<dyn Error + Send + Sync + 'static>>;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-07-15 20:40:39 -07:00
|
|
|
impl<C: Config> SharedServer<C> {
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Gets a reference to the config object used to start the server.
|
2022-07-15 20:40:39 -07:00
|
|
|
pub fn config(&self) -> &C {
|
|
|
|
&self.0.cfg
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Gets the socket address this server is bound to.
|
2022-04-14 14:55:45 -07:00
|
|
|
pub fn address(&self) -> SocketAddr {
|
|
|
|
self.0.address
|
|
|
|
}
|
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Gets the configured tick rate of this server.
|
2022-04-30 18:01:41 -07:00
|
|
|
pub fn tick_rate(&self) -> Ticks {
|
|
|
|
self.0.tick_rate
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-10-22 04:50:13 +02:00
|
|
|
/// Gets the connection mode of the server.
|
|
|
|
pub fn connection_mode(&self) -> &ConnectionMode {
|
|
|
|
&self.0.connection_mode
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Gets the maximum number of connections allowed to the server at once.
|
2022-04-30 05:06:20 -07:00
|
|
|
pub fn max_connections(&self) -> usize {
|
|
|
|
self.0.max_connections
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
/// Gets the configured incoming capacity.
|
|
|
|
pub fn incoming_capacity(&self) -> usize {
|
|
|
|
self.0.incoming_capacity
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
/// Gets the configured outgoing incoming capacity.
|
|
|
|
pub fn outgoing_capacity(&self) -> usize {
|
|
|
|
self.0.outgoing_capacity
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Gets a handle to the tokio instance this server is using.
|
2022-04-14 14:55:45 -07:00
|
|
|
pub fn tokio_handle(&self) -> &Handle {
|
|
|
|
&self.0.tokio_handle
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Obtains a [`Dimension`] by using its corresponding [`DimensionId`].
|
|
|
|
///
|
|
|
|
/// It is safe but unspecified behavior to call this function using a
|
|
|
|
/// [`DimensionId`] not originating from the configuration used to construct
|
|
|
|
/// the server.
|
|
|
|
pub fn dimension(&self, id: DimensionId) -> &Dimension {
|
|
|
|
self.0
|
|
|
|
.dimensions
|
|
|
|
.get(id.0 as usize)
|
|
|
|
.expect("invalid dimension ID")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an iterator over all added dimensions and their associated
|
|
|
|
/// [`DimensionId`].
|
2022-04-30 05:06:20 -07:00
|
|
|
pub fn dimensions(&self) -> impl FusedIterator<Item = (DimensionId, &Dimension)> + Clone {
|
2022-04-14 14:55:45 -07:00
|
|
|
self.0
|
|
|
|
.dimensions
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2022-04-30 05:06:20 -07:00
|
|
|
.map(|(i, d)| (DimensionId(i as u16), d))
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Obtains a [`Biome`] by using its corresponding [`BiomeId`].
|
2022-09-02 00:06:45 -07:00
|
|
|
///
|
|
|
|
/// It is safe but unspecified behavior to call this function using a
|
|
|
|
/// [`BiomeId`] not originating from the configuration used to construct
|
|
|
|
/// the server.
|
2022-04-14 14:55:45 -07:00
|
|
|
pub fn biome(&self, id: BiomeId) -> &Biome {
|
|
|
|
self.0.biomes.get(id.0 as usize).expect("invalid biome ID")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an iterator over all added biomes and their associated
|
2022-05-16 02:36:14 -07:00
|
|
|
/// [`BiomeId`] in ascending order.
|
|
|
|
pub fn biomes(
|
|
|
|
&self,
|
|
|
|
) -> impl ExactSizeIterator<Item = (BiomeId, &Biome)> + DoubleEndedIterator + FusedIterator + Clone
|
|
|
|
{
|
2022-04-14 14:55:45 -07:00
|
|
|
self.0
|
|
|
|
.biomes
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2022-04-30 05:06:20 -07:00
|
|
|
.map(|(i, b)| (BiomeId(i as u16), b))
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-09-23 04:51:26 -07:00
|
|
|
pub(crate) fn registry_codec(&self) -> &Compound {
|
|
|
|
&self.0.registry_codec
|
|
|
|
}
|
|
|
|
|
2022-04-14 14:55:45 -07:00
|
|
|
/// Returns the instant the server was started.
|
|
|
|
pub fn start_instant(&self) -> Instant {
|
|
|
|
self.0.start_instant
|
|
|
|
}
|
|
|
|
|
2022-05-16 02:36:14 -07:00
|
|
|
/// Returns the number of ticks that have elapsed since the server began.
|
|
|
|
pub fn current_tick(&self) -> Ticks {
|
|
|
|
self.0.tick_counter.load(Ordering::SeqCst)
|
|
|
|
}
|
|
|
|
|
2022-04-14 14:55:45 -07:00
|
|
|
/// Immediately stops new connections to the server and initiates server
|
2022-07-11 05:08:02 -07:00
|
|
|
/// shutdown. The given result is returned through [`start_server`].
|
2022-04-14 14:55:45 -07:00
|
|
|
///
|
|
|
|
/// You may want to disconnect all players with a message prior to calling
|
|
|
|
/// this function.
|
2022-11-01 03:11:51 -07:00
|
|
|
pub fn shutdown<E>(&self, res: Result<(), E>)
|
2022-04-14 14:55:45 -07:00
|
|
|
where
|
|
|
|
E: Into<Box<dyn Error + Send + Sync + 'static>>,
|
|
|
|
{
|
|
|
|
self.0.connection_sema.close();
|
2022-11-01 03:11:51 -07:00
|
|
|
*self.0.shutdown_result.lock().unwrap() = Some(res.map_err(|e| e.into()));
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-30 05:06:20 -07:00
|
|
|
/// Consumes the configuration and starts the server.
|
|
|
|
///
|
2022-11-09 18:30:44 -08:00
|
|
|
/// This function blocks the current thread and returns once the server has shut
|
|
|
|
/// down, a runtime error occurs, or the configuration is found to be invalid.
|
2022-07-27 19:21:11 -07:00
|
|
|
pub fn start_server<C: Config>(config: C, data: C::ServerState) -> ShutdownResult {
|
2022-09-23 19:10:11 -07:00
|
|
|
let shared = setup_server(config)
|
|
|
|
.context("failed to initialize server")
|
|
|
|
.map_err(Box::<dyn Error + Send + Sync + 'static>::from)?;
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
let _guard = shared.tokio_handle().enter();
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
let mut server = Server {
|
2022-07-27 19:21:11 -07:00
|
|
|
state: data,
|
2022-07-03 15:31:24 -07:00
|
|
|
shared: shared.clone(),
|
|
|
|
clients: Clients::new(),
|
|
|
|
entities: Entities::new(),
|
|
|
|
worlds: Worlds::new(shared.clone()),
|
2022-08-09 14:44:04 -07:00
|
|
|
player_lists: PlayerLists::new(),
|
2022-10-15 22:47:02 -04:00
|
|
|
inventories: Inventories::new(),
|
2022-07-03 15:31:24 -07:00
|
|
|
};
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
shared.config().init(&mut server);
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
tokio::spawn(do_accept_loop(shared));
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
do_update_loop(&mut server)
|
2022-04-30 05:06:20 -07:00
|
|
|
}
|
|
|
|
|
2022-07-15 20:40:39 -07:00
|
|
|
fn setup_server<C: Config>(cfg: C) -> anyhow::Result<SharedServer<C>> {
|
2022-04-30 05:06:20 -07:00
|
|
|
let max_connections = cfg.max_connections();
|
|
|
|
let address = cfg.address();
|
2022-04-30 18:01:41 -07:00
|
|
|
let tick_rate = cfg.tick_rate();
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-04-30 18:01:41 -07:00
|
|
|
ensure!(tick_rate > 0, "tick rate must be greater than zero");
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-10-22 04:50:13 +02:00
|
|
|
let connection_mode = cfg.connection_mode();
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
let incoming_packet_capacity = cfg.incoming_capacity();
|
2022-04-30 05:06:20 -07:00
|
|
|
|
|
|
|
ensure!(
|
|
|
|
incoming_packet_capacity > 0,
|
|
|
|
"serverbound packet capacity must be nonzero"
|
|
|
|
);
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
let outgoing_packet_capacity = cfg.outgoing_capacity();
|
2022-04-30 05:06:20 -07:00
|
|
|
|
|
|
|
ensure!(
|
|
|
|
outgoing_packet_capacity > 0,
|
|
|
|
"outgoing packet capacity must be nonzero"
|
|
|
|
);
|
|
|
|
|
|
|
|
let tokio_handle = cfg.tokio_handle();
|
|
|
|
|
2022-09-23 04:51:26 -07:00
|
|
|
let dimensions = cfg.dimensions();
|
|
|
|
validate_dimensions(&dimensions)?;
|
2022-04-30 05:06:20 -07:00
|
|
|
|
|
|
|
let biomes = cfg.biomes();
|
2022-09-23 04:51:26 -07:00
|
|
|
validate_biomes(&biomes)?;
|
2022-04-30 05:06:20 -07:00
|
|
|
|
2022-04-14 14:55:45 -07:00
|
|
|
let rsa_key = RsaPrivateKey::new(&mut OsRng, 1024)?;
|
|
|
|
|
|
|
|
let public_key_der =
|
|
|
|
rsa_der::public_key_to_der(&rsa_key.n().to_bytes_be(), &rsa_key.e().to_bytes_be())
|
|
|
|
.into_boxed_slice();
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
let (new_clients_tx, new_clients_rx) = flume::bounded(1024);
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-04-30 05:06:20 -07:00
|
|
|
let runtime = if tokio_handle.is_none() {
|
2022-04-14 14:55:45 -07:00
|
|
|
Some(Runtime::new()?)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2022-04-30 05:06:20 -07:00
|
|
|
let tokio_handle = match &runtime {
|
2022-04-14 14:55:45 -07:00
|
|
|
Some(rt) => rt.handle().clone(),
|
2022-04-30 05:06:20 -07:00
|
|
|
None => tokio_handle.unwrap(),
|
2022-04-14 14:55:45 -07:00
|
|
|
};
|
|
|
|
|
2022-09-23 04:51:26 -07:00
|
|
|
let registry_codec = make_registry_codec(&dimensions, &biomes);
|
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
let server = SharedServerInner {
|
2022-07-15 20:40:39 -07:00
|
|
|
cfg,
|
2022-04-30 05:06:20 -07:00
|
|
|
address,
|
2022-04-30 18:01:41 -07:00
|
|
|
tick_rate,
|
2022-10-22 04:50:13 +02:00
|
|
|
connection_mode,
|
2022-04-30 05:06:20 -07:00
|
|
|
max_connections,
|
2022-11-01 03:11:51 -07:00
|
|
|
incoming_capacity: incoming_packet_capacity,
|
|
|
|
outgoing_capacity: outgoing_packet_capacity,
|
2022-04-30 05:06:20 -07:00
|
|
|
tokio_handle,
|
|
|
|
_tokio_runtime: runtime,
|
|
|
|
dimensions,
|
|
|
|
biomes,
|
2022-09-23 04:51:26 -07:00
|
|
|
registry_codec,
|
2022-04-14 14:55:45 -07:00
|
|
|
start_instant: Instant::now(),
|
2022-05-16 02:36:14 -07:00
|
|
|
new_clients_rx,
|
|
|
|
new_clients_tx,
|
|
|
|
tick_counter: AtomicI64::new(0),
|
2022-04-30 05:06:20 -07:00
|
|
|
connection_sema: Arc::new(Semaphore::new(max_connections)),
|
2022-04-14 14:55:45 -07:00
|
|
|
shutdown_result: Mutex::new(None),
|
|
|
|
rsa_key,
|
|
|
|
public_key_der,
|
|
|
|
http_client: HttpClient::new(),
|
2022-05-16 02:36:14 -07:00
|
|
|
};
|
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
Ok(SharedServer(Arc::new(server)))
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-09-23 04:51:26 -07:00
|
|
|
fn make_registry_codec(dimensions: &[Dimension], biomes: &[Biome]) -> Compound {
|
|
|
|
compound! {
|
|
|
|
ident!("dimension_type") => compound! {
|
|
|
|
"type" => ident!("dimension_type"),
|
|
|
|
"value" => List::Compound(dimensions.iter().enumerate().map(|(id, dim)| compound! {
|
|
|
|
"name" => DimensionId(id as u16).dimension_type_name(),
|
|
|
|
"id" => id as i32,
|
|
|
|
"element" => dim.to_dimension_registry_item(),
|
|
|
|
}).collect()),
|
|
|
|
},
|
|
|
|
ident!("worldgen/biome") => compound! {
|
|
|
|
"type" => ident!("worldgen/biome"),
|
|
|
|
"value" => {
|
2022-10-13 18:19:35 -07:00
|
|
|
List::Compound(biomes
|
2022-09-23 04:51:26 -07:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(id, biome)| biome.to_biome_registry_item(id as i32))
|
2022-10-13 18:19:35 -07:00
|
|
|
.collect())
|
2022-09-23 04:51:26 -07:00
|
|
|
}
|
2022-10-13 18:19:35 -07:00
|
|
|
|
2022-09-23 04:51:26 -07:00
|
|
|
},
|
2022-11-12 14:32:00 +00:00
|
|
|
ident!("chat_type") => compound! {
|
2022-09-23 04:51:26 -07:00
|
|
|
"type" => ident!("chat_type"),
|
|
|
|
"value" => List::Compound(Vec::new()),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
fn do_update_loop(server: &mut Server<impl Config>) -> ShutdownResult {
|
2022-05-16 02:36:14 -07:00
|
|
|
let mut tick_start = Instant::now();
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
let shared = server.shared.clone();
|
2022-04-14 14:55:45 -07:00
|
|
|
loop {
|
2022-07-03 15:31:24 -07:00
|
|
|
if let Some(res) = shared.0.shutdown_result.lock().unwrap().take() {
|
2022-04-14 14:55:45 -07:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
while let Ok(msg) = shared.0.new_clients_rx.try_recv() {
|
2022-11-01 03:11:51 -07:00
|
|
|
server
|
|
|
|
.clients
|
|
|
|
.insert(Client::new(msg.ctrl, msg.ncd, Default::default()));
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-06-24 16:11:15 -07:00
|
|
|
// Get serverbound packets first so they are not dealt with a tick late.
|
2022-07-03 15:31:24 -07:00
|
|
|
server.clients.par_iter_mut().for_each(|(_, client)| {
|
|
|
|
client.handle_serverbound_packets(&server.entities);
|
2022-06-24 16:11:15 -07:00
|
|
|
});
|
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
shared.config().update(server);
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
server.worlds.par_iter_mut().for_each(|(id, world)| {
|
|
|
|
world.spatial_index.update(&server.entities, id);
|
|
|
|
});
|
2022-06-19 00:25:25 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
server.clients.par_iter_mut().for_each(|(_, client)| {
|
2022-08-09 14:44:04 -07:00
|
|
|
client.update(
|
|
|
|
&shared,
|
|
|
|
&server.entities,
|
|
|
|
&server.worlds,
|
|
|
|
&server.player_lists,
|
2022-10-15 22:47:02 -04:00
|
|
|
&server.inventories,
|
2022-08-09 14:44:04 -07:00
|
|
|
);
|
2022-07-03 15:31:24 -07:00
|
|
|
});
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
server.entities.update();
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-07-03 15:31:24 -07:00
|
|
|
server.worlds.par_iter_mut().for_each(|(_, world)| {
|
2022-08-10 20:09:10 -07:00
|
|
|
world.chunks.update();
|
2022-04-29 00:48:41 -07:00
|
|
|
});
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-08-09 14:44:04 -07:00
|
|
|
server.player_lists.update();
|
2022-10-15 22:47:02 -04:00
|
|
|
server.inventories.update();
|
2022-08-09 14:44:04 -07:00
|
|
|
|
2022-04-29 00:48:41 -07:00
|
|
|
// Sleep for the remainder of the tick.
|
2022-07-03 15:31:24 -07:00
|
|
|
let tick_duration = Duration::from_secs_f64((shared.0.tick_rate as f64).recip());
|
2022-05-16 02:36:14 -07:00
|
|
|
thread::sleep(tick_duration.saturating_sub(tick_start.elapsed()));
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-05-16 02:36:14 -07:00
|
|
|
tick_start = Instant::now();
|
2022-07-03 15:31:24 -07:00
|
|
|
shared.0.tick_counter.fetch_add(1, Ordering::SeqCst);
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
async fn do_accept_loop(server: SharedServer<impl Config>) {
|
2022-04-14 14:55:45 -07:00
|
|
|
log::trace!("entering accept loop");
|
|
|
|
|
|
|
|
let listener = match TcpListener::bind(server.0.address).await {
|
|
|
|
Ok(listener) => listener,
|
|
|
|
Err(e) => {
|
|
|
|
server.shutdown(Err(e).context("failed to start TCP listener"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match server.0.connection_sema.clone().acquire_owned().await {
|
|
|
|
Ok(permit) => match listener.accept().await {
|
|
|
|
Ok((stream, remote_addr)) => {
|
|
|
|
let server = server.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
if let Err(e) = stream.set_nodelay(true) {
|
2022-07-06 02:11:15 -07:00
|
|
|
log::error!("failed to set TCP_NODELAY: {e}");
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Err(e) = handle_connection(server, stream, remote_addr).await {
|
2022-07-06 02:11:15 -07:00
|
|
|
if let Some(e) = e.downcast_ref::<io::Error>() {
|
|
|
|
if e.kind() == io::ErrorKind::UnexpectedEof {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-07-11 05:08:02 -07:00
|
|
|
log::error!("connection to {remote_addr} ended: {e:#}");
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
drop(permit);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
log::error!("failed to accept incoming connection: {e}");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// Closed semaphore indicates server shutdown.
|
|
|
|
Err(_) => return,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
async fn handle_connection(
|
|
|
|
server: SharedServer<impl Config>,
|
2022-04-14 14:55:45 -07:00
|
|
|
stream: TcpStream,
|
|
|
|
remote_addr: SocketAddr,
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
let (read, write) = stream.into_split();
|
2022-11-01 03:11:51 -07:00
|
|
|
|
|
|
|
let mut ctrl = InitialPacketController::new(
|
|
|
|
read,
|
|
|
|
write,
|
|
|
|
PacketEncoder::new(),
|
|
|
|
PacketDecoder::new(),
|
|
|
|
Duration::from_secs(5),
|
|
|
|
);
|
2022-04-14 14:55:45 -07:00
|
|
|
|
|
|
|
// TODO: peek stream for 0xFE legacy ping
|
|
|
|
|
2022-11-13 06:10:42 -08:00
|
|
|
let handshake = ctrl.recv_packet::<HandshakeOwned>().await?;
|
2022-10-22 04:50:13 +02:00
|
|
|
|
|
|
|
ensure!(
|
|
|
|
matches!(server.connection_mode(), ConnectionMode::BungeeCord)
|
|
|
|
|| handshake.server_address.chars().count() <= 255,
|
|
|
|
"handshake server address is too long"
|
|
|
|
);
|
2022-08-14 15:18:22 -07:00
|
|
|
|
|
|
|
match handshake.next_state {
|
2022-11-01 03:11:51 -07:00
|
|
|
HandshakeNextState::Status => handle_status(server, ctrl, remote_addr, handshake)
|
2022-04-14 14:55:45 -07:00
|
|
|
.await
|
|
|
|
.context("error during status"),
|
2022-11-01 03:11:51 -07:00
|
|
|
HandshakeNextState::Login => match handle_login(&server, &mut ctrl, remote_addr, handshake)
|
2022-04-14 14:55:45 -07:00
|
|
|
.await
|
|
|
|
.context("error during login")?
|
|
|
|
{
|
2022-11-01 03:11:51 -07:00
|
|
|
Some(ncd) => {
|
|
|
|
let msg = NewClientMessage {
|
|
|
|
ncd,
|
|
|
|
ctrl: ctrl.into_play_packet_controller(
|
|
|
|
server.0.incoming_capacity,
|
|
|
|
server.0.outgoing_capacity,
|
2022-11-09 18:30:44 -08:00
|
|
|
server.tokio_handle().clone(),
|
2022-11-01 03:11:51 -07:00
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
let _ = server.0.new_clients_tx.send_async(msg).await;
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-04-14 14:55:45 -07:00
|
|
|
None => Ok(()),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
async fn handle_status(
|
|
|
|
server: SharedServer<impl Config>,
|
|
|
|
mut ctrl: InitialPacketController<OwnedReadHalf, OwnedWriteHalf>,
|
2022-04-14 14:55:45 -07:00
|
|
|
remote_addr: SocketAddr,
|
2022-11-13 06:10:42 -08:00
|
|
|
handshake: HandshakeOwned,
|
2022-04-14 14:55:45 -07:00
|
|
|
) -> anyhow::Result<()> {
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl.recv_packet::<StatusRequest>().await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-08-14 15:18:22 -07:00
|
|
|
match server
|
|
|
|
.0
|
|
|
|
.cfg
|
|
|
|
.server_list_ping(&server, remote_addr, handshake.protocol_version.0)
|
|
|
|
.await
|
|
|
|
{
|
2022-04-14 14:55:45 -07:00
|
|
|
ServerListPing::Respond {
|
|
|
|
online_players,
|
|
|
|
max_players,
|
2022-09-10 16:02:12 -07:00
|
|
|
player_sample,
|
2022-04-14 14:55:45 -07:00
|
|
|
description,
|
|
|
|
favicon_png,
|
|
|
|
} => {
|
|
|
|
let mut json = json!({
|
|
|
|
"version": {
|
2022-11-13 06:10:42 -08:00
|
|
|
"name": MINECRAFT_VERSION,
|
2022-04-14 14:55:45 -07:00
|
|
|
"protocol": PROTOCOL_VERSION
|
|
|
|
},
|
|
|
|
"players": {
|
|
|
|
"online": online_players,
|
|
|
|
"max": max_players,
|
2022-09-10 16:02:12 -07:00
|
|
|
"sample": player_sample,
|
2022-04-14 14:55:45 -07:00
|
|
|
},
|
|
|
|
"description": description,
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(data) = favicon_png {
|
2022-07-05 19:21:52 -07:00
|
|
|
let mut buf = "data:image/png;base64,".to_owned();
|
2022-04-14 14:55:45 -07:00
|
|
|
base64::encode_config_buf(data, base64::STANDARD, &mut buf);
|
|
|
|
json.as_object_mut()
|
|
|
|
.unwrap()
|
2022-07-05 19:21:52 -07:00
|
|
|
.insert("favicon".to_owned(), Value::String(buf));
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl.send_packet(&StatusResponse {
|
2022-11-13 06:10:42 -08:00
|
|
|
json: &json.to_string(),
|
2022-11-01 03:11:51 -07:00
|
|
|
})
|
|
|
|
.await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
ServerListPing::Ignore => return Ok(()),
|
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
let PingRequest { payload } = ctrl.recv_packet().await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl.send_packet(&PingResponse { payload }).await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-10-22 04:50:13 +02:00
|
|
|
/// Handle the login process and return the new client's data if successful.
|
|
|
|
async fn handle_login(
|
|
|
|
server: &SharedServer<impl Config>,
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl: &mut InitialPacketController<OwnedReadHalf, OwnedWriteHalf>,
|
2022-04-14 14:55:45 -07:00
|
|
|
remote_addr: SocketAddr,
|
2022-11-13 06:10:42 -08:00
|
|
|
handshake: HandshakeOwned,
|
2022-04-14 14:55:45 -07:00
|
|
|
) -> anyhow::Result<Option<NewClientData>> {
|
2022-08-14 15:18:22 -07:00
|
|
|
if handshake.protocol_version.0 != PROTOCOL_VERSION {
|
|
|
|
// TODO: send translated disconnect msg?
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
2022-04-14 14:55:45 -07:00
|
|
|
let LoginStart {
|
2022-10-22 20:17:06 -07:00
|
|
|
username,
|
2022-08-30 18:41:17 -07:00
|
|
|
sig_data: _, // TODO
|
|
|
|
profile_id: _, // TODO
|
2022-11-01 03:11:51 -07:00
|
|
|
} = ctrl.recv_packet().await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-11-13 06:10:42 -08:00
|
|
|
let username = username.to_owned_username();
|
|
|
|
|
2022-10-22 04:50:13 +02:00
|
|
|
let ncd = match server.connection_mode() {
|
2022-11-01 03:11:51 -07:00
|
|
|
ConnectionMode::Online => login::online(server, ctrl, remote_addr, username).await?,
|
2022-10-22 04:50:13 +02:00
|
|
|
ConnectionMode::Offline => login::offline(remote_addr, username)?,
|
|
|
|
ConnectionMode::BungeeCord => login::bungeecord(&handshake.server_address, username)?,
|
2022-11-01 03:11:51 -07:00
|
|
|
ConnectionMode::Velocity { secret } => login::velocity(ctrl, username, secret).await?,
|
2022-04-14 14:55:45 -07:00
|
|
|
};
|
|
|
|
|
2022-11-01 20:27:08 -07:00
|
|
|
if let Some(threshold) = server.0.cfg.compression_threshold() {
|
|
|
|
ctrl.send_packet(&SetCompression {
|
|
|
|
threshold: VarInt(threshold as i32),
|
|
|
|
})
|
|
|
|
.await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-11-01 20:27:08 -07:00
|
|
|
ctrl.set_compression(Some(threshold));
|
|
|
|
}
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-08-05 12:36:34 -07:00
|
|
|
if let Err(reason) = server.0.cfg.login(server, &ncd).await {
|
2022-04-14 14:55:45 -07:00
|
|
|
log::info!("Disconnect at login: \"{reason}\"");
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl.send_packet(&DisconnectLogin { reason }).await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
2022-11-01 03:11:51 -07:00
|
|
|
ctrl.send_packet(&LoginSuccess {
|
|
|
|
uuid: ncd.uuid,
|
2022-11-13 06:10:42 -08:00
|
|
|
username: ncd.username.as_str_username(),
|
2022-11-01 03:11:51 -07:00
|
|
|
properties: Vec::new(),
|
|
|
|
})
|
|
|
|
.await?;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-08-05 12:36:34 -07:00
|
|
|
Ok(Some(ncd))
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|