1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
//! Configuration for the server.
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::panic::{RefUnwindSafe, UnwindSafe};
use async_trait::async_trait;
use tokio::runtime::Handle as TokioHandle;
use crate::biome::Biome;
use crate::dimension::Dimension;
use crate::server::{NewClientData, Server, SharedServer};
use crate::text::Text;
use crate::{Ticks, STANDARD_TPS};
/// A trait for the configuration of a server.
///
/// This trait uses the [async_trait] attribute macro. It is exported at the
/// root of this crate. async_trait will be removed once async fns in traits
/// are stabilized.
///
/// [async_trait]: https://docs.rs/async-trait/latest/async_trait/
#[async_trait]
#[allow(unused_variables)]
pub trait Config: Sized + Send + Sync + UnwindSafe + RefUnwindSafe + 'static {
/// Custom state to store with the [`Server`].
type ServerState: Send + Sync;
/// Custom state to store with every [`Client`](crate::client::Client).
type ClientState: Default + Send + Sync;
/// Custom state to store with every [`Entity`](crate::entity::Entity).
type EntityState: Send + Sync;
/// Custom state to store with every [`World`](crate::world::World).
type WorldState: Send + Sync;
/// Custom state to store with every [`Chunk`](crate::chunk::Chunk).
type ChunkState: Send + Sync;
/// Custom state to store with every
/// [`PlayerList`](crate::player_list::PlayerList).
type PlayerListState: Send + Sync;
/// Called once at startup to get the maximum number of simultaneous
/// connections allowed to the server. This includes all
/// connections, not just those past the login stage.
///
/// You will want this value to be somewhere above the maximum number of
/// players, since status pings should still succeed even when the server is
/// full.
fn max_connections(&self) -> usize;
/// Called once at startup to get the socket address the server will
/// be bound to.
///
/// # Default Implementation
///
/// Returns `127.0.0.1:25565`.
fn address(&self) -> SocketAddr {
SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 25565).into()
}
/// Called once at startup to get the tick rate, which is the number of game
/// updates that should occur in one second.
///
/// On each game update (tick), the server is expected to update game logic
/// and respond to packets from clients. Once this is complete, the server
/// will sleep for any remaining time until a full tick has passed.
///
/// The tick rate must be greater than zero.
///
/// Note that the official Minecraft client only processes packets at 20hz,
/// so there is little benefit to a tick rate higher than 20.
///
/// # Default Implementation
///
/// Returns [`STANDARD_TPS`].
fn tick_rate(&self) -> Ticks {
STANDARD_TPS
}
/// Called once at startup to get the "online mode" option, which determines
/// if client authentication and encryption should take place.
///
/// When online mode is disabled, malicious clients can give themselves any
/// username and UUID they want, potentially gaining privileges they
/// might not otherwise have. Additionally, encryption is only enabled in
/// online mode. For these reasons online mode should only be disabled
/// for development purposes and enabled on servers exposed to the
/// internet.
///
/// # Default Implementation
///
/// Returns `true`.
fn online_mode(&self) -> bool {
true
}
/// Called once at startup to get the capacity of the buffer used to
/// hold incoming packets.
///
/// A larger capacity reduces the chance that a client needs to be
/// disconnected due to a full buffer, but increases potential memory usage.
///
/// # Default Implementation
///
/// An unspecified value is returned that should be adequate in most
/// situations.
fn incoming_packet_capacity(&self) -> usize {
64
}
/// Called once at startup to get the capacity of the buffer used to
/// hold outgoing packets.
///
/// A larger capacity reduces the chance that a client needs to be
/// disconnected due to a full buffer, but increases potential memory usage.
///
/// # Default Implementation
///
/// An unspecified value is returned that should be adequate in most
/// situations.
fn outgoing_packet_capacity(&self) -> usize {
2048
}
/// Called once at startup to get a handle to the tokio runtime the server
/// will use.
///
/// If a handle is not provided, the server will create its own tokio
/// runtime.
///
/// # Default Implementation
///
/// Returns `None`.
fn tokio_handle(&self) -> Option<TokioHandle> {
None
}
/// Called once at startup to get the list of [`Dimension`]s usable on the
/// server.
///
/// The dimensions returned by [`SharedServer::dimensions`] will be in the
/// same order as the `Vec` returned by this function.
///
/// The number of elements in the returned `Vec` must be in `1..=u16::MAX`.
/// Additionally, the documented requirements on the fields of [`Dimension`]
/// must be met.
///
/// # Default Implementation
///
/// Returns `vec![Dimension::default()]`.
fn dimensions(&self) -> Vec<Dimension> {
vec![Dimension::default()]
}
/// Called once at startup to get the list of [`Biome`]s usable on the
/// server.
///
/// The biomes returned by [`SharedServer::biomes`] will be in the same
/// order as the `Vec` returned by this function.
///
/// The number of elements in the returned `Vec` must be in `1..=u16::MAX`.
/// Additionally, the documented requirements on the fields of [`Biome`]
/// must be met.
///
/// # Default Implementation
///
/// Returns `vec![Dimension::default()]`.
fn biomes(&self) -> Vec<Biome> {
vec![Biome::default()]
}
/// Called when the server receives a Server List Ping query.
/// Data for the response can be provided or the query can be ignored.
///
/// This method is called from within a tokio runtime.
///
/// # Default Implementation
///
/// The query is ignored.
async fn server_list_ping(
&self,
shared: &SharedServer<Self>,
remote_addr: SocketAddr,
protocol_version: i32,
) -> ServerListPing {
ServerListPing::Ignore
}
/// Called asynchronously for each client after successful authentication
/// (if online mode is enabled) to determine if they can join
/// the server. On success, the new client is added to the server's
/// [`Clients`]. If this method returns with `Err(reason)`, then the
/// client is immediately disconnected with the given reason.
///
/// This method is the appropriate place to perform asynchronous
/// operations such as database queries which may take some time to
/// complete.
///
/// This method is called from within a tokio runtime.
///
/// # Default Implementation
///
/// The client is allowed to join unconditionally.
///
/// [`Clients`]: crate::client::Clients
async fn login(&self, shared: &SharedServer<Self>, ncd: &NewClientData) -> Result<(), Text> {
Ok(())
}
/// Called after the server is created, but prior to accepting connections
/// and entering the update loop.
///
/// This is useful for performing initialization work with a guarantee that
/// no connections to the server will be made until this function returns.
///
/// This method is called from within a tokio runtime.
fn init(&self, server: &mut Server<Self>) {}
/// Called once at the beginning of every server update (also known as
/// "tick"). This is likely where the majority of your code will be.
///
/// The frequency of ticks can be configured by [`Self::tick_rate`].
///
/// This method is called from within a tokio runtime.
///
/// # Default Implementation
///
/// The default implementation does nothing.
fn update(&self, server: &mut Server<Self>);
}
/// The result of the [`server_list_ping`](Config::server_list_ping) callback.
#[derive(Debug)]
pub enum ServerListPing<'a> {
/// Responds to the server list ping with the given information.
Respond {
/// Displayed as the number of players on the server.
online_players: i32,
/// Displayed as the maximum number of players allowed on the server at
/// a time.
max_players: i32,
/// A description of the server.
description: Text,
/// The server's icon as the bytes of a PNG image.
/// The image must be 64x64 pixels.
///
/// No icon is used if the value is `None`.
favicon_png: Option<&'a [u8]>,
},
/// Ignores the query and disconnects from the client.
Ignore,
}