Some refactors
This commit is contained in:
parent
fd667901cd
commit
3dae300f81
@ -3,6 +3,13 @@ name = "pumpkin-protocol"
|
|||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["packets", "query"]
|
||||||
|
packets = ["serverbound", "clientbound"]
|
||||||
|
serverbound = []
|
||||||
|
clientbound = []
|
||||||
|
query = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pumpkin-nbt = { path = "../pumpkin-nbt" }
|
pumpkin-nbt = { path = "../pumpkin-nbt" }
|
||||||
pumpkin-config = { path = "../pumpkin-config" }
|
pumpkin-config = { path = "../pumpkin-config" }
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::slot::Slot;
|
use crate::codec::slot::Slot;
|
||||||
use crate::VarInt;
|
use crate::VarInt;
|
||||||
|
|
||||||
use pumpkin_macros::client_packet;
|
use pumpkin_macros::client_packet;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::slot::Slot;
|
use crate::codec::slot::Slot;
|
||||||
use crate::VarInt;
|
use crate::VarInt;
|
||||||
|
|
||||||
use pumpkin_macros::client_packet;
|
use pumpkin_macros::client_packet;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use thiserror::Error;
|
|||||||
|
|
||||||
pub mod bit_set;
|
pub mod bit_set;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
|
pub mod slot;
|
||||||
pub mod var_int;
|
pub mod var_int;
|
||||||
pub mod var_long;
|
pub mod var_long;
|
||||||
|
|
||||||
|
|||||||
@ -7,13 +7,15 @@ use pumpkin_core::text::{style::Style, TextComponent};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod bytebuf;
|
pub mod bytebuf;
|
||||||
|
#[cfg(feature = "clientbound")]
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
pub mod packet_decoder;
|
pub mod packet_decoder;
|
||||||
pub mod packet_encoder;
|
pub mod packet_encoder;
|
||||||
|
#[cfg(feature = "query")]
|
||||||
pub mod query;
|
pub mod query;
|
||||||
|
#[cfg(feature = "serverbound")]
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod slot;
|
|
||||||
|
|
||||||
/// To current Minecraft protocol
|
/// To current Minecraft protocol
|
||||||
/// Don't forget to change this when porting
|
/// Don't forget to change this when porting
|
||||||
|
|||||||
@ -16,8 +16,8 @@ type Cipher = cfb8::Decryptor<aes::Aes128>;
|
|||||||
pub struct PacketDecoder {
|
pub struct PacketDecoder {
|
||||||
buf: BytesMut,
|
buf: BytesMut,
|
||||||
decompress_buf: BytesMut,
|
decompress_buf: BytesMut,
|
||||||
compression: bool,
|
|
||||||
cipher: Option<Cipher>,
|
cipher: Option<Cipher>,
|
||||||
|
compression: bool,
|
||||||
decompressor: Decompressor,
|
decompressor: Decompressor,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ impl Default for PacketDecoder {
|
|||||||
Self {
|
Self {
|
||||||
buf: BytesMut::new(),
|
buf: BytesMut::new(),
|
||||||
decompress_buf: BytesMut::new(),
|
decompress_buf: BytesMut::new(),
|
||||||
compression: false,
|
|
||||||
cipher: None,
|
cipher: None,
|
||||||
|
compression: false,
|
||||||
decompressor: Decompressor::new(),
|
decompressor: Decompressor::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,8 @@ type Cipher = cfb8::Encryptor<aes::Aes128>;
|
|||||||
pub struct PacketEncoder {
|
pub struct PacketEncoder {
|
||||||
buf: BytesMut,
|
buf: BytesMut,
|
||||||
compress_buf: Vec<u8>,
|
compress_buf: Vec<u8>,
|
||||||
compression_threshold: Option<u32>,
|
|
||||||
cipher: Option<Cipher>,
|
cipher: Option<Cipher>,
|
||||||
|
compression_threshold: Option<u32>,
|
||||||
compressor: Compressor, // Reuse the compressor for all packets
|
compressor: Compressor, // Reuse the compressor for all packets
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ impl Default for PacketEncoder {
|
|||||||
Self {
|
Self {
|
||||||
buf: BytesMut::with_capacity(1024),
|
buf: BytesMut::with_capacity(1024),
|
||||||
compress_buf: Vec::with_capacity(1024),
|
compress_buf: Vec::with_capacity(1024),
|
||||||
compression_threshold: None,
|
|
||||||
cipher: None,
|
cipher: None,
|
||||||
|
compression_threshold: None,
|
||||||
compressor: Compressor::new(CompressionLvl::fastest()), // init compressor with fastest compression level
|
compressor: Compressor::new(CompressionLvl::fastest()), // init compressor with fastest compression level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use crate::{
|
|||||||
#[server_packet("config:cookie_response")]
|
#[server_packet("config:cookie_response")]
|
||||||
/// Response to a Cookie Request (configuration) from the server.
|
/// Response to a Cookie Request (configuration) from the server.
|
||||||
/// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size.
|
/// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size.
|
||||||
pub struct SCookieResponse {
|
pub struct SConfigCookieResponse {
|
||||||
pub key: Identifier,
|
pub key: Identifier,
|
||||||
pub has_payload: bool,
|
pub has_payload: bool,
|
||||||
pub payload_length: Option<VarInt>,
|
pub payload_length: Option<VarInt>,
|
||||||
@ -20,7 +20,7 @@ pub struct SCookieResponse {
|
|||||||
|
|
||||||
const MAX_PAYLOAD_SIZE: i32 = 5120;
|
const MAX_PAYLOAD_SIZE: i32 = 5120;
|
||||||
|
|
||||||
impl ServerPacket for SCookieResponse {
|
impl ServerPacket for SConfigCookieResponse {
|
||||||
fn read(bytebuf: &mut impl Buf) -> Result<Self, ReadingError> {
|
fn read(bytebuf: &mut impl Buf) -> Result<Self, ReadingError> {
|
||||||
let key = bytebuf.try_get_identifer()?;
|
let key = bytebuf.try_get_identifer()?;
|
||||||
let has_payload = bytebuf.try_get_bool()?;
|
let has_payload = bytebuf.try_get_bool()?;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use serde::de;
|
|||||||
#[server_packet("login:cookie_response")]
|
#[server_packet("login:cookie_response")]
|
||||||
/// Response to a Cookie Request (login) from the server.
|
/// Response to a Cookie Request (login) from the server.
|
||||||
/// The Notchian server only accepts responses of up to 5 kiB in size.
|
/// The Notchian server only accepts responses of up to 5 kiB in size.
|
||||||
pub struct SCookieResponse {
|
pub struct SLoginCookieResponse {
|
||||||
pub key: Identifier,
|
pub key: Identifier,
|
||||||
pub has_payload: bool,
|
pub has_payload: bool,
|
||||||
pub payload_length: Option<VarInt>,
|
pub payload_length: Option<VarInt>,
|
||||||
@ -19,7 +19,7 @@ pub struct SCookieResponse {
|
|||||||
|
|
||||||
const MAX_PAYLOAD_SIZE: i32 = 5120;
|
const MAX_PAYLOAD_SIZE: i32 = 5120;
|
||||||
|
|
||||||
impl ServerPacket for SCookieResponse {
|
impl ServerPacket for SLoginCookieResponse {
|
||||||
fn read(bytebuf: &mut impl Buf) -> Result<Self, ReadingError> {
|
fn read(bytebuf: &mut impl Buf) -> Result<Self, ReadingError> {
|
||||||
let key = bytebuf.try_get_identifer()?;
|
let key = bytebuf.try_get_identifer()?;
|
||||||
let has_payload = bytebuf.try_get_bool()?;
|
let has_payload = bytebuf.try_get_bool()?;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::slot::Slot;
|
use crate::codec::slot::Slot;
|
||||||
use crate::VarInt;
|
use crate::VarInt;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use pumpkin_macros::server_packet;
|
use pumpkin_macros::server_packet;
|
||||||
|
|
||||||
use crate::slot::Slot;
|
use crate::codec::slot::Slot;
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Debug)]
|
#[derive(serde::Deserialize, Debug)]
|
||||||
#[server_packet("play:set_creative_mode_slot")]
|
#[server_packet("play:set_creative_mode_slot")]
|
||||||
|
|||||||
@ -661,7 +661,7 @@ mod test {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::BlockState,
|
block::BlockState,
|
||||||
world_gen::{
|
generation::{
|
||||||
chunk_noise::{
|
chunk_noise::{
|
||||||
BlockStateSampler, ChunkNoiseDensityFunctions, ChunkNoiseGenerator,
|
BlockStateSampler, ChunkNoiseDensityFunctions, ChunkNoiseGenerator,
|
||||||
ChunkNoiseState, LAVA_BLOCK, WATER_BLOCK,
|
ChunkNoiseState, LAVA_BLOCK, WATER_BLOCK,
|
||||||
@ -6,11 +6,11 @@ use pumpkin_macros::block_state;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::BlockState,
|
block::BlockState,
|
||||||
match_ref_implementations,
|
generation::{
|
||||||
world_gen::{
|
|
||||||
noise::{density::basic::WrapperType, lerp3},
|
noise::{density::basic::WrapperType, lerp3},
|
||||||
section_coords,
|
section_coords,
|
||||||
},
|
},
|
||||||
|
match_ref_implementations,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -1379,7 +1379,7 @@ impl ChunkNoiseGenerator {
|
|||||||
mod test {
|
mod test {
|
||||||
use pumpkin_core::math::vector2::Vector2;
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
use crate::world_gen::{
|
use crate::generation::{
|
||||||
aquifer_sampler::{FluidLevel, FluidLevelSampler},
|
aquifer_sampler::{FluidLevel, FluidLevelSampler},
|
||||||
generation_shapes::GenerationShape,
|
generation_shapes::GenerationShape,
|
||||||
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
|
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
|
||||||
@ -6,7 +6,7 @@ use crate::biome::Biome;
|
|||||||
use crate::block::block_state::BlockState;
|
use crate::block::block_state::BlockState;
|
||||||
use crate::chunk::{ChunkBlocks, ChunkData};
|
use crate::chunk::{ChunkBlocks, ChunkData};
|
||||||
use crate::coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates};
|
use crate::coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates};
|
||||||
use crate::world_gen::Seed;
|
use crate::generation::Seed;
|
||||||
|
|
||||||
pub trait GeneratorInit {
|
pub trait GeneratorInit {
|
||||||
fn new(seed: Seed) -> Self;
|
fn new(seed: Seed) -> Self;
|
||||||
@ -7,7 +7,7 @@ use crate::{
|
|||||||
biome::Biome,
|
biome::Biome,
|
||||||
chunk::ChunkBlocks,
|
chunk::ChunkBlocks,
|
||||||
coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates},
|
coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates},
|
||||||
world_gen::{
|
generation::{
|
||||||
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator},
|
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator},
|
||||||
generic_generator::GenericGenerator,
|
generic_generator::GenericGenerator,
|
||||||
Seed,
|
Seed,
|
||||||
@ -4,7 +4,7 @@ use crate::{
|
|||||||
biome::Biome,
|
biome::Biome,
|
||||||
block::block_state::BlockState,
|
block::block_state::BlockState,
|
||||||
coordinates::XZBlockCoordinates,
|
coordinates::XZBlockCoordinates,
|
||||||
world_gen::{
|
generation::{
|
||||||
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator},
|
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator},
|
||||||
generic_generator::GenericGenerator,
|
generic_generator::GenericGenerator,
|
||||||
Seed,
|
Seed,
|
||||||
@ -14,7 +14,7 @@ use crate::{
|
|||||||
coordinates::{
|
coordinates::{
|
||||||
ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates, XZBlockCoordinates,
|
ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates, XZBlockCoordinates,
|
||||||
},
|
},
|
||||||
world_gen::{
|
generation::{
|
||||||
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator},
|
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator},
|
||||||
proto_chunk::ProtoChunk,
|
proto_chunk::ProtoChunk,
|
||||||
Seed, WorldGenerator,
|
Seed, WorldGenerator,
|
||||||
@ -151,8 +151,7 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
read_data_from_file,
|
generation::noise::{
|
||||||
world_gen::noise::{
|
|
||||||
config::NoiseConfig,
|
config::NoiseConfig,
|
||||||
density::{
|
density::{
|
||||||
built_in_density_function::{
|
built_in_density_function::{
|
||||||
@ -165,6 +164,7 @@ mod test {
|
|||||||
},
|
},
|
||||||
router::OVERWORLD_NOISE_ROUTER,
|
router::OVERWORLD_NOISE_ROUTER,
|
||||||
},
|
},
|
||||||
|
read_data_from_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::LegacyChunkNoiseVisitor;
|
use super::LegacyChunkNoiseVisitor;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{hash::Hash, marker::PhantomData};
|
use std::{hash::Hash, marker::PhantomData};
|
||||||
|
|
||||||
use crate::{match_ref_implementations, world_gen::noise::clamped_map};
|
use crate::{generation::noise::clamped_map, match_ref_implementations};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
component_functions::{
|
component_functions::{
|
||||||
@ -419,10 +419,10 @@ mod test {
|
|||||||
use std::{fs, path::Path};
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
read_data_from_file,
|
generation::noise::density::{
|
||||||
world_gen::noise::density::{
|
|
||||||
component_functions::ImmutableComponentFunctionImpl, NoisePos, UnblendedNoisePos,
|
component_functions::ImmutableComponentFunctionImpl, NoisePos, UnblendedNoisePos,
|
||||||
},
|
},
|
||||||
|
read_data_from_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::YClampedFunction;
|
use super::YClampedFunction;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::world_gen::blender::BlenderImpl;
|
use crate::generation::blender::BlenderImpl;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
component_functions::{
|
component_functions::{
|
||||||
@ -953,7 +953,7 @@ mod test {
|
|||||||
|
|
||||||
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl};
|
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl};
|
||||||
|
|
||||||
use crate::world_gen::noise::{
|
use crate::generation::noise::{
|
||||||
built_in_noise_params,
|
built_in_noise_params,
|
||||||
density::{
|
density::{
|
||||||
noise::{InternalNoise, NoiseFunction},
|
noise::{InternalNoise, NoiseFunction},
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomImpl};
|
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomImpl};
|
||||||
|
|
||||||
use crate::world_gen::noise::simplex::SimplexNoiseSampler;
|
use crate::generation::noise::simplex::SimplexNoiseSampler;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
component_functions::{
|
component_functions::{
|
||||||
@ -10,7 +10,7 @@ use component_functions::{
|
|||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use noise::{InternalNoise, NoiseFunction};
|
use noise::{InternalNoise, NoiseFunction};
|
||||||
|
|
||||||
use crate::world_gen::{blender::Blender, chunk_noise::ChunkNoisePos};
|
use crate::generation::{blender::Blender, chunk_noise::ChunkNoisePos};
|
||||||
|
|
||||||
use super::perlin::DoublePerlinNoiseParameters;
|
use super::perlin::DoublePerlinNoiseParameters;
|
||||||
|
|
||||||
@ -76,8 +76,8 @@ pub trait NoisePosImpl {
|
|||||||
pub mod built_in_density_function {
|
pub mod built_in_density_function {
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
use crate::world_gen::noise::built_in_noise_params::{self};
|
use crate::generation::noise::built_in_noise_params::{self};
|
||||||
use crate::world_gen::positions::{MAX_COLUMN_HEIGHT, MIN_HEIGHT};
|
use crate::generation::positions::{MAX_COLUMN_HEIGHT, MIN_HEIGHT};
|
||||||
|
|
||||||
use pumpkin_core::math::floor_div;
|
use pumpkin_core::math::floor_div;
|
||||||
|
|
||||||
@ -879,7 +879,7 @@ mod test {
|
|||||||
legacy_rand::LegacyRand, RandomDeriver, RandomDeriverImpl, RandomImpl,
|
legacy_rand::LegacyRand, RandomDeriver, RandomDeriverImpl, RandomImpl,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::world_gen::noise::{
|
use crate::generation::noise::{
|
||||||
built_in_noise_params,
|
built_in_noise_params,
|
||||||
density::{built_in_density_function::*, NoisePos, UnblendedNoisePos},
|
density::{built_in_density_function::*, NoisePos, UnblendedNoisePos},
|
||||||
perlin::DoublePerlinNoiseSampler,
|
perlin::DoublePerlinNoiseSampler,
|
||||||
@ -3,11 +3,11 @@ use std::{marker::PhantomData, sync::Arc};
|
|||||||
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl};
|
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
match_ref_implementations,
|
generation::noise::{
|
||||||
world_gen::noise::{
|
|
||||||
clamped_lerp,
|
clamped_lerp,
|
||||||
perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler, OctavePerlinNoiseSampler},
|
perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler, OctavePerlinNoiseSampler},
|
||||||
},
|
},
|
||||||
|
match_ref_implementations,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -2,7 +2,7 @@ use std::{marker::PhantomData, sync::Arc};
|
|||||||
|
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
|
||||||
use crate::world_gen::noise::lerp;
|
use crate::generation::noise::lerp;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
component_functions::{
|
component_functions::{
|
||||||
@ -744,7 +744,7 @@ mod test {
|
|||||||
|
|
||||||
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl};
|
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl};
|
||||||
|
|
||||||
use crate::world_gen::noise::density::{
|
use crate::generation::noise::density::{
|
||||||
built_in_density_function::CONTINENTS_OVERWORLD,
|
built_in_density_function::CONTINENTS_OVERWORLD,
|
||||||
component_functions::{ComponentReference, NoEnvironment, SharedComponentReference},
|
component_functions::{ComponentReference, NoEnvironment, SharedComponentReference},
|
||||||
test::{FakeEnvironment, OwnedConverter, TestConverter},
|
test::{FakeEnvironment, OwnedConverter, TestConverter},
|
||||||
@ -1,7 +1,7 @@
|
|||||||
// From da java
|
// From da java
|
||||||
|
|
||||||
use crate::world_gen::noise::density::peaks_valleys_noise;
|
use crate::generation::noise::density::peaks_valleys_noise;
|
||||||
use crate::world_gen::noise::lerp;
|
use crate::generation::noise::lerp;
|
||||||
|
|
||||||
use super::component_functions::SharedComponentReference;
|
use super::component_functions::SharedComponentReference;
|
||||||
use super::spline::{FloatAmplifier, ImmutableSpline, ImmutableSplineRef, SplineBuilder};
|
use super::spline::{FloatAmplifier, ImmutableSpline, ImmutableSplineRef, SplineBuilder};
|
||||||
@ -523,7 +523,7 @@ pub fn create_jaggedness_spline(
|
|||||||
mod test {
|
mod test {
|
||||||
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl};
|
use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl};
|
||||||
|
|
||||||
use crate::world_gen::noise::density::{
|
use crate::generation::noise::density::{
|
||||||
built_in_density_function::{
|
built_in_density_function::{
|
||||||
CONTINENTS_OVERWORLD, EROSION_OVERWORLD, RIDGES_FOLDED_OVERWORLD, RIDGES_OVERWORLD,
|
CONTINENTS_OVERWORLD, EROSION_OVERWORLD, RIDGES_FOLDED_OVERWORLD, RIDGES_OVERWORLD,
|
||||||
},
|
},
|
||||||
@ -381,7 +381,7 @@ mod double_perlin_noise_sampler_test {
|
|||||||
legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl,
|
legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::world_gen::noise::perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler};
|
use crate::generation::noise::perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sample_legacy() {
|
fn sample_legacy() {
|
||||||
@ -760,7 +760,7 @@ mod perlin_noise_sampler_test {
|
|||||||
random::{xoroshiro128::Xoroshiro, RandomDeriverImpl, RandomGenerator, RandomImpl},
|
random::{xoroshiro128::Xoroshiro, RandomDeriverImpl, RandomGenerator, RandomImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{read_data_from_file, world_gen::noise::perlin::PerlinNoiseSampler};
|
use crate::{generation::noise::perlin::PerlinNoiseSampler, read_data_from_file};
|
||||||
|
|
||||||
use super::OctavePerlinNoiseSampler;
|
use super::OctavePerlinNoiseSampler;
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
use crate::world_gen::{
|
use crate::generation::{
|
||||||
noise::density::{
|
noise::density::{
|
||||||
apply_blend_density,
|
apply_blend_density,
|
||||||
basic::RangeFunction,
|
basic::RangeFunction,
|
||||||
@ -476,8 +476,7 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
read_data_from_file,
|
generation::noise::{
|
||||||
world_gen::noise::{
|
|
||||||
config::LegacyChunkNoiseVisitor,
|
config::LegacyChunkNoiseVisitor,
|
||||||
density::{
|
density::{
|
||||||
built_in_density_function::{EROSION_OVERWORLD, SLOPED_CHEESE_OVERWORLD},
|
built_in_density_function::{EROSION_OVERWORLD, SLOPED_CHEESE_OVERWORLD},
|
||||||
@ -491,6 +490,7 @@ mod test {
|
|||||||
perlin::DoublePerlinNoiseSampler,
|
perlin::DoublePerlinNoiseSampler,
|
||||||
router::OVERWORLD_NOISE_ROUTER,
|
router::OVERWORLD_NOISE_ROUTER,
|
||||||
},
|
},
|
||||||
|
read_data_from_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{apply_surface_slides, create_caves};
|
use super::{apply_surface_slides, create_caves};
|
||||||
@ -276,7 +276,7 @@ impl OctaveSimplexNoiseSampler {
|
|||||||
mod octave_simplex_noise_sampler_test {
|
mod octave_simplex_noise_sampler_test {
|
||||||
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl};
|
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl};
|
||||||
|
|
||||||
use crate::world_gen::noise::simplex::OctaveSimplexNoiseSampler;
|
use crate::generation::noise::simplex::OctaveSimplexNoiseSampler;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new() {
|
fn test_new() {
|
||||||
@ -413,7 +413,7 @@ mod simplex_noise_sampler_test {
|
|||||||
|
|
||||||
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl};
|
use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl};
|
||||||
|
|
||||||
use crate::world_gen::noise::simplex::SimplexNoiseSampler;
|
use crate::generation::noise::simplex::SimplexNoiseSampler;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create() {
|
fn test_create() {
|
||||||
@ -2,7 +2,7 @@ use pumpkin_core::math::{vector2::Vector2, vector3::Vector3};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::BlockState,
|
block::BlockState,
|
||||||
world_gen::{
|
generation::{
|
||||||
chunk_noise::CHUNK_DIM,
|
chunk_noise::CHUNK_DIM,
|
||||||
generation_shapes::GenerationShape,
|
generation_shapes::GenerationShape,
|
||||||
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
|
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
|
||||||
@ -14,7 +14,7 @@ use crate::{
|
|||||||
chunk::{
|
chunk::{
|
||||||
anvil::AnvilChunkReader, ChunkData, ChunkParsingError, ChunkReader, ChunkReadingError,
|
anvil::AnvilChunkReader, ChunkData, ChunkParsingError, ChunkReader, ChunkReadingError,
|
||||||
},
|
},
|
||||||
world_gen::{get_world_gen, Seed, WorldGenerator},
|
generation::{get_world_gen, Seed, WorldGenerator},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The `Level` module provides functionality for working with chunks within or outside a Minecraft world.
|
/// The `Level` module provides functionality for working with chunks within or outside a Minecraft world.
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
use pumpkin_core::math::vector2::Vector2;
|
use generation::{
|
||||||
use world_gen::{
|
|
||||||
aquifer_sampler::{FluidLevel, FluidLevelSampler},
|
aquifer_sampler::{FluidLevel, FluidLevelSampler},
|
||||||
chunk_noise::{ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK},
|
chunk_noise::{ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK},
|
||||||
generation_shapes::GenerationShape,
|
generation_shapes::GenerationShape,
|
||||||
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
|
noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER},
|
||||||
proto_chunk::{ProtoChunk, StandardChunkFluidLevelSampler},
|
proto_chunk::{ProtoChunk, StandardChunkFluidLevelSampler},
|
||||||
};
|
};
|
||||||
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
@ -13,9 +13,9 @@ pub mod chunk;
|
|||||||
pub mod coordinates;
|
pub mod coordinates;
|
||||||
pub mod cylindrical_chunk_iterator;
|
pub mod cylindrical_chunk_iterator;
|
||||||
pub mod dimension;
|
pub mod dimension;
|
||||||
|
mod generation;
|
||||||
pub mod item;
|
pub mod item;
|
||||||
pub mod level;
|
pub mod level;
|
||||||
mod world_gen;
|
|
||||||
|
|
||||||
pub const WORLD_HEIGHT: usize = 384;
|
pub const WORLD_HEIGHT: usize = 384;
|
||||||
pub const WORLD_LOWEST_Y: i16 = -64;
|
pub const WORLD_LOWEST_Y: i16 = -64;
|
||||||
|
|||||||
@ -57,10 +57,9 @@ use pumpkin_world::{
|
|||||||
use tokio::sync::{Mutex, Notify};
|
use tokio::sync::{Mutex, Notify};
|
||||||
|
|
||||||
use super::Entity;
|
use super::Entity;
|
||||||
use crate::error::PumpkinError;
|
use crate::{error::PumpkinError, net::GameProfile};
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{
|
net::{
|
||||||
authentication::GameProfile,
|
|
||||||
combat::{self, player_attack_sound, AttackType},
|
combat::{self, player_attack_sound, AttackType},
|
||||||
Client, PlayerConfig,
|
Client, PlayerConfig,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -35,7 +35,7 @@ compile_error!("Compiling for WASI targets is not supported!");
|
|||||||
|
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
|
||||||
use client::Client;
|
use net::{lan_broadcast, query, rcon::RCONServer, Client};
|
||||||
use server::{ticker::Ticker, Server};
|
use server::{ticker::Ticker, Server};
|
||||||
use std::io::{self};
|
use std::io::{self};
|
||||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||||
@ -50,19 +50,14 @@ use crate::server::CURRENT_MC_VERSION;
|
|||||||
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
||||||
use pumpkin_core::text::{color::NamedColor, TextComponent};
|
use pumpkin_core::text::{color::NamedColor, TextComponent};
|
||||||
use pumpkin_protocol::CURRENT_MC_PROTOCOL;
|
use pumpkin_protocol::CURRENT_MC_PROTOCOL;
|
||||||
use rcon::RCONServer;
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
// Setup some tokens to allow us to identify which event is for which socket.
|
// Setup some tokens to allow us to identify which event is for which socket.
|
||||||
|
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod client;
|
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod lan_broadcast;
|
pub mod net;
|
||||||
pub mod proxy;
|
|
||||||
pub mod query;
|
|
||||||
pub mod rcon;
|
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
||||||
|
|||||||
@ -2,15 +2,14 @@ use std::{collections::HashMap, net::IpAddr};
|
|||||||
|
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
use pumpkin_config::{auth::TextureConfig, ADVANCED_CONFIG};
|
use pumpkin_config::{auth::TextureConfig, ADVANCED_CONFIG};
|
||||||
use pumpkin_core::ProfileAction;
|
|
||||||
use pumpkin_protocol::Property;
|
use pumpkin_protocol::Property;
|
||||||
use reqwest::{StatusCode, Url};
|
use reqwest::{StatusCode, Url};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sha1::Digest;
|
|
||||||
use sha2::Sha256;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::GameProfile;
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@ -29,14 +28,8 @@ pub struct Texture {
|
|||||||
metadata: Option<HashMap<String, String>>,
|
metadata: Option<HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
const MOJANG_AUTHENTICATION_URL: &str = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}";
|
||||||
pub struct GameProfile {
|
const MOJANG_PREVENT_PROXY_AUTHENTICATION_URL: &str = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}";
|
||||||
pub id: Uuid,
|
|
||||||
pub name: String,
|
|
||||||
pub properties: Vec<Property>,
|
|
||||||
#[serde(rename = "profileActions")]
|
|
||||||
pub profile_actions: Option<Vec<ProfileAction>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a GET request to Mojang's authentication servers to verify a client's Minecraft account.
|
/// Sends a GET request to Mojang's authentication servers to verify a client's Minecraft account.
|
||||||
///
|
///
|
||||||
@ -50,20 +43,19 @@ pub struct GameProfile {
|
|||||||
/// 2. Mojang's servers verify the client's credentials and add the player to the their Servers
|
/// 2. Mojang's servers verify the client's credentials and add the player to the their Servers
|
||||||
/// 3. Now our server will send a Request to the Session servers and check if the Player has joined the Session Server .
|
/// 3. Now our server will send a Request to the Session servers and check if the Player has joined the Session Server .
|
||||||
///
|
///
|
||||||
/// See <https://snowiiii.github.io/Pumpkin/developer/authentication.html>
|
/// See <https://snowiiii.github.io/Pumpkin-Website/developer/authentication.html>
|
||||||
pub async fn authenticate(
|
pub async fn authenticate(
|
||||||
username: &str,
|
username: &str,
|
||||||
server_hash: &str,
|
server_hash: &str,
|
||||||
ip: &IpAddr,
|
ip: &IpAddr,
|
||||||
auth_client: &reqwest::Client,
|
auth_client: &reqwest::Client,
|
||||||
) -> Result<GameProfile, AuthError> {
|
) -> Result<GameProfile, AuthError> {
|
||||||
assert!(ADVANCED_CONFIG.authentication.enabled);
|
|
||||||
let address = if ADVANCED_CONFIG.authentication.prevent_proxy_connections {
|
let address = if ADVANCED_CONFIG.authentication.prevent_proxy_connections {
|
||||||
let auth_url = ADVANCED_CONFIG
|
let auth_url = ADVANCED_CONFIG
|
||||||
.authentication
|
.authentication
|
||||||
.prevent_proxy_connection_auth_url
|
.prevent_proxy_connection_auth_url
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}&ip={ip}");
|
.unwrap_or(MOJANG_PREVENT_PROXY_AUTHENTICATION_URL);
|
||||||
|
|
||||||
auth_url
|
auth_url
|
||||||
.replace("{username}", username)
|
.replace("{username}", username)
|
||||||
@ -74,7 +66,7 @@ pub async fn authenticate(
|
|||||||
.authentication
|
.authentication
|
||||||
.auth_url
|
.auth_url
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}");
|
.unwrap_or(MOJANG_AUTHENTICATION_URL);
|
||||||
|
|
||||||
auth_url
|
auth_url
|
||||||
.replace("{username}", username)
|
.replace("{username}", username)
|
||||||
@ -129,10 +121,6 @@ pub fn is_texture_url_valid(url: &Url, config: &TextureConfig) -> Result<(), Tex
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offline_uuid(username: &str) -> Result<Uuid, uuid::Error> {
|
|
||||||
Uuid::from_slice(&Sha256::digest(username)[..16])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AuthError {
|
pub enum AuthError {
|
||||||
#[error("Missing auth client")]
|
#[error("Missing auth client")]
|
||||||
@ -12,9 +12,9 @@ use pumpkin_inventory::{Container, WindowType};
|
|||||||
use pumpkin_protocol::client::play::{
|
use pumpkin_protocol::client::play::{
|
||||||
CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot,
|
CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot,
|
||||||
};
|
};
|
||||||
|
use pumpkin_protocol::codec::slot::Slot;
|
||||||
use pumpkin_protocol::codec::var_int::VarInt;
|
use pumpkin_protocol::codec::var_int::VarInt;
|
||||||
use pumpkin_protocol::server::play::SClickContainer;
|
use pumpkin_protocol::server::play::SClickContainer;
|
||||||
use pumpkin_protocol::slot::Slot;
|
|
||||||
use pumpkin_world::item::item_registry::Item;
|
use pumpkin_world::item::item_registry::Item;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -13,34 +13,57 @@ use crate::{
|
|||||||
server::Server,
|
server::Server,
|
||||||
};
|
};
|
||||||
|
|
||||||
use authentication::GameProfile;
|
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use pumpkin_config::compression::CompressionInfo;
|
use pumpkin_config::compression::CompressionInfo;
|
||||||
use pumpkin_core::text::TextComponent;
|
use pumpkin_core::{text::TextComponent, ProfileAction};
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
bytebuf::{packet_id::Packet, ReadingError},
|
bytebuf::{packet_id::Packet, ReadingError},
|
||||||
client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect},
|
client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect},
|
||||||
packet_decoder::PacketDecoder,
|
packet_decoder::PacketDecoder,
|
||||||
packet_encoder::{PacketEncodeError, PacketEncoder},
|
packet_encoder::{PacketEncodeError, PacketEncoder},
|
||||||
server::{
|
server::{
|
||||||
config::{SAcknowledgeFinishConfig, SClientInformationConfig, SKnownPacks, SPluginMessage},
|
config::{
|
||||||
|
SAcknowledgeFinishConfig, SClientInformationConfig, SConfigCookieResponse, SKnownPacks,
|
||||||
|
SPluginMessage,
|
||||||
|
},
|
||||||
handshake::SHandShake,
|
handshake::SHandShake,
|
||||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
login::{
|
||||||
|
SEncryptionResponse, SLoginAcknowledged, SLoginCookieResponse, SLoginPluginResponse,
|
||||||
|
SLoginStart,
|
||||||
|
},
|
||||||
status::{SStatusPingRequest, SStatusRequest},
|
status::{SStatusPingRequest, SStatusRequest},
|
||||||
},
|
},
|
||||||
ClientPacket, ConnectionState, RawPacket, ServerPacket,
|
ClientPacket, ConnectionState, Property, RawPacket, ServerPacket,
|
||||||
};
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use sha1::Digest;
|
||||||
|
use sha2::Sha256;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse;
|
|
||||||
use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
pub mod authentication;
|
use uuid::Uuid;
|
||||||
mod client_packet;
|
mod authentication;
|
||||||
pub mod combat;
|
pub mod combat;
|
||||||
mod container;
|
mod container;
|
||||||
pub mod player_packet;
|
pub mod lan_broadcast;
|
||||||
|
mod packet;
|
||||||
|
mod proxy;
|
||||||
|
pub mod query;
|
||||||
|
pub mod rcon;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct GameProfile {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub name: String,
|
||||||
|
pub properties: Vec<Property>,
|
||||||
|
#[serde(rename = "profileActions")]
|
||||||
|
pub profile_actions: Option<Vec<ProfileAction>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offline_uuid(username: &str) -> Result<Uuid, uuid::Error> {
|
||||||
|
Uuid::from_slice(&Sha256::digest(username)[..16])
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a player's configuration settings.
|
/// Represents a player's configuration settings.
|
||||||
///
|
///
|
||||||
@ -102,8 +125,6 @@ pub struct Client {
|
|||||||
pub server_address: Mutex<String>,
|
pub server_address: Mutex<String>,
|
||||||
/// The current connection state of the client (e.g., Handshaking, Status, Play).
|
/// The current connection state of the client (e.g., Handshaking, Status, Play).
|
||||||
pub connection_state: AtomicCell<ConnectionState>,
|
pub connection_state: AtomicCell<ConnectionState>,
|
||||||
/// Whether encryption is enabled for the connection.
|
|
||||||
pub encryption: AtomicBool,
|
|
||||||
/// Indicates if the client connection is closed.
|
/// Indicates if the client connection is closed.
|
||||||
pub closed: AtomicBool,
|
pub closed: AtomicBool,
|
||||||
/// The underlying TCP connection to the client.
|
/// The underlying TCP connection to the client.
|
||||||
@ -138,7 +159,6 @@ impl Client {
|
|||||||
connection_writer: Arc::new(Mutex::new(connection_writer)),
|
connection_writer: Arc::new(Mutex::new(connection_writer)),
|
||||||
enc: Arc::new(Mutex::new(PacketEncoder::default())),
|
enc: Arc::new(Mutex::new(PacketEncoder::default())),
|
||||||
dec: Arc::new(Mutex::new(PacketDecoder::default())),
|
dec: Arc::new(Mutex::new(PacketDecoder::default())),
|
||||||
encryption: AtomicBool::new(false),
|
|
||||||
closed: AtomicBool::new(false),
|
closed: AtomicBool::new(false),
|
||||||
client_packets_queue: Arc::new(Mutex::new(VecDeque::new())),
|
client_packets_queue: Arc::new(Mutex::new(VecDeque::new())),
|
||||||
make_player: AtomicBool::new(false),
|
make_player: AtomicBool::new(false),
|
||||||
@ -182,8 +202,6 @@ impl Client {
|
|||||||
shared_secret: Option<&[u8]>, // decrypted
|
shared_secret: Option<&[u8]>, // decrypted
|
||||||
) -> Result<(), EncryptionError> {
|
) -> Result<(), EncryptionError> {
|
||||||
if let Some(shared_secret) = shared_secret {
|
if let Some(shared_secret) = shared_secret {
|
||||||
self.encryption
|
|
||||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
let crypt_key: [u8; 16] = shared_secret
|
let crypt_key: [u8; 16] = shared_secret
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| EncryptionError::SharedWrongLength)?;
|
.map_err(|_| EncryptionError::SharedWrongLength)?;
|
||||||
@ -433,8 +451,8 @@ impl Client {
|
|||||||
SLoginAcknowledged::PACKET_ID => {
|
SLoginAcknowledged::PACKET_ID => {
|
||||||
self.handle_login_acknowledged(server).await;
|
self.handle_login_acknowledged(server).await;
|
||||||
}
|
}
|
||||||
SLCookieResponse::PACKET_ID => {
|
SLoginCookieResponse::PACKET_ID => {
|
||||||
self.handle_login_cookie_response(SLCookieResponse::read(bytebuf)?);
|
self.handle_login_cookie_response(SLoginCookieResponse::read(bytebuf)?);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!(
|
log::error!(
|
||||||
@ -469,8 +487,8 @@ impl Client {
|
|||||||
self.handle_known_packs(server, SKnownPacks::read(bytebuf)?)
|
self.handle_known_packs(server, SKnownPacks::read(bytebuf)?)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
SCCookieResponse::PACKET_ID => {
|
SConfigCookieResponse::PACKET_ID => {
|
||||||
self.handle_config_cookie_response(SCCookieResponse::read(bytebuf)?);
|
self.handle_config_cookie_response(SConfigCookieResponse::read(bytebuf)?);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!(
|
log::error!(
|
||||||
98
pumpkin/src/net/packet/config.rs
Normal file
98
pumpkin/src/net/packet/config.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
use std::num::NonZeroU8;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
entity::player::{ChatMode, Hand},
|
||||||
|
net::{Client, PlayerConfig},
|
||||||
|
server::Server,
|
||||||
|
};
|
||||||
|
use core::str;
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
use pumpkin_protocol::{
|
||||||
|
client::config::{CFinishConfig, CRegistryData},
|
||||||
|
codec::var_int::VarInt,
|
||||||
|
server::config::{
|
||||||
|
SClientInformationConfig, SConfigCookieResponse, SKnownPacks, SPluginMessage,
|
||||||
|
},
|
||||||
|
ConnectionState,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn handle_client_information_config(
|
||||||
|
&self,
|
||||||
|
client_information: SClientInformationConfig,
|
||||||
|
) {
|
||||||
|
log::debug!("Handling client settings");
|
||||||
|
if client_information.view_distance <= 0 {
|
||||||
|
self.kick("Cannot have zero or negative view distance!")
|
||||||
|
.await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (Some(main_hand), Some(chat_mode)) = (
|
||||||
|
Hand::from_i32(client_information.main_hand.into()),
|
||||||
|
ChatMode::from_i32(client_information.chat_mode.into()),
|
||||||
|
) {
|
||||||
|
*self.config.lock().await = Some(PlayerConfig {
|
||||||
|
locale: client_information.locale,
|
||||||
|
view_distance: unsafe {
|
||||||
|
NonZeroU8::new_unchecked(client_information.view_distance as u8)
|
||||||
|
},
|
||||||
|
chat_mode,
|
||||||
|
chat_colors: client_information.chat_colors,
|
||||||
|
skin_parts: client_information.skin_parts,
|
||||||
|
main_hand,
|
||||||
|
text_filtering: client_information.text_filtering,
|
||||||
|
server_listing: client_information.server_listing,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.kick("Invalid hand or chat type").await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) {
|
||||||
|
log::debug!("Handling plugin message");
|
||||||
|
if plugin_message
|
||||||
|
.channel
|
||||||
|
.to_string()
|
||||||
|
.starts_with("minecraft:brand")
|
||||||
|
{
|
||||||
|
log::debug!("got a client brand");
|
||||||
|
match str::from_utf8(&plugin_message.data) {
|
||||||
|
Ok(brand) => *self.brand.lock().await = Some(brand.to_string()),
|
||||||
|
Err(e) => self.kick(&e.to_string()).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_config_cookie_response(&self, packet: SConfigCookieResponse) {
|
||||||
|
// TODO: allow plugins to access this
|
||||||
|
log::debug!(
|
||||||
|
"Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
|
||||||
|
packet.key.to_string(),
|
||||||
|
packet.has_payload,
|
||||||
|
packet.payload_length.unwrap_or(VarInt::from(0)).0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_known_packs(&self, server: &Server, _config_acknowledged: SKnownPacks) {
|
||||||
|
log::debug!("Handling known packs");
|
||||||
|
for registry in &server.cached_registry {
|
||||||
|
self.send_packet(&CRegistryData::new(
|
||||||
|
®istry.registry_id,
|
||||||
|
®istry.registry_entries,
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done with configuring
|
||||||
|
log::debug!("finished config");
|
||||||
|
self.send_packet(&CFinishConfig::new()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_config_acknowledged(&self) {
|
||||||
|
log::debug!("Handling config acknowledge");
|
||||||
|
self.connection_state.store(ConnectionState::Play);
|
||||||
|
self.make_player
|
||||||
|
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
pumpkin/src/net/packet/handshake.rs
Normal file
29
pumpkin/src/net/packet/handshake.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::num::NonZeroI32;
|
||||||
|
|
||||||
|
use pumpkin_protocol::{server::handshake::SHandShake, ConnectionState, CURRENT_MC_PROTOCOL};
|
||||||
|
|
||||||
|
use crate::{net::Client, server::CURRENT_MC_VERSION};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn handle_handshake(&self, handshake: SHandShake) {
|
||||||
|
let version = handshake.protocol_version.0;
|
||||||
|
self.protocol_version
|
||||||
|
.store(version, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
*self.server_address.lock().await = handshake.server_address;
|
||||||
|
|
||||||
|
log::debug!("Handshake: next state {:?}", &handshake.next_state);
|
||||||
|
self.connection_state.store(handshake.next_state);
|
||||||
|
if self.connection_state.load() != ConnectionState::Status {
|
||||||
|
let protocol = version;
|
||||||
|
match protocol.cmp(&NonZeroI32::from(CURRENT_MC_PROTOCOL).get()) {
|
||||||
|
std::cmp::Ordering::Less => {
|
||||||
|
self.kick(&format!("Client outdated ({protocol}), Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await;
|
||||||
|
}
|
||||||
|
std::cmp::Ordering::Equal => {}
|
||||||
|
std::cmp::Ordering::Greater => {
|
||||||
|
self.kick(&format!("Server outdated, Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,43 +1,30 @@
|
|||||||
use super::{authentication::AuthError, Client, PlayerConfig};
|
use std::sync::LazyLock;
|
||||||
use crate::{
|
|
||||||
client::authentication::{self, offline_uuid, validate_textures, GameProfile},
|
|
||||||
entity::player::{ChatMode, Hand},
|
|
||||||
proxy::{
|
|
||||||
bungeecord,
|
|
||||||
velocity::{self, velocity_login},
|
|
||||||
},
|
|
||||||
server::{Server, CURRENT_MC_VERSION},
|
|
||||||
};
|
|
||||||
use core::str;
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
||||||
use pumpkin_core::text::TextComponent;
|
use pumpkin_core::text::TextComponent;
|
||||||
use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse;
|
|
||||||
use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse;
|
|
||||||
use pumpkin_protocol::{
|
|
||||||
client::config::{CServerLinks, Label, Link, LinkType},
|
|
||||||
codec::var_int::VarInt,
|
|
||||||
};
|
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
client::{
|
client::{
|
||||||
config::{CConfigAddResourcePack, CFinishConfig, CKnownPacks, CRegistryData},
|
config::{CConfigAddResourcePack, CKnownPacks},
|
||||||
login::{CLoginSuccess, CSetCompression},
|
login::{CLoginSuccess, CSetCompression},
|
||||||
status::CPingResponse,
|
play::{CServerLinks, Label, Link, LinkType},
|
||||||
},
|
},
|
||||||
server::{
|
codec::var_int::VarInt,
|
||||||
config::{SClientInformationConfig, SKnownPacks, SPluginMessage},
|
server::login::{SEncryptionResponse, SLoginCookieResponse, SLoginPluginResponse, SLoginStart},
|
||||||
handshake::SHandShake,
|
ConnectionState, KnownPack,
|
||||||
login::{SEncryptionResponse, SLoginPluginResponse, SLoginStart},
|
|
||||||
status::SStatusPingRequest,
|
|
||||||
},
|
|
||||||
ConnectionState, KnownPack, CURRENT_MC_PROTOCOL,
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
num::{NonZeroI32, NonZeroU8},
|
|
||||||
sync::LazyLock,
|
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
net::{
|
||||||
|
authentication::{self, AuthError},
|
||||||
|
offline_uuid,
|
||||||
|
packet::is_valid_player_name,
|
||||||
|
proxy::{bungeecord, velocity},
|
||||||
|
Client, GameProfile,
|
||||||
|
},
|
||||||
|
server::Server,
|
||||||
|
};
|
||||||
|
|
||||||
static LINKS: LazyLock<Vec<Link>> = LazyLock::new(|| {
|
static LINKS: LazyLock<Vec<Link>> = LazyLock::new(|| {
|
||||||
let mut links: Vec<Link> = Vec::new();
|
let mut links: Vec<Link> = Vec::new();
|
||||||
|
|
||||||
@ -98,49 +85,7 @@ static LINKS: LazyLock<Vec<Link>> = LazyLock::new(|| {
|
|||||||
links
|
links
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Processes incoming Packets from the Client to the Server
|
|
||||||
/// Implements the `Client` Packets
|
|
||||||
/// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub async fn handle_handshake(&self, handshake: SHandShake) {
|
|
||||||
let version = handshake.protocol_version.0;
|
|
||||||
self.protocol_version
|
|
||||||
.store(version, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
*self.server_address.lock().await = handshake.server_address;
|
|
||||||
|
|
||||||
log::debug!("Handshake: next state {:?}", &handshake.next_state);
|
|
||||||
self.connection_state.store(handshake.next_state);
|
|
||||||
if self.connection_state.load() != ConnectionState::Status {
|
|
||||||
let protocol = version;
|
|
||||||
match protocol.cmp(&NonZeroI32::from(CURRENT_MC_PROTOCOL).get()) {
|
|
||||||
std::cmp::Ordering::Less => {
|
|
||||||
self.kick(&format!("Client outdated ({protocol}), Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await;
|
|
||||||
}
|
|
||||||
std::cmp::Ordering::Equal => {}
|
|
||||||
std::cmp::Ordering::Greater => {
|
|
||||||
self.kick(&format!("Server outdated, Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_status_request(&self, server: &Server) {
|
|
||||||
log::debug!("Handling status request");
|
|
||||||
let status = server.get_status();
|
|
||||||
self.send_packet(&status.lock().await.get_status()).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_ping_request(&self, ping_request: SStatusPingRequest) {
|
|
||||||
log::debug!("Handling ping request");
|
|
||||||
self.send_packet(&CPingResponse::new(ping_request.payload))
|
|
||||||
.await;
|
|
||||||
self.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_valid_player_name(name: &str) -> bool {
|
|
||||||
name.len() <= 16 && name.chars().all(|c| c > 32u8 as char && c < 127u8 as char)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_login_start(&self, server: &Server, login_start: SLoginStart) {
|
pub async fn handle_login_start(&self, server: &Server, login_start: SLoginStart) {
|
||||||
log::debug!("login start");
|
log::debug!("login start");
|
||||||
|
|
||||||
@ -154,7 +99,7 @@ impl Client {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Self::is_valid_player_name(&login_start.name) {
|
if !is_valid_player_name(&login_start.name) {
|
||||||
self.kick("Invalid characters in username").await;
|
self.kick("Invalid characters in username").await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -164,9 +109,15 @@ impl Client {
|
|||||||
let proxy = &ADVANCED_CONFIG.proxy;
|
let proxy = &ADVANCED_CONFIG.proxy;
|
||||||
if proxy.enabled {
|
if proxy.enabled {
|
||||||
if proxy.velocity.enabled {
|
if proxy.velocity.enabled {
|
||||||
velocity_login(self).await;
|
velocity::velocity_login(self).await;
|
||||||
} else if proxy.bungeecord.enabled {
|
} else if proxy.bungeecord.enabled {
|
||||||
match bungeecord::bungeecord_login(self, login_start.name).await {
|
match bungeecord::bungeecord_login(
|
||||||
|
&self.address,
|
||||||
|
&self.server_address.lock().await,
|
||||||
|
login_start.name,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok((_ip, profile)) => {
|
Ok((_ip, profile)) => {
|
||||||
// self.address.lock() = ip;
|
// self.address.lock() = ip;
|
||||||
self.finish_login(&profile).await;
|
self.finish_login(&profile).await;
|
||||||
@ -309,7 +260,10 @@ impl Client {
|
|||||||
}
|
}
|
||||||
// validate textures
|
// validate textures
|
||||||
for property in &profile.properties {
|
for property in &profile.properties {
|
||||||
validate_textures(property, &ADVANCED_CONFIG.authentication.textures)
|
authentication::validate_textures(
|
||||||
|
property,
|
||||||
|
&ADVANCED_CONFIG.authentication.textures,
|
||||||
|
)
|
||||||
.map_err(AuthError::TextureError)?;
|
.map_err(AuthError::TextureError)?;
|
||||||
}
|
}
|
||||||
return Ok(profile);
|
return Ok(profile);
|
||||||
@ -317,7 +271,7 @@ impl Client {
|
|||||||
Err(AuthError::MissingAuthClient)
|
Err(AuthError::MissingAuthClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_login_cookie_response(&self, packet: SLCookieResponse) {
|
pub fn handle_login_cookie_response(&self, packet: SLoginCookieResponse) {
|
||||||
// TODO: allow plugins to access this
|
// TODO: allow plugins to access this
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
|
"Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
|
||||||
@ -326,7 +280,6 @@ impl Client {
|
|||||||
packet.payload_length.unwrap_or(VarInt::from(0)).0
|
packet.payload_length.unwrap_or(VarInt::from(0)).0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_plugin_response(&self, plugin_response: SLoginPluginResponse) {
|
pub async fn handle_plugin_response(&self, plugin_response: SLoginPluginResponse) {
|
||||||
log::debug!("Handling plugin");
|
log::debug!("Handling plugin");
|
||||||
let velocity_config = &ADVANCED_CONFIG.proxy.velocity;
|
let velocity_config = &ADVANCED_CONFIG.proxy.velocity;
|
||||||
@ -386,82 +339,4 @@ impl Client {
|
|||||||
.await;
|
.await;
|
||||||
log::debug!("login acknowledged");
|
log::debug!("login acknowledged");
|
||||||
}
|
}
|
||||||
pub async fn handle_client_information_config(
|
|
||||||
&self,
|
|
||||||
client_information: SClientInformationConfig,
|
|
||||||
) {
|
|
||||||
log::debug!("Handling client settings");
|
|
||||||
if client_information.view_distance <= 0 {
|
|
||||||
self.kick("Cannot have zero or negative view distance!")
|
|
||||||
.await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let (Some(main_hand), Some(chat_mode)) = (
|
|
||||||
Hand::from_i32(client_information.main_hand.into()),
|
|
||||||
ChatMode::from_i32(client_information.chat_mode.into()),
|
|
||||||
) {
|
|
||||||
*self.config.lock().await = Some(PlayerConfig {
|
|
||||||
locale: client_information.locale,
|
|
||||||
view_distance: unsafe {
|
|
||||||
NonZeroU8::new_unchecked(client_information.view_distance as u8)
|
|
||||||
},
|
|
||||||
chat_mode,
|
|
||||||
chat_colors: client_information.chat_colors,
|
|
||||||
skin_parts: client_information.skin_parts,
|
|
||||||
main_hand,
|
|
||||||
text_filtering: client_information.text_filtering,
|
|
||||||
server_listing: client_information.server_listing,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.kick("Invalid hand or chat type").await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) {
|
|
||||||
log::debug!("Handling plugin message");
|
|
||||||
if plugin_message
|
|
||||||
.channel
|
|
||||||
.to_string()
|
|
||||||
.starts_with("minecraft:brand")
|
|
||||||
{
|
|
||||||
log::debug!("got a client brand");
|
|
||||||
match str::from_utf8(&plugin_message.data) {
|
|
||||||
Ok(brand) => *self.brand.lock().await = Some(brand.to_string()),
|
|
||||||
Err(e) => self.kick(&e.to_string()).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_config_cookie_response(&self, packet: SCCookieResponse) {
|
|
||||||
// TODO: allow plugins to access this
|
|
||||||
log::debug!(
|
|
||||||
"Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
|
|
||||||
packet.key.to_string(),
|
|
||||||
packet.has_payload,
|
|
||||||
packet.payload_length.unwrap_or(VarInt::from(0)).0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_known_packs(&self, server: &Server, _config_acknowledged: SKnownPacks) {
|
|
||||||
log::debug!("Handling known packs");
|
|
||||||
for registry in &server.cached_registry {
|
|
||||||
self.send_packet(&CRegistryData::new(
|
|
||||||
®istry.registry_id,
|
|
||||||
®istry.registry_entries,
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are done with configuring
|
|
||||||
log::debug!("finished config");
|
|
||||||
self.send_packet(&CFinishConfig::new()).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_config_acknowledged(&self) {
|
|
||||||
log::debug!("Handling config acknowledge");
|
|
||||||
self.connection_state.store(ConnectionState::Play);
|
|
||||||
self.make_player
|
|
||||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
9
pumpkin/src/net/packet/mod.rs
Normal file
9
pumpkin/src/net/packet/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
mod config;
|
||||||
|
mod handshake;
|
||||||
|
mod login;
|
||||||
|
mod play;
|
||||||
|
mod status;
|
||||||
|
|
||||||
|
fn is_valid_player_name(name: &str) -> bool {
|
||||||
|
name.len() <= 16 && name.chars().all(|c| c > 32u8 as char && c < 127u8 as char)
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
use std::num::NonZeroU8;
|
use std::num::NonZeroU8;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::PlayerConfig;
|
|
||||||
use crate::block::block_manager::BlockActionResult;
|
use crate::block::block_manager::BlockActionResult;
|
||||||
|
use crate::net::PlayerConfig;
|
||||||
use crate::{
|
use crate::{
|
||||||
command::CommandSender,
|
command::CommandSender,
|
||||||
entity::player::{ChatMode, Hand, Player},
|
entity::player::{ChatMode, Hand, Player},
|
||||||
18
pumpkin/src/net/packet/status.rs
Normal file
18
pumpkin/src/net/packet/status.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use pumpkin_protocol::{client::status::CPingResponse, server::status::SStatusPingRequest};
|
||||||
|
|
||||||
|
use crate::{net::Client, server::Server};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn handle_status_request(&self, server: &Server) {
|
||||||
|
log::debug!("Handling status request");
|
||||||
|
let status = server.get_status();
|
||||||
|
self.send_packet(&status.lock().await.get_status()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_ping_request(&self, ping_request: SStatusPingRequest) {
|
||||||
|
log::debug!("Handling ping request");
|
||||||
|
self.send_packet(&CPingResponse::new(ping_request.payload))
|
||||||
|
.await;
|
||||||
|
self.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,10 @@
|
|||||||
use std::net::IpAddr;
|
use std::{net::IpAddr, net::SocketAddr};
|
||||||
|
|
||||||
use pumpkin_protocol::Property;
|
use pumpkin_protocol::Property;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::net::{offline_uuid, GameProfile};
|
||||||
client::authentication::{offline_uuid, GameProfile},
|
|
||||||
Client,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum BungeeCordError {
|
pub enum BungeeCordError {
|
||||||
@ -20,11 +18,23 @@ pub enum BungeeCordError {
|
|||||||
FailedMakeOfflineUUID,
|
FailedMakeOfflineUUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to login a player via `BungeeCord`.
|
||||||
|
///
|
||||||
|
/// This function should be called when receiving the `SLoginStart` packet.
|
||||||
|
/// It utilizes the `server_address` received in the `SHandShake` packet,
|
||||||
|
/// which may contain optional data about the client:
|
||||||
|
///
|
||||||
|
/// 1. IP address (if `ip_forward` is enabled on the `BungeeCord` server)
|
||||||
|
/// 2. UUID (if `ip_forward` is enabled on the `BungeeCord` server)
|
||||||
|
/// 3. Game profile properties (if `ip_forward` and `online_mode` are enabled on the `BungeeCord` server)
|
||||||
|
///
|
||||||
|
/// If any of the optional data is missing, the function will attempt to
|
||||||
|
/// determine the player's information locally.
|
||||||
pub async fn bungeecord_login(
|
pub async fn bungeecord_login(
|
||||||
client: &Client,
|
client_address: &Mutex<SocketAddr>,
|
||||||
username: String,
|
server_address: &str,
|
||||||
|
name: String,
|
||||||
) -> Result<(IpAddr, GameProfile), BungeeCordError> {
|
) -> Result<(IpAddr, GameProfile), BungeeCordError> {
|
||||||
let server_address = client.server_address.lock().await;
|
|
||||||
let data = server_address.split('\0').take(4).collect::<Vec<_>>();
|
let data = server_address.split('\0').take(4).collect::<Vec<_>>();
|
||||||
|
|
||||||
// Ip of player, only given if ip_forward on bungee is true
|
// Ip of player, only given if ip_forward on bungee is true
|
||||||
@ -32,15 +42,13 @@ pub async fn bungeecord_login(
|
|||||||
Some(ip) => ip
|
Some(ip) => ip
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| BungeeCordError::FailedParseAddress)?,
|
.map_err(|_| BungeeCordError::FailedParseAddress)?,
|
||||||
None => client.address.lock().await.ip(),
|
None => client_address.lock().await.ip(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Uuid of player, only given if ip_forward on bungee is true
|
// Uuid of player, only given if ip_forward on bungee is true
|
||||||
let id = match data.get(2) {
|
let id = match data.get(2) {
|
||||||
Some(uuid) => uuid.parse().map_err(|_| BungeeCordError::FailedParseUUID)?,
|
Some(uuid) => uuid.parse().map_err(|_| BungeeCordError::FailedParseUUID)?,
|
||||||
None => {
|
None => offline_uuid(name.as_str()).map_err(|_| BungeeCordError::FailedMakeOfflineUUID)?,
|
||||||
offline_uuid(username.as_str()).map_err(|_| BungeeCordError::FailedMakeOfflineUUID)?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Read properties and get textures
|
// Read properties and get textures
|
||||||
@ -57,7 +65,7 @@ pub async fn bungeecord_login(
|
|||||||
ip,
|
ip,
|
||||||
GameProfile {
|
GameProfile {
|
||||||
id,
|
id,
|
||||||
name: username,
|
name,
|
||||||
properties,
|
properties,
|
||||||
profile_actions: None,
|
profile_actions: None,
|
||||||
},
|
},
|
||||||
@ -14,7 +14,7 @@ use rand::Rng;
|
|||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::client::{authentication::GameProfile, Client};
|
use crate::net::{Client, GameProfile};
|
||||||
|
|
||||||
type HmacSha256 = Hmac<Sha256>;
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
@ -13,7 +13,6 @@ pub struct RCONServer;
|
|||||||
|
|
||||||
impl RCONServer {
|
impl RCONServer {
|
||||||
pub async fn new(config: &RCONConfig, server: Arc<Server>) -> Result<Self, std::io::Error> {
|
pub async fn new(config: &RCONConfig, server: Arc<Server>) -> Result<Self, std::io::Error> {
|
||||||
assert!(config.enabled, "RCON is not enabled");
|
|
||||||
let listener = tokio::net::TcpListener::bind(config.address).await.unwrap();
|
let listener = tokio::net::TcpListener::bind(config.address).await.unwrap();
|
||||||
|
|
||||||
let password = Arc::new(config.password.clone());
|
let password = Arc::new(config.password.clone());
|
||||||
@ -26,6 +26,7 @@ fn load_icon_from_file<P: AsRef<Path>>(path: P) -> Result<String, Box<dyn error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_icon_from_bytes(png_data: &[u8]) -> Result<String, Box<dyn error::Error>> {
|
fn load_icon_from_bytes(png_data: &[u8]) -> Result<String, Box<dyn error::Error>> {
|
||||||
|
assert!(!png_data.is_empty(), "PNG data is empty");
|
||||||
let icon = png::Decoder::new(Cursor::new(&png_data));
|
let icon = png::Decoder::new(Cursor::new(&png_data));
|
||||||
let reader = icon.read_info()?;
|
let reader = icon.read_info()?;
|
||||||
let info = reader.info();
|
let info = reader.info();
|
||||||
@ -70,6 +71,7 @@ impl CachedBranding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CachedStatus {
|
impl CachedStatus {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let status_response = Self::build_response(&BASIC_CONFIG);
|
let status_response = Self::build_response(&BASIC_CONFIG);
|
||||||
let status_response_json = serde_json::to_string(&status_response)
|
let status_response_json = serde_json::to_string(&status_response)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use rsa::{traits::PublicKeyParts as _, Pkcs1v15Encrypt, RsaPrivateKey};
|
|||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
|
|
||||||
use crate::client::EncryptionError;
|
use crate::net::EncryptionError;
|
||||||
|
|
||||||
pub struct KeyStore {
|
pub struct KeyStore {
|
||||||
pub private_key: RsaPrivateKey,
|
pub private_key: RsaPrivateKey,
|
||||||
@ -13,6 +13,7 @@ pub struct KeyStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KeyStore {
|
impl KeyStore {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
log::debug!("Creating encryption keys...");
|
log::debug!("Creating encryption keys...");
|
||||||
let private_key = Self::generate_private_key();
|
let private_key = Self::generate_private_key();
|
||||||
|
|||||||
@ -23,12 +23,12 @@ use tokio::sync::{Mutex, RwLock};
|
|||||||
|
|
||||||
use crate::block::block_manager::BlockManager;
|
use crate::block::block_manager::BlockManager;
|
||||||
use crate::block::default_block_manager;
|
use crate::block::default_block_manager;
|
||||||
use crate::client::EncryptionError;
|
use crate::net::EncryptionError;
|
||||||
use crate::world::custom_bossbar::CustomBossbars;
|
use crate::world::custom_bossbar::CustomBossbars;
|
||||||
use crate::{
|
use crate::{
|
||||||
client::Client,
|
|
||||||
command::{default_dispatcher, dispatcher::CommandDispatcher},
|
command::{default_dispatcher, dispatcher::CommandDispatcher},
|
||||||
entity::player::Player,
|
entity::player::Player,
|
||||||
|
net::Client,
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use pumpkin_protocol::client::play::{
|
|||||||
CSetBorderWarningDelay, CSetBorderWarningDistance,
|
CSetBorderWarningDelay, CSetBorderWarningDistance,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::client::Client;
|
use crate::net::Client;
|
||||||
|
|
||||||
use super::World;
|
use super::World;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user