Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nearby players collision check when trying to place blocks #293

Merged
merged 8 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
18 changes: 12 additions & 6 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ impl Player {
world_pos
};

//TODO: Maybe put that in config?
//check max world build height
if world_pos.0.y > 319 {
self.client
Expand All @@ -661,17 +662,22 @@ 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 posistion
if !bounding_box.intersects(&block_bounding_box) {

//Search in 20 block radius
let mut intersects = false;
for player in world.get_nearby_players(entity.pos.load(), 20).await {
Copy link
Member

Choose a reason for hiding this comment

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

Would't i make more sense to search in the players block range distance ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would not say no, because the block should not intercept with other boundingboxes. I mean the position of the player is unimportant for the collision check. As you can see the radius is 20 blocks so the "placer" or player that places the block will automatically be in that range so players cannot place in themselfs. I hope I was able to make clear why used the block as the middle of the searching circle. But if you still want that to be changed I can do that.

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;
}
}
self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
.await;
}

Ok(())
Expand Down
66 changes: 66 additions & 0 deletions pumpkin/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,72 @@ 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;
if position.0.x == player_block_pos.x
&& position.0.y == player_block_pos.y
&& position.0.z == player_block_pos.z
{
Some((*uuid, Arc::clone(player)))
} else {
None
}
})
.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
Loading