diff --git a/README.md b/README.md index 6fc2f8a9e..c1f080518 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Pumpkin is currently under heavy development. - [ ] World Borders - [ ] World Saving - Player + - [x] Player Skin - [x] Player Client brand - [x] Player Teleport - [ ] Player Movement diff --git a/pumpkin-protocol/src/bytebuf/mod.rs b/pumpkin-protocol/src/bytebuf/mod.rs index 2b38bc7f0..e4a65a1a4 100644 --- a/pumpkin-protocol/src/bytebuf/mod.rs +++ b/pumpkin-protocol/src/bytebuf/mod.rs @@ -112,6 +112,7 @@ impl ByteBuffer { } pub fn put_uuid(&mut self, v: uuid::Uuid) { + // thats the vanilla way let pair = v.as_u64_pair(); self.put_u64(pair.0); self.put_u64(pair.1); diff --git a/pumpkin-protocol/src/client/login/mod.rs b/pumpkin-protocol/src/client/login/mod.rs index e000c7c90..7e7342ba6 100644 --- a/pumpkin-protocol/src/client/login/mod.rs +++ b/pumpkin-protocol/src/client/login/mod.rs @@ -1,6 +1,4 @@ -use serde::Deserialize; - -use crate::{bytebuf::ByteBuffer, ClientPacket, VarInt}; +use crate::{bytebuf::ByteBuffer, ClientPacket, Property, VarInt}; pub struct CLoginDisconnect<'a> { reason: &'a str, @@ -83,15 +81,6 @@ impl<'a> CLoginSuccess<'a> { } } -#[derive(Deserialize, Clone, Debug)] -pub struct Property { - pub name: String, - // base 64 - pub value: String, - // base 64 - pub signature: Option, -} - impl<'a> ClientPacket for CLoginSuccess<'a> { const PACKET_ID: VarInt = 0x02; @@ -102,6 +91,7 @@ impl<'a> ClientPacket for CLoginSuccess<'a> { p.put_string(&v.name); p.put_string(&v.value); // has signature ? + // todo: for some reason we get "got too many bytes error when using a signature" p.put_bool(false); // p.put_option(&v.signature, |p,v| p.put_string(v)); }); diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 2b1f544c0..f78aa1ca9 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -1,4 +1,4 @@ -use crate::{bytebuf::ByteBuffer, text::Text, BitSet, ClientPacket, VarInt}; +use crate::{bytebuf::ByteBuffer, text::Text, BitSet, ClientPacket, Property, VarInt}; pub struct SetHeldItem { slot: i8, @@ -18,6 +18,65 @@ impl ClientPacket for SetHeldItem { } } +pub struct CPlayerInfoUpdate<'a> { + actions: i8, + players: &'a [Player<'a>], +} + +pub struct Player<'a> { + pub uuid: uuid::Uuid, + pub actions: &'a [PlayerAction], +} + +pub enum PlayerAction { + AddPlayer { + name: String, + properties: Vec, + }, + InitializeChat(u8), + UpdateGameMode(u8), + UpdateListed(u8), + UpdateLatency(u8), + UpdateDisplayName(u8), +} + +impl<'a> CPlayerInfoUpdate<'a> { + pub fn new(actions: i8, players: &'a [Player]) -> Self { + Self { actions, players } + } +} + +impl<'a> ClientPacket for CPlayerInfoUpdate<'a> { + const PACKET_ID: VarInt = 0x3E; + + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_i8(self.actions); + bytebuf.put_list::(self.players, |p, v| { + p.put_uuid(v.uuid); + for action in v.actions { + match action { + PlayerAction::AddPlayer { name, properties } => { + p.put_string(name); + p.put_list::(properties, |p, v| { + p.put_string(&v.name); + p.put_string(&v.value); + // has signature ? + // todo: for some reason we get "got too many bytes error when using a signature" + p.put_bool(false); + // todo signature + }); + } + PlayerAction::InitializeChat(_) => todo!(), + PlayerAction::UpdateGameMode(_) => todo!(), + PlayerAction::UpdateListed(_) => todo!(), + PlayerAction::UpdateLatency(_) => todo!(), + PlayerAction::UpdateDisplayName(_) => todo!(), + } + } + }); + } +} + pub struct CPlayerAbilities { flags: i8, flying_speed: f32, diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index 2cf603f7a..5b88e1a5d 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -2,7 +2,7 @@ use std::io::{self, Write}; use bytebuf::ByteBuffer; use bytes::Buf; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use thiserror::Error; pub mod bytebuf; @@ -183,6 +183,16 @@ pub struct Sample { pub id: String, // uuid } +// basicly game profile +#[derive(Deserialize, Clone, Debug)] +pub struct Property { + pub name: String, + // base 64 + pub value: String, + // base 64 + pub signature: Option, +} + pub struct KnownPack<'a> { pub namespace: &'a str, pub id: &'a str, diff --git a/pumpkin/src/client/authentication.rs b/pumpkin/src/client/authentication.rs index edf7e3807..b8f57c0fc 100644 --- a/pumpkin/src/client/authentication.rs +++ b/pumpkin/src/client/authentication.rs @@ -1,7 +1,7 @@ -use std::{net::IpAddr}; +use std::net::IpAddr; use num_bigint::BigInt; -use pumpkin_protocol::client::login::Property; +use pumpkin_protocol::Property; use reqwest::StatusCode; use serde::Deserialize; use thiserror::Error; diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 34b1b6ffe..0424784f0 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -8,7 +8,7 @@ use mio::{event::Event, Poll}; use pumpkin_protocol::{ client::{ config::CPluginMessage, - play::{CChunkDataUpdateLight, CGameEvent, CLogin}, + play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction}, }, BitSet, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version, }; @@ -129,6 +129,19 @@ impl Server { .unwrap_or_else(|e| client.kick(&e.to_string())); // teleport client.teleport(10.0, 500.0, 10.0, 10.0, 10.0); + let gameprofile = client.gameprofile.as_ref().unwrap(); + client + .send_packet(CPlayerInfoUpdate::new( + 0x01, + &[pumpkin_protocol::client::play::Player { + uuid: gameprofile.id, + actions: &[PlayerAction::AddPlayer { + name: gameprofile.name.clone(), + properties: gameprofile.properties.clone(), + }], + }], + )) + .unwrap_or_else(|e| client.kick(&e.to_string())); // Start waiting for level chunks client