Merge branch 'master' into master
This commit is contained in:
commit
72d95cd416
538
Cargo.lock
generated
538
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
22
Cargo.toml
@ -1,6 +1,17 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [ "pumpkin-config", "pumpkin-core", "pumpkin-entity", "pumpkin-inventory", "pumpkin-macros/", "pumpkin-plugin", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-world", "pumpkin/"]
|
members = [
|
||||||
|
"pumpkin-config",
|
||||||
|
"pumpkin-core",
|
||||||
|
"pumpkin-entity",
|
||||||
|
"pumpkin-inventory",
|
||||||
|
"pumpkin-macros/",
|
||||||
|
"pumpkin-plugin",
|
||||||
|
"pumpkin-protocol/",
|
||||||
|
"pumpkin-registry/",
|
||||||
|
"pumpkin-world",
|
||||||
|
"pumpkin/",
|
||||||
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -13,7 +24,14 @@ codegen-units = 1
|
|||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
tokio = { version = "1.39.2", features = ["net", "macros", "rt-multi-thread", "fs", "io-util", "sync"] }
|
tokio = { version = "1.40", features = [
|
||||||
|
"net",
|
||||||
|
"macros",
|
||||||
|
"rt-multi-thread",
|
||||||
|
"fs",
|
||||||
|
"io-util",
|
||||||
|
"sync",
|
||||||
|
] }
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
uuid = { version = "1.10.0", features = ["serde", "v3"] }
|
uuid = { version = "1.10.0", features = ["serde", "v3"] }
|
||||||
derive_more = { version = "1.0.0", features = ["full"] }
|
derive_more = { version = "1.0.0", features = ["full"] }
|
||||||
|
|||||||
@ -5,8 +5,8 @@ edition.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pumpkin-core = { path = "../pumpkin-core" }
|
pumpkin-core = { path = "../pumpkin-core" }
|
||||||
|
serde.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
|
||||||
serde = "1.0"
|
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
|
|
||||||
log.workspace = true
|
|
||||||
|
|||||||
@ -5,8 +5,8 @@ edition.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
|
||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
|
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||||
colored = "2"
|
colored = "2"
|
||||||
md5 = "0.7.0"
|
md5 = "0.7.0"
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@ use super::Text;
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "action", content = "contents", rename_all = "snake_case")]
|
#[serde(tag = "action", content = "contents", rename_all = "snake_case")]
|
||||||
#[allow(clippy::enum_variant_names)]
|
|
||||||
pub enum HoverEvent<'a> {
|
pub enum HoverEvent<'a> {
|
||||||
/// Displays a tooltip with the given text.
|
/// Displays a tooltip with the given text.
|
||||||
ShowText(Text<'a>),
|
ShowText(Text<'a>),
|
||||||
|
|||||||
@ -5,6 +5,3 @@ edition.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pumpkin-core = { path = "../pumpkin-core"}
|
pumpkin-core = { path = "../pumpkin-core"}
|
||||||
|
|
||||||
num-traits = "0.2"
|
|
||||||
num-derive = "0.4"
|
|
||||||
@ -2,8 +2,6 @@ use crate::container_click::MouseClick;
|
|||||||
use crate::{handle_item_change, Container, InventoryError, WindowType};
|
use crate::{handle_item_change, Container, InventoryError, WindowType};
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PlayerInventory {
|
pub struct PlayerInventory {
|
||||||
// Main Inventory + Hotbar
|
// Main Inventory + Hotbar
|
||||||
crafting: [Option<ItemStack>; 4],
|
crafting: [Option<ItemStack>; 4],
|
||||||
|
|||||||
@ -7,6 +7,6 @@ edition.workspace = true
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0.86"
|
proc-macro2 = "1.0"
|
||||||
quote = "1.0.37"
|
quote = "1.0"
|
||||||
syn = "2.0.76"
|
syn = "2.0"
|
||||||
|
|||||||
@ -4,6 +4,6 @@ version.workspace = true
|
|||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
extism = "1.5.0"
|
|
||||||
log.workspace = true
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
extism = "1.6.0"
|
||||||
|
|||||||
@ -13,12 +13,10 @@ bytes = "1.7"
|
|||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
# to parse strings to json responses
|
|
||||||
serde_json = "1.0"
|
|
||||||
|
|
||||||
flate2 = "1.0.33"
|
flate2 = "1.0.33"
|
||||||
|
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0"
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
@ -26,6 +24,6 @@ num-derive = "0.4"
|
|||||||
# encryption
|
# encryption
|
||||||
aes = "0.8.4"
|
aes = "0.8.4"
|
||||||
cfb8 = "0.8.1"
|
cfb8 = "0.8.1"
|
||||||
take_mut = "0.2.2"
|
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||||
|
|||||||
@ -45,77 +45,77 @@ impl<'a, 'de> de::Deserializer<'de> for Deserializer<'a> {
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_bool(self.inner.get_bool())
|
visitor.visit_bool(self.inner.get_bool()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i8(self.inner.get_i8())
|
visitor.visit_i8(self.inner.get_i8()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i16(self.inner.get_i16())
|
visitor.visit_i16(self.inner.get_i16()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i32(self.inner.get_i32())
|
visitor.visit_i32(self.inner.get_i32()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_i64(self.inner.get_i64())
|
visitor.visit_i64(self.inner.get_i64()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u8(self.inner.get_u8())
|
visitor.visit_u8(self.inner.get_u8()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u16(self.inner.get_u16())
|
visitor.visit_u16(self.inner.get_u16()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u32(self.inner.get_u32())
|
visitor.visit_u32(self.inner.get_u32()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_u64(self.inner.get_u64())
|
visitor.visit_u64(self.inner.get_u64()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_f32(self.inner.get_f32())
|
visitor.visit_f32(self.inner.get_f32()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_f64(self.inner.get_f64())
|
visitor.visit_f64(self.inner.get_f64()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||||
@ -129,7 +129,7 @@ impl<'a, 'de> de::Deserializer<'de> for Deserializer<'a> {
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
let string = self.inner.get_string().map_err(DeserializerError::Stdio)?;
|
let string = self.inner.get_string()?;
|
||||||
visitor.visit_str(&string)
|
visitor.visit_str(&string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ impl<'a, 'de> de::Deserializer<'de> for Deserializer<'a> {
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
let string = self.inner.get_string().map_err(DeserializerError::Stdio)?;
|
let string = self.inner.get_string()?;
|
||||||
visitor.visit_str(&string)
|
visitor.visit_str(&string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use crate::{BitSet, FixedBitSet, VarInt, VarLongType};
|
use crate::{BitSet, FixedBitSet, VarInt, VarLongType};
|
||||||
use bytes::{Buf, BufMut, BytesMut};
|
use bytes::{Buf, BufMut, BytesMut};
|
||||||
use core::str;
|
use core::str;
|
||||||
use std::io::{self, Error, ErrorKind};
|
|
||||||
|
|
||||||
mod deserializer;
|
mod deserializer;
|
||||||
pub use deserializer::DeserializerError;
|
pub use deserializer::DeserializerError;
|
||||||
@ -26,12 +25,12 @@ impl ByteBuffer {
|
|||||||
Self { buffer }
|
Self { buffer }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_var_int(&mut self) -> VarInt {
|
pub fn get_var_int(&mut self) -> Result<VarInt, DeserializerError> {
|
||||||
let mut value: i32 = 0;
|
let mut value: i32 = 0;
|
||||||
let mut position: i32 = 0;
|
let mut position: i32 = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let read = self.buffer.get_u8();
|
let read = self.get_u8()?;
|
||||||
|
|
||||||
value |= ((read & SEGMENT_BITS) as i32) << position;
|
value |= ((read & SEGMENT_BITS) as i32) << position;
|
||||||
|
|
||||||
@ -42,19 +41,19 @@ impl ByteBuffer {
|
|||||||
position += 7;
|
position += 7;
|
||||||
|
|
||||||
if position >= 32 {
|
if position >= 32 {
|
||||||
panic!("VarInt is too big");
|
return Err(DeserializerError::Message("VarInt is too big".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VarInt(value)
|
Ok(VarInt(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_var_long(&mut self) -> VarLongType {
|
pub fn get_var_long(&mut self) -> Result<VarLongType, DeserializerError> {
|
||||||
let mut value: i64 = 0;
|
let mut value: i64 = 0;
|
||||||
let mut position: i64 = 0;
|
let mut position: i64 = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let read = self.buffer.get_u8();
|
let read = self.get_u8()?;
|
||||||
|
|
||||||
value |= ((read & SEGMENT_BITS) as i64) << position;
|
value |= ((read & SEGMENT_BITS) as i64) << position;
|
||||||
|
|
||||||
@ -65,49 +64,48 @@ impl ByteBuffer {
|
|||||||
position += 7;
|
position += 7;
|
||||||
|
|
||||||
if position >= 64 {
|
if position >= 64 {
|
||||||
panic!("VarInt is too big");
|
return Err(DeserializerError::Message("VarLong is too big".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_string(&mut self) -> Result<String, io::Error> {
|
pub fn get_string(&mut self) -> Result<String, DeserializerError> {
|
||||||
self.get_string_len(32767)
|
self.get_string_len(32767)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_string_len(&mut self, max_size: usize) -> Result<String, io::Error> {
|
pub fn get_string_len(&mut self, max_size: usize) -> Result<String, DeserializerError> {
|
||||||
let size = self.get_var_int().0;
|
let size = self.get_var_int()?.0;
|
||||||
if size as usize > max_size {
|
if size as usize > max_size {
|
||||||
return Err(Error::new(
|
return Err(DeserializerError::Message(
|
||||||
ErrorKind::InvalidData,
|
"String length is bigger than max size".to_string(),
|
||||||
"String length is bigger than max size",
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let data = self.buffer.copy_to_bytes(size as usize);
|
|
||||||
|
let data = self.copy_to_bytes(size as usize)?;
|
||||||
if data.len() > max_size {
|
if data.len() > max_size {
|
||||||
return Err(Error::new(
|
return Err(DeserializerError::Message(
|
||||||
ErrorKind::InvalidData,
|
"String is bigger than max size".to_string(),
|
||||||
"String is bigger than max size",
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
match str::from_utf8(&data) {
|
match str::from_utf8(&data) {
|
||||||
Ok(string_result) => Ok(string_result.to_string()),
|
Ok(string_result) => Ok(string_result.to_string()),
|
||||||
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
|
Err(e) => Err(DeserializerError::Message(e.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bool(&mut self) -> bool {
|
pub fn get_bool(&mut self) -> Result<bool, DeserializerError> {
|
||||||
self.buffer.get_u8() != 0
|
Ok(self.get_u8()? != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_uuid(&mut self) -> uuid::Uuid {
|
pub fn get_uuid(&mut self) -> Result<uuid::Uuid, DeserializerError> {
|
||||||
let mut bytes = [0u8; 16];
|
let mut bytes = [0u8; 16];
|
||||||
self.buffer.copy_to_slice(&mut bytes);
|
self.copy_to_slice(&mut bytes)?;
|
||||||
uuid::Uuid::from_slice(&bytes).expect("Failed to parse UUID")
|
Ok(uuid::Uuid::from_slice(&bytes).expect("Failed to parse UUID"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fixed_bitset(&mut self, bits: usize) -> FixedBitSet {
|
pub fn get_fixed_bitset(&mut self, bits: usize) -> Result<FixedBitSet, DeserializerError> {
|
||||||
self.copy_to_bytes(bits.div_ceil(8))
|
self.copy_to_bytes(bits.div_ceil(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,11 +159,14 @@ impl ByteBuffer {
|
|||||||
|
|
||||||
/// Reads a boolean. If true, the closure is called, and the returned value is
|
/// Reads a boolean. If true, the closure is called, and the returned value is
|
||||||
/// wrapped in Some. Otherwise, this returns None.
|
/// wrapped in Some. Otherwise, this returns None.
|
||||||
pub fn get_option<T>(&mut self, val: impl FnOnce(&mut Self) -> T) -> Option<T> {
|
pub fn get_option<T>(
|
||||||
if self.get_bool() {
|
&mut self,
|
||||||
Some(val(self))
|
val: impl FnOnce(&mut Self) -> Result<T, DeserializerError>,
|
||||||
|
) -> Result<Option<T>, DeserializerError> {
|
||||||
|
if self.get_bool()? {
|
||||||
|
Ok(Some(val(self)?))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Writes `true` if the option is Some, or `false` if None. If the option is
|
/// Writes `true` if the option is Some, or `false` if None. If the option is
|
||||||
@ -177,13 +178,16 @@ impl ByteBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_list<T>(&mut self, val: impl Fn(&mut Self) -> T) -> Vec<T> {
|
pub fn get_list<T>(
|
||||||
let len = self.get_var_int().0 as usize;
|
&mut self,
|
||||||
|
val: impl Fn(&mut Self) -> Result<T, DeserializerError>,
|
||||||
|
) -> Result<Vec<T>, DeserializerError> {
|
||||||
|
let len = self.get_var_int()?.0 as usize;
|
||||||
let mut list = Vec::with_capacity(len);
|
let mut list = Vec::with_capacity(len);
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
list.push(val(self));
|
list.push(val(self)?);
|
||||||
}
|
}
|
||||||
list
|
Ok(list)
|
||||||
}
|
}
|
||||||
/// Writes a list to the buffer.
|
/// Writes a list to the buffer.
|
||||||
pub fn put_list<T>(&mut self, list: &[T], write: impl Fn(&mut Self, &T)) {
|
pub fn put_list<T>(&mut self, list: &[T], write: impl Fn(&mut Self, &T)) {
|
||||||
@ -211,50 +215,109 @@ impl ByteBuffer {
|
|||||||
pub fn buf(&mut self) -> &mut BytesMut {
|
pub fn buf(&mut self) -> &mut BytesMut {
|
||||||
&mut self.buffer
|
&mut self.buffer
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// trait
|
// Trait equivalents
|
||||||
impl ByteBuffer {
|
pub fn get_u8(&mut self) -> Result<u8, DeserializerError> {
|
||||||
pub fn get_u8(&mut self) -> u8 {
|
if self.buffer.has_remaining() {
|
||||||
self.buffer.get_u8()
|
Ok(self.buffer.get_u8())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"No bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i8(&mut self) -> i8 {
|
pub fn get_i8(&mut self) -> Result<i8, DeserializerError> {
|
||||||
self.buffer.get_i8()
|
if self.buffer.has_remaining() {
|
||||||
|
Ok(self.buffer.get_i8())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"No bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_u16(&mut self) -> u16 {
|
pub fn get_u16(&mut self) -> Result<u16, DeserializerError> {
|
||||||
self.buffer.get_u16()
|
if self.buffer.remaining() >= 2 {
|
||||||
|
Ok(self.buffer.get_u16())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 2 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i16(&mut self) -> i16 {
|
pub fn get_i16(&mut self) -> Result<i16, DeserializerError> {
|
||||||
self.buffer.get_i16()
|
if self.buffer.remaining() >= 2 {
|
||||||
|
Ok(self.buffer.get_i16())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 2 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_u32(&mut self) -> u32 {
|
pub fn get_u32(&mut self) -> Result<u32, DeserializerError> {
|
||||||
self.buffer.get_u32()
|
if self.buffer.remaining() >= 4 {
|
||||||
|
Ok(self.buffer.get_u32())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 4 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i32(&mut self) -> i32 {
|
pub fn get_i32(&mut self) -> Result<i32, DeserializerError> {
|
||||||
self.buffer.get_i32()
|
if self.buffer.remaining() >= 4 {
|
||||||
|
Ok(self.buffer.get_i32())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 4 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_u64(&mut self) -> u64 {
|
pub fn get_u64(&mut self) -> Result<u64, DeserializerError> {
|
||||||
self.buffer.get_u64()
|
if self.buffer.remaining() >= 8 {
|
||||||
|
Ok(self.buffer.get_u64())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 8 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i64(&mut self) -> i64 {
|
pub fn get_i64(&mut self) -> Result<i64, DeserializerError> {
|
||||||
self.buffer.get_i64()
|
if self.buffer.remaining() >= 8 {
|
||||||
|
Ok(self.buffer.get_i64())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 8 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_f32(&mut self) -> f32 {
|
pub fn get_f32(&mut self) -> Result<f32, DeserializerError> {
|
||||||
self.buffer.get_f32()
|
if self.buffer.remaining() >= 4 {
|
||||||
|
Ok(self.buffer.get_f32())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 4 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_f64(&mut self) -> f64 {
|
pub fn get_f64(&mut self) -> Result<f64, DeserializerError> {
|
||||||
self.buffer.get_f64()
|
if self.buffer.remaining() >= 8 {
|
||||||
|
Ok(self.buffer.get_f64())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Less than 8 bytes left to consume".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: SerializerError?
|
||||||
pub fn put_u8(&mut self, n: u8) {
|
pub fn put_u8(&mut self, n: u8) {
|
||||||
self.buffer.put_u8(n)
|
self.buffer.put_u8(n)
|
||||||
}
|
}
|
||||||
@ -295,12 +358,25 @@ impl ByteBuffer {
|
|||||||
self.buffer.put_f64(n)
|
self.buffer.put_f64(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_to_bytes(&mut self, len: usize) -> bytes::Bytes {
|
pub fn copy_to_bytes(&mut self, len: usize) -> Result<bytes::Bytes, DeserializerError> {
|
||||||
self.buffer.copy_to_bytes(len)
|
if self.buffer.len() >= len {
|
||||||
|
Ok(self.buffer.copy_to_bytes(len))
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Unable to copy bytes".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_to_slice(&mut self, dst: &mut [u8]) {
|
pub fn copy_to_slice(&mut self, dst: &mut [u8]) -> Result<(), DeserializerError> {
|
||||||
self.buffer.copy_to_slice(dst)
|
if self.buffer.remaining() >= dst.len() {
|
||||||
|
self.buffer.copy_to_slice(dst);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(DeserializerError::Message(
|
||||||
|
"Unable to copy slice".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_slice(&mut self, src: &[u8]) {
|
pub fn put_slice(&mut self, src: &[u8]) {
|
||||||
|
|||||||
@ -83,12 +83,13 @@ where
|
|||||||
P: Packet + Serialize,
|
P: Packet + Serialize,
|
||||||
{
|
{
|
||||||
fn write(&self, bytebuf: &mut ByteBuffer) {
|
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||||
take_mut::take(bytebuf, |bytebuf| {
|
let mut serializer = serializer::Serializer::new(ByteBuffer::empty());
|
||||||
let mut serializer = serializer::Serializer::new(bytebuf);
|
self.serialize(&mut serializer)
|
||||||
self.serialize(&mut serializer)
|
.expect("Could not serialize packet");
|
||||||
.expect("Could not serialize packet");
|
// We write the packet in an empty bytebuffer and then put it into our current one.
|
||||||
serializer.into()
|
// In the future we may do packet batching thats the reason i don't let every packet create a new bytebuffer and use
|
||||||
});
|
// an existing instead
|
||||||
|
bytebuf.put(serializer.output.buf());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use thiserror::Error;
|
|||||||
use super::ByteBuffer;
|
use super::ByteBuffer;
|
||||||
|
|
||||||
pub struct Serializer {
|
pub struct Serializer {
|
||||||
output: ByteBuffer,
|
pub output: ByteBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serializer {
|
impl Serializer {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ pub struct CLogin<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CLogin<'a> {
|
impl<'a> CLogin<'a> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
entity_id: i32,
|
entity_id: i32,
|
||||||
is_hardcore: bool,
|
is_hardcore: bool,
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub struct CParticle<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CParticle<'a> {
|
impl<'a> CParticle<'a> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
long_distance: bool,
|
long_distance: bool,
|
||||||
x: f64,
|
x: f64,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub struct CPlayerChatMessage<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CPlayerChatMessage<'a> {
|
impl<'a> CPlayerChatMessage<'a> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sender: UUID,
|
sender: UUID,
|
||||||
index: VarInt,
|
index: VarInt,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub struct CSpawnEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CSpawnEntity {
|
impl CSpawnEntity {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
entity_id: VarInt,
|
entity_id: VarInt,
|
||||||
entity_uuid: UUID,
|
entity_uuid: UUID,
|
||||||
|
|||||||
@ -22,8 +22,6 @@ pub struct PacketEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PacketEncoder {
|
impl PacketEncoder {
|
||||||
// i think clippy is broken
|
|
||||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
|
||||||
pub fn append_packet<P: ClientPacket>(&mut self, packet: &P) -> Result<(), PacketError> {
|
pub fn append_packet<P: ClientPacket>(&mut self, packet: &P) -> Result<(), PacketError> {
|
||||||
let start_len = self.buf.len();
|
let start_len = self.buf.len();
|
||||||
|
|
||||||
@ -87,6 +85,7 @@ impl PacketEncoder {
|
|||||||
|
|
||||||
let mut front = &mut self.buf[start_len..];
|
let mut front = &mut self.buf[start_len..];
|
||||||
|
|
||||||
|
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||||
VarInt(packet_len as i32)
|
VarInt(packet_len as i32)
|
||||||
.encode(&mut front)
|
.encode(&mut front)
|
||||||
.map_err(|_| PacketError::EncodeLength)?;
|
.map_err(|_| PacketError::EncodeLength)?;
|
||||||
|
|||||||
@ -16,10 +16,10 @@ pub struct SHandShake {
|
|||||||
impl ServerPacket for SHandShake {
|
impl ServerPacket for SHandShake {
|
||||||
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
protocol_version: bytebuf.get_var_int(),
|
protocol_version: bytebuf.get_var_int()?,
|
||||||
server_address: bytebuf.get_string_len(255).unwrap(),
|
server_address: bytebuf.get_string_len(255)?,
|
||||||
server_port: bytebuf.get_u16(),
|
server_port: bytebuf.get_u16()?,
|
||||||
next_state: bytebuf.get_var_int().into(),
|
next_state: bytebuf.get_var_int()?.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,10 +15,10 @@ pub struct SEncryptionResponse {
|
|||||||
|
|
||||||
impl ServerPacket for SEncryptionResponse {
|
impl ServerPacket for SEncryptionResponse {
|
||||||
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
let shared_secret_length = bytebuf.get_var_int();
|
let shared_secret_length = bytebuf.get_var_int()?;
|
||||||
let shared_secret = bytebuf.copy_to_bytes(shared_secret_length.0 as usize);
|
let shared_secret = bytebuf.copy_to_bytes(shared_secret_length.0 as usize)?;
|
||||||
let verify_token_length = bytebuf.get_var_int();
|
let verify_token_length = bytebuf.get_var_int()?;
|
||||||
let verify_token = bytebuf.copy_to_bytes(shared_secret_length.0 as usize);
|
let verify_token = bytebuf.copy_to_bytes(shared_secret_length.0 as usize)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
shared_secret_length,
|
shared_secret_length,
|
||||||
shared_secret: shared_secret.to_vec(),
|
shared_secret: shared_secret.to_vec(),
|
||||||
|
|||||||
@ -14,8 +14,8 @@ pub struct SLoginStart {
|
|||||||
impl ServerPacket for SLoginStart {
|
impl ServerPacket for SLoginStart {
|
||||||
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: bytebuf.get_string_len(16).unwrap(),
|
name: bytebuf.get_string_len(16)?,
|
||||||
uuid: bytebuf.get_uuid(),
|
uuid: bytebuf.get_uuid()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,9 +16,9 @@ pub struct SLoginPluginResponse {
|
|||||||
impl ServerPacket for SLoginPluginResponse {
|
impl ServerPacket for SLoginPluginResponse {
|
||||||
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
message_id: bytebuf.get_var_int(),
|
message_id: bytebuf.get_var_int()?,
|
||||||
successful: bytebuf.get_bool(),
|
successful: bytebuf.get_bool()?,
|
||||||
data: bytebuf.get_option(|v| v.get_slice()),
|
data: bytebuf.get_option(|v| Ok(v.get_slice()))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,12 +21,12 @@ pub struct SChatMessage {
|
|||||||
impl ServerPacket for SChatMessage {
|
impl ServerPacket for SChatMessage {
|
||||||
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
message: bytebuf.get_string().unwrap(),
|
message: bytebuf.get_string()?,
|
||||||
timestamp: bytebuf.get_i64(),
|
timestamp: bytebuf.get_i64()?,
|
||||||
salt: bytebuf.get_i64(),
|
salt: bytebuf.get_i64()?,
|
||||||
signature: bytebuf.get_option(|v| v.copy_to_bytes(256)),
|
signature: bytebuf.get_option(|v| v.copy_to_bytes(256))?,
|
||||||
message_count: bytebuf.get_var_int(),
|
message_count: bytebuf.get_var_int()?,
|
||||||
acknowledged: bytebuf.get_fixed_bitset(20),
|
acknowledged: bytebuf.get_fixed_bitset(20)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,8 @@ impl ServerPacket for SInteract {
|
|||||||
fn read(
|
fn read(
|
||||||
bytebuf: &mut crate::bytebuf::ByteBuffer,
|
bytebuf: &mut crate::bytebuf::ByteBuffer,
|
||||||
) -> Result<Self, crate::bytebuf::DeserializerError> {
|
) -> Result<Self, crate::bytebuf::DeserializerError> {
|
||||||
let entity_id = bytebuf.get_var_int();
|
let entity_id = bytebuf.get_var_int()?;
|
||||||
let typ = bytebuf.get_var_int();
|
let typ = bytebuf.get_var_int()?;
|
||||||
let action = ActionType::from_i32(typ.0).ok_or(DeserializerError::Message(
|
let action = ActionType::from_i32(typ.0).ok_or(DeserializerError::Message(
|
||||||
"invalid action type".to_string(),
|
"invalid action type".to_string(),
|
||||||
))?;
|
))?;
|
||||||
@ -27,13 +27,13 @@ impl ServerPacket for SInteract {
|
|||||||
ActionType::Interact => None,
|
ActionType::Interact => None,
|
||||||
ActionType::Attack => None,
|
ActionType::Attack => None,
|
||||||
ActionType::InteractAt => {
|
ActionType::InteractAt => {
|
||||||
Some((bytebuf.get_f32(), bytebuf.get_f32(), bytebuf.get_f32()))
|
Some((bytebuf.get_f32()?, bytebuf.get_f32()?, bytebuf.get_f32()?))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let hand = match action {
|
let hand = match action {
|
||||||
ActionType::Interact => Some(bytebuf.get_var_int()),
|
ActionType::Interact => Some(bytebuf.get_var_int()?),
|
||||||
ActionType::Attack => None,
|
ActionType::Attack => None,
|
||||||
ActionType::InteractAt => Some(bytebuf.get_var_int()),
|
ActionType::InteractAt => Some(bytebuf.get_var_int()?),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -41,7 +41,7 @@ impl ServerPacket for SInteract {
|
|||||||
typ,
|
typ,
|
||||||
target_position,
|
target_position,
|
||||||
hand,
|
hand,
|
||||||
sneaking: bytebuf.get_bool(),
|
sneaking: bytebuf.get_bool()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,9 +25,9 @@ pub enum Action {
|
|||||||
impl ServerPacket for SPlayerCommand {
|
impl ServerPacket for SPlayerCommand {
|
||||||
fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entity_id: bytebuf.get_var_int(),
|
entity_id: bytebuf.get_var_int()?,
|
||||||
action: bytebuf.get_var_int(),
|
action: bytebuf.get_var_int()?,
|
||||||
jump_boost: bytebuf.get_var_int(),
|
jump_boost: bytebuf.get_var_int()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ use serde::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct Slot {
|
pub struct Slot {
|
||||||
item_count: VarInt,
|
item_count: VarInt,
|
||||||
item_id: Option<VarInt>,
|
item_id: Option<VarInt>,
|
||||||
|
|||||||
@ -9,6 +9,5 @@ pumpkin-core = { path = "../pumpkin-core"}
|
|||||||
|
|
||||||
# nbt
|
# nbt
|
||||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||||
fastsnbt = "0.2"
|
|
||||||
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
|||||||
@ -33,12 +33,12 @@ impl Registry {
|
|||||||
registry_id: "minecraft:worldgen/biome".to_string(),
|
registry_id: "minecraft:worldgen/biome".to_string(),
|
||||||
registry_entries: vec![
|
registry_entries: vec![
|
||||||
RegistryEntry {
|
RegistryEntry {
|
||||||
entry_id: "minecraft:snowy_taiga",
|
entry_id: "minecraft:plains",
|
||||||
data: fastnbt::to_bytes_with_opts(&Biome::default(), SerOpts::network_nbt())
|
data: fastnbt::to_bytes_with_opts(&Biome::default(), SerOpts::network_nbt())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
},
|
||||||
RegistryEntry {
|
RegistryEntry {
|
||||||
entry_id: "minecraft:plains",
|
entry_id: "minecraft:snowy_taiga",
|
||||||
data: fastnbt::to_bytes_with_opts(&Biome::default(), SerOpts::network_nbt())
|
data: fastnbt::to_bytes_with_opts(&Biome::default(), SerOpts::network_nbt())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,20 +6,22 @@ edition.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
pumpkin-core = { path = "../pumpkin-core"}
|
pumpkin-core = { path = "../pumpkin-core"}
|
||||||
|
|
||||||
|
|
||||||
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }
|
||||||
fastsnbt = "0.2"
|
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
rayon.workspace = true
|
rayon.workspace = true
|
||||||
derive_more.workspace = true
|
derive_more.workspace = true
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0"
|
||||||
futures = "0.3.30"
|
futures = "0.3"
|
||||||
flate2 = "1.0.33"
|
flate2 = "1.0"
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
|
||||||
|
noise = "0.9.0"
|
||||||
|
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// TODO make this work with the protocol
|
// TODO make this work with the protocol
|
||||||
|
// Send by the registry
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Biome {
|
pub enum Biome {
|
||||||
Plains,
|
Plains,
|
||||||
|
SnowyTiga,
|
||||||
// TODO list all Biomes
|
// TODO list all Biomes
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ pub struct ChunkHeightmaps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
struct ChunkSection {
|
struct ChunkSection {
|
||||||
#[serde(rename = "Y")]
|
#[serde(rename = "Y")]
|
||||||
y: i32,
|
y: i32,
|
||||||
@ -64,7 +64,7 @@ struct ChunkSection {
|
|||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
struct ChunkNbt {
|
struct ChunkNbt {
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
data_version: usize,
|
data_version: usize,
|
||||||
|
|
||||||
#[serde(rename = "sections")]
|
#[serde(rename = "sections")]
|
||||||
@ -171,7 +171,7 @@ impl ChunkBlocks {
|
|||||||
index.y.get_absolute() as usize * CHUNK_AREA + *index.z as usize * 16 + *index.x as usize
|
index.y.get_absolute() as usize * CHUNK_AREA + *index.z as usize * 16 + *index.x as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
fn calculate_heightmap(&self) -> ChunkHeightmaps {
|
fn calculate_heightmap(&self) -> ChunkHeightmaps {
|
||||||
// figure out how LongArray is formatted
|
// figure out how LongArray is formatted
|
||||||
// figure out how to find out if block is motion blocking
|
// figure out how to find out if block is motion blocking
|
||||||
|
|||||||
@ -24,7 +24,6 @@ pub fn get_protocol_id(category: &str, entry: &str) -> u32 {
|
|||||||
.expect("No Entry found")
|
.expect("No Entry found")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn get_default<'a>(category: &str) -> Option<&'a str> {
|
pub fn get_default<'a>(category: &str) -> Option<&'a str> {
|
||||||
REGISTRY
|
REGISTRY
|
||||||
.get(category)
|
.get(category)
|
||||||
|
|||||||
@ -28,12 +28,12 @@ pub struct ItemElement {
|
|||||||
components: ItemComponents,
|
components: ItemComponents,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub fn get_item_element(item_id: &str) -> &ItemComponents {
|
pub fn get_item_element(item_id: &str) -> &ItemComponents {
|
||||||
&ITEMS.get(item_id).expect("Item not found").components
|
&ITEMS.get(item_id).expect("Item not found").components
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub fn get_item_protocol_id(item_id: &str) -> u32 {
|
pub fn get_item_protocol_id(item_id: &str) -> u32 {
|
||||||
global_registry::get_protocol_id(ITEM_REGISTRY, item_id)
|
global_registry::get_protocol_id(ITEM_REGISTRY, item_id)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ pub struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SaveFile {
|
struct SaveFile {
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
root_folder: PathBuf,
|
root_folder: PathBuf,
|
||||||
region_folder: PathBuf,
|
region_folder: PathBuf,
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@ impl Level {
|
|||||||
match compression {
|
match compression {
|
||||||
Compression::Gzip => {
|
Compression::Gzip => {
|
||||||
let mut z = GzDecoder::new(&compressed_data[..]);
|
let mut z = GzDecoder::new(&compressed_data[..]);
|
||||||
let mut chunk_data = Vec::new();
|
let mut chunk_data = Vec::with_capacity(compressed_data.len());
|
||||||
match z.read_to_end(&mut chunk_data) {
|
match z.read_to_end(&mut chunk_data) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -288,7 +288,7 @@ impl Level {
|
|||||||
}
|
}
|
||||||
Compression::Zlib => {
|
Compression::Zlib => {
|
||||||
let mut z = ZlibDecoder::new(&compressed_data[..]);
|
let mut z = ZlibDecoder::new(&compressed_data[..]);
|
||||||
let mut chunk_data = Vec::new();
|
let mut chunk_data = Vec::with_capacity(compressed_data.len());
|
||||||
match z.read_to_end(&mut chunk_data) {
|
match z.read_to_end(&mut chunk_data) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use noise::Perlin;
|
||||||
use pumpkin_core::math::vector2::Vector2;
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
use static_assertions::assert_obj_safe;
|
use static_assertions::assert_obj_safe;
|
||||||
|
|
||||||
@ -12,7 +13,6 @@ pub trait GeneratorInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait WorldGenerator: Sync + Send {
|
pub trait WorldGenerator: Sync + Send {
|
||||||
#[allow(dead_code)]
|
|
||||||
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData;
|
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData;
|
||||||
}
|
}
|
||||||
assert_obj_safe! {WorldGenerator}
|
assert_obj_safe! {WorldGenerator}
|
||||||
@ -21,6 +21,17 @@ pub(crate) trait BiomeGenerator: Sync + Send {
|
|||||||
fn generate_biome(&self, at: XZBlockCoordinates) -> Biome;
|
fn generate_biome(&self, at: XZBlockCoordinates) -> Biome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
pub(crate) trait TerrainGenerator: Sync + Send {
|
pub(crate) trait TerrainGenerator: Sync + Send {
|
||||||
|
fn prepare_chunk(&self, at: &Vector2<i32>);
|
||||||
|
|
||||||
|
/// Is static
|
||||||
fn generate_block(&self, at: BlockCoordinates, biome: Biome) -> BlockId;
|
fn generate_block(&self, at: BlockCoordinates, biome: Biome) -> BlockId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) trait PerlinTerrainGenerator: Sync + Send {
|
||||||
|
fn prepare_chunk(&self, at: &Vector2<i32>, perlin: &Perlin);
|
||||||
|
|
||||||
|
/// Dependens on the perlin noise height
|
||||||
|
fn generate_block(&self, at: BlockCoordinates, chunk_height: i16, biome: Biome) -> BlockId;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,35 +1,46 @@
|
|||||||
|
use noise::{NoiseFn, Perlin};
|
||||||
use pumpkin_core::math::vector2::Vector2;
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
chunk::{ChunkBlocks, ChunkData},
|
chunk::{ChunkBlocks, ChunkData},
|
||||||
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
|
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
|
||||||
WORLD_LOWEST_Y, WORLD_MAX_Y,
|
WORLD_LOWEST_Y,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator, WorldGenerator},
|
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator, WorldGenerator},
|
||||||
Seed,
|
Seed,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GenericGenerator<B: BiomeGenerator, T: TerrainGenerator> {
|
pub struct GenericGenerator<B: BiomeGenerator, T: PerlinTerrainGenerator> {
|
||||||
biome_generator: B,
|
biome_generator: B,
|
||||||
terrain_generator: T,
|
terrain_generator: T,
|
||||||
|
// TODO: May make this optional?. But would be pain to use in most biomes then. Maybe make a new trait like
|
||||||
|
// PerlinTerrainGenerator
|
||||||
|
perlin: Perlin,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BiomeGenerator + GeneratorInit, T: TerrainGenerator + GeneratorInit> GeneratorInit
|
impl<B: BiomeGenerator + GeneratorInit, T: PerlinTerrainGenerator + GeneratorInit> GeneratorInit
|
||||||
for GenericGenerator<B, T>
|
for GenericGenerator<B, T>
|
||||||
{
|
{
|
||||||
fn new(seed: Seed) -> Self {
|
fn new(seed: Seed) -> Self {
|
||||||
Self {
|
Self {
|
||||||
biome_generator: B::new(seed),
|
biome_generator: B::new(seed),
|
||||||
terrain_generator: T::new(seed),
|
terrain_generator: T::new(seed),
|
||||||
|
perlin: Perlin::new(seed.0 as u32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator<B, T> {
|
impl<B: BiomeGenerator, T: PerlinTerrainGenerator> WorldGenerator for GenericGenerator<B, T> {
|
||||||
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData {
|
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData {
|
||||||
let mut blocks = ChunkBlocks::default();
|
let mut blocks = ChunkBlocks::default();
|
||||||
|
self.terrain_generator.prepare_chunk(&at, &self.perlin);
|
||||||
|
let noise_value = self.perlin.get([at.x as f64 / 16.0, at.z as f64 / 16.0]);
|
||||||
|
|
||||||
|
let base_height = 64.0;
|
||||||
|
let height_variation = 16.0;
|
||||||
|
let chunk_height = (noise_value * height_variation + base_height) as i32;
|
||||||
|
|
||||||
for x in 0..16u8 {
|
for x in 0..16u8 {
|
||||||
for z in 0..16u8 {
|
for z in 0..16u8 {
|
||||||
@ -42,7 +53,7 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Iterate from the highest block to the lowest, in order to minimize the heightmap updates
|
// Iterate from the highest block to the lowest, in order to minimize the heightmap updates
|
||||||
for y in (WORLD_LOWEST_Y..WORLD_MAX_Y).rev() {
|
for y in (WORLD_LOWEST_Y..chunk_height as i16).rev() {
|
||||||
let coordinates = ChunkRelativeBlockCoordinates {
|
let coordinates = ChunkRelativeBlockCoordinates {
|
||||||
x: x.into(),
|
x: x.into(),
|
||||||
y: y.into(),
|
y: y.into(),
|
||||||
@ -51,8 +62,11 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
|||||||
|
|
||||||
blocks.set_block(
|
blocks.set_block(
|
||||||
coordinates,
|
coordinates,
|
||||||
self.terrain_generator
|
self.terrain_generator.generate_block(
|
||||||
.generate_block(coordinates.with_chunk_coordinates(at), biome),
|
coordinates.with_chunk_coordinates(at),
|
||||||
|
chunk_height as i16,
|
||||||
|
biome,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,3 +78,42 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: implement static terrain generator
|
||||||
|
/*
|
||||||
|
fn generate_chunk(&mut self, at: Vector2<i32>) -> ChunkData {
|
||||||
|
let mut blocks = ChunkBlocks::default();
|
||||||
|
self.terrain_generator.prepare_chunk(&at, &self.perlin);
|
||||||
|
for x in 0..16u8 {
|
||||||
|
for z in 0..16u8 {
|
||||||
|
let biome = self.biome_generator.generate_biome(
|
||||||
|
ChunkRelativeXZBlockCoordinates {
|
||||||
|
x: x.into(),
|
||||||
|
z: z.into(),
|
||||||
|
}
|
||||||
|
.with_chunk_coordinates(at),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Iterate from the highest block to the lowest, in order to minimize the heightmap updates
|
||||||
|
for y in (WORLD_LOWEST_Y..WORLD_MAX_Y).rev() {
|
||||||
|
let coordinates = ChunkRelativeBlockCoordinates {
|
||||||
|
x: x.into(),
|
||||||
|
y: y.into(),
|
||||||
|
z: z.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
blocks.set_block(
|
||||||
|
coordinates,
|
||||||
|
self.terrain_generator
|
||||||
|
.generate_block(coordinates.with_chunk_coordinates(at), biome),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkData {
|
||||||
|
blocks,
|
||||||
|
position: at,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
|
pub mod overworld;
|
||||||
pub mod superflat;
|
pub mod superflat;
|
||||||
@ -0,0 +1 @@
|
|||||||
|
pub mod plains;
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
use noise::Perlin;
|
||||||
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
biome::Biome,
|
||||||
|
block::BlockId,
|
||||||
|
coordinates::{BlockCoordinates, XZBlockCoordinates},
|
||||||
|
world_gen::{
|
||||||
|
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator},
|
||||||
|
generic_generator::GenericGenerator,
|
||||||
|
Seed,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type PlainsGenerator = GenericGenerator<PlainsBiomeGenerator, PlainsTerrainGenerator>;
|
||||||
|
|
||||||
|
pub(crate) struct PlainsBiomeGenerator {}
|
||||||
|
|
||||||
|
impl GeneratorInit for PlainsBiomeGenerator {
|
||||||
|
fn new(_: Seed) -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BiomeGenerator for PlainsBiomeGenerator {
|
||||||
|
// TODO make generic over Biome and allow changing the Biome in the config.
|
||||||
|
fn generate_biome(&self, _: XZBlockCoordinates) -> Biome {
|
||||||
|
Biome::Plains
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct PlainsTerrainGenerator {}
|
||||||
|
|
||||||
|
impl GeneratorInit for PlainsTerrainGenerator {
|
||||||
|
fn new(_: Seed) -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerlinTerrainGenerator for PlainsTerrainGenerator {
|
||||||
|
fn prepare_chunk(&self, _at: &Vector2<i32>, _perlin: &Perlin) {}
|
||||||
|
// TODO allow specifying which blocks should be at which height in the config.
|
||||||
|
fn generate_block(&self, at: BlockCoordinates, chunk_height: i16, _: Biome) -> BlockId {
|
||||||
|
let begin_stone_height = chunk_height - 5;
|
||||||
|
let begin_dirt_height = chunk_height - 1;
|
||||||
|
|
||||||
|
let y = *at.y;
|
||||||
|
if y == -64 {
|
||||||
|
BlockId::from_id(79) // BEDROCK
|
||||||
|
} else if y >= -63 && y <= begin_stone_height {
|
||||||
|
return BlockId::from_id(1); // STONE
|
||||||
|
} else if y >= begin_stone_height && y < begin_dirt_height {
|
||||||
|
return BlockId::from_id(10); // DIRT;
|
||||||
|
} else if y == chunk_height - 1 {
|
||||||
|
return BlockId::from_id(9); // GRASS BLOCK
|
||||||
|
} else {
|
||||||
|
BlockId::AIR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
pub mod biome;
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
biome::Biome,
|
biome::Biome,
|
||||||
block::BlockId,
|
block::BlockId,
|
||||||
@ -9,7 +11,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub type SuperflatGenerator = GenericGenerator<SuperflatBiomeGenerator, SuperflatTerrainGenerator>;
|
pub type SuperflatGenerator = GenericGenerator<SuperflatBiomeGenerator, SuperflatTerrainGenerator>;
|
||||||
|
|
||||||
pub(crate) struct SuperflatBiomeGenerator {}
|
pub(crate) struct SuperflatBiomeGenerator {}
|
||||||
@ -36,6 +38,7 @@ impl GeneratorInit for SuperflatTerrainGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TerrainGenerator for SuperflatTerrainGenerator {
|
impl TerrainGenerator for SuperflatTerrainGenerator {
|
||||||
|
fn prepare_chunk(&self, _at: &Vector2<i32>) {}
|
||||||
// TODO allow specifying which blocks should be at which height in the config.
|
// TODO allow specifying which blocks should be at which height in the config.
|
||||||
fn generate_block(&self, at: BlockCoordinates, _: Biome) -> BlockId {
|
fn generate_block(&self, at: BlockCoordinates, _: Biome) -> BlockId {
|
||||||
match *at.y {
|
match *at.y {
|
||||||
@ -1,16 +1,15 @@
|
|||||||
mod generator;
|
mod generator;
|
||||||
mod generic_generator;
|
mod generic_generator;
|
||||||
mod implementations;
|
mod implementation;
|
||||||
mod seed;
|
mod seed;
|
||||||
|
|
||||||
pub use generator::WorldGenerator;
|
pub use generator::WorldGenerator;
|
||||||
|
use implementation::overworld::biome::plains::PlainsGenerator;
|
||||||
pub use seed::Seed;
|
pub use seed::Seed;
|
||||||
|
|
||||||
use generator::GeneratorInit;
|
use generator::GeneratorInit;
|
||||||
use implementations::superflat::SuperflatGenerator;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn get_world_gen(seed: Seed) -> Box<dyn WorldGenerator> {
|
pub fn get_world_gen(seed: Seed) -> Box<dyn WorldGenerator> {
|
||||||
// TODO decide which WorldGenerator to pick based on config.
|
// TODO decide which WorldGenerator to pick based on config.
|
||||||
Box::new(SuperflatGenerator::new(seed))
|
Box::new(PlainsGenerator::new(seed))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Seed(pub i64);
|
pub struct Seed(pub i64);
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ pumpkin-registry = { path = "../pumpkin-registry"}
|
|||||||
# config
|
# config
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
toml = "0.8.19"
|
|
||||||
|
|
||||||
bytes = "1.7"
|
bytes = "1.7"
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ rand = "0.8.5"
|
|||||||
|
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
num-bigint = "0.4.6"
|
num-bigint = "0.4"
|
||||||
|
|
||||||
ctrlc = "3.4"
|
ctrlc = "3.4"
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ digest = "=0.11.0-pre.9"
|
|||||||
hmac = "0.12.1"
|
hmac = "0.12.1"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
|
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0"
|
||||||
|
|
||||||
# icon loading
|
# icon loading
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
@ -59,7 +58,6 @@ log.workspace = true
|
|||||||
|
|
||||||
# networking
|
# networking
|
||||||
mio = { version = "1.0.2", features = ["os-poll", "net"]}
|
mio = { version = "1.0.2", features = ["os-poll", "net"]}
|
||||||
crossbeam-channel = "0.5.13"
|
|
||||||
|
|
||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|||||||
@ -13,8 +13,8 @@ use uuid::Uuid;
|
|||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[allow(non_snake_case)]
|
#[expect(non_snake_case)]
|
||||||
#[allow(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub struct ProfileTextures {
|
pub struct ProfileTextures {
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
profileId: Uuid,
|
profileId: Uuid,
|
||||||
@ -24,8 +24,7 @@ pub struct ProfileTextures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[allow(non_snake_case)]
|
#[expect(dead_code)]
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
url: String,
|
url: String,
|
||||||
metadata: Option<HashMap<String, String>>,
|
metadata: Option<HashMap<String, String>>,
|
||||||
|
|||||||
@ -72,7 +72,7 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
|||||||
)));
|
)));
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
#[allow(clippy::let_underscore_future)]
|
#[expect(clippy::let_underscore_future)]
|
||||||
let _ = target.set_gamemode(gamemode);
|
let _ = target.set_gamemode(gamemode);
|
||||||
target.send_system_message(TextComponent::text(&format!(
|
target.send_system_message(TextComponent::text(&format!(
|
||||||
"Game mode was set to {:?}",
|
"Game mode was set to {:?}",
|
||||||
@ -97,7 +97,7 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
|||||||
)));
|
)));
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
#[allow(clippy::let_underscore_future)]
|
#[expect(clippy::let_underscore_future)]
|
||||||
let _ = target.set_gamemode(gamemode);
|
let _ = target.set_gamemode(gamemode);
|
||||||
target.send_system_message(TextComponent::text(&format!(
|
target.send_system_message(TextComponent::text(&format!(
|
||||||
"Game mode was set to {:?}",
|
"Game mode was set to {:?}",
|
||||||
|
|||||||
@ -23,8 +23,9 @@ pub(crate) enum NodeType<'a> {
|
|||||||
run: &'a (dyn Fn(&mut CommandSender, &mut Server, &ConsumedArgs) -> Result<(), InvalidTreeError>
|
run: &'a (dyn Fn(&mut CommandSender, &mut Server, &ConsumedArgs) -> Result<(), InvalidTreeError>
|
||||||
+ Sync),
|
+ Sync),
|
||||||
},
|
},
|
||||||
#[allow(dead_code)] // todo: remove (so far no commands requiring this are implemented)
|
Literal {
|
||||||
Literal { string: &'a str },
|
string: &'a str,
|
||||||
|
},
|
||||||
Argument {
|
Argument {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
consumer: ArgumentConsumer<'a>,
|
consumer: ArgumentConsumer<'a>,
|
||||||
|
|||||||
@ -131,7 +131,7 @@ impl<'a> NonLeafNodeBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Matches a sting literal.
|
/// Matches a sting literal.
|
||||||
#[allow(dead_code)] // todo: remove (so far no commands requiring this are implemented)
|
#[expect(dead_code)] // todo: remove (so far no commands requiring this are implemented)
|
||||||
pub fn literal(string: &str) -> NonLeafNodeBuilder {
|
pub fn literal(string: &str) -> NonLeafNodeBuilder {
|
||||||
NonLeafNodeBuilder {
|
NonLeafNodeBuilder {
|
||||||
node_type: NodeType::Literal { string },
|
node_type: NodeType::Literal { string },
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#![allow(clippy::await_holding_refcell_ref)]
|
#![expect(clippy::await_holding_lock)]
|
||||||
#![allow(clippy::await_holding_lock)]
|
|
||||||
|
|
||||||
#[cfg(target_os = "wasi")]
|
#[cfg(target_os = "wasi")]
|
||||||
compile_error!("Compiling for WASI targets is not supported!");
|
compile_error!("Compiling for WASI targets is not supported!");
|
||||||
|
|||||||
@ -52,7 +52,7 @@ pub fn receive_plugin_response(
|
|||||||
buf.put_slice(data_without_signature);
|
buf.put_slice(data_without_signature);
|
||||||
|
|
||||||
// check velocity version
|
// check velocity version
|
||||||
let version = buf.get_var_int();
|
let version = buf.get_var_int().unwrap();
|
||||||
let version = version.0;
|
let version = version.0;
|
||||||
if version > MAX_SUPPORTED_FORWARDING_VERSION {
|
if version > MAX_SUPPORTED_FORWARDING_VERSION {
|
||||||
client.kick(&format!(
|
client.kick(&format!(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user