2016-03-16 14:25:35 -04:00
|
|
|
// Copyright 2016 Matthew Collins
|
2015-09-17 11:21:56 -04:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
#![allow(dead_code)]
|
2018-12-03 17:22:47 -05:00
|
|
|
#![allow(non_camel_case_types)]
|
2015-09-17 11:04:25 -04:00
|
|
|
|
2018-11-01 23:45:40 -04:00
|
|
|
use aes::Aes128;
|
|
|
|
use cfb8::Cfb8;
|
|
|
|
use cfb8::stream_cipher::{NewStreamCipher, StreamCipher};
|
2015-09-17 11:04:25 -04:00
|
|
|
use serde_json;
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
use reqwest;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
pub mod mojang;
|
|
|
|
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::nbt;
|
|
|
|
use crate::format;
|
2015-09-12 15:31:26 -04:00
|
|
|
use std::fmt;
|
2015-09-08 07:57:24 -04:00
|
|
|
use std::default;
|
2015-09-07 16:11:00 -04:00
|
|
|
use std::net::TcpStream;
|
|
|
|
use std::io;
|
|
|
|
use std::io::{Write, Read};
|
|
|
|
use std::convert;
|
2015-09-17 11:04:25 -04:00
|
|
|
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
|
|
|
use flate2::read::{ZlibDecoder, ZlibEncoder};
|
2018-09-30 19:19:24 -04:00
|
|
|
use flate2::Compression;
|
2018-09-30 01:57:55 -04:00
|
|
|
use std::time::{Instant, Duration};
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::shared::Position;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
1.13.2 (404) multiprotocol support (#67)
Adds support for 1.13.2 protocol (404)
Expands https://github.com/iceiix/steven/issues/18 Enhance protocol support
Metadata:
* Support 1.13.2 slot data format, bool and varint item id, optional damage (moved to NBT)
https://wiki.vg/index.php?title=Slot_Data&type=revision&diff=14363&oldid=7835
Packets:
* Add 1.13.2 packets, and implement all the command data parsers
https://wiki.vg/Command_Data#Parsers
* Send new plugin channel minecraft:brand
https://wiki.vg/Plugin_channels#minecraft:brand
* Add 1.13.2 metadata format, with shifted IDs
https://wiki.vg/Entity_metadata#Entity_Metadata_Format
* Implement particle entity metadata
* Add structures for 16 new packets
Blocks: The Flattening:
* Assign flattened IDs in correct order using new 'offset' macro token
* Assign hierarchical (pre-flattening) block IDs sequentially by counting Some data
* Split VANILLA_ID_MAP into flat/hier struct, to support before and after the flattening
* Extend travis build time to 20 minutes because the blocks macro takes a long time
* Support both flat/hier blocks by passing protocol_version to by_vanilla_id
Add block states and offsets for all blocks, replacing metadata for 1.13+:
* Add stripped logs and what was Log2 to Log
* Add the Wood blocks, should be called bark, previously Axis::None Log
* Add leaves distance and offset
* Add jungle/acacia to Leaves moved from Leaves2
* Add dispenser offsets, direction
* Add note block states
* Add offset None to Missing253 and Missing254, no holes in block states of 1.13.2
* Add bed colors
* Add seagrass, tall seagrass, remove redundant deadgrass, and piston offset
* Add torch, TNT, fire offsets, remove slabs
* Add furnance offset, merges lit into a property
* Add pressure plate offsets, new pressure plates, redstone ore/lit merged
* Add lever offsets, new directions from ceiling/floor, rename LeverDirections
* Add redstone torch offsets, new blocks since lit/unlit is now merged, and standing/wall is split
* Change lever to split face/facing, rm LeverDirection, add AttachedFace
* Add stone button offsets, face/facing similar to lever
* Move face/facing data and variant to AttachedFace, reuse for lever/stonebutton
* Add data_with_facing_and_powered() to AttachedFace, for lever/stonebutton
* Add wooden button offsets each wood
* Add pumpkin without a face
* Add carved pumpkin, portal offsets
* Add lit pumpkin (as jack-o-lantern) offsets after carved pumpkin
* Add repeater offsets, merged into Repeater
* Change brown mushroom block to booleans instead of MushroomVariant
* Add mushroom block offsets, red/brown mushroom blocks, and a new mushroom stem block
* Add command block, cobblestone walls, and flower pot offsets
Empty flower pot, and potted plants including saplings. Rename
variant DarkOak to DarkOakSaplings because it is a sapling, and
remove the duplicate Dandelion variant which causes duplicate blocks.
* Increase recursion limit in steven_blocks
* Add colored banner offsets
* Add wooden slab including double slab, in a different position for pre-1.13 and 1.13
* StoneSlabVariant::Wood -> StoneSlabVariant::PetrifiedWood
* Add fence_gate_offset() for wooden fence gates
* Add frosted ice age, offset
* Add new blocks: kelp, turtle egg, coral, coral fans, sea pickle, blue ice, smooth stone
* Add new blocks: conduit, void air, cave aid, bubble column, last of the 1.13 blocks
2018-12-29 00:11:42 -05:00
|
|
|
pub const SUPPORTED_PROTOCOLS: [i32; 10] = [404, 340, 316, 315, 210, 109, 107, 74, 47, 5];
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2018-12-11 21:18:25 -05:00
|
|
|
// TODO: switch to using thread_local storage?, see https://doc.rust-lang.org/std/macro.thread_local.html
|
|
|
|
pub static mut CURRENT_PROTOCOL_VERSION: i32 = SUPPORTED_PROTOCOLS[0];
|
2016-03-18 07:39:03 -04:00
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
/// Helper macro for defining packets
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! state_packets {
|
|
|
|
($($state:ident $stateName:ident {
|
|
|
|
$($dir:ident $dirName:ident {
|
2015-09-12 15:31:26 -04:00
|
|
|
$(
|
2016-04-04 18:50:27 -04:00
|
|
|
$(#[$attr:meta])*
|
|
|
|
packet $name:ident {
|
|
|
|
$($(#[$fattr:meta])*field $field:ident: $field_type:ty = $(when ($cond:expr))*, )+
|
|
|
|
}
|
|
|
|
)*
|
2015-09-07 16:11:00 -04:00
|
|
|
})+
|
|
|
|
})+) => {
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::protocol::*;
|
2015-09-07 16:11:00 -04:00
|
|
|
use std::io;
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
#[derive(Debug)]
|
2015-09-07 16:11:00 -04:00
|
|
|
pub enum Packet {
|
|
|
|
$(
|
|
|
|
$(
|
|
|
|
$(
|
|
|
|
$name($state::$dir::$name),
|
|
|
|
)*
|
|
|
|
)+
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
|
|
|
|
$(
|
|
|
|
pub mod $state {
|
2016-03-18 07:39:03 -04:00
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
$(
|
|
|
|
pub mod $dir {
|
2015-09-10 06:49:41 -04:00
|
|
|
#![allow(unused_imports)]
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::protocol::*;
|
2015-09-07 16:11:00 -04:00
|
|
|
use std::io;
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::format;
|
|
|
|
use crate::nbt;
|
|
|
|
use crate::types;
|
|
|
|
use crate::item;
|
|
|
|
use crate::shared::Position;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2016-03-18 07:39:03 -04:00
|
|
|
|
2018-11-30 20:02:26 -05:00
|
|
|
#[allow(non_upper_case_globals)]
|
2016-03-18 07:39:03 -04:00
|
|
|
pub mod internal_ids {
|
2018-12-03 17:22:47 -05:00
|
|
|
create_ids!(i32, $($name),*);
|
2016-03-18 07:39:03 -04:00
|
|
|
}
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
$(
|
2015-09-12 15:31:26 -04:00
|
|
|
#[derive(Default, Debug)]
|
2016-04-04 18:50:27 -04:00
|
|
|
$(#[$attr])* pub struct $name {
|
|
|
|
$($(#[$fattr])* pub $field: $field_type),+,
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PacketType for $name {
|
|
|
|
|
2018-12-03 17:22:47 -05:00
|
|
|
fn packet_id(&self, version: i32) -> i32 {
|
|
|
|
packet::versions::translate_internal_packet_id_for_version(version, State::$stateName, Direction::$dirName, internal_ids::$name, false)
|
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write<W: io::Write>(self, buf: &mut W) -> Result<(), Error> {
|
2015-09-07 16:11:00 -04:00
|
|
|
$(
|
2015-09-10 06:49:41 -04:00
|
|
|
if true $(&& ($cond(&self)))* {
|
2018-11-04 14:34:53 -05:00
|
|
|
self.$field.write_to(buf)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
)+
|
|
|
|
|
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
)+
|
|
|
|
|
|
|
|
/// Returns the packet for the given state, direction and id after parsing the fields
|
|
|
|
/// from the buffer.
|
2018-12-03 17:22:47 -05:00
|
|
|
pub fn packet_by_id<R: io::Read>(version: i32, state: State, dir: Direction, id: i32, mut buf: &mut R) -> Result<Option<Packet>, Error> {
|
2015-09-07 16:11:00 -04:00
|
|
|
match state {
|
|
|
|
$(
|
|
|
|
State::$stateName => {
|
|
|
|
match dir {
|
|
|
|
$(
|
|
|
|
Direction::$dirName => {
|
2018-12-03 17:22:47 -05:00
|
|
|
let internal_id = packet::versions::translate_internal_packet_id_for_version(version, state, dir, id, true);
|
|
|
|
match internal_id {
|
2015-09-07 16:11:00 -04:00
|
|
|
$(
|
2016-03-18 07:39:03 -04:00
|
|
|
self::$state::$dir::internal_ids::$name => {
|
2015-09-10 06:49:41 -04:00
|
|
|
use self::$state::$dir::$name;
|
|
|
|
let mut packet : $name = $name::default();
|
2015-09-08 07:57:24 -04:00
|
|
|
$(
|
2015-09-10 06:49:41 -04:00
|
|
|
if true $(&& ($cond(&packet)))* {
|
2018-11-04 14:34:53 -05:00
|
|
|
packet.$field = Serializable::read_from(&mut buf)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2015-09-08 07:57:24 -04:00
|
|
|
)+
|
|
|
|
Result::Ok(Option::Some(Packet::$name(packet)))
|
|
|
|
},
|
2015-09-07 16:11:00 -04:00
|
|
|
)*
|
2015-09-08 07:57:24 -04:00
|
|
|
_ => Result::Ok(Option::None)
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-03 17:22:47 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! protocol_packet_ids {
|
|
|
|
($($state:ident $stateName:ident {
|
|
|
|
$($dir:ident $dirName:ident {
|
|
|
|
$(
|
|
|
|
$(#[$attr:meta])*
|
|
|
|
$id:expr => $name:ident
|
|
|
|
)*
|
|
|
|
})+
|
|
|
|
})+) => {
|
|
|
|
use crate::protocol::*;
|
|
|
|
|
|
|
|
pub fn translate_internal_packet_id(state: State, dir: Direction, id: i32, to_internal: bool) -> i32 {
|
|
|
|
match state {
|
|
|
|
$(
|
|
|
|
State::$stateName => {
|
|
|
|
match dir {
|
|
|
|
$(
|
|
|
|
Direction::$dirName => {
|
|
|
|
if to_internal {
|
|
|
|
match id {
|
|
|
|
$(
|
|
|
|
$id => crate::protocol::packet::$state::$dir::internal_ids::$name,
|
|
|
|
)*
|
2018-12-04 11:03:58 -05:00
|
|
|
_ => panic!("bad packet id 0x{:x} in {:?} {:?}", id, dir, state),
|
2018-12-03 17:22:47 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match id {
|
|
|
|
$(
|
|
|
|
crate::protocol::packet::$state::$dir::internal_ids::$name => $id,
|
|
|
|
)*
|
2018-12-04 11:03:58 -05:00
|
|
|
_ => panic!("bad packet internal id 0x{:x} in {:?} {:?}", id, dir, state),
|
2018-12-03 17:22:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2018-12-03 17:22:47 -05:00
|
|
|
pub mod packet;
|
|
|
|
pub mod versions;
|
2015-09-25 09:00:49 -04:00
|
|
|
pub trait Serializable: Sized {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error>;
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error>;
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Serializable for Vec<u8> {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Vec<u8>, Error> {
|
2015-09-12 15:31:26 -04:00
|
|
|
let mut v = Vec::new();
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.read_to_end(&mut v)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Ok(v)
|
|
|
|
}
|
|
|
|
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
buf.write_all(&self[..]).map_err(|v| v.into())
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for Option<nbt::NamedTag>{
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<nbt::NamedTag>, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
let ty = buf.read_u8()?;
|
2015-09-12 15:31:26 -04:00
|
|
|
if ty == 0 {
|
|
|
|
Result::Ok(None)
|
|
|
|
} else {
|
2018-11-04 14:34:53 -05:00
|
|
|
let name = nbt::read_string(buf)?;
|
|
|
|
let tag = nbt::Tag::read_from(buf)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Result::Ok(Some(nbt::NamedTag(name, tag)))
|
|
|
|
}
|
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-09-12 15:31:26 -04:00
|
|
|
match *self {
|
|
|
|
Some(ref val) => {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(10)?;
|
|
|
|
nbt::write_string(buf, &val.0)?;
|
|
|
|
val.1.write_to(buf)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
2018-11-04 14:34:53 -05:00
|
|
|
None => buf.write_u8(0)?,
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
impl <T> Serializable for Option<T> where T : Serializable {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<T>, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(Some(T::read_from(buf)?))
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-09-10 06:49:41 -04:00
|
|
|
if self.is_some() {
|
2018-11-04 14:34:53 -05:00
|
|
|
self.as_ref().unwrap().write_to(buf)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-08 07:57:24 -04:00
|
|
|
impl Serializable for String {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<String, Error> {
|
2016-12-09 09:32:02 -05:00
|
|
|
let len = VarInt::read_from(buf)?.0;
|
|
|
|
debug_assert!(len >= 0, "Negative string length: {}", len);
|
|
|
|
debug_assert!(len <= 65536, "String length too big: {}", len);
|
2015-09-08 07:57:24 -04:00
|
|
|
let mut ret = String::new();
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.take(len as u64).read_to_string(&mut ret)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
Result::Ok(ret)
|
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-09-08 07:57:24 -04:00
|
|
|
let bytes = self.as_bytes();
|
2018-11-04 14:34:53 -05:00
|
|
|
VarInt(bytes.len() as i32).write_to(buf)?;
|
|
|
|
buf.write_all(bytes)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
impl Serializable for format::Component {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
let len = VarInt::read_from(buf)?.0;
|
2015-09-10 06:49:41 -04:00
|
|
|
let mut ret = String::new();
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.take(len as u64).read_to_string(&mut ret)?;
|
2015-10-07 14:36:59 -04:00
|
|
|
let val: serde_json::Value = serde_json::from_str(&ret[..]).unwrap();
|
2015-09-10 06:49:41 -04:00
|
|
|
Result::Ok(Self::from_value(&val))
|
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-09-10 06:49:41 -04:00
|
|
|
let val = serde_json::to_string(&self.to_value()).unwrap();
|
|
|
|
let bytes = val.as_bytes();
|
2018-11-04 14:34:53 -05:00
|
|
|
VarInt(bytes.len() as i32).write_to(buf)?;
|
|
|
|
buf.write_all(bytes)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for () {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(_: &mut R) -> Result<(), Error> {
|
2015-09-10 06:49:41 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
2016-04-16 16:43:41 -04:00
|
|
|
fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> {
|
2015-09-10 06:49:41 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for bool {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<bool, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_u8()? != 0)
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(if *self {
|
2015-10-07 14:36:59 -04:00
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
2018-11-04 14:34:53 -05:00
|
|
|
})?;
|
2015-09-08 07:57:24 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Serializable for i8 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<i8, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_i8()?)
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_i8(*self)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
impl Serializable for i16 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<i16, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_i16::<BigEndian>()?)
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_i16::<BigEndian>(*self)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for i32 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<i32, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_i32::<BigEndian>()?)
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_i32::<BigEndian>(*self)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for i64 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<i64, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_i64::<BigEndian>()?)
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_i64::<BigEndian>(*self)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
impl Serializable for u8 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<u8, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_u8()?)
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(*self)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-08 07:57:24 -04:00
|
|
|
impl Serializable for u16 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<u16, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_u16::<BigEndian>()?)
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u16::<BigEndian>(*self)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-21 10:05:13 -04:00
|
|
|
impl Serializable for u64 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<u64, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_u64::<BigEndian>()?)
|
2016-03-21 10:05:13 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u64::<BigEndian>(*self)?;
|
2016-03-21 10:05:13 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Serializable for f32 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<f32, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_f32::<BigEndian>()?)
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_f32::<BigEndian>(*self)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for f64 {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<f64, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(buf.read_f64::<BigEndian>()?)
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_f64::<BigEndian>(*self)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 13:50:53 -04:00
|
|
|
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
2015-09-12 15:31:26 -04:00
|
|
|
pub struct UUID(u64, u64);
|
|
|
|
|
2016-04-06 17:50:31 -04:00
|
|
|
impl UUID {
|
|
|
|
pub fn from_str(s: &str) -> UUID {
|
2018-09-30 21:14:36 -04:00
|
|
|
use hex;
|
2016-04-06 17:50:31 -04:00
|
|
|
// TODO: Panics aren't the best idea here
|
|
|
|
if s.len() != 36 {
|
|
|
|
panic!("Invalid UUID format");
|
|
|
|
}
|
2018-09-30 21:14:36 -04:00
|
|
|
let mut parts = hex::decode(&s[..8]).unwrap();
|
|
|
|
parts.extend_from_slice(&hex::decode(&s[9..13]).unwrap());
|
|
|
|
parts.extend_from_slice(&hex::decode(&s[14..18]).unwrap());
|
|
|
|
parts.extend_from_slice(&hex::decode(&s[19..23]).unwrap());
|
|
|
|
parts.extend_from_slice(&hex::decode(&s[24..36]).unwrap());
|
2016-04-06 17:50:31 -04:00
|
|
|
let mut high = 0u64;
|
|
|
|
let mut low = 0u64;
|
|
|
|
for i in 0 .. 8 {
|
|
|
|
high |= (parts[i] as u64) << (56 - i*8);
|
|
|
|
low |= (parts[i + 8] as u64) << (56 - i*8);
|
|
|
|
}
|
|
|
|
UUID(high, low)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Default for UUID {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn default() -> Self {
|
|
|
|
UUID(0, 0)
|
|
|
|
}
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for UUID {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<UUID, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
Result::Ok(UUID(buf.read_u64::<BigEndian>()?,
|
|
|
|
buf.read_u64::<BigEndian>()?))
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u64::<BigEndian>(self.0)?;
|
|
|
|
buf.write_u64::<BigEndian>(self.1)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub trait Lengthable : Serializable + Copy + Default {
|
|
|
|
fn into(self) -> usize;
|
2018-11-04 14:33:23 -05:00
|
|
|
fn from(_: usize) -> Self;
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
|
|
|
|
pub struct LenPrefixed<L: Lengthable, V> {
|
|
|
|
len: L,
|
2015-10-07 14:36:59 -04:00
|
|
|
pub data: Vec<V>,
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
|
2016-03-21 06:55:31 -04:00
|
|
|
pub fn new(data: Vec<V>) -> LenPrefixed<L, V> {
|
2015-09-29 15:09:36 -04:00
|
|
|
LenPrefixed {
|
2015-09-10 06:49:41 -04:00
|
|
|
len: Default::default(),
|
2018-11-04 16:43:30 -05:00
|
|
|
data,
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixed<L, V>, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
let len_data: L = Serializable::read_from(buf)?;
|
2015-10-07 14:36:59 -04:00
|
|
|
let len: usize = len_data.into();
|
|
|
|
let mut data: Vec<V> = Vec::with_capacity(len);
|
|
|
|
for _ in 0..len {
|
2018-11-04 14:34:53 -05:00
|
|
|
data.push(Serializable::read_from(buf)?);
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2015-10-07 14:36:59 -04:00
|
|
|
Result::Ok(LenPrefixed {
|
|
|
|
len: len_data,
|
2018-11-04 16:43:30 -05:00
|
|
|
data,
|
2015-10-07 14:36:59 -04:00
|
|
|
})
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-10-07 14:36:59 -04:00
|
|
|
let len_data: L = L::from(self.data.len());
|
2018-11-04 14:34:53 -05:00
|
|
|
len_data.write_to(buf)?;
|
2015-09-29 15:09:36 -04:00
|
|
|
let data = &self.data;
|
2015-09-10 06:49:41 -04:00
|
|
|
for val in data {
|
2018-11-04 14:34:53 -05:00
|
|
|
val.write_to(buf)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
impl <L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
|
|
|
|
fn default() -> Self {
|
|
|
|
LenPrefixed {
|
|
|
|
len: default::Default::default(),
|
2015-10-07 14:36:59 -04:00
|
|
|
data: default::Default::default(),
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl <L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
self.data.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Optimization
|
|
|
|
pub struct LenPrefixedBytes<L: Lengthable> {
|
|
|
|
len: L,
|
2015-10-07 14:36:59 -04:00
|
|
|
pub data: Vec<u8>,
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl <L: Lengthable> LenPrefixedBytes<L> {
|
2016-03-21 06:55:31 -04:00
|
|
|
pub fn new(data: Vec<u8>) -> LenPrefixedBytes<L> {
|
2015-09-29 15:09:36 -04:00
|
|
|
LenPrefixedBytes {
|
2015-09-12 15:31:26 -04:00
|
|
|
len: Default::default(),
|
2018-11-04 16:43:30 -05:00
|
|
|
data,
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <L: Lengthable> Serializable for LenPrefixedBytes<L> {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixedBytes<L>, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
let len_data: L = Serializable::read_from(buf)?;
|
2015-10-07 14:36:59 -04:00
|
|
|
let len: usize = len_data.into();
|
|
|
|
let mut data: Vec<u8> = Vec::with_capacity(len);
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.take(len as u64).read_to_end(&mut data)?;
|
2015-10-07 14:36:59 -04:00
|
|
|
Result::Ok(LenPrefixedBytes {
|
|
|
|
len: len_data,
|
2018-11-04 16:43:30 -05:00
|
|
|
data,
|
2015-10-07 14:36:59 -04:00
|
|
|
})
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-10-07 14:36:59 -04:00
|
|
|
let len_data: L = L::from(self.data.len());
|
2018-11-04 14:34:53 -05:00
|
|
|
len_data.write_to(buf)?;
|
|
|
|
buf.write_all(&self.data[..])?;
|
2015-09-12 15:31:26 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl <L: Lengthable> Default for LenPrefixedBytes<L> {
|
|
|
|
fn default() -> Self {
|
|
|
|
LenPrefixedBytes {
|
|
|
|
len: default::Default::default(),
|
2015-10-07 14:36:59 -04:00
|
|
|
data: default::Default::default(),
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
self.data.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1.13.2 (404) multiprotocol support (#67)
Adds support for 1.13.2 protocol (404)
Expands https://github.com/iceiix/steven/issues/18 Enhance protocol support
Metadata:
* Support 1.13.2 slot data format, bool and varint item id, optional damage (moved to NBT)
https://wiki.vg/index.php?title=Slot_Data&type=revision&diff=14363&oldid=7835
Packets:
* Add 1.13.2 packets, and implement all the command data parsers
https://wiki.vg/Command_Data#Parsers
* Send new plugin channel minecraft:brand
https://wiki.vg/Plugin_channels#minecraft:brand
* Add 1.13.2 metadata format, with shifted IDs
https://wiki.vg/Entity_metadata#Entity_Metadata_Format
* Implement particle entity metadata
* Add structures for 16 new packets
Blocks: The Flattening:
* Assign flattened IDs in correct order using new 'offset' macro token
* Assign hierarchical (pre-flattening) block IDs sequentially by counting Some data
* Split VANILLA_ID_MAP into flat/hier struct, to support before and after the flattening
* Extend travis build time to 20 minutes because the blocks macro takes a long time
* Support both flat/hier blocks by passing protocol_version to by_vanilla_id
Add block states and offsets for all blocks, replacing metadata for 1.13+:
* Add stripped logs and what was Log2 to Log
* Add the Wood blocks, should be called bark, previously Axis::None Log
* Add leaves distance and offset
* Add jungle/acacia to Leaves moved from Leaves2
* Add dispenser offsets, direction
* Add note block states
* Add offset None to Missing253 and Missing254, no holes in block states of 1.13.2
* Add bed colors
* Add seagrass, tall seagrass, remove redundant deadgrass, and piston offset
* Add torch, TNT, fire offsets, remove slabs
* Add furnance offset, merges lit into a property
* Add pressure plate offsets, new pressure plates, redstone ore/lit merged
* Add lever offsets, new directions from ceiling/floor, rename LeverDirections
* Add redstone torch offsets, new blocks since lit/unlit is now merged, and standing/wall is split
* Change lever to split face/facing, rm LeverDirection, add AttachedFace
* Add stone button offsets, face/facing similar to lever
* Move face/facing data and variant to AttachedFace, reuse for lever/stonebutton
* Add data_with_facing_and_powered() to AttachedFace, for lever/stonebutton
* Add wooden button offsets each wood
* Add pumpkin without a face
* Add carved pumpkin, portal offsets
* Add lit pumpkin (as jack-o-lantern) offsets after carved pumpkin
* Add repeater offsets, merged into Repeater
* Change brown mushroom block to booleans instead of MushroomVariant
* Add mushroom block offsets, red/brown mushroom blocks, and a new mushroom stem block
* Add command block, cobblestone walls, and flower pot offsets
Empty flower pot, and potted plants including saplings. Rename
variant DarkOak to DarkOakSaplings because it is a sapling, and
remove the duplicate Dandelion variant which causes duplicate blocks.
* Increase recursion limit in steven_blocks
* Add colored banner offsets
* Add wooden slab including double slab, in a different position for pre-1.13 and 1.13
* StoneSlabVariant::Wood -> StoneSlabVariant::PetrifiedWood
* Add fence_gate_offset() for wooden fence gates
* Add frosted ice age, offset
* Add new blocks: kelp, turtle egg, coral, coral fans, sea pickle, blue ice, smooth stone
* Add new blocks: conduit, void air, cave aid, bubble column, last of the 1.13 blocks
2018-12-29 00:11:42 -05:00
|
|
|
impl Lengthable for bool {
|
|
|
|
fn into(self) -> usize {
|
|
|
|
if self { 1 } else { 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from(u: usize) -> bool {
|
|
|
|
u != 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1.7.10 (5) multiprotocol support (#64)
Adds 1.7.10 protocol version 5 support, a major update with significant changes.
Expands https://github.com/iceiix/steven/issues/18 Enhance protocol support
* Add v1_7_10 protocol packet structures and IDs
* EncryptionRequest/Response i16 variant in login protocol
* 1.7.10 slot NBT data parsing
* Support both 1.7/1.8+ item::Stack in read_from, using if protocol_verson
* 1.7.10 chunk format support, ChunkDataBulk_17 and ChunkData_17
* Extract dirty_chunks_by_bitmask from load_chunks17/18/19
* Implement keepalive i32 handler
* Send PlayerPositionLook_HeadY
* Send PlayerBlockPlacement_u8_Item_u8y
* Handle JoinGame_i8_NoDebug
* Handle SpawnPlayer_i32_HeldItem_String
* BlockChange_u8, MultiBlockChange_i16, UpdateBlockEntity_Data, EntityMove_i8_i32_NoGround, EntityLook_i32_NoGround, EntityLookAndMove_i8_i32_NoGround
* UpdateSign_u16, PlayerInfo_String, EntityDestroy_u8, EntityTeleport_i32_i32_NoGround
* Send feet_y = head_y - 1.62, fixes Illegal stance
https://wiki.vg/index.php?title=Protocol&oldid=6003#Player_Position
> Updates the players XYZ position on the server. If HeadY - FeetY is less than 0.1 or greater than 1.65, the stance is illegal and the client will be kicked with the message “Illegal Stance”.
> Absolute feet position, normally HeadY - 1.62. Used to modify the players bounding box when going up stairs, crouching, etc…
* Set on_ground = true in entity teleport, fixes bouncing
* Implement block change, fix metadata/id packing, bounce _u8 through on_block_change
* Implement on_multi_block_change_u16, used with explosions
2018-12-15 22:56:54 -05:00
|
|
|
impl Lengthable for u8 {
|
|
|
|
fn into(self) -> usize {
|
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from(u: usize) -> u8 {
|
|
|
|
u as u8
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Lengthable for i16 {
|
|
|
|
fn into(self) -> usize {
|
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from(u: usize) -> i16 {
|
|
|
|
u as i16
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Lengthable for i32 {
|
|
|
|
fn into(self) -> usize {
|
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from(u: usize) -> i32 {
|
|
|
|
u as i32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-02 20:26:31 -04:00
|
|
|
/// `VarInt` have a variable size (between 1 and 5 bytes) when encoded based
|
2015-09-07 16:11:00 -04:00
|
|
|
/// on the size of the number
|
2015-09-10 06:49:41 -04:00
|
|
|
#[derive(Clone, Copy)]
|
2015-09-12 15:31:26 -04:00
|
|
|
pub struct VarInt(pub i32);
|
2015-09-08 07:57:24 -04:00
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Lengthable for VarInt {
|
|
|
|
fn into(self) -> usize {
|
|
|
|
self.0 as usize
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from(u: usize) -> VarInt {
|
|
|
|
VarInt(u as i32)
|
|
|
|
}
|
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
|
2015-09-08 07:57:24 -04:00
|
|
|
impl Serializable for VarInt {
|
2016-04-02 20:26:31 -04:00
|
|
|
/// Decodes a `VarInt` from the Reader
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarInt, Error> {
|
2015-09-08 07:57:24 -04:00
|
|
|
const PART : u32 = 0x7F;
|
|
|
|
let mut size = 0;
|
|
|
|
let mut val = 0u32;
|
|
|
|
loop {
|
2018-11-04 14:34:53 -05:00
|
|
|
let b = buf.read_u8()? as u32;
|
2015-09-08 07:57:24 -04:00
|
|
|
val |= (b & PART) << (size * 7);
|
2015-10-07 14:36:59 -04:00
|
|
|
size += 1;
|
2015-09-08 07:57:24 -04:00
|
|
|
if size > 5 {
|
2016-04-08 13:46:07 -04:00
|
|
|
return Result::Err(Error::Err("VarInt too big".to_owned()));
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
|
|
|
if (b & 0x80) == 0 {
|
|
|
|
break
|
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
2015-09-08 07:57:24 -04:00
|
|
|
|
|
|
|
Result::Ok(VarInt(val as i32))
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
2016-04-02 20:26:31 -04:00
|
|
|
/// Encodes a `VarInt` into the Writer
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-09-08 07:57:24 -04:00
|
|
|
const PART : u32 = 0x7F;
|
|
|
|
let mut val = self.0 as u32;
|
|
|
|
loop {
|
|
|
|
if (val & !PART) == 0 {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(val as u8)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
return Result::Ok(());
|
|
|
|
}
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(((val & PART) | 0x80) as u8)?;
|
2015-09-08 07:57:24 -04:00
|
|
|
val >>= 7;
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2015-09-08 07:57:24 -04:00
|
|
|
impl default::Default for VarInt {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn default() -> VarInt {
|
|
|
|
VarInt(0)
|
|
|
|
}
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl fmt::Debug for VarInt {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-02 20:26:31 -04:00
|
|
|
/// `VarLong` have a variable size (between 1 and 10 bytes) when encoded based
|
2015-09-12 15:31:26 -04:00
|
|
|
/// on the size of the number
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct VarLong(pub i64);
|
|
|
|
|
|
|
|
impl Lengthable for VarLong {
|
2015-09-10 06:49:41 -04:00
|
|
|
fn into(self) -> usize {
|
|
|
|
self.0 as usize
|
|
|
|
}
|
2015-09-12 15:31:26 -04:00
|
|
|
|
|
|
|
fn from(u: usize) -> VarLong {
|
|
|
|
VarLong(u as i64)
|
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Serializable for VarLong {
|
2016-04-02 20:26:31 -04:00
|
|
|
/// Decodes a `VarLong` from the Reader
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarLong, Error> {
|
2015-09-12 15:31:26 -04:00
|
|
|
const PART : u64 = 0x7F;
|
|
|
|
let mut size = 0;
|
|
|
|
let mut val = 0u64;
|
|
|
|
loop {
|
2018-11-04 14:34:53 -05:00
|
|
|
let b = buf.read_u8()? as u64;
|
2015-09-12 15:31:26 -04:00
|
|
|
val |= (b & PART) << (size * 7);
|
2015-10-07 14:36:59 -04:00
|
|
|
size += 1;
|
2015-09-12 15:31:26 -04:00
|
|
|
if size > 10 {
|
2016-04-08 13:46:07 -04:00
|
|
|
return Result::Err(Error::Err("VarLong too big".to_owned()));
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
if (b & 0x80) == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Result::Ok(VarLong(val as i64))
|
|
|
|
}
|
|
|
|
|
2016-04-02 20:26:31 -04:00
|
|
|
/// Encodes a `VarLong` into the Writer
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2015-09-12 15:31:26 -04:00
|
|
|
const PART : u64 = 0x7F;
|
|
|
|
let mut val = self.0 as u64;
|
|
|
|
loop {
|
|
|
|
if (val & !PART) == 0 {
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(val as u8)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
return Result::Ok(());
|
|
|
|
}
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u8(((val & PART) | 0x80) as u8)?;
|
2015-09-12 15:31:26 -04:00
|
|
|
val >>= 7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl default::Default for VarLong {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn default() -> VarLong {
|
|
|
|
VarLong(0)
|
|
|
|
}
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for VarLong {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.0)
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-03 15:53:40 -04:00
|
|
|
impl Serializable for Position {
|
2016-04-08 13:46:07 -04:00
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Position, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
let pos = buf.read_u64::<BigEndian>()?;
|
2016-04-03 15:53:40 -04:00
|
|
|
Ok(Position::new(
|
|
|
|
((pos as i64) >> 38) as i32,
|
|
|
|
(((pos as i64) >> 26) & 0xFFF) as i32,
|
|
|
|
((pos as i64) << 38 >> 38) as i32
|
|
|
|
))
|
|
|
|
}
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2016-04-03 15:53:40 -04:00
|
|
|
let pos = (((self.x as u64) & 0x3FFFFFF) << 38)
|
|
|
|
| (((self.y as u64) & 0xFFF) << 26)
|
|
|
|
| ((self.z as u64) & 0x3FFFFFF);
|
2018-11-04 14:34:53 -05:00
|
|
|
buf.write_u64::<BigEndian>(pos)?;
|
2016-04-03 15:53:40 -04:00
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
/// Direction is used to define whether packets are going to the
|
|
|
|
/// server or the client.
|
2018-12-04 11:03:58 -05:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2015-09-07 16:11:00 -04:00
|
|
|
pub enum Direction {
|
|
|
|
Serverbound,
|
2015-10-07 14:36:59 -04:00
|
|
|
Clientbound,
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The protocol has multiple 'sub-protocols' or states which control which
|
|
|
|
/// packet an id points to.
|
2018-12-04 11:03:58 -05:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2015-09-07 16:11:00 -04:00
|
|
|
pub enum State {
|
|
|
|
Handshaking,
|
|
|
|
Play,
|
|
|
|
Status,
|
2015-10-07 14:36:59 -04:00
|
|
|
Login,
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return for any protocol related error.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
Err(String),
|
2016-03-20 08:04:02 -04:00
|
|
|
Disconnect(format::Component),
|
2015-09-07 16:11:00 -04:00
|
|
|
IOError(io::Error),
|
2016-03-20 19:43:31 -04:00
|
|
|
Json(serde_json::Error),
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
Reqwest(reqwest::Error),
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl convert::From<io::Error> for Error {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn from(e: io::Error) -> Error {
|
2015-09-07 16:11:00 -04:00
|
|
|
Error::IOError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-20 19:43:31 -04:00
|
|
|
impl convert::From<serde_json::Error> for Error {
|
|
|
|
fn from(e: serde_json::Error) -> Error {
|
|
|
|
Error::Json(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
impl convert::From<reqwest::Error> for Error {
|
|
|
|
fn from(e: reqwest::Error) -> Error {
|
|
|
|
Error::Reqwest(e)
|
2016-03-20 19:43:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
impl ::std::error::Error for Error {
|
|
|
|
fn description(&self) -> &str {
|
2015-09-29 15:09:36 -04:00
|
|
|
match *self {
|
|
|
|
Error::Err(ref val) => &val[..],
|
2016-03-20 08:04:02 -04:00
|
|
|
Error::Disconnect(_) => "Disconnect",
|
2015-09-29 15:09:36 -04:00
|
|
|
Error::IOError(ref e) => e.description(),
|
2016-03-20 19:43:31 -04:00
|
|
|
Error::Json(ref e) => e.description(),
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
Error::Reqwest(ref e) => e.description(),
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ::std::fmt::Display for Error {
|
2015-10-07 14:36:59 -04:00
|
|
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
2015-09-29 15:09:36 -04:00
|
|
|
match *self {
|
|
|
|
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
2016-03-20 08:04:02 -04:00
|
|
|
Error::Disconnect(ref val) => write!(f, "{}", val),
|
2015-10-07 14:36:59 -04:00
|
|
|
Error::IOError(ref e) => e.fmt(f),
|
2016-03-20 19:43:31 -04:00
|
|
|
Error::Json(ref e) => e.fmt(f),
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
Error::Reqwest(ref e) => e.fmt(f),
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 23:45:40 -04:00
|
|
|
type Aes128Cfb = Cfb8<Aes128>;
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
pub struct Conn {
|
|
|
|
stream: TcpStream,
|
2016-03-20 08:04:02 -04:00
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
2015-09-07 16:11:00 -04:00
|
|
|
direction: Direction,
|
2018-12-03 17:22:47 -05:00
|
|
|
pub protocol_version: i32,
|
2016-03-20 08:04:02 -04:00
|
|
|
pub state: State,
|
2015-09-10 06:49:41 -04:00
|
|
|
|
2018-11-01 23:45:40 -04:00
|
|
|
cipher: Option<Aes128Cfb>,
|
2015-09-10 06:49:41 -04:00
|
|
|
|
|
|
|
compression_threshold: i32,
|
2015-10-07 14:36:59 -04:00
|
|
|
compression_read: Option<ZlibDecoder<io::Cursor<Vec<u8>>>>,
|
2015-09-10 06:49:41 -04:00
|
|
|
compression_write: Option<ZlibEncoder<io::Cursor<Vec<u8>>>>,
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Conn {
|
2018-12-03 17:22:47 -05:00
|
|
|
pub fn new(target: &str, protocol_version: i32) -> Result<Conn, Error> {
|
2018-12-11 21:18:25 -05:00
|
|
|
unsafe {
|
|
|
|
CURRENT_PROTOCOL_VERSION = protocol_version;
|
|
|
|
}
|
|
|
|
|
2015-09-07 16:11:00 -04:00
|
|
|
// TODO SRV record support
|
2016-04-02 20:26:31 -04:00
|
|
|
let mut parts = target.split(':').collect::<Vec<&str>>();
|
2015-09-25 09:00:49 -04:00
|
|
|
let address = if parts.len() == 1 {
|
|
|
|
parts.push("25565");
|
|
|
|
format!("{}:25565", parts[0])
|
|
|
|
} else {
|
|
|
|
format!("{}:{}", parts[0], parts[1])
|
2015-09-07 16:11:00 -04:00
|
|
|
};
|
2018-11-04 14:34:53 -05:00
|
|
|
let stream = TcpStream::connect(&*address)?;
|
2015-09-07 16:11:00 -04:00
|
|
|
Result::Ok(Conn {
|
2018-11-04 16:43:30 -05:00
|
|
|
stream,
|
2015-09-07 16:11:00 -04:00
|
|
|
host: parts[0].to_owned(),
|
|
|
|
port: parts[1].parse().unwrap(),
|
|
|
|
direction: Direction::Serverbound,
|
|
|
|
state: State::Handshaking,
|
2018-12-03 17:22:47 -05:00
|
|
|
protocol_version,
|
2015-09-10 06:49:41 -04:00
|
|
|
cipher: Option::None,
|
|
|
|
compression_threshold: -1,
|
|
|
|
compression_read: Option::None,
|
|
|
|
compression_write: Option::None,
|
2015-09-07 16:11:00 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write_packet<T: PacketType>(&mut self, packet: T) -> Result<(), Error> {
|
|
|
|
let mut buf = Vec::new();
|
2018-12-03 17:22:47 -05:00
|
|
|
VarInt(packet.packet_id(self.protocol_version)).write_to(&mut buf)?;
|
2018-11-04 14:34:53 -05:00
|
|
|
packet.write(&mut buf)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
|
2015-10-07 14:36:59 -04:00
|
|
|
let mut extra = if self.compression_threshold >= 0 {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2015-09-10 06:49:41 -04:00
|
|
|
if self.compression_threshold >= 0 && buf.len() as i32 > self.compression_threshold {
|
2016-04-03 06:20:31 -04:00
|
|
|
if self.compression_write.is_none() {
|
2018-09-30 19:19:24 -04:00
|
|
|
self.compression_write = Some(ZlibEncoder::new(io::Cursor::new(Vec::new()), Compression::default()));
|
2016-04-03 06:20:31 -04:00
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
extra = 0;
|
|
|
|
let uncompressed_size = buf.len();
|
|
|
|
let mut new = Vec::new();
|
2018-11-04 14:34:53 -05:00
|
|
|
VarInt(uncompressed_size as i32).write_to(&mut new)?;
|
2018-09-29 21:42:13 -04:00
|
|
|
let write = self.compression_write.as_mut().unwrap();
|
2015-09-10 06:49:41 -04:00
|
|
|
write.reset(io::Cursor::new(buf));
|
2018-11-04 14:34:53 -05:00
|
|
|
write.read_to_end(&mut new)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
buf = new;
|
|
|
|
}
|
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
VarInt(buf.len() as i32 + extra).write_to(self)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
if self.compression_threshold >= 0 && extra == 1 {
|
2018-11-04 14:34:53 -05:00
|
|
|
VarInt(0).write_to(self)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2018-11-04 14:34:53 -05:00
|
|
|
self.write_all(&buf)?;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
|
|
|
Result::Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_packet(&mut self) -> Result<packet::Packet, Error> {
|
2018-11-04 14:34:53 -05:00
|
|
|
let len = VarInt::read_from(self)?.0 as usize;
|
2016-03-23 19:28:33 -04:00
|
|
|
let mut ibuf = vec![0; len];
|
2018-11-04 14:34:53 -05:00
|
|
|
self.read_exact(&mut ibuf)?;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
|
|
|
let mut buf = io::Cursor::new(ibuf);
|
2015-09-10 06:49:41 -04:00
|
|
|
|
|
|
|
if self.compression_threshold >= 0 {
|
2016-04-03 06:20:31 -04:00
|
|
|
if self.compression_read.is_none() {
|
|
|
|
self.compression_read = Some(ZlibDecoder::new(io::Cursor::new(Vec::new())));
|
|
|
|
}
|
2018-11-04 14:34:53 -05:00
|
|
|
let uncompressed_size = VarInt::read_from(&mut buf)?.0;
|
2015-09-10 06:49:41 -04:00
|
|
|
if uncompressed_size != 0 {
|
|
|
|
let mut new = Vec::with_capacity(uncompressed_size as usize);
|
|
|
|
{
|
2018-09-29 21:42:13 -04:00
|
|
|
let reader = self.compression_read.as_mut().unwrap();
|
2015-09-10 06:49:41 -04:00
|
|
|
reader.reset(buf);
|
2018-11-04 14:34:53 -05:00
|
|
|
reader.read_to_end(&mut new)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
buf = io::Cursor::new(new);
|
|
|
|
}
|
|
|
|
}
|
2018-11-04 14:34:53 -05:00
|
|
|
let id = VarInt::read_from(&mut buf)?.0;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
|
|
|
let dir = match self.direction {
|
|
|
|
Direction::Clientbound => Direction::Serverbound,
|
|
|
|
Direction::Serverbound => Direction::Clientbound,
|
|
|
|
};
|
|
|
|
|
2018-12-03 17:22:47 -05:00
|
|
|
let packet = packet::packet_by_id(self.protocol_version, self.state, dir, id, &mut buf)?;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
|
|
|
match packet {
|
|
|
|
Some(val) => {
|
|
|
|
let pos = buf.position() as usize;
|
|
|
|
let ibuf = buf.into_inner();
|
2015-09-12 15:31:26 -04:00
|
|
|
if ibuf.len() != pos {
|
2015-10-07 14:36:59 -04:00
|
|
|
return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, \
|
|
|
|
had {} bytes left",
|
|
|
|
id,
|
|
|
|
ibuf.len() - pos)))
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
Result::Ok(val)
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
|
|
|
None => Result::Err(Error::Err("missing packet".to_owned())),
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 23:45:40 -04:00
|
|
|
pub fn enable_encyption(&mut self, key: &[u8], _decrypt: bool) {
|
|
|
|
let cipher = Aes128Cfb::new_var(key, key).unwrap();
|
2016-04-05 14:35:58 -04:00
|
|
|
self.cipher = Option::Some(cipher);
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
2016-04-03 06:20:31 -04:00
|
|
|
pub fn set_compresssion(&mut self, threshold: i32) {
|
2015-09-10 06:49:41 -04:00
|
|
|
self.compression_threshold = threshold;
|
|
|
|
}
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2018-09-30 01:57:55 -04:00
|
|
|
pub fn do_status(mut self) -> Result<(Status, Duration), Error> {
|
2015-09-25 09:00:49 -04:00
|
|
|
use serde_json::Value;
|
|
|
|
use self::packet::status::serverbound::*;
|
2016-03-18 07:39:03 -04:00
|
|
|
use self::packet::handshake::serverbound::Handshake;
|
2015-09-25 09:00:49 -04:00
|
|
|
use self::packet::Packet;
|
|
|
|
let host = self.host.clone();
|
|
|
|
let port = self.port;
|
2018-11-04 14:34:53 -05:00
|
|
|
self.write_packet(Handshake {
|
2018-12-03 17:22:47 -05:00
|
|
|
protocol_version: VarInt(self.protocol_version),
|
2018-11-04 16:43:30 -05:00
|
|
|
host,
|
|
|
|
port,
|
2015-09-25 09:00:49 -04:00
|
|
|
next: VarInt(1),
|
2018-11-04 14:34:53 -05:00
|
|
|
})?;
|
2015-09-25 09:00:49 -04:00
|
|
|
self.state = State::Status;
|
2015-10-07 14:36:59 -04:00
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
self.write_packet(StatusRequest { empty: () })?;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
let status = if let Packet::StatusResponse(res) = self.read_packet()? {
|
2015-09-25 09:00:49 -04:00
|
|
|
res.status
|
|
|
|
} else {
|
|
|
|
return Err(Error::Err("Wrong packet".to_owned()));
|
|
|
|
};
|
|
|
|
|
2018-09-30 01:57:55 -04:00
|
|
|
let start = Instant::now();
|
2018-11-04 14:34:53 -05:00
|
|
|
self.write_packet(StatusPing { ping: 42 })?;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
if let Packet::StatusPong(_) = self.read_packet()? {
|
2015-09-25 09:00:49 -04:00
|
|
|
} else {
|
|
|
|
return Err(Error::Err("Wrong packet".to_owned()));
|
|
|
|
};
|
|
|
|
|
2018-09-30 01:57:55 -04:00
|
|
|
let ping = start.elapsed();
|
2015-09-25 09:00:49 -04:00
|
|
|
|
|
|
|
let val: Value = match serde_json::from_str(&status) {
|
|
|
|
Ok(val) => val,
|
|
|
|
Err(_) => return Err(Error::Err("Json parse error".to_owned())),
|
|
|
|
};
|
|
|
|
|
|
|
|
let invalid_status = || Error::Err("Invalid status".to_owned());
|
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
let version = val.get("version").ok_or(invalid_status())?;
|
|
|
|
let players = val.get("players").ok_or(invalid_status())?;
|
2015-09-25 09:00:49 -04:00
|
|
|
|
|
|
|
Ok((Status {
|
|
|
|
version: StatusVersion {
|
2018-11-04 14:34:53 -05:00
|
|
|
name: version.get("name").and_then(Value::as_str).ok_or(invalid_status())?
|
2015-10-07 14:36:59 -04:00
|
|
|
.to_owned(),
|
2018-11-04 14:34:53 -05:00
|
|
|
protocol: version.get("protocol")
|
2015-10-07 14:36:59 -04:00
|
|
|
.and_then(Value::as_i64)
|
2018-11-04 14:34:53 -05:00
|
|
|
.ok_or(invalid_status())? as i32,
|
2015-09-25 09:00:49 -04:00
|
|
|
},
|
|
|
|
players: StatusPlayers {
|
2018-11-04 14:34:53 -05:00
|
|
|
max: players.get("max")
|
2015-10-07 14:36:59 -04:00
|
|
|
.and_then(Value::as_i64)
|
2018-11-04 14:34:53 -05:00
|
|
|
.ok_or(invalid_status())? as i32,
|
|
|
|
online: players.get("online")
|
2015-10-07 14:36:59 -04:00
|
|
|
.and_then(Value::as_i64)
|
2018-11-04 14:34:53 -05:00
|
|
|
.ok_or(invalid_status())? as i32,
|
2015-10-07 14:36:59 -04:00
|
|
|
sample: Vec::new(), /* TODO */
|
2015-09-25 09:00:49 -04:00
|
|
|
},
|
2018-11-04 14:34:53 -05:00
|
|
|
description: format::Component::from_value(val.get("description")
|
|
|
|
.ok_or(invalid_status())?),
|
2018-10-23 21:47:21 -04:00
|
|
|
favicon: val.get("favicon").and_then(Value::as_str).map(|v| v.to_owned()),
|
2015-10-07 14:36:59 -04:00
|
|
|
},
|
|
|
|
ping))
|
2015-09-25 09:00:49 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Status {
|
|
|
|
pub version: StatusVersion,
|
|
|
|
pub players: StatusPlayers,
|
|
|
|
pub description: format::Component,
|
|
|
|
pub favicon: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct StatusVersion {
|
|
|
|
pub name: String,
|
|
|
|
pub protocol: i32,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct StatusPlayers {
|
|
|
|
pub max: i32,
|
|
|
|
pub online: i32,
|
|
|
|
pub sample: Vec<StatusPlayer>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct StatusPlayer {
|
|
|
|
name: String,
|
|
|
|
id: String,
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Read for Conn {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
|
match self.cipher.as_mut() {
|
|
|
|
Option::None => self.stream.read(buf),
|
|
|
|
Option::Some(cipher) => {
|
2018-11-04 14:34:53 -05:00
|
|
|
let ret = self.stream.read(buf)?;
|
2018-11-01 23:45:40 -04:00
|
|
|
cipher.decrypt(&mut buf[..ret]);
|
|
|
|
|
2015-09-10 06:49:41 -04:00
|
|
|
Ok(ret)
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Write for Conn {
|
|
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
|
|
match self.cipher.as_mut() {
|
|
|
|
Option::None => self.stream.write(buf),
|
|
|
|
Option::Some(cipher) => {
|
2018-11-01 23:45:40 -04:00
|
|
|
// TODO: avoid copying, but trait requires non-mutable buf
|
|
|
|
let mut data = vec![0; buf.len()];
|
|
|
|
for i in 0..buf.len() {
|
|
|
|
data[i] = buf[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
cipher.encrypt(&mut data);
|
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
self.stream.write_all(&data)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
Ok(buf.len())
|
2015-10-07 14:36:59 -04:00
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
|
|
self.stream.flush()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clone for Conn {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Conn {
|
|
|
|
stream: self.stream.try_clone().unwrap(),
|
|
|
|
host: self.host.clone(),
|
|
|
|
port: self.port,
|
|
|
|
direction: self.direction,
|
|
|
|
state: self.state,
|
2018-12-03 17:22:47 -05:00
|
|
|
protocol_version: self.protocol_version,
|
2015-09-10 06:49:41 -04:00
|
|
|
cipher: Option::None,
|
|
|
|
compression_threshold: self.compression_threshold,
|
|
|
|
compression_read: Option::None,
|
|
|
|
compression_write: Option::None,
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-08 13:46:07 -04:00
|
|
|
pub trait PacketType {
|
2018-12-03 17:22:47 -05:00
|
|
|
fn packet_id(&self, protocol_version: i32) -> i32;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2016-04-08 13:46:07 -04:00
|
|
|
fn write<W: io::Write>(self, buf: &mut W) -> Result<(), Error>;
|
2015-09-07 16:11:00 -04:00
|
|
|
}
|