This commit is contained in:
Snowiiii
2024-07-31 00:07:50 +02:00
parent a1b08a66dd
commit 5851ce5a3e
17 changed files with 1242 additions and 182 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
/target /target
configuration.toml
features.toml

View File

@@ -1,14 +0,0 @@
server_address = "127.0.0.1"
server_port = 25565
seed = ""
max_plyers = 32
view_distances = 10
simulation_distance = 10
resource_pack = ""
resource_pack_sha1 = ""
default_difficulty = "Normal"
allow_nether = true
hardcore = false
online_mode = true
spawn_protection = 16
motd = "A Blazing fast Pumpkin Server!"

View File

@@ -1,2 +0,0 @@
liquid_physics = true
encryption = true

View File

@@ -1,4 +1,4 @@
use crate::protocol::{nbt::NBT, VarInt, VarLong}; use crate::protocol::{nbt::nbt::NBT, VarInt, VarLong};
use super::{Endian, CONTINUE_BIT, SEGMENT_BITS}; use super::{Endian, CONTINUE_BIT, SEGMENT_BITS};
use byteorder::{BigEndian, ByteOrder, LittleEndian}; use byteorder::{BigEndian, ByteOrder, LittleEndian};
@@ -618,6 +618,29 @@ impl ByteBuffer {
read_number!(self, read_f64, 8) read_number!(self, read_f64, 8)
} }
pub fn read_list<T>(&mut self, val: impl Fn(&mut ByteBuffer) -> Result<T>) -> Result<Vec<T>> {
let len = self.read_var_int()?.try_into().unwrap();
let mut list = Vec::with_capacity(len);
for _ in 0..len {
list.push(val(self)?);
}
Ok(list)
}
/// Writes a list to the buffer.
pub fn write_list<T>(&mut self, list: &[T], write: impl Fn(&mut ByteBuffer, &T)) {
self.write_var_int(list.len().try_into().unwrap());
for v in list {
write(self, v);
}
}
pub fn read_varint_arr(&mut self) -> Result<Vec<i32>> {
self.read_list(|buf| buf.read_var_int())
}
pub fn write_varint_arr(&mut self, v: &[i32]) {
self.write_list(v, |p, &v| p.write_var_int(v))
}
pub fn read_nbt(&mut self) -> Result<NBT> { pub fn read_nbt(&mut self) -> Result<NBT> {
match NBT::deserialize_buf(self) { match NBT::deserialize_buf(self) {
Ok(v) => Ok(v), Ok(v) => Ok(v),

View File

@@ -1,26 +1,4 @@
use crate::protocol::{nbt::NBT, ClientPacket, VarInt}; use crate::protocol::{registry, ClientPacket, VarInt};
pub struct CRegistryData {
registry_id: String,
entry_count: VarInt,
entries: NBT,
}
struct Entry {
entry_id: String,
has_data: bool,
data: NBT,
}
impl ClientPacket for CRegistryData {
const PACKET_ID: VarInt = 0x07;
fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {
bytebuf.write_string(&self.registry_id);
bytebuf.write_var_int(self.entry_count);
// bytebuf.write_array(self.entries);
}
}
pub struct CCookieRequest { pub struct CCookieRequest {
// TODO // TODO
@@ -69,3 +47,69 @@ impl ClientPacket for CFinishConfig {
fn write(&self, _bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {} fn write(&self, _bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {}
} }
pub struct CKnownPacks {
count: VarInt,
known_packs: Vec<KnownPack>,
}
impl CKnownPacks {
pub fn new(count: VarInt, known_packs: Vec<KnownPack>) -> Self {
Self { count, known_packs }
}
}
pub struct KnownPack {
pub namespace: String,
pub id: String,
pub version: String,
}
impl ClientPacket for CKnownPacks {
const PACKET_ID: VarInt = 0x0E;
fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {
bytebuf.write_var_int(self.count);
bytebuf.write_list::<KnownPack>(&self.known_packs, |p, v| {
p.write_string(&v.namespace);
p.write_string(&v.id);
p.write_string(&v.version);
});
}
}
pub struct CRegistryData {
registry_id: String,
entry_count: VarInt,
entries: Vec<Entry>,
}
impl CRegistryData {
pub fn new(registry_id: String, entry_count: VarInt, entries: Vec<Entry>) -> Self {
Self {
registry_id,
entry_count,
entries,
}
}
}
pub struct Entry {
pub entry_id: String,
pub has_data: bool,
// data provided by registry::write_codec
}
impl ClientPacket for CRegistryData {
const PACKET_ID: VarInt = 0x07;
fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {
bytebuf.write_string(&self.registry_id);
bytebuf.write_var_int(self.entry_count);
bytebuf.write_list::<Entry>(&self.entries, |p, v| {
p.write_string(&v.entry_id);
p.write_bool(v.has_data);
registry::write_codec(p, -64, 320);
});
}
}

View File

@@ -1,4 +1,3 @@
use crate::{ use crate::{
entity::player::GameMode, entity::player::GameMode,
protocol::{ClientPacket, VarInt}, protocol::{ClientPacket, VarInt},

View File

@@ -1,29 +1,52 @@
use std::{collections::HashMap, error::Error, fmt, string::FromUtf8Error}; use flate2::read::{GzDecoder, ZlibDecoder};
use std::{collections::HashMap, error::Error, fmt, io, io::Read, string::FromUtf8Error};
use crate::protocol::bytebuf::buffer::ByteBuffer; use crate::protocol::bytebuf::buffer::ByteBuffer;
use super::{Tag, NBT}; use super::{nbt::ParseError, Tag, NBT};
#[derive(Debug)]
pub enum ParseError {
InvalidType(u8),
InvalidString(FromUtf8Error),
}
impl fmt::Display for ParseError { impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::InvalidType(ty) => write!(f, "invalid tag type: {}", ty), Self::InvalidType(ty) => write!(f, "invalid tag type: {ty}"),
Self::InvalidString(e) => write!(f, "invalid string: {}", e), Self::InvalidString(e) => write!(f, "invalid string: {e}"),
Self::IO(e) => write!(f, "io error: {e}"),
} }
} }
} }
impl From<FromUtf8Error> for ParseError {
fn from(e: FromUtf8Error) -> ParseError {
ParseError::InvalidString(e)
}
}
impl From<io::Error> for ParseError {
fn from(e: io::Error) -> ParseError {
ParseError::IO(e)
}
}
impl Error for ParseError {} impl Error for ParseError {}
impl NBT { impl NBT {
pub fn deserialize_file(buf: Vec<u8>) -> Result<Self, ParseError> {
if buf.len() >= 2 && buf[0] == 0x1f && buf[1] == 0x8b {
// This means its gzipped
let mut d: GzDecoder<&[u8]> = GzDecoder::new(buf.as_ref());
let mut buf = vec![];
d.read_to_end(&mut buf)?;
Self::deserialize(buf)
} else {
// It could be zlib compressed or not compressed
let mut d: ZlibDecoder<&[u8]> = ZlibDecoder::new(buf.as_ref());
let mut decompressed = vec![];
match d.read_to_end(&mut decompressed) {
Ok(_) => Self::deserialize(decompressed),
Err(_) => Self::deserialize(buf),
}
}
}
/// Deserializes the given byte array as nbt data. /// Deserializes the given byte array as nbt data.
pub fn deserialize(buf: Vec<u8>) -> Result<Self, ParseError> { pub fn deserialize(mut buf: Vec<u8>) -> Result<Self, ParseError> {
Self::deserialize_buf(&mut ByteBuffer::from_vec(buf)) Self::deserialize_buf(&mut ByteBuffer::from_vec(buf))
} }
/// Deserializes the given buffer as nbt data. This will continue reading /// Deserializes the given buffer as nbt data. This will continue reading
@@ -32,10 +55,14 @@ impl NBT {
/// buffer will be in an undefined state (it will still be safe, but there are /// buffer will be in an undefined state (it will still be safe, but there are
/// no guarantees as too how far ahead the buffer will have been advanced). /// no guarantees as too how far ahead the buffer will have been advanced).
pub fn deserialize_buf(buf: &mut ByteBuffer) -> Result<Self, ParseError> { pub fn deserialize_buf(buf: &mut ByteBuffer) -> Result<Self, ParseError> {
let ty = buf.read_u8().unwrap(); let ty = buf.read_u8()?;
let len = buf.read_u16().unwrap(); if ty == 0 {
let name = String::from_utf8(buf.read_bytes(len as usize).unwrap()).unwrap(); Ok(NBT::empty())
Ok(NBT::new(&name, Tag::deserialize(ty, buf)?)) } else {
let len = buf.read_u16()?;
let name = String::from_utf8(buf.read_bytes(len as usize)?)?;
Ok(NBT::new(&name, Tag::deserialize(ty, buf)?))
}
} }
} }
@@ -43,26 +70,26 @@ impl Tag {
fn deserialize(ty: u8, buf: &mut ByteBuffer) -> Result<Self, ParseError> { fn deserialize(ty: u8, buf: &mut ByteBuffer) -> Result<Self, ParseError> {
match ty { match ty {
0 => Ok(Self::End), 0 => Ok(Self::End),
1 => Ok(Self::Byte(buf.read_i8().unwrap())), 1 => Ok(Self::Byte(buf.read_i8()?)),
2 => Ok(Self::Short(buf.read_i16().unwrap())), 2 => Ok(Self::Short(buf.read_i16()?)),
3 => Ok(Self::Int(buf.read_i32().unwrap())), 3 => Ok(Self::Int(buf.read_i32()?)),
4 => Ok(Self::Long(buf.read_i64().unwrap())), 4 => Ok(Self::Long(buf.read_i64()?)),
5 => Ok(Self::Float(buf.read_f32().unwrap())), 5 => Ok(Self::Float(buf.read_f32()?)),
6 => Ok(Self::Double(buf.read_f64().unwrap())), 6 => Ok(Self::Double(buf.read_f64()?)),
7 => { 7 => {
let len = buf.read_i32().unwrap(); let len = buf.read_i32()?;
Ok(Self::ByteArr(buf.read_bytes(len as usize).unwrap())) Ok(Self::ByteArr(buf.read_bytes(len as usize)?))
} }
8 => { 8 => {
let len = buf.read_u16().unwrap(); let len = buf.read_u16()?;
match String::from_utf8(buf.read_bytes(len as usize).unwrap()) { match String::from_utf8(buf.read_bytes(len as usize)?) {
Ok(v) => Ok(Self::String(v)), Ok(v) => Ok(Self::String(v)),
Err(e) => Err(ParseError::InvalidString(e)), Err(e) => Err(ParseError::InvalidString(e)),
} }
} }
9 => { 9 => {
let inner_ty = buf.read_u8().unwrap(); let inner_ty = buf.read_u8()?;
let len = buf.read_i32().unwrap(); let len = buf.read_i32()?;
let mut inner = Vec::with_capacity(len as usize); let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len { for _ in 0..len {
inner.push(Tag::deserialize(inner_ty, buf)?); inner.push(Tag::deserialize(inner_ty, buf)?);
@@ -72,30 +99,30 @@ impl Tag {
10 => { 10 => {
let mut inner = HashMap::new(); let mut inner = HashMap::new();
loop { loop {
let ty = buf.read_u8().unwrap(); let ty = buf.read_u8()?;
if ty == Self::End.ty() { if ty == Self::End.ty() {
break; break;
} }
let len = buf.read_u16().unwrap(); let len = buf.read_u16()?;
let name = String::from_utf8(buf.read_bytes(len as usize).unwrap()).unwrap(); let name = String::from_utf8(buf.read_bytes(len as usize)?).unwrap();
let tag = Tag::deserialize(ty, buf)?; let tag = Tag::deserialize(ty, buf)?;
inner.insert(name, tag); inner.insert(name, tag);
} }
Ok(Self::Compound(inner)) Ok(inner.into())
} }
11 => { 11 => {
let len = buf.read_i32().unwrap(); let len = buf.read_i32()?;
let mut inner = Vec::with_capacity(len as usize); let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len { for _ in 0..len {
inner.push(buf.read_i32().unwrap()); inner.push(buf.read_i32()?);
} }
Ok(Self::IntArray(inner)) Ok(Self::IntArray(inner))
} }
12 => { 12 => {
let len = buf.read_i32().unwrap(); let len = buf.read_i32()?;
let mut inner = Vec::with_capacity(len as usize); let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len { for _ in 0..len {
inner.push(buf.read_i64().unwrap()); inner.push(buf.read_i64()?);
} }
Ok(Self::LongArray(inner)) Ok(Self::LongArray(inner))
} }

View File

@@ -0,0 +1,56 @@
use super::Tag;
use serde::{de, ser};
use std::{fmt, fmt::Display, num::TryFromIntError};
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
Message(String),
Eof,
TryFromInt(TryFromIntError),
ListType(Tag, Tag),
MapKey(Tag),
CannotSerializeNone,
Enum,
}
pub type Result<T> = std::result::Result<T, Error>;
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Message(msg) => write!(f, "{msg}"),
Error::Eof => write!(f, "unexpected end of input"),
Error::TryFromInt(e) => write!(f, "invalid integer: {e}"),
Error::ListType(expected, got) => {
write!(f, "expected type in list: {expected:?}, got: {got:?}")
}
Error::MapKey(got) => {
write!(f, "expected a string for map key, got: {got:?}")
}
Error::CannotSerializeNone => {
write!(
f,
"cannot serialize `None` or `()` (use `#[serde(skip_serializing_if = \"Option::is_none\")]`)"
)
}
Error::Enum => {
write!(f, "enums are not supported")
}
}
}
}
impl std::error::Error for Error {}

View File

@@ -1,115 +1,445 @@
use std::collections::HashMap; use std::collections::HashMap;
use error::Error;
use error::Result;
use nbt::Tag;
use nbt::NBT;
use serde::{ser, Serialize};
mod deserialize; mod deserialize;
mod error;
pub mod nbt;
mod serialize; mod serialize;
#[derive(Debug, Clone, PartialEq)] pub fn to_nbt<T>(name: &str, value: &T) -> anyhow::Result<NBT>
pub struct NBT { where
T: Serialize,
{
Ok(NBT::new(name, to_tag(value)?))
}
pub fn to_tag<T>(value: &T) -> anyhow::Result<Tag>
where
T: Serialize,
{
let mut serializer = Serializer { tag: Tag::End };
value.serialize(&mut serializer)?;
Ok(serializer.tag)
}
pub struct Serializer {
tag: Tag, tag: Tag,
name: String,
} }
/// This is a single tag. It does not contain a name, but has the actual data pub struct SeqSerializer<'a> {
/// for any of the nbt tags. ser: &'a mut Serializer,
#[derive(Debug, Clone, PartialEq)] items: Vec<Tag>,
pub enum Tag { }
End, pub struct MapSerializer<'a> {
Byte(i8), ser: &'a mut Serializer,
Short(i16), key: Option<String>,
Int(i32), items: HashMap<String, Tag>,
Long(i64),
Float(f32),
Double(f64),
ByteArr(Vec<u8>),
String(String),
List(Vec<Tag>), // All elements must be the same type, and un-named.
Compound(HashMap<String, Tag>), // Types can be any kind, and are named. Order is not defined.
IntArray(Vec<i32>),
LongArray(Vec<i64>),
} }
impl NBT { impl<'a> ser::Serializer for &'a mut Serializer {
/// Creates a new nbt tag. The tag value can be anything. // The output type produced by this `Serializer` during successful
/// // serialization. Most serializers that produce text or binary output should
/// # Panics // set `Ok = ()` and serialize into an `io::Write` or buffer contained
/// This will panic if the tag is a list, and the values within that list // within the `Serializer` instance, as happens here. Serializers that build
/// contain multiple types. This is a limitation with the nbt data format: // in-memory data structures may be simplified by using `Ok` to propagate
/// lists can only contain one type of data. // the data structure around.
pub fn new(name: &str, tag: Tag) -> Self { type Ok = ();
if let Tag::List(inner) = &tag { type Error = Error;
if let Some(v) = inner.get(0) {
let ty = v.ty(); // Associated types for keeping track of additional state while serializing
for v in inner { // compound data structures like sequences and maps. In this case no
if v.ty() != ty { // additional state is required beyond what is already stored in the
panic!("the given list contains multiple types: {:?}", inner); // Serializer struct.
} type SerializeSeq = SeqSerializer<'a>;
} type SerializeTuple = SeqSerializer<'a>;
type SerializeTupleStruct = SeqSerializer<'a>;
type SerializeTupleVariant = SeqSerializer<'a>;
type SerializeMap = MapSerializer<'a>;
type SerializeStruct = MapSerializer<'a>;
type SerializeStructVariant = MapSerializer<'a>;
// Here we go with the simple methods. The following 12 methods receive one
// of the primitive types of the data model and map it to JSON by appending
// into the output string.
fn serialize_bool(self, v: bool) -> Result<()> {
self.tag = Tag::Byte(v as i8);
Ok(())
}
// JSON does not distinguish between different sizes of integers, so all
// signed integers will be serialized the same and all unsigned integers
// will be serialized the same. Other formats, especially compact binary
// formats, may need independent logic for the different sizes.
fn serialize_i8(self, v: i8) -> Result<()> {
self.tag = Tag::Byte(v);
Ok(())
}
fn serialize_i16(self, v: i16) -> Result<()> {
self.tag = Tag::Short(v);
Ok(())
}
fn serialize_i32(self, v: i32) -> Result<()> {
self.tag = Tag::Int(v);
Ok(())
}
fn serialize_i64(self, v: i64) -> Result<()> {
self.tag = Tag::Long(v);
Ok(())
}
fn serialize_u8(self, v: u8) -> Result<()> {
self.serialize_i8(v as i8)
}
fn serialize_u16(self, v: u16) -> Result<()> {
self.serialize_i16(v as i16)
}
fn serialize_u32(self, v: u32) -> Result<()> {
self.serialize_i32(v as i32)
}
fn serialize_u64(self, v: u64) -> Result<()> {
self.serialize_i64(v as i64)
}
fn serialize_f32(self, v: f32) -> Result<()> {
self.tag = Tag::Float(v);
Ok(())
}
fn serialize_f64(self, v: f64) -> Result<()> {
self.tag = Tag::Double(v);
Ok(())
}
fn serialize_char(self, v: char) -> Result<()> {
self.serialize_str(&v.to_string())
}
fn serialize_str(self, v: &str) -> Result<()> {
self.tag = Tag::String(v.into());
Ok(())
}
fn serialize_bytes(self, v: &[u8]) -> Result<()> {
self.tag = Tag::ByteArr(v.into());
Ok(())
}
// There isn't really a `None` in NBT. There is `Tag::End`, which could be
// searched and removed if this was in a struct or map, which would essentially
// skip this value if it's `None`. However, I don't care enough, so I'm just
// going to produce an error.
fn serialize_none(self) -> Result<()> {
Err(Error::CannotSerializeNone)
}
fn serialize_some<T>(self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
fn serialize_unit(self) -> Result<()> {
Err(Error::CannotSerializeNone)
}
// Unit struct means a named value containing no data. Again, since there is
// no data, map this to JSON as `null`. There is no need to serialize the
// name in most formats.
fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
self.serialize_unit()
}
// As is done here, serializers are encouraged to treat newtype structs as
// insignificant wrappers around the data they contain.
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
// Now we get to the serialization of compound types.
//
// The start of the sequence, each value, and the end are three separate
// method calls. This one is responsible only for serializing the start,
// which in JSON is `[`.
//
// The length of the sequence may or may not be known ahead of time. This
// doesn't make a difference in JSON because the length is not represented
// explicitly in the serialized form. Some serializers may only be able to
// support sequences for which the length is known up front.
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
Ok(SeqSerializer {
ser: self,
items: vec![],
})
}
// Tuples look just like sequences in JSON. Some formats may be able to
// represent tuples more efficiently by omitting the length, since tuple
// means that the corresponding `Deserialize implementation will know the
// length without needing to look at the serialized data.
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
self.serialize_seq(Some(len))
}
// Tuple structs look just like sequences in JSON.
fn serialize_tuple_struct(
self,
_name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct> {
self.serialize_seq(Some(len))
}
// Maps are represented in JSON as `{ K: V, K: V, ... }`.
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
Ok(MapSerializer {
ser: self,
key: None,
items: HashMap::new(),
})
}
// Structs look just like maps in JSON. In particular, JSON requires that we
// serialize the field names of the struct. Other formats may be able to
// omit the field names when serializing structs because the corresponding
// Deserialize implementation is required to know what the keys are without
// looking at the serialized data.
fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
self.serialize_map(Some(len))
}
// We don't support enums (they don't really make sense)
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
) -> Result<()> {
Err(Error::Enum)
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<()>
where
T: ?Sized + Serialize,
{
Err(Error::Enum)
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant> {
Err(Error::Enum)
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant> {
Err(Error::Enum)
}
}
// The following 7 impls deal with the serialization of compound types like
// sequences and maps. Serialization of such types is begun by a Serializer
// method and followed by zero or more calls to serialize individual elements of
// the compound type and one call to end the compound type.
//
// This impl is SerializeSeq so these methods are called after `serialize_seq`
// is called on the Serializer.
impl<'a> ser::SerializeSeq for SeqSerializer<'a> {
type Ok = ();
type Error = Error;
// Serialize a single element of the sequence.
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
value.serialize(&mut *self.ser)?;
let tag = std::mem::replace(&mut self.ser.tag, Tag::End);
if let Some(first) = self.items.first() {
let expected_ty = first.ty();
let actual_ty = tag.ty();
if expected_ty != actual_ty {
return Err(Error::ListType(first.clone(), tag));
} }
} }
NBT { self.items.push(tag);
tag, Ok(())
name: name.into(),
}
} }
/// Creates an empty nbt tag. fn end(self) -> Result<()> {
pub fn empty(name: &str) -> Self { self.ser.tag = Tag::List(self.items);
NBT { Ok(())
tag: Tag::End,
name: name.into(),
}
}
/// Appends the given element to the list. This will panic if self is not a
/// list, or if tag does not match the type of the existing elements.
pub fn list_add(&mut self, tag: Tag) {
if let Tag::List(inner) = &mut self.tag {
if let Some(v) = inner.get(0) {
if tag.ty() != v.ty() {
panic!(
"cannot add different types to list. current: {:?}, new: {:?}",
inner, tag
);
} else {
inner.push(tag);
}
} else {
// No elements yet, so we add this no matter what type it is.
inner.push(tag);
}
} else {
panic!("called list_add on non-list type: {:?}", self);
}
}
/// Appends the given element to the compound. This will panic if self is not
/// a compound tag.
pub fn compound_add(&mut self, name: String, value: Tag) {
if let Tag::Compound(inner) = &mut self.tag {
inner.insert(name, value);
} else {
panic!("called compound_add on non-compound type: {:?}", self);
}
}
/// If this is a compound tag, this returns the inner data of the tag.
/// Otherwise, this panics.
pub fn compound(&self) -> &HashMap<String, Tag> {
if let Tag::Compound(inner) = &self.tag {
&inner
} else {
panic!("called compound on non-compound type: {:?}", self);
}
} }
} }
impl Tag { // Same thing but for tuples.
/// A simpler way to construct compound tags inline. impl<'a> ser::SerializeTuple for SeqSerializer<'a> {
pub fn compound(value: &[(&str, Tag)]) -> Self { type Ok = ();
let mut inner = HashMap::new(); type Error = Error;
for (name, tag) in value {
inner.insert(name.to_string(), tag.clone()); fn serialize_element<T>(&mut self, value: &T) -> Result<()>
} where
Self::Compound(inner) T: ?Sized + Serialize,
{
<Self as ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> Result<()> {
<Self as ser::SerializeSeq>::end(self)
}
}
// Same thing but for tuple structs.
impl<'a> ser::SerializeTupleStruct for SeqSerializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
<Self as ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> Result<()> {
<Self as ser::SerializeSeq>::end(self)
}
}
// Tuple variants are a little different. Refer back to the
// `serialize_tuple_variant` method above:
//
// self.output += "{";
// variant.serialize(&mut *self)?;
// self.output += ":[";
//
// So the `end` method in this impl is responsible for closing both the `]` and
// the `}`.
impl<'a> ser::SerializeTupleVariant for SeqSerializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
<Self as ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> Result<()> {
<Self as ser::SerializeSeq>::end(self)
}
}
// Some `Serialize` types are not able to hold a key and value in memory at the
// same time so `SerializeMap` implementations are required to support
// `serialize_key` and `serialize_value` individually.
//
// There is a third optional method on the `SerializeMap` trait. The
// `serialize_entry` method allows serializers to optimize for the case where
// key and value are both available simultaneously. In JSON it doesn't make a
// difference so the default behavior for `serialize_entry` is fine.
impl<'a> ser::SerializeMap for MapSerializer<'a> {
type Ok = ();
type Error = Error;
// The Serde data model allows map keys to be any serializable type. JSON
// only allows string keys so the implementation below will produce invalid
// JSON if the key serializes as something other than a string.
//
// A real JSON serializer would need to validate that map keys are strings.
// This can be done by using a different Serializer to serialize the key
// (instead of `&mut **self`) and having that other serializer only
// implement `serialize_str` and return an error on any other data type.
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
key.serialize(&mut *self.ser)?;
let tag = std::mem::replace(&mut self.ser.tag, Tag::End);
self.key = match tag {
Tag::String(key) => Some(key),
other => return Err(Error::MapKey(other)),
};
Ok(())
}
// It doesn't make a difference whether the colon is printed at the end of
// `serialize_key` or at the beginning of `serialize_value`. In this case
// the code is a bit simpler having it here.
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
value.serialize(&mut *self.ser)?;
let tag = std::mem::replace(&mut self.ser.tag, Tag::End);
self.items.insert(self.key.take().unwrap(), tag);
Ok(())
}
fn end(self) -> Result<()> {
self.ser.tag = self.items.into();
Ok(())
}
}
// Structs are like maps in which the keys are constrained to be compile-time
// constant strings.
impl<'a> ser::SerializeStruct for MapSerializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
value.serialize(&mut *self.ser)?;
let tag = std::mem::replace(&mut self.ser.tag, Tag::End);
self.items.insert(key.into(), tag);
Ok(())
}
fn end(self) -> Result<()> {
self.ser.tag = self.items.into();
Ok(())
}
}
// Similar to `SerializeTupleVariant`, here the `end` method is responsible for
// closing both of the curly braces opened by `serialize_struct_variant`.
impl<'a> ser::SerializeStructVariant for MapSerializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
value.serialize(&mut *self.ser)?;
let tag = std::mem::replace(&mut self.ser.tag, Tag::End);
self.items.insert(key.into(), tag);
Ok(())
}
fn end(self) -> Result<()> {
self.ser.tag = self.items.into();
Ok(())
} }
} }

View File

@@ -0,0 +1,283 @@
use std::{collections::HashMap, fmt, io, ops::Index, string::FromUtf8Error};
#[derive(Debug)]
pub enum ParseError {
InvalidType(u8),
InvalidString(FromUtf8Error),
IO(io::Error),
}
#[derive(Debug, Clone, PartialEq)]
pub struct WrongTag(Tag);
impl fmt::Display for WrongTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "wrong tag: {:?}", self.0)
}
}
impl std::error::Error for WrongTag {}
/// This is an nbt tag. It has a name, and any amount of data. This can be used
/// to store item data, entity data, level data, and more.
#[derive(Debug, Clone, PartialEq)]
pub struct NBT {
pub tag: Tag,
pub name: String,
}
impl Default for NBT {
fn default() -> Self {
NBT::new("", Tag::new_compound(&[]))
}
}
/// This is a single tag. It does not contain a name, but has the actual data
/// for any of the nbt tags.
#[derive(Debug, Clone, PartialEq)]
pub enum Tag {
End,
Byte(i8),
Short(i16),
Int(i32),
Long(i64),
Float(f32),
Double(f64),
ByteArr(Vec<u8>),
String(String),
List(Vec<Tag>), // All elements must be the same type, and un-named.
Compound(Compound), // Types can be any kind, and are named. Order is not defined.
IntArray(Vec<i32>),
LongArray(Vec<i64>),
}
/// An NBT Compound tag. This is essentially a map, with some extra helper
/// functions.
#[derive(Debug, Clone, PartialEq)]
pub struct Compound {
pub inner: HashMap<String, Tag>,
}
impl Compound {
pub fn new() -> Self {
Compound {
inner: HashMap::new(),
}
}
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Tag>) {
self.inner.insert(key.into(), value.into());
}
pub fn get_or_create_compound(&mut self, key: impl Into<String>) -> &mut Compound {
self.inner
.entry(key.into())
.or_insert_with(|| Tag::Compound(Compound::new()))
.compound_mut()
.unwrap()
}
pub fn contains_key(&self, key: impl AsRef<str>) -> bool {
self.inner.contains_key(key.as_ref())
}
pub fn iter(&self) -> std::collections::hash_map::Iter<String, Tag> {
self.inner.iter()
}
pub fn iter_mut(&mut self) -> std::collections::hash_map::IterMut<String, Tag> {
self.inner.iter_mut()
}
}
impl IntoIterator for Compound {
type Item = (String, Tag);
type IntoIter = std::collections::hash_map::IntoIter<String, Tag>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a> IntoIterator for &'a Compound {
type Item = (&'a String, &'a Tag);
type IntoIter = std::collections::hash_map::Iter<'a, String, Tag>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl<'a> IntoIterator for &'a mut Compound {
type Item = (&'a String, &'a mut Tag);
type IntoIter = std::collections::hash_map::IterMut<'a, String, Tag>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter_mut()
}
}
impl From<HashMap<String, Tag>> for Compound {
fn from(v: HashMap<String, Tag>) -> Self {
Compound { inner: v }
}
}
impl Index<&str> for Compound {
type Output = Tag;
fn index(&self, index: &str) -> &Tag {
&self.inner[index]
}
}
impl From<bool> for Tag {
fn from(v: bool) -> Self {
Tag::Byte(v as i8)
}
}
impl From<&str> for Tag {
fn from(s: &str) -> Self {
Tag::String(s.into())
}
}
impl From<String> for Tag {
fn from(s: String) -> Self {
Tag::String(s)
}
}
impl From<HashMap<String, Tag>> for Tag {
fn from(v: HashMap<String, Tag>) -> Self {
Tag::Compound(Compound::from(v))
}
}
impl<T> From<Vec<T>> for Tag
where
Tag: From<T>,
{
fn from(list: Vec<T>) -> Self {
Tag::List(list.into_iter().map(|it| it.into()).collect())
}
}
impl NBT {
/// Creates a new nbt tag. The tag value can be anything.
///
/// # Panics
/// This will panic if the tag is a list, and the values within that list
/// contain multiple types. This is a limitation with the nbt data format:
/// lists can only contain one type of data.
pub fn new(name: &str, tag: Tag) -> Self {
if let Tag::List(inner) = &tag {
if let Some(v) = inner.get(0) {
let ty = v.ty();
for v in inner {
if v.ty() != ty {
panic!("the given list contains multiple types: {inner:?}");
}
}
}
}
NBT {
tag,
name: name.into(),
}
}
/// Creates an empty nbt tag.
pub const fn empty() -> Self {
NBT {
tag: Tag::End,
name: String::new(),
}
}
/// Appends the given element to the list. This will panic if self is not a
/// list, or if tag does not match the type of the existing elements.
pub fn list_add(&mut self, tag: Tag) {
if let Tag::List(inner) = &mut self.tag {
if let Some(v) = inner.get(0) {
if tag.ty() != v.ty() {
panic!("cannot add different types to list. current: {inner:?}, new: {tag:?}");
} else {
inner.push(tag);
}
} else {
// No elements yet, so we add this no matter what type it is.
inner.push(tag);
}
} else {
panic!("called list_add on non-list type: {self:?}");
}
}
/// Appends the given element to the compound. This will panic if self is not
/// a compound tag.
pub fn compound_add(&mut self, name: String, value: Tag) {
if let Tag::Compound(inner) = &mut self.tag {
inner.insert(name, value);
} else {
panic!("called compound_add on non-compound type: {self:?}");
}
}
/// If this is a compound tag, this returns the inner data of the tag.
/// Otherwise, this panics.
pub fn compound(&self) -> Option<&Compound> {
if let Tag::Compound(inner) = &self.tag {
Some(inner)
} else {
None
}
}
/// If this is a compound tag, this returns the inner data of the tag.
/// Otherwise, this panics.
pub fn compound_mut(&mut self) -> Option<&mut Compound> {
if let Tag::Compound(inner) = &mut self.tag {
Some(inner)
} else {
None
}
}
pub fn tag(&self) -> &Tag {
&self.tag
}
pub fn into_tag(self) -> Tag {
self.tag
}
}
macro_rules! getter {
( $(: $conv:tt)? $name:ident -> $variant:ident ( $ty:ty ) ) => {
pub fn $name(&self) -> Result<$ty, WrongTag> {
match self {
Self::$variant(v) => Ok($($conv)? v),
_ => Err(WrongTag(self.clone())),
}
}
};
}
impl Tag {
/// A simpler way to construct compound tags inline.
pub fn new_compound(value: &[(&str, Tag)]) -> Self {
let mut inner = HashMap::new();
for (name, tag) in value {
inner.insert(name.to_string(), tag.clone());
}
inner.into()
}
getter!(:*byte -> Byte(i8));
getter!(:*short -> Short(i16));
getter!(:*int -> Int(i32));
getter!(:*long -> Long(i64));
getter!(:*float -> Float(f32));
getter!(:*double -> Double(f64));
getter!(string -> String(&str));
getter!(byte_arr -> ByteArr(&[u8]));
getter!(list -> List(&Vec<Tag>));
getter!(compound -> Compound(&Compound));
getter!(long_arr -> LongArray(&Vec<i64>));
pub fn compound_mut(&mut self) -> Result<&mut Compound, WrongTag> {
match self {
Self::Compound(v) => Ok(v),
_ => Err(WrongTag(self.clone())),
}
}
}

View File

@@ -3,12 +3,18 @@ use crate::protocol::bytebuf::buffer::ByteBuffer;
use super::{Tag, NBT}; use super::{Tag, NBT};
impl NBT { impl NBT {
pub fn serialize(&self) -> Vec<u8> { pub fn serialize_buf(&self, out: &mut ByteBuffer) {
let mut out = ByteBuffer::new();
out.write_u8(self.tag.ty()); out.write_u8(self.tag.ty());
if matches!(self.tag, Tag::End) {
return;
}
out.write_u16(self.name.len() as u16); out.write_u16(self.name.len() as u16);
out.write_bytes(self.name.as_bytes()); out.write_bytes(self.name.as_bytes());
out.write_bytes(&self.tag.serialize()); self.tag.serialize(out);
}
pub fn serialize(&self) -> Vec<u8> {
let mut out = ByteBuffer::new();
self.serialize_buf(&mut out);
out.into_vec() out.into_vec()
} }
} }
@@ -33,8 +39,8 @@ impl Tag {
} }
} }
fn serialize(&self) -> Vec<u8> { /// Serializes the data of the tag. Does not add type byte.
let mut out = ByteBuffer::new(); fn serialize(&self, out: &mut ByteBuffer) {
match self { match self {
Self::End => (), Self::End => (),
Self::Byte(v) => out.write_i8(*v), Self::Byte(v) => out.write_i8(*v),
@@ -55,11 +61,11 @@ impl Tag {
out.write_u8(v.get(0).unwrap_or(&Self::End).ty()); out.write_u8(v.get(0).unwrap_or(&Self::End).ty());
out.write_i32(v.len() as i32); out.write_i32(v.len() as i32);
for tag in v { for tag in v {
out.write_bytes(&tag.serialize()); tag.serialize(out);
} }
} }
Self::Compound(v) => { Self::Compound(v) => {
for (name, tag) in v { for (name, tag) in &v.inner {
// Each element in the HashMap is essentially a NBT, but we store it in a // Each element in the HashMap is essentially a NBT, but we store it in a
// separated form, so we have a manual implementation of serialize() here. // separated form, so we have a manual implementation of serialize() here.
out.write_u8(tag.ty()); out.write_u8(tag.ty());
@@ -69,7 +75,7 @@ impl Tag {
} }
out.write_u16(name.len() as u16); out.write_u16(name.len() as u16);
out.write_bytes(name.as_bytes()); out.write_bytes(name.as_bytes());
out.write_bytes(&tag.serialize()); tag.serialize(out);
} }
out.write_u8(Self::End.ty()); out.write_u8(Self::End.ty());
} }
@@ -86,6 +92,5 @@ impl Tag {
} }
} }
} }
out.into_vec()
} }
} }

View File

@@ -0,0 +1,73 @@
use super::CodecItem;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct Biome {
category: String,
depth: f32,
downfall: f32,
effects: BiomeEffects,
precipitation: String,
scale: f32,
temperature: f32,
has_precipitation: bool,
}
#[derive(Debug, Clone, Serialize)]
struct BiomeEffects {
sky_color: i32,
fog_color: i32,
water_fog_color: i32,
water_color: i32,
#[serde(skip_serializing_if = "Option::is_none")]
foliage_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
grass_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
mood_sound: Option<MoodSound>, // 1.18.2+
}
#[derive(Debug, Clone, Serialize)]
struct MoodSound {
block_search_extent: i32,
offset: f64,
sound: String,
tick_delay: i32,
}
pub(super) fn all() -> Vec<CodecItem<Biome>> {
let biome = Biome {
precipitation: "rain".into(),
depth: 1.0,
temperature: 1.0,
scale: 1.0,
downfall: 1.0,
category: "none".into(),
has_precipitation: true,
effects: BiomeEffects {
sky_color: 0x78a7ff,
fog_color: 0xc0d8ff,
water_fog_color: 0x050533,
water_color: 0x3f76e4,
foliage_color: None,
grass_color: None,
mood_sound: Some(MoodSound {
block_search_extent: 8,
offset: 2.0,
sound: "minecraft:ambient.cave".into(),
tick_delay: 6000,
}),
// sky_color: 0xff00ff,
// water_color: 0xff00ff,
// fog_color: 0xff00ff,
// water_fog_color: 0xff00ff,
// grass_color: 0xff00ff,
// foliage_color: 0x00ffe5,
// grass_color: 0xff5900,
},
};
vec![CodecItem {
name: "minecraft:plains".into(),
id: 0,
element: biome,
}]
}

View File

@@ -0,0 +1,30 @@
use super::CodecItem;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct ChatType {
chat: ChatParams,
narration: ChatParams,
}
#[derive(Debug, Clone, Serialize)]
struct ChatParams {
parameters: Vec<String>,
translation_key: String,
}
pub(super) fn all() -> Vec<CodecItem<ChatType>> {
vec![CodecItem {
name: "minecraft:chat".into(),
id: 0,
element: ChatType {
chat: ChatParams {
parameters: vec!["sender".into(), "content".into()],
translation_key: "chat.type.text".into(),
},
narration: ChatParams {
parameters: vec!["sender".into(), "content".into()],
translation_key: "chat.type.text.narrate".into(),
},
},
}]
}

View File

@@ -0,0 +1,58 @@
use super::CodecItem;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct DamageType {
exhaustion: f32,
message_id: String,
scaling: String,
#[serde(skip_serializing_if = "Option::is_none")]
effects: Option<String>,
}
const NAMES: &[&str] = &[
"in_fire",
"lightning_bolt",
"on_fire",
"lava",
"hot_floor",
"in_wall",
"cramming",
"drown",
"starve",
"cactus",
"fall",
"fly_into_wall",
"out_of_world",
"generic",
"magic",
"wither",
"dragon_breath",
"dry_out",
"sweet_berry_bush",
"freeze",
"stalagmite",
// 1.20+
"outside_border",
"generic_kill",
];
pub(super) fn all() -> Vec<CodecItem<DamageType>> {
let mut items: Vec<_> = NAMES
.iter()
.map(|name| CodecItem {
name: (*name).into(),
id: 0,
element: DamageType {
exhaustion: 0.1,
message_id: "inFire".into(),
scaling: "when_caused_by_living_non_player".into(),
effects: None,
},
})
.collect();
items[1].element.effects = Some("burning".into());
items
}

View File

@@ -0,0 +1,49 @@
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct Dimension {
ambient_light: f32,
bed_works: bool,
coordinate_scale: f32,
effects: String,
has_ceiling: bool,
has_raids: bool,
has_skylight: bool,
height: i32, // 1.17+
infiniburn: String,
logical_height: i32,
min_y: i32, // 1.17+
natural: bool,
piglin_safe: bool,
fixed_time: i64,
respawn_anchor_works: bool,
ultrawarm: bool,
// 1.19+
monster_spawn_light_level: i32,
monster_spawn_block_light_limit: i32,
}
pub fn overworld(world_min_y: i32, world_height: u32) -> Dimension {
Dimension {
piglin_safe: false,
natural: true,
ambient_light: 0.0,
fixed_time: 6000,
infiniburn: "#minecraft:infiniburn_overworld".into(),
respawn_anchor_works: false,
has_skylight: true,
bed_works: true,
effects: "minecraft:overworld".into(),
has_raids: false,
logical_height: 128,
coordinate_scale: 1.0,
ultrawarm: false,
has_ceiling: false,
min_y: world_min_y,
height: (world_height as i32 + 15) / 16 * 16,
monster_spawn_light_level: 7,
monster_spawn_block_light_limit: 7,
}
}

View File

@@ -1 +1,75 @@
use serde::Serialize;
use super::{bytebuf::buffer::ByteBuffer, nbt};
mod biomes;
mod chat_type;
mod damage_type;
mod dimensions;
#[derive(Debug, Clone, Serialize)]
struct LoginInfo {
#[serde(rename = "minecraft:dimension_type")]
dimensions: Codec<dimensions::Dimension>,
#[serde(rename = "minecraft:worldgen/biome")]
biomes: Codec<biomes::Biome>,
#[serde(rename = "minecraft:chat_type")]
chat: Codec<chat_type::ChatType>,
#[serde(rename = "minecraft:damage_type")]
damage: Codec<damage_type::DamageType>,
}
#[derive(Debug, Clone, Serialize)]
struct Codec<T> {
#[serde(rename = "type")]
ty: String,
value: Vec<CodecItem<T>>,
}
#[derive(Debug, Clone, Serialize)]
struct CodecItem<T> {
name: String,
id: i32,
element: T,
}
pub fn write_single_dimension<T>(out: &mut ByteBuffer, world_min_y: i32, world_height: u32)
where
std::io::Cursor<T>: std::io::Write,
{
let dimension = dimensions::overworld(world_min_y, world_height);
out.write_bytes(&nbt::to_nbt("", &dimension).unwrap().serialize());
}
pub fn write_codec(out: &mut ByteBuffer, world_min_y: i32, world_height: u32) {
let dimension = dimensions::overworld(world_min_y, world_height);
let info = LoginInfo {
dimensions: Codec {
ty: "minecraft:dimension_type".into(),
value: vec![CodecItem {
name: "minecraft:overworld".into(),
id: 0,
element: dimension,
}],
},
biomes: Codec {
ty: "minecraft:worldgen/biome".into(),
value: biomes::all(),
},
chat: Codec {
ty: "minecraft:chat_type".into(),
value: chat_type::all(),
},
damage: Codec {
ty: "minecraft:damage_type".into(),
value: damage_type::all(),
},
};
// Dimension codec
out.write_bytes(&nbt::to_nbt("", &info).unwrap().serialize());
// Current dimension type (key in dimension codec)
out.write_string("minecraft:overworld");
// Current world
out.write_string("minecraft:overworld");
}

View File

@@ -15,7 +15,13 @@ use crate::{
player::{GameMode, Player}, player::{GameMode, Player},
Entity, EntityId, Entity, EntityId,
}, },
protocol::{client::play::CLogin, Players, Sample, StatusResponse, VarInt, Version}, protocol::{
client::{
config::{CKnownPacks, CRegistryData, Entry, KnownPack},
play::CLogin,
},
Players, Sample, StatusResponse, VarInt, Version,
},
world::World, world::World,
}; };
@@ -88,6 +94,23 @@ impl Server {
entity_id: self.new_entity_id(), entity_id: self.new_entity_id(),
}, },
}; };
// known data packs
client.send_packet(CKnownPacks::new(
1,
vec![KnownPack {
namespace: "minecraft".to_string(),
id: "core".to_string(),
version: "1.21".to_string(),
}],
));
client.send_packet(CRegistryData::new(
"0".into(),
1,
vec![Entry {
entry_id: "minecraft:dimension_type".into(),
has_data: true,
}],
));
client.send_packet(CLogin::new( client.send_packet(CLogin::new(
player.entity_id(), player.entity_id(),