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::stream_cipher::{NewStreamCipher, StreamCipher};
|
2020-06-21 15:17:24 -04:00
|
|
|
use cfb8::Cfb8;
|
|
|
|
use hex;
|
Add support for compiling WebAssembly wasm32-unknown-unknown target (#92)
Note this only is the first step in web support, although the project compiles, it doesn't run!
Merging now to avoid branch divergence, until dependencies can be updated for wasm support.
* Add instructions to build for wasm32-unknown-unknown with wasm-pack in www/
* Update to rust-clipboard fork to compile with emscripten
https://github.com/aweinstock314/rust-clipboard/pull/62
* Exclude reqwest dependency in wasm32
* Exclude compiling clipboard pasting on wasm32
* Exclude reqwest-using code from wasm32
* Install wasm target with rustup in Travis CI
* Update to collision 0.19.0
Fixes wasm incompatibility in deprecated rustc-serialize crate: https://github.com/rustgd/collision-rs/issues/106
error[E0046]: not all trait items implemented, missing: `encode`
--> github.com-1ecc6299db9ec823/rustc-serialize-0.3.24/src/serialize.rs:1358:1
* Increase travis_wait time even further, try 120 minutes
* Set RUST_BACKTRACE=1 in main
* Remove unused unneeded bzip2 features in zip crate
To fix wasm32-unknown-unknown target compile error:
error[E0432]: unresolved imports `libc::c_int`, `libc::c_uint`, `libc::c_void`, `libc::c_char`
--> src/github.com-1ecc6299db9ec823/bzip2-sys-0.1.7/lib.rs:5:12
|
5 | use libc::{c_int, c_uint, c_void, c_char};
| ^^^^^ ^^^^^^ ^^^^^^ ^^^^^^ no `c_char` in the root
| | | |
| | | no `c_void` in the root
| | no `c_uint` in the root
| no `c_int` in the root
* flate2 use Rust backend
* Add console_error_panic_hook module for wasm backtraces
* Build using wasm-pack, wasm-bindgen, run with wasm-app
* Update to miniz_oxide 0.2.1, remove patch for https://github.com/Frommi/miniz_oxide/issues/42
* Update to official clipboard crate since https://github.com/aweinstock314/rust-clipboard/pull/62 was merged, but git revision pending release
* Update to branch of glutin attempting to build for wasm
https://github.com/iceiix/glutin/pull/1
* Update winit dependency of glutin to git master
https://github.com/iceiix/winit/pull/2
* Update to glutin branch with working (compiles, doesn't run) wasm_stub
* Add app name in title on web page
* Add wasm to Travis-CI test matrix
* Update glutin to fix Windows EGL compilation on AppVeyor
https://github.com/iceiix/glutin/pull/1/commits/97797352b5242436cb82d8ecfb44242b69766e4c
2019-03-03 11:32:36 -05:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
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;
|
2020-06-21 15:17:24 -04:00
|
|
|
use serde_json;
|
|
|
|
use std_or_web::fs;
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2019-05-05 21:37:37 -04:00
|
|
|
pub mod forge;
|
2020-06-21 15:17:24 -04:00
|
|
|
pub mod mojang;
|
2015-09-10 06:49:41 -04:00
|
|
|
|
2018-11-04 14:48:03 -05:00
|
|
|
use crate::format;
|
2020-06-21 15:17:24 -04:00
|
|
|
use crate::nbt;
|
|
|
|
use crate::shared::Position;
|
|
|
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
2015-09-17 11:04:25 -04:00
|
|
|
use flate2::read::{ZlibDecoder, ZlibEncoder};
|
2018-09-30 19:19:24 -04:00
|
|
|
use flate2::Compression;
|
2019-05-22 19:01:14 -04:00
|
|
|
use log::debug;
|
2020-06-21 15:17:24 -04:00
|
|
|
use std::convert;
|
|
|
|
use std::default;
|
|
|
|
use std::fmt;
|
|
|
|
use std::io;
|
|
|
|
use std::io::{Read, Write};
|
|
|
|
use std::net::TcpStream;
|
|
|
|
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
|
|
|
use std::time::{Duration, Instant};
|
2015-09-25 09:00:49 -04:00
|
|
|
|
2020-06-27 17:44:22 -04:00
|
|
|
pub const SUPPORTED_PROTOCOLS: [i32; 19] = [
|
|
|
|
578, 575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74, 47, 5,
|
2020-06-21 15:17:24 -04:00
|
|
|
];
|
2015-09-07 16:11:00 -04:00
|
|
|
|
2020-01-08 21:57:57 -05:00
|
|
|
static CURRENT_PROTOCOL_VERSION: AtomicI32 = AtomicI32::new(SUPPORTED_PROTOCOLS[0]);
|
|
|
|
static NETWORK_DEBUG: AtomicBool = AtomicBool::new(false);
|
|
|
|
|
|
|
|
pub fn current_protocol_version() -> i32 {
|
|
|
|
CURRENT_PROTOCOL_VERSION.load(Ordering::Relaxed)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn enable_network_debug() {
|
|
|
|
NETWORK_DEBUG.store(true, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_network_debug() -> bool {
|
|
|
|
NETWORK_DEBUG.load(Ordering::Relaxed)
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -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(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -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);
|
Improve error reporting of invalid UTF-8 when deserializing strings
std::io::Read read_to_string() [1] reports this uninformative error:
thread 'main' panicked at 'Err: IOError(Custom { kind: InvalidData, error: StringError("stream did not contain valid UTF-8") })', src/server/mod.rs:442:33
Instead of read_to_string(), use read_to_end() to read into a buffer,
then convert using String::from_utf8() and unwrap it. This gives a
better error message when UTF-8 fails to decode:
thread '' panicked at 'called Result::unwrap() on an Err value: FromUtf8Error { bytes: [105, 110, 101, 99, 114, 97, 102, 116, 58, 99, 114, 97, 102, 116, 105, 110, 103, 95, 115, 104, 97, 112, 101, 100, 20, 109, 105, 110, 101, 99, 114, 97, 102, 116, 58, 98, 111, 110, 101, 95, 98, 108, 111, 99, 107, 3, 3, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 1, 134, 5, 1, 0, 1, 249, 2, 1, 0, 25, 109], error: Utf8Error { valid_up_to: 50, error_len: Some(1) } }', src/libcore/result.rs:1009:5
which is helpful for tracking down protocol errors, such as updating to
a new protocol (developed for GH-132 / GH-72).
[1] https://doc.rust-lang.org/nightly/std/io/trait.Read.html#method.read_to_string
[2] https://doc.rust-lang.org/std/string/struct.String.html#method.from_utf8
2019-04-30 22:20:32 -04:00
|
|
|
let mut bytes = Vec::<u8>::new();
|
|
|
|
buf.take(len as u64).read_to_end(&mut bytes)?;
|
|
|
|
let ret = String::from_utf8(bytes).unwrap();
|
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;
|
2019-05-12 17:08:53 -04:00
|
|
|
let mut bytes = Vec::<u8>::new();
|
|
|
|
buf.take(len as u64).read_to_end(&mut bytes)?;
|
|
|
|
let ret = String::from_utf8(bytes).unwrap();
|
2019-05-08 22:12:36 -04:00
|
|
|
Result::Ok(Self::from_string(&ret[..]))
|
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
|
|
|
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> {
|
2020-06-21 15:17:24 -04:00
|
|
|
buf.write_u8(if *self { 1 } else { 0 })?;
|
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 {
|
|
|
|
// 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;
|
2020-06-21 15:17:24 -04:00
|
|
|
for i in 0..8 {
|
|
|
|
high |= (parts[i] as u64) << (56 - i * 8);
|
|
|
|
low |= (parts[i + 8] as u64) << (56 - i * 8);
|
2016-04-06 17:50:31 -04:00
|
|
|
}
|
|
|
|
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> {
|
2020-06-21 15:17:24 -04: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(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-29 18:55:19 -05:00
|
|
|
pub struct Biomes3D {
|
|
|
|
pub data: [i32; 1024],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Biomes3D {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Biomes3D(")?;
|
|
|
|
for i in 0..1024 {
|
|
|
|
write!(f, "{}, ", self.data[i])?;
|
|
|
|
}
|
|
|
|
write!(f, ")")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Biomes3D {
|
|
|
|
fn default() -> Self {
|
|
|
|
Biomes3D { data: [0; 1024] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for Biomes3D {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Biomes3D, Error> {
|
|
|
|
let mut data: [i32; 1024] = [0; 1024];
|
|
|
|
|
|
|
|
// Non-length-prefixed three-dimensional biome data
|
|
|
|
for i in 0..1024 {
|
|
|
|
let b: i32 = Serializable::read_from(buf)?;
|
|
|
|
data[i] = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result::Ok(Biomes3D { data })
|
|
|
|
}
|
|
|
|
fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), Error> {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
pub trait Lengthable: Serializable + Copy + Default {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize;
|
|
|
|
fn from_len(_: 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
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -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)?;
|
2019-05-11 16:03:24 -04:00
|
|
|
let len: usize = len_data.into_len();
|
2015-10-07 14:36:59 -04:00
|
|
|
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> {
|
2019-05-11 16:03:24 -04:00
|
|
|
let len_data: L = L::from_len(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(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
impl<L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
|
2015-09-10 06:49:41 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
impl<L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> {
|
2015-09-12 15:31:26 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -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)?;
|
2019-05-11 16:03:24 -04:00
|
|
|
let len: usize = len_data.into_len();
|
2015-10-07 14:36:59 -04:00
|
|
|
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> {
|
2019-05-11 16:03:24 -04:00
|
|
|
let len_data: L = L::from_len(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(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
impl<L: Lengthable> Default for LenPrefixedBytes<L> {
|
2015-09-12 15:31:26 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
impl<L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
|
2015-09-12 15:31:26 -04:00
|
|
|
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 {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
2020-06-21 15:17:24 -04:00
|
|
|
if self {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> bool {
|
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
|
|
|
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 {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
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
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> u8 {
|
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
|
|
|
u as u8
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-12 15:31:26 -04:00
|
|
|
impl Lengthable for i16 {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
2015-09-12 15:31:26 -04:00
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> i16 {
|
2015-09-12 15:31:26 -04:00
|
|
|
u as i16
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Lengthable for i32 {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
2015-09-12 15:31:26 -04:00
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> i32 {
|
2015-09-12 15:31:26 -04:00
|
|
|
u as i32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix movement fixed-point packets, misplaced players on 1.7/8 (#140)
Movement packets were handled incorrectly, because although the fields are specified as integers they are actually fixed-point values, which need to be converted to floating-point before use. These fields were converted with `as f64`, but they actually need to be scaled. To fix this add several new types, FixedPoint5 for 5-bit fractional fixed-point and FixedPoint12 for 12-bit. Both are parameterized by an integer type: FixedPoint5<i32> and FixedPoint5<i8> for 1.7.10/1.8.9, FixedPoint12<i16> for 1.9+. This moves the calculation into the packet field parsing, so it no longer has to be calculated in src/server/mod.rs since the scaling is taken care of as part of the field type. This fixes the long-standing invisible or actually misplaced players bug on 1.7.10 and 1.8.9, closes #139.
* Add new FixedPoint5<T> type for 1.7/8, https://wiki.vg/Data_types#Fixed-point_numbers
* Add FixedPoint12<i16> for 1.9+, moving type conversion into packet type
https://wiki.vg/index.php?title=Protocol#Entity_Relative_Move
* Add num-traits 0.2.6 dependency for NumCast to use instead of From
* Use FixedPoint5<i32> in spawn object, experience orb, global entity, mob, player, teleport
* Use FixedPoint5<i8> and FixedPoint12<i16> in entity move, look and move
* Update packet handling bouncer functions, using f64::from for each conversion
2019-05-11 16:27:52 -04:00
|
|
|
use num_traits::cast::{cast, NumCast};
|
|
|
|
/// `FixedPoint5` has the 5 least-significant bits for the fractional
|
|
|
|
/// part, upper for integer part: https://wiki.vg/Data_types#Fixed-point_numbers
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct FixedPoint5<T>(T);
|
|
|
|
|
|
|
|
impl<T: Serializable> Serializable for FixedPoint5<T> {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
|
|
|
Ok(Self(Serializable::read_from(buf)?))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
self.0.write_to(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: default::Default> default::Default for FixedPoint5<T> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(T::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: NumCast> convert::From<f64> for FixedPoint5<T> {
|
|
|
|
fn from(x: f64) -> Self {
|
|
|
|
let n: T = cast(x * 32.0).unwrap();
|
|
|
|
FixedPoint5::<T>(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: NumCast> convert::From<FixedPoint5<T>> for f64 {
|
|
|
|
fn from(x: FixedPoint5<T>) -> Self {
|
|
|
|
let f: f64 = cast(x.0).unwrap();
|
|
|
|
f / 32.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
impl<T> fmt::Debug for FixedPoint5<T>
|
|
|
|
where
|
|
|
|
T: fmt::Display,
|
|
|
|
f64: convert::From<T>,
|
|
|
|
T: NumCast + Copy,
|
|
|
|
{
|
Fix movement fixed-point packets, misplaced players on 1.7/8 (#140)
Movement packets were handled incorrectly, because although the fields are specified as integers they are actually fixed-point values, which need to be converted to floating-point before use. These fields were converted with `as f64`, but they actually need to be scaled. To fix this add several new types, FixedPoint5 for 5-bit fractional fixed-point and FixedPoint12 for 12-bit. Both are parameterized by an integer type: FixedPoint5<i32> and FixedPoint5<i8> for 1.7.10/1.8.9, FixedPoint12<i16> for 1.9+. This moves the calculation into the packet field parsing, so it no longer has to be calculated in src/server/mod.rs since the scaling is taken care of as part of the field type. This fixes the long-standing invisible or actually misplaced players bug on 1.7.10 and 1.8.9, closes #139.
* Add new FixedPoint5<T> type for 1.7/8, https://wiki.vg/Data_types#Fixed-point_numbers
* Add FixedPoint12<i16> for 1.9+, moving type conversion into packet type
https://wiki.vg/index.php?title=Protocol#Entity_Relative_Move
* Add num-traits 0.2.6 dependency for NumCast to use instead of From
* Use FixedPoint5<i32> in spawn object, experience orb, global entity, mob, player, teleport
* Use FixedPoint5<i8> and FixedPoint12<i16> in entity move, look and move
* Update packet handling bouncer functions, using f64::from for each conversion
2019-05-11 16:27:52 -04:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let x: f64 = (*self).into();
|
|
|
|
write!(f, "FixedPoint5(#{} = {}f)", self.0, x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `FixedPoint12` is like `FixedPoint5` but the fractional part is 12-bit
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct FixedPoint12<T>(T);
|
|
|
|
|
|
|
|
impl<T: Serializable> Serializable for FixedPoint12<T> {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
|
|
|
Ok(Self(Serializable::read_from(buf)?))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
|
|
|
self.0.write_to(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: default::Default> default::Default for FixedPoint12<T> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(T::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: NumCast> convert::From<f64> for FixedPoint12<T> {
|
|
|
|
fn from(x: f64) -> Self {
|
|
|
|
let n: T = cast(x * 32.0 * 128.0).unwrap();
|
|
|
|
FixedPoint12::<T>(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: NumCast> convert::From<FixedPoint12<T>> for f64 {
|
|
|
|
fn from(x: FixedPoint12<T>) -> Self {
|
|
|
|
let f: f64 = cast(x.0).unwrap();
|
|
|
|
f / (32.0 * 128.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
impl<T> fmt::Debug for FixedPoint12<T>
|
|
|
|
where
|
|
|
|
T: fmt::Display,
|
|
|
|
f64: convert::From<T>,
|
|
|
|
T: NumCast + Copy,
|
|
|
|
{
|
Fix movement fixed-point packets, misplaced players on 1.7/8 (#140)
Movement packets were handled incorrectly, because although the fields are specified as integers they are actually fixed-point values, which need to be converted to floating-point before use. These fields were converted with `as f64`, but they actually need to be scaled. To fix this add several new types, FixedPoint5 for 5-bit fractional fixed-point and FixedPoint12 for 12-bit. Both are parameterized by an integer type: FixedPoint5<i32> and FixedPoint5<i8> for 1.7.10/1.8.9, FixedPoint12<i16> for 1.9+. This moves the calculation into the packet field parsing, so it no longer has to be calculated in src/server/mod.rs since the scaling is taken care of as part of the field type. This fixes the long-standing invisible or actually misplaced players bug on 1.7.10 and 1.8.9, closes #139.
* Add new FixedPoint5<T> type for 1.7/8, https://wiki.vg/Data_types#Fixed-point_numbers
* Add FixedPoint12<i16> for 1.9+, moving type conversion into packet type
https://wiki.vg/index.php?title=Protocol#Entity_Relative_Move
* Add num-traits 0.2.6 dependency for NumCast to use instead of From
* Use FixedPoint5<i32> in spawn object, experience orb, global entity, mob, player, teleport
* Use FixedPoint5<i8> and FixedPoint12<i16> in entity move, look and move
* Update packet handling bouncer functions, using f64::from for each conversion
2019-05-11 16:27:52 -04:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let x: f64 = (*self).into();
|
|
|
|
write!(f, "FixedPoint12(#{} = {}f)", self.0, x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
2015-09-12 15:31:26 -04:00
|
|
|
self.0 as usize
|
|
|
|
}
|
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> VarInt {
|
2015-09-12 15:31:26 -04:00
|
|
|
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> {
|
2020-06-21 15:17:24 -04:00
|
|
|
const PART: u32 = 0x7F;
|
2015-09-08 07:57:24 -04:00
|
|
|
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 {
|
2020-06-21 15:17:24 -04:00
|
|
|
break;
|
2015-09-08 07:57:24 -04:00
|
|
|
}
|
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> {
|
2020-06-21 15:17:24 -04:00
|
|
|
const PART: u32 = 0x7F;
|
2015-09-08 07:57:24 -04:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 21:37:37 -04:00
|
|
|
/// `VarShort` have a variable size (2 or 3 bytes) and are backwards-compatible
|
|
|
|
/// with vanilla shorts, used for Forge custom payloads
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct VarShort(pub i32);
|
|
|
|
|
|
|
|
impl Lengthable for VarShort {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
2019-05-05 21:37:37 -04:00
|
|
|
self.0 as usize
|
|
|
|
}
|
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> VarShort {
|
2019-05-05 21:37:37 -04:00
|
|
|
VarShort(u as i32)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for VarShort {
|
|
|
|
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarShort, Error> {
|
|
|
|
let low = buf.read_u16::<BigEndian>()? as u32;
|
|
|
|
let val = if (low & 0x8000) != 0 {
|
|
|
|
let high = buf.read_u8()? as u32;
|
|
|
|
|
|
|
|
(high << 15) | (low & 0x7fff)
|
|
|
|
} else {
|
|
|
|
low
|
|
|
|
};
|
|
|
|
|
|
|
|
Result::Ok(VarShort(val as i32))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
2020-06-21 15:17:24 -04:00
|
|
|
assert!(
|
|
|
|
self.0 >= 0 && self.0 <= 0x7fffff,
|
|
|
|
"VarShort invalid value: {}",
|
|
|
|
self.0
|
|
|
|
);
|
2019-05-05 21:37:37 -04:00
|
|
|
let mut low = self.0 & 0x7fff;
|
|
|
|
let high = (self.0 & 0x7f8000) >> 15;
|
|
|
|
if high != 0 {
|
|
|
|
low |= 0x8000;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.write_u16::<BigEndian>(low as u16)?;
|
|
|
|
|
|
|
|
if high != 0 {
|
|
|
|
buf.write_u8(high as u8)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl default::Default for VarShort {
|
|
|
|
fn default() -> VarShort {
|
|
|
|
VarShort(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for VarShort {
|
|
|
|
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 {
|
2019-05-11 16:03:24 -04:00
|
|
|
fn into_len(self) -> usize {
|
2015-09-10 06:49:41 -04:00
|
|
|
self.0 as usize
|
|
|
|
}
|
2015-09-12 15:31:26 -04:00
|
|
|
|
2019-05-11 16:03:24 -04:00
|
|
|
fn from_len(u: usize) -> VarLong {
|
2015-09-12 15:31:26 -04:00
|
|
|
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> {
|
2020-06-21 15:17:24 -04:00
|
|
|
const PART: u64 = 0x7F;
|
2015-09-12 15:31:26 -04:00
|
|
|
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 {
|
2020-06-21 15:17:24 -04:00
|
|
|
break;
|
2015-09-12 15:31:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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> {
|
2020-06-21 15:17:24 -04:00
|
|
|
const PART: u64 = 0x7F;
|
2015-09-12 15:31:26 -04:00
|
|
|
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,
|
2020-06-27 21:09:05 -04:00
|
|
|
((pos as i64) & 0xFFF) as i32,
|
|
|
|
((pos as i64) << 26 >> 38) as i32,
|
2016-04-03 15:53:40 -04:00
|
|
|
))
|
|
|
|
}
|
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)
|
2020-06-27 17:08:33 -04:00
|
|
|
| ((self.y as u64) & 0xFFF)
|
|
|
|
| (((self.z as u64) & 0x3FFFFFF) << 12);
|
2020-06-27 21:09:05 -04:00
|
|
|
|
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),
|
Add support for compiling WebAssembly wasm32-unknown-unknown target (#92)
Note this only is the first step in web support, although the project compiles, it doesn't run!
Merging now to avoid branch divergence, until dependencies can be updated for wasm support.
* Add instructions to build for wasm32-unknown-unknown with wasm-pack in www/
* Update to rust-clipboard fork to compile with emscripten
https://github.com/aweinstock314/rust-clipboard/pull/62
* Exclude reqwest dependency in wasm32
* Exclude compiling clipboard pasting on wasm32
* Exclude reqwest-using code from wasm32
* Install wasm target with rustup in Travis CI
* Update to collision 0.19.0
Fixes wasm incompatibility in deprecated rustc-serialize crate: https://github.com/rustgd/collision-rs/issues/106
error[E0046]: not all trait items implemented, missing: `encode`
--> github.com-1ecc6299db9ec823/rustc-serialize-0.3.24/src/serialize.rs:1358:1
* Increase travis_wait time even further, try 120 minutes
* Set RUST_BACKTRACE=1 in main
* Remove unused unneeded bzip2 features in zip crate
To fix wasm32-unknown-unknown target compile error:
error[E0432]: unresolved imports `libc::c_int`, `libc::c_uint`, `libc::c_void`, `libc::c_char`
--> src/github.com-1ecc6299db9ec823/bzip2-sys-0.1.7/lib.rs:5:12
|
5 | use libc::{c_int, c_uint, c_void, c_char};
| ^^^^^ ^^^^^^ ^^^^^^ ^^^^^^ no `c_char` in the root
| | | |
| | | no `c_void` in the root
| | no `c_uint` in the root
| no `c_int` in the root
* flate2 use Rust backend
* Add console_error_panic_hook module for wasm backtraces
* Build using wasm-pack, wasm-bindgen, run with wasm-app
* Update to miniz_oxide 0.2.1, remove patch for https://github.com/Frommi/miniz_oxide/issues/42
* Update to official clipboard crate since https://github.com/aweinstock314/rust-clipboard/pull/62 was merged, but git revision pending release
* Update to branch of glutin attempting to build for wasm
https://github.com/iceiix/glutin/pull/1
* Update winit dependency of glutin to git master
https://github.com/iceiix/winit/pull/2
* Update to glutin branch with working (compiles, doesn't run) wasm_stub
* Add app name in title on web page
* Add wasm to Travis-CI test matrix
* Update glutin to fix Windows EGL compilation on AppVeyor
https://github.com/iceiix/glutin/pull/1/commits/97797352b5242436cb82d8ecfb44242b69766e4c
2019-03-03 11:32:36 -05:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add support for compiling WebAssembly wasm32-unknown-unknown target (#92)
Note this only is the first step in web support, although the project compiles, it doesn't run!
Merging now to avoid branch divergence, until dependencies can be updated for wasm support.
* Add instructions to build for wasm32-unknown-unknown with wasm-pack in www/
* Update to rust-clipboard fork to compile with emscripten
https://github.com/aweinstock314/rust-clipboard/pull/62
* Exclude reqwest dependency in wasm32
* Exclude compiling clipboard pasting on wasm32
* Exclude reqwest-using code from wasm32
* Install wasm target with rustup in Travis CI
* Update to collision 0.19.0
Fixes wasm incompatibility in deprecated rustc-serialize crate: https://github.com/rustgd/collision-rs/issues/106
error[E0046]: not all trait items implemented, missing: `encode`
--> github.com-1ecc6299db9ec823/rustc-serialize-0.3.24/src/serialize.rs:1358:1
* Increase travis_wait time even further, try 120 minutes
* Set RUST_BACKTRACE=1 in main
* Remove unused unneeded bzip2 features in zip crate
To fix wasm32-unknown-unknown target compile error:
error[E0432]: unresolved imports `libc::c_int`, `libc::c_uint`, `libc::c_void`, `libc::c_char`
--> src/github.com-1ecc6299db9ec823/bzip2-sys-0.1.7/lib.rs:5:12
|
5 | use libc::{c_int, c_uint, c_void, c_char};
| ^^^^^ ^^^^^^ ^^^^^^ ^^^^^^ no `c_char` in the root
| | | |
| | | no `c_void` in the root
| | no `c_uint` in the root
| no `c_int` in the root
* flate2 use Rust backend
* Add console_error_panic_hook module for wasm backtraces
* Build using wasm-pack, wasm-bindgen, run with wasm-app
* Update to miniz_oxide 0.2.1, remove patch for https://github.com/Frommi/miniz_oxide/issues/42
* Update to official clipboard crate since https://github.com/aweinstock314/rust-clipboard/pull/62 was merged, but git revision pending release
* Update to branch of glutin attempting to build for wasm
https://github.com/iceiix/glutin/pull/1
* Update winit dependency of glutin to git master
https://github.com/iceiix/winit/pull/2
* Update to glutin branch with working (compiles, doesn't run) wasm_stub
* Add app name in title on web page
* Add wasm to Travis-CI test matrix
* Update glutin to fix Windows EGL compilation on AppVeyor
https://github.com/iceiix/glutin/pull/1/commits/97797352b5242436cb82d8ecfb44242b69766e4c
2019-03-03 11:32:36 -05:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-04 22:20:36 -05:00
|
|
|
impl ::std::error::Error for Error {}
|
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),
|
Add support for compiling WebAssembly wasm32-unknown-unknown target (#92)
Note this only is the first step in web support, although the project compiles, it doesn't run!
Merging now to avoid branch divergence, until dependencies can be updated for wasm support.
* Add instructions to build for wasm32-unknown-unknown with wasm-pack in www/
* Update to rust-clipboard fork to compile with emscripten
https://github.com/aweinstock314/rust-clipboard/pull/62
* Exclude reqwest dependency in wasm32
* Exclude compiling clipboard pasting on wasm32
* Exclude reqwest-using code from wasm32
* Install wasm target with rustup in Travis CI
* Update to collision 0.19.0
Fixes wasm incompatibility in deprecated rustc-serialize crate: https://github.com/rustgd/collision-rs/issues/106
error[E0046]: not all trait items implemented, missing: `encode`
--> github.com-1ecc6299db9ec823/rustc-serialize-0.3.24/src/serialize.rs:1358:1
* Increase travis_wait time even further, try 120 minutes
* Set RUST_BACKTRACE=1 in main
* Remove unused unneeded bzip2 features in zip crate
To fix wasm32-unknown-unknown target compile error:
error[E0432]: unresolved imports `libc::c_int`, `libc::c_uint`, `libc::c_void`, `libc::c_char`
--> src/github.com-1ecc6299db9ec823/bzip2-sys-0.1.7/lib.rs:5:12
|
5 | use libc::{c_int, c_uint, c_void, c_char};
| ^^^^^ ^^^^^^ ^^^^^^ ^^^^^^ no `c_char` in the root
| | | |
| | | no `c_void` in the root
| | no `c_uint` in the root
| no `c_int` in the root
* flate2 use Rust backend
* Add console_error_panic_hook module for wasm backtraces
* Build using wasm-pack, wasm-bindgen, run with wasm-app
* Update to miniz_oxide 0.2.1, remove patch for https://github.com/Frommi/miniz_oxide/issues/42
* Update to official clipboard crate since https://github.com/aweinstock314/rust-clipboard/pull/62 was merged, but git revision pending release
* Update to branch of glutin attempting to build for wasm
https://github.com/iceiix/glutin/pull/1
* Update winit dependency of glutin to git master
https://github.com/iceiix/winit/pull/2
* Update to glutin branch with working (compiles, doesn't run) wasm_stub
* Add app name in title on web page
* Add wasm to Travis-CI test matrix
* Update glutin to fix Windows EGL compilation on AppVeyor
https://github.com/iceiix/glutin/pull/1/commits/97797352b5242436cb82d8ecfb44242b69766e4c
2019-03-03 11:32:36 -05:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
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-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> {
|
2020-01-08 21:57:57 -05:00
|
|
|
CURRENT_PROTOCOL_VERSION.store(protocol_version, Ordering::Relaxed);
|
2018-12-11 21:18:25 -05:00
|
|
|
|
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,
|
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 {
|
|
|
|
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)?;
|
Fix packet compression (fixes FTB Beyond, etc.). Closes #146 (#147)
Previously, the zlib compressor was initialized once, lazily, then reused for each packet by resetting the stream. This didn't properly emit the zlib headers, so packet compression was broken and caused "java.util.zip.DataFormatException: incorrect header check" on the server. Since packets are only compressed above a threshold, this problem manifested itself only on larger servers, such as 1.10.2 FTB Beyond and Skyfactory 3, and 1.12.2 SevTech: Ages, which require sending a large ModList above the compression threshold enabled by the server. Change to instead recreate the zlib compressor, each time it is used as to capture the full header. For symmetry, the decompressor is also recreated each time.
* Removes self.compression_write and self.compression_read instance variables
* Remove self.compression_write, initialize with cursor
* Log compressing/decompressing packets in network debug mode
2019-05-12 15:15:02 -04:00
|
|
|
let mut write = ZlibEncoder::new(io::Cursor::new(buf), Compression::default());
|
2018-11-04 14:34:53 -05:00
|
|
|
write.read_to_end(&mut new)?;
|
2020-01-08 21:57:57 -05:00
|
|
|
if is_network_debug() {
|
2020-06-21 15:17:24 -04:00
|
|
|
debug!(
|
|
|
|
"Compressed for sending {} bytes to {} since > threshold {}, new={:?}",
|
|
|
|
uncompressed_size,
|
|
|
|
new.len(),
|
|
|
|
self.compression_threshold,
|
|
|
|
new
|
|
|
|
);
|
Fix packet compression (fixes FTB Beyond, etc.). Closes #146 (#147)
Previously, the zlib compressor was initialized once, lazily, then reused for each packet by resetting the stream. This didn't properly emit the zlib headers, so packet compression was broken and caused "java.util.zip.DataFormatException: incorrect header check" on the server. Since packets are only compressed above a threshold, this problem manifested itself only on larger servers, such as 1.10.2 FTB Beyond and Skyfactory 3, and 1.12.2 SevTech: Ages, which require sending a large ModList above the compression threshold enabled by the server. Change to instead recreate the zlib compressor, each time it is used as to capture the full header. For symmetry, the decompressor is also recreated each time.
* Removes self.compression_write and self.compression_read instance variables
* Remove self.compression_write, initialize with cursor
* Log compressing/decompressing packets in network debug mode
2019-05-12 15:15:02 -04:00
|
|
|
}
|
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 {
|
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);
|
|
|
|
{
|
Fix packet compression (fixes FTB Beyond, etc.). Closes #146 (#147)
Previously, the zlib compressor was initialized once, lazily, then reused for each packet by resetting the stream. This didn't properly emit the zlib headers, so packet compression was broken and caused "java.util.zip.DataFormatException: incorrect header check" on the server. Since packets are only compressed above a threshold, this problem manifested itself only on larger servers, such as 1.10.2 FTB Beyond and Skyfactory 3, and 1.12.2 SevTech: Ages, which require sending a large ModList above the compression threshold enabled by the server. Change to instead recreate the zlib compressor, each time it is used as to capture the full header. For symmetry, the decompressor is also recreated each time.
* Removes self.compression_write and self.compression_read instance variables
* Remove self.compression_write, initialize with cursor
* Log compressing/decompressing packets in network debug mode
2019-05-12 15:15:02 -04:00
|
|
|
let mut reader = ZlibDecoder::new(buf);
|
2018-11-04 14:34:53 -05:00
|
|
|
reader.read_to_end(&mut new)?;
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2020-01-08 21:57:57 -05:00
|
|
|
if is_network_debug() {
|
2020-06-21 15:17:24 -04:00
|
|
|
debug!(
|
|
|
|
"Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
|
|
|
|
self.compression_threshold,
|
|
|
|
len,
|
|
|
|
uncompressed_size,
|
|
|
|
new.len()
|
|
|
|
);
|
Fix packet compression (fixes FTB Beyond, etc.). Closes #146 (#147)
Previously, the zlib compressor was initialized once, lazily, then reused for each packet by resetting the stream. This didn't properly emit the zlib headers, so packet compression was broken and caused "java.util.zip.DataFormatException: incorrect header check" on the server. Since packets are only compressed above a threshold, this problem manifested itself only on larger servers, such as 1.10.2 FTB Beyond and Skyfactory 3, and 1.12.2 SevTech: Ages, which require sending a large ModList above the compression threshold enabled by the server. Change to instead recreate the zlib compressor, each time it is used as to capture the full header. For symmetry, the decompressor is also recreated each time.
* Removes self.compression_write and self.compression_read instance variables
* Remove self.compression_write, initialize with cursor
* Log compressing/decompressing packets in network debug mode
2019-05-12 15:15:02 -04:00
|
|
|
}
|
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,
|
|
|
|
};
|
|
|
|
|
2020-01-08 21:57:57 -05:00
|
|
|
if is_network_debug() {
|
2020-06-21 15:17:24 -04:00
|
|
|
debug!(
|
|
|
|
"about to parse id={:x}, dir={:?} state={:?}",
|
|
|
|
id, dir, self.state
|
|
|
|
);
|
2019-05-29 11:21:56 -04:00
|
|
|
fs::File::create("last-packet")?.write_all(buf.get_ref())?;
|
2019-05-05 17:32:48 -04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2020-01-08 21:57:57 -05:00
|
|
|
if is_network_debug() {
|
2019-05-22 19:01:14 -04:00
|
|
|
debug!("packet = {:?}", packet);
|
2019-05-05 17:32:48 -04:00
|
|
|
}
|
|
|
|
|
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 {
|
2020-06-21 15:17:24 -04:00
|
|
|
return Result::Err(Error::Err(format!(
|
|
|
|
"Failed to read all of packet 0x{:X}, \
|
2015-10-07 14:36:59 -04:00
|
|
|
had {} bytes left",
|
2020-06-21 15:17:24 -04:00
|
|
|
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> {
|
2016-03-18 07:39:03 -04:00
|
|
|
use self::packet::handshake::serverbound::Handshake;
|
2020-06-21 15:17:24 -04:00
|
|
|
use self::packet::status::serverbound::*;
|
2015-09-25 09:00:49 -04:00
|
|
|
use self::packet::Packet;
|
2020-06-21 15:17:24 -04:00
|
|
|
use serde_json::Value;
|
2015-09-25 09:00:49 -04:00
|
|
|
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
|
|
|
|
2019-05-05 21:37:37 -04:00
|
|
|
// For modded servers, get the list of Forge mods installed
|
|
|
|
let mut forge_mods: std::vec::Vec<crate::protocol::forge::ForgeMod> = vec![];
|
|
|
|
if let Some(modinfo) = val.get("modinfo") {
|
|
|
|
if let Some(modinfo_type) = modinfo.get("type") {
|
|
|
|
if modinfo_type == "FML" {
|
|
|
|
if let Some(modlist) = modinfo.get("modList") {
|
|
|
|
if let Value::Array(items) = modlist {
|
|
|
|
for item in items {
|
|
|
|
if let Value::Object(obj) = item {
|
2020-06-21 15:17:24 -04:00
|
|
|
let modid =
|
|
|
|
obj.get("modid").unwrap().as_str().unwrap().to_string();
|
|
|
|
let version =
|
|
|
|
obj.get("version").unwrap().as_str().unwrap().to_string();
|
2019-05-05 21:37:37 -04:00
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
forge_mods
|
|
|
|
.push(crate::protocol::forge::ForgeMod { modid, version });
|
2019-05-05 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-06-21 15:17:24 -04:00
|
|
|
panic!(
|
|
|
|
"Unrecognized modinfo type in server ping response: {} in {}",
|
|
|
|
modinfo_type, modinfo
|
|
|
|
);
|
2019-05-05 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-21 15:01:31 -04:00
|
|
|
// Forge 1.13+ TODO: update for 1.14+ and test
|
|
|
|
if let Some(forge_data) = val.get("forgeData") {
|
|
|
|
if let Some(mods) = forge_data.get("mods") {
|
|
|
|
if let Value::Array(items) = mods {
|
|
|
|
for item in items {
|
|
|
|
if let Value::Object(obj) = item {
|
|
|
|
let modid = obj.get("modId").unwrap().as_str().unwrap().to_string();
|
2020-06-21 15:17:24 -04:00
|
|
|
let modmarker =
|
|
|
|
obj.get("modmarker").unwrap().as_str().unwrap().to_string();
|
2020-06-21 15:01:31 -04:00
|
|
|
|
|
|
|
let version = modmarker;
|
|
|
|
|
|
|
|
forge_mods.push(crate::protocol::forge::ForgeMod { modid, version });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-05 21:37:37 -04:00
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
Ok((
|
|
|
|
Status {
|
|
|
|
version: StatusVersion {
|
|
|
|
name: version
|
|
|
|
.get("name")
|
|
|
|
.and_then(Value::as_str)
|
|
|
|
.ok_or(invalid_status())?
|
|
|
|
.to_owned(),
|
|
|
|
protocol: version
|
|
|
|
.get("protocol")
|
|
|
|
.and_then(Value::as_i64)
|
|
|
|
.ok_or(invalid_status())? as i32,
|
|
|
|
},
|
|
|
|
players: StatusPlayers {
|
|
|
|
max: players
|
|
|
|
.get("max")
|
|
|
|
.and_then(Value::as_i64)
|
|
|
|
.ok_or(invalid_status())? as i32,
|
|
|
|
online: players
|
|
|
|
.get("online")
|
|
|
|
.and_then(Value::as_i64)
|
|
|
|
.ok_or(invalid_status())? as i32,
|
|
|
|
sample: Vec::new(), /* TODO */
|
|
|
|
},
|
|
|
|
description: format::Component::from_value(
|
|
|
|
val.get("description").ok_or(invalid_status())?,
|
|
|
|
),
|
|
|
|
favicon: val
|
|
|
|
.get("favicon")
|
|
|
|
.and_then(Value::as_str)
|
|
|
|
.map(|v| v.to_owned()),
|
|
|
|
forge_mods,
|
2015-09-25 09:00:49 -04:00
|
|
|
},
|
2020-06-21 15:17:24 -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>,
|
2019-05-05 21:37:37 -04:00
|
|
|
pub forge_mods: Vec<crate::protocol::forge::ForgeMod>,
|
2015-09-25 09:00:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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,
|
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
|
|
|
}
|