Simplify pathfinding block

This commit is contained in:
TheMode 2021-06-23 22:24:40 +02:00
parent 4fb6e37622
commit 78898bfa9b
6 changed files with 24 additions and 158 deletions

View File

@ -67,7 +67,6 @@ public final class MinecraftServer {
public final static Logger LOGGER = LoggerFactory.getLogger(MinecraftServer.class);
public static final String VERSION_NAME = "1.17";
public static final String VERSION_NAME_UNDERSCORED = VERSION_NAME.replace('.', '_');
public static final int PROTOCOL_VERSION = 755;
// Threads
@ -332,7 +331,8 @@ public final class MinecraftServer {
}
/**
* Gets the manager handling {@link BlockPlacementRule}.
* Gets the manager handling {@link net.minestom.server.instance.block.BlockHandler block handlers}
* and {@link BlockPlacementRule placement rules}.
*
* @return the block manager
*/
@ -615,6 +615,7 @@ public final class MinecraftServer {
/**
* Gets if the built in Minestom terminal is enabled.
*
* @return true if the terminal is enabled
*/
public static boolean isTerminalEnabled() {

View File

@ -1,39 +1,42 @@
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockDescription;
import com.extollit.gaming.ai.path.model.IBlockObject;
import com.extollit.linalg.immutable.AxisAlignedBBox;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull;
public class PFBlockObject implements IBlockObject {
public class PFBlock implements IBlockDescription, IBlockObject {
private static final Short2ObjectMap<PFBlockObject> BLOCK_OBJECT_MAP = new Short2ObjectOpenHashMap<>();
private static final Short2ObjectMap<PFBlock> BLOCK_DESCRIPTION_MAP = new Short2ObjectOpenHashMap<>();
/**
* Gets the {@link PFBlockObject} linked to the block state id.
* Gets the {@link PFBlock} linked to the block state id.
* <p>
* Cache the result if it is not already.
*
* @param block the block
* @return the {@link PFBlockObject} linked to {@code blockStateId}
* @return the {@link PFBlock} linked to {@code blockStateId}
*/
public static PFBlockObject getBlockObject(Block block) {
public static @NotNull PFBlock get(@NotNull Block block) {
final short blockStateId = block.stateId();
if (!BLOCK_OBJECT_MAP.containsKey(blockStateId)) {
synchronized (BLOCK_OBJECT_MAP) {
final PFBlockObject blockObject = new PFBlockObject(block);
BLOCK_OBJECT_MAP.put(blockStateId, blockObject);
return blockObject;
if (!BLOCK_DESCRIPTION_MAP.containsKey(blockStateId)) {
synchronized (BLOCK_DESCRIPTION_MAP) {
if (!BLOCK_DESCRIPTION_MAP.containsKey(blockStateId)) {
final var pfBlock = new PFBlock(block);
BLOCK_DESCRIPTION_MAP.put(blockStateId, pfBlock);
return pfBlock;
}
}
}
return BLOCK_OBJECT_MAP.get(blockStateId);
return BLOCK_DESCRIPTION_MAP.get(blockStateId);
}
private final Block block;
public PFBlockObject(Block block) {
public PFBlock(Block block) {
this.block = block;
}
@ -144,4 +147,5 @@ public class PFBlockObject implements IBlockObject {
public boolean isIncinerating() {
return block == Block.LAVA || block == Block.FIRE || block == Block.SOUL_FIRE;
}
}

View File

@ -1,138 +0,0 @@
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockDescription;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import net.minestom.server.instance.block.Block;
public class PFBlockDescription implements IBlockDescription {
private static final Short2ObjectMap<PFBlockDescription> BLOCK_DESCRIPTION_MAP = new Short2ObjectOpenHashMap<>();
/**
* Gets the {@link PFBlockDescription} linked to the block state id.
* <p>
* Cache the result if it is not already.
*
* @param block the block
* @return the {@link PFBlockDescription} linked to {@code blockStateId}
*/
public static PFBlockDescription getBlockDescription(Block block) {
final short blockStateId = block.stateId();
if (!BLOCK_DESCRIPTION_MAP.containsKey(blockStateId)) {
synchronized (BLOCK_DESCRIPTION_MAP) {
final PFBlockDescription blockDescription = new PFBlockDescription(block);
BLOCK_DESCRIPTION_MAP.put(blockStateId, blockDescription);
return blockDescription;
}
}
return BLOCK_DESCRIPTION_MAP.get(blockStateId);
}
private final Block block;
public PFBlockDescription(Block block) {
this.block = block;
}
@Override
public boolean isFenceLike() {
// TODO: Use Hitbox
// Return fences, fencegates and walls.
// It just so happens that their namespace IDs contain "fence".
if (block.namespace().asString().contains("fence")) {
return true;
}
// Return all walls
// It just so happens that their namespace IDs all end with "door".
return block.namespace().asString().endsWith("wall");
}
@Override
public boolean isClimbable() {
// Return ladders and vines (including weeping and twisting vines)
// Note that no other Namespace IDs contain "vine" except vines.
return block.compare(Block.LADDER) || block.namespace().asString().contains("vine");
}
@Override
public boolean isDoor() {
// Return all normal doors and trap doors.
// It just so happens that their namespace IDs all end with "door".
return block.namespace().asString().endsWith("door");
}
@Override
public boolean isImpeding() {
return block.isSolid();
}
@Override
public boolean isFullyBounded() {
// TODO: Use Hitbox (would probably be faster as well)
// Return false for anything that does not have a full hitbox but impedes
// e.g. Anvils, Lilypads, Ladders, Walls, Fences, EnchantmentTables
// Fences & Walls
if (isFenceLike()) {
return false;
}
// Ladders and Vines
if (isClimbable()) {
return false;
}
// All doors/trapdoors.
if (isDoor()) {
return false;
}
if (block.name().startsWith("potted")) {
return false;
}
// Skulls & Heads
if (block.name().contains("skull") || block.name().contains("head")) {
// NOTE: blocks.getName().contains("head") also matches Piston_Head
// I could not find out by documentation if piston_head is fully bounded, I would presume it is NOT.
return false;
}
// Carpets
if (block.name().endsWith("carpet")) {
return false;
}
// Slabs
if (block.name().contains("slab")) {
return false;
}
// Beds
if (block.name().endsWith("bed")) {
return false;
}
// Glass Panes
if (block.name().endsWith("pane")) {
return false;
}
return !Block.CHORUS_FLOWER.compare(block) && !Block.CHORUS_PLANT.compare(block) && !Block.BAMBOO.compare(block)
&& !Block.BAMBOO_SAPLING.compare(block) && !Block.SEA_PICKLE.compare(block)
&& !Block.TURTLE_EGG.compare(block) && !Block.SNOW.compare(block) && !Block.FLOWER_POT.compare(block)
&& !Block.LILY_PAD.compare(block) && !Block.ANVIL.compare(block) && !Block.CHIPPED_ANVIL.compare(block)
&& !Block.DAMAGED_ANVIL.compare(block) && !Block.CAKE.compare(block) && !Block.CACTUS.compare(block)
&& !Block.BREWING_STAND.compare(block) && !Block.LECTERN.compare(block)
&& !Block.DAYLIGHT_DETECTOR.compare(block) && !Block.CAMPFIRE.compare(block)
&& !Block.SOUL_CAMPFIRE.compare(block) && !Block.ENCHANTING_TABLE.compare(block)
&& !Block.CHEST.compare(block) && !Block.ENDER_CHEST.compare(block) && !Block.GRINDSTONE.compare(block)
&& !Block.TRAPPED_CHEST.compare(block) && !Block.SOUL_SAND.compare(block)
&& !Block.SOUL_SOIL.compare(block) && !Block.LANTERN.compare(block) && !Block.COCOA.compare(block)
&& !Block.CONDUIT.compare(block) && !Block.DIRT_PATH.compare(block) && !Block.FARMLAND.compare(block)
&& !Block.END_ROD.compare(block) && !Block.STONECUTTER.compare(block) && !Block.BELL.compare(block);
}
@Override
public boolean isLiquid() {
return block.isLiquid();
}
@Override
public boolean isIncinerating() {
return block == Block.LAVA || block == Block.FIRE || block == Block.SOUL_FIRE;
}
}

View File

@ -22,7 +22,7 @@ public class PFColumnarSpace implements IColumnarSpace {
@Override
public IBlockDescription blockAt(int x, int y, int z) {
final Block block = chunk.getBlock(x, y, z);
return PFBlockDescription.getBlockDescription(block);
return PFBlock.get(block);
}
@Override

View File

@ -22,7 +22,7 @@ public class PFInstanceSpace implements IInstanceSpace {
@Override
public IBlockObject blockObjectAt(int x, int y, int z) {
final Block block = instance.getBlock(x, y, z);
return PFBlockObject.getBlockObject(block);
return PFBlock.get(block);
}
@Override
@ -31,7 +31,6 @@ public class PFInstanceSpace implements IInstanceSpace {
if (chunk == null) {
return null;
}
return chunkSpaceMap.computeIfAbsent(chunk, c -> {
final PFColumnarSpace cs = new PFColumnarSpace(this, c);
c.setColumnarSpace(cs);

View File

@ -2,7 +2,7 @@ package net.minestom.server.instance;
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.entity.pathfinding.PFBlockDescription;
import net.minestom.server.entity.pathfinding.PFBlock;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
@ -47,7 +47,7 @@ public class DynamicChunk extends Chunk {
// Update pathfinder
if (columnarSpace != null) {
final ColumnarOcclusionFieldList columnarOcclusionFieldList = columnarSpace.occlusionFields();
final PFBlockDescription blockDescription = PFBlockDescription.getBlockDescription(block);
final var blockDescription = PFBlock.get(block);
columnarOcclusionFieldList.onBlockChanged(x, y, z, blockDescription, 0);
}
Section section = retrieveSection(y);