Skip to content

Commit

Permalink
Check collision before block place (#251)
Browse files Browse the repository at this point in the history
* Add bounding box to entities)

* Try to update boundingbox when changin pos

* Remove unused imports

* Update / recalc boundingbox when changing pos

* Add collision when placing check

* Add todo: Check collision with every entity in pos

* Change BoundingBox::new() args

* Seperate bounding box width and height

* Change intersect fn name

* Clean up code
  • Loading branch information
Tiiita authored Nov 10, 2024
1 parent 2d24098 commit 4067f65
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 16 deletions.
46 changes: 39 additions & 7 deletions pumpkin-core/src/math/boundingbox.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{position::WorldPosition, vector3::Vector3};

#[derive(Clone, Copy)]
pub struct BoundingBox {
pub min_x: f64,
pub min_y: f64,
Expand All @@ -10,14 +11,30 @@ pub struct BoundingBox {
}

impl BoundingBox {
pub fn new(min_x: f64, min_y: f64, min_z: f64, max_x: f64, max_y: f64, max_z: f64) -> Self {
pub fn new_default(size: &BoundingBoxSize) -> Self {
Self::new_from_pos(0., 0., 0., size)
}

pub fn new_from_pos(x: f64, y: f64, z: f64, size: &BoundingBoxSize) -> Self {
let f = size.width / 2.;
Self {
min_x: x - f,
min_y: y,
min_z: z - f,
max_x: x + f,
max_y: y + size.height,
max_z: z + f,
}
}

pub fn new(min: Vector3<f64>, max: Vector3<f64>) -> Self {
Self {
min_x,
min_y,
min_z,
max_x,
max_y,
max_z,
min_x: min.x,
min_y: min.y,
min_z: min.z,
max_x: max.x,
max_y: max.y,
max_z: max.z,
}
}

Expand All @@ -33,10 +50,25 @@ impl BoundingBox {
}
}

pub fn intersects(&self, other: &BoundingBox) -> bool {
self.min_x < other.max_x
&& self.max_x > other.min_x
&& self.min_y < other.max_y
&& self.max_y > other.min_y
&& self.min_z < other.max_z
&& self.max_z > other.min_z
}

pub fn squared_magnitude(&self, pos: Vector3<f64>) -> f64 {
let d = f64::max(f64::max(self.min_x - pos.x, pos.x - self.max_x), 0.0);
let e = f64::max(f64::max(self.min_y - pos.y, pos.y - self.max_y), 0.0);
let f = f64::max(f64::max(self.min_z - pos.z, pos.z - self.max_z), 0.0);
super::squared_magnitude(d, e, f)
}
}

#[derive(Clone, Copy)]
pub struct BoundingBoxSize {
pub width: f64,
pub height: f64,
}
15 changes: 8 additions & 7 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
};
use num_traits::FromPrimitive;
use pumpkin_config::ADVANCED_CONFIG;
use pumpkin_core::math::position::WorldPosition;
use pumpkin_core::math::{boundingbox::BoundingBox, position::WorldPosition};
use pumpkin_core::{
math::{vector3::Vector3, wrap_degrees},
text::TextComponent,
Expand Down Expand Up @@ -577,12 +577,13 @@ impl Player {
}
}

