204 lines
7.8 KiB
Rust
204 lines
7.8 KiB
Rust
use std::{num::NonZeroU8, sync::Arc};
|
|
|
|
use crate::{
|
|
entity::player::ChatMode,
|
|
net::{ClientPlatform, PlayerConfig, can_not_join, java::JavaClient},
|
|
server::Server,
|
|
};
|
|
use core::str;
|
|
use pumpkin_data::{registry::Registry, tag::RegistryKey};
|
|
use pumpkin_protocol::{
|
|
ConnectionState,
|
|
java::{
|
|
client::config::{CFinishConfig, CRegistryData, CUpdateTags, RegistryEntry},
|
|
server::config::{
|
|
ResourcePackResponseResult, SClientInformationConfig, SConfigCookieResponse,
|
|
SConfigResourcePack, SKnownPacks, SPluginMessage,
|
|
},
|
|
},
|
|
};
|
|
use pumpkin_util::{Hand, text::TextComponent};
|
|
|
|
impl JavaClient {
|
|
pub async fn handle_client_information_config(
|
|
&self,
|
|
client_information: SClientInformationConfig,
|
|
) {
|
|
log::debug!("Handling client settings");
|
|
if client_information.view_distance <= 0 {
|
|
self.kick(TextComponent::text(
|
|
"Cannot have zero or negative view distance!",
|
|
))
|
|
.await;
|
|
return;
|
|
}
|
|
|
|
if let (Ok(main_hand), Ok(chat_mode)) = (
|
|
Hand::try_from(client_information.main_hand.0),
|
|
ChatMode::try_from(client_information.chat_mode.0),
|
|
) {
|
|
*self.config.lock().await = Some(PlayerConfig {
|
|
locale: client_information.locale,
|
|
// client_information.view_distance was checked above to be > 0 so compiler should optimize this out.
|
|
view_distance: NonZeroU8::new(client_information.view_distance as u8).unwrap(),
|
|
chat_mode,
|
|
chat_colors: client_information.chat_colors,
|
|
skin_parts: client_information.skin_parts,
|
|
main_hand,
|
|
text_filtering: client_information.text_filtering,
|
|
server_listing: client_information.server_listing,
|
|
});
|
|
} else {
|
|
self.kick(TextComponent::text("Invalid hand or chat type"))
|
|
.await;
|
|
}
|
|
}
|
|
|
|
pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) {
|
|
log::debug!("Handling plugin message");
|
|
if plugin_message
|
|
.channel
|
|
.to_string()
|
|
.starts_with("minecraft:brand")
|
|
{
|
|
log::debug!("Got a client brand");
|
|
match str::from_utf8(&plugin_message.data) {
|
|
Ok(brand) => *self.brand.lock().await = Some(brand.to_string()),
|
|
Err(e) => self.kick(TextComponent::text(e.to_string())).await,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn handle_resource_pack_response(
|
|
&self,
|
|
server: &Server,
|
|
packet: SConfigResourcePack,
|
|
) {
|
|
let resource_config = &server.advanced_config.resource_pack;
|
|
if resource_config.enabled {
|
|
let expected_uuid =
|
|
uuid::Uuid::new_v3(&uuid::Uuid::NAMESPACE_DNS, resource_config.url.as_bytes());
|
|
|
|
if packet.uuid == expected_uuid {
|
|
match packet.response_result() {
|
|
ResourcePackResponseResult::DownloadSuccess => {
|
|
log::trace!(
|
|
"Client {} successfully downloaded the resource pack",
|
|
self.id
|
|
);
|
|
}
|
|
ResourcePackResponseResult::DownloadFail => {
|
|
log::warn!(
|
|
"Client {} failed to downloaded the resource pack. Is it available on the internet?",
|
|
self.id
|
|
);
|
|
}
|
|
ResourcePackResponseResult::Downloaded => {
|
|
log::trace!("Client {} already has the resource pack", self.id);
|
|
}
|
|
ResourcePackResponseResult::Accepted => {
|
|
log::trace!("Client {} accepted the resource pack", self.id);
|
|
|
|
// Return here to wait for the next response update
|
|
return;
|
|
}
|
|
ResourcePackResponseResult::Declined => {
|
|
log::trace!("Client {} declined the resource pack", self.id);
|
|
}
|
|
ResourcePackResponseResult::InvalidUrl => {
|
|
log::warn!(
|
|
"Client {} reported that the resource pack URL is invalid!",
|
|
self.id
|
|
);
|
|
}
|
|
ResourcePackResponseResult::ReloadFailed => {
|
|
log::trace!("Client {} failed to reload the resource pack", self.id);
|
|
}
|
|
ResourcePackResponseResult::Discarded => {
|
|
log::trace!("Client {} discarded the resource pack", self.id);
|
|
}
|
|
ResourcePackResponseResult::Unknown(result) => {
|
|
log::warn!(
|
|
"Client {} responded with a bad result: {}!",
|
|
self.id,
|
|
result
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
log::warn!(
|
|
"Client {} returned a response for a resource pack we did not set!",
|
|
self.id
|
|
);
|
|
}
|
|
} else {
|
|
log::warn!(
|
|
"Client {} returned a response for a resource pack that was not enabled!",
|
|
self.id
|
|
);
|
|
}
|
|
self.send_known_packs().await;
|
|
}
|
|
|
|
pub fn handle_config_cookie_response(&self, packet: &SConfigCookieResponse) {
|
|
// TODO: allow plugins to access this
|
|
log::debug!(
|
|
"Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{:?}\"",
|
|
packet.key,
|
|
packet.has_payload,
|
|
packet.payload.as_ref().map(|p| p.len()),
|
|
);
|
|
}
|
|
|
|
pub async fn handle_known_packs(&self, _config_acknowledged: SKnownPacks) {
|
|
log::debug!("Handling known packs");
|
|
let mut tags_to_send = Vec::new();
|
|
let registry = Registry::get_synced(self.version.load());
|
|
for registry in registry {
|
|
let entries: Vec<RegistryEntry> = registry
|
|
.registry_entries
|
|
.iter()
|
|
.map(|r| RegistryEntry::new(r.entry_id.clone(), r.data.clone()))
|
|
.collect();
|
|
self.send_packet_now(&CRegistryData::new(®istry.registry_id, &entries))
|
|
.await;
|
|
if let Some(tag) = RegistryKey::from_string(®istry.registry_id.path)
|
|
&& pumpkin_data::tag::get_registry_key_tags(self.version.load(), tag).is_some()
|
|
{
|
|
tags_to_send.push(tag);
|
|
}
|
|
}
|
|
self.send_packet_now(&CUpdateTags::new(&tags_to_send)).await;
|
|
|
|
// We are done with configuring
|
|
log::debug!("Finished config");
|
|
self.send_packet_now(&CFinishConfig).await;
|
|
}
|
|
|
|
pub async fn handle_config_acknowledged(self: &Arc<Self>, server: &Server) {
|
|
log::debug!("Handling config acknowledgement");
|
|
self.connection_state.store(ConnectionState::Play);
|
|
|
|
let profile = self.gameprofile.lock().await.clone();
|
|
let profile = profile.unwrap();
|
|
let address = self.address.lock().await;
|
|
|
|
if let Some(reason) = can_not_join(&profile, &address, server).await {
|
|
self.kick(reason).await;
|
|
return;
|
|
}
|
|
|
|
let config = self.config.lock().await;
|
|
|
|
if let Some((player, world)) = server
|
|
.add_player(ClientPlatform::Java(self.clone()), profile, config.clone())
|
|
.await
|
|
{
|
|
world
|
|
.spawn_java_player(&server.basic_config, player.clone(), server)
|
|
.await;
|
|
*self.player.lock().await = Some(player);
|
|
}
|
|
}
|
|
}
|