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