Better doc
This commit is contained in:
parent
ada0d82a72
commit
0bebc6fc31
7
pumpkin-config/README.md
Normal file
7
pumpkin-config/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
### Pumpkin Configuration
|
||||
Pumpkin offers a robust configuration system that allows users to customize various aspects of the server's behavior without relying on external plugins. This provides flexibility and control over the server's operation.
|
||||
|
||||
#### Key Features:
|
||||
- Extensive Customization: Configure server settings, player behavior, world generation, and more.
|
||||
- Performance Optimization: Optimize server performance through configuration tweaks.
|
||||
- Plugin-Free Customization: Achieve desired changes without the need for additional plugins.
|
||||
0
pumpkin-entity/README.md
Normal file
0
pumpkin-entity/README.md
Normal file
@ -69,4 +69,8 @@ Thats a Serverbound packet
|
||||
pub struct CPlayDisconnect {
|
||||
reason: TextComponent,
|
||||
}
|
||||
``
|
||||
```
|
||||
|
||||
### Porting
|
||||
You can compare difference in Protocol on wiki.vg https://wiki.vg/index.php?title=Protocol&action=history
|
||||
Also change the `CURRENT_MC_PROTOCOL` in `src/lib.rs`
|
||||
@ -12,6 +12,8 @@ pub mod server;
|
||||
pub mod slot;
|
||||
pub mod uuid;
|
||||
|
||||
/// To current Minecraft protocol
|
||||
/// Don't forget to change this when porting
|
||||
pub const CURRENT_MC_PROTOCOL: u32 = 767;
|
||||
|
||||
pub const MAX_PACKET_SIZE: i32 = 2097152;
|
||||
@ -175,7 +177,6 @@ impl From<VarInt> for ConnectionState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawPacket {
|
||||
pub id: VarInt,
|
||||
pub bytebuf: ByteBuffer,
|
||||
@ -191,29 +192,42 @@ pub trait ServerPacket: Packet + Sized {
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct StatusResponse {
|
||||
pub version: Version,
|
||||
pub players: Players,
|
||||
/// The version on which the Server is running. Optional
|
||||
pub version: Option<Version>,
|
||||
/// Informations about currently connected Players. Optional
|
||||
pub players: Option<Players>,
|
||||
/// The description displayed also called MOTD (Message of the day). Optional
|
||||
pub description: String,
|
||||
pub favicon: Option<String>, // data:image/png;base64,<data>
|
||||
// Players, favicon ...
|
||||
/// The icon displayed, Optional
|
||||
pub favicon: Option<String>,
|
||||
/// Players are forced to use Secure chat
|
||||
pub enforece_secure_chat: bool,
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
pub struct Version {
|
||||
/// The current name of the Version (e.g. 1.21.1)
|
||||
pub name: String,
|
||||
/// The current Protocol Version (e.g. 767)
|
||||
pub protocol: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Players {
|
||||
/// The maximum Player count the server allows
|
||||
pub max: u32,
|
||||
/// The current online player count
|
||||
pub online: u32,
|
||||
/// Informations about currently connected players.
|
||||
/// Note player can disable listing here.
|
||||
pub sample: Vec<Sample>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Sample {
|
||||
/// Players Name
|
||||
pub name: String,
|
||||
pub id: String, // uuid
|
||||
/// Players UUID
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
// basicly game profile
|
||||
|
||||
@ -13,6 +13,8 @@ use crate::{
|
||||
type Cipher = cfb8::Decryptor<aes::Aes128>;
|
||||
|
||||
// Decoder: Client -> Server
|
||||
// Supports ZLib decoding/decompression
|
||||
// Supports Aes128 Encyption
|
||||
#[derive(Default)]
|
||||
pub struct PacketDecoder {
|
||||
buf: BytesMut,
|
||||
@ -105,6 +107,7 @@ impl PacketDecoder {
|
||||
self.cipher = Some(cipher);
|
||||
}
|
||||
|
||||
/// Enables ZLib Deompression
|
||||
pub fn set_compression(&mut self, compression: Option<u32>) {
|
||||
self.compression = compression;
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@ use crate::{bytebuf::ByteBuffer, ClientPacket, PacketError, VarInt, MAX_PACKET_S
|
||||
type Cipher = cfb8::Encryptor<aes::Aes128>;
|
||||
|
||||
// Encoder: Server -> Client
|
||||
// Supports ZLib endecoding/compression
|
||||
// Supports Aes128 Encyption
|
||||
#[derive(Default)]
|
||||
pub struct PacketEncoder {
|
||||
buf: BytesMut,
|
||||
@ -121,6 +123,7 @@ impl PacketEncoder {
|
||||
self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key"));
|
||||
}
|
||||
|
||||
/// Enables ZLib Compression
|
||||
pub fn set_compression(&mut self, compression: Option<(u32, u32)>) {
|
||||
self.compression = compression;
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Wrapper around uuid::UUID, Please use this in every Packet containing a UUID
|
||||
/// We use this to we can do own Serializing
|
||||
pub struct UUID(pub uuid::Uuid);
|
||||
|
||||
impl Serialize for UUID {
|
||||
|
||||
17
pumpkin-world/README.md
Normal file
17
pumpkin-world/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
### Pumpkin World
|
||||
Contains everything World related for example
|
||||
|
||||
- Loading Chunks (Anvil Format)
|
||||
- Generating Chunks
|
||||
- Loading Blocks/Items
|
||||
|
||||
### Porting
|
||||
When updating your Minecraft server to a newer version, you typically need to replace the files in the assets directory to ensure compatibility with the new version's resources.
|
||||
Thankfully, vanilla Minecraft provides a way to extract these updated assets directly from the server JAR file itself.
|
||||
|
||||
1. Download the latest Minecraft server JAR file for the version you want to upgrade to.
|
||||
2. Run `java -DbundlerMainClass=net.minecraft.data.Main -jar <minecraft_server>.jar --reports`.
|
||||
3. This command will create a new folder named `reports` in the same directory as the server JAR. This folder contains the updated "assets" directory for the new version.
|
||||
4. Copy the assets folder from the reports folder and replace the existing assets directory within your server directory.
|
||||
|
||||
For details see https://wiki.vg/Data_Generators
|
||||
@ -18,7 +18,15 @@ use crate::{
|
||||
world_gen::{get_world_gen, Seed, WorldGenerator},
|
||||
};
|
||||
|
||||
/// The Level represents a single Dimension.
|
||||
/// The `Level` module provides functionality for working with chunks within or outside a Minecraft world.
|
||||
///
|
||||
/// Key features include:
|
||||
///
|
||||
/// - **Chunk Loading:** Efficiently loads chunks from disk (Anvil format).
|
||||
/// - **Chunk Caching:** Stores accessed chunks in memory for faster access.
|
||||
/// - **Chunk Generation:** Generates new chunks on-demand using a specified `WorldGenerator`.
|
||||
///
|
||||
/// For more details on world generation, refer to the `WorldGenerator` module.
|
||||
pub struct Level {
|
||||
save_file: Option<SaveFile>,
|
||||
loaded_chunks: Arc<Mutex<HashMap<Vector2<i32>, Arc<ChunkData>>>>,
|
||||
@ -126,17 +134,6 @@ impl Level {
|
||||
}
|
||||
}
|
||||
|
||||
// /// Read one chunk in the world
|
||||
// ///
|
||||
// /// Do not use this function if reading many chunks is required, since in case those two chunks which are read separately using `.read_chunk` are in the same region file, it will need to be opened and closed separately for both of them, leading to a performance loss.
|
||||
// pub async fn read_chunk(&self, chunk: (i32, i32)) -> Result<ChunkData, WorldError> {
|
||||
// self.read_chunks(vec![chunk])
|
||||
// .await
|
||||
// .pop()
|
||||
// .expect("Read chunks must return a chunk")
|
||||
// .1
|
||||
// }
|
||||
|
||||
/// Reads/Generates many chunks in a world
|
||||
/// MUST be called from a tokio runtime thread
|
||||
///
|
||||
|
||||
@ -39,6 +39,19 @@ pub struct GameProfile {
|
||||
pub profile_actions: Option<Vec<ProfileAction>>,
|
||||
}
|
||||
|
||||
/// Sends a GET request to Mojang's authentication servers to verify a client's Minecraft account.
|
||||
///
|
||||
/// **Purpose:**
|
||||
///
|
||||
/// This function is used to ensure that a client connecting to the server has a valid, premium Minecraft account. It's a crucial step in preventing unauthorized access and maintaining server security.
|
||||
///
|
||||
/// **How it Works:**
|
||||
///
|
||||
/// 1. A client with a premium account sends a login request to the Mojang session server.
|
||||
/// 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 .
|
||||
///
|
||||
/// **Note:** This process helps prevent unauthorized access to the server and ensures that only legitimate Minecraft accounts can connect.
|
||||
pub async fn authenticate(
|
||||
username: &str,
|
||||
server_hash: &str,
|
||||
@ -71,29 +84,34 @@ pub async fn authenticate(
|
||||
Ok(profile)
|
||||
}
|
||||
|
||||
pub fn unpack_textures(property: Property, config: &TextureConfig) {
|
||||
// TODO: no unwrap
|
||||
let from64 = general_purpose::STANDARD.decode(property.value).unwrap();
|
||||
let textures: ProfileTextures = serde_json::from_slice(&from64).unwrap();
|
||||
pub fn unpack_textures(property: Property, config: &TextureConfig) -> Result<(), TextureError> {
|
||||
let from64 = general_purpose::STANDARD
|
||||
.decode(property.value)
|
||||
.map_err(|e| TextureError::DecodeError(e.to_string()))?;
|
||||
let textures: ProfileTextures =
|
||||
serde_json::from_slice(&from64).map_err(|e| TextureError::JSONError(e.to_string()))?;
|
||||
for texture in textures.textures {
|
||||
is_texture_url_valid(Url::parse(&texture.1.url).unwrap(), config);
|
||||
let url =
|
||||
Url::parse(&texture.1.url).map_err(|e| TextureError::InvalidURL(e.to_string()))?;
|
||||
is_texture_url_valid(url, config)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn auth_digest(bytes: &[u8]) -> String {
|
||||
BigInt::from_signed_bytes_be(bytes).to_str_radix(16)
|
||||
}
|
||||
|
||||
pub fn is_texture_url_valid(url: Url, config: &TextureConfig) -> bool {
|
||||
pub fn is_texture_url_valid(url: Url, config: &TextureConfig) -> Result<(), TextureError> {
|
||||
let scheme = url.scheme();
|
||||
if !config.allowed_url_schemes.contains(&scheme.to_string()) {
|
||||
return false;
|
||||
return Err(TextureError::DisallowedUrlScheme(scheme.to_string()));
|
||||
}
|
||||
let domain = url.domain().unwrap_or("");
|
||||
if !config.allowed_url_domains.contains(&domain.to_string()) {
|
||||
return false;
|
||||
return Err(TextureError::DisallowedUrlDomain(domain.to_string()));
|
||||
}
|
||||
true
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@ -109,3 +127,17 @@ pub enum AuthError {
|
||||
#[error("Unknown Status Code")]
|
||||
UnknownStatusCode(String),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TextureError {
|
||||
#[error("Invalid URL")]
|
||||
InvalidURL(String),
|
||||
#[error("Invalid URL scheme for player texture: {0}")]
|
||||
DisallowedUrlScheme(String),
|
||||
#[error("Invalid URL domain for player texture: {0}")]
|
||||
DisallowedUrlDomain(String),
|
||||
#[error("Failed to decode base64 player texture: {0}")]
|
||||
DecodeError(String),
|
||||
#[error("Failed to parse JSON from player texture: {0}")]
|
||||
JSONError(String),
|
||||
}
|
||||
|
||||
@ -171,9 +171,9 @@ impl Client {
|
||||
Err(e) => self.kick(&e.to_string()),
|
||||
}
|
||||
}
|
||||
for ele in gameprofile.as_ref().unwrap().properties.clone() {
|
||||
// todo, use this
|
||||
unpack_textures(ele, &ADVANCED_CONFIG.authentication.textures);
|
||||
for property in gameprofile.as_ref().unwrap().properties.clone() {
|
||||
unpack_textures(property, &ADVANCED_CONFIG.authentication.textures)
|
||||
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||
}
|
||||
|
||||
// enable compression
|
||||
|
||||
@ -37,15 +37,30 @@ mod client_packet;
|
||||
mod container;
|
||||
pub mod player_packet;
|
||||
|
||||
/// Represents a player's configuration settings.
|
||||
///
|
||||
/// This struct contains various options that can be customized by the player, affecting their gameplay experience.
|
||||
///
|
||||
/// **Usage:**
|
||||
///
|
||||
/// This struct is typically used to store and manage a player's preferences. It can be sent to the server when a player joins or when they change their settings.
|
||||
#[derive(Clone)]
|
||||
pub struct PlayerConfig {
|
||||
/// The player's preferred language.
|
||||
pub locale: String, // 16
|
||||
/// The maximum distance at which chunks are rendered.
|
||||
pub view_distance: i8,
|
||||
/// The player's chat mode settings
|
||||
pub chat_mode: ChatMode,
|
||||
/// Whether chat colors are enabled.
|
||||
pub chat_colors: bool,
|
||||
/// The player's skin configuration options.
|
||||
pub skin_parts: u8,
|
||||
/// The player's dominant hand (left or right).
|
||||
pub main_hand: Hand,
|
||||
/// Whether text filtering is enabled.
|
||||
pub text_filtering: bool,
|
||||
/// Whether the player wants to appear in the server list.
|
||||
pub server_listing: bool,
|
||||
}
|
||||
|
||||
@ -64,23 +79,37 @@ impl Default for PlayerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Everything which makes a Conection with our Server is a `Client`.
|
||||
/// Client will become Players when they reach the `Play` state
|
||||
pub struct Client {
|
||||
/// The client's game profile information.
|
||||
pub gameprofile: Mutex<Option<GameProfile>>,
|
||||
|
||||
/// The client's configuration settings, Optional
|
||||
pub config: Mutex<Option<PlayerConfig>>,
|
||||
/// The client's brand or modpack information, Optional.
|
||||
pub brand: Mutex<Option<String>>,
|
||||
|
||||
/// The minecraft protocol version used by the client.
|
||||
pub protocol_version: AtomicI32,
|
||||
/// The current connection state of the client (e.g., Handshaking, Status, Play).
|
||||
pub connection_state: Mutex<ConnectionState>,
|
||||
/// Whether encryption is enabled for the connection.
|
||||
pub encryption: AtomicBool,
|
||||
/// Indicates if the client connection is closed.
|
||||
pub closed: AtomicBool,
|
||||
/// A unique token identifying the client.
|
||||
pub token: Token,
|
||||
/// The underlying TCP connection to the client.
|
||||
pub connection: Arc<Mutex<TcpStream>>,
|
||||
/// The client's IP address.
|
||||
pub address: Mutex<SocketAddr>,
|
||||
/// The packet encoder for outgoing packets.
|
||||
enc: Arc<Mutex<PacketEncoder>>,
|
||||
/// The packet decoder for incoming packets.
|
||||
dec: Arc<Mutex<PacketDecoder>>,
|
||||
/// A queue of raw packets received from the client, waiting to be processed.
|
||||
pub client_packets_queue: Arc<Mutex<Vec<RawPacket>>>,
|
||||
|
||||
/// Indicates whether the client should be converted into a player.
|
||||
pub make_player: AtomicBool,
|
||||
}
|
||||
|
||||
@ -104,13 +133,13 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// adds a Incoming packet to the queue
|
||||
/// Adds a Incoming packet to the queue
|
||||
pub fn add_packet(&self, packet: RawPacket) {
|
||||
let mut client_packets_queue = self.client_packets_queue.lock().unwrap();
|
||||
client_packets_queue.push(packet);
|
||||
}
|
||||
|
||||
/// enables encryption
|
||||
/// Enables encryption
|
||||
pub fn enable_encryption(
|
||||
&self,
|
||||
shared_secret: &[u8], // decrypted
|
||||
@ -125,7 +154,7 @@ impl Client {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Compression threshold, Compression level
|
||||
/// Compression threshold, Compression level
|
||||
pub fn set_compression(&self, compression: Option<(u32, u32)>) {
|
||||
self.dec
|
||||
.lock()
|
||||
@ -161,6 +190,7 @@ impl Client {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Processes all packets send by the client
|
||||
pub async fn process_packets(&self, server: &Arc<Server>) {
|
||||
while let Some(mut packet) = self.client_packets_queue.lock().unwrap().pop() {
|
||||
match self.handle_packet(server, &mut packet).await {
|
||||
@ -330,7 +360,6 @@ impl Client {
|
||||
|
||||
/// Kicks the Client with a reason depending on the connection state
|
||||
pub fn kick(&self, reason: &str) {
|
||||
dbg!(reason);
|
||||
match *self.connection_state.lock().unwrap() {
|
||||
ConnectionState::Login => {
|
||||
self.try_send_packet(&CLoginDisconnect::new(
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
use std::sync::{atomic::AtomicBool, Arc, Mutex};
|
||||
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::ToPrimitive;
|
||||
use pumpkin_core::math::{
|
||||
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
|
||||
};
|
||||
@ -14,27 +16,44 @@ use crate::world::World;
|
||||
pub mod player;
|
||||
|
||||
pub struct Entity {
|
||||
/// A unique identifier for the entity
|
||||
pub entity_id: EntityId,
|
||||
/// The type of entity (e.g., player, zombie, item)
|
||||
pub entity_type: EntityType,
|
||||
/// The world in which the entity exists.
|
||||
pub world: Arc<World>,
|
||||
/// The entity's current health level.
|
||||
pub health: Mutex<f32>,
|
||||
|
||||
/// The entity's current position in the world
|
||||
pub pos: Mutex<Vector3<f64>>,
|
||||
/// The entity's position rounded to the nearest block coordinates
|
||||
pub block_pos: Mutex<WorldPosition>,
|
||||
/// The chunk coordinates of the entity's current position
|
||||
pub chunk_pos: Mutex<Vector2<i32>>,
|
||||
|
||||
/// Indicates whether the entity is sneaking
|
||||
pub sneaking: AtomicBool,
|
||||
/// Indicates whether the entity is sprinting
|
||||
pub sprinting: AtomicBool,
|
||||
/// Indicates whether the entity is flying due to a fall
|
||||
pub fall_flying: AtomicBool,
|
||||
/// The entity's current velocity vector, aka Knockback
|
||||
pub velocity: Mutex<Vector3<f64>>,
|
||||
|
||||
// Should be not trusted
|
||||
/// Indicates whether the entity is on the ground (may not always be accurate).
|
||||
pub on_ground: AtomicBool,
|
||||
|
||||
/// The entity's yaw rotation (horizontal rotation) ← →
|
||||
pub yaw: Mutex<f32>,
|
||||
/// The entity's head yaw rotation (horizontal rotation of the head)
|
||||
pub head_yaw: Mutex<f32>,
|
||||
/// The entity's pitch rotation (vertical rotation) ↑ ↓
|
||||
pub pitch: Mutex<f32>,
|
||||
/// The height of the entity's eyes from the ground.
|
||||
// TODO: Change this in diffrent poses
|
||||
pub standing_eye_height: f32,
|
||||
/// The entity's current pose (e.g., standing, sitting, swimming).
|
||||
pub pose: Mutex<EntityPose>,
|
||||
}
|
||||
|
||||
@ -54,6 +73,8 @@ impl Entity {
|
||||
chunk_pos: Mutex::new(Vector2::new(0, 0)),
|
||||
sneaking: AtomicBool::new(false),
|
||||
world,
|
||||
// TODO: Load this from previous instance
|
||||
health: Mutex::new(20.0),
|
||||
sprinting: AtomicBool::new(false),
|
||||
fall_flying: AtomicBool::new(false),
|
||||
yaw: Mutex::new(0.0),
|
||||
@ -65,6 +86,9 @@ impl Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the entity's position, block position, and chunk position.
|
||||
///
|
||||
/// This function calculates the new position, block position, and chunk position based on the provided coordinates. If any of these values change, the corresponding fields are updated.
|
||||
pub fn set_pos(&self, x: f64, y: f64, z: f64) {
|
||||
let mut pos = self.pos.lock().unwrap();
|
||||
if pos.x != x || pos.y != y || pos.z != z {
|
||||
@ -89,16 +113,21 @@ impl Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the Entity yaw & pitch Rotation
|
||||
pub fn set_rotation(&self, yaw: f32, pitch: f32) {
|
||||
// TODO
|
||||
*self.yaw.lock().unwrap() = yaw;
|
||||
*self.pitch.lock().unwrap() = pitch
|
||||
}
|
||||
|
||||
/// Removes the Entity from their current World
|
||||
pub async fn remove(&mut self) {
|
||||
self.world.remove_entity(self);
|
||||
}
|
||||
|
||||
/// Applies knockback to the entity, following vanilla Minecraft's mechanics.
|
||||
///
|
||||
/// This function calculates the entity's new velocity based on the specified knockback strength and direction.
|
||||
pub fn knockback(&self, strength: f64, x: f64, z: f64) {
|
||||
// This has some vanilla magic
|
||||
let mut x = x;
|
||||
@ -125,7 +154,7 @@ impl Entity {
|
||||
assert!(self.sneaking.load(std::sync::atomic::Ordering::Relaxed) != sneaking);
|
||||
self.sneaking
|
||||
.store(sneaking, std::sync::atomic::Ordering::Relaxed);
|
||||
self.set_flag(Self::SNEAKING_FLAG_INDEX, sneaking).await;
|
||||
self.set_flag(Flag::Sneaking, sneaking).await;
|
||||
// if sneaking {
|
||||
// self.set_pose(EntityPose::Crouching).await;
|
||||
// } else {
|
||||
@ -137,7 +166,7 @@ impl Entity {
|
||||
assert!(self.sprinting.load(std::sync::atomic::Ordering::Relaxed) != sprinting);
|
||||
self.sprinting
|
||||
.store(sprinting, std::sync::atomic::Ordering::Relaxed);
|
||||
self.set_flag(Self::SPRINTING_FLAG_INDEX, sprinting).await;
|
||||
self.set_flag(Flag::Sprinting, sprinting).await;
|
||||
}
|
||||
|
||||
pub fn check_fall_flying(&self) -> bool {
|
||||
@ -148,18 +177,11 @@ impl Entity {
|
||||
assert!(self.fall_flying.load(std::sync::atomic::Ordering::Relaxed) != fall_flying);
|
||||
self.fall_flying
|
||||
.store(fall_flying, std::sync::atomic::Ordering::Relaxed);
|
||||
self.set_flag(Self::FALL_FLYING_FLAG_INDEX, fall_flying)
|
||||
.await;
|
||||
self.set_flag(Flag::FallFlying, fall_flying).await;
|
||||
}
|
||||
|
||||
pub const ON_FIRE_FLAG_INDEX: u32 = 0;
|
||||
pub const SNEAKING_FLAG_INDEX: u32 = 1;
|
||||
pub const SPRINTING_FLAG_INDEX: u32 = 3;
|
||||
pub const SWIMMING_FLAG_INDEX: u32 = 4;
|
||||
pub const INVISIBLE_FLAG_INDEX: u32 = 5;
|
||||
pub const GLOWING_FLAG_INDEX: u32 = 6;
|
||||
pub const FALL_FLYING_FLAG_INDEX: u32 = 7;
|
||||
async fn set_flag(&self, index: u32, value: bool) {
|
||||
async fn set_flag(&self, flag: Flag, value: bool) {
|
||||
let index = flag.to_u32().unwrap();
|
||||
let mut b = 0i8;
|
||||
if value {
|
||||
b |= 1 << index;
|
||||
@ -180,3 +202,28 @@ impl Entity {
|
||||
self.world.broadcast_packet_all(&packet)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
/// Represents various entity flags that are sent in entity metadata.
|
||||
///
|
||||
/// These flags are used by the client to modify the rendering of entities based on their current state.
|
||||
///
|
||||
/// **Purpose:**
|
||||
///
|
||||
/// This enum provides a more type-safe and readable way to represent entity flags compared to using raw integer values.
|
||||
pub enum Flag {
|
||||
/// Indicates if the entity is on fire.
|
||||
OnFire,
|
||||
/// Indicates if the entity is sneaking.
|
||||
Sneaking,
|
||||
/// Indicates if the entity is sprinting.
|
||||
Sprinting,
|
||||
/// Indicates if the entity is swimming.
|
||||
Swimming,
|
||||
/// Indicates if the entity is invisible.
|
||||
Invisible,
|
||||
/// Indicates if the entity is glowing.
|
||||
Glowing,
|
||||
/// Indicates if the entity is flying due to a fall.
|
||||
FallFlying,
|
||||
}
|
||||
|
||||
@ -38,55 +38,49 @@ use crate::{
|
||||
|
||||
use super::Entity;
|
||||
|
||||
pub struct PlayerAbilities {
|
||||
pub invulnerable: bool,
|
||||
pub flying: bool,
|
||||
pub allow_flying: bool,
|
||||
pub creative: bool,
|
||||
pub fly_speed: f32,
|
||||
pub walk_speed_fov: f32,
|
||||
}
|
||||
|
||||
impl Default for PlayerAbilities {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
invulnerable: false,
|
||||
flying: false,
|
||||
allow_flying: false,
|
||||
creative: false,
|
||||
fly_speed: 0.5,
|
||||
walk_speed_fov: 0.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a Minecraft player entity.
|
||||
///
|
||||
/// A `Player` is a special type of entity that represents a human player connected to the server.
|
||||
pub struct Player {
|
||||
/// The underlying entity object that represents the player.
|
||||
pub entity: Entity,
|
||||
|
||||
/// The player's game profile information, including their username and UUID.
|
||||
pub gameprofile: GameProfile,
|
||||
/// The client connection associated with the player.
|
||||
pub client: Client,
|
||||
/// The player's configuration settings. Changes when the Player changes their settings.
|
||||
pub config: Mutex<PlayerConfig>,
|
||||
/// Current gamemode
|
||||
/// The player's current gamemode (e.g., Survival, Creative, Adventure).
|
||||
pub gamemode: Mutex<GameMode>,
|
||||
// TODO: prbly should put this into an Living Entitiy or something
|
||||
pub health: Mutex<f32>,
|
||||
/// The player's hunger level.
|
||||
pub food: AtomicI32,
|
||||
/// The player's food saturation level.
|
||||
pub food_saturation: Mutex<f32>,
|
||||
/// The player's inventory, containing items and equipment.
|
||||
pub inventory: Mutex<PlayerInventory>,
|
||||
/// The ID of the currently open container (if any).
|
||||
pub open_container: Mutex<Option<u64>>,
|
||||
/// The item currently being held by the player.
|
||||
pub carried_item: Mutex<Option<ItemStack>>,
|
||||
|
||||
/// send `send_abilties_update` when changed
|
||||
/// The player's abilities and special powers.
|
||||
///
|
||||
/// This field represents the various abilities that the player possesses, such as flight, invulnerability, and other special effects.
|
||||
///
|
||||
/// **Note:** When the `abilities` field is updated, the server should send a `send_abilities_update` packet to the client to notify them of the changes.
|
||||
pub abilities: PlayerAbilities,
|
||||
/// The player's last known position.
|
||||
///
|
||||
/// This field is used to calculate the player's movement delta for network synchronization and other purposes.
|
||||
pub last_position: Mutex<Vector3<f64>>,
|
||||
|
||||
/// The current stage of the block the player is breaking.
|
||||
// TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done
|
||||
pub current_block_destroy_stage: AtomicU8,
|
||||
|
||||
/// A counter for teleport IDs used to track pending teleports.
|
||||
pub teleport_id_count: AtomicI32,
|
||||
// Current awaiting teleport id and location, None if did not teleport
|
||||
/// The pending teleport information, including the teleport ID and target location.
|
||||
pub awaiting_teleport: Mutex<Option<(VarInt, Vector3<f64>)>>,
|
||||
|
||||
/// The coordinates of the chunk section the player is currently watching.
|
||||
pub watched_section: Mutex<Vector3<i32>>,
|
||||
}
|
||||
|
||||
@ -112,7 +106,6 @@ impl Player {
|
||||
client,
|
||||
awaiting_teleport: Mutex::new(None),
|
||||
// TODO: Load this from previous instance
|
||||
health: Mutex::new(20.0),
|
||||
food: AtomicI32::new(20),
|
||||
food_saturation: Mutex::new(20.0),
|
||||
current_block_destroy_stage: AtomicU8::new(0),
|
||||
@ -136,6 +129,7 @@ impl Player {
|
||||
self.entity.entity_id
|
||||
}
|
||||
|
||||
/// Updates the current abilities the Player has
|
||||
pub fn send_abilties_update(&mut self) {
|
||||
let mut b = 0i8;
|
||||
let abilities = &self.abilities;
|
||||
@ -225,7 +219,7 @@ impl Player {
|
||||
}
|
||||
|
||||
pub fn update_health(&self, health: f32, food: i32, food_saturation: f32) {
|
||||
*self.health.lock().unwrap() = health;
|
||||
*self.entity.health.lock().unwrap() = health;
|
||||
self.food.store(food, std::sync::atomic::Ordering::Relaxed);
|
||||
*self.food_saturation.lock().unwrap() = food_saturation;
|
||||
}
|
||||
@ -378,15 +372,53 @@ impl Player {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a player's abilities and special powers.
|
||||
///
|
||||
/// This struct contains information about the player's current abilities, such as flight, invulnerability, and creative mode.
|
||||
pub struct PlayerAbilities {
|
||||
/// Indicates whether the player is invulnerable to damage.
|
||||
pub invulnerable: bool,
|
||||
/// Indicates whether the player is currently flying.
|
||||
pub flying: bool,
|
||||
/// Indicates whether the player is allowed to fly (if enabled).
|
||||
pub allow_flying: bool,
|
||||
/// Indicates whether the player is in creative mode.
|
||||
pub creative: bool,
|
||||
/// The player's flying speed.
|
||||
pub fly_speed: f32,
|
||||
/// The field of view adjustment when the player is walking or sprinting.
|
||||
pub walk_speed_fov: f32,
|
||||
}
|
||||
|
||||
impl Default for PlayerAbilities {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
invulnerable: false,
|
||||
flying: false,
|
||||
allow_flying: false,
|
||||
creative: false,
|
||||
fly_speed: 0.5,
|
||||
walk_speed_fov: 0.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the player's dominant hand.
|
||||
#[derive(FromPrimitive, Clone)]
|
||||
pub enum Hand {
|
||||
/// The player's primary hand (usually the right hand).
|
||||
Main,
|
||||
/// The player's off-hand (usually the left hand).
|
||||
Off,
|
||||
}
|
||||
|
||||
/// Represents the player's chat mode settings.
|
||||
#[derive(FromPrimitive, Clone)]
|
||||
pub enum ChatMode {
|
||||
/// Chat is enabled for the player.
|
||||
Enabled,
|
||||
/// The player should only see chat messages from commands
|
||||
CommandsOnly,
|
||||
/// All messages should be hidden
|
||||
Hidden,
|
||||
}
|
||||
|
||||
@ -169,11 +169,8 @@ fn main() -> io::Result<()> {
|
||||
}
|
||||
if closed {
|
||||
if let Some(player) = players.remove(&token) {
|
||||
dbg!("a");
|
||||
player.remove().await;
|
||||
dbg!("b");
|
||||
let connection = &mut player.client.connection.lock().unwrap();
|
||||
dbg!("c");
|
||||
|
||||
poll.registry().deregister(connection.by_ref())?;
|
||||
}
|
||||
|
||||
@ -161,7 +161,8 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
// move to world
|
||||
/// Generates a new entity id
|
||||
/// This should be global
|
||||
pub fn new_entity_id(&self) -> EntityId {
|
||||
self.entity_id.fetch_add(1, Ordering::SeqCst)
|
||||
}
|
||||
@ -191,20 +192,22 @@ impl Server {
|
||||
};
|
||||
|
||||
StatusResponse {
|
||||
version: Version {
|
||||
version: Some(Version {
|
||||
name: CURRENT_MC_VERSION.into(),
|
||||
protocol: CURRENT_MC_PROTOCOL,
|
||||
},
|
||||
players: Players {
|
||||
}),
|
||||
players: Some(Players {
|
||||
max: config.max_players,
|
||||
online: 0,
|
||||
sample: vec![Sample {
|
||||
name: "".into(),
|
||||
id: "".into(),
|
||||
}],
|
||||
},
|
||||
}),
|
||||
description: config.motd.clone(),
|
||||
favicon: icon,
|
||||
// TODO
|
||||
enforece_secure_chat: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,10 +26,21 @@ use crate::{
|
||||
entity::{player::Player, Entity},
|
||||
};
|
||||
|
||||
/// Represents a Minecraft world, containing entities, players, and the underlying level data.
|
||||
///
|
||||
/// Each dimension (Overworld, Nether, End) typically has its own `World`.
|
||||
///
|
||||
/// **Key Responsibilities:**
|
||||
///
|
||||
/// - Manages the `Level` instance for handling chunk-related operations.
|
||||
/// - Stores and tracks active `Player` entities within the world.
|
||||
/// - Provides a central hub for interacting with the world's entities and environment.
|
||||
pub struct World {
|
||||
/// The underlying level, responsible for chunk management and terrain generation.
|
||||
pub level: Arc<Mutex<Level>>,
|
||||
/// A map of active players within the world, keyed by their unique token.
|
||||
pub current_players: Arc<Mutex<HashMap<Token, Arc<Player>>>>,
|
||||
// entities, players...
|
||||
// TODO: entities
|
||||
}
|
||||
|
||||
impl World {
|
||||
@ -40,7 +51,11 @@ impl World {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a Packet to all Players in the World
|
||||
/// Broadcasts a packet to all connected players within the world.
|
||||
///
|
||||
/// Sends the specified packet to every player currently logged in to the server.
|
||||
///
|
||||
/// **Note:** This function acquires a lock on the `current_players` map, ensuring thread safety.
|
||||
pub fn broadcast_packet_all<P>(&self, packet: &P)
|
||||
where
|
||||
P: ClientPacket,
|
||||
@ -51,7 +66,11 @@ impl World {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a Packet to all Players in the World, Expect the Players given the the expect parameter
|
||||
/// Broadcasts a packet to all connected players within the world, excluding the specified players.
|
||||
///
|
||||
/// Sends the specified packet to every player currently logged in to the server, excluding the players listed in the `except` parameter.
|
||||
///
|
||||
/// **Note:** This function acquires a lock on the `current_players` map, ensuring thread safety.
|
||||
pub fn broadcast_packet_expect<P>(&self, except: &[Token], packet: &P)
|
||||
where
|
||||
P: ClientPacket,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user