Add Serverbound Player Command
This commit is contained in:
parent
81f82a41b7
commit
d1c3b2f10c
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -888,6 +888,17 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
@ -1151,6 +1162,8 @@ dependencies = [
|
||||
"log",
|
||||
"mio",
|
||||
"num-bigint",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-protocol",
|
||||
"pumpkin-registry",
|
||||
"pumpkin-world",
|
||||
@ -1185,6 +1198,8 @@ dependencies = [
|
||||
"cfb8",
|
||||
"fastnbt 2.5.0 (git+https://github.com/owengage/fastnbt.git)",
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-macros",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@ -17,6 +17,8 @@ serde_json = "1.0"
|
||||
|
||||
thiserror = "1.0.63"
|
||||
log = "0.4"
|
||||
num-traits = "0.2"
|
||||
num-derive = "0.4"
|
||||
|
||||
# for text component
|
||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::{ServerPacket, VarInt};
|
||||
|
||||
pub struct SConfirmTeleport {
|
||||
@ -48,6 +51,35 @@ impl ServerPacket for SPlayerPosition {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SPlayerCommand {
|
||||
pub entitiy_id: VarInt,
|
||||
pub action: Action,
|
||||
pub jump_boost: VarInt,
|
||||
}
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum Action {
|
||||
StartSneaking = 0,
|
||||
StopSneaking,
|
||||
LeaveBed,
|
||||
StartSprinting,
|
||||
StopSprinting,
|
||||
StartHourseJump,
|
||||
OpenVehicleInventory,
|
||||
StartFlyingElytra,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerCommand {
|
||||
const PACKET_ID: VarInt = 0x25;
|
||||
|
||||
fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self {
|
||||
Self {
|
||||
entitiy_id: bytebuf.get_var_int(),
|
||||
action: Action::from_i32(bytebuf.get_var_int()).unwrap(),
|
||||
jump_boost: bytebuf.get_var_int(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SPlayerPositionRotation {
|
||||
pub x: f64,
|
||||
pub feet_y: f64,
|
||||
|
||||
@ -16,6 +16,8 @@ toml = "0.8.19"
|
||||
|
||||
rand = "0.8.5"
|
||||
|
||||
num-traits = "0.2"
|
||||
num-derive = "0.4"
|
||||
num-bigint = "0.4.6"
|
||||
|
||||
# encryption
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use num_traits::FromPrimitive;
|
||||
use pumpkin_protocol::{
|
||||
client::{
|
||||
config::{CFinishConfig, CKnownPacks, CRegistryData},
|
||||
@ -140,10 +141,10 @@ impl Client {
|
||||
self.config = Some(PlayerConfig {
|
||||
locale: client_information.locale,
|
||||
view_distance: client_information.view_distance,
|
||||
chat_mode: ChatMode::from(client_information.chat_mode),
|
||||
chat_mode: ChatMode::from_i32(client_information.chat_mode).unwrap(),
|
||||
chat_colors: client_information.chat_colors,
|
||||
skin_parts: client_information.skin_parts,
|
||||
main_hand: Hand::from(client_information.main_hand),
|
||||
main_hand: Hand::from_i32(client_information.main_hand).unwrap(),
|
||||
text_filtering: client_information.text_filtering,
|
||||
server_listing: client_information.server_listing,
|
||||
});
|
||||
|
||||
@ -12,6 +12,7 @@ use crate::{
|
||||
|
||||
use authentication::GameProfile;
|
||||
use mio::{event::Event, net::TcpStream, Token};
|
||||
use num_traits::ToPrimitive;
|
||||
use pumpkin_protocol::{
|
||||
client::{
|
||||
config::CConfigDisconnect,
|
||||
@ -25,8 +26,8 @@ use pumpkin_protocol::{
|
||||
handshake::SHandShake,
|
||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
||||
play::{
|
||||
SChatCommand, SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation,
|
||||
SPlayerRotation,
|
||||
SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition,
|
||||
SPlayerPositionRotation, SPlayerRotation,
|
||||
},
|
||||
status::{SPingRequest, SStatusRequest},
|
||||
},
|
||||
@ -139,7 +140,7 @@ impl Client {
|
||||
}
|
||||
|
||||
pub fn set_gamemode(&mut self, gamemode: GameMode) {
|
||||
self.send_packet(CGameEvent::new(3, gamemode.to_byte() as f32))
|
||||
self.send_packet(CGameEvent::new(3, gamemode.to_f32().unwrap()))
|
||||
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||
}
|
||||
|
||||
@ -241,6 +242,9 @@ impl Client {
|
||||
SPlayerRotation::PACKET_ID => {
|
||||
self.handle_rotation(server, SPlayerRotation::read(bytebuf))
|
||||
}
|
||||
SPlayerCommand::PACKET_ID => {
|
||||
self.handle_player_command(server, SPlayerCommand::read(bytebuf))
|
||||
}
|
||||
_ => log::error!("Failed to handle player packet id {}", packet.id),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use pumpkin_protocol::server::play::{
|
||||
SChatCommand, SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation,
|
||||
SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation,
|
||||
SPlayerRotation,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -72,4 +73,23 @@ impl Client {
|
||||
pub fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) {
|
||||
handle_command(&mut CommandSender::Player(self), command.command, server);
|
||||
}
|
||||
|
||||
pub fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) {
|
||||
let player = self.player.as_mut().unwrap();
|
||||
|
||||
if command.entitiy_id != player.entity.entity_id {
|
||||
return;
|
||||
}
|
||||
|
||||
match command.action {
|
||||
pumpkin_protocol::server::play::Action::StartSneaking => player.sneaking = true,
|
||||
pumpkin_protocol::server::play::Action::StopSneaking => player.sneaking = false,
|
||||
pumpkin_protocol::server::play::Action::LeaveBed => todo!(),
|
||||
pumpkin_protocol::server::play::Action::StartSprinting => player.sprinting = true,
|
||||
pumpkin_protocol::server::play::Action::StopSprinting => player.sprinting = false,
|
||||
pumpkin_protocol::server::play::Action::StartHourseJump => todo!(),
|
||||
pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(),
|
||||
pumpkin_protocol::server::play::Action::StartFlyingElytra => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,9 +14,23 @@ const CURRENT_BASE_VERSION: &str = "1.0.0";
|
||||
pub struct AdvancedConfiguration {
|
||||
/// Requires Online mode
|
||||
/// Should player have skins
|
||||
use_skins: bool,
|
||||
pub use_skins: bool,
|
||||
/// Should chat be enabled
|
||||
enable_chat: bool,
|
||||
pub enable_chat: bool,
|
||||
|
||||
pub commands: Commands,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Commands {
|
||||
// Are commands from the Console accepted ?
|
||||
pub use_console: bool,
|
||||
}
|
||||
|
||||
impl Default for Commands {
|
||||
fn default() -> Self {
|
||||
Self { use_console: true }
|
||||
}
|
||||
}
|
||||
|
||||
/// Important: The Configuration should match Vanilla by default
|
||||
@ -25,6 +39,7 @@ impl Default for AdvancedConfiguration {
|
||||
Self {
|
||||
use_skins: true,
|
||||
enable_chat: true,
|
||||
commands: Commands::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,7 +82,6 @@ pub struct BasicConfiguration {
|
||||
pub default_gamemode: GameMode,
|
||||
}
|
||||
|
||||
|
||||
impl Default for BasicConfiguration {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
@ -96,7 +110,7 @@ impl AdvancedConfiguration {
|
||||
pub fn load<P: AsRef<Path>>(path: P) -> AdvancedConfiguration {
|
||||
if path.as_ref().exists() {
|
||||
let toml = std::fs::read_to_string(path).expect("Couldn't read configuration");
|
||||
toml::from_str(toml.as_str()).expect("Couldn't parse")
|
||||
toml::from_str(toml.as_str()).expect("Couldn't parse, Proberbly old config")
|
||||
} else {
|
||||
let config = AdvancedConfiguration::default();
|
||||
let toml = toml::to_string(&config).expect("Couldn't create toml!");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use pumpkin_protocol::VarInt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -16,6 +17,9 @@ pub struct Player {
|
||||
// Client side value, Should be not trusted
|
||||
pub on_ground: bool,
|
||||
|
||||
pub sneaking: bool,
|
||||
pub sprinting: bool,
|
||||
|
||||
// Current awaiting teleport id, None if did not teleport
|
||||
pub awaiting_teleport: Option<VarInt>,
|
||||
}
|
||||
@ -31,6 +35,8 @@ impl Player {
|
||||
pitch: 0.0,
|
||||
on_ground: false,
|
||||
awaiting_teleport: None,
|
||||
sneaking: false,
|
||||
sprinting: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,47 +45,22 @@ impl Player {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum Hand {
|
||||
Main,
|
||||
Off,
|
||||
}
|
||||
|
||||
impl From<VarInt> for Hand {
|
||||
fn from(value: VarInt) -> Self {
|
||||
match value {
|
||||
0 => Self::Off,
|
||||
1 => Self::Main,
|
||||
_ => {
|
||||
log::info!("Unexpected Hand {}", value);
|
||||
Self::Main
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum ChatMode {
|
||||
Enabled,
|
||||
CommandsOnly,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
impl From<VarInt> for ChatMode {
|
||||
fn from(value: VarInt) -> Self {
|
||||
match value {
|
||||
0 => Self::Enabled,
|
||||
1 => Self::CommandsOnly,
|
||||
2 => Self::Hidden,
|
||||
_ => {
|
||||
log::info!("Unexpected ChatMode {}", value);
|
||||
Self::Enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize, FromPrimitive, ToPrimitive)]
|
||||
pub enum GameMode {
|
||||
Undefined,
|
||||
Undefined = -1,
|
||||
Survival,
|
||||
Creative,
|
||||
Adventure,
|
||||
@ -102,31 +83,3 @@ impl FromStr for GameMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i8> for GameMode {
|
||||
fn from(value: i8) -> Self {
|
||||
match value {
|
||||
-1 => GameMode::Undefined,
|
||||
0 => GameMode::Survival,
|
||||
1 => GameMode::Creative,
|
||||
2 => GameMode::Adventure,
|
||||
3 => GameMode::Spectator,
|
||||
_ => {
|
||||
log::info!("Unexpected GameMode {}", value);
|
||||
Self::Survival
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GameMode {
|
||||
pub fn to_byte(self) -> i8 {
|
||||
match self {
|
||||
Self::Undefined => -1,
|
||||
Self::Survival => 0,
|
||||
Self::Creative => 1,
|
||||
Self::Adventure => 2,
|
||||
Self::Spectator => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,9 @@ pub mod util;
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
fn main() -> io::Result<()> {
|
||||
use std::time::Instant;
|
||||
|
||||
let time = Instant::now();
|
||||
let basic_config = BasicConfiguration::load("configuration.toml");
|
||||
|
||||
let advanced_configuration = AdvancedConfiguration::load("features.toml");
|
||||
@ -58,16 +61,19 @@ fn main() -> io::Result<()> {
|
||||
// Unique token for each incoming connection.
|
||||
let mut unique_token = Token(SERVER.0 + 1);
|
||||
|
||||
let mut connections: HashMap<Token, Client> = HashMap::new();
|
||||
let use_console = advanced_configuration.commands.use_console;
|
||||
|
||||
log::info!("You now can connect to the server");
|
||||
let mut connections: HashMap<Token, Client> = HashMap::new();
|
||||
|
||||
let server = Arc::new(Mutex::new(Server::new((
|
||||
basic_config,
|
||||
advanced_configuration,
|
||||
))));
|
||||
let server_clone = server.clone();
|
||||
log::info!("Started Server took {}ms", time.elapsed().as_millis());
|
||||
log::info!("You now can connect to the server");
|
||||
|
||||
if use_console {
|
||||
let server_clone = server.clone();
|
||||
thread::spawn(move || {
|
||||
let stdin = std::io::stdin();
|
||||
loop {
|
||||
@ -82,7 +88,7 @@ fn main() -> io::Result<()> {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
loop {
|
||||
if let Err(err) = poll.poll(&mut events, None) {
|
||||
if interrupted(&err) {
|
||||
|
||||
@ -7,6 +7,7 @@ use std::{
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use mio::{event::Event, Poll, Token};
|
||||
use num_traits::ToPrimitive;
|
||||
use pumpkin_protocol::{
|
||||
client::{
|
||||
config::CPluginMessage,
|
||||
@ -62,7 +63,6 @@ impl Server {
|
||||
let status_response = Self::build_response(&config.0);
|
||||
let status_response_json = serde_json::to_string(&status_response)
|
||||
.expect("Failed to parse Status response into JSON");
|
||||
|
||||
let cached_server_brand = Self::build_brand();
|
||||
|
||||
// todo, only create when needed
|
||||
@ -137,8 +137,9 @@ impl Server {
|
||||
GameMode::Undefined => GameMode::Survival,
|
||||
game_mode => game_mode,
|
||||
}
|
||||
.to_byte() as u8,
|
||||
self.base_config.default_gamemode.to_byte(),
|
||||
.to_u8()
|
||||
.unwrap(),
|
||||
self.base_config.default_gamemode.to_i8().unwrap(),
|
||||
false,
|
||||
false,
|
||||
false, // deth loc
|
||||
|
||||
Loading…
Reference in New Issue
Block a user