valence/src/player_list.rs

447 lines
14 KiB
Rust
Raw Normal View History

2022-07-15 16:18:20 +10:00
//! The player list (tab list).
2022-06-28 10:52:23 +10:00
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use bitfield_struct::bitfield;
use uuid::Uuid;
use valence_protocol::packets::s2c::play::{PlayerInfo, SetTabListHeaderAndFooter};
use valence_protocol::types::{GameMode, PlayerInfoAddPlayer, SignedProperty};
use valence_protocol::{Text, VarInt};
2022-06-28 10:52:23 +10:00
2022-08-10 07:44:04 +10:00
use crate::config::Config;
use crate::player_textures::SignedPlayerTextures;
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
use crate::server::PlayPacketController;
2022-08-10 07:44:04 +10:00
use crate::slab_rc::{Key, SlabRc};
2022-06-28 10:52:23 +10:00
2022-09-02 17:06:45 +10:00
/// A container for all [`PlayerList`]s on a server.
2022-08-10 07:44:04 +10:00
pub struct PlayerLists<C: Config> {
slab: SlabRc<PlayerList<C>>,
}
2022-09-02 17:06:45 +10:00
/// An identifier for a [`PlayerList`] on the server.
///
/// Player list IDs are refcounted. Once all IDs referring to the same player
/// list are dropped, the player list is automatically deleted.
///
/// The [`Ord`] instance on this type is correct but otherwise unspecified. This
/// is useful for storing IDs in containers such as
/// [`BTreeMap`](std::collections::BTreeMap).
2022-08-10 07:44:04 +10:00
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct PlayerListId(Key);
impl<C: Config> PlayerLists<C> {
pub(crate) fn new() -> Self {
Self {
slab: SlabRc::new(),
}
}
2022-09-02 17:37:02 +10:00
/// Creates a new player list and returns an exclusive reference to it along
/// with its ID.
2022-09-02 17:06:45 +10:00
///
2022-09-02 17:37:02 +10:00
/// The player list is automatically removed at the end of the tick once all
/// IDs to it have been dropped.
2022-08-10 07:44:04 +10:00
pub fn insert(&mut self, state: C::PlayerListState) -> (PlayerListId, &mut PlayerList<C>) {
let (key, pl) = self.slab.insert(PlayerList {
state,
entries: HashMap::new(),
removed: HashSet::new(),
header: Text::default(),
footer: Text::default(),
modified_header_or_footer: false,
});
(PlayerListId(key), pl)
}
2022-09-02 17:37:02 +10:00
/// Returns the number of player lists.
2022-08-10 07:44:04 +10:00
pub fn len(&self) -> usize {
self.slab.len()
}
2022-09-02 17:37:02 +10:00
/// Returns `true` if there are no player lists.
pub fn is_empty(&self) -> bool {
self.slab.len() == 0
}
/// Gets a shared reference to the player list with the given player list
/// ID.
///
/// This operation is infallible because [`PlayerListId`] is refcounted.
2022-08-10 07:44:04 +10:00
pub fn get(&self, id: &PlayerListId) -> &PlayerList<C> {
self.slab.get(&id.0)
}
2022-09-02 17:37:02 +10:00
/// Gets an exclusive reference to the player list with the given player
/// list ID.
///
/// This operation is infallible because [`PlayerListId`] is refcounted.
2022-08-10 07:44:04 +10:00
pub fn get_mut(&mut self, id: &PlayerListId) -> &mut PlayerList<C> {
self.slab.get_mut(&id.0)
}
pub(crate) fn update(&mut self) {
self.slab.collect_garbage();
for (_, pl) in self.slab.iter_mut() {
for entry in pl.entries.values_mut() {
entry.bits = EntryBits::new();
}
pl.removed.clear();
pl.modified_header_or_footer = false;
}
}
}
2022-07-11 22:08:02 +10:00
/// The list of players on a server visible by pressing the tab key by default.
///
/// Each entry in the player list is intended to represent a connected client to
/// the server.
///
/// In addition to a list of players, the player list has a header and a footer
/// which can contain arbitrary text.
2022-08-10 07:44:04 +10:00
pub struct PlayerList<C: Config> {
/// Custom state
pub state: C::PlayerListState,
2022-06-28 10:52:23 +10:00
entries: HashMap<Uuid, PlayerListEntry>,
removed: HashSet<Uuid>,
header: Text,
footer: Text,
modified_header_or_footer: bool,
}
2022-08-10 07:44:04 +10:00
impl<C: Config> PlayerList<C> {
2022-07-11 22:08:02 +10:00
/// Inserts a player into the player list.
///
/// If the given UUID conflicts with an existing entry, the entry is
/// overwritten and `false` is returned. Otherwise, `true` is returned.
pub fn insert(
&mut self,
uuid: Uuid,
username: impl Into<String>,
textures: Option<SignedPlayerTextures>,
game_mode: GameMode,
ping: i32,
display_name: Option<Text>,
2022-07-11 22:08:02 +10:00
) -> bool {
match self.entries.entry(uuid) {
Entry::Occupied(mut oe) => {
let e = oe.get_mut();
let username = username.into();
if e.username() != username || e.textures != textures {
self.removed.insert(*oe.key());
oe.insert(PlayerListEntry {
username,
textures,
game_mode,
ping,
display_name,
2022-08-06 05:36:34 +10:00
bits: EntryBits::new().with_created_this_tick(true),
});
} else {
e.set_game_mode(game_mode);
e.set_ping(ping);
e.set_display_name(display_name);
}
2022-07-11 22:08:02 +10:00
false
}
Entry::Vacant(ve) => {
ve.insert(PlayerListEntry {
username: username.into(),
textures,
game_mode,
ping,
display_name,
2022-08-06 05:36:34 +10:00
bits: EntryBits::new().with_created_this_tick(true),
});
2022-07-11 22:08:02 +10:00
true
}
}
}
2022-07-11 22:08:02 +10:00
/// Removes an entry from the player list with the given UUID. Returns
/// whether the entry was present in the list.
pub fn remove(&mut self, uuid: Uuid) -> bool {
if self.entries.remove(&uuid).is_some() {
self.removed.insert(uuid);
true
} else {
false
}
}
2022-09-19 11:35:46 +10:00
/// Removes all entries from the player list for which `f` returns `false`.
2022-07-11 22:08:02 +10:00
///
/// All entries are visited in an unspecified order.
pub fn retain(&mut self, mut f: impl FnMut(Uuid, &mut PlayerListEntry) -> bool) {
self.entries.retain(|&uuid, entry| {
if !f(uuid, entry) {
self.removed.insert(uuid);
false
} else {
true
}
})
}
/// Removes all entries from the player list.
pub fn clear(&mut self) {
self.removed.extend(self.entries.drain().map(|p| p.0))
}
/// Gets the header part of the player list.
2022-06-28 10:52:23 +10:00
pub fn header(&self) -> &Text {
&self.header
}
2022-07-11 22:08:02 +10:00
/// Sets the header part of the player list.
pub fn set_header(&mut self, header: impl Into<Text>) {
let header = header.into();
if self.header != header {
self.header = header;
self.modified_header_or_footer = true;
}
}
2022-07-11 22:08:02 +10:00
/// Gets the footer part of the player list.
2022-06-28 10:52:23 +10:00
pub fn footer(&self) -> &Text {
&self.footer
}
2022-07-11 22:08:02 +10:00
/// Sets the footer part of the player list.
pub fn set_footer(&mut self, footer: impl Into<Text>) {
let footer = footer.into();
if self.footer != footer {
self.footer = footer;
self.modified_header_or_footer = true;
}
}
/// Returns a reference to the entry with the given UUID.
///
/// If the entry does not exist, `None` is returned.
pub fn entry(&self, uuid: Uuid) -> Option<&PlayerListEntry> {
self.entries.get(&uuid)
}
/// Returns a mutable reference to the entry with the given UUID.
///
/// If the entry does not exist, `None` is returned.
pub fn entry_mut(&mut self, uuid: Uuid) -> Option<&mut PlayerListEntry> {
self.entries.get_mut(&uuid)
}
2022-07-11 22:08:02 +10:00
/// Returns an iterator over all entries in an unspecified order.
2022-06-28 10:52:23 +10:00
pub fn entries(&self) -> impl Iterator<Item = (Uuid, &PlayerListEntry)> + '_ {
self.entries.iter().map(|(k, v)| (*k, v))
}
2022-09-02 17:06:45 +10:00
/// Returns a mutable iterator over all entries in an unspecified order.
pub fn entries_mut(&mut self) -> impl Iterator<Item = (Uuid, &mut PlayerListEntry)> + '_ {
self.entries.iter_mut().map(|(k, v)| (*k, v))
}
pub(crate) fn send_initial_packets(
&self,
ctrl: &mut PlayPacketController,
) -> anyhow::Result<()> {
2022-06-28 10:52:23 +10:00
let add_player: Vec<_> = self
.entries
.iter()
.map(|(&uuid, e)| PlayerInfoAddPlayer {
2022-06-28 10:52:23 +10:00
uuid,
username: &e.username,
2022-06-28 10:52:23 +10:00
properties: {
let mut properties = Vec::new();
if let Some(textures) = &e.textures {
properties.push(SignedProperty {
name: "textures",
value: textures.payload(),
signature: Some(textures.signature()),
2022-06-28 10:52:23 +10:00
});
}
properties
},
game_mode: e.game_mode,
ping: VarInt(e.ping),
display_name: e.display_name.clone(),
sig_data: None,
})
.collect();
if !add_player.is_empty() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::AddPlayer(add_player))?;
2022-06-28 10:52:23 +10:00
}
if self.header != Text::default() || self.footer != Text::default() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&SetTabListHeaderAndFooter {
header: self.header.clone(),
footer: self.footer.clone(),
})?;
2022-06-28 10:52:23 +10:00
}
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
Ok(())
2022-06-28 10:52:23 +10:00
}
pub(crate) fn send_update_packets(
&self,
ctrl: &mut PlayPacketController,
) -> anyhow::Result<()> {
2022-06-28 10:52:23 +10:00
if !self.removed.is_empty() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::RemovePlayer(
self.removed.iter().cloned().collect(),
))?;
2022-06-28 10:52:23 +10:00
}
let mut add_player = Vec::new();
let mut game_mode = Vec::new();
let mut ping = Vec::new();
let mut display_name = Vec::new();
for (&uuid, e) in self.entries.iter() {
2022-08-06 05:36:34 +10:00
if e.bits.created_this_tick() {
2022-06-28 10:52:23 +10:00
let mut properties = Vec::new();
if let Some(textures) = &e.textures {
properties.push(SignedProperty {
name: "textures",
value: textures.payload(),
signature: Some(textures.signature()),
2022-06-28 10:52:23 +10:00
});
}
add_player.push(PlayerInfoAddPlayer {
2022-06-28 10:52:23 +10:00
uuid,
username: e.username(),
2022-06-28 10:52:23 +10:00
properties,
game_mode: e.game_mode,
ping: VarInt(e.ping),
display_name: e.display_name.clone(),
sig_data: None,
});
continue;
}
2022-08-06 05:36:34 +10:00
if e.bits.modified_game_mode() {
2022-06-28 10:52:23 +10:00
game_mode.push((uuid, e.game_mode));
}
2022-08-06 05:36:34 +10:00
if e.bits.modified_ping() {
2022-06-28 10:52:23 +10:00
ping.push((uuid, VarInt(e.ping)));
}
2022-08-06 05:36:34 +10:00
if e.bits.modified_display_name() {
2022-06-28 10:52:23 +10:00
display_name.push((uuid, e.display_name.clone()));
}
}
if !add_player.is_empty() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::AddPlayer(add_player))?;
2022-06-28 10:52:23 +10:00
}
if !game_mode.is_empty() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::UpdateGameMode(game_mode))?;
2022-06-28 10:52:23 +10:00
}
if !ping.is_empty() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::UpdateLatency(ping))?;
2022-06-28 10:52:23 +10:00
}
if !display_name.is_empty() {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::UpdateDisplayName(display_name))?;
2022-06-28 10:52:23 +10:00
}
if self.modified_header_or_footer {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&SetTabListHeaderAndFooter {
header: self.header.clone(),
footer: self.footer.clone(),
})?;
2022-06-28 10:52:23 +10:00
}
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
Ok(())
2022-06-28 10:52:23 +10:00
}
pub(crate) fn queue_clear_packets(
&self,
ctrl: &mut PlayPacketController,
) -> anyhow::Result<()> {
Redesign packet processing and improve `Client` update procedure. (#146) Closes #82 Closes #43 Closes #64 # Changes and Improvements - Packet encoding/decoding happens within `Client` instead of being sent over a channel first. This is better for performance and lays the groundwork for #83. - Reduce the amount of copying necessary by leveraging the `bytes` crate and recent changes to `EncodePacket`. Performance is noticeably improved with maximum players in the `rust-mc-bot` test going from 750 to 1050. - Packet encoding/decoding code is decoupled from IO. This is easier to understand and more suitable for a future protocol lib. - Precise control over the number of bytes that are buffered for sending/receiving. This is important for limiting maximum memory usage correctly. - "packet controllers" are introduced, which are convenient structures for managing packet IO before and during the play state. - `byte_channel` module is created to help implement the `PlayPacketController`. This is essentially a channel of bytes implemented with an `Arc<Mutex<BytesMut>>`. - Error handling in the update procedure for clients was improved using `anyhow::Result<()>` to exit as early as possible. The `client` module is a bit cleaner as a result. - The `LoginPlay` packet is always sent before all other play packets. We no longer have to worry about the behavior of packets sent before that packet. Most packet deferring performed currently can be eliminated. - The packet_inspector was rewritten in response to the above changes. - Timeouts on IO operations behave better. # Known Issues - The packet_inspector now re-encodes packets rather than just decoding them. This will cause problems when trying to use it with the vanilla server because there are missing clientbound packets and other issues. This will be fixed when the protocol module is moved to a separate crate.
2022-11-01 21:11:51 +11:00
ctrl.append_packet(&PlayerInfo::RemovePlayer(
self.entries.keys().cloned().collect(),
))
2022-06-28 10:52:23 +10:00
}
}
2022-07-11 22:08:02 +10:00
/// Represents a player entry in the [`PlayerList`].
2022-06-28 10:52:23 +10:00
pub struct PlayerListEntry {
username: String,
textures: Option<SignedPlayerTextures>,
2022-06-28 10:52:23 +10:00
game_mode: GameMode,
ping: i32,
display_name: Option<Text>,
2022-08-06 05:36:34 +10:00
bits: EntryBits,
}
#[bitfield(u8)]
struct EntryBits {
created_this_tick: bool,
modified_game_mode: bool,
modified_ping: bool,
modified_display_name: bool,
#[bits(4)]
_pad: u8,
2022-06-28 10:52:23 +10:00
}
impl PlayerListEntry {
2022-07-11 22:08:02 +10:00
/// Gets the username of this entry.
2022-06-28 10:52:23 +10:00
pub fn username(&self) -> &str {
&self.username
}
2022-07-15 16:18:20 +10:00
/// Gets the player textures for this entry.
pub fn textures(&self) -> Option<&SignedPlayerTextures> {
self.textures.as_ref()
2022-06-28 10:52:23 +10:00
}
2022-07-11 22:08:02 +10:00
/// Gets the game mode of this entry.
2022-06-28 10:52:23 +10:00
pub fn game_mode(&self) -> GameMode {
self.game_mode
}
2022-07-11 22:08:02 +10:00
/// Sets the game mode of this entry.
pub fn set_game_mode(&mut self, game_mode: GameMode) {
if self.game_mode != game_mode {
self.game_mode = game_mode;
2022-08-06 05:36:34 +10:00
self.bits.set_modified_game_mode(true);
}
2022-06-28 10:52:23 +10:00
}
2022-07-11 22:08:02 +10:00
/// Gets the ping (latency) of this entry measured in milliseconds.
pub fn ping(&self) -> i32 {
self.ping
2022-06-28 10:52:23 +10:00
}
2022-07-11 22:08:02 +10:00
/// Sets the ping (latency) of this entry measured in milliseconds.
pub fn set_ping(&mut self, ping: i32) {
if self.ping != ping {
self.ping = ping;
2022-08-06 05:36:34 +10:00
self.bits.set_modified_ping(true);
2022-06-28 10:52:23 +10:00
}
}
2022-07-11 22:08:02 +10:00
/// Gets the display name of this entry.
pub fn display_name(&self) -> Option<&Text> {
self.display_name.as_ref()
2022-06-28 10:52:23 +10:00
}
2022-07-11 22:08:02 +10:00
/// Sets the display name of this entry.
2022-06-28 10:52:23 +10:00
pub fn set_display_name(&mut self, display_name: impl Into<Option<Text>>) {
let display_name = display_name.into();
if self.display_name != display_name {
self.display_name = display_name;
2022-08-06 05:36:34 +10:00
self.bits.set_modified_display_name(true);
2022-06-28 10:52:23 +10:00
}
}
}