mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-26 10:01:36 +01:00
Fix block placement below players (#767)
This commit is contained in:
parent
acee29c20a
commit
bcfb4c6ea4
@ -3,11 +3,17 @@ package net.minestom.server.collision;
|
|||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.coordinate.Vec;
|
import net.minestom.server.coordinate.Vec;
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
|
import net.minestom.server.entity.EntityType;
|
||||||
|
import net.minestom.server.entity.metadata.other.ArmorStandMeta;
|
||||||
|
import net.minestom.server.instance.Instance;
|
||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
final class BlockCollision {
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public final class BlockCollision {
|
||||||
// Minimum move amount, minimum final velocity
|
// Minimum move amount, minimum final velocity
|
||||||
private static final double MIN_DELTA = 0.001;
|
private static final double MIN_DELTA = 0.001;
|
||||||
|
|
||||||
@ -325,6 +331,36 @@ final class BlockCollision {
|
|||||||
Vec.ZERO, finalResult.collidedShapePosition, finalResult.blockType);
|
Vec.ZERO, finalResult.collidedShapePosition, finalResult.blockType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean canPlaceBlockAt(Instance instance, Point blockPos, Block b) {
|
||||||
|
final Collection<Entity> entities = instance.getNearbyEntities(blockPos, 3);
|
||||||
|
|
||||||
|
return entities
|
||||||
|
.stream()
|
||||||
|
.filter(entity -> entity.getEntityType() != EntityType.ITEM)
|
||||||
|
.filter(entity -> {
|
||||||
|
// Marker Armor Stands should not prevent block placement
|
||||||
|
if (entity.getEntityMeta() instanceof ArmorStandMeta armorStandMeta) {
|
||||||
|
return !armorStandMeta.isMarker();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.noneMatch(entity -> {
|
||||||
|
boolean intersects;
|
||||||
|
|
||||||
|
if (entity.getEntityType() == EntityType.PLAYER) {
|
||||||
|
// Need to move player slightly away from block we're placing.
|
||||||
|
// If player is at block 40 we cannot place a block at block 39 with side length 1 because the block will be in [39, 40]
|
||||||
|
// For this reason we subtract a small amount from the player position
|
||||||
|
Point playerPos = entity.getPosition().add(entity.getPosition().sub(blockPos).mul(0.01));
|
||||||
|
intersects = b.registry().collisionShape().intersectBox(playerPos.sub(blockPos), entity.getBoundingBox());
|
||||||
|
} else {
|
||||||
|
intersects = b.registry().collisionShape().intersectBox(entity.getPosition().sub(blockPos), entity.getBoundingBox());
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersects;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a moving entity will collide with a block. Updates finalResult
|
* Check if a moving entity will collide with a block. Updates finalResult
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.minestom.server.collision;
|
package net.minestom.server.collision;
|
||||||
|
|
||||||
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.coordinate.Vec;
|
import net.minestom.server.coordinate.Vec;
|
||||||
import net.minestom.server.entity.Entity;
|
import net.minestom.server.entity.Entity;
|
||||||
@ -41,6 +42,10 @@ public final class CollisionUtils {
|
|||||||
return handlePhysics(entity, entityVelocity, null);
|
return handlePhysics(entity, entityVelocity, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean canPlaceBlockAt(Instance instance, Point blockPos, Block b) {
|
||||||
|
return BlockCollision.canPlaceBlockAt(instance, blockPos, b);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies world border collision.
|
* Applies world border collision.
|
||||||
*
|
*
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
package net.minestom.server.listener;
|
package net.minestom.server.listener;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.collision.CollisionUtils;
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.entity.Entity;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
import net.minestom.server.entity.GameMode;
|
import net.minestom.server.entity.GameMode;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.entity.metadata.other.ArmorStandMeta;
|
|
||||||
import net.minestom.server.event.EventDispatcher;
|
import net.minestom.server.event.EventDispatcher;
|
||||||
import net.minestom.server.event.player.PlayerBlockInteractEvent;
|
import net.minestom.server.event.player.PlayerBlockInteractEvent;
|
||||||
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
|
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
|
||||||
@ -26,8 +24,6 @@ import net.minestom.server.network.packet.server.play.BlockChangePacket;
|
|||||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||||
import net.minestom.server.utils.validate.Check;
|
import net.minestom.server.utils.validate.Check;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class BlockPlacementListener {
|
public class BlockPlacementListener {
|
||||||
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||||
|
|
||||||
@ -109,24 +105,7 @@ public class BlockPlacementListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Block placedBlock = useMaterial.block();
|
final Block placedBlock = useMaterial.block();
|
||||||
final Collection<Entity> entities = instance.getNearbyEntities(placementPosition, 5);
|
if (!CollisionUtils.canPlaceBlockAt(instance, placementPosition, placedBlock)) {
|
||||||
|
|
||||||
// Check if the player is trying to place a block in an entity
|
|
||||||
boolean intersectPlayer = placedBlock.registry().collisionShape().intersectBox(player.getPosition().sub(placementPosition), player.getBoundingBox());
|
|
||||||
|
|
||||||
boolean hasIntersect = intersectPlayer || entities
|
|
||||||
.stream()
|
|
||||||
.filter(entity -> entity.getEntityType() != EntityType.ITEM)
|
|
||||||
.filter(entity -> {
|
|
||||||
// Marker Armor Stands should not prevent block placement
|
|
||||||
if (entity.getEntityMeta() instanceof ArmorStandMeta armorStandMeta) {
|
|
||||||
return !armorStandMeta.isMarker();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.anyMatch(entity -> placedBlock.registry().collisionShape().intersectBox(entity.getPosition().sub(placementPosition), entity.getBoundingBox()));
|
|
||||||
|
|
||||||
if (hasIntersect) {
|
|
||||||
refresh(player, chunk);
|
refresh(player, chunk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package net.minestom.server.collision;
|
||||||
|
|
||||||
|
import net.minestom.server.api.Env;
|
||||||
|
import net.minestom.server.api.EnvTest;
|
||||||
|
import net.minestom.server.coordinate.Pos;
|
||||||
|
import net.minestom.server.coordinate.Vec;
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
|
import net.minestom.server.entity.EntityType;
|
||||||
|
import net.minestom.server.instance.block.Block;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@EnvTest
|
||||||
|
public class PlacementCollisionIntegrationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void empty(Env env) {
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
assertTrue(BlockCollision.canPlaceBlockAt(instance, new Vec(0, 40, 0), Block.STONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void entityBlock(Env env) {
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
new Entity(EntityType.ZOMBIE).setInstance(instance, new Pos(0, 40, 0)).join();
|
||||||
|
assertFalse(BlockCollision.canPlaceBlockAt(instance, new Vec(0, 40, 0), Block.STONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void slab(Env env) {
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
new Entity(EntityType.ZOMBIE).setInstance(instance, new Pos(0, 40.75, 0)).join();
|
||||||
|
assertTrue(BlockCollision.canPlaceBlockAt(instance, new Vec(0, 40, 0), Block.STONE_SLAB));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void belowPlayer(Env env) {
|
||||||
|
var instance = env.createFlatInstance();
|
||||||
|
env.createPlayer(instance, new Pos(5.7, -8, 6.389));
|
||||||
|
assertTrue(BlockCollision.canPlaceBlockAt(instance, new Vec(5, -9, 6), Block.STONE));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user