From 9b30f1454763526a7e6ba5cd393f39abf02db30c Mon Sep 17 00:00:00 2001 From: Andrew Gazelka Date: Thu, 31 Oct 2024 21:47:06 -0700 Subject: [PATCH] feat: add meta to flecs components - also manually register components --- Cargo.toml | 1 + crates/hyperion-permission/src/lib.rs | 2 + crates/hyperion/Cargo.toml | 1 + crates/hyperion/src/egress/mod.rs | 4 +- crates/hyperion/src/egress/sync_chunks.rs | 9 ++- crates/hyperion/src/ingress/mod.rs | 8 +- crates/hyperion/src/lib.rs | 49 +++++++++--- crates/hyperion/src/simulation/mod.rs | 74 ++++++++++++++++--- events/proof-of-concept/src/module/attack.rs | 9 +++ events/proof-of-concept/src/module/block.rs | 1 + events/proof-of-concept/src/module/level.rs | 2 + .../src/module/regeneration.rs | 3 + 12 files changed, 137 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 41a3c3e0..8f598cd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,6 +109,7 @@ default-features = false version = '1.0.30' [workspace.dependencies.flecs_ecs] +features = ["flecs_manual_registration"] git = 'https://github.com/Indra-db/Flecs-Rust' [workspace.dependencies.hyperion] diff --git a/crates/hyperion-permission/src/lib.rs b/crates/hyperion-permission/src/lib.rs index 49f5eda7..12df7d17 100644 --- a/crates/hyperion-permission/src/lib.rs +++ b/crates/hyperion-permission/src/lib.rs @@ -98,6 +98,8 @@ pub fn parse_perms_command(input: &str) -> IResult<&str, Command<'_>> { impl Module for PermissionModule { fn module(world: &World) { + world.component::(); + world.component::(); cmd_with(world, "perms", |scope| { scope.literal_with("set", |scope| { scope.argument_with( diff --git a/crates/hyperion/Cargo.toml b/crates/hyperion/Cargo.toml index e7991998..d754ccc6 100644 --- a/crates/hyperion/Cargo.toml +++ b/crates/hyperion/Cargo.toml @@ -35,6 +35,7 @@ fastrand.workspace = true flecs_ecs.workspace = true heapless.workspace = true heed.workspace = true +hex.workspace = true hyperion-crafting.workspace = true hyperion-event-macros.workspace = true hyperion-inventory.workspace = true diff --git a/crates/hyperion/src/egress/mod.rs b/crates/hyperion/src/egress/mod.rs index dd085d0e..3e3799d8 100644 --- a/crates/hyperion/src/egress/mod.rs +++ b/crates/hyperion/src/egress/mod.rs @@ -118,8 +118,8 @@ impl Module for EgressModule { stream.push(io.inner()); let position = hyperion_proto::ChunkPosition { - x: i16::try_from(pos.0.x).unwrap(), - z: i16::try_from(pos.0.y).unwrap(), + x: i16::try_from(pos.position.x).unwrap(), + z: i16::try_from(pos.position.y).unwrap(), }; positions.push(position); diff --git a/crates/hyperion/src/egress/sync_chunks.rs b/crates/hyperion/src/egress/sync_chunks.rs index 4bf7746f..df5786a3 100644 --- a/crates/hyperion/src/egress/sync_chunks.rs +++ b/crates/hyperion/src/egress/sync_chunks.rs @@ -21,6 +21,7 @@ use crate::{ }; #[derive(Component, Deref, DerefMut, Default)] +#[meta] pub struct ChunkSendQueue { changes: Vec, } @@ -30,7 +31,9 @@ pub struct SyncChunksModule; impl Module for SyncChunksModule { fn module(world: &World) { - world.component::(); + meta_register_vector_type!(world, IVec2 { x: 0, y: 0 }); + + world.component::().meta(); let radius = world.get::<&Config>(|config| config.view_distance); let liberal_radius = radius + 2; @@ -54,7 +57,7 @@ impl Module for SyncChunksModule { move |entity, (compose, last_sent, pose, &stream_id, chunk_changes)| { let world = entity.world(); - let last_sent_chunk = last_sent.0; + let last_sent_chunk = last_sent.position; let current_chunk = pose.to_chunk(); @@ -76,7 +79,7 @@ impl Module for SyncChunksModule { return; } - last_sent.0 = current_chunk; + last_sent.position = current_chunk; let last_sent_range_x = (last_sent_chunk.x - radius)..(last_sent_chunk.x + radius); let last_sent_range_z = (last_sent_chunk.y - radius)..(last_sent_chunk.y + radius); diff --git a/crates/hyperion/src/ingress/mod.rs b/crates/hyperion/src/ingress/mod.rs index f666f791..fd066a77 100644 --- a/crates/hyperion/src/ingress/mod.rs +++ b/crates/hyperion/src/ingress/mod.rs @@ -165,6 +165,11 @@ fn process_login( ign_map.insert(username.clone(), entity.id(), world); + // first 4 bytes of the uuid + let uuid_short = hex::encode(&uuid.as_bytes()[0..4]); + + let name = format!("{username}-{uuid_short}"); + entity .set(InGameName::from(username)) .add::() @@ -173,7 +178,8 @@ fn process_login( .set(Health::default()) .set(ChunkSendQueue::default()) .set(ChunkPosition::null()) - .set(EntityReaction::default()); + .set(EntityReaction::default()) + .set_name(&name); compose.io_buf().set_receive_broadcasts(stream_id, world); diff --git a/crates/hyperion/src/lib.rs b/crates/hyperion/src/lib.rs index 8b4d0461..c1a1729b 100644 --- a/crates/hyperion/src/lib.rs +++ b/crates/hyperion/src/lib.rs @@ -46,6 +46,7 @@ use derive_more::{Deref, DerefMut}; use egress::EgressModule; use flecs_ecs::prelude::*; pub use glam; +use glam::IVec2; use ingress::IngressModule; #[cfg(unix)] use libc::{getrlimit, setrlimit, RLIMIT_NOFILE}; @@ -77,7 +78,9 @@ pub use valence_ident; pub use crate::simulation::command::CommandScope; use crate::{ - simulation::{EntitySize, IgnMap, Player}, + ingress::PendingRemove, + net::{proxy::ReceiveState, NetworkStreamRef, PacketDecoder}, + simulation::{EgressComm, EntitySize, IgnMap, PacketState, Player}, util::mojang::ApiProvider, }; @@ -192,7 +195,7 @@ impl Hyperion { let world = World::new(); let world = Box::new(world); - let world = Box::leak(world); + let world: &World = Box::leak(world); let mut app = world.app(); @@ -208,20 +211,37 @@ impl Hyperion { .next() .context("could not get first address")?; + component!(world, IVec2 { x: i32, y: i32 }); + world.component::(); + + world.component::(); + component!(world, Yaw).opaque_func(meta_ser_stringify_type_display::); + + world.component::(); + component!(world, Pitch).opaque_func(meta_ser_stringify_type_display::); + + world.component::(); + + world.component::(); + + world.component::(); + world.component::(); + world.component::(); + world.component::(); + world.component::(); world.component::(); world.component::(); world.component::(); - + world.component::(); + world.component::(); + world.component::(); + world.component::(); + world.component::(); world.component::(); + world.component::(); - world.set(IgnMap::default()); - - world - .component::() - .add_trait::<(flecs::With, EntitySize)>() - .add_trait::<(flecs::With, Yaw)>() - .add_trait::<(flecs::With, Pitch)>(); + world.component::(); info!("starting hyperion"); let config = config::Config::load("run/config.toml")?; @@ -229,6 +249,7 @@ impl Hyperion { let runtime = AsyncRuntime::default(); + world.component::(); world.set(GlobalEventHandlers::default()); info!("initializing database"); @@ -277,6 +298,14 @@ impl Hyperion { world.import::(); world.import::(); + world + .component::() + .add_trait::<(flecs::With, EntitySize)>() + .add_trait::<(flecs::With, Yaw)>() + .add_trait::<(flecs::With, Pitch)>(); + + world.set(IgnMap::default()); + handlers(world); app.run(); diff --git a/crates/hyperion/src/simulation/mod.rs b/crates/hyperion/src/simulation/mod.rs index 0f3926fd..48b608a7 100644 --- a/crates/hyperion/src/simulation/mod.rs +++ b/crates/hyperion/src/simulation/mod.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use skin::PlayerSkin; use uuid; -use crate::{storage::ThreadLocalVec, Global}; +use crate::{simulation::command::Command, storage::ThreadLocalVec, Global}; pub mod animation; pub mod blocks; @@ -116,7 +116,9 @@ impl DeferredMap { } /// The in-game name of a player. +/// todo: fix the meta #[derive(Component, Deref, From, Display, Debug)] +#[meta] pub struct InGameName(Arc); #[derive(Component, Deref, DerefMut, From, Debug, Default)] @@ -156,6 +158,7 @@ pub enum PacketState { /// This method restores the entity to full health and allows it to be affected /// by subsequent health changes. #[derive(Component, Debug, PartialEq)] +#[meta] pub struct Health { value: f32, @@ -272,6 +275,7 @@ impl Default for Health { #[derive(Component, Debug, Eq, PartialEq, Default)] #[expect(missing_docs)] +#[meta] pub struct ImmuneStatus { /// The tick until the player is immune to player attacks. pub until: i64, @@ -339,6 +343,7 @@ pub struct AiTargetable; DerefMut, From )] +#[meta] pub struct Position { /// The (x, y, z) position of the entity. /// Note we are using [`Vec3`] instead of [`glam::DVec3`] because *cache locality* is important. @@ -351,6 +356,20 @@ pub struct Yaw { yaw: f16, } +impl Display for Yaw { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let yaw = self.yaw as f32; + write!(f, "{yaw}") + } +} + +impl Display for Pitch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let pitch = self.pitch as f32; + write!(f, "{pitch}") + } +} + #[derive(Component, Copy, Clone, Debug, Deref, DerefMut, Default)] pub struct Pitch { pitch: f16, @@ -359,12 +378,21 @@ pub struct Pitch { const PLAYER_WIDTH: f16 = 0.6; const PLAYER_HEIGHT: f16 = 1.8; -#[derive(Component, Copy, Clone)] +#[derive(Component, Copy, Clone, Debug)] +#[meta] pub struct EntitySize { pub half_width: f16, pub height: f16, } +impl Display for EntitySize { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let half_width = self.half_width as f32; + let height = self.height as f32; + write!(f, "{half_width}x{height}") + } +} + impl Default for EntitySize { fn default() -> Self { Self { @@ -383,8 +411,10 @@ impl Position { } #[derive(Component, Debug, Copy, Clone)] -#[expect(missing_docs)] -pub struct ChunkPosition(pub IVec2); +#[meta] +pub struct ChunkPosition { + pub position: IVec2, +} const SANE_MAX_RADIUS: i32 = 128; @@ -393,7 +423,9 @@ impl ChunkPosition { #[expect(missing_docs)] pub const fn null() -> Self { // todo: huh - Self(IVec2::new(SANE_MAX_RADIUS, SANE_MAX_RADIUS)) + Self { + position: IVec2::new(SANE_MAX_RADIUS, SANE_MAX_RADIUS), + } } } @@ -441,6 +473,7 @@ impl Position { /// - Therefore, we have an [`EntityReaction`] component which is used to store the reaction of an entity to collisions. /// - Later we can apply the reaction to the entity's [`Position`] to move the entity. #[derive(Component, Default, Debug)] +#[meta] pub struct EntityReaction { /// The velocity of the entity. pub velocity: Vec3, @@ -451,15 +484,36 @@ pub struct SimModule; impl Module for SimModule { fn module(world: &World) { - world.component::(); + world.component::(); + world.component::(); + + component!(world, EntitySize).opaque_func(meta_ser_stringify_type_display::); + component!(world, IVec3 { + x: i32, + y: i32, + z: i32 + }); + component!(world, Vec3 { + x: f32, + y: f32, + z: f32 + }); + + component!(world, IgnMap); + + world.component::().meta(); + world.component::(); + world.component::(); + component!(world, InGameName).opaque_func(meta_ser_stringify_type_display::); + world.component::(); - world.component::(); + world.component::().meta(); world.component::(); - world.component::(); - world.component::(); - world.component::(); + world.component::().meta(); + world.component::().meta(); + world.component::().meta(); world.component::(); world.component::(); world.component::(); diff --git a/events/proof-of-concept/src/module/attack.rs b/events/proof-of-concept/src/module/attack.rs index 1c5ae7c1..fbd2826b 100644 --- a/events/proof-of-concept/src/module/attack.rs +++ b/events/proof-of-concept/src/module/attack.rs @@ -42,17 +42,20 @@ use tracing::trace_span; pub struct AttackModule; #[derive(Component, Default, Copy, Clone, Debug)] +#[meta] pub struct ImmuneUntil { tick: i64, } #[derive(Component, Default, Copy, Clone, Debug)] +#[meta] pub struct Armor { pub armor: f32, } // Used as a component only for commands, does not include armor or weapons #[derive(Component, Default, Copy, Clone, Debug)] +#[meta] pub struct CombatStats { pub armor: f32, pub armor_toughness: f32, @@ -61,6 +64,7 @@ pub struct CombatStats { } #[derive(Component, Default, Copy, Clone, Debug)] +#[meta] pub struct KillCount { pub kill_count: u32, } @@ -68,6 +72,11 @@ pub struct KillCount { impl Module for AttackModule { #[allow(clippy::excessive_nesting)] fn module(world: &World) { + world.component::().meta(); + world.component::().meta(); + world.component::().meta(); + world.component::().meta(); + world .component::() .add_trait::<(flecs::With, ImmuneUntil)>() diff --git a/events/proof-of-concept/src/module/block.rs b/events/proof-of-concept/src/module/block.rs index 1fd94913..2baf2af5 100644 --- a/events/proof-of-concept/src/module/block.rs +++ b/events/proof-of-concept/src/module/block.rs @@ -49,6 +49,7 @@ impl Module for BlockModule { fn module(world: &World) { const TOTAL_DESTRUCTION_TIME: Duration = Duration::from_secs(30); + world.component::(); world.set(PendingDestruction::default()); system!("handle_pending_air", world, &mut PendingDestruction($), &mut Blocks($), &Compose($)) diff --git a/events/proof-of-concept/src/module/level.rs b/events/proof-of-concept/src/module/level.rs index 97f06873..f74e93b8 100644 --- a/events/proof-of-concept/src/module/level.rs +++ b/events/proof-of-concept/src/module/level.rs @@ -9,6 +9,7 @@ use hyperion::simulation::Player; pub struct LevelModule; #[derive(Component, Default, Copy, Clone, Debug)] +#[meta] pub struct Level { pub value: usize, } @@ -16,6 +17,7 @@ pub struct Level { impl Module for LevelModule { #[allow(clippy::excessive_nesting)] fn module(world: &World) { + world.component::().meta(); world .component::() .add_trait::<(flecs::With, Level)>(); // todo: how does this even call Default? (IndraDb) diff --git a/events/proof-of-concept/src/module/regeneration.rs b/events/proof-of-concept/src/module/regeneration.rs index 6f137172..1143fe94 100644 --- a/events/proof-of-concept/src/module/regeneration.rs +++ b/events/proof-of-concept/src/module/regeneration.rs @@ -12,6 +12,7 @@ use hyperion::{ pub struct RegenerationModule; #[derive(Component, Default, Copy, Clone, Debug)] +#[meta] pub struct LastDamaged { pub tick: i64, } @@ -19,6 +20,8 @@ pub struct LastDamaged { impl Module for RegenerationModule { #[allow(clippy::excessive_nesting)] fn module(world: &World) { + world.component::().meta(); + world .component::() .add_trait::<(flecs::With, LastDamaged)>(); // todo: how does this even call Default? (IndraDb)