From 4067f65ff92057e4cbbf37ad03f64ce99d2076e9 Mon Sep 17 00:00:00 2001 From: Tiiita <96084154+Tiiita@users.noreply.github.com> Date: Sun, 10 Nov 2024 23:28:14 +0100 Subject: [PATCH] Check collision before block place (#251) * 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 --- pumpkin-core/src/math/boundingbox.rs | 46 +++++++++++++++++++++++----- pumpkin/src/client/player_packet.rs | 15 ++++----- pumpkin/src/entity/mod.rs | 21 ++++++++++++- pumpkin/src/entity/player.rs | 14 ++++++++- 4 files changed, 80 insertions(+), 16 deletions(-) diff --git a/pumpkin-core/src/math/boundingbox.rs b/pumpkin-core/src/math/boundingbox.rs index 800a954a..d9ad58d8 100644 --- a/pumpkin-core/src/math/boundingbox.rs +++ b/pumpkin-core/src/math/boundingbox.rs @@ -1,5 +1,6 @@ use super::{position::WorldPosition, vector3::Vector3}; +#[derive(Clone, Copy)] pub struct BoundingBox { pub min_x: f64, pub min_y: f64, @@ -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, max: Vector3) -> 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, } } @@ -33,6 +50,15 @@ 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 { 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); @@ -40,3 +66,9 @@ impl BoundingBox { super::squared_magnitude(d, e, f) } } + +#[derive(Clone, Copy)] +pub struct BoundingBoxSize { + pub width: f64, + pub height: f64, +} diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index ded4ab1f..17b45d3b 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -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, @@ -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)) diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index aca6813d..a175586d 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -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::{ @@ -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, + /// The bounding box of an entity (hitbox) + pub bounding_box: AtomicCell, + ///The size (width and height) of the bounding box + pub bounding_box_size: AtomicCell, } impl Entity { @@ -58,6 +66,8 @@ impl Entity { world: Arc, entity_type: EntityType, standing_eye_height: f32, + bounding_box: AtomicCell, + bounding_box_size: AtomicCell, ) -> Self { Self { entity_id, @@ -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, } } @@ -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; diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index b61081fc..ddcbe53f 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -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, }; @@ -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,