Add Commands
This commit is contained in:
parent
5714c1b786
commit
c54ab006ae
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1141,7 +1141,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pumpkin"
|
name = "pumpkin"
|
||||||
version = "0.1.0"
|
version = "0.1.0-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
|||||||
7
pumpkin-command/src/lib.rs
Normal file
7
pumpkin-command/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
pub trait Command<'a> {
|
||||||
|
const NAME: &'a str;
|
||||||
|
const ALIEASES: [&'a str];
|
||||||
|
const DESCRIPTION: &'a str;
|
||||||
|
|
||||||
|
fn on_execute(client: &mut Cli);
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::{bytebuf::ByteBuffer, text::Text, BitSet, ClientPacket, Property, VarInt};
|
use crate::{bytebuf::ByteBuffer, text::TextComponent, BitSet, ClientPacket, Property, VarInt};
|
||||||
|
|
||||||
pub struct SetHeldItem {
|
pub struct SetHeldItem {
|
||||||
slot: i8,
|
slot: i8,
|
||||||
@ -106,11 +106,11 @@ impl ClientPacket for CPlayerAbilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CPlayDisconnect {
|
pub struct CPlayDisconnect {
|
||||||
reason: Text,
|
reason: TextComponent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CPlayDisconnect {
|
impl CPlayDisconnect {
|
||||||
pub fn new(reason: Text) -> Self {
|
pub fn new(reason: TextComponent) -> Self {
|
||||||
Self { reason }
|
Self { reason }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,6 +123,26 @@ impl ClientPacket for CPlayDisconnect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CSystemChatMessge {
|
||||||
|
content: TextComponent,
|
||||||
|
overlay: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSystemChatMessge {
|
||||||
|
pub fn new(content: TextComponent, overlay: bool) -> Self {
|
||||||
|
Self { content, overlay }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientPacket for CSystemChatMessge {
|
||||||
|
const PACKET_ID: VarInt = 0x6C;
|
||||||
|
|
||||||
|
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||||
|
bytebuf.put_slice(&self.content.encode());
|
||||||
|
bytebuf.put_bool(self.overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CChangeDifficulty {
|
pub struct CChangeDifficulty {
|
||||||
difficulty: u8,
|
difficulty: u8,
|
||||||
locked: bool,
|
locked: bool,
|
||||||
|
|||||||
@ -13,6 +13,8 @@ pub mod text;
|
|||||||
pub mod packet_decoder;
|
pub mod packet_decoder;
|
||||||
pub mod packet_encoder;
|
pub mod packet_encoder;
|
||||||
|
|
||||||
|
pub const CURRENT_MC_PROTOCOL: u32 = 767;
|
||||||
|
|
||||||
pub const MAX_PACKET_SIZE: i32 = 2097152;
|
pub const MAX_PACKET_SIZE: i32 = 2097152;
|
||||||
|
|
||||||
/// usally uses a namespace like "minecraft:thing"
|
/// usally uses a namespace like "minecraft:thing"
|
||||||
|
|||||||
@ -14,6 +14,20 @@ impl ServerPacket for SConfirmTeleport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SChatCommand {
|
||||||
|
pub command: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerPacket for SChatCommand {
|
||||||
|
const PACKET_ID: VarInt = 0x04;
|
||||||
|
|
||||||
|
fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self {
|
||||||
|
Self {
|
||||||
|
command: bytebuf.get_string().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SPlayerPosition {
|
pub struct SPlayerPosition {
|
||||||
pub x: f64,
|
pub x: f64,
|
||||||
pub feet_y: f64,
|
pub feet_y: f64,
|
||||||
|
|||||||
@ -6,12 +6,59 @@ use serde::{Deserialize, Serialize};
|
|||||||
// represents a text component
|
// represents a text component
|
||||||
// Reference: https://wiki.vg/Text_formatting#Text_components
|
// Reference: https://wiki.vg/Text_formatting#Text_components
|
||||||
#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
|
||||||
pub struct Text {
|
pub struct TextComponent {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Text {
|
impl TextComponent {
|
||||||
pub fn encode(&self) -> Vec<u8> {
|
pub fn encode(&self) -> Vec<u8> {
|
||||||
fastnbt::to_bytes_with_opts(&self, SerOpts::network_nbt()).unwrap()
|
fastnbt::to_bytes_with_opts(&self, SerOpts::network_nbt()).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for TextComponent {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self { text: value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for TextComponent {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
text: value.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Text color
|
||||||
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
|
pub enum Color {
|
||||||
|
/// The default color for the text will be used, which varies by context
|
||||||
|
/// (in some cases, it's white; in others, it's black; in still others, it
|
||||||
|
/// is a shade of gray that isn't normally used on text).
|
||||||
|
#[default]
|
||||||
|
Reset,
|
||||||
|
/// One of the 16 named Minecraft colors
|
||||||
|
Named(NamedColor),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Named Minecraft color
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub enum NamedColor {
|
||||||
|
Black = 0,
|
||||||
|
DarkBlue,
|
||||||
|
DarkGreen,
|
||||||
|
DarkCyan,
|
||||||
|
DarkRed,
|
||||||
|
Purple,
|
||||||
|
Gold,
|
||||||
|
Gray,
|
||||||
|
DarkGray,
|
||||||
|
Blue,
|
||||||
|
BrightGreen,
|
||||||
|
Cyan,
|
||||||
|
Red,
|
||||||
|
Pink,
|
||||||
|
Yellow,
|
||||||
|
White,
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pumpkin"
|
name = "pumpkin"
|
||||||
version = "0.1.0"
|
version = "0.1.0-dev"
|
||||||
|
description = "Empowering everyone to host fast and efficient Minecraft servers."
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -17,7 +17,7 @@ use pumpkin_protocol::{
|
|||||||
client::{
|
client::{
|
||||||
config::CConfigDisconnect,
|
config::CConfigDisconnect,
|
||||||
login::CLoginDisconnect,
|
login::CLoginDisconnect,
|
||||||
play::{CPlayDisconnect, CSyncPlayerPostion},
|
play::{CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge},
|
||||||
},
|
},
|
||||||
packet_decoder::PacketDecoder,
|
packet_decoder::PacketDecoder,
|
||||||
packet_encoder::PacketEncoder,
|
packet_encoder::PacketEncoder,
|
||||||
@ -25,10 +25,13 @@ use pumpkin_protocol::{
|
|||||||
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks, SPluginMessage},
|
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks, SPluginMessage},
|
||||||
handshake::SHandShake,
|
handshake::SHandShake,
|
||||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
||||||
play::{SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation},
|
play::{
|
||||||
|
SChatCommand, SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation,
|
||||||
|
SPlayerRotation,
|
||||||
|
},
|
||||||
status::{SPingRequest, SStatusRequest},
|
status::{SPingRequest, SStatusRequest},
|
||||||
},
|
},
|
||||||
text::Text,
|
text::TextComponent,
|
||||||
ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket,
|
ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -224,6 +227,9 @@ impl Client {
|
|||||||
SConfirmTeleport::PACKET_ID => {
|
SConfirmTeleport::PACKET_ID => {
|
||||||
self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf))
|
self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf))
|
||||||
}
|
}
|
||||||
|
SChatCommand::PACKET_ID => {
|
||||||
|
self.handle_chat_command(server, SChatCommand::read(bytebuf))
|
||||||
|
}
|
||||||
SPlayerPosition::PACKET_ID => {
|
SPlayerPosition::PACKET_ID => {
|
||||||
self.handle_position(server, SPlayerPosition::read(bytebuf))
|
self.handle_position(server, SPlayerPosition::read(bytebuf))
|
||||||
}
|
}
|
||||||
@ -284,6 +290,11 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_message(&mut self, text: TextComponent) {
|
||||||
|
self.send_packet(CSystemChatMessge::new(text, false))
|
||||||
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
/// Kicks the Client with a reason depending on the connection state
|
/// Kicks the Client with a reason depending on the connection state
|
||||||
pub fn kick(&mut self, reason: &str) {
|
pub fn kick(&mut self, reason: &str) {
|
||||||
dbg!(reason);
|
dbg!(reason);
|
||||||
@ -297,7 +308,7 @@ impl Client {
|
|||||||
.unwrap_or_else(|_| self.close());
|
.unwrap_or_else(|_| self.close());
|
||||||
}
|
}
|
||||||
ConnectionState::Play => {
|
ConnectionState::Play => {
|
||||||
self.send_packet(CPlayDisconnect::new(Text {
|
self.send_packet(CPlayDisconnect::new(TextComponent {
|
||||||
text: reason.to_string(),
|
text: reason.to_string(),
|
||||||
}))
|
}))
|
||||||
.unwrap_or_else(|_| self.close());
|
.unwrap_or_else(|_| self.close());
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
use pumpkin_protocol::server::play::{
|
use pumpkin_protocol::server::play::{
|
||||||
SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation,
|
SChatCommand, SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::server::Server;
|
use crate::{
|
||||||
|
commands::{handle_command, CommandSender},
|
||||||
|
server::Server,
|
||||||
|
};
|
||||||
|
|
||||||
use super::Client;
|
use super::Client;
|
||||||
|
|
||||||
@ -10,6 +13,8 @@ use super::Client;
|
|||||||
pub trait PlayerPacketProcessor {
|
pub trait PlayerPacketProcessor {
|
||||||
fn handle_confirm_teleport(&mut self, server: &mut Server, confirm_teleport: SConfirmTeleport);
|
fn handle_confirm_teleport(&mut self, server: &mut Server, confirm_teleport: SConfirmTeleport);
|
||||||
|
|
||||||
|
fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand);
|
||||||
|
|
||||||
fn handle_position(&mut self, server: &mut Server, position: SPlayerPosition);
|
fn handle_position(&mut self, server: &mut Server, position: SPlayerPosition);
|
||||||
|
|
||||||
fn handle_position_rotation(
|
fn handle_position_rotation(
|
||||||
@ -78,4 +83,8 @@ impl PlayerPacketProcessor for Client {
|
|||||||
player.yaw = rotation.yaw;
|
player.yaw = rotation.yaw;
|
||||||
player.pitch = rotation.pitch;
|
player.pitch = rotation.pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) {
|
||||||
|
handle_command(&mut CommandSender::Player(self), command.command, server);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
pumpkin/src/commands/mod.rs
Normal file
38
pumpkin/src/commands/mod.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use pumpkin::PumpkinCommand;
|
||||||
|
use pumpkin_protocol::text::TextComponent;
|
||||||
|
|
||||||
|
use crate::{client::Client, server::Server};
|
||||||
|
|
||||||
|
mod pumpkin;
|
||||||
|
|
||||||
|
/// I think it would be great to split this up into a seperate crate, But idk how i should do that, Because we have to rely on Client and Server
|
||||||
|
pub trait Command<'a> {
|
||||||
|
// Name of the Plugin, Use lower case
|
||||||
|
const NAME: &'a str;
|
||||||
|
const DESCRIPTION: &'a str;
|
||||||
|
|
||||||
|
fn on_execute(sender: &mut CommandSender<'a>, command: String, server: &mut Server);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum CommandSender<'a> {
|
||||||
|
Console,
|
||||||
|
Player(&'a mut Client),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CommandSender<'a> {
|
||||||
|
pub fn send_message(&mut self, text: TextComponent) {
|
||||||
|
match self {
|
||||||
|
// todo: add color and stuff to console
|
||||||
|
CommandSender::Console => log::info!("{}", text.text),
|
||||||
|
CommandSender::Player(c) => c.send_message(text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn handle_command(sender: &mut CommandSender, command: String, server: &mut Server) {
|
||||||
|
let command = command.to_lowercase();
|
||||||
|
dbg!("handling command");
|
||||||
|
dbg!(&command);
|
||||||
|
if command.starts_with(PumpkinCommand::NAME) {
|
||||||
|
PumpkinCommand::on_execute(sender, command, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
29
pumpkin/src/commands/pumpkin.rs
Normal file
29
pumpkin/src/commands/pumpkin.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use pumpkin_protocol::{text::TextComponent, CURRENT_MC_PROTOCOL};
|
||||||
|
|
||||||
|
use crate::server::CURRENT_MC_VERSION;
|
||||||
|
|
||||||
|
use super::Command;
|
||||||
|
|
||||||
|
pub struct PumpkinCommand {}
|
||||||
|
|
||||||
|
impl PumpkinCommand {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Command<'a> for PumpkinCommand {
|
||||||
|
const NAME: &'a str = "pumpkin";
|
||||||
|
|
||||||
|
const DESCRIPTION: &'a str = "Displays information about Pumpkin";
|
||||||
|
|
||||||
|
fn on_execute(
|
||||||
|
sender: &mut super::CommandSender<'a>,
|
||||||
|
_command: String,
|
||||||
|
_server: &mut crate::server::Server,
|
||||||
|
) {
|
||||||
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
|
let description = env!("CARGO_PKG_DESCRIPTION");
|
||||||
|
sender.send_message(TextComponent::from(format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})")))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,14 +8,23 @@ use crate::{entity::player::GameMode, server::Difficulty};
|
|||||||
const CURRENT_BASE_VERSION: &str = "1.0.0";
|
const CURRENT_BASE_VERSION: &str = "1.0.0";
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
/// The idea is that Pumpkin should very customizable, You can Enable or Disable Features depning on your needs.
|
||||||
|
/// This also allows you get some Performance or Resource boosts.
|
||||||
|
/// Important: The Configuration should match Vanilla by default
|
||||||
pub struct AdvancedConfiguration {
|
pub struct AdvancedConfiguration {
|
||||||
pub liquid_physics: bool,
|
/// Requires Online mode
|
||||||
|
/// Should player have skins
|
||||||
|
use_skins: bool,
|
||||||
|
/// Should chat be enabled
|
||||||
|
enable_chat: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Important: The Configuration should match Vanilla by default
|
||||||
impl Default for AdvancedConfiguration {
|
impl Default for AdvancedConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
liquid_physics: true,
|
use_skins: true,
|
||||||
|
enable_chat: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use server::Server;
|
|||||||
const SERVER: Token = Token(0);
|
const SERVER: Token = Token(0);
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
pub mod commands;
|
||||||
pub mod configuration;
|
pub mod configuration;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use pumpkin_protocol::{
|
|||||||
play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction},
|
play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction},
|
||||||
},
|
},
|
||||||
BitSet, ClientPacket, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version,
|
BitSet, ClientPacket, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version,
|
||||||
|
CURRENT_MC_PROTOCOL,
|
||||||
};
|
};
|
||||||
use pumpkin_world::chunk::TestChunk;
|
use pumpkin_world::chunk::TestChunk;
|
||||||
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
||||||
@ -28,6 +29,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const CURRENT_MC_VERSION: &str = "1.21";
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
pub compression_threshold: Option<u8>,
|
pub compression_threshold: Option<u8>,
|
||||||
|
|
||||||
@ -174,7 +177,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a Packet to all Players
|
/// Sends a Packet to all Players
|
||||||
fn broadcast_packet<P>(&mut self, packet: P) -> Result<(), PacketError>
|
fn _broadcast_packet<P>(&mut self, packet: P) -> Result<(), PacketError>
|
||||||
where
|
where
|
||||||
P: ClientPacket,
|
P: ClientPacket,
|
||||||
P: Clone,
|
P: Clone,
|
||||||
@ -234,8 +237,8 @@ impl Server {
|
|||||||
|
|
||||||
StatusResponse {
|
StatusResponse {
|
||||||
version: Version {
|
version: Version {
|
||||||
name: "1.21".into(),
|
name: CURRENT_MC_VERSION.into(),
|
||||||
protocol: 767,
|
protocol: CURRENT_MC_PROTOCOL,
|
||||||
},
|
},
|
||||||
players: Players {
|
players: Players {
|
||||||
max: config.max_players,
|
max: config.max_players,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user