world
.set_block(
WorldPosition(location.0 + face.to_offset()),
block.default_state_id,
)
.await;
let world_pos = WorldPosition(location.0 + face.to_offset());
let block_bounding_box = BoundingBox::from_block(&world_pos);
let bounding_box = entity.bounding_box.load();
//TODO: Make this check for every entity in that posistion
if !bounding_box.intersects(&block_bounding_box) {
world.set_block(world_pos, block.default_state_id).await;
}
}
self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
Expand Down
21 changes: 20 additions & 1 deletion pumpkin/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ use std::sync::{atomic::AtomicBool, Arc};
use crossbeam::atomic::AtomicCell;
use num_derive::FromPrimitive;
use pumpkin_core::math::{
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
boundingbox::{BoundingBox, BoundingBoxSize},
get_section_cord,
position::WorldPosition,
vector2::Vector2,
vector3::Vector3,
};
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId};
use pumpkin_protocol::{
Expand Down Expand Up @@ -50,6 +54,10 @@ pub struct Entity {
pub standing_eye_height: f32,
/// The entity's current pose (e.g., standing, sitting, swimming).
pub pose: AtomicCell<EntityPose>,
/// The bounding box of an entity (hitbox)
pub bounding_box: AtomicCell<BoundingBox>,
///The size (width and height) of the bounding box
pub bounding_box_size: AtomicCell<BoundingBoxSize>,
}

impl Entity {
Expand All @@ -58,6 +66,8 @@ impl Entity {
world: Arc<World>,
entity_type: EntityType,
standing_eye_height: f32,
bounding_box: AtomicCell<BoundingBox>,
bounding_box_size: AtomicCell<BoundingBoxSize>,
) -> Self {
Self {
entity_id,
Expand All @@ -77,6 +87,8 @@ impl Entity {
velocity: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)),
standing_eye_height,
pose: AtomicCell::new(EntityPose::Standing),
bounding_box,
bounding_box_size,
}
}

Expand All @@ -89,6 +101,13 @@ impl Entity {
if pos.x != x || pos.y != y || pos.z != z {
self.pos.store(Vector3::new(x, y, z));

self.bounding_box.store(BoundingBox::new_from_pos(
pos.x,
pos.y,
pos.z,
&self.bounding_box_size.load(),
));

let floor_x = x.floor() as i32;
let floor_y = y.floor() as i32;
let floor_z = z.floor() as i32;
Expand Down
14 changes: 13 additions & 1 deletion pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ use itertools::Itertools;
use num_derive::FromPrimitive;
use pumpkin_config::ADVANCED_CONFIG;
use pumpkin_core::{
math::{boundingbox::BoundingBox, position::WorldPosition, vector2::Vector2, vector3::Vector3},
math::{
boundingbox::{BoundingBox, BoundingBoxSize},
position::WorldPosition,
vector2::Vector2,
vector3::Vector3,
},
text::TextComponent,
GameMode,
};
Expand Down Expand Up @@ -177,12 +182,19 @@ impl Player {
|profile| profile,
);
let config = client.config.lock().await.clone().unwrap_or_default();
let bounding_box_size = BoundingBoxSize {
width: 0.6,
height: 1.8,
};

Self {
living_entity: LivingEntity::new(Entity::new(
entity_id,
world,
EntityType::Player,
1.62,
AtomicCell::new(BoundingBox::new_default(&bounding_box_size)),
AtomicCell::new(bounding_box_size),
)),
config: Mutex::new(config),
gameprofile,
Expand Down

5 comments on commit 4067f65

@DataM0del
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about placing over grass? Will open a PR to fix this if I'm not lazy.

@Snowiiii
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something different and does work differently, You would not need to work with entities. You would need to get the Block on what the Player tries to Place the new Block and check if the Block has no collision box (i think).
Sure if you want go ahead :D

@DataM0del
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something different and does work differently, You would not need to work with entities. You would need to get the Block on what the Player tries to Place the new Block and check if the Block has no collision box (i think). Sure if you want go ahead :D

I thought it wasn't working but I think last time I checked it is working???

@Snowiiii
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something different and does work differently, You would not need to work with entities. You would need to get the Block on what the Player tries toI Place the new Block and check if the Block has no collision box (i think). Sure if you want go ahead :D

I thought it wasn't working but I think last time I checked it is working???

Im pretty sure it does not work. If you try to place block on grass, It does not replace the grass

@DataM0del
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something different and does work differently, You would not need to work with entities. You would need to get the Block on what the Player tries toI Place the new Block and check if the Block has no collision box (i think). Sure if you want go ahead :D

I thought it wasn't working but I think last time I checked it is working???

Im pretty sure it does not work. If you try to place block on grass, It does not replace the grass

Oh. Ok.

Please sign in to comment.