Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ members = [
]

[workspace.package]
edition = "2021"
edition = "2024"
version = "0.1.1"

#================== Lints ==================#
Expand Down
2 changes: 1 addition & 1 deletion src/blocks/crates/property/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),*
}
Expand Down
53 changes: 53 additions & 0 deletions src/blocks/crates/property/src/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
105 changes: 103 additions & 2 deletions src/blocks/src/building/stairs.rs
Original file line number Diff line number Diff line change
@@ -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::<StairsBlock>(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::<StairsBlock>(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::<StairsBlock>(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
}
}
13 changes: 2 additions & 11 deletions src/blocks/src/decorative/door.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/src/decorative/fence_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down
18 changes: 18 additions & 0 deletions src/blocks/src/world_extensions.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -20,6 +21,12 @@ pub trait WorldBlockUpdates {
block_pos: BlockPos,
callback: impl Fn(T) -> bool,
) -> bool;

fn try_get_block<T: BlockBehavior>(
&self,
block_pos: BlockPos,
dimension: Dimension,
) -> Option<T>;
}

impl WorldBlockUpdates for World {
Expand Down Expand Up @@ -61,4 +68,15 @@ impl WorldBlockUpdates for World {
})
.unwrap_or_default()
}

fn try_get_block<T: BlockBehavior>(
&self,
block_pos: BlockPos,
dimension: Dimension,
) -> Option<T> {
self.get_chunk(block_pos.chunk(), dimension)
.map(|c| c.get_block(block_pos.chunk_block_pos()))
.unwrap_or(BlockStateId::new(0))
.try_cast::<T>()
}
}
29 changes: 20 additions & 9 deletions src/core/src/block_face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/core/src/pos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ impl Add<(i32, i32, i32)> for BlockPos {
}
}

impl Add<IVec3> 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,
Expand Down
2 changes: 1 addition & 1 deletion src/game_systems/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/game_systems/src/packets/src/place_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/game_systems/tests/mobs/chunk_visibility_lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/game_systems/tests/mobs/entity_persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions src/game_systems/tests/mobs/player_distance_reload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading