1.9.x special case: climbable trap doors.

This commit is contained in:
asofold 2016-06-06 17:14:04 +02:00
parent 785fe554e0
commit 100d3c8917
3 changed files with 174 additions and 6 deletions

View File

@ -80,6 +80,9 @@ public class BlocksMC1_9 implements BlockPropertiesSetup {
// 255(STRUCTURE_BLOCK / SOLID+GROUND)
BlockInit.setAs(255, Material.BEDROCK);
// Special case activation.
BlockProperties.setSpecialCaseTrapDoorAboveLadder(true);
StaticLog.logInfo("Added block-info for Minecraft 1.9 blocks.");
}

View File

@ -30,6 +30,7 @@ import java.util.Set;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
@ -390,8 +391,25 @@ public class BlockProperties {
/** Like slime block: bounce back 25% of fall height without taking fall damage [TODO: Check/adjust]. */
public static final long F_BOUNCE25 = 0x400000;
/**
* The facing direction is described by the lower 3 data bits in order of
* NSWE, starting at and defaulting to 2, which includes invalid states.
* Main purpose is ladders, no guarantees on defaults for other blocks yet.
*/
public static final long F_FACING_LOW3D2_NSWE = 0x800000;
/**
* The direction the block is attached to is described by the lower 2 bits
* in order of SNEW.
*/
public static final long F_ATTACHED_LOW2_SNEW = 0x1000000;
// TODO: When flags are out, switch to per-block classes :p.
// Special case activation flags.
/** Trap door is climbable with ladder underneath, both facing distinct. */
private static boolean specialCaseTrapDoorAboveLadder = false;
/**
* Map flag to names.
*/
@ -628,14 +646,28 @@ public class BlockProperties {
blockFlags[mat.getId()] |= F_HEIGHT150 | F_VARIABLE | F_THICK_FENCE;
}
// Fence gate(s).
// F_PASSABLE_X4
for (final Material mat : new Material[]{
Material.FENCE_GATE,
// TODO: Consider TRAP_DOOR too, for the case someone removes the ign_passable entry.
Material.TRAP_DOOR,
}) {
blockFlags[mat.getId()] |= F_PASSABLE_X4;
}
// F_FACING_LOW3D2_NSWE
for (final Material mat : new Material[]{
Material.LADDER
}) {
blockFlags[mat.getId()] |= F_FACING_LOW3D2_NSWE;
}
// F_FACING_LOW2_SNEW
for (final Material mat : new Material[]{
Material.TRAP_DOOR,
}) {
blockFlags[mat.getId()] |= F_ATTACHED_LOW2_SNEW;
}
// Thin fences (iron fence, glass panes).
for (final Material mat : new Material[]{
Material.IRON_FENCE, Material.THIN_GLASS,
@ -1577,6 +1609,105 @@ public class BlockProperties {
return stack == null || isAir(stack.getType());
}
/**
* Get the facing direction as BlockFace, unified approach with attached to
* = opposite of facing. Likely the necessary flags are just set where it's
* been needed so far.
*
* @param flags
* @param data
* @return Return null, if facing can not be determined.
*/
public static final BlockFace getFacing(final long flags, final int data) {
if ((flags & F_FACING_LOW3D2_NSWE) != 0L) {
switch(data & 7) {
case 3:
return BlockFace.SOUTH;
case 4:
return BlockFace.WEST;
case 5:
return BlockFace.EAST;
default: // 2 and invalid states.
return BlockFace.NORTH;
}
}
else if ((flags & F_ATTACHED_LOW2_SNEW) != 0L) {
switch (data & 3) {
case 0:
return BlockFace.NORTH; // Attached to BlockFace.SOUTH;
case 1:
return BlockFace.SOUTH; // Attached to BlockFace.NORTH;
case 2:
return BlockFace.WEST; // Attached to BlockFace.EAST;
case 3:
return BlockFace.EAST; // Attached to BlockFace.WEST;
}
}
return null;
}
/**
* Special case: Trap door above ladder attached to lower and of block, same
* facing. Thus the trap door can be climbed up like a ladder.<br>
* Suggested fast precondition checks are for nearby flags covering this and
* below:
* <ul>
* <li>F_PASSABLE_X4 (trap door at these coordinates).</li>
* <li>F_CLIMBABLE (ladder below).</li>
* </ul>
*
* @param access
* @param x
* @param y
* @param z
* @return
*/
public static final boolean isTrapDoorAboveLadderSpecialCase(final BlockCache access, final int x, final int y, final int z) {
// Special case activation.
if (!isSpecialCaseTrapDoorAboveLadder()) {
return false;
}
// Basic flags and facing for trap door.
final long flags1 = blockFlags[access.getTypeId(x, y, z)];
if ((flags1 & F_PASSABLE_X4) == 0) {
return false;
}
// TODO: Really confine to trap door types (add a flag or something else)?
final int data1 = access.getData(x, y, z);
// Trap door must be attached to the bottom half of the block.
if ((data1 & 0x08) != 0) {
return false;
}
// Trap door must be open (really?).
if ((data1 & 0x04) != 0x04) {
return false;
}
// Need the facing direction.
final BlockFace face1 = getFacing(flags1, data1);
if (face1 == null) {
return false;
}
// Basic flags and facing for ladder.
final int belowId = access.getTypeId(x, y - 1, z);
// Really confine to ladder here.
if (belowId != getId(Material.LADDER)) {
return false;
}
final long flags2 = blockFlags[belowId];
// (Type has already been checked.)
//if ((flags2 & F_CLIMBABLE) == 0) {
// return false;
//}
final int data2 = access.getData(x, y - 1, z);
final BlockFace face2 = getFacing(flags2, data2);
// Compare faces.
if (face1 != face2) {
return false;
}
return true;
}
/**
* Just check if a position is not inside of a block that has a bounding box.<br>
* This is an inaccurate check, it also returns false for doors etc.
@ -2949,4 +3080,24 @@ public class BlockProperties {
return false;
}
/**
* Test for special case activation: trap door is climbable above ladder
* with distinct facing.
*
* @return
*/
public static boolean isSpecialCaseTrapDoorAboveLadder() {
return specialCaseTrapDoorAboveLadder;
}
/**
* Set special case activation: trap door is climbable above ladder with
* distinct facing.
*
* @param specialCaseTrapDoorAboveLadder
*/
public static void setSpecialCaseTrapDoorAboveLadder(boolean specialCaseTrapDoorAboveLadder) {
BlockProperties.specialCaseTrapDoorAboveLadder = specialCaseTrapDoorAboveLadder;
}
}

View File

@ -459,21 +459,35 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
}
/**
* Checks if the player is on a ladder or vine.
* Checks if the player is on a ladder or vine. Contains special casing for
* trap doors above climbable.
*
* @return If so.
*/
public boolean isOnClimbable() {
if (onClimbable == null) {
// Climbable blocks.
if (blockFlags != null && (blockFlags.longValue() & BlockProperties.F_CLIMBABLE) == 0 ) {
// Early return with flags set and no climbable nearby.
final int typeId = getTypeId();
if (blockFlags != null && (blockFlags & BlockProperties.F_CLIMBABLE) == 0
// Special case trap doors: // Better than increasing maxYOnGround.
&& (blockFlags & BlockProperties.F_PASSABLE_X4) == 0
) {
onClimbable = false;
return false;
}
onClimbable = (BlockProperties.getBlockFlags(getTypeId()) & BlockProperties.F_CLIMBABLE) != 0;
final long thisFlags = BlockProperties.getBlockFlags(typeId);
onClimbable = (thisFlags & BlockProperties.F_CLIMBABLE) != 0;
// TODO: maybe use specialized bounding box.
// final double d = 0.1d;
// onClimbable = BlockProperties.collides(getBlockAccess(), minX - d, minY - d, minZ - d, maxX + d, minY + 1.0, maxZ + d, BlockProperties.F_CLIMBABLE);
if (!onClimbable) {
// Special case trap door (simplified preconditions check).
// TODO: Distance to the wall?
if ((thisFlags & BlockProperties.F_PASSABLE_X4) != 0
&& BlockProperties.isTrapDoorAboveLadderSpecialCase(blockCache, blockX, blockY, blockZ)) {
onClimbable = true;
}
}
}
return onClimbable;
}