Complete protocol implementation
This commit is contained in:
parent
25a033268c
commit
2d10d38e4c
|
@ -4,8 +4,7 @@ use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Component {
|
pub enum Component {
|
||||||
Text(TextComponent),
|
Text(TextComponent)
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component {
|
impl Component {
|
||||||
|
@ -16,7 +15,7 @@ impl Component {
|
||||||
} else if v.find("text").is_some(){
|
} else if v.find("text").is_some(){
|
||||||
Component::Text(TextComponent::from_value(v, modifier))
|
Component::Text(TextComponent::from_value(v, modifier))
|
||||||
} else {
|
} else {
|
||||||
Component::None
|
Component::Text(TextComponent{text: "".to_owned(), modifier: modifier})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,18 +28,17 @@ impl fmt::Display for Component {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Component::Text(ref txt) => write!(f, "{}", txt),
|
Component::Text(ref txt) => write!(f, "{}", txt),
|
||||||
Component::None => Result::Ok(()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Component {
|
impl Default for Component {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Component::None
|
Component::Text(TextComponent{text: "".to_owned(), modifier: Default::default()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Modifier {
|
pub struct Modifier {
|
||||||
pub extra: Option<Vec<Component>>,
|
pub extra: Option<Vec<Component>>,
|
||||||
pub bold: Option<bool>,
|
pub bold: Option<bool>,
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
|
use nbt;
|
||||||
|
use protocol::{Serializable};
|
||||||
|
use std::io;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Stack {
|
||||||
|
id: isize,
|
||||||
|
count: isize,
|
||||||
|
damage: isize,
|
||||||
|
tag: Option<nbt::NamedTag>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Default for Stack {
|
||||||
|
fn default() -> Stack {
|
||||||
|
Stack {
|
||||||
|
id: -1,
|
||||||
|
count: 0,
|
||||||
|
damage: 0,
|
||||||
|
tag: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for Option<Stack> {
|
||||||
|
fn read_from(buf: &mut io::Read) -> Result<Option<Stack>, io::Error> {
|
||||||
|
let id = try!(buf.read_i16::<BigEndian>());
|
||||||
|
if id == -1 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
Ok(Some(Stack{
|
||||||
|
id: id as isize,
|
||||||
|
count: try!(buf.read_u8()) as isize,
|
||||||
|
damage: try!(buf.read_i16::<BigEndian>()) as isize,
|
||||||
|
tag: try!(Serializable::read_from(buf)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
|
match *self {
|
||||||
|
Some(ref val) => {
|
||||||
|
try!(buf.write_i16::<BigEndian>(val.id as i16));
|
||||||
|
try!(buf.write_u8(val.count as u8));
|
||||||
|
try!(buf.write_i16::<BigEndian>(val.damage as i16));
|
||||||
|
try!(val.tag.write_to(buf));
|
||||||
|
},
|
||||||
|
None => try!(buf.write_i16::<BigEndian>(-1)),
|
||||||
|
}
|
||||||
|
Result::Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,274 @@
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use super::protocol::{Serializable};
|
||||||
|
use super::protocol;
|
||||||
|
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Tag {
|
||||||
|
End,
|
||||||
|
Byte(i8),
|
||||||
|
Short(i16),
|
||||||
|
Int(i32),
|
||||||
|
Long(i64),
|
||||||
|
Float(f32),
|
||||||
|
Double(f64),
|
||||||
|
ByteArray(Vec<u8>),
|
||||||
|
String(String),
|
||||||
|
List(Vec<Tag>),
|
||||||
|
Compound(HashMap<String, Tag>),
|
||||||
|
IntArray(Vec<i32>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NamedTag(pub String, pub Tag);
|
||||||
|
|
||||||
|
impl Tag {
|
||||||
|
|
||||||
|
pub fn new_compound() -> Tag {
|
||||||
|
Tag::Compound(HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_list() -> Tag {
|
||||||
|
Tag::List(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the tag with the given name from the compound.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics when the tag isn't a compound.
|
||||||
|
pub fn get(&self, name: &str) -> Option<&Tag> {
|
||||||
|
match *self {
|
||||||
|
Tag::Compound(ref val) => val.get(name),
|
||||||
|
_ => panic!("not a compound tag"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Places the tag into the compound using the given name.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics when the tag isn't a compound.
|
||||||
|
pub fn put(&mut self, name: &str, tag: Tag) {
|
||||||
|
match *self {
|
||||||
|
Tag::Compound(ref mut val) => val.insert(name.to_owned(), tag),
|
||||||
|
_ => panic!("not a compound tag"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_compound(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Tag::Compound(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_byte(&self) -> Option<i8> {
|
||||||
|
match *self {
|
||||||
|
Tag::Byte(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_short(&self) -> Option<i16> {
|
||||||
|
match *self {
|
||||||
|
Tag::Short(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_int(&self) -> Option<i32> {
|
||||||
|
match *self {
|
||||||
|
Tag::Int(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_long(&self) -> Option<i64> {
|
||||||
|
match *self {
|
||||||
|
Tag::Long(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_float(&self) -> Option<f32> {
|
||||||
|
match *self {
|
||||||
|
Tag::Float(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_double(&self) -> Option<f64> {
|
||||||
|
match *self {
|
||||||
|
Tag::Double(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_byte_array(&self) -> Option<&[u8]> {
|
||||||
|
match *self {
|
||||||
|
Tag::ByteArray(ref val) => Some(&val[..]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_string(&self) -> Option<&str> {
|
||||||
|
match *self {
|
||||||
|
Tag::String(ref val) => Some(&val[..]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_list(&self) -> Option<&[Tag]> {
|
||||||
|
match *self {
|
||||||
|
Tag::List(ref val) => Some(&val[..]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_compound(&self) -> Option<&HashMap<String, Tag>> {
|
||||||
|
match *self {
|
||||||
|
Tag::Compound(ref val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_int_array(&self) -> Option<&[i32]> {
|
||||||
|
match *self {
|
||||||
|
Tag::IntArray(ref val) => Some(&val[..]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_id(&self) -> u8 {
|
||||||
|
match *self {
|
||||||
|
Tag::End => 0,
|
||||||
|
Tag::Byte(_) => 1,
|
||||||
|
Tag::Short(_) => 2,
|
||||||
|
Tag::Int(_) => 3,
|
||||||
|
Tag::Long(_) => 4,
|
||||||
|
Tag::Float(_) => 5,
|
||||||
|
Tag::Double(_) => 6,
|
||||||
|
Tag::ByteArray(_) => 7,
|
||||||
|
Tag::String(_) => 8,
|
||||||
|
Tag::List(_) => 9,
|
||||||
|
Tag::Compound(_) => 10,
|
||||||
|
Tag::IntArray(_) => 11,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_type(id: u8, buf: &mut io::Read) -> Result<Tag, io::Error> {
|
||||||
|
match id {
|
||||||
|
0 => unreachable!(),
|
||||||
|
1 => Ok(Tag::Byte(try!(buf.read_i8()))),
|
||||||
|
2 => Ok(Tag::Short(try!(buf.read_i16::<BigEndian>()))),
|
||||||
|
3 => Ok(Tag::Int(try!(buf.read_i32::<BigEndian>()))),
|
||||||
|
4 => Ok(Tag::Long(try!(buf.read_i64::<BigEndian>()))),
|
||||||
|
5 => Ok(Tag::Float(try!(buf.read_f32::<BigEndian>()))),
|
||||||
|
6 => Ok(Tag::Double(try!(buf.read_f64::<BigEndian>()))),
|
||||||
|
7 => Ok(Tag::ByteArray({
|
||||||
|
let len : i32 = try!(Serializable::read_from(buf));
|
||||||
|
let mut data = Vec::with_capacity(len as usize);
|
||||||
|
try!(buf.take(len as u64).read_to_end(&mut data));
|
||||||
|
data
|
||||||
|
})),
|
||||||
|
8 => Ok(Tag::String(try!(read_string(buf)))),
|
||||||
|
9 => {
|
||||||
|
let mut l = Vec::new();
|
||||||
|
let ty = try!(buf.read_u8());
|
||||||
|
let len : i32 = try!(Serializable::read_from(buf));
|
||||||
|
for _ in 0 .. len {
|
||||||
|
l.push(try!(Tag::read_type(ty, buf)));
|
||||||
|
}
|
||||||
|
Ok(Tag::List(l))
|
||||||
|
},
|
||||||
|
10 => {
|
||||||
|
let mut c = Tag::new_compound();
|
||||||
|
loop {
|
||||||
|
let ty = try!(buf.read_u8());
|
||||||
|
if ty == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let name: String = try!(read_string(buf));
|
||||||
|
c.put(&name[..], try!(Tag::read_type(ty, buf)));
|
||||||
|
}
|
||||||
|
Ok(c)
|
||||||
|
},
|
||||||
|
11 => Ok(Tag::IntArray({
|
||||||
|
let len : i32 = try!(Serializable::read_from(buf));
|
||||||
|
let mut data = Vec::with_capacity(len as usize);
|
||||||
|
for _ in 0 .. len {
|
||||||
|
data.push(try!(buf.read_i32::<BigEndian>()));
|
||||||
|
}
|
||||||
|
data
|
||||||
|
})),
|
||||||
|
_ => Err(io::Error::new(io::ErrorKind::InvalidData, protocol::Error::Err("invalid tag".to_owned()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for Tag {
|
||||||
|
fn read_from(buf: &mut io::Read) -> Result<Tag, io::Error> {
|
||||||
|
Tag::read_type(10, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
|
match *self {
|
||||||
|
Tag::End => {},
|
||||||
|
Tag::Byte(val) => try!(buf.write_i8(val)),
|
||||||
|
Tag::Short(val) => try!(buf.write_i16::<BigEndian>(val)),
|
||||||
|
Tag::Int(val) => try!(buf.write_i32::<BigEndian>(val)),
|
||||||
|
Tag::Long(val) => try!(buf.write_i64::<BigEndian>(val)),
|
||||||
|
Tag::Float(val) => try!(buf.write_f32::<BigEndian>(val)),
|
||||||
|
Tag::Double(val) => try!(buf.write_f64::<BigEndian>(val)),
|
||||||
|
Tag::ByteArray(ref val) => {
|
||||||
|
try!((val.len() as i32).write_to(buf));
|
||||||
|
try!(buf.write_all(val));
|
||||||
|
},
|
||||||
|
Tag::String(ref val) => try!(write_string(buf, val)),
|
||||||
|
Tag::List(ref val) => {
|
||||||
|
if val.is_empty() {
|
||||||
|
try!(buf.write_u8(0));
|
||||||
|
try!(buf.write_i32::<BigEndian>(0));
|
||||||
|
} else {
|
||||||
|
try!(buf.write_u8(val[0].internal_id()));
|
||||||
|
try!(buf.write_i32::<BigEndian>(val.len() as i32));
|
||||||
|
for e in val {
|
||||||
|
try!(e.write_to(buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tag::Compound(ref val) => {
|
||||||
|
for (k, v) in val {
|
||||||
|
try!(v.internal_id().write_to(buf));
|
||||||
|
try!(write_string(buf, k));
|
||||||
|
try!(v.write_to(buf));
|
||||||
|
}
|
||||||
|
try!(buf.write_u8(0));
|
||||||
|
},
|
||||||
|
Tag::IntArray(ref val) => {
|
||||||
|
try!((val.len() as i32).write_to(buf));
|
||||||
|
for v in val {
|
||||||
|
try!(v.write_to(buf));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Result::Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_string(buf: &mut io::Write, s: &String)-> io::Result<()> {
|
||||||
|
let data = s.as_bytes();
|
||||||
|
try!((data.len() as i16).write_to(buf));
|
||||||
|
buf.write_all(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_string(buf: &mut io::Read) -> io::Result<String> {
|
||||||
|
let len: i16 = try!(buf.read_i16::<BigEndian>());
|
||||||
|
let mut ret = String::new();
|
||||||
|
try!(buf.take(len as u64).read_to_string(&mut ret));
|
||||||
|
Result::Ok(ret)
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use protocol::{Serializable};
|
||||||
|
use std::io;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Position(u64);
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
fn new(x: i32, y: i32, z: i32) -> Position {
|
||||||
|
Position(
|
||||||
|
(((x as u64) & 0x3FFFFFF) << 38) |
|
||||||
|
(((y as u64) & 0xFFF) << 26) |
|
||||||
|
((z as u64) & 0x3FFFFFF)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_x(&self) -> i32 {
|
||||||
|
((self.0 as i64) >> 38) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_y(&self) -> i32 {
|
||||||
|
(((self.0 as i64) >> 26) & 0xFFF) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_z(&self) -> i32 {
|
||||||
|
((self.0 as i64) << 38 >> 38) as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Position {
|
||||||
|
fn default() -> Position {
|
||||||
|
Position(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Position {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "<{},{},{}>", self.get_x(), self.get_y(), self.get_z())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for Position {
|
||||||
|
fn read_from(buf: &mut io::Read) -> Result<Position, io::Error> {
|
||||||
|
Result::Ok(Position(try!(buf.read_u64::<BigEndian>())))
|
||||||
|
}
|
||||||
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
|
try!(buf.write_u64::<BigEndian>(self.0));
|
||||||
|
Result::Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,380 @@
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::io;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::fmt;
|
||||||
|
use protocol;
|
||||||
|
use protocol::{Serializable};
|
||||||
|
use format;
|
||||||
|
use item;
|
||||||
|
|
||||||
|
pub struct MetadataKey<T: MetaValue> {
|
||||||
|
index: i32,
|
||||||
|
ty: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T: MetaValue> MetadataKey<T> {
|
||||||
|
// TODO: Make const later when possible
|
||||||
|
/*const*/ fn new(index: i32) -> MetadataKey<T> {
|
||||||
|
MetadataKey {
|
||||||
|
index: index,
|
||||||
|
ty: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Metadata {
|
||||||
|
map: HashMap<i32, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metadata {
|
||||||
|
pub fn new() -> Metadata {
|
||||||
|
Metadata { map: HashMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
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_raw<T: MetaValue>(&mut self, index: i32, val: T) {
|
||||||
|
self.map.insert(index, val.wrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for Metadata {
|
||||||
|
|
||||||
|
fn read_from(buf: &mut io::Read) -> Result<Self, io::Error> {
|
||||||
|
let mut m = Metadata::new();
|
||||||
|
loop {
|
||||||
|
let index = try!(u8::read_from(buf)) as i32;
|
||||||
|
if index == 0xFF {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let ty = try!(u8::read_from(buf));
|
||||||
|
match ty {
|
||||||
|
0 => m.put_raw(index, try!(i8::read_from(buf))),
|
||||||
|
1 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0),
|
||||||
|
2 => m.put_raw(index, try!(f32::read_from(buf))),
|
||||||
|
3 => m.put_raw(index, try!(String::read_from(buf))),
|
||||||
|
4 => m.put_raw(index, try!(format::Component::read_from(buf))),
|
||||||
|
5 => m.put_raw(index, try!(Option::<item::Stack>::read_from(buf))),
|
||||||
|
6 => m.put_raw(index, try!(bool::read_from(buf))),
|
||||||
|
7 => m.put_raw(index, [
|
||||||
|
try!(f32::read_from(buf)),
|
||||||
|
try!(f32::read_from(buf)),
|
||||||
|
try!(f32::read_from(buf))
|
||||||
|
]),
|
||||||
|
8 => m.put_raw(index, try!(super::Position::read_from(buf))),
|
||||||
|
9 => {
|
||||||
|
if try!(bool::read_from(buf)) {
|
||||||
|
m.put_raw(index, try!(Option::<super::Position>::read_from(buf)));
|
||||||
|
} else {
|
||||||
|
m.put_raw::<Option<super::Position>>(index, None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
10 => m.put_raw(index, try!(protocol::VarInt::read_from(buf))),
|
||||||
|
11 => {
|
||||||
|
if try!(bool::read_from(buf)) {
|
||||||
|
m.put_raw(index, try!(Option::<protocol::UUID>::read_from(buf)));
|
||||||
|
} else {
|
||||||
|
m.put_raw::<Option<protocol::UUID>>(index, None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
12 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0 as u16),
|
||||||
|
_ => return Err(io::Error::new(io::ErrorKind::InvalidInput, protocol::Error::Err("unknown metadata type".to_owned()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||||
|
for (k, v) in &self.map {
|
||||||
|
try!((*k as u8).write_to(buf));
|
||||||
|
match *v {
|
||||||
|
Value::Byte(ref val) => {
|
||||||
|
try!(u8::write_to(&0, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Int(ref val) => {
|
||||||
|
try!(u8::write_to(&1, buf));
|
||||||
|
try!(protocol::VarInt(*val).write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Float(ref val) => {
|
||||||
|
try!(u8::write_to(&2, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::String(ref val) => {
|
||||||
|
try!(u8::write_to(&3, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::FormatComponent(ref val) => {
|
||||||
|
try!(u8::write_to(&4, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::OptionalItemStack(ref val) => {
|
||||||
|
try!(u8::write_to(&5, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Bool(ref val) => {
|
||||||
|
try!(u8::write_to(&6, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Vector(ref val) => {
|
||||||
|
try!(u8::write_to(&7, buf));
|
||||||
|
try!(val[0].write_to(buf));
|
||||||
|
try!(val[1].write_to(buf));
|
||||||
|
try!(val[2].write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Position(ref val) => {
|
||||||
|
try!(u8::write_to(&8, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::OptionalPosition(ref val) => {
|
||||||
|
try!(u8::write_to(&9, buf));
|
||||||
|
try!(val.is_some().write_to(buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Direction(ref val) => {
|
||||||
|
try!(u8::write_to(&10, buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
}
|
||||||
|
Value::OptionalUUID(ref val) => {
|
||||||
|
try!(u8::write_to(&11, buf));
|
||||||
|
try!(val.is_some().write_to(buf));
|
||||||
|
try!(val.write_to(buf));
|
||||||
|
},
|
||||||
|
Value::Block(ref val) => {
|
||||||
|
try!(u8::write_to(&11, buf));
|
||||||
|
try!(protocol::VarInt(*val as i32).write_to(buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try!(u8::write_to(&0xFF, buf));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Metadata {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
try!(write!(f, "Metadata[ "));
|
||||||
|
for (k, v) in &self.map {
|
||||||
|
try!(write!(f, "{:?}={:?}, ", k, v));
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Metadata {
|
||||||
|
fn default() -> Metadata {
|
||||||
|
Metadata::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Value {
|
||||||
|
Byte(i8),
|
||||||
|
Int(i32),
|
||||||
|
Float(f32),
|
||||||
|
String(String),
|
||||||
|
FormatComponent(format::Component),
|
||||||
|
OptionalItemStack(Option<item::Stack>),
|
||||||
|
Bool(bool),
|
||||||
|
Vector([f32; 3]),
|
||||||
|
Position(super::Position),
|
||||||
|
OptionalPosition(Option<super::Position>),
|
||||||
|
Direction(protocol::VarInt), // TODO: Proper type
|
||||||
|
OptionalUUID(Option<protocol::UUID>),
|
||||||
|
Block(u16), // TODO: Proper type
|
||||||
|
}
|
||||||
|
|
||||||
|
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<item::Stack> {
|
||||||
|
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 super::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<super::Position> {
|
||||||
|
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<protocol::UUID> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
const TEST: MetadataKey<String> =
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
mod blockpos;
|
||||||
|
pub use self::blockpos::*;
|
||||||
|
|
||||||
|
mod metadata;
|
||||||
|
pub use self::metadata::*;
|
Loading…
Reference in New Issue