1.12.2 protocol support (340) (#40)
* Add new 1.12.2 packets and shift IDs CraftRecipeResponse AdvancementTab SelectAdvancementTab Advancements CraftingRecipeRequest UnlockRecipes CraftingBookData * Fix unlock recipes packet, add length-prefixed arrays https://wiki.vg/index.php?title=Protocol&oldid=14204#Unlock_Recipes * Update resources to 1.12.2 * Handle NBTTag metadata (value 13), parsed as nbt::NamedTag https://wiki.vg/index.php?title=Entity_metadata&oldid=14048#Entity_Metadata_Format https://github.com/iceiix/steven/pull/40#issuecomment-443454757 * Fix entity packet IDs, 0x25 now is Entity https://wiki.vg/index.php?title=Protocol&oldid=14204#Entity * Add NBT long array (type 12) support https://wiki.vg/NBT#Specification * Entity metadata type is now a VarInt, not u8: https://wiki.vg/index.php?title=Entity_metadata&oldid=14048#Entity_Metadata_Format * Keep alives changed to longs, no longer VarInts https://wiki.vg/index.php?title=Protocol&oldid=14204#Keep_Alive_.28serverbound.29 * Parse CraftRecipeResponse (0x2b) * Add structs for advancements data * Implement Serializable trait for Advancement and AdvancementDisplay * Implement advancement progress parsing; advancement packet works * Particle packet adds fallingdust (46) with length 1 https://wiki.vg/index.php?title=Protocol&oldid=14204#Particle_2
This commit is contained in:
parent
36d9c1383e
commit
be6e1f79f1
|
@ -34,6 +34,7 @@ pub enum Tag {
|
|||
List(Vec<Tag>),
|
||||
Compound(HashMap<String, Tag>),
|
||||
IntArray(Vec<i32>),
|
||||
LongArray(Vec<i64>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -155,6 +156,14 @@ impl Tag {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_long_array(&self) -> Option<&[i64]> {
|
||||
match *self {
|
||||
Tag::LongArray(ref val) => Some(&val[..]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn internal_id(&self) -> u8 {
|
||||
match *self {
|
||||
Tag::End => 0,
|
||||
|
@ -169,6 +178,7 @@ impl Tag {
|
|||
Tag::List(_) => 9,
|
||||
Tag::Compound(_) => 10,
|
||||
Tag::IntArray(_) => 11,
|
||||
Tag::LongArray(_) => 12,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,6 +227,14 @@ impl Tag {
|
|||
}
|
||||
data
|
||||
})),
|
||||
12 => Ok(Tag::LongArray({
|
||||
let len: i32 = Serializable::read_from(buf)?;
|
||||
let mut data = Vec::with_capacity(len as usize);
|
||||
for _ in 0..len {
|
||||
data.push(buf.read_i64::<BigEndian>()?);
|
||||
}
|
||||
data
|
||||
})),
|
||||
_ => Err(protocol::Error::Err("invalid tag".to_owned())),
|
||||
}
|
||||
}
|
||||
|
@ -267,6 +285,12 @@ impl Serializable for Tag {
|
|||
v.write_to(buf)?;
|
||||
}
|
||||
}
|
||||
Tag::LongArray(ref val) => {
|
||||
(val.len() as i32).write_to(buf)?;
|
||||
for v in val {
|
||||
v.write_to(buf)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Result::Ok(())
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ use flate2::Compression;
|
|||
use std::time::{Instant, Duration};
|
||||
use crate::shared::Position;
|
||||
|
||||
pub const SUPPORTED_PROTOCOL: i32 = 316;
|
||||
pub const SUPPORTED_PROTOCOL: i32 = 340;
|
||||
|
||||
|
||||
/// Helper macro for defining packets
|
||||
|
@ -96,24 +96,27 @@ pub const CloseWindow: i32 = 0x08;
|
|||
pub const PluginMessageServerbound: i32 = 0x09;
|
||||
pub const UseEntity: i32 = 0x0a;
|
||||
pub const KeepAliveServerbound: i32 = 0x0b;
|
||||
pub const PlayerPosition: i32 = 0x0c;
|
||||
pub const PlayerPositionLook: i32 = 0x0d;
|
||||
pub const PlayerLook: i32 = 0x0e;
|
||||
pub const Player: i32 = 0x0f;
|
||||
pub const Player: i32 = 0x0c;
|
||||
pub const PlayerPosition: i32 = 0x0d;
|
||||
pub const PlayerPositionLook: i32 = 0x0e;
|
||||
pub const PlayerLook: i32 = 0x0f;
|
||||
pub const VehicleMove: i32 = 0x10;
|
||||
pub const SteerBoat: i32 = 0x11;
|
||||
pub const ClientAbilities: i32 = 0x12;
|
||||
pub const PlayerDigging: i32 = 0x13;
|
||||
pub const PlayerAction: i32 = 0x14;
|
||||
pub const SteerVehicle: i32 = 0x15;
|
||||
pub const ResourcePackStatus: i32 = 0x16;
|
||||
pub const HeldItemChange: i32 = 0x17;
|
||||
pub const CreativeInventoryAction: i32 = 0x18;
|
||||
pub const SetSign: i32 = 0x19;
|
||||
pub const ArmSwing: i32 = 0x1a;
|
||||
pub const SpectateTeleport: i32 = 0x1b;
|
||||
pub const PlayerBlockPlacement: i32 = 0x1c;
|
||||
pub const UseItem: i32 = 0x1d;
|
||||
pub const CraftRecipeRequest: i32 = 0x12;
|
||||
pub const ClientAbilities: i32 = 0x13;
|
||||
pub const PlayerDigging: i32 = 0x14;
|
||||
pub const PlayerAction: i32 = 0x15;
|
||||
pub const SteerVehicle: i32 = 0x16;
|
||||
pub const CraftingBookData: i32 = 0x17;
|
||||
pub const ResourcePackStatus: i32 = 0x18;
|
||||
pub const AdvancementTab: i32 = 0x19;
|
||||
pub const HeldItemChange: i32 = 0x1a;
|
||||
pub const CreativeInventoryAction: i32 = 0x1b;
|
||||
pub const SetSign: i32 = 0x1c;
|
||||
pub const ArmSwing: i32 = 0x1d;
|
||||
pub const SpectateTeleport: i32 = 0x1e;
|
||||
pub const PlayerBlockPlacement: i32 = 0x1f;
|
||||
pub const UseItem: i32 = 0x20;
|
||||
pub const SpawnObject: i32 = 0x00;
|
||||
pub const SpawnExperienceOrb: i32 = 0x01;
|
||||
pub const SpawnGlobalEntity: i32 = 0x02;
|
||||
|
@ -151,45 +154,49 @@ pub const Effect: i32 = 0x21;
|
|||
pub const Particle: i32 = 0x22;
|
||||
pub const JoinGame: i32 = 0x23;
|
||||
pub const Maps: i32 = 0x24;
|
||||
pub const EntityMove: i32 = 0x25;
|
||||
pub const EntityLookAndMove: i32 = 0x26;
|
||||
pub const EntityLook: i32 = 0x27;
|
||||
pub const Entity: i32 = 0x28;
|
||||
pub const Entity: i32 = 0x25;
|
||||
pub const EntityMove: i32 = 0x26;
|
||||
pub const EntityLookAndMove: i32 = 0x27;
|
||||
pub const EntityLook: i32 = 0x28;
|
||||
pub const VehicleTeleport: i32 = 0x29;
|
||||
pub const SignEditorOpen: i32 = 0x2a;
|
||||
pub const PlayerAbilities: i32 = 0x2b;
|
||||
pub const CombatEvent: i32 = 0x2c;
|
||||
pub const PlayerInfo: i32 = 0x2d;
|
||||
pub const TeleportPlayer: i32 = 0x2e;
|
||||
pub const EntityUsedBed: i32 = 0x2f;
|
||||
pub const EntityDestroy: i32 = 0x30;
|
||||
pub const EntityRemoveEffect: i32 = 0x31;
|
||||
pub const ResourcePackSend: i32 = 0x32;
|
||||
pub const Respawn: i32 = 0x33;
|
||||
pub const EntityHeadLook: i32 = 0x34;
|
||||
pub const WorldBorder: i32 = 0x35;
|
||||
pub const Camera: i32 = 0x36;
|
||||
pub const SetCurrentHotbarSlot: i32 = 0x37;
|
||||
pub const ScoreboardDisplay: i32 = 0x38;
|
||||
pub const EntityMetadata: i32 = 0x39;
|
||||
pub const EntityAttach: i32 = 0x3a;
|
||||
pub const EntityVelocity: i32 = 0x3b;
|
||||
pub const EntityEquipment: i32 = 0x3c;
|
||||
pub const SetExperience: i32 = 0x3d;
|
||||
pub const UpdateHealth: i32 = 0x3e;
|
||||
pub const ScoreboardObjective: i32 = 0x3f;
|
||||
pub const SetPassengers: i32 = 0x40;
|
||||
pub const Teams: i32 = 0x41;
|
||||
pub const UpdateScore: i32 = 0x42;
|
||||
pub const SpawnPosition: i32 = 0x43;
|
||||
pub const TimeUpdate: i32 = 0x44;
|
||||
pub const Title: i32 = 0x45;
|
||||
pub const SoundEffect: i32 = 0x46;
|
||||
pub const PlayerListHeaderFooter: i32 = 0x47;
|
||||
pub const CollectItem: i32 = 0x48;
|
||||
pub const EntityTeleport: i32 = 0x49;
|
||||
pub const EntityProperties: i32 = 0x4a;
|
||||
pub const EntityEffect: i32 = 0x4b;
|
||||
pub const CraftRecipeResponse: i32 = 0x2b;
|
||||
pub const PlayerAbilities: i32 = 0x2c;
|
||||
pub const CombatEvent: i32 = 0x2d;
|
||||
pub const PlayerInfo: i32 = 0x2e;
|
||||
pub const TeleportPlayer: i32 = 0x2f;
|
||||
pub const EntityUsedBed: i32 = 0x30;
|
||||
pub const UnlockRecipes: i32 = 0x31;
|
||||
pub const EntityDestroy: i32 = 0x32;
|
||||
pub const EntityRemoveEffect: i32 = 0x33;
|
||||
pub const ResourcePackSend: i32 = 0x34;
|
||||
pub const Respawn: i32 = 0x35;
|
||||
pub const EntityHeadLook: i32 = 0x36;
|
||||
pub const SelectAdvancementTab: i32 = 0x37;
|
||||
pub const WorldBorder: i32 = 0x38;
|
||||
pub const Camera: i32 = 0x39;
|
||||
pub const SetCurrentHotbarSlot: i32 = 0x3a;
|
||||
pub const ScoreboardDisplay: i32 = 0x3b;
|
||||
pub const EntityMetadata: i32 = 0x3c;
|
||||
pub const EntityAttach: i32 = 0x3d;
|
||||
pub const EntityVelocity: i32 = 0x3e;
|
||||
pub const EntityEquipment: i32 = 0x3f;
|
||||
pub const SetExperience: i32 = 0x40;
|
||||
pub const UpdateHealth: i32 = 0x41;
|
||||
pub const ScoreboardObjective: i32 = 0x42;
|
||||
pub const SetPassengers: i32 = 0x43;
|
||||
pub const Teams: i32 = 0x44;
|
||||
pub const UpdateScore: i32 = 0x45;
|
||||
pub const SpawnPosition: i32 = 0x46;
|
||||
pub const TimeUpdate: i32 = 0x47;
|
||||
pub const Title: i32 = 0x48;
|
||||
pub const SoundEffect: i32 = 0x49;
|
||||
pub const PlayerListHeaderFooter: i32 = 0x4a;
|
||||
pub const CollectItem: i32 = 0x4b;
|
||||
pub const EntityTeleport: i32 = 0x4c;
|
||||
pub const Advancements: i32 = 0x4d;
|
||||
pub const EntityProperties: i32 = 0x4e;
|
||||
pub const EntityEffect: i32 = 0x4f;
|
||||
pub const LoginStart: i32 = 0x00;
|
||||
pub const EncryptionResponse: i32 = 0x01;
|
||||
pub const LoginDisconnect: i32 = 0x00;
|
||||
|
|
|
@ -124,7 +124,7 @@ state_packets!(
|
|||
/// KeepAliveClientbound. If the client doesn't reply the server
|
||||
/// may disconnect the client.
|
||||
packet KeepAliveServerbound {
|
||||
field id: VarInt =,
|
||||
field id: i64 =,
|
||||
}
|
||||
/// PlayerPosition is used to update the player's position.
|
||||
packet PlayerPosition {
|
||||
|
@ -166,6 +166,12 @@ state_packets!(
|
|||
field unknown: bool =,
|
||||
field unknown2: bool =,
|
||||
}
|
||||
/// CraftRecipeRequest is sent when player clicks a recipe in the crafting book.
|
||||
packet CraftRecipeRequest {
|
||||
field window_id: u8 =,
|
||||
field recipe: VarInt =,
|
||||
field make_all: bool =,
|
||||
}
|
||||
/// ClientAbilities is used to modify the players current abilities.
|
||||
/// Currently flying is the only one
|
||||
packet ClientAbilities {
|
||||
|
@ -193,11 +199,23 @@ state_packets!(
|
|||
field forward: f32 =,
|
||||
field flags: u8 =,
|
||||
}
|
||||
/// CraftingBookData is sent when the player interacts with the crafting book.
|
||||
packet CraftingBookData {
|
||||
field action: VarInt =,
|
||||
field recipe_id: i32 = when(|p: &CraftingBookData| p.action.0 == 0),
|
||||
field crafting_book_open: bool = when(|p: &CraftingBookData| p.action.0 == 1),
|
||||
field crafting_filter: bool = when(|p: &CraftingBookData| p.action.0 == 1),
|
||||
}
|
||||
/// ResourcePackStatus informs the server of the client's current progress
|
||||
/// in activating the requested resource pack
|
||||
packet ResourcePackStatus {
|
||||
field result: VarInt =,
|
||||
}
|
||||
// TODO: Document
|
||||
packet AdvancementTab {
|
||||
field action: VarInt =,
|
||||
field tab_id: String = when(|p: &AdvancementTab| p.action.0 == 0),
|
||||
}
|
||||
/// HeldItemChange is sent when the player changes the currently active
|
||||
/// hotbar slot.
|
||||
packet HeldItemChange {
|
||||
|
@ -488,7 +506,7 @@ state_packets!(
|
|||
/// The client should reply with the KeepAliveServerbound
|
||||
/// packet setting ID to the same as this one.
|
||||
packet KeepAliveClientbound {
|
||||
field id: VarInt =,
|
||||
field id: i64 =,
|
||||
}
|
||||
/// ChunkData sends or updates a single chunk on the client. If New is set
|
||||
/// then biome data should be sent too.
|
||||
|
@ -522,7 +540,7 @@ state_packets!(
|
|||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field data1: VarInt = when(|p: &Particle| p.particle_id == 36 || p.particle_id == 37 || p.particle_id == 38),
|
||||
field data1: VarInt = when(|p: &Particle| p.particle_id == 36 || p.particle_id == 37 || p.particle_id == 38 || p.particle_id == 46),
|
||||
field data2: VarInt = when(|p: &Particle| p.particle_id == 36),
|
||||
}
|
||||
/// JoinGame is sent after completing the login process. This
|
||||
|
@ -598,6 +616,11 @@ state_packets!(
|
|||
packet SignEditorOpen {
|
||||
field location: Position =,
|
||||
}
|
||||
/// CraftRecipeResponse is a response to CraftRecipeRequest, notifies the UI.
|
||||
packet CraftRecipeResponse {
|
||||
field window_id: u8 =,
|
||||
field recipe: VarInt =,
|
||||
}
|
||||
/// PlayerAbilities is used to modify the players current abilities. Flying,
|
||||
/// creative, god mode etc.
|
||||
packet PlayerAbilities {
|
||||
|
@ -636,6 +659,13 @@ state_packets!(
|
|||
field entity_id: VarInt =,
|
||||
field location: Position =,
|
||||
}
|
||||
packet UnlockRecipes {
|
||||
field action: VarInt =,
|
||||
field crafting_book_open: bool =,
|
||||
field filtering_craftable: bool =,
|
||||
field recipe_ids: LenPrefixed<VarInt, VarInt> =,
|
||||
field recipe_ids2: LenPrefixed<VarInt, VarInt> = when(|p: &UnlockRecipes| p.action.0 == 0),
|
||||
}
|
||||
/// EntityDestroy destroys the entities with the ids in the provided slice.
|
||||
packet EntityDestroy {
|
||||
field entity_ids: LenPrefixed<VarInt, VarInt> =,
|
||||
|
@ -664,6 +694,11 @@ state_packets!(
|
|||
field entity_id: VarInt =,
|
||||
field head_yaw: i8 =,
|
||||
}
|
||||
/// SelectAdvancementTab indicates the client should switch the advancement tab.
|
||||
packet SelectAdvancementTab {
|
||||
field has_id: bool =,
|
||||
field tab_id: String = when(|p: &SelectAdvancementTab| p.has_id),
|
||||
}
|
||||
/// WorldBorder configures the world's border.
|
||||
packet WorldBorder {
|
||||
field action: VarInt =,
|
||||
|
@ -818,6 +853,12 @@ state_packets!(
|
|||
field pitch: i8 =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
packet Advancements {
|
||||
field reset_clear: bool =,
|
||||
field mapping: LenPrefixed<VarInt, packet::Advancement> =,
|
||||
field identifiers: LenPrefixed<VarInt, String> =,
|
||||
field progress: LenPrefixed<VarInt, packet::AdvancementProgress> =,
|
||||
}
|
||||
/// EntityProperties updates the properties for an entity.
|
||||
packet EntityProperties {
|
||||
field entity_id: VarInt =,
|
||||
|
@ -1043,6 +1084,163 @@ impl Default for MapIcon {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Advancement {
|
||||
pub id: String,
|
||||
pub parent_id: Option<String>,
|
||||
pub display_data: Option<AdvancementDisplay>,
|
||||
pub criteria: LenPrefixed<VarInt, String>,
|
||||
pub requirements: LenPrefixed<VarInt, LenPrefixed<VarInt, String>>,
|
||||
}
|
||||
|
||||
impl Serializable for Advancement {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let id: String = Serializable::read_from(buf)?;
|
||||
let parent_id = {
|
||||
let has_parent: u8 = Serializable::read_from(buf)?;
|
||||
if has_parent != 0 {
|
||||
let parent_id: String = Serializable::read_from(buf)?;
|
||||
Some(parent_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let has_display: u8 = Serializable::read_from(buf)?;
|
||||
let display_data = {
|
||||
if has_display != 0 {
|
||||
let display_data: AdvancementDisplay = Serializable::read_from(buf)?;
|
||||
Some(display_data)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let criteria: LenPrefixed<VarInt, String> = Serializable::read_from(buf)?;
|
||||
let requirements: LenPrefixed<VarInt, LenPrefixed<VarInt, String>> = Serializable::read_from(buf)?;
|
||||
Ok(Advancement {
|
||||
id,
|
||||
parent_id,
|
||||
display_data,
|
||||
criteria,
|
||||
requirements,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.id.write_to(buf)?;
|
||||
self.parent_id.write_to(buf)?;
|
||||
self.display_data.write_to(buf)?;
|
||||
self.criteria.write_to(buf)?;
|
||||
self.requirements.write_to(buf)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AdvancementDisplay {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub icon: Option<crate::item::Stack>,
|
||||
pub frame_type: VarInt,
|
||||
pub flags: i32,
|
||||
pub background_texture: Option<String>,
|
||||
pub x_coord: f32,
|
||||
pub y_coord: f32,
|
||||
}
|
||||
|
||||
impl Serializable for AdvancementDisplay {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let title: String = Serializable::read_from(buf)?;
|
||||
let description: String = Serializable::read_from(buf)?;
|
||||
let icon: Option<crate::item::Stack> = Serializable::read_from(buf)?;
|
||||
let frame_type: VarInt = Serializable::read_from(buf)?;
|
||||
let flags: i32 = Serializable::read_from(buf)?;
|
||||
let background_texture: Option<String> = if flags & 1 != 0 {
|
||||
Serializable::read_from(buf)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let x_coord: f32 = Serializable::read_from(buf)?;
|
||||
let y_coord: f32 = Serializable::read_from(buf)?;
|
||||
|
||||
Ok(AdvancementDisplay {
|
||||
title,
|
||||
description,
|
||||
icon,
|
||||
frame_type,
|
||||
flags,
|
||||
background_texture,
|
||||
x_coord,
|
||||
y_coord,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.title.write_to(buf)?;
|
||||
self.description.write_to(buf)?;
|
||||
self.icon.write_to(buf)?;
|
||||
self.frame_type.write_to(buf)?;
|
||||
self.flags.write_to(buf)?;
|
||||
if self.flags & 1 != 0 {
|
||||
self.background_texture.write_to(buf)?;
|
||||
}
|
||||
self.x_coord.write_to(buf)?;
|
||||
self.y_coord.write_to(buf)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AdvancementProgress {
|
||||
pub id: String,
|
||||
pub criteria: LenPrefixed<VarInt, CriterionProgress>,
|
||||
}
|
||||
|
||||
impl Serializable for AdvancementProgress {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
Ok(AdvancementProgress {
|
||||
id: Serializable::read_from(buf)?,
|
||||
criteria: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.id.write_to(buf)?;
|
||||
self.criteria.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CriterionProgress {
|
||||
pub id: String,
|
||||
pub date_of_achieving: Option<i64>,
|
||||
}
|
||||
|
||||
impl Serializable for CriterionProgress {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let id = Serializable::read_from(buf)?;
|
||||
let achieved: u8 = Serializable::read_from(buf)?;
|
||||
let date_of_achieving: Option<i64> = if achieved != 0 {
|
||||
Serializable::read_from(buf)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(CriterionProgress {
|
||||
id,
|
||||
date_of_achieving,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.id.write_to(buf)?;
|
||||
self.date_of_achieving.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityProperty {
|
||||
pub key: String,
|
||||
|
|
|
@ -30,10 +30,10 @@ use zip;
|
|||
use crate::types::hash::FNVHash;
|
||||
use crate::ui;
|
||||
|
||||
const RESOURCES_VERSION: &str = "1.11.2";
|
||||
const VANILLA_CLIENT_URL: &str = "https://launcher.mojang.com/mc/game/1.11.2/client/db5aa600f0b0bf508aaf579509b345c4e34087be/client.jar";
|
||||
const ASSET_VERSION: &str = "1.11";
|
||||
const ASSET_INDEX_URL: &str = "https://launchermeta.mojang.com/mc/assets/1.11/e02b8fba4390e173057895c56ecc91e3ce3bbd40/1.11.json";
|
||||
const RESOURCES_VERSION: &str = "1.12.2";
|
||||
const VANILLA_CLIENT_URL: &str = "https://launcher.mojang.com/v1/objects/0f275bc1547d01fa5f56ba34bdc87d981ee12daf/client.jar";
|
||||
const ASSET_VERSION: &str = "1.12";
|
||||
const ASSET_INDEX_URL: &str = "https://launchermeta.mojang.com/mc/assets/1.12/67e29e024e664064c1f04c728604f83c24cbc218/1.12.json";
|
||||
|
||||
pub trait Pack: Sync + Send {
|
||||
fn open(&self, name: &str) -> Option<Box<io::Read>>;
|
||||
|
|
|
@ -21,6 +21,7 @@ use crate::protocol::Serializable;
|
|||
use crate::format;
|
||||
use crate::item;
|
||||
use crate::shared::Position;
|
||||
use crate::nbt;
|
||||
|
||||
pub struct MetadataKey<T: MetaValue> {
|
||||
index: i32,
|
||||
|
@ -68,7 +69,7 @@ impl Serializable for Metadata {
|
|||
if index == 0xFF {
|
||||
break;
|
||||
}
|
||||
let ty = u8::read_from(buf)?;
|
||||
let ty = protocol::VarInt::read_from(buf)?.0;
|
||||
match ty {
|
||||
0 => m.put_raw(index, i8::read_from(buf)?),
|
||||
1 => m.put_raw(index, protocol::VarInt::read_from(buf)?.0),
|
||||
|
@ -98,6 +99,15 @@ impl Serializable for Metadata {
|
|||
}
|
||||
}
|
||||
12 => m.put_raw(index, protocol::VarInt::read_from(buf)?.0 as u16),
|
||||
13 => {
|
||||
let ty = u8::read_from(buf)?;
|
||||
if ty != 0 {
|
||||
let name = nbt::read_string(buf)?;
|
||||
let tag = nbt::Tag::read_from(buf)?;
|
||||
|
||||
m.put_raw(index, nbt::NamedTag(name, tag));
|
||||
}
|
||||
}
|
||||
_ => return Err(protocol::Error::Err("unknown metadata type".to_owned())),
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +174,11 @@ impl Serializable for Metadata {
|
|||
u8::write_to(&11, buf)?;
|
||||
protocol::VarInt(*val as i32).write_to(buf)?;
|
||||
}
|
||||
Value::NBTTag(ref _val) => {
|
||||
u8::write_to(&13, buf)?;
|
||||
// TODO: write NBT tags metadata
|
||||
//nbt::Tag(*val).write_to(buf)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
u8::write_to(&0xFF, buf)?;
|
||||
|
@ -202,6 +217,7 @@ pub enum Value {
|
|||
Direction(protocol::VarInt), // TODO: Proper type
|
||||
OptionalUUID(Option<protocol::UUID>),
|
||||
Block(u16), // TODO: Proper type
|
||||
NBTTag(nbt::NamedTag),
|
||||
}
|
||||
|
||||
pub trait MetaValue {
|
||||
|
@ -365,6 +381,18 @@ impl MetaValue for u16 {
|
|||
}
|
||||
}
|
||||
|
||||
impl MetaValue for nbt::NamedTag {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
Value::NBTTag(ref val) => val,
|
||||
_ => panic!("incorrect key"),
|
||||
}
|
||||
}
|
||||
fn wrap(self) -> Value {
|
||||
Value::NBTTag(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in New Issue