// Copyright 2016 Matthew Collins // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::collections::HashMap; use std::marker::PhantomData; use std::io; use std::fmt; use crate::protocol; use crate::protocol::Serializable; use crate::format; use crate::item; use crate::shared::Position; use crate::nbt; pub struct MetadataKey { index: i32, ty: PhantomData, } impl MetadataKey { #[allow(dead_code)] fn new(index: i32) -> MetadataKey { MetadataKey { index, ty: PhantomData, } } } pub struct Metadata { map: HashMap, } impl Metadata { pub fn new() -> Metadata { Metadata { map: HashMap::new() } } pub fn get(&self, key: &MetadataKey) -> Option<&T> { self.map.get(&key.index).map(T::unwrap) } pub fn put(&mut self, key: &MetadataKey, val: T) { self.map.insert(key.index, val.wrap()); } fn put_raw(&mut self, index: i32, val: T) { self.map.insert(index, val.wrap()); } } impl Serializable for Metadata { fn read_from(buf: &mut R) -> Result { let mut m = Metadata::new(); loop { let index = u8::read_from(buf)? as i32; if index == 0xFF { break; } 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), 2 => m.put_raw(index, f32::read_from(buf)?), 3 => m.put_raw(index, String::read_from(buf)?), 4 => m.put_raw(index, format::Component::read_from(buf)?), 5 => m.put_raw(index, Option::::read_from(buf)?), 6 => m.put_raw(index, bool::read_from(buf)?), 7 => m.put_raw(index, [f32::read_from(buf)?, f32::read_from(buf)?, f32::read_from(buf)?]), 8 => m.put_raw(index, Position::read_from(buf)?), 9 => { if bool::read_from(buf)? { m.put_raw(index, Option::::read_from(buf)?); } else { m.put_raw::>(index, None); } } 10 => m.put_raw(index, protocol::VarInt::read_from(buf)?), 11 => { if bool::read_from(buf)? { m.put_raw(index, Option::::read_from(buf)?); } else { m.put_raw::>(index, None); } } 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())), } } Ok(m) } fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { for (k, v) in &self.map { (*k as u8).write_to(buf)?; match *v { Value::Byte(ref val) => { u8::write_to(&0, buf)?; val.write_to(buf)?; } Value::Int(ref val) => { u8::write_to(&1, buf)?; protocol::VarInt(*val).write_to(buf)?; } Value::Float(ref val) => { u8::write_to(&2, buf)?; val.write_to(buf)?; } Value::String(ref val) => { u8::write_to(&3, buf)?; val.write_to(buf)?; } Value::FormatComponent(ref val) => { u8::write_to(&4, buf)?; val.write_to(buf)?; } Value::OptionalItemStack(ref val) => { u8::write_to(&5, buf)?; val.write_to(buf)?; } Value::Bool(ref val) => { u8::write_to(&6, buf)?; val.write_to(buf)?; } Value::Vector(ref val) => { u8::write_to(&7, buf)?; val[0].write_to(buf)?; val[1].write_to(buf)?; val[2].write_to(buf)?; } Value::Position(ref val) => { u8::write_to(&8, buf)?; val.write_to(buf)?; } Value::OptionalPosition(ref val) => { u8::write_to(&9, buf)?; val.is_some().write_to(buf)?; val.write_to(buf)?; } Value::Direction(ref val) => { u8::write_to(&10, buf)?; val.write_to(buf)?; } Value::OptionalUUID(ref val) => { u8::write_to(&11, buf)?; val.is_some().write_to(buf)?; val.write_to(buf)?; } Value::Block(ref val) => { 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)?; Ok(()) } } 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, "]") } } impl Default for Metadata { fn default() -> Metadata { Metadata::new() } } #[derive(Debug)] pub enum Value { Byte(i8), Int(i32), Float(f32), String(String), FormatComponent(format::Component), OptionalItemStack(Option), Bool(bool), Vector([f32; 3]), Position(Position), OptionalPosition(Option), Direction(protocol::VarInt), // TODO: Proper type OptionalUUID(Option), Block(u16), // TODO: Proper type NBTTag(nbt::NamedTag), } pub trait MetaValue { fn unwrap(_: &Value) -> &Self; fn wrap(self) -> Value; } impl MetaValue for i8 { fn unwrap(value: &Value) -> &Self { match *value { Value::Byte(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Byte(self) } } impl MetaValue for i32 { fn unwrap(value: &Value) -> &Self { match *value { Value::Int(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Int(self) } } impl MetaValue for f32 { fn unwrap(value: &Value) -> &Self { match *value { Value::Float(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Float(self) } } impl MetaValue for String { fn unwrap(value: &Value) -> &Self { match *value { Value::String(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::String(self) } } impl MetaValue for format::Component { fn unwrap(value: &Value) -> &Self { match *value { Value::FormatComponent(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::FormatComponent(self) } } impl MetaValue for Option { fn unwrap(value: &Value) -> &Self { match *value { Value::OptionalItemStack(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::OptionalItemStack(self) } } impl MetaValue for bool { fn unwrap(value: &Value) -> &Self { match *value { Value::Bool(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Bool(self) } } impl MetaValue for [f32; 3] { fn unwrap(value: &Value) -> &Self { match *value { Value::Vector(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Vector(self) } } impl MetaValue for Position { fn unwrap(value: &Value) -> &Self { match *value { Value::Position(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Position(self) } } impl MetaValue for Option { fn unwrap(value: &Value) -> &Self { match *value { Value::OptionalPosition(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::OptionalPosition(self) } } impl MetaValue for protocol::VarInt { fn unwrap(value: &Value) -> &Self { match *value { Value::Direction(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Direction(self) } } impl MetaValue for Option { fn unwrap(value: &Value) -> &Self { match *value { Value::OptionalUUID(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::OptionalUUID(self) } } impl MetaValue for u16 { fn unwrap(value: &Value) -> &Self { match *value { Value::Block(ref val) => val, _ => panic!("incorrect key"), } } fn wrap(self) -> Value { Value::Block(self) } } 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::*; use std::marker::PhantomData; const TEST: MetadataKey = MetadataKey { index: 0, ty: PhantomData, }; #[test] fn basic() { let mut m = Metadata::new(); m.put(&TEST, "Hello world".to_owned()); match m.get(&TEST) { Some(val) => { assert!(val == "Hello world"); } None => panic!("failed"), } } }