From 289db444d02cb256be1688f21e3d4e9893157bc3 Mon Sep 17 00:00:00 2001 From: Marissa Staib Date: Wed, 10 Apr 2019 15:31:29 -0400 Subject: [PATCH] Faster portal detection --- TODO | 3 +- .../minecraftportal/MinecraftPortalPlugin.kt | 61 ++++---- .../minecraftportal/PortalFrame.kt | 131 ++++++++++-------- .../minecraftportal/extensions/Vector.kt | 3 + 4 files changed, 99 insertions(+), 99 deletions(-) diff --git a/TODO b/TODO index 74475a5..685a789 100644 --- a/TODO +++ b/TODO @@ -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 \ No newline at end of file +* 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 \ No newline at end of file diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt index 0a11fe2..00d8dcd 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/MinecraftPortalPlugin.kt @@ -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") } } } \ No newline at end of file diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/PortalFrame.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/PortalFrame.kt index b46a305..11b1c69 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/PortalFrame.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/PortalFrame.kt @@ -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 = ImmutableMap.Builder() .put(COAL_BLOCK, BLACK_STAINED_GLASS) @@ -24,129 +25,137 @@ val MINERAL_TYPES: ImmutableMap = ImmutableMap.Builder = 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() - val nonmatches = ImmutableList.Builder() +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, val nonMatchingBlocks:List) : Comparable { - 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, val airBlocks: ImmutableSet, val mineralBlocks: ImmutableSet) { +data class PortalFrame(val lowerLeftFrontCorner: Location, val direction: EntranceDirection) { + enum class State(val glassBlocks: ImmutableSet, val doorBlocks: ImmutableSet, val mineralBlocks: ImmutableSet) { 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().addAll(glassBlocks).addAll(airBlocks).addAll(mineralBlocks).build() + val allValidBlocks = ImmutableSet.Builder().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 = 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 = ImmutableList.of( + val doorOffsets: ImmutableList = 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 } } } \ No newline at end of file diff --git a/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Vector.kt b/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Vector.kt index 3073049..d5ac17a 100644 --- a/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Vector.kt +++ b/src/main/kotlin/net/deliciousreya/minecraftportal/extensions/Vector.kt @@ -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) }