add break & place check

optimize code logic of Teleport Listener
This commit is contained in:
tony_all 2023-06-07 15:34:44 +08:00
parent 97c5c1c9fb
commit 45882c8cb6
7 changed files with 81 additions and 33 deletions

View File

@ -15,6 +15,7 @@ class Game(
val scoreboard: GameScoreboard = GameScoreboard(this) val scoreboard: GameScoreboard = GameScoreboard(this)
val timer: GameTimer = GameTimer(this) val timer: GameTimer = GameTimer(this)
val players = ArrayList<Player>() val players = ArrayList<Player>()
val rule = GamePlaceBreakRule(this)
var state: GameState = GameState.WAITING var state: GameState = GameState.WAITING
private fun autoJoinTeam() { private fun autoJoinTeam() {
@ -47,6 +48,7 @@ class Game(
fun start() { fun start() {
debug("game ${map.name} started.") debug("game ${map.name} started.")
state = GameState.START state = GameState.START
timer.startTimer() timer.startTimer()
timer.submitEvent("wall_fall", Duration.ofMinutes(1)) { timer.submitEvent("wall_fall", Duration.ofMinutes(1)) {

View File

@ -1,19 +0,0 @@
package cc.maxmc.blastingcrisis.game
import org.bukkit.Location
class GameBreakRule(val rule: MutableList<(Location) -> Boolean>) {
fun matchRule(location: Location) {
}
fun addRule(rule: (Location) -> Boolean) {
}
fun defaultRule() {
rule.add {
true
}
}
}

View File

@ -0,0 +1,47 @@
package cc.maxmc.blastingcrisis.game
import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule.ActionType.BREAK
import org.bukkit.Location
import org.bukkit.entity.Player
class GamePlaceBreakRule(val game: Game) {
enum class ActionType {
PLACE,
BREAK
}
private val rule = ArrayList<(Player, ActionType, Location) -> Boolean>()
fun matchRule(player: Player, actionType: ActionType, location: Location): Boolean {
// match rules
rule.forEach {
if (it(player, actionType, location)) return true
}
// fallback strategy
return false
}
fun addRule(rule: (Player, Location) -> Boolean) {
}
fun defaultRule(game: Game) {
// allow mine
rule.add { _, _, loc ->
game.map.teams.flatMap {
it.sides + it.mine
}.map {
it.containsBlock(loc)
}.reduce { a, b -> a || b }
}
// allow enemy wall
rule.add { player, type, loc ->
val team = player.team ?: return@add false
val result = game.teams.filterNot { it == team }
.map { team.teamInfo.wall.containsBlock(loc) }
.reduce { a, b -> a || b }
if (type == BREAK) result else !result
}
}
}

View File

@ -20,6 +20,12 @@ class GameTeam(val game: Game, val teamInfo: MapTeam) {
GameListener.interactSubscribed[teamInfo.upgrade] = { GameListener.interactSubscribed[teamInfo.upgrade] = {
debug("interact team ${teamInfo.name} upgrade.") debug("interact team ${teamInfo.name} upgrade.")
} }
GameListener.moveSubscribed.add(teamInfo.teleport to {
val player = it.player ?: throw IllegalStateException("Bukkit API LOL")
debug("teleporting $player to battle field")
val team = player.team ?: throw IllegalStateException("Player ${player.name} should have a team")
player.teleport(team.teamInfo.mine.randomLocation().toPlayerLocation())
})
} }
fun join(player: Player) { fun join(player: Player) {

View File

@ -1,27 +1,29 @@
package cc.maxmc.blastingcrisis.listener package cc.maxmc.blastingcrisis.listener
import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule
import cc.maxmc.blastingcrisis.game.team import cc.maxmc.blastingcrisis.game.team
import cc.maxmc.blastingcrisis.misc.Area
import cc.maxmc.blastingcrisis.misc.GameManager import cc.maxmc.blastingcrisis.misc.GameManager
import cc.maxmc.blastingcrisis.misc.debug import cc.maxmc.blastingcrisis.misc.debug
import cc.maxmc.blastingcrisis.misc.toPlayerLocation
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.event.block.BlockBreakEvent import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.entity.EntityExplodeEvent import org.bukkit.event.entity.EntityExplodeEvent
import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerMoveEvent import org.bukkit.event.player.PlayerMoveEvent
import taboolib.common.platform.event.SubscribeEvent import taboolib.common.platform.event.SubscribeEvent
import taboolib.platform.util.sendLang
object GameListener { object GameListener {
val interactSubscribed = HashMap<Location, (PlayerInteractEvent) -> Unit>() val interactSubscribed = HashMap<Location, (PlayerInteractEvent) -> Unit>()
val moveSubscribed = ArrayList<Pair<Area, (PlayerMoveEvent) -> Unit>>()
@SubscribeEvent @SubscribeEvent
fun portalTeleport(event: PlayerMoveEvent) { fun portalTeleport(event: PlayerMoveEvent) {
if (!GameManager.currentGame.players.contains(event.player)) return if (!GameManager.currentGame.players.contains(event.player)) return
val player = event.player moveSubscribed.forEach { (area, func) ->
val team = player.team ?: return if (area.contains(event.to)) func(event)
if (!team.teamInfo.teleport.isInArea(event.to)) return }
debug("teleporting ${event.player} to battle field")
player.teleport(team.teamInfo.mine.randomLocation().toPlayerLocation())
} }
@SubscribeEvent @SubscribeEvent
@ -36,7 +38,7 @@ object GameListener {
tntExplode.blockList().clear() tntExplode.blockList().clear()
if (!GameManager.currentGame.state.isStarted()) return if (!GameManager.currentGame.state.isStarted()) return
GameManager.currentGame.teams.findLast { GameManager.currentGame.teams.findLast {
it.teamSurvive && it.teamInfo.home.isInArea(tntExplode.location) it.teamSurvive && it.teamInfo.home.contains(tntExplode.location)
}?.apply { }?.apply {
villager.damage() villager.damage()
debug("team ${teamInfo.name}'s villager damaged") debug("team ${teamInfo.name}'s villager damaged")
@ -45,7 +47,19 @@ object GameListener {
@SubscribeEvent @SubscribeEvent
fun onBreak(breakEvent: BlockBreakEvent) { fun onBreak(breakEvent: BlockBreakEvent) {
val loc = breakEvent.block.location val loc = breakEvent.block.location ?: return
val player = breakEvent.player ?: return
if (GameManager.currentGame.rule.matchRule(player, GamePlaceBreakRule.ActionType.BREAK, loc)) return
breakEvent.isCancelled = true
player.sendLang("game_cant_break_block")
}
@SubscribeEvent
fun onPlace(placeEvent: BlockPlaceEvent) {
val loc = placeEvent.block.location ?: return
val player = placeEvent.player ?: return
if (GameManager.currentGame.rule.matchRule(player, GamePlaceBreakRule.ActionType.PLACE, loc)) return
placeEvent.isCancelled = true
player.sendLang("game_cant_place_block")
} }
} }

View File

@ -9,5 +9,4 @@ class MapInfo(
var waitArea: Area, var waitArea: Area,
val teams: List<MapTeam>, val teams: List<MapTeam>,
val maxPlayersPerTeam: Int, val maxPlayersPerTeam: Int,
)
)

View File

@ -31,15 +31,14 @@ class Area(loc1: Location, loc2: Location) : ConfigurationSerializable {
* *
* @return true if the location is in this area * @return true if the location is in this area
*/ */
fun isInArea(location: Location): Boolean { fun contains(location: Location): Boolean {
if (location.world != locTop.world) return false if (location.world != locTop.world) return false
if (location.x !in (locMin.x - 1)..(locTop.x + 1)) return false if (location.x !in (locMin.x - 1)..(locTop.x + 1)) return false
if (location.y !in locMin.y..locTop.y + 1) return false if (location.y !in locMin.y..locTop.y + 1) return false
return location.z in (locMin.z - 1)..(locTop.z + 1) return location.z in (locMin.z - 1)..(locTop.z + 1)
} }
fun isBlockInArea(block: Block): Boolean { fun containsBlock(location: Location): Boolean {
val location = block.location
if (location.world != locTop.world) return false if (location.world != locTop.world) return false
if (location.x !in locMin.x..locTop.x) return false if (location.x !in locMin.x..locTop.x) return false
if (location.y !in locMin.y..locTop.y) return false if (location.y !in locMin.y..locTop.y) return false