Add WIP Resource Pack support
This commit is contained in:
parent
770d73f080
commit
76106ded18
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -776,6 +776,16 @@ version = "0.4.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md-5"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"digest 0.10.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
@ -1984,6 +1994,7 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"md-5",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
31
pumpkin-protocol/src/client/config/c_add_resource_pack.rs
Normal file
31
pumpkin-protocol/src/client/config/c_add_resource_pack.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use pumpkin_macros::packet;
|
||||||
|
use pumpkin_text::TextComponent;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[packet(0x09)]
|
||||||
|
pub struct CConfigAddResourcePack {
|
||||||
|
uuid: uuid::Uuid,
|
||||||
|
url: String,
|
||||||
|
hash: String,
|
||||||
|
forced: bool,
|
||||||
|
prompt_message: Option<TextComponent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CConfigAddResourcePack {
|
||||||
|
pub fn new(
|
||||||
|
uuid: uuid::Uuid,
|
||||||
|
url: String,
|
||||||
|
hash: String,
|
||||||
|
forced: bool,
|
||||||
|
prompt_message: Option<TextComponent>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
uuid,
|
||||||
|
url,
|
||||||
|
hash,
|
||||||
|
forced,
|
||||||
|
prompt_message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
mod c_add_resource_pack;
|
||||||
mod c_config_disconnect;
|
mod c_config_disconnect;
|
||||||
mod c_cookie_request;
|
mod c_cookie_request;
|
||||||
mod c_finish_config;
|
mod c_finish_config;
|
||||||
@ -5,6 +6,7 @@ mod c_known_packs;
|
|||||||
mod c_plugin_message;
|
mod c_plugin_message;
|
||||||
mod c_registry_data;
|
mod c_registry_data;
|
||||||
|
|
||||||
|
pub use c_add_resource_pack::*;
|
||||||
pub use c_config_disconnect::*;
|
pub use c_config_disconnect::*;
|
||||||
pub use c_cookie_request::*;
|
pub use c_cookie_request::*;
|
||||||
pub use c_finish_config::*;
|
pub use c_finish_config::*;
|
||||||
|
|||||||
@ -46,6 +46,6 @@ log = "0.4"
|
|||||||
mio = { version = "1.0.1", features = ["os-poll", "net"]}
|
mio = { version = "1.0.1", features = ["os-poll", "net"]}
|
||||||
crossbeam-channel = "0.5.13"
|
crossbeam-channel = "0.5.13"
|
||||||
|
|
||||||
uuid = { version = "1.10", features = ["serde"]}
|
uuid = { version = "1.10", features = ["serde", "v3"]}
|
||||||
|
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
@ -1,9 +1,9 @@
|
|||||||
use std::{collections::HashMap, net::IpAddr};
|
use std::{collections::HashMap, net::IpAddr, time::Duration};
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use pumpkin_protocol::Property;
|
use pumpkin_protocol::Property;
|
||||||
use reqwest::{StatusCode, Url};
|
use reqwest::{header::CONTENT_TYPE, StatusCode, Url};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -52,14 +52,16 @@ pub async fn authenticate(
|
|||||||
ip: &IpAddr,
|
ip: &IpAddr,
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
) -> Result<GameProfile, AuthError> {
|
) -> Result<GameProfile, AuthError> {
|
||||||
assert!(server.advanced_config.authentication.use_authentication);
|
assert!(server.advanced_config.authentication.enabled);
|
||||||
assert!(server.auth_client.is_some());
|
assert!(server.auth_client.is_some());
|
||||||
let address = if server
|
let address = if server
|
||||||
.advanced_config
|
.advanced_config
|
||||||
.authentication
|
.authentication
|
||||||
.prevent_proxy_connections
|
.prevent_proxy_connections
|
||||||
{
|
{
|
||||||
format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}&ip={ip}")
|
let test = format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}&ip={ip}");
|
||||||
|
dbg!(&test);
|
||||||
|
test
|
||||||
} else {
|
} else {
|
||||||
format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}")
|
format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}")
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
client::{
|
client::{
|
||||||
config::{CFinishConfig, CKnownPacks, CRegistryData},
|
config::{CConfigAddResourcePack, CFinishConfig, CKnownPacks, CRegistryData},
|
||||||
login::{CEncryptionRequest, CLoginSuccess, CSetCompression},
|
login::{CEncryptionRequest, CLoginSuccess, CSetCompression},
|
||||||
status::{CPingResponse, CStatusResponse},
|
status::{CPingResponse, CStatusResponse},
|
||||||
},
|
},
|
||||||
@ -14,6 +16,7 @@ use pumpkin_protocol::{
|
|||||||
ConnectionState, KnownPack, RawBytes,
|
ConnectionState, KnownPack, RawBytes,
|
||||||
};
|
};
|
||||||
use pumpkin_registry::Registry;
|
use pumpkin_registry::Registry;
|
||||||
|
use pumpkin_text::TextComponent;
|
||||||
use rsa::Pkcs1v15Encrypt;
|
use rsa::Pkcs1v15Encrypt;
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
@ -167,6 +170,23 @@ impl Client {
|
|||||||
) {
|
) {
|
||||||
self.connection_state = ConnectionState::Config;
|
self.connection_state = ConnectionState::Config;
|
||||||
server.send_brand(self);
|
server.send_brand(self);
|
||||||
|
|
||||||
|
let resource_config = &server.advanced_config.resource_pack;
|
||||||
|
if resource_config.enabled {
|
||||||
|
let prompt_message = if resource_config.prompt_message.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(TextComponent::from(resource_config.prompt_message.clone()))
|
||||||
|
};
|
||||||
|
self.send_packet(CConfigAddResourcePack::new(
|
||||||
|
uuid::Uuid::from_str(&resource_config.resource_pack_url).unwrap(),
|
||||||
|
resource_config.resource_pack_url.clone(),
|
||||||
|
resource_config.resource_pack_sha1.clone(),
|
||||||
|
resource_config.force,
|
||||||
|
prompt_message,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// known data packs
|
// known data packs
|
||||||
self.send_packet(CKnownPacks::new(&[KnownPack {
|
self.send_packet(CKnownPacks::new(&[KnownPack {
|
||||||
namespace: "minecraft",
|
namespace: "minecraft",
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::client::authentication::ProfileAction;
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Authentication {
|
pub struct Authentication {
|
||||||
/// Whether to use Mojang authentication.
|
/// Whether to use Mojang authentication.
|
||||||
pub use_authentication: bool,
|
pub enabled: bool,
|
||||||
|
|
||||||
/// Prevent proxy connections.
|
/// Prevent proxy connections.
|
||||||
pub prevent_proxy_connections: bool,
|
pub prevent_proxy_connections: bool,
|
||||||
@ -84,7 +84,7 @@ impl Default for TextureTypes {
|
|||||||
impl Default for Authentication {
|
impl Default for Authentication {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
use_authentication: true,
|
enabled: true,
|
||||||
prevent_proxy_connections: true,
|
prevent_proxy_connections: true,
|
||||||
player_profile: Default::default(),
|
player_profile: Default::default(),
|
||||||
textures: Default::default(),
|
textures: Default::default(),
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use auth_config::Authentication;
|
use auth_config::Authentication;
|
||||||
|
use resource_pack::ResourcePack;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{entity::player::GameMode, server::Difficulty};
|
use crate::{entity::player::GameMode, server::Difficulty};
|
||||||
|
|
||||||
pub mod auth_config;
|
pub mod auth_config;
|
||||||
|
pub mod resource_pack;
|
||||||
|
|
||||||
/// Current Config version of the Base Config
|
/// Current Config version of the Base Config
|
||||||
const CURRENT_BASE_VERSION: &str = "1.0.0";
|
const CURRENT_BASE_VERSION: &str = "1.0.0";
|
||||||
@ -18,6 +20,7 @@ pub struct AdvancedConfiguration {
|
|||||||
pub commands: Commands,
|
pub commands: Commands,
|
||||||
pub authentication: Authentication,
|
pub authentication: Authentication,
|
||||||
pub packet_compression: Compression,
|
pub packet_compression: Compression,
|
||||||
|
pub resource_pack: ResourcePack,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
@ -63,6 +66,7 @@ impl Default for AdvancedConfiguration {
|
|||||||
authentication: Authentication::default(),
|
authentication: Authentication::default(),
|
||||||
commands: Commands::default(),
|
commands: Commands::default(),
|
||||||
packet_compression: Compression::default(),
|
packet_compression: Compression::default(),
|
||||||
|
resource_pack: ResourcePack::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,10 +87,6 @@ pub struct BasicConfiguration {
|
|||||||
pub view_distance: u8,
|
pub view_distance: u8,
|
||||||
/// The maximum simulated view distance.
|
/// The maximum simulated view distance.
|
||||||
pub simulation_distance: u8,
|
pub simulation_distance: u8,
|
||||||
/// The path to the resource pack.
|
|
||||||
pub resource_pack: String,
|
|
||||||
/// The SHA1 hash of the resource pack.
|
|
||||||
pub resource_pack_sha1: String,
|
|
||||||
/// The default game difficulty.
|
/// The default game difficulty.
|
||||||
pub default_difficulty: Difficulty,
|
pub default_difficulty: Difficulty,
|
||||||
/// Whether the Nether dimension is enabled.
|
/// Whether the Nether dimension is enabled.
|
||||||
@ -113,8 +113,6 @@ impl Default for BasicConfiguration {
|
|||||||
max_players: 100000,
|
max_players: 100000,
|
||||||
view_distance: 10,
|
view_distance: 10,
|
||||||
simulation_distance: 10,
|
simulation_distance: 10,
|
||||||
resource_pack: "".to_string(),
|
|
||||||
resource_pack_sha1: "".to_string(),
|
|
||||||
default_difficulty: Difficulty::Normal,
|
default_difficulty: Difficulty::Normal,
|
||||||
allow_nether: true,
|
allow_nether: true,
|
||||||
hardcore: false,
|
hardcore: false,
|
||||||
@ -130,21 +128,30 @@ impl AdvancedConfiguration {
|
|||||||
pub fn load<P: AsRef<Path>>(path: P) -> AdvancedConfiguration {
|
pub fn load<P: AsRef<Path>>(path: P) -> AdvancedConfiguration {
|
||||||
if path.as_ref().exists() {
|
if path.as_ref().exists() {
|
||||||
let toml = std::fs::read_to_string(path).expect("Couldn't read configuration");
|
let toml = std::fs::read_to_string(path).expect("Couldn't read configuration");
|
||||||
toml::from_str(toml.as_str()).expect("Couldn't parse, Proberbly old config")
|
let config: AdvancedConfiguration =
|
||||||
|
toml::from_str(toml.as_str()).expect("Couldn't parse features.toml, Proberbly old config, Replacing with a new one or just delete it");
|
||||||
|
config.validate();
|
||||||
|
config
|
||||||
} else {
|
} else {
|
||||||
let config = AdvancedConfiguration::default();
|
let config = AdvancedConfiguration::default();
|
||||||
let toml = toml::to_string(&config).expect("Couldn't create toml!");
|
let toml = toml::to_string(&config).expect("Couldn't create toml!");
|
||||||
std::fs::write(path, toml).expect("Couldn't save configuration");
|
std::fs::write(path, toml).expect("Couldn't save configuration");
|
||||||
|
config.validate();
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn validate(&self) {
|
||||||
|
self.resource_pack.validate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicConfiguration {
|
impl BasicConfiguration {
|
||||||
pub fn load<P: AsRef<Path>>(path: P) -> BasicConfiguration {
|
pub fn load<P: AsRef<Path>>(path: P) -> BasicConfiguration {
|
||||||
if path.as_ref().exists() {
|
if path.as_ref().exists() {
|
||||||
let toml = std::fs::read_to_string(path).expect("Couldn't read configuration");
|
let toml = std::fs::read_to_string(path).expect("Couldn't read configuration");
|
||||||
toml::from_str(toml.as_str()).expect("Couldn't parse")
|
let config: BasicConfiguration = toml::from_str(toml.as_str()).expect("Couldn't parse configuration.toml, Proberbly old config, Replacing with a new one or just delete it");
|
||||||
|
config.validate();
|
||||||
|
config
|
||||||
} else {
|
} else {
|
||||||
let config = BasicConfiguration::default();
|
let config = BasicConfiguration::default();
|
||||||
let toml = toml::to_string(&config).expect("Couldn't create toml!");
|
let toml = toml::to_string(&config).expect("Couldn't create toml!");
|
||||||
@ -170,10 +177,5 @@ impl BasicConfiguration {
|
|||||||
"When Online Mode is enabled, Encryption must be enabled"
|
"When Online Mode is enabled, Encryption must be enabled"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
assert_eq!(
|
|
||||||
!self.resource_pack.is_empty(),
|
|
||||||
!self.resource_pack_sha1.is_empty(),
|
|
||||||
"Resource Pack path or Sha1 hash is missing"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
pumpkin/src/config/resource_pack.rs
Normal file
40
pumpkin/src/config/resource_pack.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct ResourcePack {
|
||||||
|
pub enabled: bool,
|
||||||
|
/// The path to the resource pack.
|
||||||
|
pub resource_pack_url: String,
|
||||||
|
/// The SHA1 hash (40) of the resource pack.
|
||||||
|
pub resource_pack_sha1: String,
|
||||||
|
/// Custom propmt Text component, Leave blank for none
|
||||||
|
pub prompt_message: String,
|
||||||
|
/// Will force the Player to accept the resource pack
|
||||||
|
pub force: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourcePack {
|
||||||
|
pub fn validate(&self) {
|
||||||
|
assert_eq!(
|
||||||
|
!self.resource_pack_url.is_empty(),
|
||||||
|
!self.resource_pack_sha1.is_empty(),
|
||||||
|
"Resource Pack path or Sha1 hash is missing"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
self.resource_pack_sha1.len() <= 40,
|
||||||
|
"Resource pack sha1 hash is too long (max. 40)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ResourcePack {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: false,
|
||||||
|
resource_pack_url: "".into(),
|
||||||
|
resource_pack_sha1: "".into(),
|
||||||
|
force: false,
|
||||||
|
prompt_message: "".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ use std::{
|
|||||||
io::Cursor,
|
io::Cursor,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::atomic::{AtomicI32, Ordering},
|
sync::atomic::{AtomicI32, Ordering},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
@ -77,7 +78,12 @@ impl Server {
|
|||||||
)
|
)
|
||||||
.into_boxed_slice();
|
.into_boxed_slice();
|
||||||
let auth_client = if config.0.online_mode {
|
let auth_client = if config.0.online_mode {
|
||||||
Some(reqwest::Client::new())
|
Some(
|
||||||
|
reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(5000))
|
||||||
|
.build()
|
||||||
|
.expect("Failed to to make reqwest client"),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user