mirror of
https://github.com/italicsjenga/valence.git
synced 2024-12-23 14:31:30 +11:00
Refactor valence_protocol
(#253)
## Description - Remove duplicate packet definitions by using `Cow`. - Rename packets to match yarn mappings. - Remove some top-level re-exports. - Move every packet into its own module for consistency. - Move packet-specific types from the `types` module into the appropriate packet module. - Remove internal use of `EncodePacket`/`DecodePacket` derives and move packet identification to `packet_group`. This can be done because there are no duplicate packets anymore. - Simplify some events. In a future PR I plan to clean things up further by properly bounding packet data (to prevent DoS exploits) and fixing any remaining inconsistencies with the game's packet definitions. ## Test Plan Behavior of `valence_protocol` should be the same. Steps: 1. Use the packet inspector against the vanilla server to ensure packet behavior has not changed. 2. Run the examples. 3. Run `valence_stresser`.
This commit is contained in:
parent
9931c8a80b
commit
0960ad7ead
|
@ -15,15 +15,15 @@ use tokio::net::{TcpListener, TcpStream};
|
|||
use tokio::sync::Semaphore;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
use valence_protocol::packets::c2s::handshake::Handshake;
|
||||
use valence_protocol::packets::c2s::login::{EncryptionResponse, LoginStart};
|
||||
use valence_protocol::packets::c2s::play::C2sPlayPacket;
|
||||
use valence_protocol::packets::c2s::status::{PingRequest, StatusRequest};
|
||||
use valence_protocol::packets::s2c::login::{LoginSuccess, S2cLoginPacket};
|
||||
use valence_protocol::packets::s2c::play::S2cPlayPacket;
|
||||
use valence_protocol::packets::s2c::status::{PingResponse, StatusResponse};
|
||||
use valence_protocol::types::HandshakeNextState;
|
||||
use valence_protocol::{DecodePacket, EncodePacket, PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::packet::c2s::handshake::handshake::NextState;
|
||||
use valence_protocol::packet::c2s::handshake::HandshakeC2s;
|
||||
use valence_protocol::packet::c2s::login::{LoginHelloC2s, LoginKeyC2s};
|
||||
use valence_protocol::packet::c2s::status::{QueryPingC2s, QueryRequestC2s};
|
||||
use valence_protocol::packet::s2c::login::LoginSuccessS2c;
|
||||
use valence_protocol::packet::s2c::status::{QueryPongS2c, QueryResponseS2c};
|
||||
use valence_protocol::packet::{C2sPlayPacket, S2cLoginPacket, S2cPlayPacket};
|
||||
use valence_protocol::{DecodePacket, EncodePacket};
|
||||
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
#[clap(author, version, about)]
|
||||
|
@ -179,23 +179,23 @@ async fn handle_connection(client: TcpStream, cli: Arc<Cli>) -> anyhow::Result<(
|
|||
style: owo_colors::Style::new().green(),
|
||||
};
|
||||
|
||||
let handshake: Handshake = c2s.rw_packet().await?;
|
||||
let handshake: HandshakeC2s = c2s.rw_packet().await?;
|
||||
|
||||
match handshake.next_state {
|
||||
HandshakeNextState::Status => {
|
||||
c2s.rw_packet::<StatusRequest>().await?;
|
||||
s2c.rw_packet::<StatusResponse>().await?;
|
||||
c2s.rw_packet::<PingRequest>().await?;
|
||||
s2c.rw_packet::<PingResponse>().await?;
|
||||
NextState::Status => {
|
||||
c2s.rw_packet::<QueryRequestC2s>().await?;
|
||||
s2c.rw_packet::<QueryResponseS2c>().await?;
|
||||
c2s.rw_packet::<QueryPingC2s>().await?;
|
||||
s2c.rw_packet::<QueryPongS2c>().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
HandshakeNextState::Login => {
|
||||
c2s.rw_packet::<LoginStart>().await?;
|
||||
NextState::Login => {
|
||||
c2s.rw_packet::<LoginHelloC2s>().await?;
|
||||
|
||||
match s2c.rw_packet::<S2cLoginPacket>().await? {
|
||||
S2cLoginPacket::EncryptionRequest(_) => {
|
||||
c2s.rw_packet::<EncryptionResponse>().await?;
|
||||
S2cLoginPacket::LoginHelloS2c(_) => {
|
||||
c2s.rw_packet::<LoginKeyC2s>().await?;
|
||||
|
||||
eprintln!(
|
||||
"Encryption was enabled! Packet contents are inaccessible to the proxy. \
|
||||
|
@ -207,7 +207,7 @@ async fn handle_connection(client: TcpStream, cli: Arc<Cli>) -> anyhow::Result<(
|
|||
s2c_res = passthrough(s2c.read, s2c.write) => s2c_res,
|
||||
};
|
||||
}
|
||||
S2cLoginPacket::SetCompression(pkt) => {
|
||||
S2cLoginPacket::LoginCompressionS2c(pkt) => {
|
||||
let threshold = pkt.threshold.0 as u32;
|
||||
|
||||
s2c.enc.set_compression(Some(threshold));
|
||||
|
@ -215,12 +215,12 @@ async fn handle_connection(client: TcpStream, cli: Arc<Cli>) -> anyhow::Result<(
|
|||
c2s.enc.set_compression(Some(threshold));
|
||||
c2s.dec.set_compression(true);
|
||||
|
||||
s2c.rw_packet::<LoginSuccess>().await?;
|
||||
s2c.rw_packet::<LoginSuccessS2c>().await?;
|
||||
}
|
||||
S2cLoginPacket::LoginSuccess(_) => {}
|
||||
S2cLoginPacket::DisconnectLogin(_) => return Ok(()),
|
||||
S2cLoginPacket::LoginPluginRequest(_) => {
|
||||
bail!("got login plugin request. Don't know how to proceed.")
|
||||
S2cLoginPacket::LoginSuccessS2c(_) => {}
|
||||
S2cLoginPacket::LoginDisconnectS2c(_) => return Ok(()),
|
||||
S2cLoginPacket::LoginQueryRequestS2c(_) => {
|
||||
bail!("got login query request. Don't know how to proceed.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{default_event_handler, ChatMessage, UseItemOnBlock};
|
||||
use valence::client::event::{default_event_handler, ChatMessage, PlayerInteractBlock};
|
||||
use valence::prelude::*;
|
||||
use valence_nbt::{compound, List};
|
||||
use valence_protocol::types::Hand;
|
||||
|
@ -75,7 +75,7 @@ fn init_clients(
|
|||
fn event_handler(
|
||||
clients: Query<&Client>,
|
||||
mut messages: EventReader<ChatMessage>,
|
||||
mut block_interacts: EventReader<UseItemOnBlock>,
|
||||
mut block_interacts: EventReader<PlayerInteractBlock>,
|
||||
mut instances: Query<&mut Instance>,
|
||||
) {
|
||||
let mut instance = instances.single_mut();
|
||||
|
@ -93,7 +93,7 @@ fn event_handler(
|
|||
nbt.insert("Text3", format!("~{}", client.username()).italic());
|
||||
}
|
||||
|
||||
for UseItemOnBlock {
|
||||
for PlayerInteractBlock {
|
||||
client,
|
||||
position,
|
||||
hand,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{
|
||||
default_event_handler, FinishDigging, StartDigging, StartSneaking, UseItemOnBlock,
|
||||
default_event_handler, PlayerInteractBlock, StartDigging, StartSneaking, StopDestroyBlock,
|
||||
};
|
||||
use valence::prelude::*;
|
||||
use valence_protocol::types::Hand;
|
||||
|
@ -93,7 +93,7 @@ fn digging_creative_mode(
|
|||
fn digging_survival_mode(
|
||||
clients: Query<&Client>,
|
||||
mut instances: Query<&mut Instance>,
|
||||
mut events: EventReader<FinishDigging>,
|
||||
mut events: EventReader<StopDestroyBlock>,
|
||||
) {
|
||||
let mut instance = instances.single_mut();
|
||||
|
||||
|
@ -110,7 +110,7 @@ fn digging_survival_mode(
|
|||
fn place_blocks(
|
||||
mut clients: Query<(&Client, &mut Inventory)>,
|
||||
mut instances: Query<&mut Instance>,
|
||||
mut events: EventReader<UseItemOnBlock>,
|
||||
mut events: EventReader<PlayerInteractBlock>,
|
||||
) {
|
||||
let mut instance = instances.single_mut();
|
||||
|
||||
|
@ -146,7 +146,7 @@ fn place_blocks(
|
|||
};
|
||||
inventory.replace_slot(slot_id, slot);
|
||||
}
|
||||
let real_pos = event.position.get_in_direction(event.face);
|
||||
let real_pos = event.position.get_in_direction(event.direction);
|
||||
instance.set_block(real_pos, block_kind.to_state());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use bevy_app::App;
|
||||
use tracing::warn;
|
||||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{default_event_handler, ChatCommand, ChatMessage};
|
||||
use valence::client::event::{default_event_handler, ChatMessage, CommandExecution};
|
||||
use valence::prelude::*;
|
||||
|
||||
const SPAWN_Y: i32 = 64;
|
||||
|
@ -73,7 +73,10 @@ fn handle_message_events(mut clients: Query<&mut Client>, mut messages: EventRea
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_command_events(mut clients: Query<&mut Client>, mut commands: EventReader<ChatCommand>) {
|
||||
fn handle_command_events(
|
||||
mut clients: Query<&mut Client>,
|
||||
mut commands: EventReader<CommandExecution>,
|
||||
) {
|
||||
for command in commands.iter() {
|
||||
let Ok(mut client) = clients.get_component_mut::<Client>(command.client) else {
|
||||
warn!("Unable to find client for message: {:?}", command);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use tracing::warn;
|
||||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{default_event_handler, StartSneaking, UseItemOnBlock};
|
||||
use valence::client::event::{default_event_handler, PlayerInteractBlock, StartSneaking};
|
||||
use valence::prelude::*;
|
||||
|
||||
const SPAWN_Y: i32 = 64;
|
||||
|
@ -79,7 +79,7 @@ fn toggle_gamemode_on_sneak(
|
|||
fn open_chest(
|
||||
mut commands: Commands,
|
||||
inventories: Query<Entity, (With<Inventory>, Without<Client>)>,
|
||||
mut events: EventReader<UseItemOnBlock>,
|
||||
mut events: EventReader<PlayerInteractBlock>,
|
||||
) {
|
||||
let Ok(inventory) = inventories.get_single() else {
|
||||
warn!("No inventories");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use glam::Vec3Swizzles;
|
||||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{
|
||||
default_event_handler, InteractWithEntity, StartSprinting, StopSprinting,
|
||||
default_event_handler, PlayerInteract, StartSprinting, StopSprinting,
|
||||
};
|
||||
use valence::prelude::*;
|
||||
|
||||
|
@ -92,7 +92,7 @@ fn handle_combat_events(
|
|||
server: Res<Server>,
|
||||
mut start_sprinting: EventReader<StartSprinting>,
|
||||
mut stop_sprinting: EventReader<StopSprinting>,
|
||||
mut interact_with_entity: EventReader<InteractWithEntity>,
|
||||
mut interact_with_entity: EventReader<PlayerInteract>,
|
||||
mut clients: Query<(&mut Client, &mut CombatState, &mut McEntity)>,
|
||||
) {
|
||||
for &StartSprinting { client } in start_sprinting.iter() {
|
||||
|
@ -107,7 +107,7 @@ fn handle_combat_events(
|
|||
}
|
||||
}
|
||||
|
||||
for &InteractWithEntity {
|
||||
for &PlayerInteract {
|
||||
client: attacker_client,
|
||||
entity_id,
|
||||
..
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{default_event_handler, ChatCommand};
|
||||
use valence::client::event::{default_event_handler, CommandExecution};
|
||||
use valence::prelude::*;
|
||||
|
||||
const SPAWN_Y: i32 = 64;
|
||||
|
@ -51,7 +51,7 @@ fn init_clients(
|
|||
}
|
||||
}
|
||||
|
||||
fn interpret_command(mut clients: Query<&mut Client>, mut events: EventReader<ChatCommand>) {
|
||||
fn interpret_command(mut clients: Query<&mut Client>, mut events: EventReader<CommandExecution>) {
|
||||
for event in events.iter() {
|
||||
let Ok(mut client) = clients.get_component_mut::<Client>(event.client) else {
|
||||
continue;
|
||||
|
|
|
@ -6,9 +6,9 @@ use rand::Rng;
|
|||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::default_event_handler;
|
||||
use valence::prelude::*;
|
||||
use valence_protocol::packets::s2c::play::SetTitleAnimationTimes;
|
||||
use valence_protocol::packet::s2c::play::TitleFadeS2c;
|
||||
use valence_protocol::sound::Sound;
|
||||
use valence_protocol::types::SoundCategory;
|
||||
use valence_protocol::Sound;
|
||||
|
||||
const START_POS: BlockPos = BlockPos::new(0, 100, 0);
|
||||
const VIEW_DIST: u8 = 10;
|
||||
|
@ -149,7 +149,7 @@ fn manage_blocks(mut clients: Query<(&mut Client, &mut GameState, &mut Instance)
|
|||
client.set_title(
|
||||
"",
|
||||
state.score.to_string().color(Color::LIGHT_PURPLE).bold(),
|
||||
SetTitleAnimationTimes {
|
||||
TitleFadeS2c {
|
||||
fade_in: 0,
|
||||
stay: 7,
|
||||
fade_out: 4,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::default_event_handler;
|
||||
use valence::prelude::*;
|
||||
use valence_protocol::packets::s2c::particle::Particle;
|
||||
|
||||
const SPAWN_Y: i32 = 64;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use valence::client::despawn_disconnected_clients;
|
||||
use valence::client::event::{
|
||||
default_event_handler, InteractWithEntity, ResourcePackStatus, ResourcePackStatusChange,
|
||||
default_event_handler, PlayerInteract, ResourcePackStatus, ResourcePackStatusChange,
|
||||
};
|
||||
use valence::prelude::*;
|
||||
use valence_protocol::types::EntityInteraction;
|
||||
use valence_protocol::packet::c2s::play::player_interact::Interaction;
|
||||
|
||||
const SPAWN_Y: i32 = 64;
|
||||
|
||||
|
@ -59,12 +59,12 @@ fn init_clients(
|
|||
}
|
||||
}
|
||||
|
||||
fn prompt_on_punch(mut clients: Query<&mut Client>, mut events: EventReader<InteractWithEntity>) {
|
||||
fn prompt_on_punch(mut clients: Query<&mut Client>, mut events: EventReader<PlayerInteract>) {
|
||||
for event in events.iter() {
|
||||
let Ok(mut client) = clients.get_mut(event.client) else {
|
||||
continue;
|
||||
};
|
||||
if event.interact == EntityInteraction::Attack {
|
||||
if event.interact == Interaction::Attack {
|
||||
client.set_resource_pack(
|
||||
"https://github.com/valence-rs/valence/raw/main/assets/example_pack.zip",
|
||||
"d7c6108849fb190ec2a49f2d38b7f1f897d9ce9f",
|
||||
|
|
|
@ -9,21 +9,27 @@ use bytes::BytesMut;
|
|||
use glam::{DVec3, Vec3};
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
use valence_protocol::packets::s2c::particle::Particle;
|
||||
use valence_protocol::packets::s2c::play::{
|
||||
AcknowledgeBlockChange, CombatDeath, DisconnectPlay, EntityEvent, GameEvent, KeepAliveS2c,
|
||||
LoginPlay, ParticleS2c, PluginMessageS2c, RemoveEntitiesEncode, ResourcePackS2c, Respawn,
|
||||
SetActionBarText, SetCenterChunk, SetDefaultSpawnPosition, SetEntityMetadata,
|
||||
SetEntityVelocity, SetRenderDistance, SetSubtitleText, SetTitleAnimationTimes, SetTitleText,
|
||||
SoundEffect, SynchronizePlayerPosition, SystemChatMessage, UnloadChunk,
|
||||
};
|
||||
use valence_protocol::types::{
|
||||
GameEventKind, GameMode, GlobalPos, Property, SoundCategory, SyncPlayerPosLookFlags,
|
||||
};
|
||||
use valence_protocol::{
|
||||
BlockPos, EncodePacket, Ident, ItemStack, PacketDecoder, PacketEncoder, RawBytes, Sound, Text,
|
||||
Username, VarInt,
|
||||
use valence_protocol::block_pos::BlockPos;
|
||||
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::ident::Ident;
|
||||
use valence_protocol::item::ItemStack;
|
||||
use valence_protocol::packet::s2c::play::game_state_change::GameEventKind;
|
||||
use valence_protocol::packet::s2c::play::particle::Particle;
|
||||
use valence_protocol::packet::s2c::play::player_position_look::Flags as PlayerPositionLookFlags;
|
||||
use valence_protocol::packet::s2c::play::{
|
||||
ChunkLoadDistanceS2c, ChunkRenderDistanceCenterS2c, CustomPayloadS2c, DeathMessageS2c,
|
||||
DisconnectS2c, EntitiesDestroyS2c, EntityStatusS2c, EntityTrackerUpdateS2c,
|
||||
EntityVelocityUpdateS2c, GameJoinS2c, GameMessageS2c, GameStateChangeS2c, KeepAliveS2c,
|
||||
OverlayMessageS2c, ParticleS2c, PlaySoundS2c, PlayerActionResponseS2c, PlayerPositionLookS2c,
|
||||
PlayerRespawnS2c, PlayerSpawnPositionS2c, ResourcePackSendS2c, SubtitleS2c, TitleFadeS2c,
|
||||
TitleS2c, UnloadChunkS2c,
|
||||
};
|
||||
use valence_protocol::sound::Sound;
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::types::{GameMode, GlobalPos, Property, SoundCategory};
|
||||
use valence_protocol::username::Username;
|
||||
use valence_protocol::var_int::VarInt;
|
||||
use valence_protocol::EncodePacket;
|
||||
|
||||
use crate::dimension::DimensionId;
|
||||
use crate::entity::data::Player;
|
||||
|
@ -261,7 +267,7 @@ impl Client {
|
|||
}
|
||||
|
||||
pub fn set_velocity(&mut self, velocity: impl Into<Vec3>) {
|
||||
self.enc.write_packet(&SetEntityVelocity {
|
||||
self.enc.write_packet(&EntityVelocityUpdateS2c {
|
||||
entity_id: VarInt(0),
|
||||
velocity: velocity_to_packet_units(velocity.into()),
|
||||
});
|
||||
|
@ -297,7 +303,7 @@ impl Client {
|
|||
/// Kills the client and shows `message` on the death screen. If an entity
|
||||
/// killed the player, you should supply it as `killer`.
|
||||
pub fn kill(&mut self, killer: Option<&McEntity>, message: impl Into<Text>) {
|
||||
self.write_packet(&CombatDeath {
|
||||
self.write_packet(&DeathMessageS2c {
|
||||
player_id: VarInt(0),
|
||||
entity_id: killer.map_or(-1, |k| k.protocol_id()),
|
||||
message: message.into().into(),
|
||||
|
@ -306,7 +312,7 @@ impl Client {
|
|||
|
||||
/// Respawns client. Optionally can roll the credits before respawning.
|
||||
pub fn win_game(&mut self, show_credits: bool) {
|
||||
self.write_packet(&GameEvent {
|
||||
self.write_packet(&GameStateChangeS2c {
|
||||
kind: GameEventKind::WinGame,
|
||||
value: if show_credits { 1.0 } else { 0.0 },
|
||||
});
|
||||
|
@ -322,7 +328,7 @@ impl Client {
|
|||
self.has_respawn_screen = enable;
|
||||
|
||||
if !self.is_new {
|
||||
self.write_packet(&GameEvent {
|
||||
self.write_packet(&GameStateChangeS2c {
|
||||
kind: GameEventKind::EnableRespawnScreen,
|
||||
value: if enable { 0.0 } else { 1.0 },
|
||||
});
|
||||
|
@ -381,7 +387,7 @@ impl Client {
|
|||
self.game_mode = game_mode;
|
||||
|
||||
if !self.is_new {
|
||||
self.write_packet(&GameEvent {
|
||||
self.write_packet(&GameStateChangeS2c {
|
||||
kind: GameEventKind::ChangeGameMode,
|
||||
value: game_mode as i32 as f32,
|
||||
});
|
||||
|
@ -397,7 +403,7 @@ impl Client {
|
|||
return;
|
||||
}
|
||||
|
||||
self.write_packet(&EntityEvent {
|
||||
self.write_packet(&EntityStatusS2c {
|
||||
entity_id: 0,
|
||||
entity_status: 24 + op_level,
|
||||
});
|
||||
|
@ -421,7 +427,7 @@ impl Client {
|
|||
}
|
||||
|
||||
pub fn trigger_status(&mut self, status: EntityStatus) {
|
||||
self.write_packet(&EntityEvent {
|
||||
self.write_packet(&EntityStatusS2c {
|
||||
entity_id: 0,
|
||||
entity_status: status as u8,
|
||||
});
|
||||
|
@ -457,16 +463,16 @@ impl Client {
|
|||
/// Sends a system message to the player which is visible in the chat. The
|
||||
/// message is only visible to this client.
|
||||
pub fn send_message(&mut self, msg: impl Into<Text>) {
|
||||
self.write_packet(&SystemChatMessage {
|
||||
self.write_packet(&GameMessageS2c {
|
||||
chat: msg.into().into(),
|
||||
overlay: false,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_plugin_message(&mut self, channel: Ident<&str>, data: &[u8]) {
|
||||
self.write_packet(&PluginMessageS2c {
|
||||
self.write_packet(&CustomPayloadS2c {
|
||||
channel,
|
||||
data: RawBytes(data),
|
||||
data: data.into(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -478,7 +484,7 @@ impl Client {
|
|||
|
||||
/// Kick the client with the given reason.
|
||||
pub fn kick(&mut self, reason: impl Into<Text>) {
|
||||
self.write_packet(&DisconnectPlay {
|
||||
self.write_packet(&DisconnectS2c {
|
||||
reason: reason.into().into(),
|
||||
});
|
||||
self.is_disconnected = true;
|
||||
|
@ -501,7 +507,7 @@ impl Client {
|
|||
forced: bool,
|
||||
prompt_message: Option<Text>,
|
||||
) {
|
||||
self.write_packet(&ResourcePackS2c {
|
||||
self.write_packet(&ResourcePackSendS2c {
|
||||
url,
|
||||
hash,
|
||||
forced,
|
||||
|
@ -513,21 +519,21 @@ impl Client {
|
|||
///
|
||||
/// A title is a large piece of text displayed in the center of the screen
|
||||
/// which may also include a subtitle underneath it. The title can be
|
||||
/// configured to fade in and out using the [`SetTitleAnimationTimes`]
|
||||
/// configured to fade in and out using the [`TitleFadeS2c`]
|
||||
/// struct.
|
||||
pub fn set_title(
|
||||
&mut self,
|
||||
title: impl Into<Text>,
|
||||
subtitle: impl Into<Text>,
|
||||
animation: impl Into<Option<SetTitleAnimationTimes>>,
|
||||
animation: impl Into<Option<TitleFadeS2c>>,
|
||||
) {
|
||||
let title = title.into().into();
|
||||
let subtitle = subtitle.into();
|
||||
|
||||
self.write_packet(&SetTitleText { title_text: title });
|
||||
self.write_packet(&TitleS2c { title_text: title });
|
||||
|
||||
if !subtitle.is_empty() {
|
||||
self.write_packet(&SetSubtitleText {
|
||||
self.write_packet(&SubtitleS2c {
|
||||
subtitle_text: subtitle.into(),
|
||||
});
|
||||
}
|
||||
|
@ -542,7 +548,7 @@ impl Client {
|
|||
/// The action bar is a small piece of text displayed at the bottom of the
|
||||
/// screen, above the hotbar.
|
||||
pub fn set_action_bar(&mut self, text: impl Into<Text>) {
|
||||
self.write_packet(&SetActionBarText {
|
||||
self.write_packet(&OverlayMessageS2c {
|
||||
action_bar_text: text.into().into(),
|
||||
});
|
||||
}
|
||||
|
@ -552,7 +558,7 @@ impl Client {
|
|||
/// If you want to show a particle effect to all players, use
|
||||
/// [`Instance::play_particle`]
|
||||
///
|
||||
/// [`Instance::play_particle`]: crate::instance::Instance::play_particle
|
||||
/// [`Instance::play_particle`]: Instance::play_particle
|
||||
pub fn play_particle(
|
||||
&mut self,
|
||||
particle: &Particle,
|
||||
|
@ -563,7 +569,7 @@ impl Client {
|
|||
count: i32,
|
||||
) {
|
||||
self.write_packet(&ParticleS2c {
|
||||
particle: particle.clone(),
|
||||
particle: Cow::Borrowed(particle),
|
||||
long_distance,
|
||||
position: position.into().into(),
|
||||
offset: offset.into().into(),
|
||||
|
@ -577,7 +583,7 @@ impl Client {
|
|||
/// If you want to play a sound effect to all players, use
|
||||
/// [`Instance::play_sound`]
|
||||
///
|
||||
/// [`Instance::play_sound`]: crate::instance::Instance::play_sound
|
||||
/// [`Instance::play_sound`]: Instance::play_sound
|
||||
pub fn play_sound(
|
||||
&mut self,
|
||||
sound: Sound,
|
||||
|
@ -588,7 +594,7 @@ impl Client {
|
|||
) {
|
||||
let position = position.into();
|
||||
|
||||
self.write_packet(&SoundEffect {
|
||||
self.write_packet(&PlaySoundS2c {
|
||||
id: sound.to_id(),
|
||||
category,
|
||||
position: (position * 8.0).as_ivec3().into(),
|
||||
|
@ -638,7 +644,7 @@ pub(crate) fn update_clients(
|
|||
&entities,
|
||||
&server,
|
||||
) {
|
||||
client.write_packet(&DisconnectPlay {
|
||||
client.write_packet(&DisconnectS2c {
|
||||
reason: Text::from("").into(),
|
||||
});
|
||||
client.is_disconnected = true;
|
||||
|
@ -689,7 +695,7 @@ fn update_one_client(
|
|||
// The login packet is prepended so that it is sent before all the other
|
||||
// packets. Some packets don't work correctly when sent before the login packet,
|
||||
// which is why we're doing this.
|
||||
client.enc.prepend_packet(&LoginPlay {
|
||||
client.enc.prepend_packet(&GameJoinS2c {
|
||||
entity_id: 0, // ID 0 is reserved for clients.
|
||||
is_hardcore: client.is_hardcore,
|
||||
game_mode: client.game_mode,
|
||||
|
@ -718,7 +724,7 @@ fn update_one_client(
|
|||
} else {
|
||||
if client.view_distance != client.old_view_distance {
|
||||
// Change the render distance fog.
|
||||
client.enc.append_packet(&SetRenderDistance {
|
||||
client.enc.append_packet(&ChunkLoadDistanceS2c {
|
||||
view_distance: VarInt(client.view_distance.into()),
|
||||
})?;
|
||||
}
|
||||
|
@ -733,7 +739,7 @@ fn update_one_client(
|
|||
position: pos,
|
||||
});
|
||||
|
||||
client.enc.append_packet(&Respawn {
|
||||
client.enc.append_packet(&PlayerRespawnS2c {
|
||||
dimension_type_name: dimension_name,
|
||||
dimension_name,
|
||||
hashed_seed: 0,
|
||||
|
@ -770,7 +776,7 @@ fn update_one_client(
|
|||
// Make sure the center chunk is set before loading chunks!
|
||||
if old_view.pos != view.pos {
|
||||
// TODO: does the client initialize the center chunk to (0, 0)?
|
||||
client.enc.write_packet(&SetCenterChunk {
|
||||
client.enc.write_packet(&ChunkRenderDistanceCenterS2c {
|
||||
chunk_x: VarInt(view.pos.x),
|
||||
chunk_z: VarInt(view.pos.z),
|
||||
});
|
||||
|
@ -782,7 +788,7 @@ fn update_one_client(
|
|||
if let Some(cell) = old_instance.partition.get(&pos) {
|
||||
if cell.chunk_removed && cell.chunk.is_none() {
|
||||
// Chunk was previously loaded and is now deleted.
|
||||
client.enc.write_packet(&UnloadChunk {
|
||||
client.enc.write_packet(&UnloadChunkS2c {
|
||||
chunk_x: pos.x,
|
||||
chunk_z: pos.z,
|
||||
});
|
||||
|
@ -841,7 +847,7 @@ fn update_one_client(
|
|||
if let Some(cell) = old_instance.partition.get(&pos) {
|
||||
// Unload the chunk at this cell if it was loaded.
|
||||
if cell.chunk.is_some() {
|
||||
client.enc.write_packet(&UnloadChunk {
|
||||
client.enc.write_packet(&UnloadChunkS2c {
|
||||
chunk_x: pos.x,
|
||||
chunk_z: pos.z,
|
||||
});
|
||||
|
@ -896,7 +902,7 @@ fn update_one_client(
|
|||
if let Some(cell) = instance.partition.get(&pos) {
|
||||
// Unload the chunk at this cell if it was loaded.
|
||||
if cell.chunk.is_some() {
|
||||
client.enc.write_packet(&UnloadChunk {
|
||||
client.enc.write_packet(&UnloadChunkS2c {
|
||||
chunk_x: pos.x,
|
||||
chunk_z: pos.z,
|
||||
});
|
||||
|
@ -943,8 +949,8 @@ fn update_one_client(
|
|||
|
||||
// Despawn all the entities that are queued to be despawned.
|
||||
if !client.entities_to_despawn.is_empty() {
|
||||
client.enc.append_packet(&RemoveEntitiesEncode {
|
||||
entity_ids: &client.entities_to_despawn,
|
||||
client.enc.append_packet(&EntitiesDestroyS2c {
|
||||
entity_ids: Cow::Borrowed(&client.entities_to_despawn),
|
||||
})?;
|
||||
|
||||
client.entities_to_despawn.clear();
|
||||
|
@ -953,14 +959,14 @@ fn update_one_client(
|
|||
// Teleport the client. Do this after chunk packets are sent so the client does
|
||||
// not accidentally pass through blocks.
|
||||
if client.position_modified || client.yaw_modified || client.pitch_modified {
|
||||
let flags = SyncPlayerPosLookFlags::new()
|
||||
let flags = PlayerPositionLookFlags::new()
|
||||
.with_x(!client.position_modified)
|
||||
.with_y(!client.position_modified)
|
||||
.with_z(!client.position_modified)
|
||||
.with_y_rot(!client.yaw_modified)
|
||||
.with_x_rot(!client.pitch_modified);
|
||||
|
||||
client.enc.write_packet(&SynchronizePlayerPosition {
|
||||
client.enc.write_packet(&PlayerPositionLookS2c {
|
||||
position: if client.position_modified {
|
||||
client.position.to_array()
|
||||
} else {
|
||||
|
@ -988,7 +994,7 @@ fn update_one_client(
|
|||
// This closes the "downloading terrain" screen.
|
||||
// Send this after the initial chunks are loaded.
|
||||
if client.is_new {
|
||||
client.enc.write_packet(&SetDefaultSpawnPosition {
|
||||
client.enc.write_packet(&PlayerSpawnPositionS2c {
|
||||
position: BlockPos::at(client.position),
|
||||
angle: client.yaw,
|
||||
});
|
||||
|
@ -1002,15 +1008,15 @@ fn update_one_client(
|
|||
|
||||
client.scratch.push(0xff);
|
||||
|
||||
client.enc.write_packet(&SetEntityMetadata {
|
||||
client.enc.write_packet(&EntityTrackerUpdateS2c {
|
||||
entity_id: VarInt(0),
|
||||
metadata: RawBytes(&client.scratch),
|
||||
metadata: client.scratch.as_slice().into(),
|
||||
});
|
||||
}
|
||||
|
||||
// Acknowledge broken/placed blocks.
|
||||
if client.block_change_sequence != 0 {
|
||||
client.enc.write_packet(&AcknowledgeBlockChange {
|
||||
client.enc.write_packet(&PlayerActionResponseS2c {
|
||||
sequence: VarInt(client.block_change_sequence),
|
||||
});
|
||||
|
||||
|
@ -1034,8 +1040,8 @@ mod tests {
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use bevy_app::App;
|
||||
use valence_protocol::packets::s2c::play::ChunkDataAndUpdateLight;
|
||||
use valence_protocol::packets::S2cPlayPacket;
|
||||
use valence_protocol::packet::s2c::play::ChunkDataS2c;
|
||||
use valence_protocol::packet::S2cPlayPacket;
|
||||
|
||||
use super::*;
|
||||
use crate::instance::Chunk;
|
||||
|
@ -1070,10 +1076,8 @@ mod tests {
|
|||
let mut loaded_chunks = BTreeSet::new();
|
||||
|
||||
for pkt in client_helper.collect_sent().unwrap() {
|
||||
if let S2cPlayPacket::ChunkDataAndUpdateLight(ChunkDataAndUpdateLight {
|
||||
chunk_x,
|
||||
chunk_z,
|
||||
..
|
||||
if let S2cPlayPacket::ChunkDataS2c(ChunkDataS2c {
|
||||
chunk_x, chunk_z, ..
|
||||
}) = pkt
|
||||
{
|
||||
assert!(
|
||||
|
@ -1098,17 +1102,15 @@ mod tests {
|
|||
|
||||
for pkt in client_helper.collect_sent().unwrap() {
|
||||
match pkt {
|
||||
S2cPlayPacket::ChunkDataAndUpdateLight(ChunkDataAndUpdateLight {
|
||||
chunk_x,
|
||||
chunk_z,
|
||||
..
|
||||
S2cPlayPacket::ChunkDataS2c(ChunkDataS2c {
|
||||
chunk_x, chunk_z, ..
|
||||
}) => {
|
||||
assert!(
|
||||
loaded_chunks.insert(ChunkPos::new(chunk_x, chunk_z)),
|
||||
"({chunk_x}, {chunk_z})"
|
||||
);
|
||||
}
|
||||
S2cPlayPacket::UnloadChunk(UnloadChunk { chunk_x, chunk_z }) => {
|
||||
S2cPlayPacket::UnloadChunkS2c(UnloadChunkS2c { chunk_x, chunk_z }) => {
|
||||
assert!(
|
||||
loaded_chunks.remove(&ChunkPos::new(chunk_x, chunk_z)),
|
||||
"({chunk_x}, {chunk_z})"
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,8 @@ use serde::Serialize;
|
|||
use tokio::runtime::Handle;
|
||||
use tracing::error;
|
||||
use uuid::Uuid;
|
||||
use valence_protocol::{Text, Username};
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::username::Username;
|
||||
|
||||
use crate::biome::Biome;
|
||||
use crate::dimension::Dimension;
|
||||
|
|
|
@ -9,13 +9,14 @@ use glam::{DVec3, UVec3, Vec3};
|
|||
use rustc_hash::FxHashMap;
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
use valence_protocol::entity_meta::{Facing, PaintingKind, Pose};
|
||||
use valence_protocol::packets::s2c::play::{
|
||||
EntityAnimationS2c, EntityEvent as EntityEventS2c, SetEntityMetadata, SetEntityVelocity,
|
||||
SetHeadRotation, SpawnEntity, SpawnExperienceOrb, SpawnPlayer, TeleportEntity,
|
||||
UpdateEntityPosition, UpdateEntityPositionAndRotation, UpdateEntityRotation,
|
||||
use valence_protocol::byte_angle::ByteAngle;
|
||||
use valence_protocol::packet::s2c::play::{
|
||||
EntityAnimationS2c, EntityPositionS2c, EntitySetHeadYawS2c, EntitySpawnS2c,
|
||||
EntityStatusS2c as EntityEventS2c, EntityTrackerUpdateS2c, EntityVelocityUpdateS2c,
|
||||
ExperienceOrbSpawnS2c, MoveRelativeS2c, PlayerSpawnS2c, RotateAndMoveRelativeS2c, RotateS2c,
|
||||
};
|
||||
use valence_protocol::{ByteAngle, RawBytes, VarInt};
|
||||
use valence_protocol::tracked_data::{Facing, PaintingKind, Pose};
|
||||
use valence_protocol::var_int::VarInt;
|
||||
|
||||
use crate::config::DEFAULT_TPS;
|
||||
use crate::math::Aabb;
|
||||
|
@ -321,7 +322,7 @@ impl McEntity {
|
|||
/// The hitbox of an entity is determined by its position, entity type, and
|
||||
/// other state specific to that type.
|
||||
///
|
||||
/// [interact event]: crate::client::event::InteractWithEntity
|
||||
/// [interact event]: crate::client::event::PlayerInteract
|
||||
pub fn hitbox(&self) -> Aabb {
|
||||
fn baby(is_baby: bool, adult_hitbox: [f64; 3]) -> [f64; 3] {
|
||||
if is_baby {
|
||||
|
@ -612,7 +613,7 @@ impl McEntity {
|
|||
position: DVec3,
|
||||
scratch: &mut Vec<u8>,
|
||||
) {
|
||||
let with_object_data = |data| SpawnEntity {
|
||||
let with_object_data = |data| EntitySpawnS2c {
|
||||
entity_id: VarInt(self.protocol_id),
|
||||
object_uuid: self.uuid,
|
||||
kind: VarInt(self.kind() as i32),
|
||||
|
@ -626,13 +627,13 @@ impl McEntity {
|
|||
|
||||
match &self.data {
|
||||
TrackedData::Marker(_) => {}
|
||||
TrackedData::ExperienceOrb(_) => writer.write_packet(&SpawnExperienceOrb {
|
||||
TrackedData::ExperienceOrb(_) => writer.write_packet(&ExperienceOrbSpawnS2c {
|
||||
entity_id: VarInt(self.protocol_id),
|
||||
position: position.to_array(),
|
||||
count: 0, // TODO
|
||||
}),
|
||||
TrackedData::Player(_) => {
|
||||
writer.write_packet(&SpawnPlayer {
|
||||
writer.write_packet(&PlayerSpawnS2c {
|
||||
entity_id: VarInt(self.protocol_id),
|
||||
player_uuid: self.uuid,
|
||||
position: position.to_array(),
|
||||
|
@ -641,7 +642,7 @@ impl McEntity {
|
|||
});
|
||||
|
||||
// Player spawn packet doesn't include head yaw for some reason.
|
||||
writer.write_packet(&SetHeadRotation {
|
||||
writer.write_packet(&EntitySetHeadYawS2c {
|
||||
entity_id: VarInt(self.protocol_id),
|
||||
head_yaw: ByteAngle::from_degrees(self.head_yaw),
|
||||
});
|
||||
|
@ -673,9 +674,9 @@ impl McEntity {
|
|||
scratch.clear();
|
||||
self.data.write_initial_tracked_data(scratch);
|
||||
if !scratch.is_empty() {
|
||||
writer.write_packet(&SetEntityMetadata {
|
||||
writer.write_packet(&EntityTrackerUpdateS2c {
|
||||
entity_id: VarInt(self.protocol_id),
|
||||
metadata: RawBytes(scratch),
|
||||
metadata: scratch.as_slice().into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -690,7 +691,7 @@ impl McEntity {
|
|||
let changed_position = self.position != self.old_position;
|
||||
|
||||
if changed_position && !needs_teleport && self.yaw_or_pitch_modified {
|
||||
writer.write_packet(&UpdateEntityPositionAndRotation {
|
||||
writer.write_packet(&RotateAndMoveRelativeS2c {
|
||||
entity_id,
|
||||
delta: (position_delta * 4096.0).to_array().map(|v| v as i16),
|
||||
yaw: ByteAngle::from_degrees(self.yaw),
|
||||
|
@ -699,7 +700,7 @@ impl McEntity {
|
|||
});
|
||||
} else {
|
||||
if changed_position && !needs_teleport {
|
||||
writer.write_packet(&UpdateEntityPosition {
|
||||
writer.write_packet(&MoveRelativeS2c {
|
||||
entity_id,
|
||||
delta: (position_delta * 4096.0).to_array().map(|v| v as i16),
|
||||
on_ground: self.on_ground,
|
||||
|
@ -707,7 +708,7 @@ impl McEntity {
|
|||
}
|
||||
|
||||
if self.yaw_or_pitch_modified {
|
||||
writer.write_packet(&UpdateEntityRotation {
|
||||
writer.write_packet(&RotateS2c {
|
||||
entity_id,
|
||||
yaw: ByteAngle::from_degrees(self.yaw),
|
||||
pitch: ByteAngle::from_degrees(self.pitch),
|
||||
|
@ -717,7 +718,7 @@ impl McEntity {
|
|||
}
|
||||
|
||||
if needs_teleport {
|
||||
writer.write_packet(&TeleportEntity {
|
||||
writer.write_packet(&EntityPositionS2c {
|
||||
entity_id,
|
||||
position: self.position.to_array(),
|
||||
yaw: ByteAngle::from_degrees(self.yaw),
|
||||
|
@ -727,14 +728,14 @@ impl McEntity {
|
|||
}
|
||||
|
||||
if self.velocity_modified {
|
||||
writer.write_packet(&SetEntityVelocity {
|
||||
writer.write_packet(&EntityVelocityUpdateS2c {
|
||||
entity_id,
|
||||
velocity: velocity_to_packet_units(self.velocity),
|
||||
});
|
||||
}
|
||||
|
||||
if self.head_yaw_modified {
|
||||
writer.write_packet(&SetHeadRotation {
|
||||
writer.write_packet(&EntitySetHeadYawS2c {
|
||||
entity_id,
|
||||
head_yaw: ByteAngle::from_degrees(self.head_yaw),
|
||||
});
|
||||
|
@ -743,9 +744,9 @@ impl McEntity {
|
|||
scratch.clear();
|
||||
self.data.write_updated_tracked_data(scratch);
|
||||
if !scratch.is_empty() {
|
||||
writer.write_packet(&SetEntityMetadata {
|
||||
writer.write_packet(&EntityTrackerUpdateS2c {
|
||||
entity_id,
|
||||
metadata: RawBytes(scratch),
|
||||
metadata: scratch.as_slice().into(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
#![allow(clippy::all, missing_docs, trivial_numeric_casts, dead_code)]
|
||||
|
||||
use uuid::Uuid;
|
||||
use valence_protocol::entity_meta::*;
|
||||
use valence_protocol::{BlockPos, BlockState, Encode, Text, VarInt};
|
||||
use valence_protocol::block::BlockState;
|
||||
use valence_protocol::block_pos::BlockPos;
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::tracked_data::*;
|
||||
use valence_protocol::var_int::VarInt;
|
||||
use valence_protocol::Encode;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/entity.rs"));
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::BTreeSet;
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use bevy_ecs::prelude::*;
|
||||
pub use chunk::{Block, BlockEntity, BlockMut, BlockRef, Chunk};
|
||||
pub use chunk_entry::*;
|
||||
use glam::{DVec3, Vec3};
|
||||
use num::integer::div_ceil;
|
||||
use rustc_hash::FxHashMap;
|
||||
use valence_protocol::packets::s2c::particle::{Particle, ParticleS2c};
|
||||
use valence_protocol::packets::s2c::play::{SetActionBarText, SoundEffect};
|
||||
use valence_protocol::array::LengthPrefixedArray;
|
||||
use valence_protocol::block_pos::BlockPos;
|
||||
use valence_protocol::packet::s2c::play::particle::Particle;
|
||||
use valence_protocol::packet::s2c::play::{OverlayMessageS2c, ParticleS2c, PlaySoundS2c};
|
||||
use valence_protocol::sound::Sound;
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::types::SoundCategory;
|
||||
use valence_protocol::{BlockPos, EncodePacket, LengthPrefixedArray, Sound, Text};
|
||||
use valence_protocol::EncodePacket;
|
||||
|
||||
use crate::dimension::DimensionId;
|
||||
use crate::entity::McEntity;
|
||||
pub use crate::instance::chunk::{Block, BlockMut, BlockRef, Chunk};
|
||||
use crate::packet::{PacketWriter, WritePacket};
|
||||
use crate::server::{Server, SharedServer};
|
||||
use crate::view::ChunkPos;
|
||||
|
@ -383,7 +388,7 @@ impl Instance {
|
|||
|
||||
self.write_packet_at(
|
||||
&ParticleS2c {
|
||||
particle: particle.clone(),
|
||||
particle: Cow::Borrowed(particle),
|
||||
long_distance,
|
||||
position: position.into(),
|
||||
offset: offset.into().into(),
|
||||
|
@ -408,7 +413,7 @@ impl Instance {
|
|||
let position = position.into();
|
||||
|
||||
self.write_packet_at(
|
||||
&SoundEffect {
|
||||
&PlaySoundS2c {
|
||||
id: sound.to_id(),
|
||||
category,
|
||||
position: (position * 8.0).as_ivec3().into(),
|
||||
|
@ -422,7 +427,7 @@ impl Instance {
|
|||
|
||||
/// Sets the action bar text of all players in the instance.
|
||||
pub fn set_action_bar(&mut self, text: impl Into<Text>) {
|
||||
self.write_packet(&SetActionBarText {
|
||||
self.write_packet(&OverlayMessageS2c {
|
||||
action_bar_text: text.into().into(),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,12 +6,15 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||
// Using nonstandard mutex to avoid poisoning API.
|
||||
use parking_lot::Mutex;
|
||||
use valence_nbt::{compound, Compound};
|
||||
use valence_protocol::block::{BlockEntity, BlockState};
|
||||
use valence_protocol::packets::s2c::play::{
|
||||
BlockEntityData, BlockUpdate, ChunkDataAndUpdateLightEncode, UpdateSectionBlocksEncode,
|
||||
use valence_protocol::block::{BlockEntityKind, BlockState};
|
||||
use valence_protocol::block_pos::BlockPos;
|
||||
use valence_protocol::packet::s2c::play::chunk_data::ChunkDataBlockEntity;
|
||||
use valence_protocol::packet::s2c::play::{
|
||||
BlockEntityUpdateS2c, BlockUpdateS2c, ChunkDataS2c, ChunkDeltaUpdateS2c,
|
||||
};
|
||||
use valence_protocol::types::ChunkDataBlockEntity;
|
||||
use valence_protocol::{BlockPos, Encode, VarInt, VarLong};
|
||||
use valence_protocol::var_int::VarInt;
|
||||
use valence_protocol::var_long::VarLong;
|
||||
use valence_protocol::Encode;
|
||||
|
||||
use crate::biome::BiomeId;
|
||||
use crate::instance::paletted_container::PalettedContainer;
|
||||
|
@ -171,6 +174,18 @@ impl<'a> BlockMut<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct BlockEntity {
|
||||
pub kind: BlockEntityKind,
|
||||
pub nbt: Compound,
|
||||
}
|
||||
|
||||
impl BlockEntity {
|
||||
pub fn new(kind: BlockEntityKind, nbt: Compound) -> Self {
|
||||
Self { kind, nbt }
|
||||
}
|
||||
}
|
||||
|
||||
const SECTION_BLOCK_COUNT: usize = 16 * 16 * 16;
|
||||
const SECTION_BIOME_COUNT: usize = 4 * 4 * 4;
|
||||
|
||||
|
@ -329,7 +344,7 @@ impl Chunk<true> {
|
|||
let global_y = info.min_y + sect_y as i32 * 16 + offset_y as i32;
|
||||
let global_z = pos.z * 16 + offset_z as i32;
|
||||
|
||||
writer.write_packet(&BlockUpdate {
|
||||
writer.write_packet(&BlockUpdateS2c {
|
||||
position: BlockPos::new(global_x, global_y, global_z),
|
||||
block_id: VarInt(block as i32),
|
||||
})
|
||||
|
@ -338,10 +353,10 @@ impl Chunk<true> {
|
|||
| (pos.z as i64 & 0x3fffff) << 20
|
||||
| (sect_y as i64 + info.min_y.div_euclid(16) as i64) & 0xfffff;
|
||||
|
||||
writer.write_packet(&UpdateSectionBlocksEncode {
|
||||
writer.write_packet(&ChunkDeltaUpdateS2c {
|
||||
chunk_section_position,
|
||||
invert_trust_edges: false,
|
||||
blocks: §.section_updates,
|
||||
blocks: Cow::Borrowed(§.section_updates),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -357,7 +372,7 @@ impl Chunk<true> {
|
|||
let global_y = info.min_y + y as i32;
|
||||
let global_z = pos.z * 16 + z as i32;
|
||||
|
||||
writer.write_packet(&BlockEntityData {
|
||||
writer.write_packet(&BlockEntityUpdateS2c {
|
||||
position: BlockPos::new(global_x, global_y, global_z),
|
||||
kind: block_entity.kind,
|
||||
data: Cow::Borrowed(&block_entity.nbt),
|
||||
|
@ -429,21 +444,23 @@ impl Chunk<true> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
writer.write_packet(&ChunkDataAndUpdateLightEncode {
|
||||
let heightmaps = compound! {
|
||||
// TODO: MOTION_BLOCKING heightmap
|
||||
};
|
||||
|
||||
writer.write_packet(&ChunkDataS2c {
|
||||
chunk_x: pos.x,
|
||||
chunk_z: pos.z,
|
||||
heightmaps: &compound! {
|
||||
// TODO: MOTION_BLOCKING heightmap
|
||||
},
|
||||
heightmaps: Cow::Owned(heightmaps),
|
||||
blocks_and_biomes: scratch,
|
||||
block_entities: &block_entities,
|
||||
block_entities: Cow::Borrowed(&block_entities),
|
||||
trust_edges: true,
|
||||
sky_light_mask: &info.filler_sky_light_mask,
|
||||
block_light_mask: &[],
|
||||
empty_sky_light_mask: &[],
|
||||
empty_block_light_mask: &[],
|
||||
sky_light_arrays: &info.filler_sky_light_arrays,
|
||||
block_light_arrays: &[],
|
||||
sky_light_mask: Cow::Borrowed(&info.filler_sky_light_mask),
|
||||
block_light_mask: Cow::Borrowed(&[]),
|
||||
empty_sky_light_mask: Cow::Borrowed(&[]),
|
||||
empty_block_light_mask: Cow::Borrowed(&[]),
|
||||
sky_light_arrays: Cow::Borrowed(&info.filler_sky_light_arrays),
|
||||
block_light_arrays: Cow::Borrowed(&[]),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::array;
|
|||
use std::io::Write;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use valence_protocol::{Encode, VarInt};
|
||||
use valence_protocol::var_int::VarInt;
|
||||
use valence_protocol::Encode;
|
||||
|
||||
use crate::math::bit_width;
|
||||
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use std::borrow::Cow;
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use bevy_ecs::prelude::*;
|
||||
use tracing::{debug, warn};
|
||||
use valence_protocol::packets::s2c::play::{
|
||||
CloseContainerS2c, OpenScreen, SetContainerContentEncode, SetContainerSlotEncode,
|
||||
use valence_protocol::item::ItemStack;
|
||||
use valence_protocol::packet::s2c::play::{
|
||||
CloseScreenS2c, InventoryS2c, OpenScreenS2c, ScreenHandlerSlotUpdateS2c,
|
||||
};
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::types::{GameMode, WindowType};
|
||||
use valence_protocol::{ItemStack, Text, VarInt};
|
||||
use valence_protocol::var_int::VarInt;
|
||||
|
||||
use crate::client::event::{ClickContainer, CloseContainer, SetCreativeModeSlot, SetHeldItem};
|
||||
use crate::client::event::{
|
||||
ClickSlot, CloseHandledScreen, CreativeInventoryAction, UpdateSelectedSlot,
|
||||
};
|
||||
use crate::client::Client;
|
||||
|
||||
#[derive(Debug, Clone, Component)]
|
||||
|
@ -124,11 +129,11 @@ pub(crate) fn update_player_inventories(
|
|||
client.inventory_state_id += 1;
|
||||
let cursor_item = client.cursor_item.clone();
|
||||
let state_id = client.inventory_state_id.0;
|
||||
client.write_packet(&SetContainerContentEncode {
|
||||
client.write_packet(&InventoryS2c {
|
||||
window_id: 0,
|
||||
state_id: VarInt(state_id),
|
||||
slots: inventory.slot_slice(),
|
||||
carried_item: &cursor_item,
|
||||
slots: Cow::Borrowed(inventory.slot_slice()),
|
||||
carried_item: Cow::Borrowed(&cursor_item),
|
||||
});
|
||||
|
||||
client.cursor_item_modified = false;
|
||||
|
@ -142,11 +147,11 @@ pub(crate) fn update_player_inventories(
|
|||
let state_id = client.inventory_state_id.0;
|
||||
for (i, slot) in inventory.slots.iter().enumerate() {
|
||||
if ((modified_filtered >> i) & 1) == 1 {
|
||||
client.write_packet(&SetContainerSlotEncode {
|
||||
client.write_packet(&ScreenHandlerSlotUpdateS2c {
|
||||
window_id: 0,
|
||||
state_id: VarInt(state_id),
|
||||
slot_idx: i as i16,
|
||||
slot_data: slot.as_ref(),
|
||||
slot_data: Cow::Borrowed(slot),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -162,13 +167,14 @@ pub(crate) fn update_player_inventories(
|
|||
|
||||
client.cursor_item_modified = false;
|
||||
|
||||
// TODO: eliminate clone?
|
||||
let cursor_item = client.cursor_item.clone();
|
||||
let state_id = client.inventory_state_id.0;
|
||||
client.write_packet(&SetContainerSlotEncode {
|
||||
client.write_packet(&ScreenHandlerSlotUpdateS2c {
|
||||
window_id: -1,
|
||||
state_id: VarInt(state_id),
|
||||
slot_idx: -1,
|
||||
slot_data: cursor_item.as_ref(),
|
||||
slot_data: Cow::Borrowed(&cursor_item),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +348,7 @@ pub(crate) fn update_open_inventories(
|
|||
// the inventory no longer exists, so close the inventory
|
||||
commands.entity(client_entity).remove::<OpenInventory>();
|
||||
let window_id = client.window_id;
|
||||
client.write_packet(&CloseContainerS2c {
|
||||
client.write_packet(&CloseScreenS2c {
|
||||
window_id,
|
||||
});
|
||||
continue;
|
||||
|
@ -353,18 +359,19 @@ pub(crate) fn update_open_inventories(
|
|||
client.window_id = client.window_id % 100 + 1;
|
||||
open_inventory.client_modified = 0;
|
||||
|
||||
let packet = OpenScreen {
|
||||
let packet = OpenScreenS2c {
|
||||
window_id: VarInt(client.window_id.into()),
|
||||
window_type: WindowType::from(inventory.kind),
|
||||
window_title: (&inventory.title).into(),
|
||||
};
|
||||
client.write_packet(&packet);
|
||||
|
||||
let packet = SetContainerContentEncode {
|
||||
let packet = InventoryS2c {
|
||||
window_id: client.window_id,
|
||||
state_id: VarInt(client.inventory_state_id.0),
|
||||
slots: inventory.slot_slice(),
|
||||
carried_item: &client.cursor_item.clone(),
|
||||
slots: Cow::Borrowed(inventory.slot_slice()),
|
||||
// TODO: eliminate clone?
|
||||
carried_item: Cow::Owned(client.cursor_item.clone()),
|
||||
};
|
||||
client.write_packet(&packet);
|
||||
} else {
|
||||
|
@ -372,11 +379,12 @@ pub(crate) fn update_open_inventories(
|
|||
if inventory.modified == u64::MAX {
|
||||
// send the entire inventory
|
||||
client.inventory_state_id += 1;
|
||||
let packet = SetContainerContentEncode {
|
||||
let packet = InventoryS2c {
|
||||
window_id: client.window_id,
|
||||
state_id: VarInt(client.inventory_state_id.0),
|
||||
slots: inventory.slot_slice(),
|
||||
carried_item: &client.cursor_item.clone(),
|
||||
slots: Cow::Borrowed(inventory.slot_slice()),
|
||||
// TODO: eliminate clone?
|
||||
carried_item: Cow::Owned(client.cursor_item.clone()),
|
||||
};
|
||||
client.write_packet(&packet);
|
||||
} else {
|
||||
|
@ -389,11 +397,11 @@ pub(crate) fn update_open_inventories(
|
|||
let state_id = client.inventory_state_id.0;
|
||||
for (i, slot) in inventory.slots.iter().enumerate() {
|
||||
if (modified_filtered >> i) & 1 == 1 {
|
||||
client.write_packet(&SetContainerSlotEncode {
|
||||
client.write_packet(&ScreenHandlerSlotUpdateS2c {
|
||||
window_id,
|
||||
state_id: VarInt(state_id),
|
||||
slot_idx: i as i16,
|
||||
slot_data: slot.as_ref(),
|
||||
slot_data: Cow::Borrowed(slot),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +426,7 @@ pub(crate) fn update_open_inventories(
|
|||
/// Handles clients telling the server that they are closing an inventory.
|
||||
pub(crate) fn handle_close_container(
|
||||
mut commands: Commands,
|
||||
mut events: EventReader<CloseContainer>,
|
||||
mut events: EventReader<CloseHandledScreen>,
|
||||
) {
|
||||
for event in events.iter() {
|
||||
commands.entity(event.client).remove::<OpenInventory>();
|
||||
|
@ -434,7 +442,7 @@ pub(crate) fn update_client_on_close_inventory(
|
|||
for entity in removals.iter() {
|
||||
if let Ok(mut client) = clients.get_component_mut::<Client>(entity) {
|
||||
let window_id = client.window_id;
|
||||
client.write_packet(&CloseContainerS2c { window_id });
|
||||
client.write_packet(&CloseScreenS2c { window_id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +450,7 @@ pub(crate) fn update_client_on_close_inventory(
|
|||
pub(crate) fn handle_click_container(
|
||||
mut clients: Query<(&mut Client, &mut Inventory, Option<&mut OpenInventory>)>,
|
||||
mut inventories: Query<&mut Inventory, Without<Client>>,
|
||||
mut events: EventReader<ClickContainer>,
|
||||
mut events: EventReader<ClickSlot>,
|
||||
) {
|
||||
for event in events.iter() {
|
||||
let Ok((mut client, mut client_inventory, mut open_inventory)) =
|
||||
|
@ -472,11 +480,12 @@ pub(crate) fn handle_click_container(
|
|||
// client is out of sync, resync, ignore click
|
||||
debug!("Client state id mismatch, resyncing");
|
||||
client.inventory_state_id += 1;
|
||||
let packet = SetContainerContentEncode {
|
||||
let packet = InventoryS2c {
|
||||
window_id: client.window_id,
|
||||
state_id: VarInt(client.inventory_state_id.0),
|
||||
slots: target_inventory.slot_slice(),
|
||||
carried_item: &client.cursor_item.clone(),
|
||||
slots: Cow::Borrowed(target_inventory.slot_slice()),
|
||||
// TODO: eliminate clone?
|
||||
carried_item: Cow::Owned(client.cursor_item.clone()),
|
||||
};
|
||||
client.write_packet(&packet);
|
||||
continue;
|
||||
|
@ -484,15 +493,15 @@ pub(crate) fn handle_click_container(
|
|||
|
||||
client.cursor_item = event.carried_item.clone();
|
||||
|
||||
for (slot_id, item) in event.slot_changes.clone() {
|
||||
if (0i16..target_inventory.slot_count() as i16).contains(&slot_id) {
|
||||
for slot in event.slot_changes.clone() {
|
||||
if (0i16..target_inventory.slot_count() as i16).contains(&slot.idx) {
|
||||
// the client is interacting with a slot in the target inventory
|
||||
target_inventory.replace_slot(slot_id as u16, item);
|
||||
open_inventory.client_modified |= 1 << slot_id;
|
||||
target_inventory.replace_slot(slot.idx as u16, slot.item);
|
||||
open_inventory.client_modified |= 1 << slot.idx;
|
||||
} else {
|
||||
// the client is interacting with a slot in their own inventory
|
||||
let slot_id = convert_to_player_slot_id(target_inventory.kind, slot_id as u16);
|
||||
client_inventory.replace_slot(slot_id, item);
|
||||
let slot_id = convert_to_player_slot_id(target_inventory.kind, slot.idx as u16);
|
||||
client_inventory.replace_slot(slot_id, slot.item);
|
||||
client.inventory_slots_modified |= 1 << slot_id;
|
||||
}
|
||||
}
|
||||
|
@ -503,11 +512,12 @@ pub(crate) fn handle_click_container(
|
|||
// client is out of sync, resync, and ignore the click
|
||||
debug!("Client state id mismatch, resyncing");
|
||||
client.inventory_state_id += 1;
|
||||
let packet = SetContainerContentEncode {
|
||||
let packet = InventoryS2c {
|
||||
window_id: client.window_id,
|
||||
state_id: VarInt(client.inventory_state_id.0),
|
||||
slots: client_inventory.slot_slice(),
|
||||
carried_item: &client.cursor_item.clone(),
|
||||
slots: Cow::Borrowed(client_inventory.slot_slice()),
|
||||
// TODO: eliminate clone?
|
||||
carried_item: Cow::Owned(client.cursor_item.clone()),
|
||||
};
|
||||
client.write_packet(&packet);
|
||||
continue;
|
||||
|
@ -515,16 +525,16 @@ pub(crate) fn handle_click_container(
|
|||
|
||||
// TODO: do more validation on the click
|
||||
client.cursor_item = event.carried_item.clone();
|
||||
for (slot_id, item) in event.slot_changes.clone() {
|
||||
if (0i16..client_inventory.slot_count() as i16).contains(&slot_id) {
|
||||
client_inventory.replace_slot(slot_id as u16, item);
|
||||
client.inventory_slots_modified |= 1 << slot_id;
|
||||
for slot in event.slot_changes.clone() {
|
||||
if (0i16..client_inventory.slot_count() as i16).contains(&slot.idx) {
|
||||
client_inventory.replace_slot(slot.idx as u16, slot.item);
|
||||
client.inventory_slots_modified |= 1 << slot.idx;
|
||||
} else {
|
||||
// the client is trying to interact with a slot that does not exist,
|
||||
// ignore
|
||||
warn!(
|
||||
"Client attempted to interact with slot {} which does not exist",
|
||||
slot_id
|
||||
slot.idx
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -534,7 +544,7 @@ pub(crate) fn handle_click_container(
|
|||
|
||||
pub(crate) fn handle_set_slot_creative(
|
||||
mut clients: Query<(&mut Client, &mut Inventory)>,
|
||||
mut events: EventReader<SetCreativeModeSlot>,
|
||||
mut events: EventReader<CreativeInventoryAction>,
|
||||
) {
|
||||
for event in events.iter() {
|
||||
if let Ok((mut client, mut inventory)) = clients.get_mut(event.client) {
|
||||
|
@ -554,11 +564,11 @@ pub(crate) fn handle_set_slot_creative(
|
|||
// creative mode Simply marking the slot as modified is not enough. This was
|
||||
// discovered because shift-clicking the destroy item slot in creative mode does
|
||||
// not work without this hack.
|
||||
client.write_packet(&SetContainerSlotEncode {
|
||||
client.write_packet(&ScreenHandlerSlotUpdateS2c {
|
||||
window_id: 0,
|
||||
state_id: VarInt(state_id),
|
||||
slot_idx: event.slot,
|
||||
slot_data: event.clicked_item.as_ref(),
|
||||
slot_data: Cow::Borrowed(&event.clicked_item),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -566,7 +576,7 @@ pub(crate) fn handle_set_slot_creative(
|
|||
|
||||
pub(crate) fn handle_set_held_item(
|
||||
mut clients: Query<&mut Client>,
|
||||
mut events: EventReader<SetHeldItem>,
|
||||
mut events: EventReader<UpdateSelectedSlot>,
|
||||
) {
|
||||
for event in events.iter() {
|
||||
if let Ok(mut client) = clients.get_mut(event.client) {
|
||||
|
@ -590,8 +600,8 @@ fn convert_hotbar_slot_id(slot_id: u16) -> u16 {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use bevy_app::App;
|
||||
use valence_protocol::packets::S2cPlayPacket;
|
||||
use valence_protocol::ItemKind;
|
||||
use valence_protocol::item::ItemKind;
|
||||
use valence_protocol::packet::S2cPlayPacket;
|
||||
|
||||
use super::*;
|
||||
use crate::unit_test::util::scenario_single_client;
|
||||
|
@ -636,12 +646,12 @@ mod test {
|
|||
// Make assertions
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::OpenScreen(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::SetContainerContent(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::OpenScreenS2c(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::InventoryS2c(_));
|
||||
assert_packet_order!(
|
||||
sent_packets,
|
||||
S2cPlayPacket::OpenScreen(_),
|
||||
S2cPlayPacket::SetContainerContent(_)
|
||||
S2cPlayPacket::OpenScreenS2c(_),
|
||||
S2cPlayPacket::InventoryS2c(_)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -680,7 +690,7 @@ mod test {
|
|||
// Make assertions
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::CloseContainerS2c(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::CloseScreenS2c(_));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -715,13 +725,13 @@ mod test {
|
|||
// Make assertions
|
||||
assert!(app.world.get::<OpenInventory>(client_ent).is_none());
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::CloseContainerS2c(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::CloseScreenS2c(_));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_modify_player_inventory_click_container() -> anyhow::Result<()> {
|
||||
fn test_should_modify_player_inventory_click_slot() -> anyhow::Result<()> {
|
||||
let mut app = App::new();
|
||||
let (client_ent, mut client_helper) = scenario_single_client(&mut app);
|
||||
let mut inventory = app
|
||||
|
@ -740,13 +750,16 @@ mod test {
|
|||
.get::<Client>(client_ent)
|
||||
.unwrap()
|
||||
.inventory_state_id;
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::ClickContainer {
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::ClickSlotC2s {
|
||||
window_id: 0,
|
||||
button: 0,
|
||||
mode: valence_protocol::types::ClickContainerMode::Click,
|
||||
mode: valence_protocol::packet::c2s::play::click_slot::ClickMode::Click,
|
||||
state_id: VarInt(state_id.0),
|
||||
slot_idx: 20,
|
||||
slots: vec![(20, None)],
|
||||
slots: vec![valence_protocol::packet::c2s::play::click_slot::Slot {
|
||||
idx: 20,
|
||||
item: None,
|
||||
}],
|
||||
carried_item: Some(ItemStack::new(ItemKind::Diamond, 2, None)),
|
||||
});
|
||||
|
||||
|
@ -761,7 +774,7 @@ mod test {
|
|||
assert_packet_count!(
|
||||
sent_packets,
|
||||
0,
|
||||
S2cPlayPacket::SetContainerContent(_) | S2cPlayPacket::SetContainerSlot(_)
|
||||
S2cPlayPacket::InventoryS2c(_) | S2cPlayPacket::ScreenHandlerSlotUpdateS2c(_)
|
||||
);
|
||||
let inventory = app
|
||||
.world
|
||||
|
@ -807,7 +820,11 @@ mod test {
|
|||
let sent_packets = client_helper.collect_sent()?;
|
||||
// because the inventory was modified server side, the client needs to be
|
||||
// updated with the change.
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::SetContainerSlot(_));
|
||||
assert_packet_count!(
|
||||
sent_packets,
|
||||
1,
|
||||
S2cPlayPacket::ScreenHandlerSlotUpdateS2c(_)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -831,7 +848,7 @@ mod test {
|
|||
|
||||
// Make assertions
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::SetContainerContent(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::InventoryS2c(_));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -851,7 +868,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_modify_open_inventory_click_container() -> anyhow::Result<()> {
|
||||
fn test_should_modify_open_inventory_click_slot() -> anyhow::Result<()> {
|
||||
let mut app = App::new();
|
||||
let (client_ent, mut client_helper) = scenario_single_client(&mut app);
|
||||
let inventory_ent = set_up_open_inventory(&mut app, client_ent);
|
||||
|
@ -867,13 +884,16 @@ mod test {
|
|||
.unwrap()
|
||||
.inventory_state_id;
|
||||
let window_id = app.world.get::<Client>(client_ent).unwrap().window_id;
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::ClickContainer {
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::ClickSlotC2s {
|
||||
window_id,
|
||||
button: 0,
|
||||
mode: valence_protocol::types::ClickContainerMode::Click,
|
||||
mode: valence_protocol::packet::c2s::play::click_slot::ClickMode::Click,
|
||||
state_id: VarInt(state_id.0),
|
||||
slot_idx: 20,
|
||||
slots: vec![(20, None)],
|
||||
slots: vec![valence_protocol::packet::c2s::play::click_slot::Slot {
|
||||
idx: 20,
|
||||
item: None,
|
||||
}],
|
||||
carried_item: Some(ItemStack::new(ItemKind::Diamond, 2, None)),
|
||||
});
|
||||
|
||||
|
@ -888,7 +908,7 @@ mod test {
|
|||
assert_packet_count!(
|
||||
sent_packets,
|
||||
0,
|
||||
S2cPlayPacket::SetContainerContent(_) | S2cPlayPacket::SetContainerSlot(_)
|
||||
S2cPlayPacket::InventoryS2c(_) | S2cPlayPacket::ScreenHandlerSlotUpdateS2c(_)
|
||||
);
|
||||
let inventory = app
|
||||
.world
|
||||
|
@ -931,7 +951,11 @@ mod test {
|
|||
|
||||
// because the inventory was modified server side, the client needs to be
|
||||
// updated with the change.
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::SetContainerSlot(_));
|
||||
assert_packet_count!(
|
||||
sent_packets,
|
||||
1,
|
||||
S2cPlayPacket::ScreenHandlerSlotUpdateS2c(_)
|
||||
);
|
||||
let inventory = app
|
||||
.world
|
||||
.get::<Inventory>(inventory_ent)
|
||||
|
@ -964,7 +988,7 @@ mod test {
|
|||
|
||||
// Make assertions
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::SetContainerContent(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::InventoryS2c(_));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -983,10 +1007,12 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::SetCreativeModeSlot {
|
||||
slot: 36,
|
||||
clicked_item: Some(ItemStack::new(ItemKind::Diamond, 2, None)),
|
||||
});
|
||||
client_helper.send(
|
||||
&valence_protocol::packet::c2s::play::CreativeInventoryActionC2s {
|
||||
slot: 36,
|
||||
clicked_item: Some(ItemStack::new(ItemKind::Diamond, 2, None)),
|
||||
},
|
||||
);
|
||||
|
||||
app.update();
|
||||
|
||||
|
@ -1015,10 +1041,12 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::SetCreativeModeSlot {
|
||||
slot: 36,
|
||||
clicked_item: Some(ItemStack::new(ItemKind::Diamond, 2, None)),
|
||||
});
|
||||
client_helper.send(
|
||||
&valence_protocol::packet::c2s::play::CreativeInventoryActionC2s {
|
||||
slot: 36,
|
||||
clicked_item: Some(ItemStack::new(ItemKind::Diamond, 2, None)),
|
||||
},
|
||||
);
|
||||
|
||||
app.update();
|
||||
|
||||
|
@ -1075,7 +1103,7 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::SetHeldItemC2s { slot: 4 });
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::UpdateSelectedSlotC2s { slot: 4 });
|
||||
|
||||
app.update();
|
||||
|
||||
|
@ -1090,8 +1118,10 @@ mod test {
|
|||
}
|
||||
|
||||
mod dropping_items {
|
||||
use valence_protocol::types::{ClickContainerMode, DiggingStatus};
|
||||
use valence_protocol::{BlockFace, BlockPos};
|
||||
use valence_protocol::block_pos::BlockPos;
|
||||
use valence_protocol::packet::c2s::play::click_slot::ClickMode;
|
||||
use valence_protocol::packet::c2s::play::player_action::Action;
|
||||
use valence_protocol::types::Direction;
|
||||
|
||||
use super::*;
|
||||
use crate::client::event::DropItemStack;
|
||||
|
@ -1110,10 +1140,10 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::PlayerAction {
|
||||
status: DiggingStatus::DropItem,
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::PlayerActionC2s {
|
||||
action: Action::DropItem,
|
||||
position: BlockPos::new(0, 0, 0),
|
||||
face: BlockFace::Bottom,
|
||||
direction: Direction::Down,
|
||||
sequence: VarInt(0),
|
||||
});
|
||||
|
||||
|
@ -1142,7 +1172,11 @@ mod test {
|
|||
);
|
||||
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
assert_packet_count!(sent_packets, 0, S2cPlayPacket::SetContainerSlot(_));
|
||||
assert_packet_count!(
|
||||
sent_packets,
|
||||
0,
|
||||
S2cPlayPacket::ScreenHandlerSlotUpdateS2c(_)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1161,10 +1195,10 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::PlayerAction {
|
||||
status: DiggingStatus::DropItemStack,
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::PlayerActionC2s {
|
||||
action: Action::DropAllItems,
|
||||
position: BlockPos::new(0, 0, 0),
|
||||
face: BlockFace::Bottom,
|
||||
direction: Direction::Down,
|
||||
sequence: VarInt(0),
|
||||
});
|
||||
|
||||
|
@ -1206,10 +1240,12 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::SetCreativeModeSlot {
|
||||
slot: -1,
|
||||
clicked_item: Some(ItemStack::new(ItemKind::IronIngot, 32, None)),
|
||||
});
|
||||
client_helper.send(
|
||||
&valence_protocol::packet::c2s::play::CreativeInventoryActionC2s {
|
||||
slot: -1,
|
||||
clicked_item: Some(ItemStack::new(ItemKind::IronIngot, 32, None)),
|
||||
},
|
||||
);
|
||||
|
||||
app.update();
|
||||
|
||||
|
@ -1245,11 +1281,11 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::ClickContainer {
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::ClickSlotC2s {
|
||||
window_id: 0,
|
||||
slot_idx: -999,
|
||||
button: 0,
|
||||
mode: ClickContainerMode::Click,
|
||||
mode: ClickMode::Click,
|
||||
state_id: VarInt(state_id),
|
||||
slots: vec![],
|
||||
carried_item: None,
|
||||
|
@ -1298,11 +1334,11 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::ClickContainer {
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::ClickSlotC2s {
|
||||
window_id: 0,
|
||||
slot_idx: 40,
|
||||
button: 0,
|
||||
mode: ClickContainerMode::DropKey,
|
||||
mode: ClickMode::DropKey,
|
||||
state_id: VarInt(state_id),
|
||||
slots: vec![],
|
||||
carried_item: None,
|
||||
|
@ -1346,11 +1382,11 @@ mod test {
|
|||
app.update();
|
||||
client_helper.clear_sent();
|
||||
|
||||
client_helper.send(&valence_protocol::packets::c2s::play::ClickContainer {
|
||||
client_helper.send(&valence_protocol::packet::c2s::play::ClickSlotC2s {
|
||||
window_id: 0,
|
||||
slot_idx: 40,
|
||||
button: 1, // pressing control
|
||||
mode: ClickContainerMode::DropKey,
|
||||
mode: ClickMode::DropKey,
|
||||
state_id: VarInt(state_id),
|
||||
slots: vec![],
|
||||
carried_item: None,
|
||||
|
|
|
@ -66,14 +66,17 @@ pub mod prelude {
|
|||
pub use player_list::{PlayerList, PlayerListEntry};
|
||||
pub use protocol::block::{BlockState, PropName, PropValue};
|
||||
pub use protocol::ident::Ident;
|
||||
pub use protocol::item::{ItemKind, ItemStack};
|
||||
pub use protocol::text::{Color, Text, TextFormat};
|
||||
pub use protocol::types::GameMode;
|
||||
pub use protocol::username::Username;
|
||||
pub use protocol::{ident, ItemKind, ItemStack};
|
||||
pub use server::{EventLoop, NewClientInfo, Server, SharedServer};
|
||||
pub use uuid::Uuid;
|
||||
pub use valence_nbt::Compound;
|
||||
pub use valence_protocol::{BlockKind, BlockPos};
|
||||
pub use valence_protocol::block::BlockKind;
|
||||
pub use valence_protocol::block_pos::BlockPos;
|
||||
pub use valence_protocol::ident;
|
||||
pub use valence_protocol::packet::s2c::play::particle::Particle;
|
||||
pub use view::{ChunkPos, ChunkView};
|
||||
|
||||
use super::*;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::io::Write;
|
||||
|
||||
use tracing::warn;
|
||||
use valence_protocol::{encode_packet, encode_packet_compressed, EncodePacket, PacketEncoder};
|
||||
use valence_protocol::codec::{encode_packet, encode_packet_compressed, PacketEncoder};
|
||||
use valence_protocol::EncodePacket;
|
||||
|
||||
pub(crate) trait WritePacket {
|
||||
fn write_packet<P>(&mut self, packet: &P)
|
||||
|
|
|
@ -7,12 +7,12 @@ use std::mem;
|
|||
use bevy_ecs::prelude::*;
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
use valence_protocol::packets::s2c::play::{PlayerInfoRemove, SetTabListHeaderAndFooter};
|
||||
use valence_protocol::packets::s2c::player_info_update::{
|
||||
Actions, Entry as PlayerInfoEntry, PlayerInfoUpdate,
|
||||
use valence_protocol::packet::s2c::play::player_list::{
|
||||
Actions, Entry as PlayerInfoEntry, PlayerListS2c,
|
||||
};
|
||||
use valence_protocol::packet::s2c::play::{PlayerListHeaderS2c, PlayerRemoveS2c};
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::types::{GameMode, Property};
|
||||
use valence_protocol::Text;
|
||||
|
||||
use crate::client::Client;
|
||||
use crate::packet::{PacketWriter, WritePacket};
|
||||
|
@ -242,14 +242,14 @@ impl PlayerList {
|
|||
.collect();
|
||||
|
||||
if !entries.is_empty() {
|
||||
writer.write_packet(&PlayerInfoUpdate {
|
||||
writer.write_packet(&PlayerListS2c {
|
||||
actions,
|
||||
entries: entries.into(),
|
||||
});
|
||||
}
|
||||
|
||||
if !self.header.is_empty() || !self.footer.is_empty() {
|
||||
writer.write_packet(&SetTabListHeaderAndFooter {
|
||||
writer.write_packet(&PlayerListHeaderS2c {
|
||||
header: (&self.header).into(),
|
||||
footer: (&self.footer).into(),
|
||||
});
|
||||
|
@ -610,7 +610,7 @@ pub(crate) fn update_player_list(
|
|||
display_name: entry.display_name.as_ref().map(|t| t.into()),
|
||||
};
|
||||
|
||||
writer.write_packet(&PlayerInfoUpdate {
|
||||
writer.write_packet(&PlayerListS2c {
|
||||
actions,
|
||||
entries: Cow::Borrowed(&[packet_entry]),
|
||||
});
|
||||
|
@ -638,7 +638,7 @@ pub(crate) fn update_player_list(
|
|||
}
|
||||
|
||||
if u8::from(actions) != 0 {
|
||||
writer.write_packet(&PlayerInfoUpdate {
|
||||
writer.write_packet(&PlayerListS2c {
|
||||
actions,
|
||||
entries: Cow::Borrowed(&[PlayerInfoEntry {
|
||||
player_uuid: uuid,
|
||||
|
@ -658,7 +658,7 @@ pub(crate) fn update_player_list(
|
|||
});
|
||||
|
||||
if !removed.is_empty() {
|
||||
writer.write_packet(&PlayerInfoRemove {
|
||||
writer.write_packet(&PlayerRemoveS2c {
|
||||
uuids: removed.into(),
|
||||
});
|
||||
}
|
||||
|
@ -666,7 +666,7 @@ pub(crate) fn update_player_list(
|
|||
if pl.modified_header_or_footer {
|
||||
pl.modified_header_or_footer = false;
|
||||
|
||||
writer.write_packet(&SetTabListHeaderAndFooter {
|
||||
writer.write_packet(&PlayerListHeaderS2c {
|
||||
header: (&pl.header).into(),
|
||||
footer: (&pl.footer).into(),
|
||||
});
|
||||
|
|
|
@ -17,8 +17,9 @@ use tokio::runtime::{Handle, Runtime};
|
|||
use tokio::sync::Semaphore;
|
||||
use uuid::Uuid;
|
||||
use valence_nbt::{compound, Compound, List};
|
||||
use valence_protocol::ident;
|
||||
use valence_protocol::types::Property;
|
||||
use valence_protocol::{ident, Username};
|
||||
use valence_protocol::username::Username;
|
||||
|
||||
use crate::biome::{validate_biomes, Biome, BiomeId};
|
||||
use crate::client::event::{event_loop_run_criteria, register_client_events};
|
||||
|
|
|
@ -21,18 +21,22 @@ use tokio::net::{TcpListener, TcpStream};
|
|||
use tokio::sync::OwnedSemaphorePermit;
|
||||
use tracing::{error, info, instrument, trace, warn};
|
||||
use uuid::Uuid;
|
||||
use valence_protocol::packets::c2s::handshake::HandshakeOwned;
|
||||
use valence_protocol::packets::c2s::login::{EncryptionResponse, LoginPluginResponse, LoginStart};
|
||||
use valence_protocol::packets::c2s::status::{PingRequest, StatusRequest};
|
||||
use valence_protocol::packets::s2c::login::{
|
||||
DisconnectLogin, EncryptionRequest, LoginPluginRequest, LoginSuccess, SetCompression,
|
||||
};
|
||||
use valence_protocol::packets::s2c::status::{PingResponse, StatusResponse};
|
||||
use valence_protocol::types::{HandshakeNextState, Property};
|
||||
use valence_protocol::{
|
||||
translation_key, Decode, Ident, PacketDecoder, PacketEncoder, RawBytes, Text, Username, VarInt,
|
||||
MINECRAFT_VERSION, PROTOCOL_VERSION,
|
||||
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::ident::Ident;
|
||||
use valence_protocol::packet::c2s::handshake::handshake::NextState;
|
||||
use valence_protocol::packet::c2s::handshake::HandshakeC2s;
|
||||
use valence_protocol::packet::c2s::login::{LoginHelloC2s, LoginKeyC2s, LoginQueryResponseC2s};
|
||||
use valence_protocol::packet::c2s::status::{QueryPingC2s, QueryRequestC2s};
|
||||
use valence_protocol::packet::s2c::login::{
|
||||
LoginCompressionS2c, LoginDisconnectS2c, LoginHelloS2c, LoginQueryRequestS2c, LoginSuccessS2c,
|
||||
};
|
||||
use valence_protocol::packet::s2c::status::{QueryPongS2c, QueryResponseS2c};
|
||||
use valence_protocol::raw_bytes::RawBytes;
|
||||
use valence_protocol::text::Text;
|
||||
use valence_protocol::types::Property;
|
||||
use valence_protocol::username::Username;
|
||||
use valence_protocol::var_int::VarInt;
|
||||
use valence_protocol::{translation_key, Decode, MINECRAFT_VERSION, PROTOCOL_VERSION};
|
||||
|
||||
use crate::config::{AsyncCallbacks, ConnectionMode, ServerListPing};
|
||||
use crate::server::connection::InitialConnection;
|
||||
|
@ -110,13 +114,25 @@ async fn handle_connection(
|
|||
}
|
||||
}
|
||||
|
||||
struct HandshakeData {
|
||||
protocol_version: i32,
|
||||
server_address: String,
|
||||
next_state: NextState,
|
||||
}
|
||||
|
||||
async fn handle_handshake(
|
||||
shared: SharedServer,
|
||||
callbacks: Arc<impl AsyncCallbacks>,
|
||||
mut conn: InitialConnection<OwnedReadHalf, OwnedWriteHalf>,
|
||||
remote_addr: SocketAddr,
|
||||
) -> anyhow::Result<()> {
|
||||
let handshake = conn.recv_packet::<HandshakeOwned>().await?;
|
||||
let handshake = conn.recv_packet::<HandshakeC2s>().await?;
|
||||
|
||||
let handshake = HandshakeData {
|
||||
protocol_version: handshake.protocol_version.0,
|
||||
server_address: handshake.server_address.to_owned(),
|
||||
next_state: handshake.next_state,
|
||||
};
|
||||
|
||||
ensure!(
|
||||
matches!(shared.connection_mode(), ConnectionMode::BungeeCord)
|
||||
|
@ -125,12 +141,10 @@ async fn handle_handshake(
|
|||
);
|
||||
|
||||
match handshake.next_state {
|
||||
HandshakeNextState::Status => {
|
||||
handle_status(shared, callbacks, conn, remote_addr, handshake)
|
||||
.await
|
||||
.context("error handling status")
|
||||
}
|
||||
HandshakeNextState::Login => {
|
||||
NextState::Status => handle_status(shared, callbacks, conn, remote_addr, handshake)
|
||||
.await
|
||||
.context("error handling status"),
|
||||
NextState::Login => {
|
||||
match handle_login(&shared, callbacks, &mut conn, remote_addr, handshake)
|
||||
.await
|
||||
.context("error handling login")?
|
||||
|
@ -157,12 +171,12 @@ async fn handle_status(
|
|||
callbacks: Arc<impl AsyncCallbacks>,
|
||||
mut conn: InitialConnection<OwnedReadHalf, OwnedWriteHalf>,
|
||||
remote_addr: SocketAddr,
|
||||
handshake: HandshakeOwned,
|
||||
handshake: HandshakeData,
|
||||
) -> anyhow::Result<()> {
|
||||
conn.recv_packet::<StatusRequest>().await?;
|
||||
conn.recv_packet::<QueryRequestC2s>().await?;
|
||||
|
||||
match callbacks
|
||||
.server_list_ping(&shared, remote_addr, handshake.protocol_version.0)
|
||||
.server_list_ping(&shared, remote_addr, handshake.protocol_version)
|
||||
.await
|
||||
{
|
||||
ServerListPing::Respond {
|
||||
|
@ -191,7 +205,7 @@ async fn handle_status(
|
|||
json["favicon"] = Value::String(buf);
|
||||
}
|
||||
|
||||
conn.send_packet(&StatusResponse {
|
||||
conn.send_packet(&QueryResponseS2c {
|
||||
json: &json.to_string(),
|
||||
})
|
||||
.await?;
|
||||
|
@ -199,9 +213,9 @@ async fn handle_status(
|
|||
ServerListPing::Ignore => return Ok(()),
|
||||
}
|
||||
|
||||
let PingRequest { payload } = conn.recv_packet().await?;
|
||||
let QueryPingC2s { payload } = conn.recv_packet().await?;
|
||||
|
||||
conn.send_packet(&PingResponse { payload }).await?;
|
||||
conn.send_packet(&QueryPongS2c { payload }).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -212,14 +226,14 @@ async fn handle_login(
|
|||
callbacks: Arc<impl AsyncCallbacks>,
|
||||
conn: &mut InitialConnection<OwnedReadHalf, OwnedWriteHalf>,
|
||||
remote_addr: SocketAddr,
|
||||
handshake: HandshakeOwned,
|
||||
handshake: HandshakeData,
|
||||
) -> anyhow::Result<Option<NewClientInfo>> {
|
||||
if handshake.protocol_version.0 != PROTOCOL_VERSION {
|
||||
if handshake.protocol_version != PROTOCOL_VERSION {
|
||||
// TODO: send translated disconnect msg?
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let LoginStart {
|
||||
let LoginHelloC2s {
|
||||
username,
|
||||
profile_id: _, // TODO
|
||||
} = conn.recv_packet().await?;
|
||||
|
@ -236,7 +250,7 @@ async fn handle_login(
|
|||
};
|
||||
|
||||
if let Some(threshold) = shared.0.compression_threshold {
|
||||
conn.send_packet(&SetCompression {
|
||||
conn.send_packet(&LoginCompressionS2c {
|
||||
threshold: VarInt(threshold as i32),
|
||||
})
|
||||
.await?;
|
||||
|
@ -246,14 +260,14 @@ async fn handle_login(
|
|||
|
||||
if let Err(reason) = callbacks.login(shared, &info).await {
|
||||
info!("disconnect at login: \"{reason}\"");
|
||||
conn.send_packet(&DisconnectLogin {
|
||||
conn.send_packet(&LoginDisconnectS2c {
|
||||
reason: reason.into(),
|
||||
})
|
||||
.await?;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
conn.send_packet(&LoginSuccess {
|
||||
conn.send_packet(&LoginSuccessS2c {
|
||||
uuid: info.uuid,
|
||||
username: info.username.as_str_username(),
|
||||
properties: Default::default(),
|
||||
|
@ -273,14 +287,14 @@ pub(super) async fn login_online(
|
|||
) -> anyhow::Result<NewClientInfo> {
|
||||
let my_verify_token: [u8; 16] = rand::random();
|
||||
|
||||
conn.send_packet(&EncryptionRequest {
|
||||
conn.send_packet(&LoginHelloS2c {
|
||||
server_id: "", // Always empty
|
||||
public_key: &shared.0.public_key_der,
|
||||
verify_token: &my_verify_token,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let EncryptionResponse {
|
||||
let LoginKeyC2s {
|
||||
shared_secret,
|
||||
verify_token: encrypted_verify_token,
|
||||
} = conn.recv_packet().await?;
|
||||
|
@ -332,7 +346,7 @@ pub(super) async fn login_online(
|
|||
translation_key::MULTIPLAYER_DISCONNECT_UNVERIFIED_USERNAME,
|
||||
[],
|
||||
);
|
||||
conn.send_packet(&DisconnectLogin {
|
||||
conn.send_packet(&LoginDisconnectS2c {
|
||||
reason: reason.into(),
|
||||
})
|
||||
.await?;
|
||||
|
@ -417,7 +431,7 @@ pub(super) async fn login_velocity(
|
|||
let message_id: i32 = 0; // TODO: make this random?
|
||||
|
||||
// Send Player Info Request into the Plugin Channel
|
||||
conn.send_packet(&LoginPluginRequest {
|
||||
conn.send_packet(&LoginQueryRequestS2c {
|
||||
message_id: VarInt(message_id),
|
||||
channel: Ident::new("velocity:player_info").unwrap(),
|
||||
data: RawBytes(&[VELOCITY_MIN_SUPPORTED_VERSION]),
|
||||
|
@ -425,7 +439,7 @@ pub(super) async fn login_velocity(
|
|||
.await?;
|
||||
|
||||
// Get Response
|
||||
let plugin_response: LoginPluginResponse = conn.recv_packet().await?;
|
||||
let plugin_response: LoginQueryResponseC2s = conn.recv_packet().await?;
|
||||
|
||||
ensure!(
|
||||
plugin_response.message_id.0 == message_id,
|
||||
|
|
|
@ -9,7 +9,8 @@ use tokio::sync::OwnedSemaphorePermit;
|
|||
use tokio::task::JoinHandle;
|
||||
use tokio::time::timeout;
|
||||
use tracing::debug;
|
||||
use valence_protocol::{DecodePacket, EncodePacket, PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::{DecodePacket, EncodePacket};
|
||||
|
||||
use crate::client::{Client, ClientConnection};
|
||||
use crate::server::byte_channel::{
|
||||
|
|
|
@ -53,7 +53,7 @@ use crate::unit_test::util::scenario_single_client;
|
|||
/// Some of the tests in this file may be inferior duplicates of real tests.
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use valence_protocol::packets::S2cPlayPacket;
|
||||
use valence_protocol::packet::S2cPlayPacket;
|
||||
|
||||
use super::*;
|
||||
use crate::client::Client;
|
||||
|
@ -80,7 +80,7 @@ mod tests {
|
|||
let (client_ent, mut client_helper) = scenario_single_client(&mut app);
|
||||
|
||||
// Send a packet as the client to the server.
|
||||
let packet = valence_protocol::packets::c2s::play::SetPlayerPosition {
|
||||
let packet = valence_protocol::packet::c2s::play::PositionAndOnGroundC2s {
|
||||
position: [12.0, 64.0, 0.0],
|
||||
on_ground: true,
|
||||
};
|
||||
|
@ -123,12 +123,12 @@ mod tests {
|
|||
.expect("client not found");
|
||||
let sent_packets = client_helper.collect_sent()?;
|
||||
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::OpenScreen(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::SetContainerContent(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::OpenScreenS2c(_));
|
||||
assert_packet_count!(sent_packets, 1, S2cPlayPacket::InventoryS2c(_));
|
||||
assert_packet_order!(
|
||||
sent_packets,
|
||||
S2cPlayPacket::OpenScreen(_),
|
||||
S2cPlayPacket::SetContainerContent(_)
|
||||
S2cPlayPacket::OpenScreenS2c(_),
|
||||
S2cPlayPacket::InventoryS2c(_)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -3,8 +3,10 @@ use std::sync::{Arc, Mutex};
|
|||
use bevy_app::App;
|
||||
use bevy_ecs::prelude::Entity;
|
||||
use bytes::BytesMut;
|
||||
use valence_protocol::packets::S2cPlayPacket;
|
||||
use valence_protocol::{EncodePacket, PacketDecoder, PacketEncoder, Username};
|
||||
use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||
use valence_protocol::packet::S2cPlayPacket;
|
||||
use valence_protocol::username::Username;
|
||||
use valence_protocol::EncodePacket;
|
||||
|
||||
use crate::client::{Client, ClientConnection};
|
||||
use crate::config::{ConnectionMode, ServerPlugin};
|
||||
|
@ -133,7 +135,7 @@ impl MockClientHelper {
|
|||
|
||||
/// Inject a packet to be treated as a packet inbound to the server. Panics
|
||||
/// if the packet cannot be sent.
|
||||
pub fn send(&mut self, packet: &impl EncodePacket) {
|
||||
pub fn send(&mut self, packet: &(impl EncodePacket + ?Sized)) {
|
||||
self.enc
|
||||
.append_packet(packet)
|
||||
.expect("failed to encode packet");
|
||||
|
@ -179,7 +181,7 @@ pub fn scenario_single_client(app: &mut App) -> (Entity, MockClientHelper) {
|
|||
#[macro_export]
|
||||
macro_rules! assert_packet_order {
|
||||
($sent_packets:ident, $($packets:pat),+) => {{
|
||||
let sent_packets: &Vec<valence_protocol::packets::S2cPlayPacket> = &$sent_packets;
|
||||
let sent_packets: &Vec<valence_protocol::packet::S2cPlayPacket> = &$sent_packets;
|
||||
let positions = [
|
||||
$((sent_packets.iter().position(|p| matches!(p, $packets))),)*
|
||||
];
|
||||
|
@ -190,7 +192,7 @@ macro_rules! assert_packet_order {
|
|||
#[macro_export]
|
||||
macro_rules! assert_packet_count {
|
||||
($sent_packets:ident, $count:tt, $packet:pat) => {{
|
||||
let sent_packets: &Vec<valence_protocol::packets::S2cPlayPacket> = &$sent_packets;
|
||||
let sent_packets: &Vec<valence_protocol::packet::S2cPlayPacket> = &$sent_packets;
|
||||
let count = sent_packets.iter().filter(|p| matches!(p, $packet)).count();
|
||||
assert_eq!(
|
||||
count,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use glam::DVec3;
|
||||
use valence_protocol::BlockPos;
|
||||
use valence_protocol::block_pos::BlockPos;
|
||||
|
||||
/// The X and Z position of a chunk in an
|
||||
/// [`Instance`](crate::instance::Instance).
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use num_integer::{div_ceil, Integer};
|
||||
use thiserror::Error;
|
||||
use valence::biome::BiomeId;
|
||||
use valence::instance::Chunk;
|
||||
use valence::protocol::block::{BlockEntity, BlockEntityKind, BlockKind, PropName, PropValue};
|
||||
use valence::protocol::Ident;
|
||||
use valence::instance::{BlockEntity, Chunk};
|
||||
use valence::protocol::block::{BlockEntityKind, BlockKind, PropName, PropValue};
|
||||
use valence::protocol::ident::Ident;
|
||||
use valence_nbt::{Compound, List, Value};
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
|
|
|
@ -437,10 +437,13 @@ impl<'a> SnbtReader<'a> {
|
|||
/// Assert that the string has no trailing data.
|
||||
/// SNBT is quite similar to JSON, but with some differences.
|
||||
/// See [the wiki](https://minecraft.gamepedia.com/NBT_format#SNBT_format) for more information.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use valence_nbt::snbt::SnbtReader;
|
||||
/// use valence_nbt::snbt::from_snbt_str;
|
||||
/// use valence_nbt::Value;
|
||||
///
|
||||
/// let value = from_snbt_str("1f").unwrap();
|
||||
/// assert_eq!(value, Value::Float(1.0));
|
||||
/// ```
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
use std::borrow::Cow;
|
||||
use std::time::Duration;
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use rand::Rng;
|
||||
use valence_nbt::{compound, List};
|
||||
use valence_protocol::array::LengthPrefixedArray;
|
||||
use valence_protocol::block::{BlockKind, BlockState, PropName, PropValue};
|
||||
use valence_protocol::packets::s2c::play::{
|
||||
ChunkDataAndUpdateLight, ChunkDataAndUpdateLightEncode, SetTabListHeaderAndFooter, SpawnEntity,
|
||||
};
|
||||
use valence_protocol::text::Color;
|
||||
use valence_protocol::{
|
||||
encode_packet, encode_packet_compressed, ByteAngle, Decode, Encode, ItemKind,
|
||||
LengthPrefixedArray, PacketDecoder, PacketEncoder, TextFormat, VarInt, VarLong,
|
||||
use valence_protocol::byte_angle::ByteAngle;
|
||||
use valence_protocol::codec::{
|
||||
encode_packet, encode_packet_compressed, PacketDecoder, PacketEncoder,
|
||||
};
|
||||
use valence_protocol::item::ItemKind;
|
||||
use valence_protocol::packet::s2c::play::{ChunkDataS2c, EntitySpawnS2c, PlayerListHeaderS2c};
|
||||
use valence_protocol::text::{Color, TextFormat};
|
||||
use valence_protocol::var_int::VarInt;
|
||||
use valence_protocol::var_long::VarLong;
|
||||
use valence_protocol::{Decode, Encode};
|
||||
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
|
@ -112,24 +116,24 @@ fn packets(c: &mut Criterion) {
|
|||
const SKY_LIGHT_ARRAYS: [LengthPrefixedArray<u8, 2048>; 26] =
|
||||
[LengthPrefixedArray([0xff; 2048]); 26];
|
||||
|
||||
let chunk_data_packet = ChunkDataAndUpdateLightEncode {
|
||||
let chunk_data_packet = ChunkDataS2c {
|
||||
chunk_x: 123,
|
||||
chunk_z: 456,
|
||||
heightmaps: &compound! {
|
||||
heightmaps: Cow::Owned(compound! {
|
||||
"MOTION_BLOCKING" => List::Long(vec![123; 256]),
|
||||
},
|
||||
}),
|
||||
blocks_and_biomes: BLOCKS_AND_BIOMES.as_slice(),
|
||||
block_entities: &[],
|
||||
block_entities: Cow::Borrowed(&[]),
|
||||
trust_edges: false,
|
||||
sky_light_mask: &[],
|
||||
block_light_mask: &[],
|
||||
empty_sky_light_mask: &[],
|
||||
empty_block_light_mask: &[],
|
||||
sky_light_arrays: SKY_LIGHT_ARRAYS.as_slice(),
|
||||
block_light_arrays: &[],
|
||||
sky_light_mask: Cow::Borrowed(&[]),
|
||||
block_light_mask: Cow::Borrowed(&[]),
|
||||
empty_sky_light_mask: Cow::Borrowed(&[]),
|
||||
empty_block_light_mask: Cow::Borrowed(&[]),
|
||||
sky_light_arrays: Cow::Borrowed(SKY_LIGHT_ARRAYS.as_slice()),
|
||||
block_light_arrays: Cow::Borrowed(&[]),
|
||||
};
|
||||
|
||||
let tab_list_header_footer_packet = SetTabListHeaderAndFooter {
|
||||
let player_list_header_packet = PlayerListHeaderS2c {
|
||||
header: ("this".italic() + " is the " + "header".bold().color(Color::RED)).into(),
|
||||
footer: ("this".italic()
|
||||
+ " is the "
|
||||
|
@ -139,7 +143,7 @@ fn packets(c: &mut Criterion) {
|
|||
.into(),
|
||||
};
|
||||
|
||||
let spawn_entity_packet = SpawnEntity {
|
||||
let spawn_entity_packet = EntitySpawnS2c {
|
||||
entity_id: VarInt(1234),
|
||||
object_uuid: Default::default(),
|
||||
kind: VarInt(5),
|
||||
|
@ -162,14 +166,12 @@ fn packets(c: &mut Criterion) {
|
|||
});
|
||||
});
|
||||
|
||||
c.bench_function("encode_tab_list_header_footer", |b| {
|
||||
c.bench_function("encode_player_list_header", |b| {
|
||||
b.iter(|| {
|
||||
let encoder = black_box(&mut encoder);
|
||||
|
||||
encoder.clear();
|
||||
encoder
|
||||
.append_packet(&tab_list_header_footer_packet)
|
||||
.unwrap();
|
||||
encoder.append_packet(&player_list_header_packet).unwrap();
|
||||
|
||||
black_box(encoder);
|
||||
});
|
||||
|
@ -199,14 +201,12 @@ fn packets(c: &mut Criterion) {
|
|||
});
|
||||
});
|
||||
|
||||
c.bench_function("encode_tab_list_header_footer_compressed", |b| {
|
||||
c.bench_function("encode_player_list_header_compressed", |b| {
|
||||
b.iter(|| {
|
||||
let encoder = black_box(&mut encoder);
|
||||
|
||||
encoder.clear();
|
||||
encoder
|
||||
.append_packet(&tab_list_header_footer_packet)
|
||||
.unwrap();
|
||||
encoder.append_packet(&player_list_header_packet).unwrap();
|
||||
|
||||
black_box(encoder);
|
||||
});
|
||||
|
@ -233,25 +233,21 @@ fn packets(c: &mut Criterion) {
|
|||
let decoder = black_box(&mut decoder);
|
||||
|
||||
decoder.queue_slice(&packet_buf);
|
||||
decoder
|
||||
.try_next_packet::<ChunkDataAndUpdateLight>()
|
||||
.unwrap();
|
||||
decoder.try_next_packet::<ChunkDataS2c>().unwrap();
|
||||
|
||||
black_box(decoder);
|
||||
});
|
||||
});
|
||||
|
||||
packet_buf.clear();
|
||||
encode_packet(&mut packet_buf, &tab_list_header_footer_packet).unwrap();
|
||||
encode_packet(&mut packet_buf, &player_list_header_packet).unwrap();
|
||||
|
||||
c.bench_function("decode_tab_list_header_footer", |b| {
|
||||
c.bench_function("decode_player_list_header", |b| {
|
||||
b.iter(|| {
|
||||
let decoder = black_box(&mut decoder);
|
||||
|
||||
decoder.queue_slice(&packet_buf);
|
||||
decoder
|
||||
.try_next_packet::<SetTabListHeaderAndFooter>()
|
||||
.unwrap();
|
||||
decoder.try_next_packet::<PlayerListHeaderS2c>().unwrap();
|
||||
|
||||
black_box(decoder);
|
||||
});
|
||||
|
@ -260,12 +256,12 @@ fn packets(c: &mut Criterion) {
|
|||
packet_buf.clear();
|
||||
encode_packet(&mut packet_buf, &spawn_entity_packet).unwrap();
|
||||
|
||||
c.bench_function("decode_spawn_entity", |b| {
|
||||
c.bench_function("decode_entity_spawn", |b| {
|
||||
b.iter(|| {
|
||||
let decoder = black_box(&mut decoder);
|
||||
|
||||
decoder.queue_slice(&packet_buf);
|
||||
decoder.try_next_packet::<SpawnEntity>().unwrap();
|
||||
decoder.try_next_packet::<EntitySpawnS2c>().unwrap();
|
||||
|
||||
black_box(decoder);
|
||||
});
|
||||
|
@ -283,9 +279,7 @@ fn packets(c: &mut Criterion) {
|
|||
let decoder = black_box(&mut decoder);
|
||||
|
||||
decoder.queue_slice(&packet_buf);
|
||||
decoder
|
||||
.try_next_packet::<ChunkDataAndUpdateLight>()
|
||||
.unwrap();
|
||||
decoder.try_next_packet::<ChunkDataS2c>().unwrap();
|
||||
|
||||
black_box(decoder);
|
||||
});
|
||||
|
@ -294,20 +288,18 @@ fn packets(c: &mut Criterion) {
|
|||
packet_buf.clear();
|
||||
encode_packet_compressed(
|
||||
&mut packet_buf,
|
||||
&tab_list_header_footer_packet,
|
||||
&player_list_header_packet,
|
||||
256,
|
||||
&mut scratch,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
c.bench_function("decode_tab_list_header_footer_compressed", |b| {
|
||||
c.bench_function("decode_player_list_header_compressed", |b| {
|
||||
b.iter(|| {
|
||||
let decoder = black_box(&mut decoder);
|
||||
|
||||
decoder.queue_slice(&packet_buf);
|
||||
decoder
|
||||
.try_next_packet::<SetTabListHeaderAndFooter>()
|
||||
.unwrap();
|
||||
decoder.try_next_packet::<PlayerListHeaderS2c>().unwrap();
|
||||
|
||||
black_box(decoder);
|
||||
});
|
||||
|
@ -321,7 +313,7 @@ fn packets(c: &mut Criterion) {
|
|||
let decoder = black_box(&mut decoder);
|
||||
|
||||
decoder.queue_slice(&packet_buf);
|
||||
decoder.try_next_packet::<SpawnEntity>().unwrap();
|
||||
decoder.try_next_packet::<EntitySpawnS2c>().unwrap();
|
||||
|
||||
black_box(decoder);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::io::Write;
|
|||
|
||||
use anyhow::ensure;
|
||||
|
||||
use crate::{Decode, Encode, VarInt};
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
/// A fixed-size array encoded and decoded with a [`VarInt`] length prefix.
|
||||
///
|
||||
|
|
|
@ -6,10 +6,12 @@ use std::io::Write;
|
|||
use std::iter::FusedIterator;
|
||||
|
||||
use anyhow::Context;
|
||||
use valence_nbt::Compound;
|
||||
use valence_protocol_macros::ident_str;
|
||||
|
||||
use crate::{Decode, Encode, Ident, ItemKind, Result, VarInt};
|
||||
use crate::ident::Ident;
|
||||
use crate::item::ItemKind;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode, Result};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/block.rs"));
|
||||
|
||||
|
@ -81,34 +83,6 @@ impl Decode<'_> for BlockKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct BlockEntity {
|
||||
pub kind: BlockEntityKind,
|
||||
pub nbt: Compound,
|
||||
}
|
||||
|
||||
impl BlockEntity {
|
||||
pub const fn new(kind: BlockEntityKind, nbt: Compound) -> Self {
|
||||
Self { kind, nbt }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum BlockFace {
|
||||
/// -Y
|
||||
Bottom,
|
||||
/// +Y
|
||||
Top,
|
||||
/// -Z
|
||||
North,
|
||||
/// +Z
|
||||
South,
|
||||
/// -X
|
||||
West,
|
||||
/// +X
|
||||
East,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::io::Write;
|
|||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{BlockFace, Decode, Encode};
|
||||
use crate::types::Direction;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
/// Represents an absolute block position in world space.
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Debug)]
|
||||
|
@ -27,20 +28,21 @@ impl BlockPos {
|
|||
/// direction.
|
||||
///
|
||||
/// ```
|
||||
/// use valence_protocol::{BlockFace, BlockPos};
|
||||
/// use valence_protocol::block_pos::BlockPos;
|
||||
/// use valence_protocol::types::Direction;
|
||||
///
|
||||
/// let pos = BlockPos::new(0, 0, 0);
|
||||
/// let adj = pos.get_in_direction(BlockFace::South);
|
||||
/// let adj = pos.get_in_direction(Direction::South);
|
||||
/// assert_eq!(adj, BlockPos::new(0, 0, 1));
|
||||
/// ```
|
||||
pub fn get_in_direction(self, dir: BlockFace) -> BlockPos {
|
||||
pub fn get_in_direction(self, dir: Direction) -> BlockPos {
|
||||
match dir {
|
||||
BlockFace::Bottom => BlockPos::new(self.x, self.y - 1, self.z),
|
||||
BlockFace::Top => BlockPos::new(self.x, self.y + 1, self.z),
|
||||
BlockFace::North => BlockPos::new(self.x, self.y, self.z - 1),
|
||||
BlockFace::South => BlockPos::new(self.x, self.y, self.z + 1),
|
||||
BlockFace::West => BlockPos::new(self.x - 1, self.y, self.z),
|
||||
BlockFace::East => BlockPos::new(self.x + 1, self.y, self.z),
|
||||
Direction::Down => BlockPos::new(self.x, self.y - 1, self.z),
|
||||
Direction::Up => BlockPos::new(self.x, self.y + 1, self.z),
|
||||
Direction::North => BlockPos::new(self.x, self.y, self.z - 1),
|
||||
Direction::South => BlockPos::new(self.x, self.y, self.z + 1),
|
||||
Direction::West => BlockPos::new(self.x - 1, self.y, self.z),
|
||||
Direction::East => BlockPos::new(self.x + 1, self.y, self.z),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
// TODO: implement BoundedFloat when floats are permitted in const generics.
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::ensure;
|
||||
|
||||
use crate::{Decode, Encode, Result};
|
||||
|
||||
/// An integer with a minimum and maximum value known at compile time. `T` is
|
||||
/// the underlying integer type.
|
||||
///
|
||||
/// If the value is not in bounds, an error is generated while
|
||||
/// encoding or decoding.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
||||
pub struct BoundedInt<T, const MIN: i128, const MAX: i128>(pub T);
|
||||
|
||||
impl<T, const MIN: i128, const MAX: i128> Encode for BoundedInt<T, MIN, MAX>
|
||||
where
|
||||
T: Encode + Clone + Into<i128>,
|
||||
{
|
||||
fn encode(&self, w: impl Write) -> Result<()> {
|
||||
let n = self.0.clone().into();
|
||||
|
||||
ensure!(
|
||||
(MIN..=MAX).contains(&n),
|
||||
"integer is not in bounds while encoding (got {n}, expected {MIN}..={MAX})"
|
||||
);
|
||||
|
||||
self.0.encode(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, const MIN: i128, const MAX: i128> Decode<'a> for BoundedInt<T, MIN, MAX>
|
||||
where
|
||||
T: Decode<'a> + Clone + Into<i128>,
|
||||
{
|
||||
fn decode(r: &mut &'a [u8]) -> Result<Self> {
|
||||
let res = T::decode(r)?;
|
||||
let n = res.clone().into();
|
||||
|
||||
ensure!(
|
||||
(MIN..=MAX).contains(&n),
|
||||
"integer is not in bounds while decoding (got {n}, expected {MIN}..={MAX})"
|
||||
);
|
||||
|
||||
Ok(Self(res))
|
||||
}
|
||||
}
|
||||
|
||||
/// A string with a minimum and maximum character length known at compile time.
|
||||
/// `S` is the underlying string type which is anything that implements
|
||||
/// `AsRef<str>`.
|
||||
///
|
||||
/// If the string is not in bounds, an error is generated while
|
||||
/// encoding or decoding.
|
||||
///
|
||||
/// Note that the length is a count of the _characters_ in the string, not
|
||||
/// bytes.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
||||
pub struct BoundedString<S, const MIN: usize, const MAX: usize>(pub S);
|
||||
|
||||
impl<S, const MIN: usize, const MAX: usize> Encode for BoundedString<S, MIN, MAX>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
fn encode(&self, w: impl Write) -> Result<()> {
|
||||
let s = self.0.as_ref();
|
||||
let cnt = s.chars().count();
|
||||
|
||||
ensure!(
|
||||
(MIN..=MAX).contains(&s.chars().count()),
|
||||
"char count of string is out of bounds while encoding (got {cnt}, expected \
|
||||
{MIN}..={MAX})"
|
||||
);
|
||||
|
||||
s.encode(w)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S, const MIN: usize, const MAX: usize> Decode<'a> for BoundedString<S, MIN, MAX>
|
||||
where
|
||||
S: Decode<'a> + AsRef<str>,
|
||||
{
|
||||
fn decode(r: &mut &'a [u8]) -> Result<Self> {
|
||||
let s = S::decode(r)?;
|
||||
let cnt = s.as_ref().chars().count();
|
||||
|
||||
ensure!(
|
||||
(MIN..=MAX).contains(&cnt),
|
||||
"char count of string is out of bounds while decoding (got {cnt}, expected \
|
||||
{MIN}..={MAX})"
|
||||
);
|
||||
|
||||
Ok(Self(s))
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -501,10 +501,10 @@ impl PacketDecoder {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::block_pos::BlockPos;
|
||||
use crate::entity_meta::PaintingKind;
|
||||
use crate::ident::Ident;
|
||||
use crate::item::{ItemKind, ItemStack};
|
||||
use crate::text::{Text, TextFormat};
|
||||
use crate::tracked_data::PaintingKind;
|
||||
use crate::username::Username;
|
||||
use crate::var_long::VarLong;
|
||||
use crate::Decode;
|
||||
|
|
|
@ -12,7 +12,8 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
|||
use uuid::Uuid;
|
||||
use valence_nbt::Compound;
|
||||
|
||||
use crate::{Decode, Encode, Result, VarInt, MAX_PACKET_SIZE};
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode, Result, MAX_PACKET_SIZE};
|
||||
|
||||
// ==== Primitive ==== //
|
||||
|
||||
|
@ -22,6 +23,7 @@ impl Encode for bool {
|
|||
}
|
||||
|
||||
fn write_slice(slice: &[bool], mut w: impl Write) -> io::Result<()> {
|
||||
// SAFETY: Bools have the same layout as u8.
|
||||
// Bools are guaranteed to have the correct bit pattern.
|
||||
let bytes: &[u8] = unsafe { mem::transmute(slice) };
|
||||
w.write_all(bytes)
|
||||
|
|
|
@ -3,7 +3,9 @@ use std::io::Write;
|
|||
use anyhow::{ensure, Context};
|
||||
use valence_nbt::Compound;
|
||||
|
||||
use crate::{BlockKind, Decode, Encode, Result, VarInt};
|
||||
use crate::block::BlockKind;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode, Result};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/item.rs"));
|
||||
|
||||
|
|
|
@ -2,18 +2,21 @@
|
|||
//! protocol.
|
||||
//!
|
||||
//! The API is centered around the [`Encode`] and [`Decode`] traits. Clientbound
|
||||
//! and serverbound packets are defined in the [`packets`] module. Packets are
|
||||
//! and serverbound packets are defined in the [`packet`] module. Packets are
|
||||
//! encoded and decoded using the [`PacketEncoder`] and [`PacketDecoder`] types.
|
||||
//!
|
||||
//! [`PacketEncoder`]: codec::PacketEncoder
|
||||
//! [`PacketDecoder`]: codec::PacketDecoder
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! use valence_protocol::packets::c2s::play::RenameItem;
|
||||
//! use valence_protocol::{PacketDecoder, PacketEncoder};
|
||||
//! use valence_protocol::codec::{PacketDecoder, PacketEncoder};
|
||||
//! use valence_protocol::packet::c2s::play::RenameItemC2s;
|
||||
//!
|
||||
//! let mut enc = PacketEncoder::new();
|
||||
//!
|
||||
//! let outgoing = RenameItem {
|
||||
//! let outgoing = RenameItemC2s {
|
||||
//! item_name: "Hello!",
|
||||
//! };
|
||||
//!
|
||||
|
@ -23,7 +26,7 @@
|
|||
//!
|
||||
//! dec.queue_bytes(enc.take());
|
||||
//!
|
||||
//! let incoming = dec.try_next_packet::<RenameItem>().unwrap().unwrap();
|
||||
//! let incoming = dec.try_next_packet::<RenameItemC2s>().unwrap().unwrap();
|
||||
//!
|
||||
//! assert_eq!(outgoing.item_name, incoming.item_name);
|
||||
//! ```
|
||||
|
@ -72,21 +75,7 @@ use std::io::Write;
|
|||
use std::{fmt, io};
|
||||
|
||||
pub use anyhow::{Error, Result};
|
||||
pub use array::LengthPrefixedArray;
|
||||
pub use block::{BlockFace, BlockKind, BlockState};
|
||||
pub use block_pos::BlockPos;
|
||||
pub use byte_angle::ByteAngle;
|
||||
pub use codec::*;
|
||||
pub use ident::Ident;
|
||||
pub use item::{ItemKind, ItemStack};
|
||||
pub use raw_bytes::RawBytes;
|
||||
pub use sound::Sound;
|
||||
pub use text::{Text, TextFormat};
|
||||
pub use username::Username;
|
||||
pub use uuid::Uuid;
|
||||
pub use valence_protocol_macros::{Decode, DecodePacket, Encode, EncodePacket};
|
||||
pub use var_int::VarInt;
|
||||
pub use var_long::VarLong;
|
||||
pub use valence_protocol_macros::{ident_str, Decode, DecodePacket, Encode, EncodePacket};
|
||||
pub use {uuid, valence_nbt as nbt};
|
||||
|
||||
/// The Minecraft protocol version this library currently targets.
|
||||
|
@ -96,33 +85,33 @@ pub const PROTOCOL_VERSION: i32 = 761;
|
|||
/// targets.
|
||||
pub const MINECRAFT_VERSION: &str = "1.19.3";
|
||||
|
||||
mod array;
|
||||
pub mod array;
|
||||
pub mod block;
|
||||
mod block_pos;
|
||||
mod bounded;
|
||||
mod byte_angle;
|
||||
mod codec;
|
||||
pub mod block_pos;
|
||||
pub mod byte_angle;
|
||||
pub mod codec;
|
||||
pub mod enchant;
|
||||
pub mod entity_meta;
|
||||
pub mod ident;
|
||||
mod impls;
|
||||
mod item;
|
||||
pub mod packets;
|
||||
mod raw_bytes;
|
||||
pub mod item;
|
||||
pub mod packet;
|
||||
pub mod raw_bytes;
|
||||
pub mod sound;
|
||||
pub mod text;
|
||||
pub mod tracked_data;
|
||||
pub mod translation_key;
|
||||
pub mod types;
|
||||
pub mod username;
|
||||
pub mod var_int;
|
||||
mod var_long;
|
||||
pub mod var_long;
|
||||
|
||||
/// Used only by proc macros. Not public API.
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
pub use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||
|
||||
pub use crate::{Decode, DecodePacket, Encode, EncodePacket, VarInt};
|
||||
pub use crate::var_int::VarInt;
|
||||
pub use crate::{Decode, DecodePacket, Encode, EncodePacket};
|
||||
}
|
||||
|
||||
/// The maximum number of bytes in a single Minecraft packet.
|
||||
|
@ -175,6 +164,7 @@ pub const MAX_PACKET_SIZE: i32 = 2097152;
|
|||
/// ```
|
||||
///
|
||||
/// [macro]: valence_protocol_macros::Encode
|
||||
/// [`VarInt`]: var_int::VarInt
|
||||
pub trait Encode {
|
||||
/// Writes this object to the provided writer.
|
||||
///
|
||||
|
@ -250,6 +240,7 @@ pub trait Encode {
|
|||
/// ```
|
||||
///
|
||||
/// [macro]: valence_protocol_macros::Decode
|
||||
/// [`VarInt`]: var_int::VarInt
|
||||
pub trait Decode<'a>: Sized {
|
||||
/// Reads this object from the provided byte slice.
|
||||
///
|
||||
|
@ -285,6 +276,7 @@ pub trait Decode<'a>: Sized {
|
|||
/// ```
|
||||
///
|
||||
/// [macro]: valence_protocol_macros::DecodePacket
|
||||
/// [`VarInt`]: var_int::VarInt
|
||||
pub trait EncodePacket: fmt::Debug {
|
||||
/// The packet ID that is written when [`Self::encode_packet`] is called. A
|
||||
/// negative value indicates that the packet ID is not statically known.
|
||||
|
@ -292,6 +284,8 @@ pub trait EncodePacket: fmt::Debug {
|
|||
|
||||
/// Like [`Encode::encode`], but a leading [`VarInt`] packet ID must be
|
||||
/// written first.
|
||||
///
|
||||
/// [`VarInt`]: var_int::VarInt
|
||||
fn encode_packet(&self, w: impl Write) -> Result<()>;
|
||||
}
|
||||
|
||||
|
@ -324,6 +318,7 @@ pub trait EncodePacket: fmt::Debug {
|
|||
/// ```
|
||||
///
|
||||
/// [macro]: valence_protocol::DecodePacket
|
||||
/// [`VarInt`]: var_int::VarInt
|
||||
pub trait DecodePacket<'a>: Sized + fmt::Debug {
|
||||
/// The packet ID that is read when [`Self::decode_packet`] is called. A
|
||||
/// negative value indicates that the packet ID is not statically known.
|
||||
|
@ -331,6 +326,8 @@ pub trait DecodePacket<'a>: Sized + fmt::Debug {
|
|||
|
||||
/// Like [`Decode::decode`], but a leading [`VarInt`] packet ID must be read
|
||||
/// first.
|
||||
///
|
||||
/// [`VarInt`]: var_int::VarInt
|
||||
fn decode_packet(r: &mut &'a [u8]) -> Result<Self>;
|
||||
}
|
||||
|
||||
|
@ -361,14 +358,14 @@ mod derive_tests {
|
|||
|
||||
#[derive(Encode, EncodePacket, Decode, DecodePacket, Debug)]
|
||||
#[packet_id = 5]
|
||||
struct StructWithGenerics<'z, T: std::fmt::Debug = ()> {
|
||||
struct StructWithGenerics<'z, T: fmt::Debug = ()> {
|
||||
foo: &'z str,
|
||||
bar: T,
|
||||
}
|
||||
|
||||
#[derive(Encode, EncodePacket, Decode, DecodePacket, Debug)]
|
||||
#[packet_id = 6]
|
||||
struct TupleStructWithGenerics<'z, T: std::fmt::Debug = ()>(&'z str, i32, T);
|
||||
struct TupleStructWithGenerics<'z, T: fmt::Debug = ()>(&'z str, i32, T);
|
||||
|
||||
#[derive(Encode, EncodePacket, Decode, DecodePacket, Debug)]
|
||||
#[packet_id = 7]
|
||||
|
@ -384,7 +381,7 @@ mod derive_tests {
|
|||
|
||||
#[derive(Encode, EncodePacket, Decode, DecodePacket, Debug)]
|
||||
#[packet_id = 0xbeef]
|
||||
enum EnumWithGenericsAndTags<'z, T: std::fmt::Debug = ()> {
|
||||
enum EnumWithGenericsAndTags<'z, T: fmt::Debug = ()> {
|
||||
#[tag = 5]
|
||||
First {
|
||||
foo: &'z str,
|
||||
|
|
|
@ -12,12 +12,13 @@ pub use s2c::login::S2cLoginPacket;
|
|||
pub use s2c::play::S2cPlayPacket;
|
||||
pub use s2c::status::S2cStatusPacket;
|
||||
|
||||
/// Defines an enum of packets.
|
||||
macro_rules! packet_enum {
|
||||
/// Defines an enum of packets and implements `EncodePacket` and `DecodePacket`
|
||||
/// for each.
|
||||
macro_rules! packet_group {
|
||||
(
|
||||
$(#[$attrs:meta])*
|
||||
$enum_name:ident<$enum_life:lifetime> {
|
||||
$($packet:ident $(<$life:lifetime>)?),* $(,)?
|
||||
$($packet_id:literal = $packet:ident $(<$life:lifetime>)?),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$(#[$attrs])*
|
||||
|
@ -33,11 +34,41 @@ macro_rules! packet_enum {
|
|||
Self::$packet(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl$(<$life>)? crate::EncodePacket for $packet$(<$life>)? {
|
||||
const PACKET_ID: i32 = $packet_id;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
fn encode_packet(&self, mut w: impl std::io::Write) -> crate::Result<()> {
|
||||
use ::valence_protocol::__private::{Encode, Context, VarInt};
|
||||
|
||||
VarInt($packet_id)
|
||||
.encode(&mut w)
|
||||
.context("failed to encode packet ID")?;
|
||||
|
||||
self.encode(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$enum_life> crate::DecodePacket<$enum_life> for $packet$(<$life>)? {
|
||||
const PACKET_ID: i32 = $packet_id;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
fn decode_packet(r: &mut &$enum_life [u8]) -> ::valence_protocol::__private::Result<Self> {
|
||||
use ::valence_protocol::__private::{Decode, Context, VarInt, ensure};
|
||||
|
||||
let id = VarInt::decode(r).context("failed to decode packet ID")?.0;
|
||||
ensure!(id == $packet_id, "unexpected packet ID {} (expected {})", id, $packet_id);
|
||||
|
||||
Self::decode(r)
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
impl<$enum_life> crate::EncodePacket for $enum_name<$enum_life> {
|
||||
fn encode_packet(&self, mut w: impl std::io::Write) -> crate::Result<()> {
|
||||
use crate::{Encode, VarInt};
|
||||
use crate::Encode;
|
||||
use crate::var_int::VarInt;
|
||||
|
||||
match self {
|
||||
$(
|
||||
|
@ -54,7 +85,8 @@ macro_rules! packet_enum {
|
|||
|
||||
impl<$enum_life> crate::DecodePacket<$enum_life> for $enum_name<$enum_life> {
|
||||
fn decode_packet(r: &mut &$enum_life [u8]) -> crate::Result<Self> {
|
||||
use crate::{Decode, VarInt};
|
||||
use crate::Decode;
|
||||
use crate::var_int::VarInt;
|
||||
|
||||
let id = VarInt::decode(r)?.0;
|
||||
Ok(match id {
|
||||
|
@ -62,7 +94,7 @@ macro_rules! packet_enum {
|
|||
<$packet as crate::DecodePacket>::PACKET_ID =>
|
||||
Self::$packet($packet::decode(r)?),
|
||||
)*
|
||||
id => anyhow::bail!("unknown packet ID {:#02x} while decoding {}", id, stringify!($enum_name)),
|
||||
id => anyhow::bail!("unknown packet ID {} while decoding {}", id, stringify!($enum_name)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +113,7 @@ macro_rules! packet_enum {
|
|||
(
|
||||
$(#[$attrs:meta])*
|
||||
$enum_name:ident {
|
||||
$($packet:ident),* $(,)?
|
||||
$($packet_id:literal = $packet:ident),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$(#[$attrs])*
|
||||
|
@ -97,11 +129,41 @@ macro_rules! packet_enum {
|
|||
Self::$packet(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::EncodePacket for $packet {
|
||||
const PACKET_ID: i32 = $packet_id;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
fn encode_packet(&self, mut w: impl std::io::Write) -> crate::Result<()> {
|
||||
use ::valence_protocol::__private::{Encode, Context, VarInt};
|
||||
|
||||
VarInt($packet_id)
|
||||
.encode(&mut w)
|
||||
.context("failed to encode packet ID")?;
|
||||
|
||||
self.encode(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::DecodePacket<'_> for $packet {
|
||||
const PACKET_ID: i32 = $packet_id;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
fn decode_packet(r: &mut &[u8]) -> ::valence_protocol::__private::Result<Self> {
|
||||
use ::valence_protocol::__private::{Decode, Context, VarInt, ensure};
|
||||
|
||||
let id = VarInt::decode(r).context("failed to decode packet ID")?.0;
|
||||
ensure!(id == $packet_id, "unexpected packet ID {} (expected {})", id, $packet_id);
|
||||
|
||||
Self::decode(r)
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
impl crate::EncodePacket for $enum_name {
|
||||
fn encode_packet(&self, mut w: impl std::io::Write) -> crate::Result<()> {
|
||||
use crate::{Encode, VarInt};
|
||||
use crate::Encode;
|
||||
use crate::var_int::VarInt;
|
||||
|
||||
match self {
|
||||
$(
|
||||
|
@ -118,7 +180,8 @@ macro_rules! packet_enum {
|
|||
|
||||
impl crate::DecodePacket<'_> for $enum_name {
|
||||
fn decode_packet(r: &mut &[u8]) -> crate::Result<Self> {
|
||||
use crate::{Decode, VarInt};
|
||||
use crate::Decode;
|
||||
use crate::var_int::VarInt;
|
||||
|
||||
let id = VarInt::decode(r)?.0;
|
||||
Ok(match id {
|
||||
|
@ -126,7 +189,7 @@ macro_rules! packet_enum {
|
|||
<$packet as crate::DecodePacket>::PACKET_ID =>
|
||||
Self::$packet($packet::decode(r)?),
|
||||
)*
|
||||
id => anyhow::bail!("unknown packet ID {:#02x} while decoding {}", id, stringify!($enum_name)),
|
||||
id => anyhow::bail!("unknown packet ID {} while decoding {}", id, stringify!($enum_name)),
|
||||
})
|
||||
}
|
||||
}
|
205
crates/valence_protocol/src/packet/c2s.rs
Normal file
205
crates/valence_protocol/src/packet/c2s.rs
Normal file
|
@ -0,0 +1,205 @@
|
|||
pub mod handshake {
|
||||
pub use handshake::HandshakeC2s;
|
||||
|
||||
#[allow(clippy::module_inception)]
|
||||
pub mod handshake;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
C2sHandshakePacket<'a> {
|
||||
0 = HandshakeC2s<'a>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod status {
|
||||
pub use query_ping::QueryPingC2s;
|
||||
pub use query_request::QueryRequestC2s;
|
||||
|
||||
pub mod query_ping;
|
||||
pub mod query_request;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
C2sStatusPacket {
|
||||
0 = QueryRequestC2s,
|
||||
1 = QueryPingC2s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod login {
|
||||
pub use login_hello::LoginHelloC2s;
|
||||
pub use login_key::LoginKeyC2s;
|
||||
pub use login_query_response::LoginQueryResponseC2s;
|
||||
|
||||
pub mod login_hello;
|
||||
pub mod login_key;
|
||||
pub mod login_query_response;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
C2sLoginPacket<'a> {
|
||||
0 = LoginHelloC2s<'a>,
|
||||
1 = LoginKeyC2s<'a>,
|
||||
2 = LoginQueryResponseC2s<'a>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod play {
|
||||
pub use advancement_tab::AdvancementTabC2s;
|
||||
pub use boat_paddle::BoatPaddleStateC2s;
|
||||
pub use book_update::BookUpdateC2s;
|
||||
pub use button_click::ButtonClickC2s;
|
||||
pub use chat_message::ChatMessageC2s;
|
||||
pub use click_slot::ClickSlotC2s;
|
||||
pub use client_command::ClientCommandC2s;
|
||||
pub use client_settings::ClientSettingsC2s;
|
||||
pub use client_status::ClientStatusC2s;
|
||||
pub use close_handled_screen::CloseHandledScreenC2s;
|
||||
pub use command_execution::CommandExecutionC2s;
|
||||
pub use craft_request::CraftRequestC2s;
|
||||
pub use creative_inventory_action::CreativeInventoryActionC2s;
|
||||
pub use custom_payload::CustomPayloadC2s;
|
||||
pub use hand_swing::HandSwingC2s;
|
||||
pub use jigsaw_generating::JigsawGeneratingC2s;
|
||||
pub use keep_alive::KeepAliveC2s;
|
||||
pub use message_acknowledgment::MessageAcknowledgmentC2s;
|
||||
pub use pick_from_inventory::PickFromInventoryC2s;
|
||||
pub use play_pong::PlayPongC2s;
|
||||
pub use player_action::PlayerActionC2s;
|
||||
pub use player_input::PlayerInputC2s;
|
||||
pub use player_interact::PlayerInteractC2s;
|
||||
pub use player_interact_block::PlayerInteractBlockC2s;
|
||||
pub use player_interact_item::PlayerInteractItemC2s;
|
||||
pub use player_move::{FullC2s, LookAndOnGroundC2s, OnGroundOnlyC2s, PositionAndOnGroundC2s};
|
||||
pub use player_session::PlayerSessionC2s;
|
||||
pub use query_block_nbt::QueryBlockNbtC2s;
|
||||
pub use query_entity_nbt::QueryEntityNbtC2s;
|
||||
pub use recipe_book_data::RecipeBookDataC2s;
|
||||
pub use recipe_category_options::RecipeCategoryOptionsC2s;
|
||||
pub use rename_item::RenameItemC2s;
|
||||
pub use request_command_completions::RequestCommandCompletionsC2s;
|
||||
pub use resource_pack_status::ResourcePackStatusC2s;
|
||||
pub use select_merchant_trade::SelectMerchantTradeC2s;
|
||||
pub use spectator_teleport::SpectatorTeleportC2s;
|
||||
pub use teleport_confirm::TeleportConfirmC2s;
|
||||
pub use update_beacon::UpdateBeaconC2s;
|
||||
pub use update_command_block::UpdateCommandBlockC2s;
|
||||
pub use update_command_block_minecart::UpdateCommandBlockMinecartC2s;
|
||||
pub use update_difficulty::UpdateDifficultyC2s;
|
||||
pub use update_difficulty_lock::UpdateDifficultyLockC2s;
|
||||
pub use update_jigsaw::UpdateJigsawC2s;
|
||||
pub use update_player_abilities::UpdatePlayerAbilitiesC2s;
|
||||
pub use update_selected_slot::UpdateSelectedSlotC2s;
|
||||
pub use update_sign::UpdateSignC2s;
|
||||
pub use update_structure_block::UpdateStructureBlockC2s;
|
||||
pub use vehicle_move::VehicleMoveC2s;
|
||||
|
||||
pub mod advancement_tab;
|
||||
pub mod boat_paddle;
|
||||
pub mod book_update;
|
||||
pub mod button_click;
|
||||
pub mod chat_message;
|
||||
pub mod click_slot;
|
||||
pub mod client_command;
|
||||
pub mod client_settings;
|
||||
pub mod client_status;
|
||||
pub mod close_handled_screen;
|
||||
pub mod command_execution;
|
||||
pub mod craft_request;
|
||||
pub mod creative_inventory_action;
|
||||
pub mod custom_payload;
|
||||
pub mod hand_swing;
|
||||
pub mod jigsaw_generating;
|
||||
pub mod keep_alive;
|
||||
pub mod message_acknowledgment;
|
||||
pub mod pick_from_inventory;
|
||||
pub mod play_pong;
|
||||
pub mod player_action;
|
||||
pub mod player_input;
|
||||
pub mod player_interact;
|
||||
pub mod player_interact_block;
|
||||
pub mod player_interact_item;
|
||||
pub mod player_move;
|
||||
pub mod player_session;
|
||||
pub mod query_block_nbt;
|
||||
pub mod query_entity_nbt;
|
||||
pub mod recipe_book_data;
|
||||
pub mod recipe_category_options;
|
||||
pub mod rename_item;
|
||||
pub mod request_command_completions;
|
||||
pub mod resource_pack_status;
|
||||
pub mod select_merchant_trade;
|
||||
pub mod spectator_teleport;
|
||||
pub mod teleport_confirm;
|
||||
pub mod update_beacon;
|
||||
pub mod update_command_block;
|
||||
pub mod update_command_block_minecart;
|
||||
pub mod update_difficulty;
|
||||
pub mod update_difficulty_lock;
|
||||
pub mod update_jigsaw;
|
||||
pub mod update_player_abilities;
|
||||
pub mod update_selected_slot;
|
||||
pub mod update_sign;
|
||||
pub mod update_structure_block;
|
||||
pub mod vehicle_move;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
C2sPlayPacket<'a> {
|
||||
0 = TeleportConfirmC2s,
|
||||
1 = QueryBlockNbtC2s,
|
||||
2 = UpdateDifficultyC2s,
|
||||
3 = MessageAcknowledgmentC2s,
|
||||
4 = CommandExecutionC2s<'a>,
|
||||
5 = ChatMessageC2s<'a>,
|
||||
6 = ClientStatusC2s,
|
||||
7 = ClientSettingsC2s<'a>,
|
||||
8 = RequestCommandCompletionsC2s<'a>,
|
||||
9 = ButtonClickC2s,
|
||||
10 = ClickSlotC2s,
|
||||
11 = CloseHandledScreenC2s,
|
||||
12 = CustomPayloadC2s<'a>,
|
||||
13 = BookUpdateC2s<'a>,
|
||||
14 = QueryEntityNbtC2s,
|
||||
15 = PlayerInteractC2s,
|
||||
16 = JigsawGeneratingC2s,
|
||||
17 = KeepAliveC2s,
|
||||
18 = UpdateDifficultyLockC2s,
|
||||
19 = PositionAndOnGroundC2s,
|
||||
20 = FullC2s,
|
||||
21 = LookAndOnGroundC2s,
|
||||
22 = OnGroundOnlyC2s,
|
||||
23 = VehicleMoveC2s,
|
||||
24 = BoatPaddleStateC2s,
|
||||
25 = PickFromInventoryC2s,
|
||||
26 = CraftRequestC2s<'a>,
|
||||
27 = UpdatePlayerAbilitiesC2s,
|
||||
28 = PlayerActionC2s,
|
||||
29 = ClientCommandC2s,
|
||||
30 = PlayerInputC2s,
|
||||
31 = PlayPongC2s,
|
||||
32 = PlayerSessionC2s<'a>,
|
||||
33 = RecipeCategoryOptionsC2s,
|
||||
34 = RecipeBookDataC2s<'a>,
|
||||
35 = RenameItemC2s<'a>,
|
||||
36 = ResourcePackStatusC2s,
|
||||
37 = AdvancementTabC2s<'a>,
|
||||
38 = SelectMerchantTradeC2s,
|
||||
39 = UpdateBeaconC2s,
|
||||
40 = UpdateSelectedSlotC2s,
|
||||
41 = UpdateCommandBlockC2s<'a>,
|
||||
42 = UpdateCommandBlockMinecartC2s<'a>,
|
||||
43 = CreativeInventoryActionC2s,
|
||||
44 = UpdateJigsawC2s<'a>,
|
||||
45 = UpdateStructureBlockC2s<'a>,
|
||||
46 = UpdateSignC2s<'a>,
|
||||
47 = HandSwingC2s,
|
||||
48 = SpectatorTeleportC2s,
|
||||
49 = PlayerInteractBlockC2s,
|
||||
50 = PlayerInteractItemC2s
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct HandshakeC2s<'a> {
|
||||
pub protocol_version: VarInt,
|
||||
pub server_address: &'a str,
|
||||
pub server_port: u16,
|
||||
pub next_state: NextState,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Encode, Decode)]
|
||||
pub enum NextState {
|
||||
#[tag = 1]
|
||||
Status,
|
||||
#[tag = 2]
|
||||
Login,
|
||||
}
|
10
crates/valence_protocol/src/packet/c2s/login/login_hello.rs
Normal file
10
crates/valence_protocol/src/packet/c2s/login/login_hello.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::username::Username;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginHelloC2s<'a> {
|
||||
pub username: Username<&'a str>,
|
||||
pub profile_id: Option<Uuid>,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginKeyC2s<'a> {
|
||||
pub shared_secret: &'a [u8],
|
||||
pub verify_token: &'a [u8],
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::raw_bytes::RawBytes;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginQueryResponseC2s<'a> {
|
||||
pub message_id: VarInt,
|
||||
pub data: Option<RawBytes<'a>>,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::ident::Ident;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub enum AdvancementTabC2s<'a> {
|
||||
OpenedTab { tab_id: Ident<&'a str> },
|
||||
ClosedScreen,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct BoatPaddleStateC2s {
|
||||
pub left_paddle_turning: bool,
|
||||
pub right_paddle_turning: bool,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct BookUpdateC2s<'a> {
|
||||
pub slot: VarInt,
|
||||
pub entries: Vec<&'a str>,
|
||||
pub title: Option<&'a str>,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct ButtonClickC2s {
|
||||
pub window_id: i8,
|
||||
pub button_id: i8,
|
||||
}
|
15
crates/valence_protocol/src/packet/c2s/play/chat_message.rs
Normal file
15
crates/valence_protocol/src/packet/c2s/play/chat_message.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct ChatMessageC2s<'a> {
|
||||
pub message: &'a str,
|
||||
pub timestamp: u64,
|
||||
pub salt: u64,
|
||||
pub signature: Option<&'a [u8; 256]>,
|
||||
pub message_count: VarInt,
|
||||
// This is a bitset of 20; each bit represents one
|
||||
// of the last 20 messages received and whether or not
|
||||
// the message was acknowledged by the client
|
||||
pub acknowledgement: [u8; 3],
|
||||
}
|
31
crates/valence_protocol/src/packet/c2s/play/click_slot.rs
Normal file
31
crates/valence_protocol/src/packet/c2s/play/click_slot.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use crate::item::ItemStack;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct ClickSlotC2s {
|
||||
pub window_id: u8,
|
||||
pub state_id: VarInt,
|
||||
pub slot_idx: i16,
|
||||
pub button: i8,
|
||||
pub mode: ClickMode,
|
||||
pub slots: Vec<Slot>,
|
||||
pub carried_item: Option<ItemStack>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Encode, Decode)]
|
||||
pub enum ClickMode {
|
||||
Click,
|
||||
ShiftClick,
|
||||
Hotbar,
|
||||
CreativeMiddleClick,
|
||||
DropKey,
|
||||
Drag,
|
||||
DoubleClick,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct Slot {
|
||||
pub idx: i16,
|
||||
pub item: Option<ItemStack>,
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct ClientCommandC2s {
|
||||
pub entity_id: VarInt,
|
||||
pub action: Action,
|
||||
pub jump_boost: VarInt,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Action {
|
||||
StartSneaking,
|
||||
StopSneaking,
|
||||
LeaveBed,
|
||||
StartSprinting,
|
||||
StopSprinting,
|
||||
StartJumpWithHorse,
|
||||
StopJumpWithHorse,
|
||||
OpenHorseInventory,
|
||||
StartFlyingWithElytra,
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
use bitfield_struct::bitfield;
|
||||
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct ClientSettingsC2s<'a> {
|
||||
pub locale: &'a str,
|
||||
pub view_distance: u8,
|
||||
pub chat_mode: ChatMode,
|
||||
pub chat_colors: bool,
|
||||
pub displayed_skin_parts: DisplayedSkinParts,
|
||||
pub main_hand: MainHand,
|
||||
pub enable_text_filtering: bool,
|
||||
pub allow_server_listings: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum ChatMode {
|
||||
Enabled,
|
||||
CommandsOnly,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
#[bitfield(u8)]
|
||||
#[derive(PartialEq, Eq, Encode, Decode)]
|
||||
pub struct DisplayedSkinParts {
|
||||
pub cape: bool,
|
||||
pub jacket: bool,
|
||||
pub left_sleeve: bool,
|
||||
pub right_sleeve: bool,
|
||||
pub left_pants_leg: bool,
|
||||
pub right_pants_leg: bool,
|
||||
pub hat: bool,
|
||||
_pad: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Encode, Decode)]
|
||||
pub enum MainHand {
|
||||
Left,
|
||||
#[default]
|
||||
Right,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub enum ClientStatusC2s {
|
||||
PerformRespawn,
|
||||
RequestStats,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct CloseHandledScreenC2s {
|
||||
pub window_id: i8,
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct CommandExecutionC2s<'a> {
|
||||
pub command: &'a str,
|
||||
pub timestamp: u64,
|
||||
pub salt: u64,
|
||||
pub argument_signatures: Vec<CommandArgumentSignature<'a>>,
|
||||
pub message_count: VarInt,
|
||||
//// This is a bitset of 20; each bit represents one
|
||||
//// of the last 20 messages received and whether or not
|
||||
//// the message was acknowledged by the client
|
||||
pub acknowledgement: [u8; 3],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct CommandArgumentSignature<'a> {
|
||||
pub argument_name: &'a str,
|
||||
pub signature: &'a [u8; 256],
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::ident::Ident;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct CraftRequestC2s<'a> {
|
||||
pub window_id: i8,
|
||||
pub recipe: Ident<&'a str>,
|
||||
pub make_all: bool,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::item::ItemStack;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct CreativeInventoryActionC2s {
|
||||
pub slot: i16,
|
||||
pub clicked_item: Option<ItemStack>,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::ident::Ident;
|
||||
use crate::raw_bytes::RawBytes;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct CustomPayloadC2s<'a> {
|
||||
pub channel: Ident<&'a str>,
|
||||
pub data: RawBytes<'a>,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::types::Hand;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct HandSwingC2s {
|
||||
pub hand: Hand,
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
use crate::block_pos::BlockPos;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct JigsawGeneratingC2s {
|
||||
pub position: BlockPos,
|
||||
pub levels: VarInt,
|
||||
pub keep_jigsaws: bool,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct KeepAliveC2s {
|
||||
pub id: u64,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct MessageAcknowledgmentC2s {
|
||||
pub message_count: VarInt,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PickFromInventoryC2s {
|
||||
pub slot_to_use: VarInt,
|
||||
}
|
6
crates/valence_protocol/src/packet/c2s/play/play_pong.rs
Normal file
6
crates/valence_protocol/src/packet/c2s/play/play_pong.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayPongC2s {
|
||||
pub id: i32,
|
||||
}
|
23
crates/valence_protocol/src/packet/c2s/play/player_action.rs
Normal file
23
crates/valence_protocol/src/packet/c2s/play/player_action.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use crate::block_pos::BlockPos;
|
||||
use crate::types::Direction;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayerActionC2s {
|
||||
pub action: Action,
|
||||
pub position: BlockPos,
|
||||
pub direction: Direction,
|
||||
pub sequence: VarInt,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Action {
|
||||
StartDestroyBlock,
|
||||
AbortDestroyBlock,
|
||||
StopDestroyBlock,
|
||||
DropAllItems,
|
||||
DropItem,
|
||||
ReleaseUseItem,
|
||||
SwapItemWithOffhand,
|
||||
}
|
19
crates/valence_protocol/src/packet/c2s/play/player_input.rs
Normal file
19
crates/valence_protocol/src/packet/c2s/play/player_input.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use bitfield_struct::bitfield;
|
||||
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayerInputC2s {
|
||||
pub sideways: f32,
|
||||
pub forward: f32,
|
||||
pub flags: Flags,
|
||||
}
|
||||
|
||||
#[bitfield(u8)]
|
||||
#[derive(PartialEq, Eq, Encode, Decode)]
|
||||
pub struct Flags {
|
||||
pub jump: bool,
|
||||
pub unmount: bool,
|
||||
#[bits(6)]
|
||||
_pad: u8,
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
use crate::types::Hand;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayerInteractC2s {
|
||||
pub entity_id: VarInt,
|
||||
pub interact: Interaction,
|
||||
pub sneaking: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Encode, Decode)]
|
||||
pub enum Interaction {
|
||||
Interact(Hand),
|
||||
Attack,
|
||||
InteractAt { target: [f32; 3], hand: Hand },
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
use crate::block_pos::BlockPos;
|
||||
use crate::types::{Direction, Hand};
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayerInteractBlockC2s {
|
||||
pub hand: Hand,
|
||||
pub position: BlockPos,
|
||||
pub face: Direction,
|
||||
pub cursor_pos: [f32; 3],
|
||||
pub head_inside_block: bool,
|
||||
pub sequence: VarInt,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::types::Hand;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayerInteractItemC2s {
|
||||
pub hand: Hand,
|
||||
pub sequence: VarInt,
|
||||
}
|
27
crates/valence_protocol/src/packet/c2s/play/player_move.rs
Normal file
27
crates/valence_protocol/src/packet/c2s/play/player_move.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PositionAndOnGroundC2s {
|
||||
pub position: [f64; 3],
|
||||
pub on_ground: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct FullC2s {
|
||||
pub position: [f64; 3],
|
||||
pub yaw: f32,
|
||||
pub pitch: f32,
|
||||
pub on_ground: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct LookAndOnGroundC2s {
|
||||
pub yaw: f32,
|
||||
pub pitch: f32,
|
||||
pub on_ground: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct OnGroundOnlyC2s {
|
||||
pub on_ground: bool,
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct PlayerSessionC2s<'a> {
|
||||
pub session_id: Uuid,
|
||||
// Public key
|
||||
pub expires_at: i64,
|
||||
pub public_key_data: &'a [u8],
|
||||
pub key_signature: &'a [u8],
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::block_pos::BlockPos;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct QueryBlockNbtC2s {
|
||||
pub transaction_id: VarInt,
|
||||
pub position: BlockPos,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct QueryEntityNbtC2s {
|
||||
pub transaction_id: VarInt,
|
||||
pub entity_id: VarInt,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::ident::Ident;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct RecipeBookDataC2s<'a> {
|
||||
pub recipe_id: Ident<&'a str>,
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct RecipeCategoryOptionsC2s {
|
||||
pub book_id: RecipeBookId,
|
||||
pub book_open: bool,
|
||||
pub filter_active: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum RecipeBookId {
|
||||
Crafting,
|
||||
Furnace,
|
||||
BlastFurnace,
|
||||
Smoker,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct RenameItemC2s<'a> {
|
||||
pub item_name: &'a str,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct RequestCommandCompletionsC2s<'a> {
|
||||
pub transaction_id: VarInt,
|
||||
pub text: &'a str,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub enum ResourcePackStatusC2s {
|
||||
SuccessfullyLoaded,
|
||||
Declined,
|
||||
FailedDownload,
|
||||
Accepted,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct SelectMerchantTradeC2s {
|
||||
pub selected_slot: VarInt,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct SpectatorTeleportC2s {
|
||||
pub target: Uuid,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct TeleportConfirmC2s {
|
||||
pub teleport_id: VarInt,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateBeaconC2s {
|
||||
// TODO: extract effect IDs?
|
||||
pub primary_effect: Option<VarInt>,
|
||||
pub secondary_effect: Option<VarInt>,
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
use bitfield_struct::bitfield;
|
||||
|
||||
use crate::block_pos::BlockPos;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateCommandBlockC2s<'a> {
|
||||
pub position: BlockPos,
|
||||
pub command: &'a str,
|
||||
pub mode: Mode,
|
||||
pub flags: Flags,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Mode {
|
||||
Sequence,
|
||||
Auto,
|
||||
Redstone,
|
||||
}
|
||||
|
||||
#[bitfield(u8)]
|
||||
#[derive(PartialEq, Eq, Encode, Decode)]
|
||||
pub struct Flags {
|
||||
pub track_output: bool,
|
||||
pub conditional: bool,
|
||||
pub automatic: bool,
|
||||
#[bits(5)]
|
||||
_pad: u8,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateCommandBlockMinecartC2s<'a> {
|
||||
pub entity_id: VarInt,
|
||||
pub command: &'a str,
|
||||
pub track_output: bool,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::types::Difficulty;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub struct UpdateDifficultyC2s {
|
||||
pub difficulty: Difficulty,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateDifficultyLockC2s {
|
||||
pub locked: bool,
|
||||
}
|
13
crates/valence_protocol/src/packet/c2s/play/update_jigsaw.rs
Normal file
13
crates/valence_protocol/src/packet/c2s/play/update_jigsaw.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use crate::block_pos::BlockPos;
|
||||
use crate::ident::Ident;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateJigsawC2s<'a> {
|
||||
pub position: BlockPos,
|
||||
pub name: Ident<&'a str>,
|
||||
pub target: Ident<&'a str>,
|
||||
pub pool: Ident<&'a str>,
|
||||
pub final_state: &'a str,
|
||||
pub joint_type: &'a str,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub enum UpdatePlayerAbilitiesC2s {
|
||||
#[tag = 0b00]
|
||||
StopFlying,
|
||||
#[tag = 0b10]
|
||||
StartFlying,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateSelectedSlotC2s {
|
||||
pub slot: i16,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::block_pos::BlockPos;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateSignC2s<'a> {
|
||||
pub position: BlockPos,
|
||||
pub lines: [&'a str; 4],
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
use bitfield_struct::bitfield;
|
||||
|
||||
use crate::block_pos::BlockPos;
|
||||
use crate::var_long::VarLong;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct UpdateStructureBlockC2s<'a> {
|
||||
pub position: BlockPos,
|
||||
pub action: Action,
|
||||
pub mode: Mode,
|
||||
pub name: &'a str,
|
||||
pub offset_xyz: [i8; 3],
|
||||
pub size_xyz: [i8; 3],
|
||||
pub mirror: Mirror,
|
||||
pub rotation: Rotation,
|
||||
pub metadata: &'a str,
|
||||
pub integrity: f32,
|
||||
pub seed: VarLong,
|
||||
pub flags: Flags,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Action {
|
||||
UpdateData,
|
||||
SaveStructure,
|
||||
LoadStructure,
|
||||
DetectSize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Mode {
|
||||
Save,
|
||||
Load,
|
||||
Corner,
|
||||
Data,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Mirror {
|
||||
None,
|
||||
LeftRight,
|
||||
FrontBack,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub enum Rotation {
|
||||
None,
|
||||
Clockwise90,
|
||||
Clockwise180,
|
||||
Counterclockwise90,
|
||||
}
|
||||
|
||||
#[bitfield(u8)]
|
||||
#[derive(PartialEq, Eq, Encode, Decode)]
|
||||
pub struct Flags {
|
||||
pub ignore_entities: bool,
|
||||
pub show_air: bool,
|
||||
pub show_bounding_box: bool,
|
||||
#[bits(5)]
|
||||
_pad: u8,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct VehicleMoveC2s {
|
||||
pub position: [f64; 3],
|
||||
pub yaw: f32,
|
||||
pub pitch: f32,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct QueryPingC2s {
|
||||
pub payload: u64,
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct QueryRequestC2s;
|
367
crates/valence_protocol/src/packet/s2c.rs
Normal file
367
crates/valence_protocol/src/packet/s2c.rs
Normal file
|
@ -0,0 +1,367 @@
|
|||
pub mod status {
|
||||
pub use query_pong::QueryPongS2c;
|
||||
pub use query_response::QueryResponseS2c;
|
||||
|
||||
pub mod query_pong;
|
||||
pub mod query_response;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
S2cStatusPacket<'a> {
|
||||
0 = QueryResponseS2c<'a>,
|
||||
1 = QueryPongS2c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod login {
|
||||
pub use login_compression::LoginCompressionS2c;
|
||||
pub use login_disconnect::LoginDisconnectS2c;
|
||||
pub use login_hello::LoginHelloS2c;
|
||||
pub use login_query_request::LoginQueryRequestS2c;
|
||||
pub use login_success::LoginSuccessS2c;
|
||||
|
||||
pub mod login_compression;
|
||||
pub mod login_disconnect;
|
||||
pub mod login_hello;
|
||||
pub mod login_query_request;
|
||||
pub mod login_success;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
S2cLoginPacket<'a> {
|
||||
0 = LoginDisconnectS2c<'a>,
|
||||
1 = LoginHelloS2c<'a>,
|
||||
2 = LoginSuccessS2c<'a>,
|
||||
3 = LoginCompressionS2c,
|
||||
4 = LoginQueryRequestS2c<'a>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod play {
|
||||
pub use advancement_update::AdvancementUpdateS2c;
|
||||
pub use block_breaking_progress::BlockBreakingProgressS2c;
|
||||
pub use block_entity_update::BlockEntityUpdateS2c;
|
||||
pub use block_event::BlockEventS2c;
|
||||
pub use block_update::BlockUpdateS2c;
|
||||
pub use boss_bar::BossBarS2c;
|
||||
pub use chat_message::ChatMessageS2c;
|
||||
pub use chat_suggestions::ChatSuggestionsS2c;
|
||||
pub use chunk_data::ChunkDataS2c;
|
||||
pub use chunk_delta_update::ChunkDeltaUpdateS2c;
|
||||
pub use chunk_load_distance::ChunkLoadDistanceS2c;
|
||||
pub use chunk_render_distance_center::ChunkRenderDistanceCenterS2c;
|
||||
pub use clear_titles::ClearTitlesS2c;
|
||||
pub use close_screen::CloseScreenS2c;
|
||||
pub use command_suggestions::CommandSuggestionsS2c;
|
||||
pub use command_tree::CommandTreeS2c;
|
||||
pub use cooldown_update::CooldownUpdateS2c;
|
||||
pub use craft_failed_response::CraftFailedResponseS2c;
|
||||
pub use custom_payload::CustomPayloadS2c;
|
||||
pub use death_message::DeathMessageS2c;
|
||||
pub use difficulty::DifficultyS2c;
|
||||
pub use disconnect::DisconnectS2c;
|
||||
pub use end_combat::EndCombatS2c;
|
||||
pub use enter_combat::EnterCombatS2c;
|
||||
pub use entities_destroy::EntitiesDestroyS2c;
|
||||
pub use entity::{MoveRelativeS2c, RotateAndMoveRelativeS2c, RotateS2c};
|
||||
pub use entity_animation::EntityAnimationS2c;
|
||||
pub use entity_attach::EntityAttachS2c;
|
||||
pub use entity_attributes::EntityAttributesS2c;
|
||||
pub use entity_equipment_update::EntityEquipmentUpdateS2c;
|
||||
pub use entity_passengers_set::EntityPassengersSetS2c;
|
||||
pub use entity_position::EntityPositionS2c;
|
||||
pub use entity_set_head_yaw::EntitySetHeadYawS2c;
|
||||
pub use entity_spawn::EntitySpawnS2c;
|
||||
pub use entity_status::EntityStatusS2c;
|
||||
pub use entity_status_effect::EntityStatusEffectS2c;
|
||||
pub use entity_tracker_update::EntityTrackerUpdateS2c;
|
||||
pub use entity_velocity_update::EntityVelocityUpdateS2c;
|
||||
pub use experience_bar_update::ExperienceBarUpdateS2c;
|
||||
pub use experience_orb_spawn::ExperienceOrbSpawnS2c;
|
||||
pub use explosion::ExplosionS2c;
|
||||
pub use features::FeaturesS2c;
|
||||
pub use game_join::GameJoinS2c;
|
||||
pub use game_message::GameMessageS2c;
|
||||
pub use game_state_change::GameStateChangeS2c;
|
||||
pub use health_update::HealthUpdateS2c;
|
||||
pub use inventory::InventoryS2c;
|
||||
pub use item_pickup_animation::ItemPickupAnimationS2c;
|
||||
pub use keep_alive::KeepAliveS2c;
|
||||
pub use light_update::LightUpdateS2c;
|
||||
pub use look_at::LookAtS2c;
|
||||
pub use map_update::MapUpdateS2c;
|
||||
pub use nbt_query_response::NbtQueryResponseS2c;
|
||||
pub use open_horse_screen::OpenHorseScreenS2c;
|
||||
pub use open_screen::OpenScreenS2c;
|
||||
pub use open_written_book::OpenWrittenBookS2c;
|
||||
pub use overlay_message::OverlayMessageS2c;
|
||||
pub use particle::ParticleS2c;
|
||||
pub use play_ping::PlayPingS2c;
|
||||
pub use play_sound::PlaySoundS2c;
|
||||
pub use play_sound_from_entity::PlaySoundFromEntityS2c;
|
||||
pub use player_abilities::PlayerAbilitiesS2c;
|
||||
pub use player_action_response::PlayerActionResponseS2c;
|
||||
pub use player_list::PlayerListS2c;
|
||||
pub use player_list_header::PlayerListHeaderS2c;
|
||||
pub use player_position_look::PlayerPositionLookS2c;
|
||||
pub use player_remove::PlayerRemoveS2c;
|
||||
pub use player_respawn::PlayerRespawnS2c;
|
||||
pub use player_spawn::PlayerSpawnS2c;
|
||||
pub use player_spawn_position::PlayerSpawnPositionS2c;
|
||||
pub use profileless_chat_message::ProfilelessChatMessageS2c;
|
||||
pub use remove_entity_status_effect::RemoveEntityStatusEffectS2c;
|
||||
pub use remove_message::RemoveMessageS2c;
|
||||
pub use resource_pack_send::ResourcePackSendS2c;
|
||||
pub use scoreboard_display::ScoreboardDisplayS2c;
|
||||
pub use scoreboard_objective_update::ScoreboardObjectiveUpdateS2c;
|
||||
pub use scoreboard_player_update::ScoreboardPlayerUpdateS2c;
|
||||
pub use screen_handler_property_update::ScreenHandlerPropertyUpdateS2c;
|
||||
pub use screen_handler_slot_update::ScreenHandlerSlotUpdateS2c;
|
||||
pub use select_advancements_tab::SelectAdvancementsTabS2c;
|
||||
pub use server_metadata::ServerMetadataS2c;
|
||||
pub use set_camera_entity::SetCameraEntityS2c;
|
||||
pub use set_trade_offers::SetTradeOffersS2c;
|
||||
pub use sign_editor_open::SignEditorOpen;
|
||||
pub use simulation_distance::SimulationDistanceS2c;
|
||||
pub use statistics::StatisticsS2c;
|
||||
pub use stop_sound::StopSoundS2c;
|
||||
pub use subtitle::SubtitleS2c;
|
||||
pub use synchronize_recipes::SynchronizeRecipesS2c;
|
||||
pub use synchronize_tags::SynchronizeTagsS2c;
|
||||
pub use team::TeamS2c;
|
||||
pub use title::TitleS2c;
|
||||
pub use title_fade::TitleFadeS2c;
|
||||
pub use unload_chunk::UnloadChunkS2c;
|
||||
pub use unlock_recipes::UnlockRecipesS2c;
|
||||
pub use update_selected_slot::UpdateSelectedSlotS2c;
|
||||
pub use vehicle_move::VehicleMoveS2c;
|
||||
pub use world_border_center_changed::WorldBorderCenterChangedS2c;
|
||||
pub use world_border_initialize::WorldBorderInitializeS2c;
|
||||
pub use world_border_interpolate_size::WorldBorderInterpolateSizeS2c;
|
||||
pub use world_border_size_changed::WorldBorderSizeChangedS2c;
|
||||
pub use world_border_warning_blocks_changed::WorldBorderWarningBlocksChangedS2c;
|
||||
pub use world_border_warning_time_changed::WorldBorderWarningTimeChangedS2c;
|
||||
pub use world_event::WorldEventS2c;
|
||||
pub use world_time_update::WorldTimeUpdateS2c;
|
||||
|
||||
pub mod advancement_update;
|
||||
pub mod block_breaking_progress;
|
||||
pub mod block_entity_update;
|
||||
pub mod block_event;
|
||||
pub mod block_update;
|
||||
pub mod boss_bar;
|
||||
pub mod chat_message;
|
||||
pub mod chat_suggestions;
|
||||
pub mod chunk_data;
|
||||
pub mod chunk_delta_update;
|
||||
pub mod chunk_load_distance;
|
||||
pub mod chunk_render_distance_center;
|
||||
pub mod clear_titles;
|
||||
pub mod close_screen;
|
||||
pub mod command_suggestions;
|
||||
pub mod command_tree;
|
||||
pub mod cooldown_update;
|
||||
pub mod craft_failed_response;
|
||||
pub mod custom_payload;
|
||||
pub mod death_message;
|
||||
pub mod difficulty;
|
||||
pub mod disconnect;
|
||||
pub mod end_combat;
|
||||
pub mod enter_combat;
|
||||
pub mod entities_destroy;
|
||||
pub mod entity;
|
||||
pub mod entity_animation;
|
||||
pub mod entity_attach;
|
||||
pub mod entity_attributes;
|
||||
pub mod entity_equipment_update;
|
||||
pub mod entity_passengers_set;
|
||||
pub mod entity_position;
|
||||
pub mod entity_set_head_yaw;
|
||||
pub mod entity_spawn;
|
||||
pub mod entity_status;
|
||||
pub mod entity_status_effect;
|
||||
pub mod entity_tracker_update;
|
||||
pub mod entity_velocity_update;
|
||||
pub mod experience_bar_update;
|
||||
pub mod experience_orb_spawn;
|
||||
pub mod explosion;
|
||||
pub mod features;
|
||||
pub mod game_join;
|
||||
pub mod game_message;
|
||||
pub mod game_state_change;
|
||||
pub mod health_update;
|
||||
pub mod inventory;
|
||||
pub mod item_pickup_animation;
|
||||
pub mod keep_alive;
|
||||
pub mod light_update;
|
||||
pub mod look_at;
|
||||
pub mod map_update;
|
||||
pub mod nbt_query_response;
|
||||
pub mod open_horse_screen;
|
||||
pub mod open_screen;
|
||||
pub mod open_written_book;
|
||||
pub mod overlay_message;
|
||||
pub mod particle;
|
||||
pub mod play_ping;
|
||||
pub mod play_sound;
|
||||
pub mod play_sound_from_entity;
|
||||
pub mod player_abilities;
|
||||
pub mod player_action_response;
|
||||
pub mod player_list;
|
||||
pub mod player_list_header;
|
||||
pub mod player_position_look;
|
||||
pub mod player_remove;
|
||||
pub mod player_respawn;
|
||||
pub mod player_spawn;
|
||||
pub mod player_spawn_position;
|
||||
pub mod profileless_chat_message;
|
||||
pub mod remove_entity_status_effect;
|
||||
pub mod remove_message;
|
||||
pub mod resource_pack_send;
|
||||
pub mod scoreboard_display;
|
||||
pub mod scoreboard_objective_update;
|
||||
pub mod scoreboard_player_update;
|
||||
pub mod screen_handler_property_update;
|
||||
pub mod screen_handler_slot_update;
|
||||
pub mod select_advancements_tab;
|
||||
pub mod server_metadata;
|
||||
pub mod set_camera_entity;
|
||||
pub mod set_trade_offers;
|
||||
pub mod sign_editor_open;
|
||||
pub mod simulation_distance;
|
||||
pub mod statistics;
|
||||
pub mod stop_sound;
|
||||
pub mod subtitle;
|
||||
pub mod synchronize_recipes;
|
||||
pub mod synchronize_tags;
|
||||
pub mod team;
|
||||
pub mod title;
|
||||
pub mod title_fade;
|
||||
pub mod unload_chunk;
|
||||
pub mod unlock_recipes;
|
||||
pub mod update_selected_slot;
|
||||
pub mod vehicle_move;
|
||||
pub mod world_border_center_changed;
|
||||
pub mod world_border_initialize;
|
||||
pub mod world_border_interpolate_size;
|
||||
pub mod world_border_size_changed;
|
||||
pub mod world_border_warning_blocks_changed;
|
||||
pub mod world_border_warning_time_changed;
|
||||
pub mod world_event;
|
||||
pub mod world_time_update;
|
||||
|
||||
packet_group! {
|
||||
#[derive(Clone)]
|
||||
S2cPlayPacket<'a> {
|
||||
0 = EntitySpawnS2c,
|
||||
1 = ExperienceOrbSpawnS2c,
|
||||
2 = PlayerSpawnS2c,
|
||||
3 = EntityAnimationS2c,
|
||||
4 = StatisticsS2c,
|
||||
5 = PlayerActionResponseS2c,
|
||||
6 = BlockBreakingProgressS2c,
|
||||
7 = BlockEntityUpdateS2c<'a>,
|
||||
8 = BlockEventS2c,
|
||||
9 = BlockUpdateS2c,
|
||||
10 = BossBarS2c,
|
||||
11 = DifficultyS2c,
|
||||
12 = ClearTitlesS2c,
|
||||
13 = CommandSuggestionsS2c<'a>,
|
||||
14 = CommandTreeS2c<'a>,
|
||||
15 = CloseScreenS2c,
|
||||
16 = InventoryS2c<'a>,
|
||||
17 = ScreenHandlerPropertyUpdateS2c,
|
||||
18 = ScreenHandlerSlotUpdateS2c<'a>,
|
||||
19 = CooldownUpdateS2c,
|
||||
20 = ChatSuggestionsS2c<'a>,
|
||||
21 = CustomPayloadS2c<'a>,
|
||||
22 = RemoveMessageS2c<'a>,
|
||||
23 = DisconnectS2c<'a>,
|
||||
24 = ProfilelessChatMessageS2c<'a>,
|
||||
25 = EntityStatusS2c,
|
||||
26 = ExplosionS2c<'a>,
|
||||
27 = UnloadChunkS2c,
|
||||
28 = GameStateChangeS2c,
|
||||
29 = OpenHorseScreenS2c,
|
||||
30 = WorldBorderInitializeS2c,
|
||||
31 = KeepAliveS2c,
|
||||
32 = ChunkDataS2c<'a>,
|
||||
33 = WorldEventS2c,
|
||||
34 = LightUpdateS2c,
|
||||
35 = ParticleS2c<'a>,
|
||||
36 = GameJoinS2c<'a>,
|
||||
37 = MapUpdateS2c<'a>,
|
||||
38 = SetTradeOffersS2c,
|
||||
39 = MoveRelativeS2c,
|
||||
40 = RotateAndMoveRelativeS2c,
|
||||
41 = RotateS2c,
|
||||
42 = VehicleMoveS2c,
|
||||
43 = OpenWrittenBookS2c,
|
||||
44 = OpenScreenS2c<'a>,
|
||||
45 = SignEditorOpen,
|
||||
46 = PlayPingS2c,
|
||||
47 = CraftFailedResponseS2c<'a>,
|
||||
48 = PlayerAbilitiesS2c,
|
||||
49 = ChatMessageS2c<'a>,
|
||||
50 = EndCombatS2c,
|
||||
51 = EnterCombatS2c,
|
||||
52 = DeathMessageS2c<'a>,
|
||||
53 = PlayerRemoveS2c<'a>,
|
||||
54 = PlayerListS2c<'a>,
|
||||
55 = LookAtS2c,
|
||||
56 = PlayerPositionLookS2c,
|
||||
57 = UnlockRecipesS2c<'a>,
|
||||
58 = EntitiesDestroyS2c<'a>,
|
||||
59 = RemoveEntityStatusEffectS2c,
|
||||
60 = ResourcePackSendS2c<'a>,
|
||||
61 = PlayerRespawnS2c<'a>,
|
||||
62 = EntitySetHeadYawS2c,
|
||||
63 = ChunkDeltaUpdateS2c<'a>,
|
||||
64 = SelectAdvancementsTabS2c<'a>,
|
||||
65 = ServerMetadataS2c<'a>,
|
||||
66 = OverlayMessageS2c<'a>,
|
||||
67 = WorldBorderCenterChangedS2c,
|
||||
68 = WorldBorderInterpolateSizeS2c,
|
||||
69 = WorldBorderSizeChangedS2c,
|
||||
70 = WorldBorderWarningTimeChangedS2c,
|
||||
71 = WorldBorderWarningBlocksChangedS2c,
|
||||
72 = SetCameraEntityS2c,
|
||||
73 = UpdateSelectedSlotS2c,
|
||||
74 = ChunkRenderDistanceCenterS2c,
|
||||
75 = ChunkLoadDistanceS2c,
|
||||
76 = PlayerSpawnPositionS2c,
|
||||
77 = ScoreboardDisplayS2c<'a>,
|
||||
78 = EntityTrackerUpdateS2c<'a>,
|
||||
79 = EntityAttachS2c,
|
||||
80 = EntityVelocityUpdateS2c,
|
||||
81 = EntityEquipmentUpdateS2c,
|
||||
82 = ExperienceBarUpdateS2c,
|
||||
83 = HealthUpdateS2c,
|
||||
84 = ScoreboardObjectiveUpdateS2c<'a>,
|
||||
85 = EntityPassengersSetS2c,
|
||||
86 = TeamS2c<'a>,
|
||||
87 = ScoreboardPlayerUpdateS2c<'a>,
|
||||
88 = SimulationDistanceS2c,
|
||||
89 = SubtitleS2c<'a>,
|
||||
90 = WorldTimeUpdateS2c,
|
||||
91 = TitleS2c<'a>,
|
||||
92 = TitleFadeS2c,
|
||||
93 = PlaySoundFromEntityS2c,
|
||||
94 = PlaySoundS2c<'a>,
|
||||
95 = StopSoundS2c<'a>,
|
||||
96 = GameMessageS2c<'a>,
|
||||
97 = PlayerListHeaderS2c<'a>,
|
||||
98 = NbtQueryResponseS2c,
|
||||
99 = ItemPickupAnimationS2c,
|
||||
100 = EntityPositionS2c,
|
||||
101 = AdvancementUpdateS2c<'a>,
|
||||
102 = EntityAttributesS2c<'a>,
|
||||
103 = FeaturesS2c<'a>,
|
||||
104 = EntityStatusEffectS2c,
|
||||
105 = SynchronizeRecipesS2c<'a>,
|
||||
106 = SynchronizeTagsS2c<'a>,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginCompressionS2c {
|
||||
pub threshold: VarInt,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::text::Text;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginDisconnectS2c<'a> {
|
||||
pub reason: Cow<'a, Text>,
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginHelloS2c<'a> {
|
||||
pub server_id: &'a str,
|
||||
pub public_key: &'a [u8],
|
||||
pub verify_token: &'a [u8],
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
use crate::ident::Ident;
|
||||
use crate::raw_bytes::RawBytes;
|
||||
use crate::var_int::VarInt;
|
||||
use crate::{Decode, Encode};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||
pub struct LoginQueryRequestS2c<'a> {
|
||||
pub message_id: VarInt,
|
||||
pub channel: Ident<&'a str>,
|
||||
pub data: RawBytes<'a>,
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue