diff --git a/protocol/src/format.rs b/protocol/src/format.rs new file mode 100644 index 0000000..29776bd --- /dev/null +++ b/protocol/src/format.rs @@ -0,0 +1,377 @@ +// 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 serde_json; +use std::fmt; +use std::mem; + +#[derive(Debug, Clone)] +pub enum Component { + Text(TextComponent), +} + +impl Component { + + pub fn from_string(str: &str) -> Self { + let mut component; + match serde_json::from_str::(str) { + Ok(value) => component = Component::from_value(&value), + // Sometimes mojang sends a literal string, so we should interpret it literally + Err(_) => { + component = Component::Text(TextComponent::new(str)); + convert_legacy(&mut component); + }, + } + component + } + + pub fn from_value(v: &serde_json::Value) -> Self { + let mut modifier = Modifier::from_value(v); + if let Some(val) = v.as_str() { + Component::Text(TextComponent { + text: val.to_owned(), + modifier, + }) + } else if v.get("text").is_some() { + Component::Text(TextComponent::from_value(v, modifier)) + } else if v.get("translate").is_some() { + // TODO: translations + Component::Text(TextComponent::new(v.get("translate").unwrap().as_str().unwrap())) + } else { + modifier.color = Some(Color::RGB(255, 0, 0)); + Component::Text(TextComponent { + text: "UNHANDLED".to_owned(), + modifier, + }) + } + } + + pub fn to_value(&self) -> serde_json::Value { + unimplemented!() + } +} + +impl fmt::Display for Component { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Component::Text(ref txt) => write!(f, "{}", txt), + } + } +} + +impl Default for Component { + fn default() -> Self { + Component::Text(TextComponent { + text: "".to_owned(), + modifier: Default::default(), + }) + } +} + +#[derive(Debug, Default, Clone)] +pub struct Modifier { + pub extra: Option>, + pub bold: Option, + pub italic: Option, + pub underlined: Option, + pub strikethrough: Option, + pub obfuscated: Option, + pub color: Option, +} + +// TODO: Missing events click/hover/insert + +impl Modifier { + pub fn from_value(v: &serde_json::Value) -> Self { + let mut m = Modifier { + bold: v.get("bold").map_or(Option::None, |v| v.as_bool()), + italic: v.get("italic").map_or(Option::None, |v| v.as_bool()), + underlined: v.get("underlined").map_or(Option::None, |v| v.as_bool()), + strikethrough: v.get("strikethrough").map_or(Option::None, |v| v.as_bool()), + obfuscated: v.get("obfuscated").map_or(Option::None, |v| v.as_bool()), + color: v.get("color") + .map_or(Option::None, |v| v.as_str()) + .map(|v| Color::from_string(&v.to_owned())), + extra: Option::None, + }; + if let Some(extra) = v.get("extra") { + if let Some(data) = extra.as_array() { + let mut ex = Vec::new(); + for e in data { + ex.push(Component::from_value(e)); + } + m.extra = Some(ex); + } + } + m + } + + pub fn to_value(&self) -> serde_json::Value { + unimplemented!() + } +} + +#[derive(Debug, Clone)] +pub struct TextComponent { + pub text: String, + pub modifier: Modifier, +} + +impl TextComponent { + pub fn new(val: &str) -> TextComponent { + TextComponent { + text: val.to_owned(), + modifier: Modifier { ..Default::default() }, + } + } + + pub fn from_value(v: &serde_json::Value, modifier: Modifier) -> Self { + TextComponent { + text: v.get("text").unwrap().as_str().unwrap_or("").to_owned(), + modifier, + } + } + + pub fn to_value(&self) -> serde_json::Value { + unimplemented!() + } +} + +impl fmt::Display for TextComponent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.text)?; + if let Some(ref extra) = self.modifier.extra { + for c in extra { + write!(f, "{}", c)?; + } + } + Result::Ok(()) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Color { + Black, + DarkBlue, + DarkGreen, + DarkAqua, + DarkRed, + DarkPurple, + Gold, + Gray, + DarkGray, + Blue, + Green, + Aqua, + Red, + LightPurple, + Yellow, + White, + RGB(u8, u8, u8), +} + +impl fmt::Display for Color { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +impl Color { + fn from_string(val: &str) -> Self { + match val { + "black" => Color::Black, + "dark_blue" => Color::DarkBlue, + "dark_green" => Color::DarkGreen, + "dark_aqua" => Color::DarkAqua, + "dark_red" => Color::DarkRed, + "dark_purple" => Color::DarkPurple, + "gold" => Color::Gold, + "gray" => Color::Gray, + "dark_gray" => Color::DarkGray, + "blue" => Color::Blue, + "green" => Color::Green, + "aqua" => Color::Aqua, + "red" => Color::Red, + "light_purple" => Color::LightPurple, + "yellow" => Color::Yellow, + val if val.len() == 7 && val.as_bytes()[0] == b'#' => { + let r = match u8::from_str_radix(&val[1..3], 16) { + Ok(r) => r, + Err(_) => return Color::White, + }; + let g = match u8::from_str_radix(&val[3..5], 16) { + Ok(g) => g, + Err(_) => return Color::White, + }; + let b = match u8::from_str_radix(&val[5..7], 16) { + Ok(b) => b, + Err(_) => return Color::White, + }; + Color::RGB(r, g, b) + } + "white" | _ => Color::White, + } + } + + pub fn to_string(&self) -> String { + match *self { + Color::Black => "black".to_owned(), + Color::DarkBlue => "dark_blue".to_owned(), + Color::DarkGreen => "dark_green".to_owned(), + Color::DarkAqua => "dark_aqua".to_owned(), + Color::DarkRed => "dark_red".to_owned(), + Color::DarkPurple => "dark_purple".to_owned(), + Color::Gold => "gold".to_owned(), + Color::Gray => "gray".to_owned(), + Color::DarkGray => "dark_gray".to_owned(), + Color::Blue => "blue".to_owned(), + Color::Green => "green".to_owned(), + Color::Aqua => "aqua".to_owned(), + Color::Red => "red".to_owned(), + Color::LightPurple => "light_purple".to_owned(), + Color::Yellow => "yellow".to_owned(), + Color::White => "white".to_owned(), + Color::RGB(r, g, b) => format!("#{:02X}{:02X}{:02X}", r, g, b), + } + } + + pub fn to_rgb(&self) -> (u8, u8, u8) { + match *self { + Color::Black => (0, 0, 0), + Color::DarkBlue => (0, 0, 170), + Color::DarkGreen => (0, 170, 0), + Color::DarkAqua => (0, 170, 170), + Color::DarkRed => (170, 0, 0), + Color::DarkPurple => (170, 0, 170), + Color::Gold => (255, 170, 0), + Color::Gray => (170, 170, 170), + Color::DarkGray => (85, 85, 85), + Color::Blue => (85, 85, 255), + Color::Green => (85, 255, 85), + Color::Aqua => (85, 255, 255), + Color::Red => (255, 85, 85), + Color::LightPurple => (255, 85, 255), + Color::Yellow => (255, 255, 85), + Color::White => (255, 255, 255), + Color::RGB(r, g, b) => (r, g, b), + } + } +} + +#[test] +fn test_color_from() { + let test = Color::from_string(&"#FF0000".to_owned()); + match test { + Color::RGB(r, g, b) => assert!(r == 255 && g == 0 && b == 0), + _ => panic!("Wrong type"), + } + let test = Color::from_string(&"#123456".to_owned()); + match test { + Color::RGB(r, g, b) => assert!(r == 0x12 && g == 0x34 && b == 0x56), + _ => panic!("Wrong type"), + } + let test = Color::from_string(&"red".to_owned()); + match test { + Color::Red => {} + _ => panic!("Wrong type"), + } + let test = Color::from_string(&"dark_blue".to_owned()); + match test { + Color::DarkBlue => {} + _ => panic!("Wrong type"), + } +} + +const LEGACY_CHAR: char = 'ยง'; + +pub fn convert_legacy(c: &mut Component) { + match *c { + Component::Text(ref mut txt) => { + if let Some(ref mut extra) = txt.modifier.extra.as_mut() { + for e in extra.iter_mut() { + convert_legacy(e); + } + } + if txt.text.contains(LEGACY_CHAR) { + let mut parts = Vec::new(); + let mut last = 0; + let mut current = TextComponent::new(""); + { + let mut iter = txt.text.char_indices(); + while let Some((i, c)) = iter.next() { + if c == LEGACY_CHAR { + let next = match iter.next() { + Some(val) => val, + None => break, + }; + let color_char = next.1.to_lowercase().next().unwrap(); + current.text = txt.text[last..i].to_owned(); + last = next.0 + 1; + + let mut modifier = if (color_char >= 'a' && color_char <= 'f') || + (color_char >= '0' && color_char <= '9') { + Default::default() + } else { + current.modifier.clone() + }; + + let new = TextComponent::new(""); + parts.push(Component::Text(mem::replace(&mut current, new))); + + match color_char { + '0' => modifier.color = Some(Color::Black), + '1' => modifier.color = Some(Color::DarkBlue), + '2' => modifier.color = Some(Color::DarkGreen), + '3' => modifier.color = Some(Color::DarkAqua), + '4' => modifier.color = Some(Color::DarkRed), + '5' => modifier.color = Some(Color::DarkPurple), + '6' => modifier.color = Some(Color::Gold), + '7' => modifier.color = Some(Color::Gray), + '8' => modifier.color = Some(Color::DarkGray), + '9' => modifier.color = Some(Color::Blue), + 'a' => modifier.color = Some(Color::Green), + 'b' => modifier.color = Some(Color::Aqua), + 'c' => modifier.color = Some(Color::Red), + 'd' => modifier.color = Some(Color::LightPurple), + 'e' => modifier.color = Some(Color::Yellow), + 'f' => modifier.color = Some(Color::White), + 'k' => modifier.obfuscated = Some(true), + 'l' => modifier.bold = Some(true), + 'm' => modifier.strikethrough = Some(true), + 'n' => modifier.underlined = Some(true), + 'o' => modifier.italic = Some(true), + 'r' => {} + _ => unimplemented!(), + } + + current.modifier = modifier; + } + } + } + if last < txt.text.len() { + current.text = txt.text[last..].to_owned(); + parts.push(Component::Text(current)); + } + + let old = mem::replace(&mut txt.modifier.extra, Some(parts)); + if let Some(old_extra) = old { + if let Some(ref mut extra) = txt.modifier.extra.as_mut() { + extra.extend(old_extra); + } + } + txt.text = "".to_owned(); + } + } + } +} diff --git a/protocol/src/item.rs b/protocol/src/item.rs new file mode 100644 index 0000000..8aa6ab4 --- /dev/null +++ b/protocol/src/item.rs @@ -0,0 +1,105 @@ +// 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 crate::nbt; +use crate::protocol::{self, Serializable}; +use std::io; +use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; + +#[derive(Debug)] +pub struct Stack { + id: isize, + count: isize, + damage: Option, + tag: Option, +} + + +impl Default for Stack { + fn default() -> Stack { + Stack { + id: -1, + count: 0, + damage: None, + tag: None, + } + } +} + +impl Serializable for Option { + fn read_from(buf: &mut R) -> Result, protocol::Error> { + let protocol_version = protocol::current_protocol_version(); + + if protocol_version >= 404 { + let present = buf.read_u8()? != 0; + if !present { + return Ok(None) + } + } + + let id = if protocol_version >= 404 { + protocol::VarInt::read_from(buf)?.0 as isize + } else { + buf.read_i16::()? as isize + }; + + if id == -1 { + return Ok(None); + } + let count = buf.read_u8()? as isize; + let damage = if protocol_version >= 404 { + // 1.13.2+ stores damage in the NBT + None + } else { + Some(buf.read_i16::()? as isize) + }; + + let tag: Option = if protocol_version >= 47 { + Serializable::read_from(buf)? + } else { + // 1.7 uses a different slot data format described on https://wiki.vg/index.php?title=Slot_Data&diff=6056&oldid=4753 + let tag_size = buf.read_i16::()?; + if tag_size != -1 { + for _ in 0..tag_size { + let _ = buf.read_u8()?; + } + // TODO: decompress zlib NBT for 1.7 + None + } else { + None + } + }; + + Ok(Some(Stack { + id: id as isize, + count, + damage, + tag, + })) + } + fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { + match *self { + Some(ref val) => { + // TODO: if protocol_version >= 404, send present and id varint, no damage, for 1.13.2 + buf.write_i16::(val.id as i16)?; + buf.write_u8(val.count as u8)?; + buf.write_i16::(val.damage.unwrap_or(0) as i16)?; + // TODO: compress zlib NBT if 1.7 + val.tag.write_to(buf)?; + } + None => buf.write_i16::(-1)?, + } + Result::Ok(()) + } +} diff --git a/protocol/src/macros.rs b/protocol/src/macros.rs new file mode 100644 index 0000000..bf2b7a2 --- /dev/null +++ b/protocol/src/macros.rs @@ -0,0 +1,25 @@ + + +#[doc(hidden)] +#[macro_export] +macro_rules! create_ids { + ($t:ty, ) => (); + ($t:ty, prev($prev:ident), $name:ident) => ( + #[allow(non_upper_case_globals)] + pub const $name: $t = $prev + 1; + ); + ($t:ty, prev($prev:ident), $name:ident, $($n:ident),+) => ( + #[allow(non_upper_case_globals)] + pub const $name: $t = $prev + 1; + create_ids!($t, prev($name), $($n),+); + ); + ($t:ty, $name:ident, $($n:ident),+) => ( + #[allow(non_upper_case_globals)] + pub const $name: $t = 0; + create_ids!($t, prev($name), $($n),+); + ); + ($t:ty, $name:ident) => ( + #[allow(non_upper_case_globals)] + pub const $name: $t = 0; + ); +} diff --git a/protocol/src/nbt/mod.rs b/protocol/src/nbt/mod.rs new file mode 100644 index 0000000..37c3eca --- /dev/null +++ b/protocol/src/nbt/mod.rs @@ -0,0 +1,311 @@ +// 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::io; +use std::io::Read; + +use super::protocol::Serializable; +use super::protocol; +use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; + +#[derive(Debug, Clone)] +pub enum Tag { + End, + Byte(i8), + Short(i16), + Int(i32), + Long(i64), + Float(f32), + Double(f64), + ByteArray(Vec), + String(String), + List(Vec), + Compound(HashMap), + IntArray(Vec), + LongArray(Vec), +} + +#[derive(Debug, Clone)] +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 { + match *self { + Tag::Byte(val) => Some(val), + _ => None, + } + } + + pub fn as_short(&self) -> Option { + match *self { + Tag::Short(val) => Some(val), + _ => None, + } + } + + pub fn as_int(&self) -> Option { + match *self { + Tag::Int(val) => Some(val), + _ => None, + } + } + + pub fn as_long(&self) -> Option { + match *self { + Tag::Long(val) => Some(val), + _ => None, + } + } + + pub fn as_float(&self) -> Option { + match *self { + Tag::Float(val) => Some(val), + _ => None, + } + } + + pub fn as_double(&self) -> Option { + 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_str(&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> { + 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, + } + } + + 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, + 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, + Tag::LongArray(_) => 12, + } + } + + fn read_type(id: u8, buf: &mut R) -> Result { + match id { + 0 => unreachable!(), + 1 => Ok(Tag::Byte(buf.read_i8()?)), + 2 => Ok(Tag::Short(buf.read_i16::()?)), + 3 => Ok(Tag::Int(buf.read_i32::()?)), + 4 => Ok(Tag::Long(buf.read_i64::()?)), + 5 => Ok(Tag::Float(buf.read_f32::()?)), + 6 => Ok(Tag::Double(buf.read_f64::()?)), + 7 => Ok(Tag::ByteArray({ + let len: i32 = Serializable::read_from(buf)?; + let mut data = Vec::with_capacity(len as usize); + buf.take(len as u64).read_to_end(&mut data)?; + data + })), + 8 => Ok(Tag::String(read_string(buf)?)), + 9 => { + let mut l = Vec::new(); + let ty = buf.read_u8()?; + let len: i32 = Serializable::read_from(buf)?; + for _ in 0..len { + l.push(Tag::read_type(ty, buf)?); + } + Ok(Tag::List(l)) + } + 10 => { + let mut c = Tag::new_compound(); + loop { + let ty = buf.read_u8()?; + if ty == 0 { + break; + } + let name: String = read_string(buf)?; + c.put(&name[..], Tag::read_type(ty, buf)?); + } + Ok(c) + } + 11 => Ok(Tag::IntArray({ + let len: i32 = Serializable::read_from(buf)?; + let mut data = Vec::with_capacity(len as usize); + for _ in 0..len { + data.push(buf.read_i32::()?); + } + 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::()?); + } + data + })), + _ => Err(protocol::Error::Err("invalid tag".to_owned())), + } + } +} + +impl Serializable for Tag { + fn read_from(buf: &mut R) -> Result { + Tag::read_type(10, buf) + } + + fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { + match *self { + Tag::End => {} + Tag::Byte(val) => buf.write_i8(val)?, + Tag::Short(val) => buf.write_i16::(val)?, + Tag::Int(val) => buf.write_i32::(val)?, + Tag::Long(val) => buf.write_i64::(val)?, + Tag::Float(val) => buf.write_f32::(val)?, + Tag::Double(val) => buf.write_f64::(val)?, + Tag::ByteArray(ref val) => { + (val.len() as i32).write_to(buf)?; + buf.write_all(val)?; + } + Tag::String(ref val) => write_string(buf, val)?, + Tag::List(ref val) => { + if val.is_empty() { + buf.write_u8(0)?; + buf.write_i32::(0)?; + } else { + buf.write_u8(val[0].internal_id())?; + buf.write_i32::(val.len() as i32)?; + for e in val { + e.write_to(buf)?; + } + } + } + Tag::Compound(ref val) => { + for (k, v) in val { + v.internal_id().write_to(buf)?; + write_string(buf, k)?; + v.write_to(buf)?; + } + buf.write_u8(0)?; + } + Tag::IntArray(ref val) => { + (val.len() as i32).write_to(buf)?; + for v in val { + 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(()) + } +} + +pub fn write_string(buf: &mut W, s: &str) -> Result<(), protocol::Error> { + let data = s.as_bytes(); + (data.len() as i16).write_to(buf)?; + buf.write_all(data).map_err(|v| v.into()) +} + +pub fn read_string(buf: &mut R) -> Result { + let len: i16 = buf.read_i16::()?; + let mut bytes = Vec::::new(); + buf.take(len as u64).read_to_end(&mut bytes)?; + let ret = String::from_utf8(bytes).unwrap(); + Result::Ok(ret) +} diff --git a/protocol/src/types/bit/map.rs b/protocol/src/types/bit/map.rs new file mode 100644 index 0000000..2f86979 --- /dev/null +++ b/protocol/src/types/bit/map.rs @@ -0,0 +1,105 @@ +// 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. + +pub struct Map { + bits: Vec, + pub bit_size: usize, + length: usize, +} + +#[test] +fn test_map() { + let mut map = Map::new(4096, 4); + for i in 0..4096 { + for j in 0..16 { + map.set(i, j); + if map.get(i) != j { + panic!("Fail"); + } + } + } +} + +#[test] +fn test_map_odd() { + for size in 1..16 { + let mut map = Map::new(64 * 3, size); + let max = (1 << size) - 1; + for i in 0..64 * 3 { + for j in 0..max { + map.set(i, j); + if map.get(i) != j { + panic!("Index: {} wanted {} and got {}", i, j, map.get(i)); + } + } + } + } +} + +impl Map { + pub fn new(len: usize, size: usize) -> Map { + let mut map = Map { + bit_size: size, + length: len, + bits: Vec::with_capacity((len * size) / 64), + }; + for _ in 0..len { + map.bits.push(0) + } + map + } + pub fn from_raw(bits: Vec, size: usize) -> Map { + Map { + length: (bits.len()*64 + (size-1)) / size, + bit_size: size, + bits, + } + } + + pub fn resize(&self, size: usize) -> Map { + let mut n = Map::new(self.length, size); + for i in 0..self.length { + n.set(i, self.get(i)); + } + n + } + + pub fn set(&mut self, i: usize, val: usize) { + let i = i * self.bit_size; + let pos = i / 64; + let mask = (1u64 << self.bit_size) - 1; + let ii = i % 64; + self.bits[pos] = (self.bits[pos] & !(mask << ii)) | ((val as u64) << ii); + let pos2 = (i + self.bit_size - 1) / 64; + if pos2 != pos { + let used = 64 - ii; + let rem = self.bit_size - used; + self.bits[pos2] = self.bits[pos2] >> rem << rem | (val as u64 >> used); + } + } + + pub fn get(&self, i: usize) -> usize { + let i = i * self.bit_size; + let pos = i / 64; + let mask = (1 << self.bit_size) - 1; + let ii = i % 64; + let pos2 = (i + self.bit_size - 1) / 64; + if pos2 == pos { + ((self.bits[pos] >> ii) & mask) as usize + } else { + let used = 64 - ii; + (((self.bits[pos] >> ii) | (self.bits[pos2] << used)) & mask) as usize + } + } +} diff --git a/protocol/src/types/bit/mod.rs b/protocol/src/types/bit/mod.rs new file mode 100644 index 0000000..6754eab --- /dev/null +++ b/protocol/src/types/bit/mod.rs @@ -0,0 +1,19 @@ +// 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. + +pub mod set; +pub mod map; + +pub use self::set::Set; +pub use self::map::Map; diff --git a/protocol/src/types/bit/set.rs b/protocol/src/types/bit/set.rs new file mode 100644 index 0000000..894d936 --- /dev/null +++ b/protocol/src/types/bit/set.rs @@ -0,0 +1,74 @@ +// 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. + +#[derive(Clone, Debug)] +pub struct Set { + data: Vec, +} + +#[test] +fn test_set() { + let mut set = Set::new(200); + for i in 0..200 { + if i % 3 == 0 { + set.set(i, true) + } + } + for i in 0..200 { + if set.get(i) != (i % 3 == 0) { + panic!("Fail") + } + } +} + +impl Set { + pub fn new(size: usize) -> Set { + Set { data: vec![0; (size + 63) / 64] } + } + + pub fn resize(&mut self, new_size: usize) { + self.data.resize((new_size + 63) / 64, 0); + } + + pub fn capacity(&self) -> usize { + self.data.len() * 64 + } + + pub fn set(&mut self, i: usize, v: bool) { + if v { + self.data[i >> 6] |= 1 << (i & 0x3F) + } else { + self.data[i >> 6] &= !(1 << (i & 0x3F)) + } + } + + pub fn get(&self, i: usize) -> bool { + (self.data[i >> 6] & (1 << (i & 0x3F))) != 0 + } + + pub fn includes_set(&self, other: &Set) -> bool { + for (a, b) in self.data.iter().zip(&other.data) { + if a & b != *b { + return false; + } + } + true + } + + pub fn or(&mut self, other: &Set) { + for (a, b) in self.data.iter_mut().zip(&other.data) { + *a |= *b; + } + } +} diff --git a/protocol/src/types/hash.rs b/protocol/src/types/hash.rs new file mode 100644 index 0000000..cf16af9 --- /dev/null +++ b/protocol/src/types/hash.rs @@ -0,0 +1,24 @@ + + +use std::hash::Hasher; + +pub struct FNVHash(u64); + +impl Hasher for FNVHash { + fn write(&mut self, bytes: &[u8]) { + for b in bytes { + self.0 = self.0.wrapping_mul(0x100000001b3); + self.0 ^= *b as u64 + } + } + + fn finish(&self) -> u64 { + self.0 + } +} + +impl Default for FNVHash { + fn default() -> Self { + FNVHash(0xcbf29ce484222325) + } +} diff --git a/protocol/src/types/metadata.rs b/protocol/src/types/metadata.rs new file mode 100644 index 0000000..17c18eb --- /dev/null +++ b/protocol/src/types/metadata.rs @@ -0,0 +1,964 @@ +// 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::protocol::LenPrefixed; +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()); + } + + fn read_from18(buf: &mut R) -> Result { + 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::::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_to18(&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)?; + } + + _ => { + panic!("attempted to write 1.9+ metadata to 1.8"); + } + } + } + u8::write_to(&0x7f, buf)?; + Ok(()) + } + + fn read_from19(buf: &mut R) -> Result { + let mut m = Self::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_to19(&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)?; + } + _ => panic!("unexpected metadata"), + } + } + u8::write_to(&0xFF, buf)?; + Ok(()) + } + + fn read_from113(buf: &mut R) -> Result { + let mut m = Self::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, LenPrefixed::::read_from(buf)?), + 6 => m.put_raw(index, Option::::read_from(buf)?), + 7 => m.put_raw(index, bool::read_from(buf)?), + 8 => m.put_raw(index, + [f32::read_from(buf)?, + f32::read_from(buf)?, + f32::read_from(buf)?]), + 9 => m.put_raw(index, Position::read_from(buf)?), + 10 => { + if bool::read_from(buf)? { + m.put_raw(index, Option::::read_from(buf)?); + } else { + m.put_raw::>(index, None); + } + } + 11 => m.put_raw(index, protocol::VarInt::read_from(buf)?), + 12 => { + if bool::read_from(buf)? { + m.put_raw(index, Option::::read_from(buf)?); + } else { + m.put_raw::>(index, None); + } + } + 13 => m.put_raw(index, protocol::VarInt::read_from(buf)?.0 as u16), + 14 => { + 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)); + } + } + 15 => panic!("TODO: particle"), + 16 => m.put_raw(index, VillagerData::read_from(buf)?), + 17 => { + if bool::read_from(buf)? { + m.put_raw(index, Option::::read_from(buf)?); + } else { + m.put_raw::>(index, None); + } + }, + 18 => m.put_raw(index, PoseData::read_from(buf)?), + _ => return Err(protocol::Error::Err("unknown metadata type".to_owned())), + } + } + Ok(m) + } + + fn write_to113(&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::OptionalFormatComponent(ref val) => { + u8::write_to(&5, buf)?; + val.write_to(buf)?; + } + Value::OptionalItemStack(ref val) => { + u8::write_to(&6, buf)?; + val.write_to(buf)?; + } + Value::Bool(ref val) => { + u8::write_to(&7, buf)?; + val.write_to(buf)?; + } + Value::Vector(ref val) => { + u8::write_to(&8, buf)?; + val[0].write_to(buf)?; + val[1].write_to(buf)?; + val[2].write_to(buf)?; + } + Value::Position(ref val) => { + u8::write_to(&9, buf)?; + val.write_to(buf)?; + } + Value::OptionalPosition(ref val) => { + u8::write_to(&10, buf)?; + val.is_some().write_to(buf)?; + val.write_to(buf)?; + } + Value::Direction(ref val) => { + u8::write_to(&11, buf)?; + val.write_to(buf)?; + } + Value::OptionalUUID(ref val) => { + u8::write_to(&12, buf)?; + val.is_some().write_to(buf)?; + val.write_to(buf)?; + } + Value::Block(ref val) => { + u8::write_to(&13, buf)?; + protocol::VarInt(*val as i32).write_to(buf)?; + } + Value::NBTTag(ref _val) => { + u8::write_to(&14, buf)?; + // TODO: write NBT tags metadata + //nbt::Tag(*val).write_to(buf)?; + } + Value::Particle(ref val) => { + u8::write_to(&15, buf)?; + val.write_to(buf)?; + } + Value::Villager(ref val) => { + u8::write_to(&16, buf)?; + val.write_to(buf)?; + } + Value::OptionalVarInt(ref val) => { + u8::write_to(&17, buf)?; + val.write_to(buf)?; + } + Value::Pose(ref val) => { + u8::write_to(&18, buf)?; + val.write_to(buf)?; + } + _ => panic!("unexpected metadata"), + } + } + u8::write_to(&0xFF, buf)?; + Ok(()) + } + + +} + +impl Serializable for Metadata { + fn read_from(buf: &mut R) -> Result { + let protocol_version = protocol::current_protocol_version(); + + if protocol_version >= 404 { + Metadata::read_from113(buf) + } else if protocol_version >= 74 { + Metadata::read_from19(buf) + } else { + Metadata::read_from18(buf) + } + } + + fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { + let protocol_version = protocol::current_protocol_version(); + + if protocol_version >= 404 { + self.write_to113(buf) + } else if protocol_version >= 74 { + self.write_to19(buf) + } else { + self.write_to18(buf) + } + } +} + +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), + Short(i16), + Int(i32), + Float(f32), + String(String), + FormatComponent(format::Component), + OptionalFormatComponent(LenPrefixed), + OptionalItemStack(Option), + Bool(bool), + Vector([f32; 3]), + Rotation([i32; 3]), + Position(Position), + OptionalPosition(Option), + Direction(protocol::VarInt), // TODO: Proper type + OptionalUUID(Option), + Block(u16), // TODO: Proper type + NBTTag(nbt::NamedTag), + Particle(ParticleData), + Villager(VillagerData), + OptionalVarInt(Option), + Pose(PoseData), +} + +#[derive(Debug)] +pub enum ParticleData { + AmbientEntityEffect, + AngryVillager, + Barrier, + Block { + block_state: protocol::VarInt, + }, + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + DrippingWater, + Dust { + red: f32, + green: f32, + blue: f32, + scale: f32, + }, + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust { + block_state: protocol::VarInt, + }, + Firework, + Fishing, + Flame, + HappyVillager, + Heart, + InstantEffect, + Item { + item: Option, + }, + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BubblePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, +} + +impl Serializable for ParticleData { + fn read_from(buf: &mut R) -> Result { + let id = protocol::VarInt::read_from(buf)?.0; + Ok(match id { + 0 => ParticleData::AmbientEntityEffect, + 1 => ParticleData::AngryVillager, + 2 => ParticleData::Barrier, + 3 => ParticleData::Block { + block_state: Serializable::read_from(buf)? + }, + 4 => ParticleData::Bubble, + 5 => ParticleData::Cloud, + 6 => ParticleData::Crit, + 7 => ParticleData::DamageIndicator, + 8 => ParticleData::DragonBreath, + 9 => ParticleData::DrippingLava, + 10 => ParticleData::DrippingWater, + 11 => ParticleData::Dust { + red: Serializable::read_from(buf)?, + green: Serializable::read_from(buf)?, + blue: Serializable::read_from(buf)?, + scale: Serializable::read_from(buf)?, + }, + 12 => ParticleData::Effect, + 13 => ParticleData::ElderGuardian, + 14 => ParticleData::EnchantedHit, + 15 => ParticleData::Enchant, + 16 => ParticleData::EndRod, + 17 => ParticleData::EntityEffect, + 18 => ParticleData::ExplosionEmitter, + 19 => ParticleData::Explosion, + 20 => ParticleData::FallingDust { + block_state: Serializable::read_from(buf)?, + }, + 21 => ParticleData::Firework, + 22 => ParticleData::Fishing, + 23 => ParticleData::Flame, + 24 => ParticleData::HappyVillager, + 25 => ParticleData::Heart, + 26 => ParticleData::InstantEffect, + 27 => ParticleData::Item { + item: Serializable::read_from(buf)?, + }, + 28 => ParticleData::ItemSlime, + 29 => ParticleData::ItemSnowball, + 30 => ParticleData::LargeSmoke, + 31 => ParticleData::Lava, + 32 => ParticleData::Mycelium, + 33 => ParticleData::Note, + 34 => ParticleData::Poof, + 35 => ParticleData::Portal, + 36 => ParticleData::Rain, + 37 => ParticleData::Smoke, + 38 => ParticleData::Spit, + 39 => ParticleData::SquidInk, + 40 => ParticleData::SweepAttack, + 41 => ParticleData::TotemOfUndying, + 42 => ParticleData::Underwater, + 43 => ParticleData::Splash, + 44 => ParticleData::Witch, + 45 => ParticleData::BubblePop, + 46 => ParticleData::CurrentDown, + 47 => ParticleData::BubbleColumnUp, + 48 => ParticleData::Nautilus, + 49 => ParticleData::Dolphin, + _ => panic!("unrecognized particle data id {}", id), + }) + } + + fn write_to(&self, _buf: &mut W) -> Result<(), protocol::Error> { + unimplemented!() + } +} + +#[derive(Debug)] +pub struct VillagerData { + villager_type: protocol::VarInt, + profession: protocol::VarInt, + level: protocol::VarInt, +} + +impl Serializable for VillagerData { + fn read_from(buf: &mut R) -> Result { + let villager_type = protocol::VarInt::read_from(buf)?; + let profession = protocol::VarInt::read_from(buf)?; + let level = protocol::VarInt::read_from(buf)?; + Ok(VillagerData { villager_type, profession, level }) + } + + fn write_to(&self, _buf: &mut W) -> Result<(), protocol::Error> { + unimplemented!() + } +} + +#[derive(Debug)] +pub enum PoseData { + Standing, + FallFlying, + Sleeping, + Swimming, + SpinAttack, + Sneaking, + Dying, +} + +impl Serializable for PoseData { + fn read_from(buf: &mut R) -> Result { + let n = protocol::VarInt::read_from(buf)?; + Ok(match n.0 { + 0 => PoseData::Standing, + 1 => PoseData::FallFlying, + 2 => PoseData::Sleeping, + 3 => PoseData::Swimming, + 4 => PoseData::SpinAttack, + 5 => PoseData::Sneaking, + 6 => PoseData::Dying, + _ => panic!("unknown pose data: {}", n.0), + }) + } + + fn write_to(&self, _buf: &mut W) -> Result<(), protocol::Error> { + unimplemented!() + } +} + + + +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 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 { + 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 LenPrefixed { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::OptionalFormatComponent(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::OptionalFormatComponent(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 [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 { + 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) + } +} + +impl MetaValue for VillagerData { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Villager(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Villager(self) + } +} + +impl MetaValue for Option { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::OptionalVarInt(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::OptionalVarInt(self) + } +} + +impl MetaValue for PoseData { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::Pose(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::Pose(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"), + } + } +} diff --git a/protocol/src/types/mod.rs b/protocol/src/types/mod.rs new file mode 100644 index 0000000..5232c8c --- /dev/null +++ b/protocol/src/types/mod.rs @@ -0,0 +1,60 @@ +// 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. + +mod metadata; +pub use self::metadata::*; + +pub mod bit; +pub mod nibble; +pub mod hash; + +#[derive(Clone, Copy, Debug)] +pub enum Gamemode { + Survival = 0, + Creative = 1, + Adventure = 2, + Spectator = 3, +} + +impl Gamemode { + pub fn from_int(val: i32) -> Gamemode { + match val { + 3 => Gamemode::Spectator, + 2 => Gamemode::Adventure, + 1 => Gamemode::Creative, + 0 | _ => Gamemode::Survival, + } + } + + pub fn can_fly(&self) -> bool { + match *self { + Gamemode::Creative | Gamemode::Spectator => true, + _ => false, + } + } + + pub fn always_fly(&self) -> bool { + match *self { + Gamemode::Spectator => true, + _ => false, + } + } + + pub fn noclip(&self) -> bool { + match *self { + Gamemode::Spectator => true, + _ => false, + } + } +} diff --git a/protocol/src/types/nibble.rs b/protocol/src/types/nibble.rs new file mode 100644 index 0000000..91ecdc8 --- /dev/null +++ b/protocol/src/types/nibble.rs @@ -0,0 +1,45 @@ +// Copyright 2015 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. + + +pub struct Array { + pub data: Vec, +} + +impl Array { + pub fn new(size: usize) -> Array { + Array { + data: vec![0; (size + 1) >> 1], + } + } + + pub fn get(&self, idx: usize) -> u8 { + let val = self.data[idx>>1]; + if idx&1 == 0 { + val & 0xF + } else { + val >> 4 + } + } + + pub fn set(&mut self, idx: usize, val: u8) { + let i = idx >> 1; + let old = self.data[i]; + if idx&1 == 0 { + self.data[i] = (old & 0xF0) | (val & 0xF); + } else { + self.data[i] = (old & 0x0F) | ((val & 0xF) << 4); + } + } +}