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 timer: GameTimer = GameTimer(this)
val players = ArrayList<Player>()
val rule = GamePlaceBreakRule(this)
var state: GameState = GameState.WAITING
private fun autoJoinTeam() {
@ -47,6 +48,7 @@ class Game(
fun start() {
debug("game ${map.name} started.")
state = GameState.START
timer.startTimer()
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] = {
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) {

View File

@ -1,27 +1,29 @@
package cc.maxmc.blastingcrisis.listener
import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule
import cc.maxmc.blastingcrisis.game.team
import cc.maxmc.blastingcrisis.misc.Area
import cc.maxmc.blastingcrisis.misc.GameManager
import cc.maxmc.blastingcrisis.misc.debug
import cc.maxmc.blastingcrisis.misc.toPlayerLocation
import org.bukkit.Location
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.entity.EntityExplodeEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerMoveEvent
import taboolib.common.platform.event.SubscribeEvent
import taboolib.platform.util.sendLang
object GameListener {
val interactSubscribed = HashMap<Location, (PlayerInteractEvent) -> Unit>()
val moveSubscribed = ArrayList<Pair<Area, (PlayerMoveEvent) -> Unit>>()
@SubscribeEvent
fun portalTeleport(event: PlayerMoveEvent) {
if (!GameManager.currentGame.players.contains(event.player)) return
val player = event.player
val team = player.team ?: return
if (!team.teamInfo.teleport.isInArea(event.to)) return
debug("teleporting ${event.player} to battle field")
player.teleport(team.teamInfo.mine.randomLocation().toPlayerLocation())
moveSubscribed.forEach { (area, func) ->
if (area.contains(event.to)) func(event)
}
}
@SubscribeEvent
@ -36,7 +38,7 @@ object GameListener {
tntExplode.blockList().clear()
if (!GameManager.currentGame.state.isStarted()) return
GameManager.currentGame.teams.findLast {
it.teamSurvive && it.teamInfo.home.isInArea(tntExplode.location)
it.teamSurvive && it.teamInfo.home.contains(tntExplode.location)
}?.apply {
villager.damage()
debug("team ${teamInfo.name}'s villager damaged")
@ -45,7 +47,19 @@ object GameListener {
@SubscribeEvent
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,
val teams: List<MapTeam>,
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
*/
fun isInArea(location: Location): Boolean {
fun contains(location: Location): Boolean {
if (location.world != locTop.world) 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
return location.z in (locMin.z - 1)..(locTop.z + 1)
}
fun isBlockInArea(block: Block): Boolean {
val location = block.location
fun containsBlock(location: Location): Boolean {
if (location.world != locTop.world) return false
if (location.x !in locMin.x..locTop.x) return false
if (location.y !in locMin.y..locTop.y) return false