diff --git a/Cargo.toml b/Cargo.toml index 88792e6e..70e95684 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ members = [ ] [workspace.package] -edition = "2021" +edition = "2024" version = "0.1.1" #================== Lints ==================# diff --git a/src/blocks/crates/property/src/lib.rs b/src/blocks/crates/property/src/lib.rs index 96c7c4dd..ad161e3a 100644 --- a/src/blocks/crates/property/src/lib.rs +++ b/src/blocks/crates/property/src/lib.rs @@ -97,7 +97,7 @@ impl BlockStateProperty for bool {} #[macro_export] macro_rules! enum_property { ($name:ident, $($variant:ident => $variant_str:expr),* $(,)?) => { - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq)] pub enum $name { $($variant),* } diff --git a/src/blocks/crates/property/src/simple.rs b/src/blocks/crates/property/src/simple.rs index 0f2039fd..e86e73cb 100644 --- a/src/blocks/crates/property/src/simple.rs +++ b/src/blocks/crates/property/src/simple.rs @@ -66,6 +66,59 @@ enum_property!( West => "west", ); +impl Direction { + pub fn from_yaw(yaw: f32) -> Self { + let index = ((yaw / 90.0 + 0.5).floor() as i32).rem_euclid(4); + match index { + 0 => Self::South, + 1 => Self::West, + 2 => Self::North, + 3 => Self::East, + _ => unreachable!(), + } + } + + pub fn axis(&self) -> Axis { + match self { + Self::East | Self::West => Axis::X, + Self::Up | Self::Down => Axis::Y, + Self::North | Self::South => Axis::Z, + } + } + + pub fn get_normal(&self) -> bevy_math::IVec3 { + match self { + Self::Up => bevy_math::IVec3::new(0, 1, 0), + Self::Down => bevy_math::IVec3::new(0, -1, 0), + Self::North => bevy_math::IVec3::new(0, 0, -1), + Self::South => bevy_math::IVec3::new(0, 0, 1), + Self::East => bevy_math::IVec3::new(1, 0, 0), + Self::West => bevy_math::IVec3::new(-1, 0, 0), + } + } + + pub fn opposite(&self) -> Self { + match self { + Self::Up => Self::Down, + Self::Down => Self::Up, + Self::North => Self::South, + Self::South => Self::North, + Self::East => Self::West, + Self::West => Self::East, + } + } + + pub fn rotate_y_counter_clockwise(&self) -> Self { + match self { + Self::North => Self::West, + Self::East => Self::North, + Self::South => Self::East, + Self::West => Self::South, + _ => self.clone(), + } + } +} + enum_property!( DoorHingeSide, Left => "left", diff --git a/src/blocks/src/building/stairs.rs b/src/blocks/src/building/stairs.rs index 41d85074..e07a98f3 100644 --- a/src/blocks/src/building/stairs.rs +++ b/src/blocks/src/building/stairs.rs @@ -1,4 +1,105 @@ -use crate::BlockBehavior; +use crate::{BlockBehavior, world_extensions::WorldBlockUpdates}; +use temper_block_data::{PlacedBlocks, PlacementContext}; +use temper_block_properties::{Direction, Half, StairsShape}; use temper_blocks_generated::StairsBlock; +use temper_core::{block_face::BlockFace, block_state_id::BlockStateId, pos::BlockPos}; +use temper_macros::match_block; +use temper_world::{Dimension, World}; -impl BlockBehavior for StairsBlock {} +fn is_different_orientation( + level: &World, + block: &StairsBlock, + block_pos: BlockPos, + direction: &Direction, + dimension: Dimension, +) -> bool { + if let Some(other_block) = + level.try_get_block::(block_pos + direction.get_normal(), dimension) + { + other_block.facing != block.facing || other_block.half != block.half + } else { + true + } +} + +fn get_shape( + block: &StairsBlock, + level: &World, + block_pos: BlockPos, + dimension: Dimension, +) -> StairsShape { + let offset_block_pos = block_pos + block.facing.get_normal(); + let opposite_offset_block_pos = block_pos + block.facing.opposite().get_normal(); + + if let Some(offset_block) = level.try_get_block::(offset_block_pos, dimension) + && block.half == offset_block.half + && offset_block.facing.axis() != block.facing.axis() + && is_different_orientation( + level, + block, + block_pos, + &offset_block.facing.opposite(), + dimension, + ) + { + return if offset_block.facing == block.facing.rotate_y_counter_clockwise() { + StairsShape::OuterLeft + } else { + StairsShape::OuterRight + }; + } + + if let Some(opposite_offset_block) = + level.try_get_block::(opposite_offset_block_pos, dimension) + && block.half == opposite_offset_block.half + && opposite_offset_block.facing.axis() != block.facing.axis() + && is_different_orientation( + level, + block, + block_pos, + &opposite_offset_block.facing, + dimension, + ) + { + return if opposite_offset_block.facing == block.facing.rotate_y_counter_clockwise() { + StairsShape::InnerLeft + } else { + StairsShape::InnerRight + }; + } + + StairsShape::Straight +} + +impl BlockBehavior for StairsBlock { + fn get_placement_state(&mut self, context: PlacementContext) -> PlacedBlocks { + let block = context + .level + .get_chunk(context.block_pos.chunk(), context.dimension) + .map(|c| c.get_block(context.block_pos.chunk_block_pos())) + .unwrap_or(BlockStateId::new(0)); + + self.waterlogged = match_block!("water", block); + + self.half = match context.face { + BlockFace::Top => Half::Bottom, + BlockFace::Bottom => Half::Top, + _ => { + if context.cursor.y > 0.5 { + Half::Top + } else { + Half::Bottom + } + } + }; + self.facing = Direction::from_yaw(context.player_rotation.yaw); + self.shape = get_shape(self, context.level, context.block_pos, context.dimension); + + PlacedBlocks::default() + } + + fn update(&mut self, world: &World, pos: BlockPos) -> bool { + self.shape = get_shape(self, world, pos, Dimension::Overworld); + false + } +} diff --git a/src/blocks/src/decorative/door.rs b/src/blocks/src/decorative/door.rs index d51c3ccb..288330ab 100644 --- a/src/blocks/src/decorative/door.rs +++ b/src/blocks/src/decorative/door.rs @@ -1,5 +1,5 @@ -use crate::world_extensions::WorldBlockUpdates; use crate::BlockBehavior; +use crate::world_extensions::WorldBlockUpdates; use std::collections::HashMap; use temper_block_data::{BlockUpdates, BrokenBlocks, PlacedBlocks, PlacementContext}; use temper_block_properties::{Direction, DoorHingeSide, DoubleBlockHalf}; @@ -17,16 +17,7 @@ impl BlockBehavior for DoorBlock { BlockFace::South => Direction::North, BlockFace::East => Direction::West, BlockFace::West => Direction::East, - BlockFace::Top => { - let yaw = (context.player_rotation.yaw + 180.0) % 360.0; - - match yaw { - 45.0..135.0 => Direction::East, - 135.0..225.0 => Direction::South, - 225.0..315.0 => Direction::West, - _ => Direction::North, - } - } + BlockFace::Top => Direction::from_yaw(context.player_rotation.yaw), _ => { error!("Invalid block face clicked"); return PlacedBlocks::default(); // TODO: should return None or Err in the future diff --git a/src/blocks/src/decorative/fence_pane.rs b/src/blocks/src/decorative/fence_pane.rs index c145211b..1723eabd 100644 --- a/src/blocks/src/decorative/fence_pane.rs +++ b/src/blocks/src/decorative/fence_pane.rs @@ -29,7 +29,7 @@ impl BlockBehavior for FenceAndPaneBlock { &mut self.south, &mut self.west, ]) { - let pos = context.block_pos + IVec3::new(*dx, 0, *dz).into(); + let pos = context.block_pos + IVec3::new(*dx, 0, *dz); let block = context .level .get_block(pos, context.dimension) @@ -61,7 +61,7 @@ impl BlockBehavior for FenceAndPaneBlock { &mut self.south, &mut self.west, ]) { - let pos = pos + IVec3::new(*dx, 0, *dz).into(); + let pos = pos + IVec3::new(*dx, 0, *dz); let block = world .get_block(pos, Dimension::Overworld) .unwrap_or_default(); diff --git a/src/blocks/src/world_extensions.rs b/src/blocks/src/world_extensions.rs index 839b7664..eeae965f 100644 --- a/src/blocks/src/world_extensions.rs +++ b/src/blocks/src/world_extensions.rs @@ -1,4 +1,5 @@ use crate::BlockBehavior; +use crate::behavior_trait::BlockDispatch; use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::BlockPos; @@ -20,6 +21,12 @@ pub trait WorldBlockUpdates { block_pos: BlockPos, callback: impl Fn(T) -> bool, ) -> bool; + + fn try_get_block( + &self, + block_pos: BlockPos, + dimension: Dimension, + ) -> Option; } impl WorldBlockUpdates for World { @@ -61,4 +68,15 @@ impl WorldBlockUpdates for World { }) .unwrap_or_default() } + + fn try_get_block( + &self, + block_pos: BlockPos, + dimension: Dimension, + ) -> Option { + self.get_chunk(block_pos.chunk(), dimension) + .map(|c| c.get_block(block_pos.chunk_block_pos())) + .unwrap_or(BlockStateId::new(0)) + .try_cast::() + } } diff --git a/src/core/src/block_face.rs b/src/core/src/block_face.rs index 632b4073..2a9412f4 100644 --- a/src/core/src/block_face.rs +++ b/src/core/src/block_face.rs @@ -16,26 +16,37 @@ pub enum BlockFace { impl BlockFace { pub fn is_x_axis(&self) -> bool { - matches!(self, BlockFace::East | BlockFace::West) + matches!(self, Self::East | Self::West) } pub fn is_y_axis(&self) -> bool { - matches!(self, BlockFace::Top | BlockFace::Bottom) + matches!(self, Self::Top | Self::Bottom) } pub fn is_z_axis(&self) -> bool { - matches!(self, BlockFace::North | BlockFace::South) + matches!(self, Self::North | Self::South) } /// Returns the translation vector that will get the block that touches this face. pub fn get_normal(&self) -> IVec3 { match self { - BlockFace::Top => IVec3::new(0, 1, 0), - BlockFace::Bottom => IVec3::new(0, -1, 0), - BlockFace::North => IVec3::new(0, 0, -1), - BlockFace::South => IVec3::new(0, 0, 1), - BlockFace::East => IVec3::new(1, 0, 0), - BlockFace::West => IVec3::new(-1, 0, 0), + Self::Top => IVec3::new(0, 1, 0), + Self::Bottom => IVec3::new(0, -1, 0), + Self::North => IVec3::new(0, 0, -1), + Self::South => IVec3::new(0, 0, 1), + Self::East => IVec3::new(1, 0, 0), + Self::West => IVec3::new(-1, 0, 0), + } + } + + pub fn opposite(&self) -> BlockFace { + match self { + Self::Top => Self::Bottom, + Self::Bottom => Self::Bottom, + Self::North => Self::South, + Self::South => Self::North, + Self::East => Self::West, + Self::West => Self::East, } } } diff --git a/src/core/src/pos.rs b/src/core/src/pos.rs index f22ca563..91719527 100644 --- a/src/core/src/pos.rs +++ b/src/core/src/pos.rs @@ -104,6 +104,16 @@ impl Add<(i32, i32, i32)> for BlockPos { } } +impl Add for BlockPos { + type Output = BlockPos; + + fn add(self, rhs: IVec3) -> Self::Output { + Self { + pos: self.pos + rhs, + } + } +} + #[derive(Clone, Copy, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct ChunkHeight { pub min_y: i16, diff --git a/src/game_systems/src/lib.rs b/src/game_systems/src/lib.rs index 9ebc6076..96e7dc32 100644 --- a/src/game_systems/src/lib.rs +++ b/src/game_systems/src/lib.rs @@ -2,7 +2,7 @@ use bevy_ecs::prelude::ApplyDeferred; use bevy_ecs::schedule::{ExecutorKind, IntoScheduleConfigs, Schedule, SystemSet}; use std::time::Duration; use temper_commands::infrastructure::register_command_systems; -use temper_scheduler::{drain_registered_schedules, MissedTickBehavior, Scheduler, TimedSchedule}; +use temper_scheduler::{MissedTickBehavior, Scheduler, TimedSchedule, drain_registered_schedules}; pub use background::lan_pinger::LanPinger; use temper_state::GlobalState; diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 383fe20e..2debd77e 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -123,8 +123,7 @@ pub fn handle( (event.cursor_x * 2.0 - 1.0) as i32, (event.cursor_y * 2.0 - 1.0) as i32, (event.cursor_z * 2.0 - 1.0) as i32, - ) - .into(); + ); let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) else { diff --git a/src/game_systems/tests/mobs/chunk_visibility_lifecycle.rs b/src/game_systems/tests/mobs/chunk_visibility_lifecycle.rs index 53b5e4b6..69468650 100644 --- a/src/game_systems/tests/mobs/chunk_visibility_lifecycle.rs +++ b/src/game_systems/tests/mobs/chunk_visibility_lifecycle.rs @@ -12,10 +12,10 @@ use temper_components::player::player_marker::PlayerMarker; use temper_components::player::position::Position; use temper_core::dimension::Dimension; use temper_core::pos::ChunkPos; +use temper_entities::MobKind; use temper_entities::entity_types::EntityTypeEnum; use temper_entities::markers::entity_types::{Fox, Pig}; use temper_entities::markers::{HasCollisions, HasGravity, HasWaterDrag}; -use temper_entities::MobKind; use temper_entities::{FoxBundle, PigBundle}; use temper_messages::chunk_calc::ChunkCalc; use temper_messages::load_chunk_entities::LoadChunkEntities; diff --git a/src/game_systems/tests/mobs/entity_persistence.rs b/src/game_systems/tests/mobs/entity_persistence.rs index e8f87d41..468087a8 100644 --- a/src/game_systems/tests/mobs/entity_persistence.rs +++ b/src/game_systems/tests/mobs/entity_persistence.rs @@ -15,12 +15,12 @@ use temper_entities::entity_types::EntityTypeEnum; use temper_entities::markers::entity_types::{Cow, Fox, Pig}; use temper_entities::markers::{HasCollisions, HasGravity, HasWaterDrag}; use temper_entities::{CowBundle, FoxBundle, MobBundle, MobKind, PigBundle}; +use temper_messages::SpawnMobCommand; use temper_messages::load_chunk_entities::LoadChunkEntities; use temper_messages::save_chunk_entities::SaveChunkEntities; -use temper_messages::SpawnMobCommand; use temper_resources::world_sync_tracker::WorldSyncTracker; use temper_scheduler::Scheduler; -use temper_state::{create_test_state, GlobalStateResource}; +use temper_state::{GlobalStateResource, create_test_state}; fn emit_save_for( chunk: temper_core::pos::ChunkPos, @@ -147,7 +147,7 @@ fn run_registered_shutdown_schedule(world: &mut World) { let mut timed = Scheduler::new(); let mut shutdown_schedule = Schedule::default(); let state = create_test_state(); - temper_game_systems::register_schedules(&mut timed, &mut shutdown_schedule, state.0 .0); + temper_game_systems::register_schedules(&mut timed, &mut shutdown_schedule, state.0.0); shutdown_schedule.run(world); } diff --git a/src/game_systems/tests/mobs/player_distance_reload.rs b/src/game_systems/tests/mobs/player_distance_reload.rs index 3d293c94..c9b2877a 100644 --- a/src/game_systems/tests/mobs/player_distance_reload.rs +++ b/src/game_systems/tests/mobs/player_distance_reload.rs @@ -13,11 +13,11 @@ use temper_components::player::player_marker::PlayerMarker; use temper_components::player::position::Position; use temper_core::dimension::Dimension; use temper_core::pos::ChunkPos; +use temper_entities::FoxBundle; +use temper_entities::MobKind; use temper_entities::entity_types::EntityTypeEnum; use temper_entities::markers::entity_types::Fox; use temper_entities::markers::{HasCollisions, HasGravity, HasWaterDrag}; -use temper_entities::FoxBundle; -use temper_entities::MobKind; use temper_messages::chunk_calc::ChunkCalc; use temper_messages::load_chunk_entities::LoadChunkEntities; use temper_state::create_test_state; diff --git a/src/game_systems/tests/mobs/spawn_mob_bundle.rs b/src/game_systems/tests/mobs/spawn_mob_bundle.rs index b23147e7..0c9d54dd 100644 --- a/src/game_systems/tests/mobs/spawn_mob_bundle.rs +++ b/src/game_systems/tests/mobs/spawn_mob_bundle.rs @@ -1,7 +1,7 @@ use bevy_ecs::prelude::*; use mobs::pig::tick_pig; use mobs::spawn::{handle_despawn_mob, handle_spawn_mob_bundle}; -use pathfinding::{pos_to_block, Pathfinder, PathfinderSearch}; +use pathfinding::{Pathfinder, PathfinderSearch, pos_to_block}; use std::collections::HashMap; use temper_components::bossbar::BossbarOwner; use temper_components::entity_identity::Identity; @@ -12,16 +12,16 @@ use temper_components::player::player_marker::PlayerMarker; use temper_components::player::position::Position; use temper_components::player::velocity::Velocity; use temper_core::dimension::Dimension; +use temper_entities::MobBundle; use temper_entities::entity_types::EntityTypeEnum; use temper_entities::markers::entity_types::{Axolotl, Bat, Cow, Fox, Pig, Warden}; use temper_entities::markers::{HasCollisions, HasGravity, HasWaterDrag}; use temper_entities::mob_definition::MobProfile; -use temper_entities::MobBundle; use temper_entities::{ AxolotlBundle, BatBundle, CowBundle, FoxBundle, MobKind, PigBundle, WardenBundle, }; use temper_messages::{DespawnMob, SpawnMobBundle}; -use temper_state::{create_test_state, GlobalStateResource}; +use temper_state::{GlobalStateResource, create_test_state}; #[derive(Clone)] struct SpawnedMob { diff --git a/src/game_systems/tests/physics/collisions.rs b/src/game_systems/tests/physics/collisions.rs index 1e84beb2..bcbb1278 100644 --- a/src/game_systems/tests/physics/collisions.rs +++ b/src/game_systems/tests/physics/collisions.rs @@ -7,10 +7,10 @@ use temper_components::player::velocity::Velocity; use temper_core::block_state_id::BlockStateId; use temper_core::dimension::Dimension; use temper_core::pos::{ChunkBlockPos, ChunkPos}; +use temper_entities::PhysicalRegistry; use temper_entities::bundles::PigBundle; -use temper_entities::markers::entity_types::Pig; use temper_entities::markers::HasCollisions; -use temper_entities::PhysicalRegistry; +use temper_entities::markers::entity_types::Pig; use temper_macros::block; use temper_messages::entity_update::SendEntityUpdate; use temper_state::create_test_state; diff --git a/src/game_systems/tests/physics/gravity.rs b/src/game_systems/tests/physics/gravity.rs index 45fd1642..741475ab 100644 --- a/src/game_systems/tests/physics/gravity.rs +++ b/src/game_systems/tests/physics/gravity.rs @@ -9,7 +9,7 @@ use temper_core::dimension::Dimension; use temper_core::pos::ChunkPos; use temper_entities::markers::{HasGravity, HasWaterDrag}; use temper_macros::block; -use temper_state::{create_test_state, GlobalStateResource}; +use temper_state::{GlobalStateResource, create_test_state}; fn create_chunk_with_water(state: &GlobalStateResource, chunk_pos: ChunkPos) { let mut chunk = state diff --git a/src/particles/src/net.rs b/src/particles/src/net.rs index 1da3616f..4a24fe11 100644 --- a/src/particles/src/net.rs +++ b/src/particles/src/net.rs @@ -1,10 +1,10 @@ use crate::{ParticleType, VibrationSource}; +use ParticleType::*; use std::io::Write; use temper_codec::encode::errors::NetEncodeError; use temper_codec::encode::{NetEncode, NetEncodeOpts}; use temper_codec::net_types::network_position::NetworkPosition; use temper_codec::net_types::var_int::VarInt; -use ParticleType::*; impl NetEncode for ParticleType { fn encode(&self, writer: &mut W, opts: &NetEncodeOpts) -> Result<(), NetEncodeError> { diff --git a/src/performance/src/lib.rs b/src/performance/src/lib.rs index 7134180d..b60e1aba 100644 --- a/src/performance/src/lib.rs +++ b/src/performance/src/lib.rs @@ -43,7 +43,9 @@ pub struct ServerPerformance { impl ServerPerformance { pub fn new(tps: u32) -> Self { if !sysinfo::IS_SUPPORTED_SYSTEM { - warn!("System does not support 'sysinfo', metrics are likely to be inaccurate or unavailable"); + warn!( + "System does not support 'sysinfo', metrics are likely to be inaccurate or unavailable" + ); } Self { diff --git a/src/performance/src/tps.rs b/src/performance/src/tps.rs index 5584d515..624dfd8f 100644 --- a/src/performance/src/tps.rs +++ b/src/performance/src/tps.rs @@ -1,8 +1,8 @@ use std::time::Duration; use crate::{ - tick::{TickData, TickHistory}, WINDOW_SECONDS, + tick::{TickData, TickHistory}, }; #[derive(Debug)]