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]]
|
||||
name = "pumpkin"
|
||||
version = "0.1.0"
|
||||
version = "0.1.0-dev"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"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 {
|
||||
slot: i8,
|
||||
@ -106,11 +106,11 @@ impl ClientPacket for CPlayerAbilities {
|
||||
}
|
||||
|
||||
pub struct CPlayDisconnect {
|
||||
reason: Text,
|
||||
reason: TextComponent,
|
||||
}
|
||||
|
||||
impl CPlayDisconnect {
|
||||
pub fn new(reason: Text) -> Self {
|
||||
pub fn new(reason: TextComponent) -> Self {
|
||||
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 {
|
||||
difficulty: u8,
|
||||
locked: bool,
|
||||
|
||||
@ -13,6 +13,8 @@ pub mod text;
|
||||
pub mod packet_decoder;
|
||||
pub mod packet_encoder;
|
||||
|
||||
pub const CURRENT_MC_PROTOCOL: u32 = 767;
|
||||
|
||||
pub const MAX_PACKET_SIZE: i32 = 2097152;
|
||||
|
||||
/// 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 x: f64,
|
||||
pub feet_y: f64,
|
||||
|
||||
@ -6,12 +6,59 @@ use serde::{Deserialize, Serialize};
|
||||
// represents a text component
|
||||
// Reference: https://wiki.vg/Text_formatting#Text_components
|
||||
#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Text {
|
||||
pub struct TextComponent {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl Text {
|
||||
impl TextComponent {
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
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]
|
||||
name = "pumpkin"
|
||||
version = "0.1.0"
|
||||
version = "0.1.0-dev"
|
||||
description = "Empowering everyone to host fast and efficient Minecraft servers."
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@ -17,7 +17,7 @@ use pumpkin_protocol::{
|
||||
client::{
|
||||
config::CConfigDisconnect,
|
||||
login::CLoginDisconnect,
|
||||
play::{CPlayDisconnect, CSyncPlayerPostion},
|
||||
play::{CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge},
|
||||
},
|
||||
packet_decoder::PacketDecoder,
|
||||
packet_encoder::PacketEncoder,
|
||||
@ -25,10 +25,13 @@ use pumpkin_protocol::{
|
||||
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks, SPluginMessage},
|
||||
handshake::SHandShake,
|
||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
||||
play::{SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation},
|
||||
play::{
|
||||
SChatCommand, SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation,
|
||||
SPlayerRotation,
|
||||
},
|
||||
status::{SPingRequest, SStatusRequest},
|
||||
},
|
||||
text::Text,
|
||||
text::TextComponent,
|
||||
ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket,
|
||||
};
|
||||
|
||||
@ -224,6 +227,9 @@ impl Client {
|
||||
SConfirmTeleport::PACKET_ID => {
|
||||
self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf))
|
||||
}
|
||||
SChatCommand::PACKET_ID => {
|
||||
self.handle_chat_command(server, SChatCommand::read(bytebuf))
|
||||
}
|
||||
SPlayerPosition::PACKET_ID => {
|
||||
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
|
||||
pub fn kick(&mut self, reason: &str) {
|
||||
dbg!(reason);
|
||||
@ -297,7 +308,7 @@ impl Client {
|
||||
.unwrap_or_else(|_| self.close());
|
||||
}
|
||||
ConnectionState::Play => {
|
||||
self.send_packet(CPlayDisconnect::new(Text {
|
||||
self.send_packet(CPlayDisconnect::new(TextComponent {
|
||||
text: reason.to_string(),
|
||||
}))
|
||||
.unwrap_or_else(|_| self.close());
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
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;
|
||||
|
||||
@ -10,6 +13,8 @@ use super::Client;
|
||||
pub trait PlayerPacketProcessor {
|
||||
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_rotation(
|
||||
@ -78,4 +83,8 @@ impl PlayerPacketProcessor for Client {
|
||||
player.yaw = rotation.yaw;
|
||||
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";
|
||||
|
||||
#[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 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 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
liquid_physics: true,
|
||||
use_skins: true,
|
||||
enable_chat: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ use server::Server;
|
||||
const SERVER: Token = Token(0);
|
||||
|
||||
pub mod client;
|
||||
pub mod commands;
|
||||
pub mod configuration;
|
||||
pub mod entity;
|
||||
pub mod server;
|
||||
|
||||
@ -14,6 +14,7 @@ use pumpkin_protocol::{
|
||||
play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction},
|
||||
},
|
||||
BitSet, ClientPacket, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version,
|
||||
CURRENT_MC_PROTOCOL,
|
||||
};
|
||||
use pumpkin_world::chunk::TestChunk;
|
||||
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 compression_threshold: Option<u8>,
|
||||
|
||||
@ -174,7 +177,7 @@ impl Server {
|
||||
}
|
||||
|
||||
/// 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
|
||||
P: ClientPacket,
|
||||
P: Clone,
|
||||
@ -234,8 +237,8 @@ impl Server {
|
||||
|
||||
StatusResponse {
|
||||
version: Version {
|
||||
name: "1.21".into(),
|
||||
protocol: 767,
|
||||
name: CURRENT_MC_VERSION.into(),
|
||||
protocol: CURRENT_MC_PROTOCOL,
|
||||
},
|
||||
players: Players {
|
||||
max: config.max_players,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user