Add protocol dependencies for #167

This commit is contained in:
ice_iix 2020-02-02 05:50:17 -08:00
commit 3baba519c8
11 changed files with 2109 additions and 0 deletions

377
protocol/src/format.rs Normal file
View File

@ -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::<serde_json::Value>(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<Vec<Component>>,
pub bold: Option<bool>,
pub italic: Option<bool>,
pub underlined: Option<bool>,
pub strikethrough: Option<bool>,
pub obfuscated: Option<bool>,
pub color: Option<Color>,
}
// 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();
}
}
}
}

105
protocol/src/item.rs Normal file
View File

@ -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<isize>,
tag: Option<nbt::NamedTag>,
}
impl Default for Stack {
fn default() -> Stack {
Stack {
id: -1,
count: 0,
damage: None,
tag: None,
}
}
}
impl Serializable for Option<Stack> {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<Stack>, 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::<BigEndian>()? 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::<BigEndian>()? as isize)
};
let tag: Option<nbt::NamedTag> = 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::<BigEndian>()?;
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<W: io::Write>(&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::<BigEndian>(val.id as i16)?;
buf.write_u8(val.count as u8)?;
buf.write_i16::<BigEndian>(val.damage.unwrap_or(0) as i16)?;
// TODO: compress zlib NBT if 1.7
val.tag.write_to(buf)?;
}
None => buf.write_i16::<BigEndian>(-1)?,
}
Result::Ok(())
}
}

25
protocol/src/macros.rs Normal file
View File

@ -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;
);
}

311
protocol/src/nbt/mod.rs Normal file
View File

@ -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<u8>),
String(String),
List(Vec<Tag>),
Compound(HashMap<String, Tag>),
IntArray(Vec<i32>),
LongArray(Vec<i64>),
}
#[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<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_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<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,
}
}
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<R: io::Read>(id: u8, buf: &mut R) -> Result<Tag, protocol::Error> {
match id {
0 => unreachable!(),
1 => Ok(Tag::Byte(buf.read_i8()?)),
2 => Ok(Tag::Short(buf.read_i16::<BigEndian>()?)),
3 => Ok(Tag::Int(buf.read_i32::<BigEndian>()?)),
4 => Ok(Tag::Long(buf.read_i64::<BigEndian>()?)),
5 => Ok(Tag::Float(buf.read_f32::<BigEndian>()?)),
6 => Ok(Tag::Double(buf.read_f64::<BigEndian>()?)),
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::<BigEndian>()?);
}
data
})),
12 => Ok(Tag::LongArray({
let len: i32 = Serializable::read_from(buf)?;
let mut data = Vec::with_capacity(len as usize);
for _ in 0..len {
data.push(buf.read_i64::<BigEndian>()?);
}
data
})),
_ => Err(protocol::Error::Err("invalid tag".to_owned())),
}
}
}
impl Serializable for Tag {
fn read_from<R: io::Read>(buf: &mut R) -> Result<Tag, protocol::Error> {
Tag::read_type(10, buf)
}
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), protocol::Error> {
match *self {
Tag::End => {}
Tag::Byte(val) => buf.write_i8(val)?,
Tag::Short(val) => buf.write_i16::<BigEndian>(val)?,
Tag::Int(val) => buf.write_i32::<BigEndian>(val)?,
Tag::Long(val) => buf.write_i64::<BigEndian>(val)?,
Tag::Float(val) => buf.write_f32::<BigEndian>(val)?,
Tag::Double(val) => buf.write_f64::<BigEndian>(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::<BigEndian>(0)?;
} else {
buf.write_u8(val[0].internal_id())?;
buf.write_i32::<BigEndian>(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<W: io::Write>(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<R: io::Read>(buf: &mut R) -> Result<String, protocol::Error> {
let len: i16 = buf.read_i16::<BigEndian>()?;
let mut bytes = Vec::<u8>::new();
buf.take(len as u64).read_to_end(&mut bytes)?;
let ret = String::from_utf8(bytes).unwrap();
Result::Ok(ret)
}

View File

@ -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<u64>,
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<u64>, 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
}
}
}

View File

@ -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;

View File

@ -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<u64>,
}
#[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;
}
}
}

View File

@ -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)
}
}

View File

@ -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<T: MetaValue> {
index: i32,
ty: PhantomData<T>,
}
impl <T: MetaValue> MetadataKey<T> {
#[allow(dead_code)]
fn new(index: i32) -> MetadataKey<T> {
MetadataKey {
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());
}
fn read_from18<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
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_to18<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)?;
}
_ => {
panic!("attempted to write 1.9+ metadata to 1.8");
}
}
}
u8::write_to(&0x7f, buf)?;
Ok(())
}
fn read_from19<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 {
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::<item::Stack>::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::<Position>::read_from(buf)?);
} else {
m.put_raw::<Option<Position>>(index, None);
}
}
10 => m.put_raw(index, protocol::VarInt::read_from(buf)?),
11 => {
if bool::read_from(buf)? {
m.put_raw(index, Option::<protocol::UUID>::read_from(buf)?);
} else {
m.put_raw::<Option<protocol::UUID>>(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<W: io::Write>(&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<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 {
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::<bool, format::Component>::read_from(buf)?),
6 => m.put_raw(index, Option::<item::Stack>::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::<Position>::read_from(buf)?);
} else {
m.put_raw::<Option<Position>>(index, None);
}
}
11 => m.put_raw(index, protocol::VarInt::read_from(buf)?),
12 => {
if bool::read_from(buf)? {
m.put_raw(index, Option::<protocol::UUID>::read_from(buf)?);
} else {
m.put_raw::<Option<protocol::UUID>>(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::<protocol::VarInt>::read_from(buf)?);
} else {
m.put_raw::<Option<protocol::VarInt>>(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<W: io::Write>(&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<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
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<W: io::Write>(&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<bool, format::Component>),
OptionalItemStack(Option<item::Stack>),
Bool(bool),
Vector([f32; 3]),
Rotation([i32; 3]),
Position(Position),
OptionalPosition(Option<Position>),
Direction(protocol::VarInt), // TODO: Proper type
OptionalUUID(Option<protocol::UUID>),
Block(u16), // TODO: Proper type
NBTTag(nbt::NamedTag),
Particle(ParticleData),
Villager(VillagerData),
OptionalVarInt(Option<protocol::VarInt>),
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<item::Stack>,
},
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<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
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<W: io::Write>(&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<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
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<W: io::Write>(&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<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
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<W: io::Write>(&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<bool, format::Component> {
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<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 [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<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)
}
}
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<protocol::VarInt> {
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<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"),
}
}
}

60
protocol/src/types/mod.rs Normal file
View File

@ -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,
}
}
}

View File

@ -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<u8>,
}
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);
}
}
}