forked from SteamWar/SteamWar
Migrate FightSystem modes and countdowns to GameCore
- Move shared arena-mode abstractions into GameCore - Adapt fight countdowns and APIs to the shared model - Add SteamWar issue audit workflow and SQL language settings
This commit is contained in:
@@ -27,6 +27,7 @@ kotlin {
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.paperapi)
|
||||
compileOnly(project(":GameCore", "default"))
|
||||
compileOnly(project(":SpigotCore", "default"))
|
||||
compileOnly(project(":KotlinCore", "default"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ package de.steamwar.tntleague
|
||||
import de.steamwar.message.Message
|
||||
import de.steamwar.tntleague.command.*
|
||||
import de.steamwar.tntleague.events.GlobalListener
|
||||
import de.steamwar.tntleague.events.LobbyListener
|
||||
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||
import de.steamwar.tntleague.game.TNTLeagueTeam
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
@@ -38,8 +38,8 @@ class TNTLeague : JavaPlugin() {
|
||||
override fun onEnable() {
|
||||
message = Message("de.steamwar.tntleague.TNTLeague", classLoader)
|
||||
|
||||
server.pluginManager.registerEvents(LobbyListener, this)
|
||||
server.pluginManager.registerEvents(GlobalListener, this)
|
||||
TNTLeagueGame.initialize()
|
||||
|
||||
logger.info("TNTLeague enabled")
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
package de.steamwar.tntleague.config
|
||||
|
||||
import de.steamwar.gamecore.ArenaMode
|
||||
import de.steamwar.gamecore.config.GameRuntimeProperties
|
||||
import de.steamwar.message.SubMessage
|
||||
import de.steamwar.sql.Event
|
||||
import de.steamwar.sql.EventFight
|
||||
@@ -32,16 +34,19 @@ import org.bukkit.inventory.meta.Damageable
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import java.util.*
|
||||
|
||||
private val runtimeProperties = GameRuntimeProperties.load()
|
||||
|
||||
data class TNTLeagueConfig(
|
||||
val startDelay: Int = 10,
|
||||
val gameTime: Int = 60 * 20,
|
||||
|
||||
val prices: Map<Material, Price>,
|
||||
|
||||
val blueLeader: UUID? = System.getProperty("blueLeader")?.let { UUID.fromString(it) },
|
||||
val redLeader: UUID? = System.getProperty("redLeader")?.let { UUID.fromString(it) },
|
||||
val blueLeader: UUID? = runtimeProperties.blueLeader,
|
||||
val redLeader: UUID? = runtimeProperties.redLeader,
|
||||
|
||||
val eventFightId: Int? = System.getProperty("fightID")?.toInt()
|
||||
val eventFightId: Int? = runtimeProperties.fightId.takeIf { it != 0 },
|
||||
val arenaMode: ArenaMode = ArenaMode.from(runtimeProperties),
|
||||
) {
|
||||
lateinit var eventFight: EventFight
|
||||
lateinit var event: Event
|
||||
@@ -92,9 +97,7 @@ data class TNTLeagueConfig(
|
||||
}
|
||||
}
|
||||
|
||||
fun isEvent() =
|
||||
(config.eventFightId
|
||||
?: 0) > 0
|
||||
fun isEvent() = config.arenaMode == ArenaMode.EVENT
|
||||
}
|
||||
|
||||
data class Price(
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
|
||||
package de.steamwar.tntleague.game
|
||||
|
||||
import de.steamwar.gamecore.countdown.Countdown
|
||||
import de.steamwar.gamecore.state.GameStateMachine
|
||||
import de.steamwar.gamecore.state.StateDependentListener
|
||||
import de.steamwar.gamecore.team.TeamRegistry
|
||||
import de.steamwar.gamecore.wincondition.GameResult
|
||||
import de.steamwar.gamecore.wincondition.WinConditions
|
||||
import de.steamwar.kotlin.util.Area
|
||||
import de.steamwar.network.NetworkSender
|
||||
import de.steamwar.network.packets.common.FightInfoPacket
|
||||
@@ -41,38 +47,49 @@ import org.bukkit.Sound
|
||||
import org.bukkit.entity.Item
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.entity.TNTPrimed
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.sql.Timestamp
|
||||
import java.time.Instant
|
||||
|
||||
object TNTLeagueGame {
|
||||
var state: GameState = GameState.LOBBY
|
||||
private val stateMachine = GameStateMachine(GameState.LOBBY)
|
||||
private val stateDependencies by lazy {
|
||||
listOf(
|
||||
StateDependentListener(stateMachine, true, setOf(GameState.LOBBY, GameState.STARTING), plugin, LobbyListener),
|
||||
StateDependentListener(stateMachine, true, setOf(GameState.RUNNING), plugin, IngameListener),
|
||||
StateDependentListener(stateMachine, true, setOf(GameState.END), plugin, DummyListener),
|
||||
)
|
||||
}
|
||||
|
||||
var state: GameState
|
||||
get() = stateMachine.currentState
|
||||
set(value) {
|
||||
if (field.listener != value.listener) {
|
||||
HandlerList.unregisterAll(field.listener)
|
||||
plugin.server.pluginManager.registerEvents(value.listener, plugin)
|
||||
}
|
||||
field = value
|
||||
stateMachine.transitionTo(value)
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
stateDependencies
|
||||
}
|
||||
|
||||
var gameTimeRemaining: Int = TNTLeagueConfig.config.gameTime
|
||||
|
||||
val blueTeam = TNTLeagueTeam(TNTLeagueConfig.config.blueTeam)
|
||||
val redTeam = TNTLeagueTeam(TNTLeagueConfig.config.redTeam)
|
||||
private val teams = TeamRegistry<TNTLeagueTeam, Player>(listOf(blueTeam, redTeam))
|
||||
|
||||
private lateinit var start: Timestamp
|
||||
|
||||
private var task: Int? = null
|
||||
private var startCountdown: Countdown? = null
|
||||
private var gameCountdown: Countdown? = null
|
||||
private var endCountdown: Countdown? = null
|
||||
private lateinit var spawnerTask: BukkitTask
|
||||
private lateinit var timerTask: BukkitTask
|
||||
|
||||
private fun setup() {
|
||||
assert(state == GameState.STARTING) { "Game is already running" }
|
||||
|
||||
state = GameState.RUNNING
|
||||
gameTimeRemaining = TNTLeagueConfig.config.gameTime
|
||||
|
||||
plugin.server.onlinePlayers.forEach { SWScoreboard.impl.createScoreboard(it, TNTLeagueScoreboard(it)) }
|
||||
|
||||
@@ -104,24 +121,33 @@ object TNTLeagueGame {
|
||||
}
|
||||
}, 5, 10)
|
||||
|
||||
timerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
|
||||
gameTimeRemaining--
|
||||
if (gameTimeRemaining == 0) {
|
||||
if (blueTeam.damagedBlocks > redTeam.damagedBlocks) {
|
||||
win(blueTeam, WinReason.TIMEOUT)
|
||||
} else if (redTeam.damagedBlocks > blueTeam.damagedBlocks) {
|
||||
win(redTeam, WinReason.TIMEOUT)
|
||||
} else {
|
||||
draw(WinReason.TIMEOUT)
|
||||
gameCountdown = object : Countdown(
|
||||
plugin,
|
||||
TNTLeagueConfig.config.gameTime,
|
||||
20,
|
||||
20,
|
||||
false,
|
||||
) {
|
||||
override fun onTick(timeLeft: Int) {
|
||||
gameTimeRemaining = timeLeft
|
||||
if (timeLeft > 0 && timeLeft % 300 == 0) {
|
||||
message.broadcast("TIME_REMAINING", (timeLeft / 60))
|
||||
plugin.server.onlinePlayers.forEach {
|
||||
it.playSound(it.location, Sound.BLOCK_NOTE_BLOCK_PLING, 1f, 1f)
|
||||
}
|
||||
}
|
||||
return@bukkit
|
||||
}
|
||||
|
||||
if (gameTimeRemaining % 300 == 0) {
|
||||
message.broadcast("TIME_REMAINING", (gameTimeRemaining / 60))
|
||||
plugin.server.onlinePlayers.forEach { it.playSound(it.location, Sound.BLOCK_NOTE_BLOCK_PLING, 1f, 1f) }
|
||||
override fun onFinished() {
|
||||
when (val result = WinConditions.winnerByScore(
|
||||
teams.teams,
|
||||
{ team -> team.damagedBlocks.toDouble() },
|
||||
)) {
|
||||
is GameResult.Winner -> win(result.winner, WinReason.TIMEOUT)
|
||||
GameResult.Draw -> draw(WinReason.TIMEOUT)
|
||||
}
|
||||
}
|
||||
}, 20, 20)
|
||||
}.also { it.enable() }
|
||||
}
|
||||
|
||||
private fun bukkit(f: () -> Unit): () -> Unit =
|
||||
@@ -140,18 +166,19 @@ object TNTLeagueGame {
|
||||
message.broadcast("GAME_ENDED")
|
||||
|
||||
spawnerTask.cancel()
|
||||
gameCountdown?.disable()
|
||||
|
||||
var shutdown = 10
|
||||
|
||||
plugin.server.scheduler.runTaskTimer(plugin, bukkit {
|
||||
if (shutdown == 0) {
|
||||
plugin.server.shutdown()
|
||||
endCountdown = object : Countdown(plugin, 11, 20, 20, false) {
|
||||
override fun onTick(timeLeft: Int) {
|
||||
if (timeLeft > 0) {
|
||||
message.broadcast("SHUTDOWN", timeLeft)
|
||||
}
|
||||
}
|
||||
|
||||
message.broadcast("SHUTDOWN", shutdown)
|
||||
|
||||
shutdown--
|
||||
}, 20, 20)
|
||||
override fun onFinished() {
|
||||
plugin.server.shutdown()
|
||||
}
|
||||
}.also { it.enable() }
|
||||
|
||||
updateFightinfo()
|
||||
}
|
||||
@@ -160,7 +187,10 @@ object TNTLeagueGame {
|
||||
plugin.server.worlds.first().dropItem(loc, item)
|
||||
|
||||
fun getTeam(player: Player) =
|
||||
if (player in blueTeam.members) blueTeam else if (player in redTeam.members) redTeam else null
|
||||
teams.findTeam(player)
|
||||
|
||||
fun opposite(team: TNTLeagueTeam) =
|
||||
teams.opposite(team)
|
||||
|
||||
fun getFreeTeam(player: Player) =
|
||||
if (TNTLeagueConfig.isEvent()) getEventFreeTeam(player) else getNormalFreeTeam(player)
|
||||
@@ -178,27 +208,31 @@ object TNTLeagueGame {
|
||||
}
|
||||
|
||||
fun checkStart() {
|
||||
if (blueTeam.isReady && redTeam.isReady) {
|
||||
if (teams.allReady()) {
|
||||
blueTeam.leader?.inventory?.clear()
|
||||
redTeam.leader?.inventory?.clear()
|
||||
state = GameState.STARTING
|
||||
|
||||
var countdown = TNTLeagueConfig.config.startDelay
|
||||
message.broadcast("GAME_STARTING", countdown.toString())
|
||||
task = plugin.server.scheduler.scheduleSyncRepeatingTask(plugin, {
|
||||
plugin.server.onlinePlayers.forEach { it.playSound(it.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1f) }
|
||||
if (--countdown == 0) {
|
||||
plugin.server.onlinePlayers.forEach { it.level = 0 }
|
||||
task = task?.also { plugin.server.scheduler.cancelTask(it) }.let { null }
|
||||
setup()
|
||||
} else {
|
||||
plugin.server.onlinePlayers.forEach { it.level = countdown }
|
||||
message.broadcast("GAME_STARTING", TNTLeagueConfig.config.startDelay.toString())
|
||||
startCountdown = object : Countdown(
|
||||
plugin,
|
||||
TNTLeagueConfig.config.startDelay,
|
||||
20,
|
||||
20,
|
||||
false,
|
||||
) {
|
||||
override fun onTick(timeLeft: Int) {
|
||||
plugin.server.onlinePlayers.forEach {
|
||||
it.playSound(it.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1f)
|
||||
it.level = timeLeft
|
||||
}
|
||||
}
|
||||
}, 20, 20)
|
||||
|
||||
if (task == -1) {
|
||||
error("Failed to start countdown task")
|
||||
}
|
||||
override fun onFinished() {
|
||||
plugin.server.onlinePlayers.forEach { it.level = 0 }
|
||||
setup()
|
||||
}
|
||||
}.also { it.enable() }
|
||||
|
||||
updateFightinfo()
|
||||
}
|
||||
@@ -216,7 +250,8 @@ object TNTLeagueGame {
|
||||
assert(state == GameState.LOBBY || state == GameState.STARTING) { "Game is not in lobby or starting state" }
|
||||
|
||||
if (state == GameState.STARTING) {
|
||||
task = task?.also { plugin.server.scheduler.cancelTask(it) }.let { null }
|
||||
startCountdown?.disable()
|
||||
startCountdown = null
|
||||
state = GameState.LOBBY
|
||||
}
|
||||
|
||||
@@ -277,11 +312,11 @@ object TNTLeagueGame {
|
||||
))
|
||||
}
|
||||
|
||||
enum class GameState(val listener: Listener, val lobbyName: String) {
|
||||
LOBBY(LobbyListener, "PRE_LEADER_SETUP"),
|
||||
STARTING(LobbyListener, "POST_SCHEM_SETUP"),
|
||||
RUNNING(IngameListener, "RUNNING"),
|
||||
END(DummyListener, "SPECTATE");
|
||||
enum class GameState(val lobbyName: String) {
|
||||
LOBBY("PRE_LEADER_SETUP"),
|
||||
STARTING("POST_SCHEM_SETUP"),
|
||||
RUNNING("RUNNING"),
|
||||
END("SPECTATE");
|
||||
}
|
||||
|
||||
enum class WinReason {
|
||||
@@ -289,4 +324,4 @@ object TNTLeagueGame {
|
||||
DESTROYED,
|
||||
LEAVE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package de.steamwar.tntleague.game
|
||||
|
||||
import de.steamwar.message.SubMessage
|
||||
import de.steamwar.gamecore.team.GameTeam
|
||||
import de.steamwar.tntleague.colorByTeam
|
||||
import de.steamwar.tntleague.config.TNTLeagueWorldConfig
|
||||
import de.steamwar.tntleague.config.TeamConfig
|
||||
@@ -36,7 +37,7 @@ import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
data class TNTLeagueTeam(val config: TeamConfig) {
|
||||
data class TNTLeagueTeam(val config: TeamConfig) : GameTeam<Player> {
|
||||
|
||||
var leader: Player? = null
|
||||
set(player) {
|
||||
@@ -82,11 +83,7 @@ data class TNTLeagueTeam(val config: TeamConfig) {
|
||||
var coins: Int = 0
|
||||
|
||||
val opposite: TNTLeagueTeam
|
||||
get() = when (this) {
|
||||
TNTLeagueGame.redTeam -> TNTLeagueGame.blueTeam
|
||||
TNTLeagueGame.blueTeam -> TNTLeagueGame.redTeam
|
||||
else -> error("Invalid Team")
|
||||
}
|
||||
get() = TNTLeagueGame.opposite(this)
|
||||
|
||||
val ergebnisInt: Int
|
||||
get() = when (this) {
|
||||
@@ -95,6 +92,21 @@ data class TNTLeagueTeam(val config: TeamConfig) {
|
||||
else -> error("Invalid Team")
|
||||
}
|
||||
|
||||
override fun teamId() =
|
||||
name.message
|
||||
|
||||
override fun members(): Collection<Player> =
|
||||
members
|
||||
|
||||
override fun leader(): Player? =
|
||||
leader
|
||||
|
||||
override fun ready() =
|
||||
isReady
|
||||
|
||||
override fun contains(member: Player) =
|
||||
member in members
|
||||
|
||||
fun join(player: Player): Boolean {
|
||||
members.add(player)
|
||||
|
||||
@@ -168,4 +180,4 @@ data class TNTLeagueTeam(val config: TeamConfig) {
|
||||
}
|
||||
updateFightinfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ load: POSTWORLD
|
||||
api-version: '1.21'
|
||||
dependencies:
|
||||
server:
|
||||
GameCore:
|
||||
required: true
|
||||
load: BEFORE
|
||||
SpigotCore:
|
||||
required: true
|
||||
load: BEFORE
|
||||
KotlinCore:
|
||||
required: true
|
||||
load: BEFORE
|
||||
load: BEFORE
|
||||
|
||||
Reference in New Issue
Block a user