|
|
@ -1,31 +1,45 @@ |
|
|
|
package net.deliciousreya.minecraftportal |
|
|
|
package net.deliciousreya.minecraftportal |
|
|
|
|
|
|
|
|
|
|
|
import com.google.common.collect.ImmutableList |
|
|
|
import com.google.common.collect.ImmutableList |
|
|
|
|
|
|
|
import com.google.common.collect.ImmutableMap |
|
|
|
|
|
|
|
import com.google.common.collect.ImmutableSet |
|
|
|
import org.bukkit.Location |
|
|
|
import org.bukkit.Location |
|
|
|
import org.bukkit.Material.AIR |
|
|
|
|
|
|
|
import org.bukkit.Material.GLASS |
|
|
|
|
|
|
|
import org.bukkit.block.Block |
|
|
|
import org.bukkit.block.Block |
|
|
|
import org.bukkit.util.Vector |
|
|
|
import org.bukkit.util.Vector |
|
|
|
import net.deliciousreya.minecraftportal.extensions.* |
|
|
|
import net.deliciousreya.minecraftportal.extensions.* |
|
|
|
|
|
|
|
import org.bukkit.Material |
|
|
|
|
|
|
|
import org.bukkit.Material.* |
|
|
|
|
|
|
|
import org.bukkit.block.BlockFace |
|
|
|
|
|
|
|
|
|
|
|
fun findPortalFrameConnectedTo(block:Block): PortalScanResults { |
|
|
|
val MINERAL_TYPES: ImmutableMap<Material, Material> = ImmutableMap.Builder<Material, Material>() |
|
|
|
|
|
|
|
.put(COAL_BLOCK, BLACK_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(REDSTONE_BLOCK, RED_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(LAPIS_BLOCK, BLUE_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(GOLD_BLOCK, YELLOW_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(DIAMOND_BLOCK, CYAN_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(EMERALD_BLOCK, GREEN_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(IRON_BLOCK, GRAY_STAINED_GLASS) |
|
|
|
|
|
|
|
.put(QUARTZ_BLOCK, WHITE_STAINED_GLASS) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val DOOR_TYPES: ImmutableSet<Material> = ImmutableSet.of(ACACIA_DOOR, BIRCH_DOOR, DARK_OAK_DOOR, IRON_DOOR, JUNGLE_DOOR, OAK_DOOR, SPRUCE_DOOR) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun findPortalFrameConnectedTo(block:Block, state:PortalFrame.State): PortalScanResults { |
|
|
|
var bestScan:PortalScanResults? = null |
|
|
|
var bestScan:PortalScanResults? = null |
|
|
|
if (block.type == GLASS) { |
|
|
|
when { |
|
|
|
for (direction in PortalFrame.Direction.values()) { |
|
|
|
block.type in state.glassBlocks -> for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
for (vector in direction.glassOffsets) { |
|
|
|
for (vector in direction.glassOffsets) { |
|
|
|
val scanResult = checkPortalFrameAt(block.location.subtract(vector), direction) |
|
|
|
val scanResult = checkPortalFrameAt(block.location.subtract(vector), direction, state) |
|
|
|
if (scanResult.frame != null) { |
|
|
|
if (scanResult.frame != null) { |
|
|
|
return scanResult |
|
|
|
return scanResult |
|
|
|
} |
|
|
|
} else if (bestScan == null || scanResult > bestScan) { |
|
|
|
if (bestScan == null || scanResult > bestScan) { |
|
|
|
|
|
|
|
bestScan = scanResult |
|
|
|
bestScan = scanResult |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
block.type in state.airBlocks -> for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
if (block.type == GLASS) { |
|
|
|
for (vector in direction.airOffsets) { |
|
|
|
for (direction in PortalFrame.Direction.values()) { |
|
|
|
val scanResult = checkPortalFrameAt(block.location.subtract(vector), direction, state) |
|
|
|
val scanResult = checkPortalFrameAt(block.location.subtract(direction.mineralOffset), direction) |
|
|
|
|
|
|
|
if (scanResult.frame != null) { |
|
|
|
if (scanResult.frame != null) { |
|
|
|
return scanResult |
|
|
|
return scanResult |
|
|
|
} else if (bestScan == null || scanResult > bestScan) { |
|
|
|
} else if (bestScan == null || scanResult > bestScan) { |
|
|
@ -33,27 +47,32 @@ fun findPortalFrameConnectedTo(block:Block): PortalScanResults { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (bestScan != null) { |
|
|
|
block.type in state.mineralBlocks -> for (direction in PortalFrame.EntranceDirection.values()) { |
|
|
|
return bestScan |
|
|
|
val scanResult = checkPortalFrameAt(block.location.subtract(direction.mineralOffset), direction, state) |
|
|
|
} else { |
|
|
|
if (scanResult.frame != null) { |
|
|
|
return PortalScanResults(null, ImmutableList.of(), ImmutableList.of()) |
|
|
|
return scanResult |
|
|
|
|
|
|
|
} else if (bestScan == null || scanResult > bestScan) { |
|
|
|
|
|
|
|
bestScan = scanResult |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return bestScan!! |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Detects whether there is a portal frame in 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.Direction): PortalScanResults { |
|
|
|
fun checkPortalFrameAt(location:Location, direction:PortalFrame.EntranceDirection, state:PortalFrame.State): PortalScanResults { |
|
|
|
val matches = ImmutableList.Builder<Block>() |
|
|
|
val matches = ImmutableList.Builder<Block>() |
|
|
|
val nonmatches = ImmutableList.Builder<Block>() |
|
|
|
val nonmatches = ImmutableList.Builder<Block>() |
|
|
|
for (vector in direction.glassOffsets) { |
|
|
|
for (vector in direction.glassOffsets) { |
|
|
|
val block = (location + vector).block |
|
|
|
val block = (location + vector).block |
|
|
|
(if (block.type == GLASS) matches else nonmatches).add(block) |
|
|
|
(if (block.type in state.glassBlocks) matches else nonmatches).add(block) |
|
|
|
} |
|
|
|
} |
|
|
|
for (vector in direction.airOffsets) { |
|
|
|
for (vector in direction.airOffsets) { |
|
|
|
val block = (location + vector).block |
|
|
|
val block = (location + vector).block |
|
|
|
(if (block.type == AIR) matches else nonmatches).add(block) |
|
|
|
(if (block.type in state.airBlocks) matches else nonmatches).add(block) |
|
|
|
} |
|
|
|
} |
|
|
|
val block = (location + direction.mineralOffset).block |
|
|
|
val block = (location + direction.mineralOffset).block |
|
|
|
(if (block.type == GLASS) matches else nonmatches).add(block) |
|
|
|
(if (block.type in state.mineralBlocks) matches else nonmatches).add(block) |
|
|
|
val nonmatchesBuilt = nonmatches.build() |
|
|
|
val nonmatchesBuilt = nonmatches.build() |
|
|
|
return PortalScanResults(if (nonmatchesBuilt.isEmpty()) {PortalFrame(location, direction)} else {null}, matches.build(), nonmatchesBuilt) |
|
|
|
return PortalScanResults(if (nonmatchesBuilt.isEmpty()) {PortalFrame(location, direction)} else {null}, matches.build(), nonmatchesBuilt) |
|
|
|
} |
|
|
|
} |
|
|
@ -65,32 +84,69 @@ data class PortalScanResults(val frame: PortalFrame?, val matchingBlocks:List<Bl |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Information about a portal frame. */ |
|
|
|
/** Information about a portal frame. */ |
|
|
|
data class PortalFrame(val lowerLeftCorner: Location, val direction: Direction) { |
|
|
|
data class PortalFrame(val lowerLeftCorner: Location, val direction: EntranceDirection) { |
|
|
|
val UP = Vector(0, 1, 0) |
|
|
|
val UP = Vector(0, 1, 0) |
|
|
|
/** The direction along which a portal frame extends. */ |
|
|
|
enum class State(val glassBlocks: ImmutableSet<Material>, val airBlocks: ImmutableSet<Material>, val mineralBlocks: ImmutableSet<Material>) { |
|
|
|
enum class Direction(vector: Vector) { |
|
|
|
ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)), |
|
|
|
X_AXIS(Vector(1, 0, 0)), |
|
|
|
INACTIVE(ImmutableSet.of(GLASS), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)); |
|
|
|
Z_AXIS(Vector(0, 0, 1)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private val rightSideVector = vector * 2 |
|
|
|
val allValidBlocks = ImmutableSet.Builder<Material>().addAll(glassBlocks).addAll(airBlocks).addAll(mineralBlocks).build() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/** The direction along which a portal frame extends. */ |
|
|
|
|
|
|
|
enum class EntranceDirection(toRight: Vector, toBack: Vector, doorDirection: BlockFace) { |
|
|
|
|
|
|
|
NORTH(Vector(1, 0, 0), Vector(0, 0, 1), BlockFace.NORTH), |
|
|
|
|
|
|
|
SOUTH(Vector(1, 0, 0), Vector(0, 0, -1), BlockFace.SOUTH), |
|
|
|
|
|
|
|
EAST(Vector(0, 0, 1), Vector(-1, 0, 0), BlockFace.EAST), |
|
|
|
|
|
|
|
WEST(Vector(0, 0, 1), Vector(1, 0, 0), BlockFace.WEST); |
|
|
|
|
|
|
|
|
|
|
|
val glassOffsets: ImmutableList<Vector> = ImmutableList.of( |
|
|
|
val glassOffsets: ImmutableList<Vector> = ImmutableList.of( |
|
|
|
Vector(0, 0, 0), |
|
|
|
Vector(0, 0, 0), |
|
|
|
Vector(0, 1, 0), |
|
|
|
Vector(0, 1, 0), |
|
|
|
Vector(0, 2, 0), |
|
|
|
Vector(0, 2, 0), |
|
|
|
Vector(0, 3, 0), |
|
|
|
Vector(0, 3, 0), |
|
|
|
vector, |
|
|
|
Vector(0, 3, 0) + toRight, |
|
|
|
rightSideVector, |
|
|
|
toRight * 2, |
|
|
|
Vector(0, 1, 0) + rightSideVector, |
|
|
|
Vector(0, 1, 0) + toRight * 2, |
|
|
|
Vector(0, 2, 0) + rightSideVector, |
|
|
|
Vector(0, 2, 0) + toRight * 2, |
|
|
|
Vector(0, 3, 0) + rightSideVector |
|
|
|
Vector(0, 3, 0) + toRight * 2, |
|
|
|
|
|
|
|
Vector(0, 0, 0) + toBack, |
|
|
|
|
|
|
|
Vector(0, 1, 0) + toBack, |
|
|
|
|
|
|
|
Vector(0, 2, 0) + toBack, |
|
|
|
|
|
|
|
Vector(0, 3, 0) + toBack, |
|
|
|
|
|
|
|
Vector(0, 0, 0) + toBack + toRight, |
|
|
|
|
|
|
|
Vector(0, 1, 0) + toBack + toRight, |
|
|
|
|
|
|
|
Vector(0, 2, 0) + toBack + toRight, |
|
|
|
|
|
|
|
Vector(0, 3, 0) + toBack + toRight, |
|
|
|
|
|
|
|
Vector(0, 0, 0) + toBack + toRight * 2, |
|
|
|
|
|
|
|
Vector(0, 1, 0) + toBack + toRight * 2, |
|
|
|
|
|
|
|
Vector(0, 2, 0) + toBack + toRight * 2, |
|
|
|
|
|
|
|
Vector(0, 3, 0) + toBack + toRight * 2 |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
val mineralOffset: Vector = Vector(0, 3, 0) + vector |
|
|
|
val mineralOffset: Vector = toRight |
|
|
|
|
|
|
|
|
|
|
|
val airOffsets: ImmutableList<Vector> = ImmutableList.of( |
|
|
|
val airOffsets: ImmutableList<Vector> = ImmutableList.of( |
|
|
|
Vector(0, 1, 0) + vector, |
|
|
|
Vector(0, 1, 0) + toRight, |
|
|
|
Vector(0, 2, 0) + vector |
|
|
|
Vector(0, 2, 0) + toRight |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val portalCenter = lowerLeftCorner + direction.airOffsets[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun isStandingInPortal(location: Location): Boolean { |
|
|
|
|
|
|
|
return direction.airOffsets.any { offset -> location.block.location - offset == lowerLeftCorner } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun color() { |
|
|
|
|
|
|
|
val mineral = (lowerLeftCorner + direction.mineralOffset).block |
|
|
|
|
|
|
|
for (offset in direction.glassOffsets) { |
|
|
|
|
|
|
|
(lowerLeftCorner + offset).block.type = MINERAL_TYPES.getOrDefault(mineral.type, BROWN_STAINED_GLASS) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun uncolor() { |
|
|
|
|
|
|
|
for (offset in direction.glassOffsets) { |
|
|
|
|
|
|
|
(lowerLeftCorner + offset).block.type = GLASS |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |