Add: Bungeecord support
This commit is contained in:
parent
e725d1995e
commit
15832078af
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1,3 +1,4 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: [ Snowiiii ]
|
github: [ Snowiiii ]
|
||||||
|
custom: ["https://www.paypal.me/alexxmedvedev"]
|
||||||
@ -24,7 +24,6 @@ and customizable experience. It prioritizes performance and player enjoyment whi
|
|||||||
|
|
||||||
## What Pumpkin will not
|
## What Pumpkin will not
|
||||||
|
|
||||||
- Be a drop-in replacement for Vanilla or other servers
|
|
||||||
- Be compatible with plugins or mods for other servers
|
- Be compatible with plugins or mods for other servers
|
||||||
- Function as a framework for building a server from scratch.
|
- Function as a framework for building a server from scratch.
|
||||||
|
|
||||||
@ -68,6 +67,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi
|
|||||||
- [x] Chat
|
- [x] Chat
|
||||||
- [x] Commands
|
- [x] Commands
|
||||||
- Proxy
|
- Proxy
|
||||||
|
- [x] Bungeecord
|
||||||
- [ ] Velocity
|
- [ ] Velocity
|
||||||
|
|
||||||
Check out our [Github Project](https://github.com/users/Snowiiii/projects/12/views/3) to see current progress
|
Check out our [Github Project](https://github.com/users/Snowiiii/projects/12/views/3) to see current progress
|
||||||
@ -90,7 +90,7 @@ Consider joining our [discord](https://discord.gg/wT8XjrjKkf) to stay up-to-date
|
|||||||
|
|
||||||
## Funding
|
## Funding
|
||||||
|
|
||||||
If you want to fund me and help the project, Check out my [GitHub sponsors](https://github.com/sponsors/Snowiiii)
|
If you want to fund me and help the project, Check out my [GitHub sponsors](https://github.com/sponsors/Snowiiii) or my [PayPal](https://www.paypal.me/alexxmedvedev)
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,6 @@ and customizable experience. It prioritizes performance and player enjoyment whi
|
|||||||
|
|
||||||
## What Pumpkin will not
|
## What Pumpkin will not
|
||||||
|
|
||||||
- Be a drop-in replacement for vanilla or other servers
|
|
||||||
- Be compatible with plugins or mods for other servers
|
- Be compatible with plugins or mods for other servers
|
||||||
- Function as a framework for building a server from scratch.
|
- Function as a framework for building a server from scratch.
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,13 @@ This secret is used to ensure that player info forwarded by Velocity comes from
|
|||||||
secret=
|
secret=
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Bungeecord
|
||||||
|
`proxy.bungeecord`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
enabled=false
|
||||||
|
```
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
`authentication`
|
`authentication`
|
||||||
|
|||||||
@ -22,6 +22,6 @@ features:
|
|||||||
details: Pumpkin is written 100% in Rust, ensuring memory safety and unmatched performance.
|
details: Pumpkin is written 100% in Rust, ensuring memory safety and unmatched performance.
|
||||||
- title: Feature complete
|
- title: Feature complete
|
||||||
details: With all vanilla features supported, you will have no issues.
|
details: With all vanilla features supported, you will have no issues.
|
||||||
- title: Extensible
|
- title: Flexibility
|
||||||
details: Using Extism you can extend Pumpkin to your needs. Play your way!
|
details: Highly configurable, with the ability to disable unnecessary features.
|
||||||
---
|
---
|
||||||
|
|||||||
36
package-lock.json
generated
36
package-lock.json
generated
@ -1280,24 +1280,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/devtools-api": {
|
"node_modules/@vue/devtools-api": {
|
||||||
"version": "7.4.6",
|
"version": "7.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.5.2.tgz",
|
||||||
"integrity": "sha512-XipBV5k0/IfTr0sNBDTg7OBUCp51cYMMXyPxLXJZ4K/wmUeMqt8cVdr2ZZGOFq+si/jTyCYnNxeKoyev5DOUUA==",
|
"integrity": "sha512-VxPbAQxJrYSIkoGVvQ2oOoKW8u4CMpvRLySTxhoJA38z8bQEGy9GO33eoRY/DulJbSFRfjZFNvH+dh8B4qpesQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-kit": "^7.4.6"
|
"@vue/devtools-kit": "^7.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/devtools-kit": {
|
"node_modules/@vue/devtools-kit": {
|
||||||
"version": "7.4.6",
|
"version": "7.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.5.2.tgz",
|
||||||
"integrity": "sha512-NbYBwPWgEic1AOd9bWExz9weBzFdjiIfov0yRn4DrRfR+EQJCI9dn4I0XS7IxYGdkmUJi8mFW42LLk18WsGqew==",
|
"integrity": "sha512-0leUOE2HBfl8sHf9ePKzxqnCFskkU22tWWqd9OfeSlslAKE30/TViYvWcF4vgQmPlJnAAdHU0WfW5dYlCeOiuw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-shared": "^7.4.6",
|
"@vue/devtools-shared": "^7.5.2",
|
||||||
"birpc": "^0.2.17",
|
"birpc": "^0.2.19",
|
||||||
"hookable": "^5.5.3",
|
"hookable": "^5.5.3",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"perfect-debounce": "^1.0.0",
|
"perfect-debounce": "^1.0.0",
|
||||||
@ -1306,9 +1306,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/devtools-shared": {
|
"node_modules/@vue/devtools-shared": {
|
||||||
"version": "7.4.6",
|
"version": "7.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.5.2.tgz",
|
||||||
"integrity": "sha512-rPeSBzElnHYMB05Cc056BQiJpgocQjY8XVulgni+O9a9Gr9tNXgPteSzFFD+fT/iWMxNuUgGKs9CuW5DZewfIg==",
|
"integrity": "sha512-+zmcixnD6TAo+zwm30YuwZckhL9iIi4u+gFwbq9C8zpm3SMndTlEYZtNhAHUhOXB+bCkzyunxw80KQ/T0trF4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2101,9 +2101,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/preact": {
|
"node_modules/preact": {
|
||||||
"version": "10.24.2",
|
"version": "10.24.3",
|
||||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz",
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
|
||||||
"integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==",
|
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@ -2386,9 +2386,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.4.8",
|
"version": "5.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz",
|
||||||
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
|
"integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,16 +1,31 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_inline_default::serde_inline_default;
|
||||||
|
|
||||||
|
#[serde_inline_default]
|
||||||
#[derive(Deserialize, Serialize, Default)]
|
#[derive(Deserialize, Serialize, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct ProxyConfig {
|
pub struct ProxyConfig {
|
||||||
|
#[serde_inline_default(false)]
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub velocity: VelocityConfig,
|
pub velocity: VelocityConfig,
|
||||||
|
pub bungeecord: BungeeCordConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_inline_default]
|
||||||
|
#[derive(Deserialize, Serialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct BungeeCordConfig {
|
||||||
|
#[serde_inline_default(false)]
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde_inline_default]
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VelocityConfig {
|
pub struct VelocityConfig {
|
||||||
|
#[serde_inline_default(false)]
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
|
#[serde_inline_default("".to_string())]
|
||||||
pub secret: String,
|
pub secret: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@ use pumpkin_core::ProfileAction;
|
|||||||
use pumpkin_protocol::Property;
|
use pumpkin_protocol::Property;
|
||||||
use reqwest::{StatusCode, Url};
|
use reqwest::{StatusCode, Url};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use sha1::Digest;
|
||||||
|
use sha2::Sha256;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -119,6 +121,10 @@ pub fn is_texture_url_valid(url: Url, config: &TextureConfig) -> Result<(), Text
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offline_uuid(username: &str) -> Result<Uuid, uuid::Error> {
|
||||||
|
Uuid::from_slice(&Sha256::digest(username)[..16])
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AuthError {
|
pub enum AuthError {
|
||||||
#[error("Missing auth client")]
|
#[error("Missing auth client")]
|
||||||
|
|||||||
@ -20,7 +20,7 @@ use uuid::Uuid;
|
|||||||
use crate::{
|
use crate::{
|
||||||
client::authentication::{self, validate_textures, GameProfile},
|
client::authentication::{self, validate_textures, GameProfile},
|
||||||
entity::player::{ChatMode, Hand},
|
entity::player::{ChatMode, Hand},
|
||||||
proxy::velocity::velocity_login,
|
proxy::{bungeecord::bungeecord_login, velocity::velocity_login},
|
||||||
server::{Server, CURRENT_MC_VERSION},
|
server::{Server, CURRENT_MC_VERSION},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ impl Client {
|
|||||||
let version = handshake.protocol_version.0;
|
let version = handshake.protocol_version.0;
|
||||||
self.protocol_version
|
self.protocol_version
|
||||||
.store(version, std::sync::atomic::Ordering::Relaxed);
|
.store(version, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
*self.server_address.lock() = handshake.server_address;
|
||||||
|
|
||||||
self.connection_state.store(handshake.next_state);
|
self.connection_state.store(handshake.next_state);
|
||||||
if self.connection_state.load() != ConnectionState::Status {
|
if self.connection_state.load() != ConnectionState::Status {
|
||||||
@ -79,23 +80,32 @@ impl Client {
|
|||||||
// default game profile, when no online mode
|
// default game profile, when no online mode
|
||||||
// TODO: make offline uuid
|
// TODO: make offline uuid
|
||||||
let mut gameprofile = self.gameprofile.lock();
|
let mut gameprofile = self.gameprofile.lock();
|
||||||
*gameprofile = Some(GameProfile {
|
|
||||||
id: login_start.uuid,
|
|
||||||
name: login_start.name,
|
|
||||||
properties: vec![],
|
|
||||||
profile_actions: None,
|
|
||||||
});
|
|
||||||
let proxy = &ADVANCED_CONFIG.proxy;
|
let proxy = &ADVANCED_CONFIG.proxy;
|
||||||
if proxy.enabled {
|
if proxy.enabled {
|
||||||
if proxy.velocity.enabled {
|
if proxy.velocity.enabled {
|
||||||
velocity_login(self)
|
velocity_login(self);
|
||||||
|
} else if proxy.bungeecord.enabled {
|
||||||
|
match bungeecord_login(self, login_start.name) {
|
||||||
|
Ok((_ip, profile)) => {
|
||||||
|
// self.address.lock() = ip;
|
||||||
|
self.finish_login(&profile);
|
||||||
|
*gameprofile = Some(profile);
|
||||||
|
}
|
||||||
|
Err(error) => self.kick(&error.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
}
|
*gameprofile = Some(GameProfile {
|
||||||
|
id: login_start.uuid,
|
||||||
|
name: login_start.name,
|
||||||
|
properties: vec![],
|
||||||
|
profile_actions: None,
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: check config for encryption
|
// TODO: check config for encryption
|
||||||
let verify_token: [u8; 4] = rand::random();
|
let verify_token: [u8; 4] = rand::random();
|
||||||
self.send_packet(&server.encryption_request(&verify_token, BASIC_CONFIG.online_mode));
|
self.send_packet(&server.encryption_request(&verify_token, BASIC_CONFIG.online_mode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_encryption_response(
|
pub async fn handle_encryption_response(
|
||||||
@ -122,6 +132,14 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(profile) = gameprofile.as_ref() {
|
||||||
|
self.finish_login(profile);
|
||||||
|
} else {
|
||||||
|
self.kick("No Game profile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_login(&self, profile: &GameProfile) {
|
||||||
// enable compression
|
// enable compression
|
||||||
if ADVANCED_CONFIG.packet_compression.enabled {
|
if ADVANCED_CONFIG.packet_compression.enabled {
|
||||||
let compression = ADVANCED_CONFIG.packet_compression.compression_info.clone();
|
let compression = ADVANCED_CONFIG.packet_compression.compression_info.clone();
|
||||||
@ -129,12 +147,8 @@ impl Client {
|
|||||||
self.set_compression(Some(compression));
|
self.set_compression(Some(compression));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(profile) = gameprofile.as_ref() {
|
let packet = CLoginSuccess::new(&profile.id, &profile.name, &profile.properties, false);
|
||||||
let packet = CLoginSuccess::new(&profile.id, &profile.name, &profile.properties, false);
|
self.send_packet(&packet);
|
||||||
self.send_packet(&packet);
|
|
||||||
} else {
|
|
||||||
self.kick("game profile is none");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn autenticate(
|
async fn autenticate(
|
||||||
|
|||||||
@ -93,6 +93,8 @@ pub struct Client {
|
|||||||
pub brand: Mutex<Option<String>>,
|
pub brand: Mutex<Option<String>>,
|
||||||
/// The minecraft protocol version used by the client.
|
/// The minecraft protocol version used by the client.
|
||||||
pub protocol_version: AtomicI32,
|
pub protocol_version: AtomicI32,
|
||||||
|
/// The Address used to connect to the Server, Send in the Handshake
|
||||||
|
pub server_address: Mutex<String>,
|
||||||
/// The current connection state of the client (e.g., Handshaking, Status, Play).
|
/// The current connection state of the client (e.g., Handshaking, Status, Play).
|
||||||
pub connection_state: AtomicCell<ConnectionState>,
|
pub connection_state: AtomicCell<ConnectionState>,
|
||||||
/// Whether encryption is enabled for the connection.
|
/// Whether encryption is enabled for the connection.
|
||||||
@ -132,6 +134,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()),
|
||||||
id,
|
id,
|
||||||
address: Mutex::new(address),
|
address: Mutex::new(address),
|
||||||
connection_state: AtomicCell::new(ConnectionState::HandShake),
|
connection_state: AtomicCell::new(ConnectionState::HandShake),
|
||||||
|
|||||||
65
pumpkin/src/proxy/bungeecord.rs
Normal file
65
pumpkin/src/proxy/bungeecord.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
use pumpkin_protocol::Property;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
client::authentication::{offline_uuid, GameProfile},
|
||||||
|
Client,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum BungeeCordError {
|
||||||
|
#[error("Failed to parse Address")]
|
||||||
|
FailedParseAddress,
|
||||||
|
#[error("Failed to parse UUID")]
|
||||||
|
FailedParseUUID,
|
||||||
|
#[error("Failed to parse Properties")]
|
||||||
|
FailedParseProperties,
|
||||||
|
#[error("Failed to make offline UUID")]
|
||||||
|
FailedMakeOfflineUUID,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bungeecord_login(
|
||||||
|
client: &Client,
|
||||||
|
username: String,
|
||||||
|
) -> Result<(IpAddr, GameProfile), BungeeCordError> {
|
||||||
|
let server_address = client.server_address.lock();
|
||||||
|
let data = server_address.split('\0').take(4).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Ip of player, only given if ip_forward on bungee is true
|
||||||
|
let ip = match data.get(1) {
|
||||||
|
Some(ip) => ip
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| BungeeCordError::FailedParseAddress)?,
|
||||||
|
None => client.address.lock().ip(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Uuid of player, only given if ip_forward on bungee is true
|
||||||
|
let id = match data.get(2) {
|
||||||
|
Some(uuid) => uuid.parse().map_err(|_| BungeeCordError::FailedParseUUID)?,
|
||||||
|
None => {
|
||||||
|
offline_uuid(username.as_str()).map_err(|_| BungeeCordError::FailedMakeOfflineUUID)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read properties and get textures
|
||||||
|
// Properties of player's game profile, only given if ip_forward and online_mode
|
||||||
|
// on bungee both are true
|
||||||
|
let properties: Vec<Property> = match data.get(3) {
|
||||||
|
Some(properties) => {
|
||||||
|
serde_json::from_str(properties).map_err(|_| BungeeCordError::FailedParseProperties)?
|
||||||
|
}
|
||||||
|
None => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
ip,
|
||||||
|
GameProfile {
|
||||||
|
id,
|
||||||
|
name: username,
|
||||||
|
properties,
|
||||||
|
profile_actions: None,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
@ -1 +1,4 @@
|
|||||||
|
pub mod bungeecord;
|
||||||
pub mod velocity;
|
pub mod velocity;
|
||||||
|
|
||||||
|
// TODO: Maybe make a trait for proxies
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user