Update to 1.19

Authentication is currently broken. Looks like the EncryptionResponse
packet changed.
This commit is contained in:
Ryan 2022-06-21 04:55:32 -07:00
parent 8ad9c8587a
commit c86b8286ce
11 changed files with 15445 additions and 13853 deletions

View file

@ -41,9 +41,14 @@ enum Type {
Nbt,
Particle,
VillagerData,
Pose,
// ==== Specialized ==== //
/// Also known as OptVarInt
OptEntityId,
Pose,
CatVariant,
FrogVariant,
OptGlobalPosition,
PaintingVariant,
// ==== Specialized ==== //
BoatVariant,
MainHand,
}
@ -83,8 +88,12 @@ impl Type {
Type::Nbt => quote! { nbt::Blob::new() },
Type::Particle => quote! { () }, // TODO
Type::VillagerData => quote! { VillagerData::default() },
Type::Pose => quote! { Pose::default() },
Type::OptEntityId => quote! { None },
Type::Pose => quote! { Pose::default() },
Type::CatVariant => quote! { CatVariant::default() },
Type::FrogVariant => quote! { FrogVariant::default() },
Type::OptGlobalPosition => quote! { () }, // TODO
Type::PaintingVariant => quote! { PaintingVariant::default() },
Type::BoatVariant => quote! { BoatVariant::default() },
Type::MainHand => quote! { MainHand::default() },
}
@ -110,8 +119,12 @@ impl Type {
Type::Nbt => 14,
Type::Particle => 15,
Type::VillagerData => 16,
Type::Pose => 18,
Type::OptEntityId => 17,
Type::Pose => 18,
Type::CatVariant => 19,
Type::FrogVariant => 20,
Type::OptGlobalPosition => 21,
Type::PaintingVariant => 22,
Type::BoatVariant => 1,
Type::MainHand => 0,
}
@ -225,6 +238,56 @@ const ABSTRACT_ARROW: Class = Class {
],
};
const ITEM_FRAME: Class = Class {
name: "item_frame",
inherit: Some(&BASE_ENTITY),
fields: &[
Field {
name: "item",
typ: Type::Slot,
},
Field {
name: "rotation",
typ: Type::VarInt(0), // TODO: Direction enum?
},
],
};
const BOAT: Class = Class {
name: "boat",
inherit: Some(&BASE_ENTITY),
fields: &[
Field {
name: "last_hit_ticks",
typ: Type::VarInt(0),
},
Field {
name: "forward_direction",
typ: Type::VarInt(1), // TODO: direction enum?
},
Field {
name: "damage_taken",
typ: Type::Float(0.0),
},
Field {
name: "typ",
typ: Type::BoatVariant,
},
Field {
name: "left_paddle_turning",
typ: Type::Bool(false),
},
Field {
name: "right_paddle_turning",
typ: Type::Bool(false),
},
Field {
name: "splash_timer",
typ: Type::VarInt(0),
},
],
};
const LIVING_ENTITY: Class = Class {
name: "living_entity",
inherit: Some(&BASE_ENTITY),
@ -566,6 +629,11 @@ const ABSTRACT_MINECART_CONTAINER: Class = Class {
};
const ENTITIES: &[Class] = &[
Class {
name: "allay",
inherit: Some(&PATHFINDER_MOB),
fields: &[], // TODO: fields?
},
Class {
// TODO: how is this defined?
name: "leash_knot",
@ -583,11 +651,6 @@ const ENTITIES: &[Class] = &[
inherit: None,
fields: &[],
},
Class {
name: "painting",
inherit: None,
fields: &[],
},
Class {
name: "marker",
inherit: None,
@ -717,39 +780,21 @@ const ENTITIES: &[Class] = &[
},
],
},
BOAT,
Class {
name: "boat",
inherit: Some(&BASE_ENTITY),
fields: &[
Field {
name: "last_hit_ticks",
typ: Type::VarInt(0),
},
Field {
name: "forward_direction",
typ: Type::VarInt(1), // TODO: direction enum?
},
Field {
name: "damage_taken",
typ: Type::Float(0.0),
},
Field {
name: "typ",
typ: Type::BoatVariant,
},
Field {
name: "left_paddle_turning",
typ: Type::Bool(false),
},
Field {
name: "right_paddle_turning",
typ: Type::Bool(false),
},
Field {
name: "splash_timer",
typ: Type::VarInt(0),
},
],
name: "chest_boat",
inherit: Some(&BOAT),
fields: &[],
},
Class {
name: "tadpole",
inherit: Some(&ABSTRACT_FISH),
fields: &[],
},
Class {
name: "warden",
inherit: Some(&MONSTER),
fields: &[], // TODO: warden anger
},
Class {
name: "end_crystal",
@ -812,34 +857,19 @@ const ENTITIES: &[Class] = &[
},
],
},
ITEM_FRAME,
Class {
name: "item_frame",
inherit: Some(&BASE_ENTITY),
fields: &[
Field {
name: "item",
typ: Type::Slot,
},
Field {
name: "rotation",
typ: Type::VarInt(0), // TODO: Direction enum?
},
],
name: "glow_item_frame",
inherit: Some(&ITEM_FRAME),
fields: &[],
},
Class {
// TODO: How is glow item frame defined? This is a guess.
name: "glow_item_frame",
name: "painting",
inherit: Some(&BASE_ENTITY),
fields: &[
Field {
name: "item",
typ: Type::Slot,
},
Field {
name: "rotation",
typ: Type::VarInt(0), // TODO: Direction enum?
},
],
fields: &[Field {
name: "variant",
typ: Type::PaintingVariant,
}],
},
Class {
name: "player",
@ -905,6 +935,10 @@ const ENTITIES: &[Class] = &[
name: "right_shoulder_entity_data",
typ: Type::Nbt,
},
Field {
name: "global_position",
typ: Type::OptGlobalPosition,
}
],
},
Class {
@ -1187,6 +1221,20 @@ const ENTITIES: &[Class] = &[
},
],
},
Class {
name: "frog",
inherit: Some(&ANIMAL),
fields: &[
Field {
name: "variant",
typ: Type::FrogVariant,
},
Field {
name: "tongue_target",
typ: Type::VarInt(0),
}
],
},
Class {
name: "ocelot",
inherit: Some(&ANIMAL),
@ -1339,7 +1387,20 @@ const ENTITIES: &[Class] = &[
Class {
name: "goat",
inherit: Some(&ANIMAL),
fields: &[], // TODO: What are the goat fields?
fields: &[
Field {
name: "screaming",
typ: Type::Bool(false),
},
Field {
name: "left_horn",
typ: Type::Bool(true),
},
Field {
name: "right_horn",
typ: Type::Bool(true),
}
],
},
Class {
name: "strider",
@ -1365,7 +1426,7 @@ const ENTITIES: &[Class] = &[
fields: &[
Field {
name: "variant",
typ: Type::VarInt(1), // TODO: cat variant enum.
typ: Type::CatVariant,
},
Field {
name: "lying",
@ -1849,49 +1910,6 @@ pub fn build() -> anyhow::Result<()> {
.map(|c| ident(c.name.to_pascal_case()))
.collect::<Vec<_>>();
/*
let set_type_arms = entities.iter().map(|&entity| {
let entity_name = ident(entity.name.to_pascal_case());
let mut old_fields = Vec::new();
collect_class_fields(entity, &mut old_fields);
let new_type_arms = entities.iter().map(|&new_entity| {
let new_entity_name = ident(new_entity.name.to_pascal_case());
let mut new_fields = Vec::new();
collect_class_fields(new_entity, &mut new_fields);
let assign_fields = new_fields
.iter()
.cloned()
.filter(|&new_field| old_fields.iter().any(|&f| f.name == new_field.name))
.map(|new_field| {
let name = ident(new_field.name.to_snake_case());
quote! {
new.#name = old.#name;
}
});
quote! {
EntityType::#new_entity_name => {
let mut new = #new_entity_name::new();
#(#assign_fields)*
*self = Self::#new_entity_name(new);
}
}
});
quote! {
Self::#entity_name(old) => match new_type {
#(#new_type_arms)*
},
}
});
*/
let entity_structs = entities.iter().map(|&class| {
let mut fields = Vec::new();
collect_class_fields(class, &mut fields);
@ -1918,8 +1936,12 @@ pub fn build() -> anyhow::Result<()> {
Type::Nbt => quote! { nbt::Blob },
Type::Particle => quote! { () }, // TODO
Type::VillagerData => quote! { VillagerData },
Type::Pose => quote! { Pose },
Type::OptEntityId => quote! { Option<EntityId> },
Type::Pose => quote! { Pose },
Type::CatVariant => quote! { CatVariant },
Type::FrogVariant => quote! { FrogVariant },
Type::OptGlobalPosition => quote! { () }, // TODO
Type::PaintingVariant => quote! { PaintingVariant },
Type::BoatVariant => quote! { BoatVariant },
Type::MainHand => quote! { MainHand },
};
@ -2071,8 +2093,12 @@ pub fn build() -> anyhow::Result<()> {
},
Type::Particle => quote! {}, // TODO
Type::VillagerData => standard_getter_setter(quote!(VillagerData)),
Type::Pose => standard_getter_setter(quote!(Pose)),
Type::OptEntityId => standard_getter_setter(quote!(Option<EntityId>)),
Type::Pose => standard_getter_setter(quote!(Pose)),
Type::CatVariant => standard_getter_setter(quote!(CatVariant)),
Type::FrogVariant => standard_getter_setter(quote!(FrogVariant)),
Type::OptGlobalPosition => quote! {}, // TODO
Type::PaintingVariant => standard_getter_setter(quote!(PaintingVariant)),
Type::BoatVariant => standard_getter_setter(quote!(BoatVariant)),
Type::MainHand => standard_getter_setter(quote!(MainHand)),
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -17,11 +17,11 @@ pub use crate::packets::play::s2c::GameMode;
use crate::packets::play::s2c::{
Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic,
BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, ChangeGameState,
ChangeGameStateReason, DestroyEntities, DimensionCodec, DimensionType, DimensionTypeRegistry,
ChangeGameStateReason, ChatTypeRegistry, DestroyEntities, DimensionType, DimensionTypeRegistry,
DimensionTypeRegistryEntry, Disconnect, EntityHeadLook, EntityPosition,
EntityPositionAndRotation, EntityRotation, EntityTeleport, EntityVelocity, JoinGame,
KeepAliveClientbound, PlayerPositionAndLook, PlayerPositionAndLookFlags, S2cPlayPacket,
SpawnPosition, UnloadChunk, UpdateViewDistance, UpdateViewPosition,
KeepAliveClientbound, PlayerPositionAndLook, PlayerPositionAndLookFlags, RegistryCodec,
S2cPlayPacket, SpawnPosition, UnloadChunk, UpdateViewDistance, UpdateViewPosition,
};
use crate::protocol::{BoundedInt, Nbt};
use crate::server::C2sPacketChannels;
@ -378,17 +378,21 @@ impl<'a> ClientMut<'a> {
.dimensions()
.map(|(id, _)| ident!("{LIBRARY_NAMESPACE}:dimension_{}", id.0))
.collect(),
dimension_codec: Nbt(make_dimension_codec(server)),
dimension: Nbt(to_dimension_registry_item(dimension)),
registry_codec: Nbt(make_dimension_codec(server)),
dimension_type_name: ident!(
"{LIBRARY_NAMESPACE}:dimension_type_{}",
meta.dimension().0
),
dimension_name: ident!("{LIBRARY_NAMESPACE}:dimension_{}", meta.dimension().0),
hashed_seed: 0,
max_players: VarInt(0),
view_distance: BoundedInt(VarInt(self.new_max_view_distance as i32)),
simulation_distance: VarInt(16),
reduced_debug_info: false,
enable_respawn_screen: false, // TODO
is_debug: false,
is_flat: false, // TODO
reduced_debug_info: false, // TODO
enable_respawn_screen: false,
is_debug: false, // TODO
is_flat: false,
last_death_location: None, // TODO
});
self.teleport(self.position(), self.yaw(), self.pitch());
@ -688,6 +692,7 @@ impl<'a> ClientMut<'a> {
C2sPlayPacket::QueryBlockNbt(_) => {}
C2sPlayPacket::SetDifficulty(_) => {}
C2sPlayPacket::ChatMessageServerbound(_) => {}
C2sPlayPacket::ChatPreview(_) => {}
C2sPlayPacket::ClientStatus(_) => {}
C2sPlayPacket::ClientSettings(p) => {
let old = client.settings.replace(Settings {
@ -704,7 +709,6 @@ impl<'a> ClientMut<'a> {
}
C2sPlayPacket::TabCompleteServerbound(_) => {}
C2sPlayPacket::ClickWindowButton(_) => {}
C2sPlayPacket::ClickWindow(_) => {}
C2sPlayPacket::CloseWindow(_) => {}
C2sPlayPacket::PluginMessageServerbound(_) => {}
C2sPlayPacket::EditBook(_) => {}
@ -828,7 +832,7 @@ fn send_packet(send_opt: &mut Option<Sender<S2cPlayPacket>>, pkt: impl Into<S2cP
}
}
fn make_dimension_codec(server: &Server) -> DimensionCodec {
fn make_dimension_codec(server: &Server) -> RegistryCodec {
let mut dims = Vec::new();
for (id, dim) in server.dimensions() {
let id = id.0 as i32;
@ -854,7 +858,7 @@ fn make_dimension_codec(server: &Server) -> DimensionCodec {
biomes.push(to_biome_registry_item(&biome, 0));
}
DimensionCodec {
RegistryCodec {
dimension_type_registry: DimensionTypeRegistry {
typ: ident!("dimension_type"),
value: dims,
@ -863,12 +867,19 @@ fn make_dimension_codec(server: &Server) -> DimensionCodec {
typ: ident!("worldgen/biome"),
value: biomes,
},
chat_type_registry: ChatTypeRegistry {
typ: ident!("chat_type"),
value: Vec::new(),
},
}
}
fn to_dimension_registry_item(dim: &Dimension) -> DimensionType {
DimensionType {
piglin_safe: true,
has_raids: true,
monster_spawn_light_level: 0,
monster_spawn_block_light_limit: 0,
natural: dim.natural,
ambient_light: dim.ambient_light,
fixed_time: dim.fixed_time.map(|t| t as i64),
@ -881,7 +892,6 @@ fn to_dimension_registry_item(dim: &Dimension) -> DimensionType {
DimensionEffects::TheNether => ident!("the_nether"),
DimensionEffects::TheEnd => ident!("the_end"),
},
has_raids: true,
min_y: dim.min_y,
height: dim.height,
logical_height: dim.height,

View file

@ -51,6 +51,8 @@ pub struct Dimension {
// TODO: The following fields should be added if they can affect the
// appearance of the dimension to clients.
// * infiniburn
// * monster_spawn_light_level
// * monster_spawn_block_light_level
// * respawn_anchor_works
// * has_skylight
// * bed_works

View file

@ -14,8 +14,7 @@ use vek::{Aabb, Vec3};
use crate::byte_angle::ByteAngle;
use crate::packets::play::s2c::{
EntityMetadata, S2cPlayPacket, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity,
SpawnPainting, SpawnPlayer,
EntityMetadata, S2cPlayPacket, SpawnEntity, SpawnExperienceOrb, SpawnPlayer,
};
use crate::protocol::RawBytes;
use crate::slotmap::{Key, SlotMap};
@ -306,90 +305,43 @@ impl Entity {
}
pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option<EntitySpawnPacket> {
use EntityMeta::*;
match &self.meta {
Marker(_) => None,
ExperienceOrb(_) => Some(EntitySpawnPacket::SpawnExperienceOrb(SpawnExperienceOrb {
EntityMeta::Marker(_) => None,
EntityMeta::ExperienceOrb(_) => {
Some(EntitySpawnPacket::SpawnExperienceOrb(SpawnExperienceOrb {
entity_id: VarInt(this_id.to_network_id()),
position: self.new_position,
count: 0, // TODO
}))
}
EntityMeta::Player(_) => Some(EntitySpawnPacket::SpawnPlayer(SpawnPlayer {
entity_id: VarInt(this_id.to_network_id()),
player_uuid: self.uuid,
position: self.new_position,
count: 0, // TODO
yaw: ByteAngle::from_degrees(self.yaw),
pitch: ByteAngle::from_degrees(self.pitch),
})),
Painting(_) => todo!(),
Player(_) => todo!(),
AreaEffectCloud(_)
| Arrow(_)
| Boat(_)
| DragonFireball(_)
| EndCrystal(_)
| EvokerFangs(_)
| EyeOfEnder(_)
| FallingBlock(_)
| FireworkRocket(_)
| GlowItemFrame(_)
| Item(_)
| ItemFrame(_)
| Fireball(_)
| LeashKnot(_)
| LightningBolt(_)
| LlamaSpit(_)
| Minecart(_)
| ChestMinecart(_)
| CommandBlockMinecart(_)
| FurnaceMinecart(_)
| HopperMinecart(_)
| SpawnerMinecart(_)
| TntMinecart(_)
| Tnt(_)
| ShulkerBullet(_)
| SmallFireball(_)
| Snowball(_)
| SpectralArrow(_)
| Egg(_)
| EnderPearl(_)
| ExperienceBottle(_)
| Potion(_)
| Trident(_)
| WitherSkull(_)
| FishingBobber(_) => Some(EntitySpawnPacket::SpawnEntity(SpawnEntity {
_ => Some(EntitySpawnPacket::SpawnEntity(SpawnEntity {
entity_id: VarInt(this_id.to_network_id()),
object_uuid: self.uuid,
typ: VarInt(self.typ() as i32),
position: self.new_position,
pitch: ByteAngle::from_degrees(self.pitch),
yaw: ByteAngle::from_degrees(self.yaw),
data: 1, // TODO
head_yaw: ByteAngle::from_degrees(self.head_yaw),
data: VarInt(1), // TODO
velocity: velocity_to_packet_units(self.velocity),
})),
ArmorStand(_) | Axolotl(_) | Bat(_) | Bee(_) | Blaze(_) | Cat(_) | CaveSpider(_)
| Chicken(_) | Cod(_) | Cow(_) | Creeper(_) | Dolphin(_) | Donkey(_) | Drowned(_)
| ElderGuardian(_) | EnderDragon(_) | Enderman(_) | Endermite(_) | Evoker(_)
| Fox(_) | Ghast(_) | Giant(_) | GlowSquid(_) | Goat(_) | Guardian(_) | Hoglin(_)
| Horse(_) | Husk(_) | Illusioner(_) | IronGolem(_) | Llama(_) | MagmaCube(_)
| Mule(_) | Mooshroom(_) | Ocelot(_) | Panda(_) | Parrot(_) | Phantom(_) | Pig(_)
| Piglin(_) | PiglinBrute(_) | Pillager(_) | PolarBear(_) | Pufferfish(_)
| Rabbit(_) | Ravager(_) | Salmon(_) | Sheep(_) | Shulker(_) | Silverfish(_)
| Skeleton(_) | SkeletonHorse(_) | Slime(_) | SnowGolem(_) | Spider(_) | Squid(_)
| Stray(_) | Strider(_) | TraderLlama(_) | TropicalFish(_) | Turtle(_) | Vex(_)
| Villager(_) | Vindicator(_) | WanderingTrader(_) | Witch(_) | Wither(_)
| WitherSkeleton(_) | Wolf(_) | Zoglin(_) | Zombie(_) | ZombieHorse(_)
| ZombieVillager(_) | ZombifiedPiglin(_) => {
Some(EntitySpawnPacket::SpawnLivingEntity(SpawnLivingEntity {
entity_id: VarInt(this_id.to_network_id()),
entity_uuid: self.uuid,
typ: VarInt(self.typ() as i32),
position: self.new_position,
yaw: ByteAngle::from_degrees(self.yaw),
pitch: ByteAngle::from_degrees(self.pitch),
head_yaw: ByteAngle::from_degrees(self.head_yaw),
velocity: velocity_to_packet_units(self.velocity),
}))
}
}
}
pub fn hitbox(&self) -> Aabb<f64> {
let dims = match &self.meta {
EntityMeta::Allay(_) => [0.6, 0.35, 0.6],
EntityMeta::ChestBoat(_) => [1.375, 0.5625, 1.375],
EntityMeta::Frog(_) => [0.5, 0.5, 0.5],
EntityMeta::Tadpole(_) => [0.4, 0.3, 0.4],
EntityMeta::Warden(_) => [0.9, 2.9, 0.9],
EntityMeta::AreaEffectCloud(e) => [
e.get_radius() as f64 * 2.0,
0.5,
@ -598,8 +550,6 @@ impl<'a> EntityMut<'a> {
pub(crate) enum EntitySpawnPacket {
SpawnEntity(SpawnEntity),
SpawnExperienceOrb(SpawnExperienceOrb),
SpawnLivingEntity(SpawnLivingEntity),
SpawnPainting(SpawnPainting),
SpawnPlayer(SpawnPlayer),
}
@ -608,8 +558,6 @@ impl From<EntitySpawnPacket> for S2cPlayPacket {
match pkt {
EntitySpawnPacket::SpawnEntity(pkt) => pkt.into(),
EntitySpawnPacket::SpawnExperienceOrb(pkt) => pkt.into(),
EntitySpawnPacket::SpawnLivingEntity(pkt) => pkt.into(),
EntitySpawnPacket::SpawnPainting(pkt) => pkt.into(),
EntitySpawnPacket::SpawnPlayer(pkt) => pkt.into(),
}
}

View file

@ -2,13 +2,8 @@
use std::io::Write;
use anyhow::Context;
use uuid::Uuid;
use crate::block_pos::BlockPos;
use crate::protocol::Encode;
use crate::var_int::VarInt;
use crate::Text;
#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug)]
pub struct ArmorStandRotations {
@ -137,6 +132,12 @@ pub enum Pose {
Sneaking,
LongJumping,
Dying,
Croaking,
UsingTongue,
Roaring,
Sniffing,
Emerging,
Digging,
}
impl Default for Pose {
@ -191,3 +192,66 @@ impl Encode for BoatVariant {
VarInt(*self as i32).encode(w)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum CatVariant {
Tabby,
Black,
Red,
Siamese,
BritishShorthair,
Calico,
Persian,
Ragdoll,
White,
Jellie,
AllBlack,
}
impl Default for CatVariant {
fn default() -> Self {
CatVariant::Black
}
}
impl Encode for CatVariant {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
VarInt(*self as i32).encode(w)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum FrogVariant {
Temperate,
Warm,
Cold,
}
impl Default for FrogVariant {
fn default() -> Self {
FrogVariant::Temperate
}
}
impl Encode for FrogVariant {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
VarInt(*self as i32).encode(w)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum PaintingVariant {
Default, // TODO
}
impl Default for PaintingVariant {
fn default() -> Self {
PaintingVariant::Default
}
}
impl Encode for PaintingVariant {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
VarInt(*self as i32).encode(w)
}
}

View file

@ -47,9 +47,9 @@ pub use world::{WorldId, WorldMeta, WorldMetaMut, WorldMut, WorldRef, Worlds, Wo
pub use {nbt, uuid, vek};
/// The Minecraft protocol version that this library targets.
pub const PROTOCOL_VERSION: i32 = 758;
pub const PROTOCOL_VERSION: i32 = 759;
/// The name of the Minecraft version that this library targets.
pub const VERSION_NAME: &str = "1.18.2";
pub const VERSION_NAME: &str = "1.19";
/// The namespace for this library used internally for namespaced identifiers.
const LIBRARY_NAMESPACE: &str = "valence";

View file

@ -2,7 +2,7 @@
//!
//! See <https://wiki.vg/Protocol> for up to date protocol information.
#![allow(dead_code)] // TODO: remove this
#![allow(dead_code)]
use std::fmt;
use std::io::{Read, Write};
@ -409,6 +409,7 @@ pub mod login {
LoginSuccess 0x02 {
uuid: Uuid,
username: BoundedString<3, 16>,
null_byte: u8, // TODO: Why is this needed?
}
}
@ -425,6 +426,15 @@ pub mod login {
def_struct! {
LoginStart 0x00 {
username: BoundedString<3, 16>,
sig_data: Option<LoginStartSignatureData>,
}
}
def_struct! {
LoginStartSignatureData {
timestamp: i64,
public_key: Vec<u8>,
signature: Vec<u8>,
}
}
@ -450,7 +460,8 @@ pub mod play {
position: Vec3<f64>,
pitch: ByteAngle,
yaw: ByteAngle,
data: i32,
head_yaw: ByteAngle,
data: VarInt,
velocity: Vec3<i16>,
}
}
@ -463,29 +474,6 @@ pub mod play {
}
}
def_struct! {
SpawnLivingEntity 0x02 {
entity_id: VarInt,
entity_uuid: Uuid,
typ: VarInt,
position: Vec3<f64>,
yaw: ByteAngle,
pitch: ByteAngle,
head_yaw: ByteAngle,
velocity: Vec3<i16>,
}
}
def_struct! {
SpawnPainting 0x03 {
entity_id: VarInt,
entity_uuid: Uuid,
variant: VarInt, // TODO: painting ID enum
location: BlockPos,
direction: PaintingDirection,
}
}
def_enum! {
PaintingDirection: u8 {
South = 0,
@ -496,7 +484,7 @@ pub mod play {
}
def_struct! {
SpawnPlayer 0x04 {
SpawnPlayer 0x02 {
entity_id: VarInt,
player_uuid: Uuid,
position: Vec3<f64>,
@ -506,16 +494,7 @@ pub mod play {
}
def_struct! {
SculkVibrationSignal 0x05 {
source_position: BlockPos,
destination_identifier: Ident, // TODO: destination codec type?
destination: BlockPos, // TODO: this type varies depending on destination_identifier
arrival_ticks: VarInt,
}
}
def_struct! {
EntityAnimation 0x06 {
EntityAnimation 0x03 {
entity_id: VarInt,
animation: Animation,
}
@ -533,16 +512,13 @@ pub mod play {
}
def_struct! {
AcknoledgePlayerDigging 0x08 {
location: BlockPos,
block: VarInt, // TODO: block state ID type.
status: VarInt, // TODO: VarInt enum here.
sucessful: bool,
AcknoledgeBlockChanges 0x05 {
sequence: VarInt,
}
}
def_struct! {
BlockBreakAnimation 0x09 {
BlockBreakAnimation 0x06 {
entity_id: VarInt,
location: BlockPos,
destroy_stage: BoundedInt<u8, 0, 10>,
@ -550,7 +526,7 @@ pub mod play {
}
def_struct! {
BlockEntityData 0x0a {
BlockEntityData 0x07 {
location: BlockPos,
typ: VarInt, // TODO: use enum here
data: nbt::Blob,
@ -558,23 +534,24 @@ pub mod play {
}
def_struct! {
BlockAction 0x0b {
BlockAction 0x08 {
location: BlockPos,
action_id: u8,
action_param: u8,
block_type: VarInt,
// TODO: sequence?
}
}
def_struct! {
BlockChange 0x0c {
BlockChange 0x09 {
location: BlockPos,
block_id: VarInt,
}
}
def_struct! {
BossBar 0x0d {
BossBar 0x0a {
uuid: Uuid,
action: BossBarAction,
}
@ -583,6 +560,7 @@ pub mod play {
def_enum! {
BossBarAction: VarInt {
Add: BossBarActionAdd = 0,
// TODO
}
}
@ -620,7 +598,7 @@ pub mod play {
}
def_struct! {
ServerDifficulty 0x0e {
ServerDifficulty 0x0b {
difficulty: Difficulty,
locked: bool,
}
@ -636,29 +614,35 @@ pub mod play {
}
def_struct! {
ChatMessageClientbound 0x0f {
ChatMessageClientbound 0x30 {
message: Text,
position: ChatMessagePosition,
typ: ChatMessageType,
sender: Uuid,
// TODO more fields
}
}
def_enum! {
ChatMessagePosition: u8 {
ChatMessageType: VarInt {
Chat = 0,
SystemMessage = 1,
GameInfo = 2,
SayCommand = 3,
MsgCommand = 4,
TeamMsgCommand = 5,
EmoteCommand = 6,
TellrawCommand = 7,
}
}
def_struct! {
ClearTitles 0x10 {
ClearTitles 0x0d {
reset: bool,
}
}
def_struct! {
TabComplete 0x11 {
TabComplete 0x0e {
id: VarInt,
start: VarInt,
length: VarInt,
@ -681,7 +665,7 @@ pub mod play {
}
def_struct! {
WindowProperty 0x15 {
WindowProperty 0x12 {
// TODO: use enums
window_id: u8,
property: i16,
@ -690,20 +674,20 @@ pub mod play {
}
def_struct! {
SetCooldown 0x17 {
SetCooldown 0x14 {
item_id: VarInt,
cooldown_ticks: VarInt,
}
}
def_struct! {
Disconnect 0x1a {
Disconnect 0x17 {
reason: Text,
}
}
def_struct! {
EntityStatus 0x1b {
EntityStatus 0x18 {
entity_id: i32,
/// TODO: enum
entity_status: u8,
@ -711,14 +695,14 @@ pub mod play {
}
def_struct! {
UnloadChunk 0x1d {
UnloadChunk 0x1a {
chunk_x: i32,
chunk_z: i32
}
}
def_struct! {
ChangeGameState 0x1e {
ChangeGameState 0x1b {
reason: ChangeGameStateReason,
value: f32,
}
@ -742,7 +726,7 @@ pub mod play {
}
def_struct! {
OpenHorseWindow 0x1f {
OpenHorseWindow 0x1c {
window_id: u8,
slot_count: VarInt,
entity_id: i32,
@ -750,7 +734,7 @@ pub mod play {
}
def_struct! {
InitializeWorldBorder 0x20 {
InitializeWorldBorder 0x1d {
x: f64,
z: f64,
old_diameter: f64,
@ -763,13 +747,13 @@ pub mod play {
}
def_struct! {
KeepAliveClientbound 0x21 {
KeepAliveClientbound 0x1e {
id: i64,
}
}
def_struct! {
ChunkDataAndUpdateLight 0x22 {
ChunkDataAndUpdateLight 0x1f {
chunk_x: i32,
chunk_z: i32,
heightmaps: Nbt<ChunkDataHeightmaps>,
@ -801,19 +785,17 @@ pub mod play {
}
def_struct! {
JoinGame 0x26 {
JoinGame 0x23 {
/// Entity ID of the joining player
entity_id: i32,
is_hardcore: bool,
gamemode: GameMode,
/// The previous gamemode for the purpose of the F3+F4 gamemode switcher. (TODO: verify)
/// Is `-1` if there was no previous gamemode.
previous_gamemode: GameMode,
dimension_names: Vec<Ident>,
dimension_codec: Nbt<DimensionCodec>,
/// The specification of the dimension being spawned into.
dimension: Nbt<DimensionType>,
/// The identifier of the dimension being spawned into.
registry_codec: Nbt<RegistryCodec>,
/// The name of the dimension type being spawned into.
dimension_type_name: Ident,
/// The name of the dimension being spawned into.
dimension_name: Ident,
/// Hash of the world's seed used for client biome noise.
hashed_seed: i64,
@ -829,15 +811,18 @@ pub mod play {
/// If this is a superflat world.
/// Superflat worlds have different void fog and horizon levels.
is_flat: bool,
last_death_location: Option<(Ident, BlockPos)>,
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DimensionCodec {
pub struct RegistryCodec {
#[serde(rename = "minecraft:dimension_type")]
pub dimension_type_registry: DimensionTypeRegistry,
#[serde(rename = "minecraft:worldgen/biome")]
pub biome_registry: BiomeRegistry,
#[serde(rename = "minecraft:chat_type")]
pub chat_type_registry: ChatTypeRegistry,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -857,6 +842,9 @@ pub mod play {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DimensionType {
pub piglin_safe: bool,
pub has_raids: bool,
pub monster_spawn_light_level: i32,
pub monster_spawn_block_light_limit: i32,
pub natural: bool,
pub ambient_light: f32,
pub fixed_time: Option<i64>,
@ -865,7 +853,6 @@ pub mod play {
pub has_skylight: bool,
pub bed_works: bool,
pub effects: Ident,
pub has_raids: bool,
pub min_y: i32,
pub height: i32,
pub logical_height: i32,
@ -950,6 +937,18 @@ pub mod play {
pub typ: Ident,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ChatTypeRegistry {
#[serde(rename = "type")]
pub typ: Ident,
pub value: Vec<ChatTypeRegistryEntry>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ChatTypeRegistryEntry {
// TODO
}
def_enum! {
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
GameMode: u8 {
@ -967,7 +966,7 @@ pub mod play {
}
def_struct! {
EntityPosition 0x29 {
EntityPosition 0x26 {
entity_id: VarInt,
delta: Vec3<i16>,
on_ground: bool,
@ -975,7 +974,7 @@ pub mod play {
}
def_struct! {
EntityPositionAndRotation 0x2a {
EntityPositionAndRotation 0x27 {
entity_id: VarInt,
delta: Vec3<i16>,
yaw: ByteAngle,
@ -985,7 +984,7 @@ pub mod play {
}
def_struct! {
EntityRotation 0x2b {
EntityRotation 0x28 {
entity_id: VarInt,
yaw: ByteAngle,
pitch: ByteAngle,
@ -994,7 +993,7 @@ pub mod play {
}
def_struct! {
PlayerPositionAndLook 0x38 {
PlayerPositionAndLook 0x36 {
position: Vec3<f64>,
yaw: f32,
pitch: f32,
@ -1015,20 +1014,20 @@ pub mod play {
}
def_struct! {
DestroyEntities 0x3a {
DestroyEntities 0x38 {
entities: Vec<VarInt>,
}
}
def_struct! {
EntityHeadLook 0x3e {
EntityHeadLook 0x3c {
entity_id: VarInt,
head_yaw: ByteAngle,
}
}
def_struct! {
MultiBlockChange 0x3f {
MultiBlockChange 0x3d {
chunk_section_position: u64,
invert_trust_edges: bool,
blocks: Vec<u64>,
@ -1036,26 +1035,26 @@ pub mod play {
}
def_struct! {
HeldItemChangeClientbound 0x48 {
HeldItemChangeClientbound 0x47 {
slot: BoundedInt<u8, 0, 9>,
}
}
def_struct! {
UpdateViewPosition 0x49 {
UpdateViewPosition 0x48 {
chunk_x: VarInt,
chunk_z: VarInt,
}
}
def_struct! {
UpdateViewDistance 0x4a {
UpdateViewDistance 0x49 {
view_distance: BoundedInt<VarInt, 2, 32>,
}
}
def_struct! {
SpawnPosition 0x4b {
SpawnPosition 0x4a {
location: BlockPos,
angle: f32,
}
@ -1087,7 +1086,7 @@ pub mod play {
}
def_struct! {
EntityTeleport 0x62 {
EntityTeleport 0x63 {
entity_id: VarInt,
position: Vec3<f64>,
yaw: ByteAngle,
@ -1156,12 +1155,9 @@ pub mod play {
def_s2c_play_packet_enum! {
SpawnEntity,
SpawnExperienceOrb,
SpawnLivingEntity,
SpawnPainting,
SpawnPlayer,
SculkVibrationSignal,
EntityAnimation,
AcknoledgePlayerDigging,
AcknoledgeBlockChanges,
BlockBreakAnimation,
BlockEntityData,
BlockAction,
@ -1218,13 +1214,28 @@ pub mod play {
}
def_struct! {
ChatMessageServerbound 0x03 {
ChatCommand 0x03 {
command: String, // TODO: bounded?
// TODO: timestamp, arg signatures
signed_preview: bool,
}
}
def_struct! {
ChatMessageServerbound 0x04 {
message: BoundedString<0, 256>
}
}
def_struct! {
ChatPreview 0x05 {
query: i32, // TODO: is this an i32 or a varint?
message: BoundedString<0, 256>,
}
}
def_enum! {
ClientStatus 0x04: VarInt {
ClientStatus 0x06: VarInt {
/// Sent when ready to complete login and ready to respawn after death.
PerformRespawn = 0,
/// Sent when the statistics menu is opened.
@ -1233,7 +1244,7 @@ pub mod play {
}
def_struct! {
ClientSettings 0x05 {
ClientSettings 0x07 {
/// e.g. en_US
locale: BoundedString<0, 16>,
/// Client-side render distance in chunks.
@ -1279,7 +1290,7 @@ pub mod play {
}
def_struct! {
TabCompleteServerbound 0x06 {
TabCompleteServerbound 0x08 {
transaction_id: VarInt,
/// Text behind the cursor without the '/'.
text: BoundedString<0, 32500>
@ -1287,60 +1298,42 @@ pub mod play {
}
def_struct! {
ClickWindowButton 0x07 {
ClickWindowButton 0x09 {
window_id: i8,
button_id: i8,
}
}
def_struct! {
ClickWindow 0x08 {
window_id: u8,
state_id: VarInt,
slot: i16,
button: i8,
mode: VarInt, // TODO: enum
// TODO
}
}
def_struct! {
CloseWindow 0x09 {
CloseWindow 0x0b {
window_id: u8,
}
}
def_struct! {
PluginMessageServerbound 0x0a {
PluginMessageServerbound 0x0c {
channel: Ident,
data: RawBytes,
}
}
def_struct! {
EditBook 0x0b {
hand: Hand,
EditBook 0x0d {
slot: VarInt,
entries: Vec<String>,
title: Option<String>,
}
}
def_enum! {
Hand: VarInt {
Main = 0,
Off = 1,
}
}
def_struct! {
QueryEntityNbt 0x0c {
QueryEntityNbt 0x0e {
transaction_id: VarInt,
entity_id: VarInt,
}
}
def_struct! {
InteractEntity 0x0d {
InteractEntity 0x0f {
entity_id: VarInt,
typ: InteractType,
sneaking: bool,
@ -1362,8 +1355,15 @@ pub mod play {
}
}
def_enum! {
Hand: VarInt {
Main = 0,
Off = 1,
}
}
def_struct! {
GenerateStructure 0x0e {
GenerateStructure 0x10 {
location: BlockPos,
levels: VarInt,
keep_jigsaws: bool,
@ -1371,26 +1371,26 @@ pub mod play {
}
def_struct! {
KeepAliveServerbound 0x0f {
KeepAliveServerbound 0x11 {
id: i64,
}
}
def_struct! {
LockDifficulty 0x10 {
LockDifficulty 0x12 {
locked: bool
}
}
def_struct! {
PlayerPosition 0x11 {
PlayerPosition 0x13 {
position: Vec3<f64>,
on_ground: bool,
}
}
def_struct! {
PlayerPositionAndRotation 0x12 {
PlayerPositionAndRotation 0x14 {
// Absolute position
position: Vec3<f64>,
/// Absolute rotation on X axis in degrees.
@ -1402,7 +1402,7 @@ pub mod play {
}
def_struct! {
PlayerRotation 0x13 {
PlayerRotation 0x15 {
/// Absolute rotation on X axis in degrees.
yaw: f32,
/// Absolute rotation on Y axis in degrees.
@ -1412,13 +1412,13 @@ pub mod play {
}
def_struct! {
PlayerMovement 0x14 {
PlayerMovement 0x16 {
on_ground: bool
}
}
def_struct! {
VehicleMoveServerbound 0x15 {
VehicleMoveServerbound 0x17 {
/// Absolute position
position: Vec3<f64>,
/// Degrees
@ -1429,20 +1429,20 @@ pub mod play {
}
def_struct! {
SteerBoat 0x16 {
SteerBoat 0x18 {
left_paddle_turning: bool,
right_paddle_turning: bool,
}
}
def_struct! {
PickItem 0x17 {
PickItem 0x19 {
slot_to_use: VarInt,
}
}
def_struct! {
CraftRecipeRequest 0x18 {
CraftRecipeRequest 0x1a {
window_id: i8,
recipe: Ident,
make_all: bool,
@ -1450,14 +1450,14 @@ pub mod play {
}
def_enum! {
PlayerAbilitiesServerbound 0x19: i8 {
PlayerAbilitiesServerbound 0x1b: i8 {
NotFlying = 0,
Flying = 0b10,
}
}
def_struct! {
PlayerDigging 0x1a {
PlayerDigging 0x1c {
status: DiggingStatus,
location: BlockPos,
face: BlockFace,
@ -1494,7 +1494,7 @@ pub mod play {
}
def_struct! {
EntityAction 0x1b {
EntityAction 0x1d {
entity_id: VarInt,
action_id: EntityActionId,
jump_boost: BoundedInt<VarInt, 0, 100>,
@ -1516,7 +1516,7 @@ pub mod play {
}
def_struct! {
SteerVehicle 0x1c {
SteerVehicle 0x1e {
sideways: f32,
forward: f32,
flags: SteerVehicleFlags,
@ -1531,13 +1531,13 @@ pub mod play {
}
def_struct! {
Pong 0x1d {
Pong 0x1f {
id: i32,
}
}
def_struct! {
SetRecipeBookState 0x1e {
SetRecipeBookState 0x20 {
book_id: RecipeBookId,
book_open: bool,
filter_active: bool,
@ -1554,19 +1554,19 @@ pub mod play {
}
def_struct! {
SetDisplayedRecipe 0x1f {
SetDisplayedRecipe 0x21 {
recipe_id: Ident,
}
}
def_struct! {
NameItem 0x20 {
NameItem 0x22 {
item_name: BoundedString<0, 50>,
}
}
def_enum! {
ResourcePackStatus 0x21: VarInt {
ResourcePackStatus 0x23: VarInt {
SuccessfullyLoaded = 0,
Declined = 1,
FailedDownload = 2,
@ -1575,34 +1575,34 @@ pub mod play {
}
def_enum! {
AdvancementTab 0x22: VarInt {
AdvancementTab 0x24: VarInt {
OpenedTab: Ident = 0,
ClosedScreen = 1,
}
}
def_struct! {
SelectTrade 0x23 {
SelectTrade 0x25 {
selected_slot: VarInt,
}
}
def_struct! {
SetBeaconEffect 0x24 {
// TODO: potion ids?
primary_effect: VarInt,
secondary_effect: VarInt,
SetBeaconEffect 0x26 {
// TODO: potion ids
primary_effect: Option<VarInt>,
secondary_effect: Option<VarInt>,
}
}
def_struct! {
HeldItemChangeServerbound 0x25 {
HeldItemChangeServerbound 0x27 {
slot: BoundedInt<i16, 0, 8>,
}
}
def_struct! {
UpdateCommandBlock 0x26 {
UpdateCommandBlock 0x28 {
location: BlockPos,
command: String,
mode: CommandBlockMode,
@ -1627,7 +1627,7 @@ pub mod play {
}
def_struct! {
UpdateCommandBlockMinecart 0x27 {
UpdateCommandBlockMinecart 0x29 {
entity_id: VarInt,
command: String,
track_output: bool,
@ -1635,14 +1635,14 @@ pub mod play {
}
def_struct! {
CreativeInventoryAction 0x28 {
CreativeInventoryAction 0x2a {
slot: i16,
// TODO: clicked_item: Slot,
}
}
def_struct! {
UpdateJigsawBlock 0x29 {
UpdateJigsawBlock 0x2b {
location: BlockPos,
name: Ident,
target: Ident,
@ -1653,7 +1653,7 @@ pub mod play {
}
def_struct! {
UpdateStructureBlock 0x2a {
UpdateStructureBlock 0x2c {
location: BlockPos,
action: StructureBlockAction,
mode: StructureBlockMode,
@ -1713,37 +1713,39 @@ pub mod play {
}
def_struct! {
UpdateSign 0x2b {
UpdateSign 0x2d {
location: BlockPos,
lines: [BoundedString<0, 384>; 4],
}
}
def_struct! {
PlayerArmSwing 0x2c {
PlayerArmSwing 0x2e {
hand: Hand,
}
}
def_struct! {
Spectate 0x2d {
Spectate 0x2f {
target: Uuid,
}
}
def_struct! {
PlayerBlockPlacement 0x2e {
PlayerBlockPlacement 0x30 {
hand: Hand,
location: BlockPos,
face: BlockFace,
cursor_pos: Vec3<f64>,
head_inside_block: bool,
sequence: VarInt,
}
}
def_struct! {
UseItem 0x2f {
UseItem 0x31 {
hand: Hand,
sequence: VarInt,
}
}
@ -1802,11 +1804,11 @@ pub mod play {
QueryBlockNbt,
SetDifficulty,
ChatMessageServerbound,
ChatPreview,
ClientStatus,
ClientSettings,
TabCompleteServerbound,
ClickWindowButton,
ClickWindow,
CloseWindow,
PluginMessageServerbound,
EditBook,

View file

@ -5,7 +5,8 @@ use anyhow::{anyhow, ensure, Context};
use arrayvec::ArrayVec;
use bitvec::prelude::*;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Serialize};
use serde::de::DeserializeOwned;
use serde::Serialize;
use uuid::Uuid;
use vek::{Vec2, Vec3, Vec4};
@ -37,6 +38,19 @@ impl Decode for () {
}
}
impl<T: Encode, U: Encode> Encode for (T, U) {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
self.0.encode(w)?;
self.1.encode(w)
}
}
impl<T: Decode, U: Decode> Decode for (T, U) {
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
Ok((T::decode(r)?, U::decode(r)?))
}
}
impl<T: Encode> Encode for &T {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
(*self).encode(w)
@ -477,16 +491,13 @@ pub struct Nbt<T>(pub T);
impl<T: Serialize> Encode for Nbt<T> {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
let mut enc = nbt::ser::Encoder::new(w, None);
self.0.serialize(&mut enc)?;
Ok(())
Ok(nbt::to_writer(w, &self.0, None)?)
}
}
impl<'a, T: Deserialize<'a>> Decode for Nbt<T> {
impl<T: DeserializeOwned> Decode for Nbt<T> {
fn decode(r: &mut impl Read) -> anyhow::Result<Self> {
let mut dec = nbt::de::Decoder::new(r);
Ok(Nbt(Deserialize::deserialize(&mut dec)?))
Ok(Self(nbt::from_reader(r)?))
}
}

View file

@ -573,6 +573,7 @@ async fn handle_login(
) -> anyhow::Result<Option<NewClientData>> {
let LoginStart {
username: BoundedString(username),
sig_data: _, // TODO
} = c.1.read_packet().await?;
ensure!(valid_username(&username), "invalid username '{username}'");
@ -596,23 +597,23 @@ async fn handle_login(
.0
.rsa_key
.decrypt(PaddingScheme::PKCS1v15Encrypt, &encrypted_shared_secret)
.context("Failed to decrypt shared secret")?;
.context("failed to decrypt shared secret")?;
let new_verify_token = server
.0
.rsa_key
.decrypt(PaddingScheme::PKCS1v15Encrypt, &encrypted_verify_token)
.context("Failed to decrypt verify token")?;
.context("failed to decrypt verify token")?;
ensure!(
verify_token.as_slice() == new_verify_token,
"Verify tokens do not match"
"verify tokens do not match"
);
let crypt_key: [u8; 16] = shared_secret
.as_slice()
.try_into()
.context("Shared secret has the wrong length")?;
.context("shared secret has the wrong length")?;
c.0.enable_encryption(&crypt_key);
c.1.enable_encryption(&crypt_key);
@ -689,6 +690,7 @@ async fn handle_login(
c.0.write_packet(&LoginSuccess {
uuid: npd.uuid,
username: npd.username.clone().into(),
null_byte: 0,
})
.await?;