Clippy: warn clippy::pedantic
This commit is contained in:
parent
11a588b622
commit
12ab2c7298
@ -96,12 +96,12 @@ pub fn validate_textures(property: &Property, config: &TextureConfig) -> Result<
|
|||||||
for texture in textures.textures {
|
for texture in textures.textures {
|
||||||
let url =
|
let url =
|
||||||
Url::parse(&texture.1.url).map_err(|e| TextureError::InvalidURL(e.to_string()))?;
|
Url::parse(&texture.1.url).map_err(|e| TextureError::InvalidURL(e.to_string()))?;
|
||||||
is_texture_url_valid(url, config)?
|
is_texture_url_valid(&url, config)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_texture_url_valid(url: Url, config: &TextureConfig) -> Result<(), TextureError> {
|
pub fn is_texture_url_valid(url: &Url, config: &TextureConfig) -> Result<(), TextureError> {
|
||||||
let scheme = url.scheme();
|
let scheme = url.scheme();
|
||||||
if !config
|
if !config
|
||||||
.allowed_url_schemes
|
.allowed_url_schemes
|
||||||
|
|||||||
@ -192,15 +192,11 @@ impl Client {
|
|||||||
let profile = authentication::authenticate(username, &hash, &ip, auth_client).await?;
|
let profile = authentication::authenticate(username, &hash, &ip, auth_client).await?;
|
||||||
// Check if player should join
|
// Check if player should join
|
||||||
if let Some(actions) = &profile.profile_actions {
|
if let Some(actions) = &profile.profile_actions {
|
||||||
if !ADVANCED_CONFIG
|
if ADVANCED_CONFIG
|
||||||
.authentication
|
.authentication
|
||||||
.player_profile
|
.player_profile
|
||||||
.allow_banned_players
|
.allow_banned_players
|
||||||
{
|
{
|
||||||
if !actions.is_empty() {
|
|
||||||
return Err(AuthError::Banned);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for allowed in &ADVANCED_CONFIG
|
for allowed in &ADVANCED_CONFIG
|
||||||
.authentication
|
.authentication
|
||||||
.player_profile
|
.player_profile
|
||||||
@ -210,6 +206,11 @@ impl Client {
|
|||||||
return Err(AuthError::DisallowedAction);
|
return Err(AuthError::DisallowedAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !actions.is_empty() {
|
||||||
|
return Err(AuthError::Banned);
|
||||||
|
}
|
||||||
|
} else if !actions.is_empty() {
|
||||||
|
return Err(AuthError::Banned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// validate textures
|
// validate textures
|
||||||
@ -234,7 +235,7 @@ impl Client {
|
|||||||
Ok((profile, new_address)) => {
|
Ok((profile, new_address)) => {
|
||||||
self.finish_login(&profile).await;
|
self.finish_login(&profile).await;
|
||||||
*self.gameprofile.lock().await = Some(profile);
|
*self.gameprofile.lock().await = Some(profile);
|
||||||
*address = new_address
|
*address = new_address;
|
||||||
}
|
}
|
||||||
Err(error) => self.kick(&error.to_string()).await,
|
Err(error) => self.kick(&error.to_string()).await,
|
||||||
}
|
}
|
||||||
@ -259,10 +260,10 @@ impl Client {
|
|||||||
&resource_config.resource_pack_url,
|
&resource_config.resource_pack_url,
|
||||||
&resource_config.resource_pack_sha1,
|
&resource_config.resource_pack_sha1,
|
||||||
resource_config.force,
|
resource_config.force,
|
||||||
if !resource_config.prompt_message.is_empty() {
|
if resource_config.prompt_message.is_empty() {
|
||||||
Some(TextComponent::text(&resource_config.prompt_message))
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(TextComponent::text(&resource_config.prompt_message))
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -298,7 +299,7 @@ impl Client {
|
|||||||
server_listing: client_information.server_listing,
|
server_listing: client_information.server_listing,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.kick("Invalid hand or chat type").await
|
self.kick("Invalid hand or chat type").await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +329,7 @@ impl Client {
|
|||||||
self.send_packet(&CFinishConfig::new()).await;
|
self.send_packet(&CFinishConfig::new()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_config_acknowledged(&self, _config_acknowledged: SAcknowledgeFinishConfig) {
|
pub fn handle_config_acknowledged(&self, _config_acknowledged: &SAcknowledgeFinishConfig) {
|
||||||
dbg!("config acknowledged");
|
dbg!("config acknowledged");
|
||||||
self.connection_state.store(ConnectionState::Play);
|
self.connection_state.store(ConnectionState::Play);
|
||||||
self.make_player
|
self.make_player
|
||||||
|
|||||||
@ -71,7 +71,7 @@ impl Player {
|
|||||||
.carried_item
|
.carried_item
|
||||||
.load()
|
.load()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or_else(Slot::empty, |item| item.into());
|
.map_or_else(Slot::empty, std::convert::Into::into);
|
||||||
|
|
||||||
// Gets the previous value
|
// Gets the previous value
|
||||||
let i = inventory
|
let i = inventory
|
||||||
@ -92,7 +92,7 @@ impl Player {
|
|||||||
inventory.total_opened_containers += 1;
|
inventory.total_opened_containers += 1;
|
||||||
self.client
|
self.client
|
||||||
.send_packet(&CCloseContainer::new(inventory.total_opened_containers))
|
.send_packet(&CCloseContainer::new(inventory.total_opened_containers))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_container_property<T: WindowPropertyTrait>(
|
pub async fn set_container_property<T: WindowPropertyTrait>(
|
||||||
@ -270,7 +270,7 @@ impl Player {
|
|||||||
slots.skip(36).rev().find_map(find_condition)
|
slots.skip(36).rev().find_map(find_condition)
|
||||||
};
|
};
|
||||||
if let Some(slot) = slots {
|
if let Some(slot) = slots {
|
||||||
let mut item_slot = container.all_slots()[slot].map(|i| i.to_owned());
|
let mut item_slot = container.all_slots()[slot].map(|i| i);
|
||||||
container.handle_item_change(&mut item_slot, slot, MouseClick::Left)?;
|
container.handle_item_change(&mut item_slot, slot, MouseClick::Left)?;
|
||||||
*container.all_slots()[slot] = item_slot;
|
*container.all_slots()[slot] = item_slot;
|
||||||
}
|
}
|
||||||
@ -363,13 +363,14 @@ impl Player {
|
|||||||
let player_id = self.entity_id();
|
let player_id = self.entity_id();
|
||||||
let container_id = opened_container
|
let container_id = opened_container
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|container| container.internal_pumpkin_id())
|
.map_or(player_id as u64, |container| {
|
||||||
.unwrap_or(player_id as u64);
|
container.internal_pumpkin_id()
|
||||||
|
});
|
||||||
match mouse_drag_state {
|
match mouse_drag_state {
|
||||||
MouseDragState::Start(drag_type) => {
|
MouseDragState::Start(drag_type) => {
|
||||||
if drag_type == MouseDragType::Middle && self.gamemode.load() != GameMode::Creative
|
if drag_type == MouseDragType::Middle && self.gamemode.load() != GameMode::Creative
|
||||||
{
|
{
|
||||||
Err(InventoryError::PermissionError)?
|
Err(InventoryError::PermissionError)?;
|
||||||
}
|
}
|
||||||
drag_handler
|
drag_handler
|
||||||
.new_drag(container_id, player_id, drag_type)
|
.new_drag(container_id, player_id, drag_type)
|
||||||
@ -417,15 +418,15 @@ impl Player {
|
|||||||
.await
|
.await
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(token, player)| {
|
.filter_map(|(token, player)| {
|
||||||
if *token != player_token {
|
if *token == player_token {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
let entity_id = player.entity_id();
|
let entity_id = player.entity_id();
|
||||||
if player_ids.contains(&entity_id) {
|
if player_ids.contains(&entity_id) {
|
||||||
Some(player.clone())
|
Some(player.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|||||||
@ -125,7 +125,7 @@ impl Client {
|
|||||||
gameprofile: Mutex::new(None),
|
gameprofile: Mutex::new(None),
|
||||||
config: Mutex::new(None),
|
config: Mutex::new(None),
|
||||||
brand: Mutex::new(None),
|
brand: Mutex::new(None),
|
||||||
server_address: Mutex::new("".to_string()),
|
server_address: Mutex::new(String::new()),
|
||||||
id,
|
id,
|
||||||
address: Mutex::new(address),
|
address: Mutex::new(address),
|
||||||
connection_state: AtomicCell::new(ConnectionState::HandShake),
|
connection_state: AtomicCell::new(ConnectionState::HandShake),
|
||||||
@ -211,9 +211,9 @@ impl Client {
|
|||||||
while let Some(mut packet) = self.client_packets_queue.lock().await.pop_front() {
|
while let Some(mut packet) = self.client_packets_queue.lock().await.pop_front() {
|
||||||
if let Err(error) = self.handle_packet(server, &mut packet).await {
|
if let Err(error) = self.handle_packet(server, &mut packet).await {
|
||||||
dbg!("{:?}", packet.id);
|
dbg!("{:?}", packet.id);
|
||||||
let text = format!("Error while reading incoming packet {}", error);
|
let text = format!("Error while reading incoming packet {error}");
|
||||||
log::error!("{}", text);
|
log::error!("{}", text);
|
||||||
self.kick(&text).await
|
self.kick(&text).await;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ impl Client {
|
|||||||
pumpkin_protocol::ConnectionState::Config => {
|
pumpkin_protocol::ConnectionState::Config => {
|
||||||
self.handle_config_packet(server, packet).await
|
self.handle_config_packet(server, packet).await
|
||||||
}
|
}
|
||||||
_ => {
|
pumpkin_protocol::ConnectionState::Play => {
|
||||||
log::error!("Invalid Connection state {:?}", self.connection_state);
|
log::error!("Invalid Connection state {:?}", self.connection_state);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -251,20 +251,16 @@ impl Client {
|
|||||||
packet: &mut RawPacket,
|
packet: &mut RawPacket,
|
||||||
) -> Result<(), DeserializerError> {
|
) -> Result<(), DeserializerError> {
|
||||||
let bytebuf = &mut packet.bytebuf;
|
let bytebuf = &mut packet.bytebuf;
|
||||||
match packet.id.0 {
|
if packet.id.0 == SHandShake::PACKET_ID {
|
||||||
SHandShake::PACKET_ID => {
|
|
||||||
self.handle_handshake(SHandShake::read(bytebuf)?).await;
|
self.handle_handshake(SHandShake::read(bytebuf)?).await;
|
||||||
Ok(())
|
} else {
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
log::error!(
|
log::error!(
|
||||||
"Failed to handle packet id {} while in Handshake state",
|
"Failed to handle packet id {} while in Handshake state",
|
||||||
packet.id.0
|
packet.id.0
|
||||||
);
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_status_packet(
|
async fn handle_status_packet(
|
||||||
&self,
|
&self,
|
||||||
@ -276,22 +272,20 @@ impl Client {
|
|||||||
SStatusRequest::PACKET_ID => {
|
SStatusRequest::PACKET_ID => {
|
||||||
self.handle_status_request(server, SStatusRequest::read(bytebuf)?)
|
self.handle_status_request(server, SStatusRequest::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SStatusPingRequest::PACKET_ID => {
|
SStatusPingRequest::PACKET_ID => {
|
||||||
self.handle_ping_request(SStatusPingRequest::read(bytebuf)?)
|
self.handle_ping_request(SStatusPingRequest::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Failed to handle packet id {} while in Status state",
|
"Failed to handle packet id {} while in Status state",
|
||||||
packet.id.0
|
packet.id.0
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_login_packet(
|
async fn handle_login_packet(
|
||||||
&self,
|
&self,
|
||||||
@ -303,32 +297,28 @@ impl Client {
|
|||||||
SLoginStart::PACKET_ID => {
|
SLoginStart::PACKET_ID => {
|
||||||
self.handle_login_start(server, SLoginStart::read(bytebuf)?)
|
self.handle_login_start(server, SLoginStart::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SEncryptionResponse::PACKET_ID => {
|
SEncryptionResponse::PACKET_ID => {
|
||||||
self.handle_encryption_response(server, SEncryptionResponse::read(bytebuf)?)
|
self.handle_encryption_response(server, SEncryptionResponse::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SLoginPluginResponse::PACKET_ID => {
|
SLoginPluginResponse::PACKET_ID => {
|
||||||
self.handle_plugin_response(SLoginPluginResponse::read(bytebuf)?)
|
self.handle_plugin_response(SLoginPluginResponse::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SLoginAcknowledged::PACKET_ID => {
|
SLoginAcknowledged::PACKET_ID => {
|
||||||
self.handle_login_acknowledged(server, SLoginAcknowledged::read(bytebuf)?)
|
self.handle_login_acknowledged(server, SLoginAcknowledged::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Failed to handle packet id {} while in Login state",
|
"Failed to handle packet id {} while in Login state",
|
||||||
packet.id.0
|
packet.id.0
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_config_packet(
|
async fn handle_config_packet(
|
||||||
&self,
|
&self,
|
||||||
@ -340,32 +330,27 @@ impl Client {
|
|||||||
SClientInformationConfig::PACKET_ID => {
|
SClientInformationConfig::PACKET_ID => {
|
||||||
self.handle_client_information_config(SClientInformationConfig::read(bytebuf)?)
|
self.handle_client_information_config(SClientInformationConfig::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SPluginMessage::PACKET_ID => {
|
SPluginMessage::PACKET_ID => {
|
||||||
self.handle_plugin_message(SPluginMessage::read(bytebuf)?)
|
self.handle_plugin_message(SPluginMessage::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SAcknowledgeFinishConfig::PACKET_ID => {
|
SAcknowledgeFinishConfig::PACKET_ID => {
|
||||||
self.handle_config_acknowledged(SAcknowledgeFinishConfig::read(bytebuf)?)
|
self.handle_config_acknowledged(&SAcknowledgeFinishConfig::read(bytebuf)?);
|
||||||
.await;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
SKnownPacks::PACKET_ID => {
|
SKnownPacks::PACKET_ID => {
|
||||||
self.handle_known_packs(server, SKnownPacks::read(bytebuf)?)
|
self.handle_known_packs(server, SKnownPacks::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Failed to handle packet id {} while in Config state",
|
"Failed to handle packet id {} while in Config state",
|
||||||
packet.id.0
|
packet.id.0
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads the connection until our buffer of len 4096 is full, then decode
|
/// Reads the connection until our buffer of len 4096 is full, then decode
|
||||||
/// Close connection when an error occurs or when the Client closed the connection
|
/// Close connection when an error occurs or when the Client closed the connection
|
||||||
@ -406,7 +391,7 @@ impl Client {
|
|||||||
match self.connection_state.load() {
|
match self.connection_state.load() {
|
||||||
ConnectionState::Login => {
|
ConnectionState::Login => {
|
||||||
self.try_send_packet(&CLoginDisconnect::new(
|
self.try_send_packet(&CLoginDisconnect::new(
|
||||||
&serde_json::to_string_pretty(&reason).unwrap_or_else(|_| "".into()),
|
&serde_json::to_string_pretty(&reason).unwrap_or_else(|_| String::new()),
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|_| self.close());
|
.unwrap_or_else(|_| self.close());
|
||||||
@ -423,10 +408,10 @@ impl Client {
|
|||||||
.unwrap_or_else(|_| self.close());
|
.unwrap_or_else(|_| self.close());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("Can't kick in {:?} State", self.connection_state)
|
log::warn!("Can't kick in {:?} State", self.connection_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.close()
|
self.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// You should prefer to use `kick` when you can
|
/// You should prefer to use `kick` when you can
|
||||||
|
|||||||
@ -52,13 +52,13 @@ impl Player {
|
|||||||
|
|
||||||
*awaiting_teleport = None;
|
*awaiting_teleport = None;
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Wrong teleport id")).await
|
self.kick(TextComponent::text("Wrong teleport id")).await;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text(
|
self.kick(TextComponent::text(
|
||||||
"Send Teleport confirm, but we did not teleport",
|
"Send Teleport confirm, but we did not teleport",
|
||||||
))
|
))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_player_ground(&self, ground: SSetPlayerGround) {
|
pub fn handle_player_ground(&self, ground: &SSetPlayerGround) {
|
||||||
self.living_entity
|
self.living_entity
|
||||||
.entity
|
.entity
|
||||||
.on_ground
|
.on_ground
|
||||||
@ -272,23 +272,23 @@ impl Player {
|
|||||||
match action {
|
match action {
|
||||||
pumpkin_protocol::server::play::Action::StartSneaking => {
|
pumpkin_protocol::server::play::Action::StartSneaking => {
|
||||||
if !entity.sneaking.load(std::sync::atomic::Ordering::Relaxed) {
|
if !entity.sneaking.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
entity.set_sneaking(true).await
|
entity.set_sneaking(true).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::StopSneaking => {
|
pumpkin_protocol::server::play::Action::StopSneaking => {
|
||||||
if entity.sneaking.load(std::sync::atomic::Ordering::Relaxed) {
|
if entity.sneaking.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
entity.set_sneaking(false).await
|
entity.set_sneaking(false).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::LeaveBed => todo!(),
|
pumpkin_protocol::server::play::Action::LeaveBed => todo!(),
|
||||||
pumpkin_protocol::server::play::Action::StartSprinting => {
|
pumpkin_protocol::server::play::Action::StartSprinting => {
|
||||||
if !entity.sprinting.load(std::sync::atomic::Ordering::Relaxed) {
|
if !entity.sprinting.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
entity.set_sprinting(true).await
|
entity.set_sprinting(true).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::StopSprinting => {
|
pumpkin_protocol::server::play::Action::StopSprinting => {
|
||||||
if entity.sprinting.load(std::sync::atomic::Ordering::Relaxed) {
|
if entity.sprinting.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
entity.set_sprinting(false).await
|
entity.set_sprinting(false).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::StartHorseJump => todo!(),
|
pumpkin_protocol::server::play::Action::StartHorseJump => todo!(),
|
||||||
@ -307,7 +307,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Invalid player command"))
|
self.kick(TextComponent::text("Invalid player command"))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +325,7 @@ impl Player {
|
|||||||
&[self.client.id],
|
&[self.client.id],
|
||||||
&CEntityAnimation::new(id.into(), animation as u8),
|
&CEntityAnimation::new(id.into(), animation as u8),
|
||||||
)
|
)
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.kick(TextComponent::text("Invalid hand")).await;
|
self.kick(TextComponent::text("Invalid hand")).await;
|
||||||
@ -362,7 +362,7 @@ impl Player {
|
|||||||
TextComponent::text(&gameprofile.name),
|
TextComponent::text(&gameprofile.name),
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
.await
|
.await;
|
||||||
|
|
||||||
/* server.broadcast_packet(
|
/* server.broadcast_packet(
|
||||||
self,
|
self,
|
||||||
@ -392,7 +392,7 @@ impl Player {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Invalid hand or chat type"))
|
self.kick(TextComponent::text("Invalid hand or chat type"))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,8 +425,8 @@ impl Player {
|
|||||||
let saved_velo = victem_entity.velocity.load();
|
let saved_velo = victem_entity.velocity.load();
|
||||||
victem_entity.knockback(
|
victem_entity.knockback(
|
||||||
strength * 0.5,
|
strength * 0.5,
|
||||||
(yaw * (PI / 180.0)).sin() as f64,
|
f64::from((yaw * (PI / 180.0)).sin()),
|
||||||
-(yaw * (PI / 180.0)).cos() as f64,
|
f64::from(-(yaw * (PI / 180.0)).cos()),
|
||||||
);
|
);
|
||||||
let victem_velocity = victem_entity.velocity.load();
|
let victem_velocity = victem_entity.velocity.load();
|
||||||
let packet = &CEntityVelocity::new(
|
let packet = &CEntityVelocity::new(
|
||||||
@ -447,12 +447,12 @@ impl Player {
|
|||||||
&entity_id,
|
&entity_id,
|
||||||
entity.yaw.load(),
|
entity.yaw.load(),
|
||||||
))
|
))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
if config.swing {}
|
if config.swing {}
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Interacted with invalid entity id"))
|
self.kick(TextComponent::text("Interacted with invalid entity id"))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,7 +552,7 @@ impl Player {
|
|||||||
self.wait_for_keep_alive
|
self.wait_for_keep_alive
|
||||||
.store(false, std::sync::atomic::Ordering::Relaxed);
|
.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Timeout")).await
|
self.kick(TextComponent::text("Timeout")).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,11 +605,11 @@ impl Player {
|
|||||||
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
|
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
|
||||||
.await;
|
.await;
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Invalid block face")).await
|
self.kick(TextComponent::text("Invalid block face")).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_use_item(&self, _use_item: SUseItem) {
|
pub fn handle_use_item(&self, _use_item: &SUseItem) {
|
||||||
// TODO: handle packet correctly
|
// TODO: handle packet correctly
|
||||||
log::error!("An item was used(SUseItem), but the packet is not implemented yet");
|
log::error!("An item was used(SUseItem), but the packet is not implemented yet");
|
||||||
}
|
}
|
||||||
@ -651,7 +651,7 @@ impl Player {
|
|||||||
if let Some(id) = open_container {
|
if let Some(id) = open_container {
|
||||||
let mut open_containers = server.open_containers.write().await;
|
let mut open_containers = server.open_containers.write().await;
|
||||||
if let Some(container) = open_containers.get_mut(&id) {
|
if let Some(container) = open_containers.get_mut(&id) {
|
||||||
container.remove_player(self.entity_id())
|
container.remove_player(self.entity_id());
|
||||||
}
|
}
|
||||||
self.open_container.store(None);
|
self.open_container.store(None);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,9 +17,8 @@ pub fn consume_arg_player(
|
|||||||
"@s" => {
|
"@s" => {
|
||||||
if src.is_player() {
|
if src.is_player() {
|
||||||
return Ok(arg.into());
|
return Ok(arg.into());
|
||||||
} else {
|
|
||||||
return Err(Some("You are not a Player".into()));
|
|
||||||
}
|
}
|
||||||
|
return Err(Some("You are not a Player".into()));
|
||||||
}
|
}
|
||||||
"@p" if src.is_player() => return Ok(arg.into()),
|
"@p" if src.is_player() => return Ok(arg.into()),
|
||||||
"@r" => todo!(), // todo: implement random player target selector
|
"@r" => todo!(), // todo: implement random player target selector
|
||||||
@ -31,7 +30,7 @@ pub fn consume_arg_player(
|
|||||||
return Ok(name.into());
|
return Ok(name.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(Some(format!("Player not found: {}", arg)));
|
return Err(Some(format!("Player not found: {arg}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,9 +51,9 @@ pub fn parse_arg_player(
|
|||||||
|
|
||||||
match s {
|
match s {
|
||||||
"@s" if src.is_player() => Ok(src.as_mut_player().unwrap()),
|
"@s" if src.is_player() => Ok(src.as_mut_player().unwrap()),
|
||||||
"@p" if src.is_player() => Ok(src.as_mut_player().unwrap()),
|
"@p" => todo!(),
|
||||||
"@r" => Err(InvalidConsumptionError(Some(s.into()))), // todo: implement random player target selector
|
"@r" => todo!(), // todo: implement random player target selector
|
||||||
"@a" | "@e" => Err(InvalidConsumptionError(Some(s.into()))), // todo: implement all players target selector
|
"@a" | "@e" => todo!(), // todo: implement all players target selector
|
||||||
name => {
|
name => {
|
||||||
for world in &server.worlds {
|
for world in &server.worlds {
|
||||||
if let Some(player) = world.get_player_by_name(name) {
|
if let Some(player) = world.get_player_by_name(name) {
|
||||||
|
|||||||
@ -37,7 +37,7 @@ pub fn consume_arg_gamemode(
|
|||||||
|
|
||||||
match GameMode::from_str(arg) {
|
match GameMode::from_str(arg) {
|
||||||
Err(_) | Ok(GameMode::Undefined) => {
|
Err(_) | Ok(GameMode::Undefined) => {
|
||||||
return Err(Some(format!("Gamemode not found: {}", arg)))
|
return Err(Some(format!("Gamemode not found: {arg}")))
|
||||||
}
|
}
|
||||||
Ok(_) => return Ok(arg.into()),
|
Ok(_) => return Ok(arg.into()),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ pub fn init_command_tree<'a>() -> CommandTree<'a> {
|
|||||||
)
|
)
|
||||||
.execute(&|sender, server, _args| {
|
.execute(&|sender, server, _args| {
|
||||||
let mut keys: Vec<&str> = server.command_dispatcher.commands.keys().copied().collect();
|
let mut keys: Vec<&str> = server.command_dispatcher.commands.keys().copied().collect();
|
||||||
keys.sort();
|
keys.sort_unstable();
|
||||||
|
|
||||||
for key in keys {
|
for key in keys {
|
||||||
let Command::Tree(tree) = &server.command_dispatcher.commands[key] else {
|
let Command::Tree(tree) = &server.command_dispatcher.commands[key] else {
|
||||||
|
|||||||
@ -15,7 +15,7 @@ pub(crate) enum InvalidTreeError {
|
|||||||
/// never fail.
|
/// never fail.
|
||||||
InvalidConsumptionError(Option<String>),
|
InvalidConsumptionError(Option<String>),
|
||||||
|
|
||||||
/// Return this if a condition that a [Node::Require] should ensure is met is not met.
|
/// Return this if a condition that a [`Node::Require`] should ensure is met is not met.
|
||||||
InvalidRequirementError,
|
InvalidRequirementError,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ pub struct CommandDispatcher<'a> {
|
|||||||
pub(crate) commands: HashMap<&'a str, Command<'a>>,
|
pub(crate) commands: HashMap<&'a str, Command<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores registered [CommandTree]s and dispatches commands to them.
|
/// Stores registered [`CommandTree`]s and dispatches commands to them.
|
||||||
impl<'a> CommandDispatcher<'a> {
|
impl<'a> CommandDispatcher<'a> {
|
||||||
pub async fn handle_command(&self, sender: &mut CommandSender<'a>, server: &Server, cmd: &str) {
|
pub async fn handle_command(&self, sender: &mut CommandSender<'a>, server: &Server, cmd: &str) {
|
||||||
if let Err(err) = self.dispatch(sender, server, cmd) {
|
if let Err(err) = self.dispatch(sender, server, cmd) {
|
||||||
@ -37,7 +37,7 @@ impl<'a> CommandDispatcher<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a command using its corresponding [CommandTree].
|
/// Execute a command using its corresponding [`CommandTree`].
|
||||||
pub(crate) fn dispatch(
|
pub(crate) fn dispatch(
|
||||||
&'a self,
|
&'a self,
|
||||||
src: &mut CommandSender,
|
src: &mut CommandSender,
|
||||||
@ -52,7 +52,7 @@ impl<'a> CommandDispatcher<'a> {
|
|||||||
|
|
||||||
// try paths until fitting path is found
|
// try paths until fitting path is found
|
||||||
for path in tree.iter_paths() {
|
for path in tree.iter_paths() {
|
||||||
match Self::try_is_fitting_path(src, server, path, tree, raw_args.clone()) {
|
match Self::try_is_fitting_path(src, server, &path, tree, raw_args.clone()) {
|
||||||
Err(InvalidConsumptionError(s)) => {
|
Err(InvalidConsumptionError(s)) => {
|
||||||
println!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed");
|
println!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed");
|
||||||
return Err("Internal Error (See logs for details)".into());
|
return Err("Internal Error (See logs for details)".into());
|
||||||
@ -62,7 +62,7 @@ impl<'a> CommandDispatcher<'a> {
|
|||||||
return Err("Internal Error (See logs for details)".into());
|
return Err("Internal Error (See logs for details)".into());
|
||||||
}
|
}
|
||||||
Ok(is_fitting_path) => match is_fitting_path {
|
Ok(is_fitting_path) => match is_fitting_path {
|
||||||
Ok(_) => return Ok(()),
|
Ok(()) => return Ok(()),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// Custom error message or not ?
|
// Custom error message or not ?
|
||||||
if let Some(error) = error {
|
if let Some(error) = error {
|
||||||
@ -72,7 +72,7 @@ impl<'a> CommandDispatcher<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(format!("Invalid Syntax. Usage: {}", tree))
|
Err(format!("Invalid Syntax. Usage: {tree}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_tree(&'a self, key: &str) -> Result<&'a CommandTree<'a>, String> {
|
pub(crate) fn get_tree(&'a self, key: &str) -> Result<&'a CommandTree<'a>, String> {
|
||||||
@ -93,7 +93,7 @@ impl<'a> CommandDispatcher<'a> {
|
|||||||
fn try_is_fitting_path(
|
fn try_is_fitting_path(
|
||||||
src: &mut CommandSender,
|
src: &mut CommandSender,
|
||||||
server: &Server,
|
server: &Server,
|
||||||
path: Vec<usize>,
|
path: &[usize],
|
||||||
tree: &CommandTree,
|
tree: &CommandTree,
|
||||||
mut raw_args: RawArgs,
|
mut raw_args: RawArgs,
|
||||||
) -> Result<Result<(), Option<String>>, InvalidTreeError> {
|
) -> Result<Result<(), Option<String>>, InvalidTreeError> {
|
||||||
|
|||||||
@ -35,39 +35,30 @@ impl<'a> CommandSender<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn is_player(&self) -> bool {
|
pub const fn is_player(&self) -> bool {
|
||||||
match self {
|
matches!(self, CommandSender::Player(_))
|
||||||
CommandSender::Console => false,
|
|
||||||
CommandSender::Player(_) => true,
|
|
||||||
CommandSender::Rcon(_) => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn is_console(&self) -> bool {
|
pub const fn is_console(&self) -> bool {
|
||||||
match self {
|
matches!(self, CommandSender::Console)
|
||||||
CommandSender::Console => true,
|
|
||||||
CommandSender::Player(_) => false,
|
|
||||||
CommandSender::Rcon(_) => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn as_mut_player(&mut self) -> Option<Arc<Player>> {
|
pub fn as_mut_player(&mut self) -> Option<Arc<Player>> {
|
||||||
match self {
|
match self {
|
||||||
CommandSender::Player(player) => Some(player.clone()),
|
CommandSender::Player(player) => Some(player.clone()),
|
||||||
CommandSender::Console => None,
|
_ => None,
|
||||||
CommandSender::Rcon(_) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// todo: implement
|
/// todo: implement
|
||||||
|
#[must_use]
|
||||||
pub const fn permission_lvl(&self) -> i32 {
|
pub const fn permission_lvl(&self) -> i32 {
|
||||||
match self {
|
4
|
||||||
CommandSender::Rcon(_) => 4,
|
|
||||||
CommandSender::Console => 4,
|
|
||||||
CommandSender::Player(_) => 4,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> {
|
pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> {
|
||||||
let mut dispatcher = CommandDispatcher::default();
|
let mut dispatcher = CommandDispatcher::default();
|
||||||
|
|
||||||
|
|||||||
@ -2,13 +2,13 @@ use super::RunFunctionType;
|
|||||||
use crate::{commands::CommandSender, server::Server};
|
use crate::{commands::CommandSender, server::Server};
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
/// see [crate::commands::tree_builder::argument]
|
/// see [`crate::commands::tree_builder::argument`]
|
||||||
pub type RawArgs<'a> = Vec<&'a str>;
|
pub type RawArgs<'a> = Vec<&'a str>;
|
||||||
|
|
||||||
/// see [crate::commands::tree_builder::argument] and [CommandTree::execute]/[crate::commands::tree_builder::NonLeafNodeBuilder::execute]
|
/// see [`crate::commands::tree_builder::argument`] and [`CommandTree::execute`]/[`crate::commands::tree_builder::NonLeafNodeBuilder::execute`]
|
||||||
pub type ConsumedArgs<'a> = HashMap<&'a str, String>;
|
pub type ConsumedArgs<'a> = HashMap<&'a str, String>;
|
||||||
|
|
||||||
/// see [crate::commands::tree_builder::argument]
|
/// see [`crate::commands::tree_builder::argument`]
|
||||||
/// Provide value or an Optional error message, If no Error message provided the default will be used
|
/// Provide value or an Optional error message, If no Error message provided the default will be used
|
||||||
pub type ArgumentConsumer<'a> =
|
pub type ArgumentConsumer<'a> =
|
||||||
fn(&CommandSender, &Server, &mut RawArgs) -> Result<String, Option<String>>;
|
fn(&CommandSender, &Server, &mut RawArgs) -> Result<String, Option<String>>;
|
||||||
@ -48,7 +48,7 @@ pub struct CommandTree<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CommandTree<'a> {
|
impl<'a> CommandTree<'a> {
|
||||||
/// iterate over all possible paths that end in a [NodeType::ExecuteLeaf]
|
/// iterate over all possible paths that end in a [`NodeType::ExecuteLeaf`]
|
||||||
pub(crate) fn iter_paths(&'a self) -> impl Iterator<Item = Vec<usize>> + 'a {
|
pub(crate) fn iter_paths(&'a self) -> impl Iterator<Item = Vec<usize>> + 'a {
|
||||||
let mut todo = VecDeque::<(usize, usize)>::new();
|
let mut todo = VecDeque::<(usize, usize)>::new();
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use crate::commands::CommandSender;
|
|||||||
use super::RunFunctionType;
|
use super::RunFunctionType;
|
||||||
|
|
||||||
impl<'a> CommandTree<'a> {
|
impl<'a> CommandTree<'a> {
|
||||||
/// Add a child [Node] to the root of this [CommandTree].
|
/// Add a child [Node] to the root of this [`CommandTree`].
|
||||||
pub fn with_child(mut self, child: impl NodeBuilder<'a>) -> Self {
|
pub fn with_child(mut self, child: impl NodeBuilder<'a>) -> Self {
|
||||||
let node = child.build(&mut self);
|
let node = child.build(&mut self);
|
||||||
self.children.push(self.nodes.len());
|
self.children.push(self.nodes.len());
|
||||||
@ -35,11 +35,11 @@ impl<'a> CommandTree<'a> {
|
|||||||
|
|
||||||
/// Executes if a command terminates at this [Node], i.e. without any arguments.
|
/// Executes if a command terminates at this [Node], i.e. without any arguments.
|
||||||
///
|
///
|
||||||
/// [ConsumedArgs] maps the names of all
|
/// [`ConsumedArgs`] maps the names of all
|
||||||
/// arguments to the result of their consumption, i.e. a string that can be parsed to the
|
/// arguments to the result of their consumption, i.e. a string that can be parsed to the
|
||||||
/// desired type.
|
/// desired type.
|
||||||
///
|
///
|
||||||
/// Also see [NonLeafNodeBuilder::execute].
|
/// Also see [`NonLeafNodeBuilder::execute`].
|
||||||
pub fn execute(mut self, run: &'a RunFunctionType) -> Self {
|
pub fn execute(mut self, run: &'a RunFunctionType) -> Self {
|
||||||
let node = Node {
|
let node = Node {
|
||||||
node_type: NodeType::ExecuteLeaf { run },
|
node_type: NodeType::ExecuteLeaf { run },
|
||||||
@ -108,11 +108,11 @@ impl<'a> NonLeafNodeBuilder<'a> {
|
|||||||
|
|
||||||
/// Executes if a command terminates at this [Node].
|
/// Executes if a command terminates at this [Node].
|
||||||
///
|
///
|
||||||
/// [ConsumedArgs] maps the names of all
|
/// [`ConsumedArgs`] maps the names of all
|
||||||
/// arguments to the result of their consumption, i.e. a string that can be parsed to the
|
/// arguments to the result of their consumption, i.e. a string that can be parsed to the
|
||||||
/// desired type.
|
/// desired type.
|
||||||
///
|
///
|
||||||
/// Also see [CommandTree::execute].
|
/// Also see [`CommandTree::execute`].
|
||||||
pub fn execute(mut self, run: &'a RunFunctionType) -> Self {
|
pub fn execute(mut self, run: &'a RunFunctionType) -> Self {
|
||||||
self.leaf_nodes.push(LeafNodeBuilder {
|
self.leaf_nodes.push(LeafNodeBuilder {
|
||||||
node_type: NodeType::ExecuteLeaf { run },
|
node_type: NodeType::ExecuteLeaf { run },
|
||||||
@ -132,14 +132,14 @@ pub const fn literal(string: &str) -> NonLeafNodeBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```name``` identifies this argument in [ConsumedArgs].
|
/// ```name``` identifies this argument in [`ConsumedArgs`].
|
||||||
///
|
///
|
||||||
/// ```consumer: ArgumentConsumer``` has the purpose of validating arguments. Conversion may start
|
/// ```consumer: ArgumentConsumer``` has the purpose of validating arguments. Conversion may start
|
||||||
/// here, as long as the result remains a [String] (e.g. convert offset to absolute position actual
|
/// here, as long as the result remains a [String] (e.g. convert offset to absolute position actual
|
||||||
/// coordinates), because the result of this function will be passed to following
|
/// coordinates), because the result of this function will be passed to following
|
||||||
/// [NonLeafNodeBuilder::execute] nodes in a [ConsumedArgs] instance. It must remove consumed arg(s)
|
/// [`NonLeafNodeBuilder::execute`] nodes in a [`ConsumedArgs`] instance. It must remove consumed arg(s)
|
||||||
/// from [RawArgs] and return them. It must return None if [RawArgs] are invalid. [RawArgs] is
|
/// from [`RawArgs`] and return them. It must return None if [`RawArgs`] are invalid. [`RawArgs`] is
|
||||||
/// reversed, so [Vec::pop] can be used to obtain args in ltr order.
|
/// reversed, so [`Vec::pop`] can be used to obtain args in ltr order.
|
||||||
pub fn argument<'a>(name: &'a str, consumer: ArgumentConsumer) -> NonLeafNodeBuilder<'a> {
|
pub fn argument<'a>(name: &'a str, consumer: ArgumentConsumer) -> NonLeafNodeBuilder<'a> {
|
||||||
NonLeafNodeBuilder {
|
NonLeafNodeBuilder {
|
||||||
node_type: NodeType::Argument { name, consumer },
|
node_type: NodeType::Argument { name, consumer },
|
||||||
|
|||||||
@ -9,12 +9,10 @@ trait IsVisible {
|
|||||||
|
|
||||||
impl<'a> IsVisible for Node<'a> {
|
impl<'a> IsVisible for Node<'a> {
|
||||||
fn is_visible(&self) -> bool {
|
fn is_visible(&self) -> bool {
|
||||||
match self.node_type {
|
matches!(
|
||||||
NodeType::ExecuteLeaf { .. } => false,
|
self.node_type,
|
||||||
NodeType::Literal { .. } => true,
|
NodeType::Literal { .. } | NodeType::Argument { .. }
|
||||||
NodeType::Argument { .. } => true,
|
)
|
||||||
NodeType::Require { .. } => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +41,7 @@ fn flatten_require_nodes(nodes: &[Node], children: &[usize]) -> Vec<usize> {
|
|||||||
let node = &nodes[i];
|
let node = &nodes[i];
|
||||||
match &node.node_type {
|
match &node.node_type {
|
||||||
NodeType::Require { .. } => {
|
NodeType::Require { .. } => {
|
||||||
new_children.extend(flatten_require_nodes(nodes, node.children.as_slice()))
|
new_children.extend(flatten_require_nodes(nodes, node.children.as_slice()));
|
||||||
}
|
}
|
||||||
_ => new_children.push(i),
|
_ => new_children.push(i),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -201,7 +201,7 @@ impl Entity {
|
|||||||
self.entity_id.into(),
|
self.entity_id.into(),
|
||||||
Metadata::new(6, 20.into(), (pose).into()),
|
Metadata::new(6, 20.into(), (pose).into()),
|
||||||
);
|
);
|
||||||
self.world.broadcast_packet_all(&packet).await
|
self.world.broadcast_packet_all(&packet).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@ pub struct Player {
|
|||||||
/// This field represents the various abilities that the player possesses, such as flight, invulnerability, and other special effects.
|
/// This field represents the various abilities that the player possesses, such as flight, invulnerability, and other special effects.
|
||||||
///
|
///
|
||||||
/// **Note:** When the `abilities` field is updated, the server should send a `send_abilities_update` packet to the client to notify them of the changes.
|
/// **Note:** When the `abilities` field is updated, the server should send a `send_abilities_update` packet to the client to notify them of the changes.
|
||||||
pub abilities: Mutex<PlayerAbilities>,
|
pub abilities: Mutex<Abilities>,
|
||||||
/// The player's last known position.
|
/// The player's last known position.
|
||||||
///
|
///
|
||||||
/// This field is used to calculate the player's movement delta for network synchronization and other purposes.
|
/// This field is used to calculate the player's movement delta for network synchronization and other purposes.
|
||||||
@ -110,7 +110,7 @@ impl Player {
|
|||||||
log::error!("No gameprofile?. Impossible");
|
log::error!("No gameprofile?. Impossible");
|
||||||
GameProfile {
|
GameProfile {
|
||||||
id: uuid::Uuid::new_v4(),
|
id: uuid::Uuid::new_v4(),
|
||||||
name: "".to_string(),
|
name: String::new(),
|
||||||
properties: vec![],
|
properties: vec![],
|
||||||
profile_actions: None,
|
profile_actions: None,
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ impl Player {
|
|||||||
open_container: AtomicCell::new(None),
|
open_container: AtomicCell::new(None),
|
||||||
carried_item: AtomicCell::new(None),
|
carried_item: AtomicCell::new(None),
|
||||||
teleport_id_count: AtomicI32::new(0),
|
teleport_id_count: AtomicI32::new(0),
|
||||||
abilities: Mutex::new(PlayerAbilities::default()),
|
abilities: Mutex::new(Abilities::default()),
|
||||||
gamemode: AtomicCell::new(gamemode),
|
gamemode: AtomicCell::new(gamemode),
|
||||||
watched_section: AtomicCell::new(Vector3::new(0, 0, 0)),
|
watched_section: AtomicCell::new(Vector3::new(0, 0, 0)),
|
||||||
last_position: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)),
|
last_position: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)),
|
||||||
@ -152,7 +152,7 @@ impl Player {
|
|||||||
self.living_entity.entity.world.remove_player(self).await;
|
self.living_entity.entity.world.remove_player(self).await;
|
||||||
|
|
||||||
let watched = chunk_section_from_pos(&self.living_entity.entity.block_pos.load());
|
let watched = chunk_section_from_pos(&self.living_entity.entity.block_pos.load());
|
||||||
let view_distance = get_view_distance(self).await as i32;
|
let view_distance = i32::from(get_view_distance(self).await);
|
||||||
let cylindrical = Cylindrical::new(Vector2::new(watched.x, watched.z), view_distance);
|
let cylindrical = Cylindrical::new(Vector2::new(watched.x, watched.z), view_distance);
|
||||||
self.living_entity
|
self.living_entity
|
||||||
.entity
|
.entity
|
||||||
@ -256,7 +256,7 @@ impl Player {
|
|||||||
let standing_eye_height = self.living_entity.entity.standing_eye_height;
|
let standing_eye_height = self.living_entity.entity.standing_eye_height;
|
||||||
box_pos.squared_magnitude(Vector3 {
|
box_pos.squared_magnitude(Vector3 {
|
||||||
x: entity_pos.x,
|
x: entity_pos.x,
|
||||||
y: entity_pos.y + standing_eye_height as f64,
|
y: entity_pos.y + f64::from(standing_eye_height),
|
||||||
z: entity_pos.z,
|
z: entity_pos.z,
|
||||||
}) < d * d
|
}) < d * d
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@ impl Player {
|
|||||||
self.gameprofile.name,
|
self.gameprofile.name,
|
||||||
reason.to_pretty_console()
|
reason.to_pretty_console()
|
||||||
);
|
);
|
||||||
self.client.close()
|
self.client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_health(&self, health: f32, food: i32, food_saturation: f32) {
|
pub async fn set_health(&self, health: f32, food: i32, food_saturation: f32) {
|
||||||
@ -330,15 +330,14 @@ impl Player {
|
|||||||
let mut packets = self.client.client_packets_queue.lock().await;
|
let mut packets = self.client.client_packets_queue.lock().await;
|
||||||
while let Some(mut packet) = packets.pop_back() {
|
while let Some(mut packet) = packets.pop_back() {
|
||||||
match self.handle_play_packet(server, &mut packet).await {
|
match self.handle_play_packet(server, &mut packet).await {
|
||||||
Ok(_) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.is_kick() {
|
if e.is_kick() {
|
||||||
if let Some(kick_reason) = e.client_kick_reason() {
|
if let Some(kick_reason) = e.client_kick_reason() {
|
||||||
self.kick(TextComponent::text(&kick_reason)).await
|
self.kick(TextComponent::text(&kick_reason)).await;
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text(&format!(
|
self.kick(TextComponent::text(&format!(
|
||||||
"Error while reading incoming packet {}",
|
"Error while reading incoming packet {e}"
|
||||||
e
|
|
||||||
)))
|
)))
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -380,7 +379,7 @@ impl Player {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SSetPlayerGround::PACKET_ID => {
|
SSetPlayerGround::PACKET_ID => {
|
||||||
self.handle_player_ground(SSetPlayerGround::read(bytebuf)?);
|
self.handle_player_ground(&SSetPlayerGround::read(bytebuf)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SPlayerCommand::PACKET_ID => {
|
SPlayerCommand::PACKET_ID => {
|
||||||
@ -421,7 +420,7 @@ impl Player {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SUseItem::PACKET_ID => {
|
SUseItem::PACKET_ID => {
|
||||||
self.handle_use_item(SUseItem::read(bytebuf)?);
|
self.handle_use_item(&SUseItem::read(bytebuf)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SSetHeldItem::PACKET_ID => {
|
SSetHeldItem::PACKET_ID => {
|
||||||
@ -464,7 +463,7 @@ impl Player {
|
|||||||
/// Represents a player's abilities and special powers.
|
/// Represents a player's abilities and special powers.
|
||||||
///
|
///
|
||||||
/// This struct contains information about the player's current abilities, such as flight, invulnerability, and creative mode.
|
/// This struct contains information about the player's current abilities, such as flight, invulnerability, and creative mode.
|
||||||
pub struct PlayerAbilities {
|
pub struct Abilities {
|
||||||
/// Indicates whether the player is invulnerable to damage.
|
/// Indicates whether the player is invulnerable to damage.
|
||||||
pub invulnerable: bool,
|
pub invulnerable: bool,
|
||||||
/// Indicates whether the player is currently flying.
|
/// Indicates whether the player is currently flying.
|
||||||
@ -479,7 +478,7 @@ pub struct PlayerAbilities {
|
|||||||
pub walk_speed_fov: f32,
|
pub walk_speed_fov: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerAbilities {
|
impl Default for Abilities {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
invulnerable: false,
|
invulnerable: false,
|
||||||
|
|||||||
@ -22,14 +22,20 @@ impl<ErrorType: PumpkinError + 'static> From<ErrorType> for Box<dyn PumpkinError
|
|||||||
}
|
}
|
||||||
impl PumpkinError for InventoryError {
|
impl PumpkinError for InventoryError {
|
||||||
fn is_kick(&self) -> bool {
|
fn is_kick(&self) -> bool {
|
||||||
use InventoryError::*;
|
use InventoryError::{
|
||||||
|
ClosedContainerInteract, InvalidPacket, InvalidSlot, LockError,
|
||||||
|
MultiplePlayersDragging, OutOfOrderDragging, PermissionError,
|
||||||
|
};
|
||||||
match self {
|
match self {
|
||||||
InvalidSlot | ClosedContainerInteract(..) | InvalidPacket | PermissionError => true,
|
InvalidSlot | ClosedContainerInteract(..) | InvalidPacket | PermissionError => true,
|
||||||
LockError | OutOfOrderDragging | MultiplePlayersDragging => false,
|
LockError | OutOfOrderDragging | MultiplePlayersDragging => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn severity(&self) -> log::Level {
|
fn severity(&self) -> log::Level {
|
||||||
use InventoryError::*;
|
use InventoryError::{
|
||||||
|
ClosedContainerInteract, InvalidPacket, InvalidSlot, LockError,
|
||||||
|
MultiplePlayersDragging, OutOfOrderDragging, PermissionError,
|
||||||
|
};
|
||||||
match self {
|
match self {
|
||||||
LockError
|
LockError
|
||||||
| InvalidSlot
|
| InvalidSlot
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
#![deny(clippy::all)]
|
#![deny(clippy::all)]
|
||||||
// #![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
// #![warn(clippy::restriction)]
|
// #![warn(clippy::restriction)]
|
||||||
#![warn(clippy::nursery)]
|
#![warn(clippy::nursery)]
|
||||||
#![warn(clippy::cargo)]
|
#![warn(clippy::cargo)]
|
||||||
// expect
|
// REMOVE SOME WHEN RELEASE
|
||||||
#![expect(clippy::cargo_common_metadata)]
|
#![expect(clippy::cargo_common_metadata)]
|
||||||
#![expect(clippy::multiple_crate_versions)]
|
#![expect(clippy::multiple_crate_versions)]
|
||||||
#![expect(clippy::while_float)]
|
#![expect(clippy::while_float)]
|
||||||
@ -11,6 +11,16 @@
|
|||||||
#![expect(clippy::significant_drop_tightening)]
|
#![expect(clippy::significant_drop_tightening)]
|
||||||
#![expect(clippy::future_not_send)]
|
#![expect(clippy::future_not_send)]
|
||||||
#![expect(clippy::single_call_fn)]
|
#![expect(clippy::single_call_fn)]
|
||||||
|
#![expect(clippy::cast_sign_loss)]
|
||||||
|
#![expect(clippy::cast_possible_truncation)]
|
||||||
|
#![expect(clippy::cast_possible_wrap)]
|
||||||
|
#![expect(clippy::too_many_lines)]
|
||||||
|
#![expect(clippy::missing_panics_doc)]
|
||||||
|
#![expect(clippy::missing_errors_doc)]
|
||||||
|
#![expect(clippy::module_name_repetitions)]
|
||||||
|
#![expect(clippy::struct_excessive_bools)]
|
||||||
|
#![expect(clippy::many_single_char_names)]
|
||||||
|
#![expect(clippy::float_cmp)]
|
||||||
|
|
||||||
#[cfg(target_os = "wasi")]
|
#[cfg(target_os = "wasi")]
|
||||||
compile_error!("Compiling for WASI targets is not supported!");
|
compile_error!("Compiling for WASI targets is not supported!");
|
||||||
@ -60,7 +70,7 @@ fn init_logger() {
|
|||||||
|
|
||||||
logger = logger.with_colors(ADVANCED_CONFIG.logging.color);
|
logger = logger.with_colors(ADVANCED_CONFIG.logging.color);
|
||||||
logger = logger.with_threads(ADVANCED_CONFIG.logging.threads);
|
logger = logger.with_threads(ADVANCED_CONFIG.logging.threads);
|
||||||
logger.init().unwrap()
|
logger.init().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +92,7 @@ async fn main() -> io::Result<()> {
|
|||||||
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
||||||
use pumpkin_core::text::{color::NamedColor, TextComponent};
|
use pumpkin_core::text::{color::NamedColor, TextComponent};
|
||||||
use rcon::RCONServer;
|
use rcon::RCONServer;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
init_logger();
|
init_logger();
|
||||||
|
|
||||||
@ -109,8 +120,6 @@ async fn main() -> io::Result<()> {
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
let time = Instant::now();
|
let time = Instant::now();
|
||||||
|
|
||||||
// Setup the TCP server socket.
|
// Setup the TCP server socket.
|
||||||
@ -173,7 +182,7 @@ async fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"Accepted connection from: {} (id: {})",
|
"Accepted connection from: {} (id: {})",
|
||||||
scrub_address(&format!("{}", address)),
|
scrub_address(&format!("{address}")),
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -188,7 +197,7 @@ async fn main() -> io::Result<()> {
|
|||||||
{
|
{
|
||||||
let open = client.poll().await;
|
let open = client.poll().await;
|
||||||
if open {
|
if open {
|
||||||
client.process_packets(&server).await
|
client.process_packets(&server).await;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if client
|
if client
|
||||||
@ -206,7 +215,7 @@ async fn main() -> io::Result<()> {
|
|||||||
{
|
{
|
||||||
let open = player.client.poll().await;
|
let open = player.client.poll().await;
|
||||||
if open {
|
if open {
|
||||||
player.process_packets(&server).await
|
player.process_packets(&server).await;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
player.remove().await;
|
player.remove().await;
|
||||||
|
|||||||
@ -13,9 +13,9 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use crate::client::{authentication::GameProfile, Client};
|
use crate::client::{authentication::GameProfile, Client};
|
||||||
|
|
||||||
/// Proxy implementation for Velocity <https://papermc.io/software/velocity> by PaperMC
|
/// Proxy implementation for Velocity <https://papermc.io/software/velocity> by `PaperMC`
|
||||||
/// Sadly PaperMC does not care about 3th Parties providing support for Velocity, There is no documentation.
|
/// Sadly `PaperMC` does not care about 3th Parties providing support for Velocity, There is no documentation.
|
||||||
/// I had to understand the Code logic by looking at PaperMC's Velocity implementation: <https://github.com/PaperMC/Paper/blob/master/patches/server/0731-Add-Velocity-IP-Forwarding-Support.patch>
|
/// I had to understand the Code logic by looking at `PaperMC`'s Velocity implementation: <https://github.com/PaperMC/Paper/blob/master/patches/server/0731-Add-Velocity-IP-Forwarding-Support.patch>
|
||||||
|
|
||||||
type HmacSha256 = Hmac<Sha256>;
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
@ -59,6 +59,7 @@ pub async fn velocity_login(client: &Client) {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn check_integrity(data: (&[u8], &[u8]), secret: &str) -> bool {
|
pub fn check_integrity(data: (&[u8], &[u8]), secret: &str) -> bool {
|
||||||
let (signature, data_without_signature) = data;
|
let (signature, data_without_signature) = data;
|
||||||
// Our fault, We can panic/expect ?
|
// Our fault, We can panic/expect ?
|
||||||
@ -80,7 +81,7 @@ fn read_game_profile(buf: &mut ByteBuffer) -> Result<GameProfile, VelocityError>
|
|||||||
.get_list(|data| {
|
.get_list(|data| {
|
||||||
let name = data.get_string()?;
|
let name = data.get_string()?;
|
||||||
let value = data.get_string()?;
|
let value = data.get_string()?;
|
||||||
let signature = data.get_option(|data| data.get_string())?;
|
let signature = data.get_option(pumpkin_protocol::bytebuf::ByteBuffer::get_string)?;
|
||||||
|
|
||||||
Ok(Property {
|
Ok(Property {
|
||||||
name,
|
name,
|
||||||
|
|||||||
@ -95,15 +95,14 @@ impl RCONClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn poll(&mut self, server: &Server, password: &str) -> Result<(), PacketError> {
|
async fn poll(&mut self, server: &Server, password: &str) -> Result<(), PacketError> {
|
||||||
let packet = match self.receive_packet().await? {
|
let Some(packet) = self.receive_packet().await? else {
|
||||||
Some(p) => p,
|
return Ok(());
|
||||||
None => return Ok(()),
|
|
||||||
};
|
};
|
||||||
let config = &ADVANCED_CONFIG.rcon;
|
let config = &ADVANCED_CONFIG.rcon;
|
||||||
match packet.get_type() {
|
match packet.get_type() {
|
||||||
ServerboundPacket::Auth => {
|
ServerboundPacket::Auth => {
|
||||||
if packet.get_body() == password {
|
if packet.get_body() == password {
|
||||||
self.send(ClientboundPacket::AuthResponse, packet.get_id(), "".into())
|
self.send(ClientboundPacket::AuthResponse, packet.get_id(), "")
|
||||||
.await?;
|
.await?;
|
||||||
if config.logging.log_logged_successfully {
|
if config.logging.log_logged_successfully {
|
||||||
log::info!("RCON ({}): Client logged in successfully", self.address);
|
log::info!("RCON ({}): Client logged in successfully", self.address);
|
||||||
@ -113,8 +112,7 @@ impl RCONClient {
|
|||||||
if config.logging.log_wrong_password {
|
if config.logging.log_wrong_password {
|
||||||
log::info!("RCON ({}): Client has tried wrong password", self.address);
|
log::info!("RCON ({}): Client has tried wrong password", self.address);
|
||||||
}
|
}
|
||||||
self.send(ClientboundPacket::AuthResponse, -1, "".into())
|
self.send(ClientboundPacket::AuthResponse, -1, "").await?;
|
||||||
.await?;
|
|
||||||
self.closed = true;
|
self.closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,7 +131,7 @@ impl RCONClient {
|
|||||||
if config.logging.log_commands {
|
if config.logging.log_commands {
|
||||||
log::info!("RCON ({}): {}", self.address, line);
|
log::info!("RCON ({}): {}", self.address, line);
|
||||||
}
|
}
|
||||||
self.send(ClientboundPacket::Output, packet.get_id(), line)
|
self.send(ClientboundPacket::Output, packet.get_id(), &line)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +154,7 @@ impl RCONClient {
|
|||||||
&mut self,
|
&mut self,
|
||||||
packet: ClientboundPacket,
|
packet: ClientboundPacket,
|
||||||
id: i32,
|
id: i32,
|
||||||
body: String,
|
body: &str,
|
||||||
) -> Result<(), PacketError> {
|
) -> Result<(), PacketError> {
|
||||||
let buf = packet.write_buf(id, body);
|
let buf = packet.write_buf(id, body);
|
||||||
self.connection
|
self.connection
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use tokio::io::AsyncReadExt;
|
|||||||
pub enum ServerboundPacket {
|
pub enum ServerboundPacket {
|
||||||
/// Typically, the first packet sent by the client, which is used to authenticate the connection with the server.
|
/// Typically, the first packet sent by the client, which is used to authenticate the connection with the server.
|
||||||
Auth = 2,
|
Auth = 2,
|
||||||
/// This packet type represents a command issued to the server by a client. This can be a ConCommand such as kill <player> or weather clear.
|
/// This packet type represents a command issued to the server by a client. This can be a `ConCommand` such as kill <player> or weather clear.
|
||||||
/// The response will vary depending on the command issued.
|
/// The response will vary depending on the command issued.
|
||||||
ExecCommand = 3,
|
ExecCommand = 3,
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ pub enum ServerboundPacket {
|
|||||||
impl ServerboundPacket {
|
impl ServerboundPacket {
|
||||||
pub const fn from_i32(n: i32) -> Self {
|
pub const fn from_i32(n: i32) -> Self {
|
||||||
match n {
|
match n {
|
||||||
3 => Self::Auth,
|
// 3 => Self::Auth,
|
||||||
2 => Self::ExecCommand,
|
2 => Self::ExecCommand,
|
||||||
_ => Self::Auth,
|
_ => Self::Auth,
|
||||||
}
|
}
|
||||||
@ -32,21 +32,21 @@ impl ServerboundPacket {
|
|||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
/// Server -> Client
|
/// Server -> Client
|
||||||
pub enum ClientboundPacket {
|
pub enum ClientboundPacket {
|
||||||
/// This packet is a notification of the connection's current auth status. When the server receives an auth request, it will respond with an empty SERVERDATA_RESPONSE_VALUE,
|
/// This packet is a notification of the connection's current auth status. When the server receives an auth request, it will respond with an empty `SERVERDATA_RESPONSE_VALUE`,
|
||||||
/// followed immediately by a SERVERDATA_AUTH_RESPONSE indicating whether authentication succeeded or failed. Note that the status code is returned in the packet id field, so when pairing the response with the original auth request, you may need to look at the packet id of the preceeding SERVERDATA_RESPONSE_VALUE.
|
/// followed immediately by a `SERVERDATA_AUTH_RESPONSE` indicating whether authentication succeeded or failed. Note that the status code is returned in the packet id field, so when pairing the response with the original auth request, you may need to look at the packet id of the preceeding `SERVERDATA_RESPONSE_VALUE`.
|
||||||
AuthResponse = 2,
|
AuthResponse = 2,
|
||||||
/// A SERVERDATA_RESPONSE packet is the response to a SERVERDATA_EXECCOMMAND request.
|
/// A `SERVERDATA_RESPONSE` packet is the response to a `SERVERDATA_EXECCOMMAND` request.
|
||||||
Output = 0,
|
Output = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientboundPacket {
|
impl ClientboundPacket {
|
||||||
pub fn write_buf(&self, id: i32, body: String) -> BytesMut {
|
pub fn write_buf(self, id: i32, body: &str) -> BytesMut {
|
||||||
// let len = outgoing.len() as u64;
|
// let len = outgoing.len() as u64;
|
||||||
let mut buf = BytesMut::new();
|
let mut buf = BytesMut::new();
|
||||||
// 10 is for 4 bytes ty, 4 bytes id, and 2 terminating nul bytes.
|
// 10 is for 4 bytes ty, 4 bytes id, and 2 terminating nul bytes.
|
||||||
buf.put_i32_le(10 + body.len() as i32);
|
buf.put_i32_le(10 + body.len() as i32);
|
||||||
buf.put_i32_le(id);
|
buf.put_i32_le(id);
|
||||||
buf.put_i32_le(*self as i32);
|
buf.put_i32_le(self as i32);
|
||||||
let bytes = body.as_bytes();
|
let bytes = body.as_bytes();
|
||||||
buf.put_slice(bytes);
|
buf.put_slice(bytes);
|
||||||
buf.put_u8(0);
|
buf.put_u8(0);
|
||||||
|
|||||||
@ -113,8 +113,8 @@ impl CachedStatus {
|
|||||||
max: config.max_players,
|
max: config.max_players,
|
||||||
online: 0,
|
online: 0,
|
||||||
sample: vec![Sample {
|
sample: vec![Sample {
|
||||||
name: "".into(),
|
name: String::new(),
|
||||||
id: "".into(),
|
id: String::new(),
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
description: config.motd.clone(),
|
description: config.motd.clone(),
|
||||||
|
|||||||
@ -56,6 +56,7 @@ pub struct Server {
|
|||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
// TODO: only create when needed
|
// TODO: only create when needed
|
||||||
|
|
||||||
@ -126,13 +127,13 @@ impl Server {
|
|||||||
P: ClientPacket,
|
P: ClientPacket,
|
||||||
{
|
{
|
||||||
for world in &self.worlds {
|
for world in &self.worlds {
|
||||||
world.broadcast_packet_all(packet).await
|
world.broadcast_packet_all(packet).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches every world for a player by name
|
/// Searches every world for a player by name
|
||||||
pub async fn get_player_by_name(&self, name: &str) -> Option<Arc<Player>> {
|
pub fn get_player_by_name(&self, name: &str) -> Option<Arc<Player>> {
|
||||||
for world in self.worlds.iter() {
|
for world in &self.worlds {
|
||||||
if let Some(player) = world.get_player_by_name(name) {
|
if let Some(player) = world.get_player_by_name(name) {
|
||||||
return Some(player);
|
return Some(player);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ pub struct Ticker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ticker {
|
impl Ticker {
|
||||||
|
#[must_use]
|
||||||
pub fn new(tps: f32) -> Self {
|
pub fn new(tps: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tick_interval: Duration::from_millis((1000.0 / tps) as u64),
|
tick_interval: Duration::from_millis((1000.0 / tps) as u64),
|
||||||
|
|||||||
@ -43,6 +43,7 @@ pub struct World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
|
#[must_use]
|
||||||
pub fn load(level: Level) -> Self {
|
pub fn load(level: Level) -> Self {
|
||||||
Self {
|
Self {
|
||||||
level: Arc::new(Mutex::new(level)),
|
level: Arc::new(Mutex::new(level)),
|
||||||
@ -174,7 +175,7 @@ impl World {
|
|||||||
},
|
},
|
||||||
PlayerAction::UpdateListed(true),
|
PlayerAction::UpdateListed(true),
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
player
|
player
|
||||||
.client
|
.client
|
||||||
@ -234,7 +235,7 @@ impl World {
|
|||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
))
|
))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
// entity meta data
|
// entity meta data
|
||||||
// set skin parts
|
// set skin parts
|
||||||
@ -243,7 +244,7 @@ impl World {
|
|||||||
entity_id.into(),
|
entity_id.into(),
|
||||||
Metadata::new(17, VarInt(0), config.skin_parts),
|
Metadata::new(17, VarInt(0), config.skin_parts),
|
||||||
);
|
);
|
||||||
self.broadcast_packet_all(&packet).await
|
self.broadcast_packet_all(&packet).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start waiting for level chunks, Sets the "Loading Terrain" screen
|
// Start waiting for level chunks, Sets the "Loading Terrain" screen
|
||||||
@ -266,12 +267,7 @@ impl World {
|
|||||||
level.mark_chunk_as_newly_watched(chunks);
|
level.mark_chunk_as_newly_watched(chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn_world_chunks(
|
fn spawn_world_chunks(&self, client: Arc<Client>, chunks: Vec<Vector2<i32>>, distance: i32) {
|
||||||
&self,
|
|
||||||
client: Arc<Client>,
|
|
||||||
chunks: Vec<Vector2<i32>>,
|
|
||||||
distance: i32,
|
|
||||||
) {
|
|
||||||
if client.closed.load(std::sync::atomic::Ordering::Relaxed) {
|
if client.closed.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
log::info!(
|
log::info!(
|
||||||
"The connection with {} has closed before world chunks were spawned",
|
"The connection with {} has closed before world chunks were spawned",
|
||||||
@ -286,7 +282,7 @@ impl World {
|
|||||||
let chunks = Arc::new(chunks);
|
let chunks = Arc::new(chunks);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let level = level.lock().await;
|
let level = level.lock().await;
|
||||||
level.fetch_chunks(&chunks, sender)
|
level.fetch_chunks(&chunks, sender);
|
||||||
});
|
});
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
@ -358,6 +354,6 @@ impl World {
|
|||||||
|
|
||||||
pub async fn remove_entity(&self, entity: &Entity) {
|
pub async fn remove_entity(&self, entity: &Entity) {
|
||||||
self.broadcast_packet_all(&CRemoveEntities::new(&[entity.entity_id.into()]))
|
self.broadcast_packet_all(&CRemoveEntities::new(&[entity.entity_id.into()]))
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ pub async fn player_join(world: &World, player: Arc<Player>) {
|
|||||||
chunk_z: chunk_pos.z.into(),
|
chunk_z: chunk_pos.z.into(),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
let view_distance = get_view_distance(&player).await as i32;
|
let view_distance = i32::from(get_view_distance(&player).await);
|
||||||
dbg!(view_distance);
|
dbg!(view_distance);
|
||||||
let old_cylindrical = Cylindrical::new(
|
let old_cylindrical = Cylindrical::new(
|
||||||
Vector2::new(watched_section.x, watched_section.z),
|
Vector2::new(watched_section.x, watched_section.z),
|
||||||
@ -57,9 +57,7 @@ pub async fn player_join(world: &World, player: Arc<Player>) {
|
|||||||
);
|
);
|
||||||
if !loading_chunks.is_empty() {
|
if !loading_chunks.is_empty() {
|
||||||
world.mark_chunks_as_watched(&loading_chunks).await;
|
world.mark_chunks_as_watched(&loading_chunks).await;
|
||||||
world
|
world.spawn_world_chunks(player.client.clone(), loading_chunks, view_distance);
|
||||||
.spawn_world_chunks(player.client.clone(), loading_chunks, view_distance)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !unloading_chunks.is_empty() {
|
if !unloading_chunks.is_empty() {
|
||||||
@ -93,7 +91,7 @@ pub async fn update_position(player: &Player) {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let view_distance = get_view_distance(player).await as i32;
|
let view_distance = i32::from(get_view_distance(player).await);
|
||||||
let old_cylindrical = Cylindrical::new(
|
let old_cylindrical = Cylindrical::new(
|
||||||
Vector2::new(current_watched.x, current_watched.z),
|
Vector2::new(current_watched.x, current_watched.z),
|
||||||
view_distance,
|
view_distance,
|
||||||
@ -119,8 +117,7 @@ pub async fn update_position(player: &Player) {
|
|||||||
entity.world.mark_chunks_as_watched(&loading_chunks).await;
|
entity.world.mark_chunks_as_watched(&loading_chunks).await;
|
||||||
entity
|
entity
|
||||||
.world
|
.world
|
||||||
.spawn_world_chunks(player.client.clone(), loading_chunks, view_distance)
|
.spawn_world_chunks(player.client.clone(), loading_chunks, view_distance);
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !unloading_chunks.is_empty() {
|
if !unloading_chunks.is_empty() {
|
||||||
@ -145,6 +142,7 @@ pub async fn update_position(player: &Player) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn chunk_section_from_pos(block_pos: &WorldPosition) -> Vector3<i32> {
|
pub const fn chunk_section_from_pos(block_pos: &WorldPosition) -> Vector3<i32> {
|
||||||
let block_pos = block_pos.0;
|
let block_pos = block_pos.0;
|
||||||
Vector3::new(
|
Vector3::new(
|
||||||
|
|||||||
@ -20,6 +20,7 @@ impl Default for Scoreboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Scoreboard {
|
impl Scoreboard {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
objectives: HashMap::new(),
|
objectives: HashMap::new(),
|
||||||
@ -87,6 +88,7 @@ pub struct ScoreboardObjective<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScoreboardObjective<'a> {
|
impl<'a> ScoreboardObjective<'a> {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
display_name: TextComponent<'a>,
|
display_name: TextComponent<'a>,
|
||||||
@ -111,6 +113,7 @@ pub struct ScoreboardScore<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScoreboardScore<'a> {
|
impl<'a> ScoreboardScore<'a> {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
entity_name: &'a str,
|
entity_name: &'a str,
|
||||||
objective_name: &'a str,
|
objective_name: &'a str,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user