valence_server_common/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod despawn;
4mod uuid;
5
6use std::num::NonZeroU32;
7use std::time::Duration;
8
9use bevy_app::prelude::*;
10use bevy_app::ScheduleRunnerPlugin;
11use bevy_ecs::prelude::*;
12pub use despawn::*;
13use valence_protocol::CompressionThreshold;
14
15pub use crate::uuid::*;
16
17/// Minecraft's standard ticks per second (TPS).
18pub const DEFAULT_TPS: NonZeroU32 = match NonZeroU32::new(20) {
19    Some(n) => n,
20    None => unreachable!(),
21};
22
23#[derive(Clone, Resource)]
24pub struct ServerSettings {
25    /// The target ticks per second (TPS) of the server. This is the number of
26    /// game updates that should occur in one second.
27    ///
28    /// On each game update (tick), the server is expected to update game logic
29    /// and respond to packets from clients. Once this is complete, the server
30    /// will sleep for any remaining time until a full tick duration has passed.
31    ///
32    /// Note that the official Minecraft client only processes packets at 20hz,
33    /// so there is little benefit to a tick rate higher than the default 20.
34    ///
35    /// # Default Value
36    ///
37    /// [`DEFAULT_TPS`]
38    pub tick_rate: NonZeroU32,
39    /// The compression threshold to use for compressing packets. For a
40    /// compression threshold of `Some(N)`, packets with encoded lengths >= `N`
41    /// are compressed while all others are not. `None` disables compression
42    /// completely.
43    ///
44    /// If the server is used behind a proxy on the same machine, you will
45    /// likely want to disable compression.
46    ///
47    /// # Default Value
48    ///
49    /// Compression is enabled with an unspecified value. This value may
50    /// change in future versions.
51    pub compression_threshold: CompressionThreshold,
52}
53
54impl Default for ServerSettings {
55    fn default() -> Self {
56        Self {
57            tick_rate: DEFAULT_TPS,
58            compression_threshold: CompressionThreshold(256),
59        }
60    }
61}
62
63pub struct ServerPlugin;
64
65impl Plugin for ServerPlugin {
66    fn build(&self, app: &mut App) {
67        let settings = app
68            .world_mut()
69            .get_resource_or_insert_with(ServerSettings::default)
70            .clone();
71
72        app.insert_resource(Server {
73            current_tick: 0,
74            threshold: settings.compression_threshold,
75            tick_rate: settings.tick_rate,
76        });
77
78        let tick_period = Duration::from_secs_f64(f64::from(settings.tick_rate.get()).recip());
79
80        // Make the app loop forever at the configured TPS.
81        app.add_plugins(ScheduleRunnerPlugin::run_loop(tick_period));
82
83        fn increment_tick_counter(mut server: ResMut<Server>) {
84            server.current_tick += 1;
85        }
86
87        app.add_systems(Last, (increment_tick_counter, despawn_marked_entities));
88    }
89}
90
91/// Contains global server state accessible as a [`Resource`].
92#[derive(Resource, Clone)]
93pub struct Server {
94    /// Incremented on every tick.
95    current_tick: i64,
96    threshold: CompressionThreshold,
97    tick_rate: NonZeroU32,
98}
99
100impl Server {
101    /// Returns the number of ticks that have elapsed since the server began.
102    pub fn current_tick(&self) -> i64 {
103        self.current_tick
104    }
105
106    /// Returns the server's [compression
107    /// threshold](ServerSettings::compression_threshold).
108    pub fn compression_threshold(&self) -> CompressionThreshold {
109        self.threshold
110    }
111
112    // Returns the server's [tick rate](ServerPlugin::tick_rate).
113    pub fn tick_rate(&self) -> NonZeroU32 {
114        self.tick_rate
115    }
116}