1
0
Fork 0
The portal creating plugin for Minecraft.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
6.6 KiB

package net.deliciousreya.minecraftportal
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.block.Block
import org.bukkit.util.Vector
import net.deliciousreya.minecraftportal.extensions.*
import org.bukkit.Material
import org.bukkit.Material.*
import org.bukkit.block.BlockFace
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
when {
block.type in state.glassBlocks -> for (direction in PortalFrame.EntranceDirection.values()) {
for (vector in direction.glassOffsets) {
val scanResult = checkPortalFrameAt(block.location.subtract(vector), direction, state)
if (scanResult.frame != null) {
return scanResult
} else if (bestScan == null || scanResult > bestScan) {
bestScan = scanResult
}
}
}
block.type in state.airBlocks -> for (direction in PortalFrame.EntranceDirection.values()) {
for (vector in direction.airOffsets) {
val scanResult = checkPortalFrameAt(block.location.subtract(vector), direction, state)
if (scanResult.frame != null) {
return scanResult
} else if (bestScan == null || scanResult > bestScan) {
bestScan = scanResult
}
}
}
block.type in state.mineralBlocks -> for (direction in PortalFrame.EntranceDirection.values()) {
val scanResult = checkPortalFrameAt(block.location.subtract(direction.mineralOffset), direction, state)
if (scanResult.frame != null) {
return scanResult
} else if (bestScan == null || scanResult > bestScan) {
bestScan = scanResult
}
}
}
return bestScan!!
}
/** 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): PortalScanResults {
val matches = ImmutableList.Builder<Block>()
val nonmatches = ImmutableList.Builder<Block>()
for (vector in direction.glassOffsets) {
val block = (location + vector).block
(if (block.type in state.glassBlocks) matches else nonmatches).add(block)
}
for (vector in direction.airOffsets) {
val block = (location + vector).block
(if (block.type in state.airBlocks) matches else nonmatches).add(block)
}
val block = (location + direction.mineralOffset).block
(if (block.type in state.mineralBlocks) matches else nonmatches).add(block)
val nonmatchesBuilt = nonmatches.build()
return PortalScanResults(if (nonmatchesBuilt.isEmpty()) {PortalFrame(location, direction)} else {null}, matches.build(), nonmatchesBuilt)
}
data class PortalScanResults(val frame: PortalFrame?, val matchingBlocks:List<Block>, val nonMatchingBlocks:List<Block>) : Comparable<PortalScanResults> {
override fun compareTo(other:PortalScanResults): Int {
return matchingBlocks.size - other.matchingBlocks.size
}
}
/** Information about a portal frame. */
data class PortalFrame(val lowerLeftCorner: Location, val direction: EntranceDirection) {
val UP = Vector(0, 1, 0)
enum class State(val glassBlocks: ImmutableSet<Material>, val airBlocks: ImmutableSet<Material>, val mineralBlocks: ImmutableSet<Material>) {
ACTIVE(ImmutableSet.copyOf(MINERAL_TYPES.values), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys)),
INACTIVE(ImmutableSet.of(GLASS), DOOR_TYPES, ImmutableSet.copyOf(MINERAL_TYPES.keys));
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(
Vector(0, 0, 0),
Vector(0, 1, 0),
Vector(0, 2, 0),
Vector(0, 3, 0),
Vector(0, 3, 0) + toRight,
toRight * 2,
Vector(0, 1, 0) + toRight * 2,
Vector(0, 2, 0) + toRight * 2,
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 = toRight
val airOffsets: ImmutableList<Vector> = ImmutableList.of(
Vector(0, 1, 0) + toRight,
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
}
}
}