refactored
This commit is contained in:
parent
a3375c53a4
commit
278e28ad18
5 changed files with 321 additions and 227 deletions
|
@ -43,8 +43,8 @@ impl NetworkClient {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn send_packet(&mut self, packet: ClientBoundPacket) -> std::io::Result<()> {
|
||||
self.stream.write_all(&packet.encode())?;
|
||||
pub fn send_packet(&mut self, packet: impl ClientBoundPacket) -> std::io::Result<()> {
|
||||
self.stream.write_all(&encode_packet(packet))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ impl <'lua> NetworkServer<'lua> {
|
|||
let mut closed = Vec::new();
|
||||
for client in self.clients.iter_mut() {
|
||||
if client.player.is_some() {
|
||||
let result = client.send_packet(ClientBoundPacket::KeepAlive(0));
|
||||
let result = client.send_packet(KeepAlive { data: 0 });
|
||||
if result.is_err() {
|
||||
client.close();
|
||||
self.plugins.player_leave(client.player.as_ref().unwrap());
|
||||
|
@ -114,7 +114,7 @@ impl <'lua> NetworkServer<'lua> {
|
|||
for client in self.clients.iter_mut() {
|
||||
if let Some(p) = &client.player {
|
||||
if p.name == player || p.uuid.to_string() == player {
|
||||
client.send_packet(ClientBoundPacket::SystemChatMessage(message, false))?;
|
||||
client.send_packet(SystemChatMessage { message, overlay: false })?;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ impl <'lua> NetworkServer<'lua> {
|
|||
Response::Broadcast { message } => {
|
||||
for client in self.clients.iter_mut() {
|
||||
if client.player.is_some() {
|
||||
client.send_packet(ClientBoundPacket::SystemChatMessage(message.clone(), false))?;
|
||||
client.send_packet(SystemChatMessage { message: message.clone(), overlay: false })?;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -131,7 +131,7 @@ impl <'lua> NetworkServer<'lua> {
|
|||
for client in self.clients.iter_mut() {
|
||||
if let Some(pl) = &client.player {
|
||||
if pl.name == player || pl.uuid.to_string() == player {
|
||||
client.send_packet(ClientBoundPacket::Disconnect(reason.clone()))?;
|
||||
client.send_packet(Disconnect { reason: reason.clone() })?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,88 +147,21 @@ impl <'lua> NetworkServer<'lua> {
|
|||
ServerBoundPacket::Unknown(id) => warn!("Unknown packet: {}", id),
|
||||
ServerBoundPacket::Handshake(_) => (),
|
||||
ServerBoundPacket::StatusRequest()
|
||||
=> client.send_packet(ClientBoundPacket::StatusResponse(
|
||||
r#"{"version":{"name":"1.19.3","protocol":761}}"#.to_owned()
|
||||
))?,
|
||||
=> client.send_packet(StatusResponse {
|
||||
data: r#"{"version":{"name":"1.19.3","protocol":761}}"#.to_owned()
|
||||
})?,
|
||||
ServerBoundPacket::PingRequest(n) => {
|
||||
client.send_packet(ClientBoundPacket::PingResponse(n))?;
|
||||
client.send_packet(PingResponse { data: n })?;
|
||||
client.close();
|
||||
}
|
||||
ServerBoundPacket::LoginStart(login_start) => {
|
||||
if self.clients.iter().filter_map(|x| x.player.as_ref()).any(|x| x.uuid == login_start.uuid) {
|
||||
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({
|
||||
"translate": "multiplayer.disconnect.duplicate_login"
|
||||
})))?;
|
||||
client.close();
|
||||
return Ok(())
|
||||
}
|
||||
client.player = Some(Player {
|
||||
name: login_start.name.clone(),
|
||||
uuid: login_start.uuid,
|
||||
});
|
||||
match self.config.login {
|
||||
LoginMode::Offline => {
|
||||
client.verified = true;
|
||||
client.send_packet(ClientBoundPacket::LoginPluginRequest{
|
||||
id: -1,
|
||||
channel: "qc:init".to_owned(),
|
||||
data: Vec::new()
|
||||
})?;
|
||||
},
|
||||
LoginMode::Velocity => {
|
||||
client.send_packet(ClientBoundPacket::LoginPluginRequest{
|
||||
id: 10,
|
||||
channel: "velocity:player_info".to_owned(),
|
||||
data: vec![1],
|
||||
})?
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finalize login
|
||||
ServerBoundPacket::LoginPluginResponse { id: -1, .. } => {
|
||||
if !client.verified {
|
||||
client.send_packet(ClientBoundPacket::Disconnect(json!({
|
||||
"text": "Failed to verify your connection",
|
||||
"color": "red",
|
||||
})))?;
|
||||
client.close();
|
||||
}
|
||||
client.send_packet(ClientBoundPacket::LoginSuccess(LoginSuccess {
|
||||
name: client.player.as_ref().unwrap().name.to_owned(),
|
||||
uuid: client.player.as_ref().unwrap().uuid,
|
||||
}))?;
|
||||
self.plugins.player_join(client.player.as_ref().unwrap());
|
||||
self.post_login(client)?;
|
||||
}
|
||||
// Velocity login
|
||||
ServerBoundPacket::LoginPluginResponse { id: 10, data } => {
|
||||
let Some(data) = data else {
|
||||
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({
|
||||
"text": "This server can only be connected to via a Velocity proxy",
|
||||
"color": "red"
|
||||
})))?;
|
||||
client.close();
|
||||
return Ok(());
|
||||
};
|
||||
let (sig, data) = data.split_at(32);
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(self.config.velocity_secret.clone().unwrap().as_bytes())?;
|
||||
mac.update(data);
|
||||
if let Err(_) = mac.verify_slice(sig) {
|
||||
client.send_packet(ClientBoundPacket::Disconnect(json!({
|
||||
"text": "Could not verify secret. Ensure that the secrets configured for Velocity and Quectocraft match."
|
||||
})))?;
|
||||
client.close();
|
||||
return Ok(())
|
||||
}
|
||||
client.verified = true;
|
||||
client.send_packet(ClientBoundPacket::LoginPluginRequest{
|
||||
id: -1,
|
||||
channel: "qc:init".to_owned(),
|
||||
data: Vec::new()
|
||||
})?;
|
||||
}
|
||||
ServerBoundPacket::LoginStart(login_start)
|
||||
=> self.start_login(client, login_start)?,
|
||||
ServerBoundPacket::LoginPluginResponse(LoginPluginResponse { id: 10, data })
|
||||
=> self.velocity_login(client, data)?,
|
||||
ServerBoundPacket::LoginPluginResponse(LoginPluginResponse{ id: -1, .. })
|
||||
=> self.login(client)?,
|
||||
ServerBoundPacket::LoginPluginResponse { .. } => {
|
||||
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({"text": "bad plugin response"})))?;
|
||||
client.send_packet(LoginDisconnect { reason: json!({"text": "bad plugin response"}) })?;
|
||||
client.close();
|
||||
}
|
||||
ServerBoundPacket::ChatMessage(msg) => {
|
||||
|
@ -238,10 +171,10 @@ impl <'lua> NetworkServer<'lua> {
|
|||
let mut parts = msg.message.splitn(1, " ");
|
||||
if let Some(cmd) = parts.next() {
|
||||
if cmd == "qc" {
|
||||
client.send_packet(ClientBoundPacket::SystemChatMessage(json!({
|
||||
client.send_packet(SystemChatMessage { message: json!({
|
||||
"text": format!("QuectoCraft version {}", VERSION),
|
||||
"color": "green"
|
||||
}), false))?;
|
||||
}), overlay: false })?;
|
||||
} else {
|
||||
let args = parts.next().unwrap_or_default();
|
||||
self.plugins.command(client.player.as_ref().unwrap(), cmd, args);
|
||||
|
@ -252,12 +185,85 @@ impl <'lua> NetworkServer<'lua> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn post_login(&mut self, client: &mut NetworkClient) -> std::io::Result<()> {
|
||||
client.send_packet(ClientBoundPacket::LoginPlay(LoginPlay {
|
||||
fn start_login(&mut self, client: &mut NetworkClient, login_start: LoginStart) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if self.clients.iter().filter_map(|x| x.player.as_ref()).any(|x| x.uuid == login_start.uuid) {
|
||||
client.send_packet(LoginDisconnect { reason: json!({
|
||||
"translate": "multiplayer.disconnect.duplicate_login"
|
||||
})})?;
|
||||
client.close();
|
||||
return Ok(())
|
||||
}
|
||||
client.player = Some(Player {
|
||||
name: login_start.name.clone(),
|
||||
uuid: login_start.uuid,
|
||||
});
|
||||
match self.config.login {
|
||||
LoginMode::Offline => {
|
||||
client.verified = true;
|
||||
client.send_packet(LoginPluginRequest{
|
||||
id: -1,
|
||||
channel: "qc:init".to_owned(),
|
||||
data: Vec::new()
|
||||
})?;
|
||||
},
|
||||
LoginMode::Velocity => {
|
||||
client.send_packet(LoginPluginRequest{
|
||||
id: 10,
|
||||
channel: "velocity:player_info".to_owned(),
|
||||
data: vec![1],
|
||||
})?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn velocity_login(&mut self, client: &mut NetworkClient, data: Option<Vec<u8>>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let Some(data) = data else {
|
||||
client.send_packet(LoginDisconnect { reason: json!({
|
||||
"text": "This server can only be connected to via a Velocity proxy",
|
||||
"color": "red"
|
||||
})})?;
|
||||
client.close();
|
||||
return Ok(());
|
||||
};
|
||||
let (sig, data) = data.split_at(32);
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(self.config.velocity_secret.clone().unwrap().as_bytes())?;
|
||||
mac.update(data);
|
||||
if let Err(_) = mac.verify_slice(sig) {
|
||||
client.send_packet(Disconnect { reason: json!({
|
||||
"text": "Could not verify secret. Ensure that the secrets configured for Velocity and Quectocraft match."
|
||||
})})?;
|
||||
client.close();
|
||||
return Ok(())
|
||||
}
|
||||
client.verified = true;
|
||||
client.send_packet(LoginPluginRequest{
|
||||
id: -1,
|
||||
channel: "qc:init".to_owned(),
|
||||
data: Vec::new()
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn login(&mut self, client: &mut NetworkClient) -> std::io::Result<()> {
|
||||
if !client.verified {
|
||||
client.send_packet(Disconnect { reason: json!({
|
||||
"text": "Failed to verify your connection",
|
||||
"color": "red",
|
||||
})})?;
|
||||
client.close();
|
||||
return Ok(())
|
||||
}
|
||||
client.send_packet(LoginSuccess {
|
||||
name: client.player.as_ref().unwrap().name.to_owned(),
|
||||
uuid: client.player.as_ref().unwrap().uuid,
|
||||
})?;
|
||||
self.plugins.player_join(client.player.as_ref().unwrap());
|
||||
client.send_packet(LoginPlay {
|
||||
eid: client.id,
|
||||
is_hardcore: false,
|
||||
gamemode: 1,
|
||||
prev_gamemode: 1,
|
||||
gamemode: 3,
|
||||
prev_gamemode: 3,
|
||||
dimensions: vec![
|
||||
"qc:world".to_owned(),
|
||||
],
|
||||
|
@ -273,16 +279,16 @@ impl <'lua> NetworkServer<'lua> {
|
|||
is_debug: false,
|
||||
is_flat: false,
|
||||
death_location: None,
|
||||
}))?;
|
||||
client.send_packet(ClientBoundPacket::PluginMessage(PluginMessage {
|
||||
})?;
|
||||
client.send_packet(PluginMessage {
|
||||
channel: "minecraft:brand".to_owned(),
|
||||
data: {
|
||||
let mut data = Vec::new();
|
||||
data.write_string(32767, &format!("Quectocraft {}", VERSION));
|
||||
data
|
||||
}
|
||||
}))?;
|
||||
client.send_packet(ClientBoundPacket::Commands(self.commands.clone()))?;
|
||||
})?;
|
||||
client.send_packet(self.commands.clone())?;
|
||||
let mut chunk_data: Vec<u8> = Vec::new();
|
||||
for _ in 0..(384 / 16) {
|
||||
// number of non-air blocks
|
||||
|
@ -299,16 +305,16 @@ impl <'lua> NetworkServer<'lua> {
|
|||
let hmdata = vec![0i64; 37];
|
||||
let mut heightmap = nbt::Blob::new();
|
||||
heightmap.insert("MOTION_BLOCKING", hmdata).unwrap();
|
||||
client.send_packet(ClientBoundPacket::ChunkData(ChunkData {
|
||||
client.send_packet(ChunkData {
|
||||
x: 0,
|
||||
z: 0,
|
||||
heightmap,
|
||||
chunk_data,
|
||||
}))?;
|
||||
client.send_packet(ClientBoundPacket::SetDefaultSpawnPosition(
|
||||
Position { x: 0, y: 0, z: 0 }, 0.0
|
||||
))?;
|
||||
client.send_packet(ClientBoundPacket::SyncPlayerPosition(SyncPlayerPosition {
|
||||
})?;
|
||||
client.send_packet(SetDefaultSpawnPosition {
|
||||
pos: Position { x: 0, y: 0, z: 0 }, angle: 0.0
|
||||
})?;
|
||||
client.send_packet(SyncPlayerPosition {
|
||||
x: 0.0,
|
||||
y: 64.0,
|
||||
z: 0.0,
|
||||
|
@ -317,7 +323,7 @@ impl <'lua> NetworkServer<'lua> {
|
|||
flags: 0,
|
||||
teleport_id: 0,
|
||||
dismount: false
|
||||
}))?;
|
||||
})?;
|
||||
// TODO why doesn't this work with quilt?
|
||||
// client.send_packet(ClientBoundPacket::PlayerAbilities(0x0f, 0.05, 0.1))?;
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,50 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use super::{data::{PacketEncoder, finalize_packet}, Position, command::Commands};
|
||||
use super::{data::{PacketEncoder, finalize_packet}, Position};
|
||||
|
||||
pub trait ClientBoundPacket: std::fmt::Debug {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder);
|
||||
fn packet_id(&self) -> i32;
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// //
|
||||
// Status //
|
||||
// //
|
||||
//////////////////
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PingResponse {
|
||||
pub data: i64
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for PingResponse {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_long(self.data)
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x01 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StatusResponse {
|
||||
pub data: String
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for StatusResponse {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_string(32767, &self.data)
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x00 }
|
||||
}
|
||||
|
||||
|
||||
/////////////////
|
||||
// //
|
||||
// Login //
|
||||
// //
|
||||
/////////////////
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginSuccess {
|
||||
|
@ -8,14 +52,52 @@ pub struct LoginSuccess {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
impl LoginSuccess {
|
||||
pub fn encode(self, encoder: &mut impl PacketEncoder) {
|
||||
impl ClientBoundPacket for LoginSuccess {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_uuid(self.uuid);
|
||||
encoder.write_string(16, &self.name);
|
||||
encoder.write_varint(0);
|
||||
}
|
||||
fn packet_id(&self) -> i32 { 0x02 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginPluginRequest {
|
||||
pub id: i32,
|
||||
pub channel: String,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for LoginPluginRequest {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_varint(self.id);
|
||||
encoder.write_string(32767, &self.channel);
|
||||
encoder.write_bytes(&self.data);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x04 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginDisconnect {
|
||||
pub reason: serde_json::Value
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for LoginDisconnect {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_string(262144, &self.reason.to_string())
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x00 }
|
||||
}
|
||||
|
||||
|
||||
////////////////
|
||||
// //
|
||||
// Play //
|
||||
// //
|
||||
////////////////
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginPlay {
|
||||
pub eid: i32,
|
||||
|
@ -37,14 +119,14 @@ pub struct LoginPlay {
|
|||
pub death_location: Option<(String, Position)>
|
||||
}
|
||||
|
||||
impl LoginPlay {
|
||||
pub fn encode(self, encoder: &mut impl PacketEncoder) {
|
||||
impl ClientBoundPacket for LoginPlay {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_int(self.eid);
|
||||
encoder.write_bool(self.is_hardcore);
|
||||
encoder.write_ubyte(self.gamemode);
|
||||
encoder.write_ubyte(self.prev_gamemode);
|
||||
encoder.write_varint(self.dimensions.len() as i32);
|
||||
for dim in self.dimensions {
|
||||
for dim in &self.dimensions {
|
||||
encoder.write_string(32767, &dim);
|
||||
}
|
||||
encoder.write_bytes(&self.registry_codec);
|
||||
|
@ -59,11 +141,13 @@ impl LoginPlay {
|
|||
encoder.write_bool(self.is_debug);
|
||||
encoder.write_bool(self.is_flat);
|
||||
encoder.write_bool(self.death_location.is_some());
|
||||
if let Some(dl) = self.death_location {
|
||||
if let Some(dl) = &self.death_location {
|
||||
encoder.write_string(32767, &dl.0);
|
||||
encoder.write_position(dl.1);
|
||||
}
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x24 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -72,11 +156,13 @@ pub struct PluginMessage {
|
|||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl PluginMessage {
|
||||
pub fn encode(self, encoder: &mut impl PacketEncoder) {
|
||||
impl ClientBoundPacket for PluginMessage {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_string(32767, &self.channel);
|
||||
encoder.write_bytes(&self.data);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x15 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -91,8 +177,8 @@ pub struct SyncPlayerPosition {
|
|||
pub dismount: bool,
|
||||
}
|
||||
|
||||
impl SyncPlayerPosition {
|
||||
pub fn encode(self, encoder: &mut impl PacketEncoder) {
|
||||
impl ClientBoundPacket for SyncPlayerPosition {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_double(self.x);
|
||||
encoder.write_double(self.y);
|
||||
encoder.write_double(self.z);
|
||||
|
@ -102,6 +188,8 @@ impl SyncPlayerPosition {
|
|||
encoder.write_varint(self.teleport_id);
|
||||
encoder.write_bool(self.dismount);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x38 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -112,8 +200,8 @@ pub struct ChunkData {
|
|||
pub chunk_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ChunkData {
|
||||
pub fn encode(self, encoder: &mut impl PacketEncoder) {
|
||||
impl ClientBoundPacket for ChunkData {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_int(self.x);
|
||||
encoder.write_int(self.z);
|
||||
self.heightmap.to_writer(encoder).unwrap();
|
||||
|
@ -133,104 +221,86 @@ impl ChunkData {
|
|||
// block light array
|
||||
encoder.write_varint(0);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x20 }
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
pub enum ClientBoundPacket {
|
||||
// status
|
||||
StatusResponse(String),
|
||||
PingResponse(i64),
|
||||
// login
|
||||
LoginPluginRequest { id: i32, channel: String, data: Vec<u8> },
|
||||
LoginSuccess(LoginSuccess),
|
||||
LoginDisconnect(serde_json::Value),
|
||||
// play
|
||||
LoginPlay(LoginPlay),
|
||||
PluginMessage(PluginMessage),
|
||||
Commands(Commands),
|
||||
ChunkData(ChunkData),
|
||||
SyncPlayerPosition(SyncPlayerPosition),
|
||||
KeepAlive(i64),
|
||||
PlayerAbilities(i8, f32, f32),
|
||||
Disconnect(serde_json::Value),
|
||||
SetDefaultSpawnPosition(Position, f32),
|
||||
SystemChatMessage(serde_json::Value, bool),
|
||||
pub struct KeepAlive {
|
||||
pub data: i64
|
||||
}
|
||||
|
||||
impl ClientBoundPacket {
|
||||
pub fn encode(self) -> Vec<u8> {
|
||||
let mut packet = Vec::new();
|
||||
match self {
|
||||
// Status
|
||||
Self::StatusResponse(status) => {
|
||||
packet.write_string(32767, &status);
|
||||
finalize_packet(packet, 0)
|
||||
},
|
||||
Self::PingResponse(n) => {
|
||||
packet.write_long(n);
|
||||
finalize_packet(packet, 1)
|
||||
},
|
||||
// Login
|
||||
Self::LoginDisconnect(message) => {
|
||||
packet.write_string(262144, &message.to_string());
|
||||
finalize_packet(packet, 0)
|
||||
}
|
||||
Self::LoginPluginRequest { id, channel, data } => {
|
||||
packet.write_varint(id);
|
||||
packet.write_string(32767, &channel);
|
||||
packet.write_bytes(&data);
|
||||
finalize_packet(packet, 4)
|
||||
}
|
||||
Self::LoginSuccess(login_success) => {
|
||||
login_success.encode(&mut packet);
|
||||
finalize_packet(packet, 2)
|
||||
}
|
||||
// Play
|
||||
Self::Disconnect(message) => {
|
||||
packet.write_string(262144, &message.to_string());
|
||||
finalize_packet(packet, 23)
|
||||
}
|
||||
Self::LoginPlay(login_play) => {
|
||||
login_play.encode(&mut packet);
|
||||
finalize_packet(packet, 36)
|
||||
}
|
||||
Self::PluginMessage(plugin_message) => {
|
||||
plugin_message.encode(&mut packet);
|
||||
finalize_packet(packet, 21)
|
||||
}
|
||||
Self::Commands(commands) => {
|
||||
commands.encode(&mut packet);
|
||||
finalize_packet(packet, 14)
|
||||
}
|
||||
Self::ChunkData(chunk_data) => {
|
||||
chunk_data.encode(&mut packet);
|
||||
finalize_packet(packet, 32)
|
||||
}
|
||||
Self::SyncPlayerPosition(sync_player_position) => {
|
||||
sync_player_position.encode(&mut packet);
|
||||
finalize_packet(packet, 56)
|
||||
}
|
||||
Self::KeepAlive(n) => {
|
||||
packet.write_long(n);
|
||||
finalize_packet(packet, 31)
|
||||
}
|
||||
Self::SetDefaultSpawnPosition(pos, angle) => {
|
||||
packet.write_position(pos);
|
||||
packet.write_float(angle);
|
||||
finalize_packet(packet, 76)
|
||||
}
|
||||
Self::PlayerAbilities(flags, speed, view) => {
|
||||
packet.write_byte(flags);
|
||||
packet.write_float(speed);
|
||||
packet.write_float(view);
|
||||
finalize_packet(packet, 48)
|
||||
}
|
||||
Self::SystemChatMessage(msg, overlay) => {
|
||||
packet.write_string(262144, &msg.to_string());
|
||||
packet.write_bool(overlay);
|
||||
finalize_packet(packet, 96)
|
||||
}
|
||||
}
|
||||
impl ClientBoundPacket for KeepAlive {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_long(self.data)
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x1f }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PlayerAbilities {
|
||||
pub flags: i8,
|
||||
pub fly_speed: f32,
|
||||
pub fov_modifier: f32,
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for PlayerAbilities {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_byte(self.flags);
|
||||
encoder.write_float(self.fly_speed);
|
||||
encoder.write_float(self.fov_modifier);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x30 }
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Disconnect {
|
||||
pub reason: serde_json::Value
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for Disconnect {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_string(262144, &self.reason.to_string())
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x17 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetDefaultSpawnPosition {
|
||||
pub pos: Position,
|
||||
pub angle: f32
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for SetDefaultSpawnPosition {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_position(self.pos);
|
||||
encoder.write_float(self.angle);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x4c }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SystemChatMessage {
|
||||
pub message: serde_json::Value,
|
||||
pub overlay: bool
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for SystemChatMessage {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_string(262144, &self.message.to_string());
|
||||
encoder.write_bool(self.overlay);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x60 }
|
||||
}
|
||||
|
||||
pub fn encode_packet(packet: impl ClientBoundPacket) -> Vec<u8> {
|
||||
let mut buffer = Vec::new();
|
||||
packet.encode(&mut buffer);
|
||||
finalize_packet(buffer, packet.packet_id())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
use super::data::PacketEncoder;
|
||||
use super::{data::PacketEncoder, clientbound::ClientBoundPacket};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Commands {
|
||||
nodes: Vec<CommandNode>,
|
||||
}
|
||||
|
||||
impl ClientBoundPacket for Commands {
|
||||
fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_varint(self.nodes.len() as i32);
|
||||
for node in &self.nodes {
|
||||
node.encode(encoder);
|
||||
}
|
||||
// root node
|
||||
encoder.write_varint(0);
|
||||
}
|
||||
|
||||
fn packet_id(&self) -> i32 { 0x0e }
|
||||
}
|
||||
|
||||
impl Commands {
|
||||
pub fn new() -> Self {
|
||||
let root = CommandNode {
|
||||
|
@ -67,14 +80,6 @@ impl Commands {
|
|||
self.nodes[node as usize].children.push(child);
|
||||
}
|
||||
|
||||
pub fn encode(&self, encoder: &mut impl PacketEncoder) {
|
||||
encoder.write_varint(self.nodes.len() as i32);
|
||||
for node in &self.nodes {
|
||||
node.encode(encoder);
|
||||
}
|
||||
// root node
|
||||
encoder.write_varint(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum NodeError {
|
||||
|
|
|
@ -60,6 +60,25 @@ impl ChatMessage {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginPluginResponse {
|
||||
pub id: i32,
|
||||
pub data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl LoginPluginResponse {
|
||||
pub fn decode(mut decoder: PacketDecoder) -> Self {
|
||||
let id = decoder.read_varint();
|
||||
let success = decoder.read_bool();
|
||||
let data = if success {
|
||||
Some(decoder.read_to_end().to_vec())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self { id, data }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ServerBoundPacket {
|
||||
Unknown(i32),
|
||||
|
@ -71,7 +90,7 @@ pub enum ServerBoundPacket {
|
|||
PingRequest(i64),
|
||||
// login
|
||||
LoginStart(LoginStart),
|
||||
LoginPluginResponse { id: i32, data: Option<Vec<u8>> },
|
||||
LoginPluginResponse(LoginPluginResponse),
|
||||
// play
|
||||
ChatMessage(ChatMessage),
|
||||
ChatCommand(ChatMessage),
|
||||
|
@ -98,17 +117,11 @@ impl ServerBoundPacket {
|
|||
ServerBoundPacket::LoginStart(LoginStart::decode(decoder))
|
||||
},
|
||||
(NS::Login, 2) => {
|
||||
let id = decoder.read_varint();
|
||||
let success = decoder.read_bool();
|
||||
let data = if success {
|
||||
Some(decoder.read_to_end().to_vec())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if id == -1 {
|
||||
let lpr = LoginPluginResponse::decode(decoder);
|
||||
if lpr.id == -1 {
|
||||
*state = NetworkState::Play;
|
||||
}
|
||||
ServerBoundPacket::LoginPluginResponse { id, data }
|
||||
ServerBoundPacket::LoginPluginResponse(lpr)
|
||||
},
|
||||
(NS::Play, 4) => ServerBoundPacket::ChatCommand(ChatMessage::decode(decoder)),
|
||||
(NS::Play, 5) => ServerBoundPacket::ChatMessage(ChatMessage::decode(decoder)),
|
||||
|
|
Loading…
Reference in a new issue