Skip to content

Commit

Permalink
Add nearby players collision check when trying to place blocks (#293)
Browse files Browse the repository at this point in the history
* Try to update boundingbox when changin pos

* Remove unused imports

* Add nearby player check when placing blocks

* Add seach for nearby players when placing block

* Reformat

* Fix conflict

* fix: conflicts

and fix clippy

---------

Co-authored-by: Alexander Medvedev <[email protected]>
  • Loading branch information
Tiiita and Snowiiii authored Dec 25, 2024
1 parent 0e9b1af commit e8deff5
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 3 deletions.
11 changes: 8 additions & 3 deletions pumpkin/src/net/packet/play.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,9 +764,14 @@ impl Player {
}

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 position
if !bounding_box.intersects(&block_bounding_box) {
let mut intersects = false;
for player in world.get_nearby_players(entity.pos.load(), 20).await {
let bounding_box = player.1.living_entity.entity.bounding_box.load();
if bounding_box.intersects(&block_bounding_box) {
intersects = true;
}
}
if !intersects {
world
.set_block_state(world_pos, block.default_state_id)
.await;
Expand Down
62 changes: 62 additions & 0 deletions pumpkin/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,68 @@ impl World {
return self.current_players.lock().await.get(&id).cloned();
}

/// Gets a list of players who's location equals the given position in the world.
///
/// It iterates through the players in the world and checks their location. If the player's location matches the
/// given position it will add this to a Vec which it later returns. If no
/// player was found in that position it will just return an empty Vec.
///
/// # Arguments
///
/// * `position`: The position the function will check.
pub async fn get_players_by_pos(
&self,
position: WorldPosition,
) -> HashMap<uuid::Uuid, Arc<Player>> {
self.current_players
.lock()
.await
.iter()
.filter_map(|(uuid, player)| {
let player_block_pos = player.living_entity.entity.block_pos.load().0;
(position.0.x == player_block_pos.x
&& position.0.y == player_block_pos.y
&& position.0.z == player_block_pos.z)
.then(|| (*uuid, Arc::clone(player)))
})
.collect::<HashMap<uuid::Uuid, Arc<Player>>>()
}

/// Gets the nearby players around a given world position
/// It "creates" a sphere and checks if whether players are inside
/// and returns a hashmap where the uuid is the key and the player
/// object the value.
///
/// # Arguments
/// * `pos`: The middlepoint of the sphere
/// * `radius`: The radius of the sphere. The higher the radius
/// the more area will be checked, in every direction.
pub async fn get_nearby_players(
&self,
pos: Vector3<f64>,
radius: u16,
) -> HashMap<uuid::Uuid, Arc<Player>> {
let radius_squared = (f64::from(radius)).powi(2);

let mut found_players = HashMap::new();
for player in self.current_players.lock().await.iter() {
let player_pos = player.1.living_entity.entity.pos.load();

let diff = Vector3::new(
player_pos.x - pos.x,
player_pos.y - pos.y,
player_pos.z - pos.z,
);

let distance_squared = diff.x.powi(2) + diff.y.powi(2) + diff.z.powi(2);
if distance_squared <= radius_squared {
found_players.insert(*player.0, player.1.clone());
}
}

found_players
}

/// Adds a player to the world and broadcasts a join message if enabled.
///
/// This function takes a player's UUID and an `Arc<Player>` reference.
Expand Down

0 comments on commit e8deff5

Please sign in to comment.