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
|
||||
|
||||
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
|
||||
|
||||
- Be a drop-in replacement for Vanilla or other servers
|
||||
- Be compatible with plugins or mods for other servers
|
||||
- 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] Commands
|
||||
- Proxy
|
||||
- [x] Bungeecord
|
||||
- [ ] Velocity
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ and customizable experience. It prioritizes performance and player enjoyment whi
|
||||
|
||||
## What Pumpkin will not
|
||||
|
||||
- Be a drop-in replacement for vanilla or other servers
|
||||
- Be compatible with plugins or mods for other servers
|
||||
- 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=
|
||||
```
|
||||
|
||||
### Bungeecord
|
||||
`proxy.bungeecord`
|
||||
|
||||
```toml
|
||||
enabled=false
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
`authentication`
|
||||
|
||||
@ -22,6 +22,6 @@ features:
|
||||
details: Pumpkin is written 100% in Rust, ensuring memory safety and unmatched performance.
|
||||
- title: Feature complete
|
||||
details: With all vanilla features supported, you will have no issues.
|
||||
- title: Extensible
|
||||
details: Using Extism you can extend Pumpkin to your needs. Play your way!
|
||||
- title: Flexibility
|
||||
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": {
|
||||
"version": "7.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.4.6.tgz",
|
||||
"integrity": "sha512-XipBV5k0/IfTr0sNBDTg7OBUCp51cYMMXyPxLXJZ4K/wmUeMqt8cVdr2ZZGOFq+si/jTyCYnNxeKoyev5DOUUA==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.5.2.tgz",
|
||||
"integrity": "sha512-VxPbAQxJrYSIkoGVvQ2oOoKW8u4CMpvRLySTxhoJA38z8bQEGy9GO33eoRY/DulJbSFRfjZFNvH+dh8B4qpesQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-kit": "^7.4.6"
|
||||
"@vue/devtools-kit": "^7.5.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-kit": {
|
||||
"version": "7.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.4.6.tgz",
|
||||
"integrity": "sha512-NbYBwPWgEic1AOd9bWExz9weBzFdjiIfov0yRn4DrRfR+EQJCI9dn4I0XS7IxYGdkmUJi8mFW42LLk18WsGqew==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.5.2.tgz",
|
||||
"integrity": "sha512-0leUOE2HBfl8sHf9ePKzxqnCFskkU22tWWqd9OfeSlslAKE30/TViYvWcF4vgQmPlJnAAdHU0WfW5dYlCeOiuw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-shared": "^7.4.6",
|
||||
"birpc": "^0.2.17",
|
||||
"@vue/devtools-shared": "^7.5.2",
|
||||
"birpc": "^0.2.19",
|
||||
"hookable": "^5.5.3",
|
||||
"mitt": "^3.0.1",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
@ -1306,9 +1306,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-shared": {
|
||||
"version": "7.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.4.6.tgz",
|
||||
"integrity": "sha512-rPeSBzElnHYMB05Cc056BQiJpgocQjY8XVulgni+O9a9Gr9tNXgPteSzFFD+fT/iWMxNuUgGKs9CuW5DZewfIg==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.5.2.tgz",
|
||||
"integrity": "sha512-+zmcixnD6TAo+zwm30YuwZckhL9iIi4u+gFwbq9C8zpm3SMndTlEYZtNhAHUhOXB+bCkzyunxw80KQ/T0trF4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -2101,9 +2101,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.24.2",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz",
|
||||
"integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==",
|
||||
"version": "10.24.3",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
|
||||
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@ -2386,9 +2386,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.8",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
|
||||
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
|
||||
"version": "5.4.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz",
|
||||
"integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,16 +1,31 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_inline_default::serde_inline_default;
|
||||
|
||||
#[serde_inline_default]
|
||||
#[derive(Deserialize, Serialize, Default)]
|
||||
#[serde(default)]
|
||||
pub struct ProxyConfig {
|
||||
#[serde_inline_default(false)]
|
||||
pub enabled: bool,
|
||||
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)]
|
||||
#[serde(default)]
|
||||
pub struct VelocityConfig {
|
||||
#[serde_inline_default(false)]
|
||||
pub enabled: bool,
|
||||
#[serde_inline_default("".to_string())]
|
||||
pub secret: String,
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ use pumpkin_core::ProfileAction;
|
||||
use pumpkin_protocol::Property;
|
||||
use reqwest::{StatusCode, Url};
|
||||
use serde::Deserialize;
|
||||
use sha1::Digest;
|
||||
use sha2::Sha256;
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -119,6 +121,10 @@ pub fn is_texture_url_valid(url: Url, config: &TextureConfig) -> Result<(), Text
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn offline_uuid(username: &str) -> Result<Uuid, uuid::Error> {
|
||||
Uuid::from_slice(&Sha256::digest(username)[..16])
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AuthError {
|
||||
#[error("Missing auth client")]
|
||||
|
||||
@ -20,7 +20,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
client::authentication::{self, validate_textures, GameProfile},
|
||||
entity::player::{ChatMode, Hand},
|
||||
proxy::velocity::velocity_login,
|
||||
proxy::{bungeecord::bungeecord_login, velocity::velocity_login},
|
||||
server::{Server, CURRENT_MC_VERSION},
|
||||
};
|
||||
|
||||
@ -36,6 +36,7 @@ impl Client {
|
||||
let version = handshake.protocol_version.0;
|
||||
self.protocol_version
|
||||
.store(version, std::sync::atomic::Ordering::Relaxed);
|
||||
*self.server_address.lock() = handshake.server_address;
|
||||
|
||||
self.connection_state.store(handshake.next_state);
|
||||
if self.connection_state.load() != ConnectionState::Status {
|
||||
@ -79,24 +80,33 @@ impl Client {
|
||||
// default game profile, when no online mode
|
||||
// TODO: make offline uuid
|
||||
let mut gameprofile = self.gameprofile.lock();
|
||||
let proxy = &ADVANCED_CONFIG.proxy;
|
||||
if proxy.enabled {
|
||||
if proxy.velocity.enabled {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*gameprofile = Some(GameProfile {
|
||||
id: login_start.uuid,
|
||||
name: login_start.name,
|
||||
properties: vec![],
|
||||
profile_actions: None,
|
||||
});
|
||||
let proxy = &ADVANCED_CONFIG.proxy;
|
||||
if proxy.enabled {
|
||||
if proxy.velocity.enabled {
|
||||
velocity_login(self)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: check config for encryption
|
||||
let verify_token: [u8; 4] = rand::random();
|
||||
self.send_packet(&server.encryption_request(&verify_token, BASIC_CONFIG.online_mode));
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_encryption_response(
|
||||
&self,
|
||||
@ -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
|
||||
if ADVANCED_CONFIG.packet_compression.enabled {
|
||||
let compression = ADVANCED_CONFIG.packet_compression.compression_info.clone();
|
||||
@ -129,12 +147,8 @@ impl Client {
|
||||
self.set_compression(Some(compression));
|
||||
}
|
||||
|
||||
if let Some(profile) = gameprofile.as_ref() {
|
||||
let packet = CLoginSuccess::new(&profile.id, &profile.name, &profile.properties, false);
|
||||
self.send_packet(&packet);
|
||||
} else {
|
||||
self.kick("game profile is none");
|
||||
}
|
||||
}
|
||||
|
||||
async fn autenticate(
|
||||
|
||||
@ -93,6 +93,8 @@ pub struct Client {
|
||||
pub brand: Mutex<Option<String>>,
|
||||
/// The minecraft protocol version used by the client.
|
||||
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).
|
||||
pub connection_state: AtomicCell<ConnectionState>,
|
||||
/// Whether encryption is enabled for the connection.
|
||||
@ -132,6 +134,7 @@ impl Client {
|
||||
gameprofile: Mutex::new(None),
|
||||
config: Mutex::new(None),
|
||||
brand: Mutex::new(None),
|
||||
server_address: Mutex::new("".to_string()),
|
||||
id,
|
||||
address: Mutex::new(address),
|
||||
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;
|
||||
|
||||
// TODO: Maybe make a trait for proxies
|
||||
|
||||
Loading…
Reference in New Issue
Block a user