|
|
@ -15,7 +15,7 @@ import org.bukkit.Sound |
|
|
|
import org.bukkit.block.BlockFace |
|
|
|
import org.bukkit.block.BlockFace |
|
|
|
import org.bukkit.block.data.Directional |
|
|
|
import org.bukkit.block.data.Directional |
|
|
|
import org.bukkit.block.data.Openable |
|
|
|
import org.bukkit.block.data.Openable |
|
|
|
import org.bukkit.block.data.type.Door |
|
|
|
import org.bukkit.util.BoundingBox |
|
|
|
|
|
|
|
|
|
|
|
val MINERAL_TYPES: ImmutableMap<Material, Material> = ImmutableMap.Builder<Material, Material>() |
|
|
|
val MINERAL_TYPES: ImmutableMap<Material, Material> = ImmutableMap.Builder<Material, Material>() |
|
|
|
.put(COAL_BLOCK, BLACK_STAINED_GLASS) |
|
|
|
.put(COAL_BLOCK, BLACK_STAINED_GLASS) |
|
|
@ -32,7 +32,7 @@ val DOOR_TYPES: ImmutableSet<Material> = ImmutableSet.of(ACACIA_DOOR, BIRCH_DOOR |
|
|
|
|
|
|
|
|
|
|
|
fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFrame? { |
|
|
|
fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFrame? { |
|
|
|
when { |
|
|
|
when { |
|
|
|
block.type in state.glassBlocks -> for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
block.type in state.glassBlocks -> for (direction in PortalFrame.ExitDirection.values()) { |
|
|
|
for (vector in direction.glassOffsets) { |
|
|
|
for (vector in direction.glassOffsets) { |
|
|
|
val scanResult = checkPortalFrameAt( |
|
|
|
val scanResult = checkPortalFrameAt( |
|
|
|
block.location.subtract(vector), |
|
|
|
block.location.subtract(vector), |
|
|
@ -44,7 +44,7 @@ fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFra |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
block.type in state.doorBlocks -> for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
block.type in state.doorBlocks -> for (direction in PortalFrame.ExitDirection.values()) { |
|
|
|
for (vector in direction.doorOffsets) { |
|
|
|
for (vector in direction.doorOffsets) { |
|
|
|
val scanResult = checkPortalFrameAt( |
|
|
|
val scanResult = checkPortalFrameAt( |
|
|
|
block.location.subtract(vector), |
|
|
|
block.location.subtract(vector), |
|
|
@ -56,7 +56,7 @@ fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFra |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
block.type in state.mineralBlocks -> for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
block.type in state.mineralBlocks -> for (direction in PortalFrame.ExitDirection.values()) { |
|
|
|
val scanResult = checkPortalFrameAt( |
|
|
|
val scanResult = checkPortalFrameAt( |
|
|
|
block.location.subtract(direction.mineralOffset), |
|
|
|
block.location.subtract(direction.mineralOffset), |
|
|
|
direction, |
|
|
|
direction, |
|
|
@ -71,7 +71,7 @@ fun findPortalFrameConnectedTo(block:Block, state: PortalFrame.State): PortalFra |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Detects whether there is a portal frame in the given state at the given location, extending in the given direction. */ |
|
|
|
/** Detects whether there is a portal frame in the given state at the given location, extending in the given direction. */ |
|
|
|
fun checkPortalFrameAt(location:Location, direction: PortalFrame.EntranceDirection, state: PortalFrame.State): PortalFrame? { |
|
|
|
fun checkPortalFrameAt(location:Location, direction: PortalFrame.ExitDirection, state: PortalFrame.State): PortalFrame? { |
|
|
|
val mineral = (location + direction.mineralOffset).block |
|
|
|
val mineral = (location + direction.mineralOffset).block |
|
|
|
if (mineral.type !in state.mineralBlocks) { |
|
|
|
if (mineral.type !in state.mineralBlocks) { |
|
|
|
return null |
|
|
|
return null |
|
|
@ -92,8 +92,8 @@ fun checkPortalFrameAt(location:Location, direction: PortalFrame.EntranceDirecti |
|
|
|
return PortalFrame(location, direction) |
|
|
|
return PortalFrame(location, direction) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun PortalSaveDataProtos.Portal.Direction.toDirection(): PortalFrame.EntranceDirection { |
|
|
|
fun PortalSaveDataProtos.Portal.Direction.toDirection(): PortalFrame.ExitDirection { |
|
|
|
for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
for (direction in PortalFrame.ExitDirection.values()) { |
|
|
|
if (direction.protoEnum == this) { |
|
|
|
if (direction.protoEnum == this) { |
|
|
|
return direction |
|
|
|
return direction |
|
|
|
} |
|
|
|
} |
|
|
@ -102,7 +102,7 @@ fun PortalSaveDataProtos.Portal.Direction.toDirection(): PortalFrame.EntranceDir |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Information about a portal frame. */ |
|
|
|
/** Information about a portal frame. */ |
|
|
|
data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: EntranceDirection) { |
|
|
|
data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: ExitDirection) { |
|
|
|
enum class State(val glassBlocks: ImmutableSet<Material>, val doorBlocks: ImmutableSet<Material>, val mineralBlocks: ImmutableSet<Material>) { |
|
|
|
enum class State(val glassBlocks: ImmutableSet<Material>, val doorBlocks: ImmutableSet<Material>, val mineralBlocks: ImmutableSet<Material>) { |
|
|
|
ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), |
|
|
|
ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), |
|
|
|
DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)), |
|
|
|
DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)), |
|
|
@ -111,12 +111,12 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: Entran |
|
|
|
|
|
|
|
|
|
|
|
val allValidBlocks:ImmutableSet<Material> = ImmutableSet.Builder<Material>().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).build() |
|
|
|
val allValidBlocks:ImmutableSet<Material> = ImmutableSet.Builder<Material>().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).build() |
|
|
|
} |
|
|
|
} |
|
|
|
/** The direction along which a portal frame extends. */ |
|
|
|
/** The direction a player faces when exiting the portal. */ |
|
|
|
enum class EntranceDirection(toRight: Vector, toBack: Vector, val doorDirection: BlockFace, val protoEnum: PortalSaveDataProtos.Portal.Direction) { |
|
|
|
enum class ExitDirection(val toRight: Vector, val toBack: Vector, val doorDirection: BlockFace, val protoEnum: PortalSaveDataProtos.Portal.Direction) { |
|
|
|
NORTH(Vector(1, 0, 0), Vector(0, 0, 1), BlockFace.SOUTH, PortalSaveDataProtos.Portal.Direction.NORTH), |
|
|
|
NORTH(Vector(1, 0, 0), Vector(0, 0, 1), BlockFace.SOUTH, PortalSaveDataProtos.Portal.Direction.NORTH), |
|
|
|
SOUTH(Vector(1, 0, 0), Vector(0, 0, -1), BlockFace.NORTH, PortalSaveDataProtos.Portal.Direction.SOUTH), |
|
|
|
SOUTH(Vector(-1, 0, 0), Vector(0, 0, -1), BlockFace.NORTH, PortalSaveDataProtos.Portal.Direction.SOUTH), |
|
|
|
EAST(Vector(0, 0, 1), Vector(-1, 0, 0), BlockFace.WEST, PortalSaveDataProtos.Portal.Direction.EAST), |
|
|
|
EAST(Vector(0, 0, 1), Vector(-1, 0, 0), BlockFace.WEST, PortalSaveDataProtos.Portal.Direction.EAST), |
|
|
|
WEST(Vector(0, 0, 1), Vector(1, 0, 0), BlockFace.EAST, PortalSaveDataProtos.Portal.Direction.WEST); |
|
|
|
WEST(Vector(0, 0, -1), Vector(1, 0, 0), BlockFace.EAST, PortalSaveDataProtos.Portal.Direction.WEST); |
|
|
|
|
|
|
|
|
|
|
|
val glassOffsets: ImmutableList<Vector> = ImmutableList.of( |
|
|
|
val glassOffsets: ImmutableList<Vector> = ImmutableList.of( |
|
|
|
// check corners first: |
|
|
|
// check corners first: |
|
|
@ -174,9 +174,35 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: Entran |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val portalCenter = lowerLeftFrontCorner + direction.doorOffsets[0] |
|
|
|
val portalCenter = lowerLeftFrontCorner + direction.doorOffsets[0] |
|
|
|
|
|
|
|
val fullPortalBoundingBox = BoundingBox.of(lowerLeftFrontCorner.block, (lowerLeftFrontCorner + UP * 3 + direction.toRight * 2 + direction.toBack).block) |
|
|
|
|
|
|
|
val portalInsideBoundingBox = BoundingBox.of(portalCenter.block, (portalCenter + UP).block) |
|
|
|
|
|
|
|
|
|
|
|
fun isStandingInPortal(location: Location): Boolean { |
|
|
|
/** Gets the worldless location (direction and position vectors) relative to the center of the chamber, rotating so that the exit is north. */ |
|
|
|
return direction.doorOffsets.any { offset -> location.block.location - offset == lowerLeftFrontCorner } |
|
|
|
fun getRelativeLocationFromAbsoluteLocation(location: Location): Location { |
|
|
|
|
|
|
|
if (portalCenter.world != location.world) { |
|
|
|
|
|
|
|
throw IllegalArgumentException("can't get relative position from ${portalCenter.world} to ${location.world}") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (portalCenter.world == null) { |
|
|
|
|
|
|
|
throw IllegalArgumentException("How did we end up with a relative portal center??") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
val oldDirection = location.direction |
|
|
|
|
|
|
|
val translatedPosition = location.toVector() - (portalCenter + MID_BLOCK_BOTTOM).toVector() |
|
|
|
|
|
|
|
val newLocation = Location(null, translatedPosition.dot(direction.toRight), translatedPosition.dot(UP), translatedPosition.dot(direction.toBack), 0f, 0f) |
|
|
|
|
|
|
|
newLocation.direction = Vector(oldDirection.dot(direction.toRight), oldDirection.dot(UP), oldDirection.dot(direction.toBack)) |
|
|
|
|
|
|
|
return newLocation |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun getAbsoluteLocationFromRelativeLocation(location: Location): Location { |
|
|
|
|
|
|
|
if (location.world != null) { |
|
|
|
|
|
|
|
throw IllegalArgumentException("can't get absolute position from already absolute position") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
val world = portalCenter.world ?: throw IllegalArgumentException("How did we end up with a relative portal center??") |
|
|
|
|
|
|
|
val oldDirection = location.direction |
|
|
|
|
|
|
|
val oldPosition = location.toVector() |
|
|
|
|
|
|
|
val rotatedPosition = Vector(oldPosition.dot(direction.toRight), oldPosition.dot(UP), oldPosition.dot(direction.toBack)) |
|
|
|
|
|
|
|
val newLocation = (rotatedPosition + portalCenter.toVector() + MID_BLOCK_BOTTOM).toLocation(world) |
|
|
|
|
|
|
|
newLocation.direction = Vector(oldDirection.dot(direction.toRight), oldDirection.dot(UP), oldDirection.dot(direction.toBack)) |
|
|
|
|
|
|
|
return newLocation |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block.type |
|
|
|
val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block.type |
|
|
@ -199,6 +225,14 @@ data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: Entran |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun ejectEntities() { |
|
|
|
|
|
|
|
val world = portalCenter.world ?: return |
|
|
|
|
|
|
|
for (entity in world.getNearbyEntities(portalInsideBoundingBox)) { |
|
|
|
|
|
|
|
// kick 'em out the front! |
|
|
|
|
|
|
|
entity.teleport(entity.location - direction.toBack) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun activate() { |
|
|
|
fun activate() { |
|
|
|
val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block |
|
|
|
val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block |
|
|
|
for (offset in direction.glassOffsets) { |
|
|
|
for (offset in direction.glassOffsets) { |
|
|
|