1.8.9 (47) multiprotocol support (#57)
Protocol 47 (1.8.9-1.8) is the biggest multiprotocol (https://github.com/iceiix/steven/issues/18) change yet: * New chunk format (load_chunk18) * New metadata format (Metadata18) * New packets and changes to 13 packets References: http://wiki.vg/index.php?title=Protocol&oldid=7368 https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite https://wiki.vg/Protocol_History#1.8 https://github.com/PrismarineJS/minecraft-data/blob/master/data/pc/1.8/protocol.json 1.8 chunk format: https://wiki.vg/index.php?title=Chunk_Format&oldid=6124 1.9 chunk format: https://wiki.vg/index.php?title=Chunk_Format&oldid=7411 1.8 vs 1.9: https://wiki.vg/index.php?title=Chunk_Format&diff=7411&oldid=6124 https://github.com/PrismarineJS/prismarine-chunk/blob/master/src/pc/1.8/section.js https://github.com/PrismarineJS/prismarine-chunk/blob/master/src/pc/1.8/chunk.js Details: * Add 1.8.9 packet IDs from https://github.com/iceiix/steven/pull/37 * Add ChunkDataBulk, parse the ChunkMeta and save data in Vec<u8> * Add EntityEquipment u16 variant, EntityStatus, ChunkData u16 variants * SpawnPlayer with added held item https://wiki.vg/Protocol_History#15w31a Removed Current Item short from Spawn Player (0x0C) * SpawnObject no UUID and optional velocity https://wiki.vg/index.php?title=Protocol&oldid=7368#Spawn_Object https://wiki.vg/Protocol_History#15w31a Added Entity UUID after entity ID to Spawn Object (0x0E) Spawn Object always sends velocity, even if data is 0 * SpawnMob no UUID variant https://wiki.vg/Protocol_History#15w31a Added Entity UUID after entity ID to Spawn Mob (0x0F) * Maps packet without tracking position boolean https://wiki.vg/index.php?title=Protocol&oldid=7368#Map https://wiki.vg/Protocol_History#15w34a Added tracking position boolean to Map (0x34) * Update Entity NBT was removed and Bossbar added (both 0x49) >1.8 https://wiki.vg/index.php?title=Protocol&oldid=7368#Update_Entity_NBT https://wiki.vg/Protocol_History#15w31a Removed Update Entity NBT Packet (0x49) Added Boss Bar packet (0x4 * Use entity without hands https://wiki.vg/index.php?title=Protocol&oldid=7368#Use_Entity https://wiki.vg/Protocol_History#15w31a Added VarInt enum for selected hand in Use Entity (0x02); only sent if type is interact or interact at * Player block placement, held item stack and face byte variant https://wiki.vg/index.php?title=Protocol&oldid=7368#Player_Block_Placement https://wiki.vg/Protocol_History#15w31a Face for Player Block Placement is now a VarInt enum instead of a byte Replaced held item (slot) with VarInt enum selected hand in Player Block Placement * Arm swing without hands, a packet with no fields, uses a ZST https://wiki.vg/index.php?title=Protocol&oldid=7368#Animation_2 https://github.com/iceiix/steven/pull/57#issuecomment-444289008 https://doc.rust-lang.org/nomicon/exotic-sizes.html * ClickWindow uses u8 mode, same as in 15w39c * ClientSettings without hands * SpectateTeleport is added before ResourcePackStatus * Copy load_chunk to load_chunk19 and load_chunk18 * 1.8 chunk reading implementation, load_chunk18 * Support both metadata formats, Metadata18/Metadata19 * Remove fmt::Debug * Implement formatting in MetadataBase and bounce through fmt::Debug
This commit is contained in:
parent
ad8bcf6aba
commit
7f2e2033ca
|
@ -38,32 +38,161 @@ impl <T: MetaValue> MetadataKey<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Metadata {
|
||||
pub struct Metadata18 {
|
||||
map: HashMap<i32, Value>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn new() -> Metadata {
|
||||
Metadata { map: HashMap::new() }
|
||||
pub struct Metadata19 {
|
||||
map: HashMap<i32, Value>,
|
||||
}
|
||||
|
||||
trait MetadataBase: fmt::Debug + Default {
|
||||
fn map(&self) -> &HashMap<i32, Value>;
|
||||
fn map_mut(&mut self) -> &mut HashMap<i32, Value>;
|
||||
|
||||
fn get<T: MetaValue>(&self, key: &MetadataKey<T>) -> Option<&T> {
|
||||
self.map().get(&key.index).map(T::unwrap)
|
||||
}
|
||||
|
||||
pub fn get<T: MetaValue>(&self, key: &MetadataKey<T>) -> Option<&T> {
|
||||
self.map.get(&key.index).map(T::unwrap)
|
||||
}
|
||||
|
||||
pub fn put<T: MetaValue>(&mut self, key: &MetadataKey<T>, val: T) {
|
||||
self.map.insert(key.index, val.wrap());
|
||||
fn put<T: MetaValue>(&mut self, key: &MetadataKey<T>, val: T) {
|
||||
self.map_mut().insert(key.index, val.wrap());
|
||||
}
|
||||
|
||||
fn put_raw<T: MetaValue>(&mut self, index: i32, val: T) {
|
||||
self.map.insert(index, val.wrap());
|
||||
self.map_mut().insert(index, val.wrap());
|
||||
}
|
||||
|
||||
fn fmt2(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Metadata[ ")?;
|
||||
for (k, v) in self.map() {
|
||||
write!(f, "{:?}={:?}, ", k, v)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializable for Metadata {
|
||||
impl MetadataBase for Metadata18 {
|
||||
fn map(&self) -> &HashMap<i32, Value> { &self.map }
|
||||
fn map_mut(&mut self) -> &mut HashMap<i32, Value> { &mut self.map }
|
||||
}
|
||||
|
||||
impl MetadataBase for Metadata19 {
|
||||
fn map(&self) -> &HashMap<i32, Value> { &self.map }
|
||||
fn map_mut(&mut self) -> &mut HashMap<i32, Value> { &mut self.map }
|
||||
}
|
||||
|
||||
impl Metadata18 {
|
||||
pub fn new() -> Self {
|
||||
Self { map: HashMap::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Metadata19 {
|
||||
pub fn new() -> Self {
|
||||
Self { map: HashMap::new() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Serializable for Metadata18 {
|
||||
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
|
||||
let mut m = Metadata::new();
|
||||
let mut m = Self::new();
|
||||
loop {
|
||||
let ty_index = u8::read_from(buf)? as i32;
|
||||
if ty_index == 0x7f {
|
||||
break;
|
||||
}
|
||||
let index = ty_index & 0x1f;
|
||||
let ty = ty_index >> 5;
|
||||
|
||||
match ty {
|
||||
0 => m.put_raw(index, i8::read_from(buf)?),
|
||||
1 => m.put_raw(index, i16::read_from(buf)?),
|
||||
2 => m.put_raw(index, i32::read_from(buf)?),
|
||||
3 => m.put_raw(index, f32::read_from(buf)?),
|
||||
4 => m.put_raw(index, String::read_from(buf)?),
|
||||
5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
|
||||
6 => m.put_raw(index,
|
||||
[i32::read_from(buf)?,
|
||||
i32::read_from(buf)?,
|
||||
i32::read_from(buf)?]),
|
||||
7 => m.put_raw(index,
|
||||
[f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?]),
|
||||
_ => return Err(protocol::Error::Err("unknown metadata type".to_owned())),
|
||||
}
|
||||
}
|
||||
Ok(m)
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), protocol::Error> {
|
||||
for (k, v) in &self.map {
|
||||
if (*k as u8) > 0x1f {
|
||||
panic!("write metadata index {:x} > 0x1f", *k as u8);
|
||||
}
|
||||
|
||||
let ty_index: u8 = *k as u8;
|
||||
const TYPE_SHIFT: usize = 5;
|
||||
|
||||
match *v
|
||||
{
|
||||
Value::Byte(ref val) => {
|
||||
u8::write_to(&(ty_index | (0 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::Short(ref val) => {
|
||||
u8::write_to(&(ty_index | (1 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
|
||||
Value::Int(ref val) => {
|
||||
u8::write_to(&(ty_index | (2 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::Float(ref val) => {
|
||||
u8::write_to(&(ty_index | (3 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::String(ref val) => {
|
||||
u8::write_to(&(ty_index | (4 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::OptionalItemStack(ref val) => {
|
||||
u8::write_to(&(ty_index | (5 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::Vector(ref val) => {
|
||||
u8::write_to(&(ty_index | (6 << TYPE_SHIFT)), buf)?;
|
||||
val[0].write_to(buf)?;
|
||||
val[1].write_to(buf)?;
|
||||
val[2].write_to(buf)?;
|
||||
}
|
||||
Value::Rotation(ref val) => {
|
||||
u8::write_to(&(ty_index | (7 << TYPE_SHIFT)), buf)?;
|
||||
val[0].write_to(buf)?;
|
||||
val[1].write_to(buf)?;
|
||||
val[2].write_to(buf)?;
|
||||
}
|
||||
|
||||
Value::FormatComponent(_) | Value::Bool(_) | Value::Position(_) |
|
||||
Value::OptionalPosition(_) | Value::Direction(_) | Value::OptionalUUID(_) |
|
||||
Value::Block(_) | Value::NBTTag(_) => {
|
||||
panic!("attempted to write 1.9+ metadata to 1.8");
|
||||
}
|
||||
}
|
||||
}
|
||||
u8::write_to(&0x7f, buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializable for Metadata19 {
|
||||
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
|
||||
let mut m = Self::new();
|
||||
loop {
|
||||
let index = u8::read_from(buf)? as i32;
|
||||
if index == 0xFF {
|
||||
|
@ -179,6 +308,7 @@ impl Serializable for Metadata {
|
|||
// TODO: write NBT tags metadata
|
||||
//nbt::Tag(*val).write_to(buf)?;
|
||||
}
|
||||
_ => panic!("unexpected metadata"),
|
||||
}
|
||||
}
|
||||
u8::write_to(&0xFF, buf)?;
|
||||
|
@ -186,25 +316,25 @@ impl Serializable for Metadata {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Metadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Metadata[ ")?;
|
||||
for (k, v) in &self.map {
|
||||
write!(f, "{:?}={:?}, ", k, v)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
// TODO: is it possible to implement these traits on MetadataBase instead?
|
||||
impl fmt::Debug for Metadata19 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt2(f) } }
|
||||
impl fmt::Debug for Metadata18 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt2(f) } }
|
||||
|
||||
impl Default for Metadata19 {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Metadata {
|
||||
fn default() -> Metadata {
|
||||
Metadata::new()
|
||||
impl Default for Metadata18 {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
Byte(i8),
|
||||
Short(i16),
|
||||
Int(i32),
|
||||
Float(f32),
|
||||
String(String),
|
||||
|
@ -212,6 +342,7 @@ pub enum Value {
|
|||
OptionalItemStack(Option<item::Stack>),
|
||||
Bool(bool),
|
||||
Vector([f32; 3]),
|
||||
Rotation([i32; 3]),
|
||||
Position(Position),
|
||||
OptionalPosition(Option<Position>),
|
||||
Direction(protocol::VarInt), // TODO: Proper type
|
||||
|
@ -237,6 +368,18 @@ impl MetaValue for i8 {
|
|||
}
|
||||
}
|
||||
|
||||
impl MetaValue for i16 {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
Value::Short(ref val) => val,
|
||||
_ => panic!("incorrect key"),
|
||||
}
|
||||
}
|
||||
fn wrap(self) -> Value {
|
||||
Value::Short(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl MetaValue for i32 {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
|
@ -309,6 +452,18 @@ impl MetaValue for bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl MetaValue for [i32; 3] {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
Value::Rotation(ref val) => val,
|
||||
_ => panic!("incorrect key"),
|
||||
}
|
||||
}
|
||||
fn wrap(self) -> Value {
|
||||
Value::Rotation(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl MetaValue for [f32; 3] {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
|
@ -406,7 +561,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut m = Metadata::new();
|
||||
let mut m = Metadata19::new();
|
||||
|
||||
m.put(&TEST, "Hello world".to_owned());
|
||||
|
||||
|
|
Loading…
Reference in New Issue