1
0
Fork 0

Faster portal detection

main
Marissa Staib 5 years ago
parent 52b937f7d2
commit 289db444d0
  1. 3
      TODO
  2. 61
      src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt
  3. 131
      src/main/kotlin/net/deliciousreya/minecraftportal/PortalFrame.kt
  4. 3
      src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Vector.kt

@ -6,4 +6,5 @@
* close the door on the other side when someone shuts the door
* teleport everyone inside the portal, not just the person who closed the door
* interrupt teleportation if portal is destroyed mid-teleportation
* save any effects that would be overwritten by teleportation (including to disk!), and put them back when the player opens the door or arrives
* save any effects that would be overwritten by teleportation (including to disk!), and put them back when the player opens the door or arrives
* add portal particles and ambient sounds to the teleporter

@ -31,11 +31,11 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
fun onBlockPlaced(e: BlockPlaceEvent) {
if (e.block.type in PortalFrame.State.INACTIVE.allValidBlocks) {
val portalScanResults = findPortalFrameConnectedTo(e.block, PortalFrame.State.INACTIVE)
if (portalScanResults.frame != null) {
if (portalScanResults != null) {
logger.info("found portal frame, creating portal")
portalScanResults.frame.color()
e.block.world.playSound(portalScanResults.frame.portalCenter, Sound.BLOCK_BEACON_ACTIVATE, 20f, 1f)
e.block.world.spawnParticle(Particle.SPELL, portalScanResults.frame.portalCenter, 40)
portalScanResults.color()
e.block.world.playSound(portalScanResults.portalCenter, Sound.BLOCK_BEACON_ACTIVATE, 20f, 1f)
e.block.world.spawnParticle(Particle.SPELL, portalScanResults.portalCenter, 40)
} else {
logger.info("no portal frame found matching placed block, ignoring")
}
@ -68,11 +68,6 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
onDestroyedBlock(e.block)
}
@EventHandler
fun onSpongeAbsorb(e: SpongeAbsorbEvent) {
e.blocks.forEach { blockstate -> onDestroyedBlock(blockstate.location.block) }
}
@EventHandler
fun onBlockBreak(e:BlockBreakEvent) {
onDestroyedBlock(e.block)
@ -83,11 +78,6 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
onDestroyedBlock(e.block)
}
@EventHandler
fun onPlayerFillBucket(e: PlayerBucketFillEvent) {
onDestroyedBlock(e.blockClicked)
}
@EventHandler
fun onPlayerInteract(e: PlayerInteractEvent) {
if (e.clickedBlock == null || e.action != Action.RIGHT_CLICK_BLOCK) {
@ -97,42 +87,39 @@ class MinecraftPortalPlugin() : JavaPlugin(), Listener
if(block.type !in DOOR_TYPES) {
return
}
val portalScanResults = findPortalFrameConnectedTo(block, PortalFrame.State.ACTIVE)
if (portalScanResults.frame == null) {
return
}
val portalScanResults = findPortalFrameConnectedTo(block, PortalFrame.State.ACTIVE) ?: return
val door = block.blockData as Door
if (!portalScanResults.frame.isStandingInPortal(e.player.location)) {
if (!portalScanResults.isStandingInPortal(e.player.location)) {
e.isCancelled = true
return
}
if (door.isOpen) {
// door is about to be closed, so drug the player
e.player.playSound(e.player.location, Sound.BLOCK_PORTAL_TRIGGER, 20f, 1f)
e.player.addPotionEffect(PotionEffect(PotionEffectType.CONFUSION, 200, 10, false, false, false))
e.player.addPotionEffect(PotionEffect(PotionEffectType.BLINDNESS, 200, 1, false, false, false))
e.player.addPotionEffect(PotionEffect(PotionEffectType.INVISIBILITY, 200, 1, false, false, false))
} else {
if (!door.isOpen) {
// door is about to be opened, so undrug the player
e.player.stopSound(Sound.BLOCK_PORTAL_TRIGGER)
e.player.removePotionEffect(PotionEffectType.BLINDNESS)
e.player.removePotionEffect(PotionEffectType.CONFUSION)
e.player.removePotionEffect(PotionEffectType.INVISIBILITY)
} else {
// door is about to be closed, so drug the player
e.player.playSound(e.player.location, Sound.BLOCK_PORTAL_TRIGGER, 20f, 1f)
e.player.addPotionEffect(PotionEffect(PotionEffectType.CONFUSION, 200, 1, false, false, false))
e.player.addPotionEffect(PotionEffect(PotionEffectType.BLINDNESS, 200, 1, false, false, false))
e.player.addPotionEffect(PotionEffect(PotionEffectType.INVISIBILITY, 200, 1, false, false, false))
}
}
fun onDestroyedBlock(block: Block) {
if (block.type in PortalFrame.State.ACTIVE.allValidBlocks) {
val portalScanResults = findPortalFrameConnectedTo(block, PortalFrame.State.ACTIVE)
if (portalScanResults.frame != null) {
logger.info("found portal frame matching destroyed block, deactivating")
portalScanResults.frame.uncolor()
block.world.playSound(portalScanResults.frame.portalCenter, Sound.BLOCK_BEACON_DEACTIVATE, 20f, 1f)
block.world.spawnParticle(Particle.SMOKE_NORMAL, portalScanResults.frame.portalCenter, 40)
} else {
logger.info("no portal frame found matching destroyed block, ignoring")
}
if (block.type !in PortalFrame.State.ACTIVE.allValidBlocks) {
return
}
val portalScanResults = findPortalFrameConnectedTo(block, PortalFrame.State.ACTIVE)
if (portalScanResults != null) {
logger.info("found portal frame matching destroyed block, deactivating")
portalScanResults.uncolor()
block.world.playSound(portalScanResults.portalCenter, Sound.BLOCK_BEACON_DEACTIVATE, 20f, 1f)
block.world.spawnParticle(Particle.SMOKE_NORMAL, portalScanResults.portalCenter, 40)
} else {
logger.info("no portal frame found matching destroyed block, ignoring")
}
}
}

@ -10,6 +10,7 @@ import net.deliciousreya.minecraftportal.extensions.*
import org.bukkit.Material
import org.bukkit.Material.*
import org.bukkit.block.BlockFace
import org.bukkit.material.Directional
val MINERAL_TYPES: ImmutableMap<Material, Material> = ImmutableMap.Builder<Material, Material>()
.put(COAL_BLOCK, BLACK_STAINED_GLASS)
@ -24,129 +25,137 @@ val MINERAL_TYPES: ImmutableMap<Material, Material> = ImmutableMap.Builder<Mater
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
fun findPortalFrameConnectedTo(block:Block, state:PortalFrame.State): PortalFrame? {
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) {
if (scanResult != 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) {
block.type in state.doorBlocks -> for (direction in PortalFrame.EntranceDirection.values()) {
for (vector in direction.doorOffsets) {
val scanResult = checkPortalFrameAt(block.location.subtract(vector), direction, state)
if (scanResult.frame != null) {
if (scanResult != 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) {
if (scanResult != null) {
return scanResult
} else if (bestScan == null || scanResult > bestScan) {
bestScan = scanResult
}
}
}
return bestScan!!
return null
}
/** 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>()
fun checkPortalFrameAt(location:Location, direction:PortalFrame.EntranceDirection, state:PortalFrame.State): PortalFrame? {
val mineral = (location + direction.mineralOffset).block
if (mineral.type !in state.mineralBlocks) {
return null
}
for (vector in direction.glassOffsets) {
val block = (location + vector).block
(if (block.type in state.glassBlocks) matches else nonmatches).add(block)
if (block.type !in state.glassBlocks) {
return null
}
}
for (vector in direction.airOffsets) {
for (vector in direction.doorOffsets) {
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
if (block.type !in state.doorBlocks || (block.blockData is Directional && (block.blockData as Directional).facing != direction.doorDirection)) {
return null
}
}
return PortalFrame(location, direction)
}
/** 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>) {
data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: EntranceDirection) {
enum class State(val glassBlocks: ImmutableSet<Material>, val doorBlocks: 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()
val allValidBlocks = ImmutableSet.Builder<Material>().addAll(glassBlocks).addAll(doorBlocks).addAll(mineralBlocks).build()
}
/** The direction along which a portal frame extends. */
enum class EntranceDirection(toRight: Vector, toBack: Vector, doorDirection: BlockFace) {
enum class EntranceDirection(toRight: Vector, toBack: Vector, val 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,
// check corners first:
// bottom left, front
ZERO,
// top right, back
UP * 3 + toBack + toRight * 2,
// bottom right, front
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
// top right, front
UP * 3 + toRight * 2,
// top left, front
UP * 3,
// bottom left, back
toBack,
// top left, back
UP * 3 + toBack,
// bottom right, back
toBack + toRight * 2,
// then do front walls
// left front wall
UP,
UP * 2,
// top front wall
UP * 3 + toRight,
// right front wall
UP + toRight * 2,
UP * 2 + toRight * 2,
// now do the rest of the back
// left back wall
UP + toBack,
UP * 2 + toBack,
// center back wall
toBack + toRight,
UP + toBack + toRight,
UP * 2 + toBack + toRight,
UP * 3 + toBack + toRight,
// right back wall
UP + toBack + toRight * 2,
UP * 2 + toBack + toRight * 2
)
val mineralOffset: Vector = toRight
val airOffsets: ImmutableList<Vector> = ImmutableList.of(
val doorOffsets: ImmutableList<Vector> = ImmutableList.of(
Vector(0, 1, 0) + toRight,
Vector(0, 2, 0) + toRight
)
}
val portalCenter = lowerLeftCorner + direction.airOffsets[0]
val portalCenter = lowerLeftFrontCorner + direction.doorOffsets[0]
fun isStandingInPortal(location: Location): Boolean {
return direction.airOffsets.any { offset -> location.block.location - offset == lowerLeftCorner }
return direction.doorOffsets.any { offset -> location.block.location - offset == lowerLeftFrontCorner }
}
fun color() {
val mineral = (lowerLeftCorner + direction.mineralOffset).block
val mineral = (lowerLeftFrontCorner + direction.mineralOffset).block
for (offset in direction.glassOffsets) {
(lowerLeftCorner + offset).block.type = MINERAL_TYPES.getOrDefault(mineral.type, BROWN_STAINED_GLASS)
(lowerLeftFrontCorner + offset).block.type = MINERAL_TYPES.getOrDefault(mineral.type, BROWN_STAINED_GLASS)
}
}
fun uncolor() {
for (offset in direction.glassOffsets) {
(lowerLeftCorner + offset).block.type = GLASS
(lowerLeftFrontCorner + offset).block.type = GLASS
}
}
}

@ -2,6 +2,9 @@ package net.deliciousreya.minecraftportal.extensions
import org.bukkit.util.Vector
val ZERO = Vector(0, 0, 0)
val UP = Vector(0, 1, 0)
operator fun Vector.plus(v:Vector):Vector {
return this.clone().add(v)
}

Loading…
Cancel
Save