Remove legacy modules, add language & scoreboard
Large refactor removing many legacy subsystems (abilities, kit system, database repos, recraft, world manager, extensive config classes, lunar/luckperms integrations and various listeners/commands). Introduces a lightweight LanguageManager, AntiRunningManager, ScoreboardManager, ConnectListener and a SoupListener; simplifies the main SpeedHG plugin to initialize these components and register the connection listener. Build changes: update Gradle wrapper to 8.10, remove paperweight and several external dependencies, add fr.mrmicky:fastboard and simplify shadowJar/build task configuration. Adds default language resource (languages/en_US.yml) and updates plugin/config resources. Purpose: simplify and decouple the plugin, reduce dependency surface and prepare for a leaner, modular rewrite.
This commit is contained in:
@@ -2,7 +2,6 @@ plugins {
|
|||||||
id("java")
|
id("java")
|
||||||
id("maven-publish")
|
id("maven-publish")
|
||||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||||
id("io.papermc.paperweight.userdev") version "1.7.1"
|
|
||||||
kotlin("jvm") version libs.versions.kotlin
|
kotlin("jvm") version libs.versions.kotlin
|
||||||
kotlin("kapt") version libs.versions.kotlin
|
kotlin("kapt") version libs.versions.kotlin
|
||||||
}
|
}
|
||||||
@@ -18,36 +17,11 @@ repositories {
|
|||||||
maven("https://libraries.minecraft.net/")
|
maven("https://libraries.minecraft.net/")
|
||||||
maven("https://repo.codemc.io/repository/maven-public/")
|
maven("https://repo.codemc.io/repository/maven-public/")
|
||||||
maven("https://repo.lunarclient.dev")
|
maven("https://repo.lunarclient.dev")
|
||||||
|
|
||||||
maven {
|
|
||||||
url = uri("https://maven.pkg.github.com/McScrims-Network/Main-CoreSystem")
|
|
||||||
credentials {
|
|
||||||
username = System.getenv("GITHUB_ACTOR")
|
|
||||||
password = System.getenv("GITHUB_TOKEN")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.mongodb:mongodb-driver-kotlin-coroutine:4.11.1")
|
implementation("fr.mrmicky:fastboard:2.1.3")
|
||||||
implementation("org.mongodb:bson-kotlinx:4.11.1")
|
|
||||||
|
|
||||||
implementation("net.kyori:adventure-api:4.14.0")
|
|
||||||
implementation("net.kyori:adventure-text-minimessage:4.14.0")
|
|
||||||
implementation("net.kyori:adventure-platform-bukkit:4.3.2")
|
|
||||||
|
|
||||||
compileOnly("net.luckperms:api:5.4")
|
|
||||||
|
|
||||||
compileOnly("com.lunarclient:apollo-api:1.2.0")
|
|
||||||
compileOnly("com.lunarclient:apollo-extra-adventure4:1.2.0")
|
|
||||||
|
|
||||||
compileOnly("org.popcraft:chunky-common:1.3.38")
|
|
||||||
|
|
||||||
implementation("club.mcscrims:core:1.4.3.2")
|
|
||||||
implementation("club.mcscrims:spigot:1.4.3.2")
|
|
||||||
|
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
|
||||||
paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
@@ -65,10 +39,6 @@ tasks {
|
|||||||
archiveVersion.set(project.version.toString())
|
archiveVersion.set(project.version.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
assemble {
|
|
||||||
dependsOn( reobfJar )
|
|
||||||
}
|
|
||||||
|
|
||||||
build {
|
build {
|
||||||
dependsOn( shadowJar )
|
dependsOn( shadowJar )
|
||||||
}
|
}
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -1,291 +1,61 @@
|
|||||||
package club.mcscrims.speedhg
|
package club.mcscrims.speedhg
|
||||||
|
|
||||||
import club.mcscrims.core.config.ConfigData
|
import club.mcscrims.speedhg.config.LanguageManager
|
||||||
import club.mcscrims.core.config.ConfigFormat
|
|
||||||
import club.mcscrims.core.config.ConfigLoader
|
|
||||||
import club.mcscrims.core.database.DatabaseConfig
|
|
||||||
import club.mcscrims.core.database.mongodb.MongoManager
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityHitListener
|
|
||||||
import club.mcscrims.speedhg.ability.CooldownManager
|
|
||||||
import club.mcscrims.speedhg.ability.HitCounterManager
|
|
||||||
import club.mcscrims.speedhg.config.KitConfig
|
|
||||||
import club.mcscrims.speedhg.config.MessageConfig
|
|
||||||
import club.mcscrims.speedhg.config.PluginConfig
|
|
||||||
import club.mcscrims.speedhg.database.StatsRepository
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
import club.mcscrims.speedhg.game.GameManager
|
||||||
import club.mcscrims.speedhg.command.KitsCommand
|
import club.mcscrims.speedhg.game.modules.AntiRunningManager
|
||||||
import club.mcscrims.speedhg.database.PlayerRepository
|
import club.mcscrims.speedhg.listener.ConnectListener
|
||||||
import club.mcscrims.speedhg.kit.KitInventoryListener
|
import club.mcscrims.speedhg.scoreboard.ScoreboardManager
|
||||||
import club.mcscrims.speedhg.kit.KitInventoryManager
|
|
||||||
import club.mcscrims.speedhg.kit.KitListener
|
|
||||||
import club.mcscrims.speedhg.kit.KitManager
|
|
||||||
import club.mcscrims.speedhg.listener.GameStateListener
|
|
||||||
import club.mcscrims.speedhg.listener.LunarClientListener
|
|
||||||
import club.mcscrims.speedhg.recraft.RecraftInspector
|
|
||||||
import club.mcscrims.speedhg.recraft.RecraftUtils
|
|
||||||
import club.mcscrims.speedhg.world.WorldManager
|
|
||||||
import club.mcscrims.spigot.chat.ChatFormatter
|
|
||||||
import club.mcscrims.spigot.chat.ChatManager
|
|
||||||
import club.mcscrims.spigot.network.SpigotNetworkManager
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import club.mcscrims.spigot.util.WorldEditUtils
|
|
||||||
import com.mongodb.client.model.Indexes
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
|
||||||
import net.luckperms.api.LuckPerms
|
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
class SpeedHG : JavaPlugin() {
|
class SpeedHG : JavaPlugin() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal lateinit var instance: SpeedHG
|
lateinit var instance: SpeedHG
|
||||||
|
private set
|
||||||
fun Component.content(): String
|
|
||||||
{
|
|
||||||
return LegacyComponentSerializer.legacySection().serialize( this )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var configLoader: ConfigLoader
|
lateinit var languageManager: LanguageManager
|
||||||
internal lateinit var pluginConfig: ConfigData<PluginConfig>
|
private set
|
||||||
internal lateinit var messageConfig: ConfigData<MessageConfig>
|
|
||||||
internal lateinit var kitConfig: ConfigData<KitConfig>
|
|
||||||
internal lateinit var databaseConfig: ConfigData<DatabaseConfig>
|
|
||||||
|
|
||||||
internal lateinit var chatManager: ChatManager<MessageConfig>
|
lateinit var gameManager: GameManager
|
||||||
internal lateinit var chatFormatter: ChatFormatter<MessageConfig>
|
private set
|
||||||
|
|
||||||
private lateinit var mongoManager: MongoManager
|
lateinit var antiRunningManager: AntiRunningManager
|
||||||
internal lateinit var statsRepository: StatsRepository
|
private set
|
||||||
internal lateinit var playerRepository: PlayerRepository
|
|
||||||
|
|
||||||
internal lateinit var networkManager: SpigotNetworkManager
|
lateinit var scoreboardManager: ScoreboardManager
|
||||||
internal lateinit var schedulerManager: SchedulerManager
|
private set
|
||||||
|
|
||||||
internal lateinit var gameManager: GameManager
|
|
||||||
internal lateinit var worldManager: WorldManager
|
|
||||||
|
|
||||||
internal lateinit var abilityContext: AbilityContext
|
|
||||||
internal lateinit var kitManager: KitManager
|
|
||||||
internal lateinit var kitInventoryManager: KitInventoryManager
|
|
||||||
|
|
||||||
internal lateinit var worldEditUtils: WorldEditUtils
|
|
||||||
|
|
||||||
internal lateinit var luckPerms: LuckPerms
|
|
||||||
internal var isReady: Boolean = false
|
|
||||||
|
|
||||||
override fun onLoad()
|
|
||||||
{
|
|
||||||
instance = this
|
|
||||||
|
|
||||||
worldManager = WorldManager( this )
|
|
||||||
worldManager.deleteWorld()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEnable()
|
override fun onEnable()
|
||||||
{
|
{
|
||||||
loadConfigurations()
|
instance = this
|
||||||
setupDatabase()
|
|
||||||
networkManager = SpigotNetworkManager.getInstance()!!
|
|
||||||
|
|
||||||
worldManager.setupWorld()
|
saveDefaultConfig()
|
||||||
|
languageManager = LanguageManager( this )
|
||||||
chatFormatter = ChatFormatter.create(
|
|
||||||
plugin = this,
|
|
||||||
configClass = MessageConfig::class,
|
|
||||||
messageExtractor = { config -> config.getAllMessages() },
|
|
||||||
listExtractor = { config -> config.getListMessages() }
|
|
||||||
)
|
|
||||||
|
|
||||||
chatManager = ChatManager.withCustomConfig( this, chatFormatter )
|
|
||||||
chatManager.initialize()
|
|
||||||
|
|
||||||
schedulerManager = SchedulerManager( this )
|
|
||||||
|
|
||||||
worldEditUtils = WorldEditUtils( this )
|
|
||||||
|
|
||||||
gameManager = GameManager( this )
|
gameManager = GameManager( this )
|
||||||
gameManager.initialize()
|
antiRunningManager = AntiRunningManager( this )
|
||||||
|
|
||||||
val cooldownManager = CooldownManager()
|
scoreboardManager = ScoreboardManager( this )
|
||||||
val hitCounterManager = HitCounterManager()
|
|
||||||
abilityContext = AbilityContext( cooldownManager, hitCounterManager )
|
|
||||||
|
|
||||||
kitManager = KitManager( this )
|
|
||||||
kitManager.initialize()
|
|
||||||
|
|
||||||
kitInventoryManager = KitInventoryManager( this, kitManager )
|
|
||||||
|
|
||||||
setupLuckPerms()
|
|
||||||
registerListener()
|
registerListener()
|
||||||
registerCommands()
|
|
||||||
|
|
||||||
RecraftUtils.registerRecipes()
|
logger.info("SpeedHG wurde geladen!")
|
||||||
RecraftInspector( this ).startRunnable()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisable()
|
override fun onDisable()
|
||||||
{
|
{
|
||||||
kitManager.clearAll()
|
super.onDisable()
|
||||||
closeDatabase()
|
|
||||||
networkManager.shutdown()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerListener()
|
private fun registerListener()
|
||||||
{
|
{
|
||||||
server.pluginManager.registerEvents(GameStateListener( this, gameManager ), this )
|
val pm = Bukkit.getPluginManager()
|
||||||
server.pluginManager.registerEvents(KitListener( this, kitManager ), this )
|
|
||||||
server.pluginManager.registerEvents(KitInventoryListener( this, kitManager, kitInventoryManager ), this )
|
pm.registerEvents( ConnectListener(), this )
|
||||||
server.pluginManager.registerEvents(AbilityHitListener( this, abilityContext ), this )
|
|
||||||
LunarClientListener( this )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerCommands()
|
}
|
||||||
{
|
|
||||||
getCommand("kits")?.setExecutor(KitsCommand( this, kitInventoryManager ))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAlivePlayers(): List<Player>
|
|
||||||
{
|
|
||||||
val alivePlayers = mutableListOf<Player>()
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
val players = playerRepository.findAlivePlayers( server.name )
|
|
||||||
alivePlayers.addAll(players.map { Bukkit.getPlayer( it.uuid )!! })
|
|
||||||
}
|
|
||||||
|
|
||||||
return alivePlayers
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* LUCKPERMS >>
|
|
||||||
*/
|
|
||||||
|
|
||||||
private fun setupLuckPerms()
|
|
||||||
{
|
|
||||||
val provider = server.servicesManager.getRegistration( LuckPerms::class.java )
|
|
||||||
|
|
||||||
if ( provider != null )
|
|
||||||
luckPerms = provider.provider
|
|
||||||
|
|
||||||
if ( !::luckPerms.isInitialized )
|
|
||||||
logger.warning( "LuckPerms could not be loaded." )
|
|
||||||
else
|
|
||||||
logger.info( "LuckPerms has successfully been loaded." )
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DATABASE >>
|
|
||||||
*/
|
|
||||||
|
|
||||||
private fun setupDatabase()
|
|
||||||
{
|
|
||||||
// MongoManager initialisieren
|
|
||||||
mongoManager = MongoManager.getInstance( name, logger )
|
|
||||||
val connection = mongoManager.createConnection( "speedhg", databaseConfig.data )
|
|
||||||
|
|
||||||
// Repositories initialisieren
|
|
||||||
statsRepository = StatsRepository( connection )
|
|
||||||
playerRepository = PlayerRepository( connection )
|
|
||||||
|
|
||||||
// Indizes erstellen
|
|
||||||
runBlocking {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
connection.createIndex( "player_stats", Indexes.ascending( "kills" ))
|
|
||||||
connection.createIndex( "player_stats", Indexes.descending( "deaths" ))
|
|
||||||
connection.createIndex( "player_stats", Indexes.ascending( "wins" ))
|
|
||||||
connection.createIndex( "player_stats", Indexes.ascending( "unathleticIndex" ))
|
|
||||||
connection.createIndex( "player_stats", Indexes.ascending( "ironFarmed" ))
|
|
||||||
connection.createIndex( "kit_players", Indexes.text( "server" ))
|
|
||||||
}
|
|
||||||
catch ( ex: Exception ) {
|
|
||||||
logger.warning( "Failed to create MongoDB indexes: ${ex.message}" )
|
|
||||||
return@runBlocking
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info( "Successfully enabled MongoDB" )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun closeDatabase()
|
|
||||||
{
|
|
||||||
// Alle Server von Kit-Spielern auf NULL setzen
|
|
||||||
runBlocking {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
val players = Bukkit.getOnlinePlayers()
|
|
||||||
players.forEach { player ->
|
|
||||||
playerRepository.updateServer( player.uniqueId, "NULL" )
|
|
||||||
}
|
|
||||||
logger.info( "Updated ${players.size} players server to NULL." )
|
|
||||||
}
|
|
||||||
catch ( ex: Exception ) {
|
|
||||||
logger.warning( "Failed to update player server: ${ex.message}" )
|
|
||||||
}
|
|
||||||
}.also {
|
|
||||||
// MongoManager beenden
|
|
||||||
mongoManager.shutdown()
|
|
||||||
|
|
||||||
logger.info( "Successfully disabled MongoDB" )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CONFIG >>
|
|
||||||
*/
|
|
||||||
|
|
||||||
private fun loadConfigurations()
|
|
||||||
{
|
|
||||||
configLoader = ConfigLoader.getInstance( name, logger, dataFolder )
|
|
||||||
createConfigurations()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createConfigurations()
|
|
||||||
{
|
|
||||||
pluginConfig = configLoader.loadConfig<PluginConfig>(
|
|
||||||
fileName = "config.yml",
|
|
||||||
format = ConfigFormat.YAML,
|
|
||||||
autoReload = true
|
|
||||||
)
|
|
||||||
|
|
||||||
messageConfig = configLoader.loadConfig<MessageConfig>(
|
|
||||||
fileName = "messages.yml",
|
|
||||||
format = ConfigFormat.YAML,
|
|
||||||
autoReload = false
|
|
||||||
)
|
|
||||||
|
|
||||||
kitConfig = configLoader.loadConfig<KitConfig>(
|
|
||||||
fileName = "kits.yml",
|
|
||||||
format = ConfigFormat.YAML,
|
|
||||||
autoReload = false
|
|
||||||
)
|
|
||||||
|
|
||||||
databaseConfig = configLoader.loadConfig<DatabaseConfig>(
|
|
||||||
fileName = "database.json",
|
|
||||||
format = ConfigFormat.JSON,
|
|
||||||
autoReload = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun reloadConfigurations()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pluginConfig.reload()
|
|
||||||
messageConfig.reload()
|
|
||||||
kitConfig.reload()
|
|
||||||
databaseConfig.reload()
|
|
||||||
}
|
|
||||||
catch ( ex: Exception ) {
|
|
||||||
logger.severe( "Failed to reload configurations: ${ex.message}" )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.ability
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
|
|
||||||
class AbilityContext(
|
|
||||||
val cooldownManager: CooldownManager,
|
|
||||||
val hitCounterManager: HitCounterManager
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun canUseAbility(
|
|
||||||
player: Player,
|
|
||||||
key: String,
|
|
||||||
requiredHits: Int? = null,
|
|
||||||
cooldownSeconds: Int? = null
|
|
||||||
): AbilityResult
|
|
||||||
{
|
|
||||||
if ( cooldownSeconds != null && cooldownManager.isOnCooldown( player, key ))
|
|
||||||
{
|
|
||||||
val remaining = cooldownManager.getRemainingSeconds( player, key )
|
|
||||||
return AbilityResult.onCooldown( remaining )
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( requiredHits != null && !hitCounterManager.hasReachedThreshold( player, key, requiredHits ))
|
|
||||||
{
|
|
||||||
val missing = hitCounterManager.getRemainingHits( player, key, requiredHits )
|
|
||||||
return AbilityResult.insufficientHits( missing )
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( requiredHits != null )
|
|
||||||
hitCounterManager.resetHits( player, key )
|
|
||||||
|
|
||||||
if ( cooldownSeconds != null )
|
|
||||||
cooldownManager.startCooldown( player, key, cooldownSeconds )
|
|
||||||
|
|
||||||
return AbilityResult.success()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun incrementHit(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Int
|
|
||||||
{
|
|
||||||
return hitCounterManager.incrementHit( player, key )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getHits(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Int
|
|
||||||
{
|
|
||||||
return hitCounterManager.getHits( player, key )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRemainingCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Double
|
|
||||||
{
|
|
||||||
return cooldownManager.getRemainingSeconds( player, key )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearPlayerData(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
cooldownManager.clearAllCooldowns( player )
|
|
||||||
hitCounterManager.clearAllHits( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAll()
|
|
||||||
{
|
|
||||||
cooldownManager.clearAll()
|
|
||||||
hitCounterManager.clearAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.ability
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
|
|
||||||
class AbilityHitListener(
|
|
||||||
private val plugin: SpeedHG,
|
|
||||||
private val abilityContext: AbilityContext
|
|
||||||
) : Listener {
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onEntityDamage(
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
val damager = event.damager
|
|
||||||
val victim = event.entity
|
|
||||||
|
|
||||||
if ( damager !is Player || victim !is Player )
|
|
||||||
return
|
|
||||||
|
|
||||||
val hitCount = abilityContext.incrementHit( damager, "melee_hit" )
|
|
||||||
|
|
||||||
val result = abilityContext.canUseAbility(
|
|
||||||
player = damager,
|
|
||||||
key = "example_ability",
|
|
||||||
requiredHits = 3,
|
|
||||||
cooldownSeconds = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
if ( result.success )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( damager, "ability.activated", "{player}" to victim.name )
|
|
||||||
}
|
|
||||||
else if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( damager, "ability.more_hits", "{current}" to hitCount.toString(), "{needed}" to result.missingHits.toString() )
|
|
||||||
}
|
|
||||||
else if ( result.remainingCooldown > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( damager, "ability.cooldown", "{cooldown}" to result.remainingCooldown.toString() )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.ability
|
|
||||||
|
|
||||||
data class AbilityResult(
|
|
||||||
val success: Boolean,
|
|
||||||
val reason: String?,
|
|
||||||
val remainingCooldown: Double = 0.0,
|
|
||||||
val missingHits: Int = 0
|
|
||||||
) {
|
|
||||||
companion object
|
|
||||||
{
|
|
||||||
|
|
||||||
fun success(): AbilityResult = AbilityResult( true, null )
|
|
||||||
|
|
||||||
fun onCooldown( remaining: Double ): AbilityResult =
|
|
||||||
AbilityResult( false, "Ability is on cooldown", remainingCooldown = remaining )
|
|
||||||
|
|
||||||
fun insufficientHits( missing: Int ): AbilityResult =
|
|
||||||
AbilityResult( false, "Not enough hits", missingHits = missing )
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.ability
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import java.util.UUID
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
class CooldownManager {
|
|
||||||
|
|
||||||
private val cooldowns = ConcurrentHashMap<UUID, ConcurrentHashMap<String, Long>>()
|
|
||||||
|
|
||||||
fun startCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String,
|
|
||||||
seconds: Int
|
|
||||||
) {
|
|
||||||
val expiryTime = System.currentTimeMillis() + ( seconds * 1000L )
|
|
||||||
cooldowns.computeIfAbsent( player.uniqueId ) { ConcurrentHashMap() }[ key ] = expiryTime
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isOnCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
val playerCooldowns = cooldowns[player.uniqueId] ?: return false
|
|
||||||
val expiryTime = playerCooldowns[key] ?: return false
|
|
||||||
|
|
||||||
if ( System.currentTimeMillis() >= expiryTime )
|
|
||||||
{
|
|
||||||
playerCooldowns.remove( key )
|
|
||||||
if ( playerCooldowns.isEmpty() ) cooldowns.remove( player.uniqueId )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRemainingSeconds(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Double
|
|
||||||
{
|
|
||||||
val playerCooldowns = cooldowns[player.uniqueId] ?: return 0.0
|
|
||||||
val expiryTime = playerCooldowns[key] ?: return 0.0
|
|
||||||
|
|
||||||
val remaining = ( expiryTime - System.currentTimeMillis() ) / 1000.0
|
|
||||||
return if ( remaining > 0 ) remaining else 0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
) {
|
|
||||||
cooldowns[player.uniqueId]?.remove( key )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAllCooldowns(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
cooldowns.remove( player.uniqueId )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAll()
|
|
||||||
{
|
|
||||||
cooldowns.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.ability
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import java.util.UUID
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
class HitCounterManager {
|
|
||||||
|
|
||||||
private val hitCounts = ConcurrentHashMap<UUID, ConcurrentHashMap<String, Int>>()
|
|
||||||
|
|
||||||
fun incrementHit(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Int
|
|
||||||
{
|
|
||||||
val playerHits = hitCounts.computeIfAbsent( player.uniqueId ) { ConcurrentHashMap() }
|
|
||||||
val newCount = playerHits.compute( key ) { _, current -> ( current ?: 0 ) + 1 } ?: 1
|
|
||||||
return newCount
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getHits(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Int
|
|
||||||
{
|
|
||||||
return hitCounts[player.uniqueId]?.get( key ) ?: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resetHits(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
) {
|
|
||||||
hitCounts[player.uniqueId]?.remove( key )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasReachedThreshold(
|
|
||||||
player: Player,
|
|
||||||
key: String,
|
|
||||||
requiredHits: Int
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
return getHits( player, key ) >= requiredHits
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRemainingHits(
|
|
||||||
player: Player,
|
|
||||||
key: String,
|
|
||||||
requiredHits: Int
|
|
||||||
): Int
|
|
||||||
{
|
|
||||||
val current = getHits( player, key )
|
|
||||||
return maxOf( 0, requiredHits - current )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAllHits(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
hitCounts.remove( player.uniqueId )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAll()
|
|
||||||
{
|
|
||||||
hitCounts.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.command
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.kit.KitInventoryManager
|
|
||||||
import org.bukkit.command.Command
|
|
||||||
import org.bukkit.command.CommandExecutor
|
|
||||||
import org.bukkit.command.CommandSender
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
|
|
||||||
class KitsCommand(
|
|
||||||
private val plugin: SpeedHG,
|
|
||||||
private val kitInventoryManager: KitInventoryManager
|
|
||||||
) : CommandExecutor {
|
|
||||||
|
|
||||||
override fun onCommand(
|
|
||||||
sender: CommandSender,
|
|
||||||
command: Command,
|
|
||||||
label: String,
|
|
||||||
args: Array<out String>
|
|
||||||
): Boolean {
|
|
||||||
if ( sender !is Player )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendSenderMessage( sender, "default.only_players" )
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
kitInventoryManager.openKitInventory( sender, 1 )
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.config
|
|
||||||
|
|
||||||
import club.mcscrims.core.config.annotations.ConfigClass
|
|
||||||
import club.mcscrims.core.config.annotations.ConfigField
|
|
||||||
|
|
||||||
@ConfigClass(
|
|
||||||
name = "kits",
|
|
||||||
description = "Kit configuration",
|
|
||||||
version = "1.0"
|
|
||||||
)
|
|
||||||
data class KitConfig(
|
|
||||||
|
|
||||||
@ConfigField(name = "anchor", description = "Anchor configurations")
|
|
||||||
val anchor: Map<String, Double> = getAnchorConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "armorer", description = "Armorer configurations")
|
|
||||||
val armorer: Map<String, Double> = getArmorerConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "blackpanther", description = "BlackPanther configurations")
|
|
||||||
val blackPanther: Map<String, Double> = getBlackPantherConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "blitzcrank", description = "Blitzcrank configurations")
|
|
||||||
val blitzcrank: Map<String, Double> = getBlitzcrankConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "gladiator", description = "Gladiator configurations")
|
|
||||||
val gladiator: Map<String, Double> = getGladiatorConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "goblin", description = "Goblin configurations")
|
|
||||||
val goblin: Map<String, Double> = getGoblinConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "icemage", description = "IceMage configurations")
|
|
||||||
val iceMage: Map<String, Double> = getIceMageConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "poseidon", description = "Poseidon configurations")
|
|
||||||
val poseidon: Map<String, Double> = getPoseidonConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "rattlesnake", description = "Rattlesnake configurations")
|
|
||||||
val rattlesnake: Map<String, Double> = getRattlesnakeConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "tesla", description = "Tesla configurations")
|
|
||||||
val tesla: Map<String, Double> = getTeslaConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "voodoo", description = "Voodoo configurations")
|
|
||||||
val voodoo: Map<String, Double> = getVoodooConfigurations(),
|
|
||||||
|
|
||||||
@ConfigField(name = "perks", description = "Perk configuration")
|
|
||||||
val perks: Map<String, Pair<String, Double>> = getPerkConfiguration()
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun getAllKitConfigurations(): Map<String, Double>
|
|
||||||
{
|
|
||||||
return anchor + armorer + blackPanther + gladiator + goblin + iceMage + poseidon +
|
|
||||||
rattlesnake + tesla + voodoo
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getConfigForKit(id: String): Map<String, Double>
|
|
||||||
{
|
|
||||||
return when (id.lowercase()) {
|
|
||||||
"anchor" -> anchor
|
|
||||||
"armorer" -> armorer
|
|
||||||
"blackpanther" -> blackPanther
|
|
||||||
"gladiator" -> gladiator
|
|
||||||
"goblin" -> goblin
|
|
||||||
"icemage" -> iceMage
|
|
||||||
"poseidon" -> poseidon
|
|
||||||
"rattlesnake" -> rattlesnake
|
|
||||||
"tesla" -> tesla
|
|
||||||
"voodoo" -> voodoo
|
|
||||||
else -> emptyMap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAnchorConfigurations() = mapOf(
|
|
||||||
"offensive extra damage" to 1.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getArmorerConfigurations() = mapOf(
|
|
||||||
"kills until new armor" to 2.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getBlackPantherConfigurations() = mapOf(
|
|
||||||
"enderpearl hit damage" to 3.0,
|
|
||||||
"extra damage on top" to 0.5,
|
|
||||||
"default hit radius" to 3.0,
|
|
||||||
"explosion multiplier" to 3.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getBlitzcrankConfigurations() = mapOf(
|
|
||||||
"ultimate damage" to 10.0,
|
|
||||||
"ultimate radius" to 5.0,
|
|
||||||
"ultimate stun duration" to 0.5,
|
|
||||||
"hook range" to 8.0,
|
|
||||||
"stun height" to 4.0,
|
|
||||||
"stun radius" to 3.0,
|
|
||||||
"stun slow duration" to 5.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getGladiatorConfigurations() = mapOf(
|
|
||||||
"cage radius" to 23.0,
|
|
||||||
"cage height" to 10.0,
|
|
||||||
"wither effect after x seconds" to 180.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getGoblinConfigurations() = mapOf(
|
|
||||||
"bunker radius" to 10.0,
|
|
||||||
"bunker time until disappear" to 15.0,
|
|
||||||
"knockback and pullin radius" to 7.0,
|
|
||||||
"kit steal time" to 60.0,
|
|
||||||
"soup steal chance" to 20.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getIceMageConfigurations() = mapOf(
|
|
||||||
"chance for slowness" to 2.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getPoseidonConfigurations() = mapOf(
|
|
||||||
"default hit radius" to 3.0,
|
|
||||||
"lightning hit damage" to 4.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getRattlesnakeConfigurations() = mapOf(
|
|
||||||
"maximum jump distance" to 10.0,
|
|
||||||
"speed duration" to 10.0,
|
|
||||||
"poison duration" to 8.0,
|
|
||||||
"maximum negative effect duration" to 16.0,
|
|
||||||
"default jump radius" to 10.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getTeslaConfigurations() = mapOf(
|
|
||||||
"disable push at height" to 50.0,
|
|
||||||
"default thunder radius" to 5.0,
|
|
||||||
"push strength" to 1.0,
|
|
||||||
"fire tick duration" to 5.0,
|
|
||||||
"time until thunder disables" to 7.0,
|
|
||||||
"thunder damage" to 1.5
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getVoodooConfigurations() = mapOf(
|
|
||||||
"default curse radius" to 3.0,
|
|
||||||
"maximum effect duration" to 15.0,
|
|
||||||
"clicked players minimum health" to 10.0,
|
|
||||||
"voodoo hold duration" to 5.0,
|
|
||||||
"chance for wither effect" to 5.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getPerkConfiguration() = mapOf(
|
|
||||||
"knockback" to Pair( "knockback strength", 1.5 ),
|
|
||||||
"pullin" to Pair( "pullin strength", 0.5 ),
|
|
||||||
"radiusincrease" to Pair( "new radius", 5.0 )
|
|
||||||
)
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package club.mcscrims.speedhg.config
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage
|
||||||
|
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class LanguageManager(
|
||||||
|
private val plugin: JavaPlugin
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Map: Sprachcode -> (Key -> Nachricht)
|
||||||
|
private val languages = ConcurrentHashMap<String, Map<String, String>>()
|
||||||
|
private val miniMessage = MiniMessage.miniMessage()
|
||||||
|
private val defaultLanguage = plugin.config.getString("default.language", "en_US")!!
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadLanguages()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadLanguages()
|
||||||
|
{
|
||||||
|
languages.clear()
|
||||||
|
val folder = File( plugin.dataFolder, "languages" )
|
||||||
|
|
||||||
|
if ( !folder.exists() ) {
|
||||||
|
folder.mkdirs()
|
||||||
|
createDefault("de_DE")
|
||||||
|
createDefault("en_US")
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.walk().filter { it.extension == "yml" }.forEach { file ->
|
||||||
|
val langCode = file.nameWithoutExtension
|
||||||
|
val config = YamlConfiguration.loadConfiguration( file )
|
||||||
|
|
||||||
|
val messages = config.getKeys( true )
|
||||||
|
.filter { config.isString( it ) }
|
||||||
|
.associateWith { config.getString( it ) }
|
||||||
|
|
||||||
|
languages[ langCode ] = messages as Map<String, String>
|
||||||
|
plugin.logger.info("Sprache geladen: $langCode (${messages.size} Nachrichten)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDefault(
|
||||||
|
locale: String
|
||||||
|
) {
|
||||||
|
val fileName = "languages/$locale.yml"
|
||||||
|
if (plugin.getResource( fileName ) != null) {
|
||||||
|
plugin.saveResource( fileName, false )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRawMessage(
|
||||||
|
player: Player,
|
||||||
|
key: String
|
||||||
|
): String
|
||||||
|
{
|
||||||
|
val locale = player.locale().toString()
|
||||||
|
val langMap = languages[ locale ] ?: languages[ defaultLanguage ]
|
||||||
|
return langMap?.get( key ) ?: "<red>Missing Key: $key</red>"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRawMessageList(
|
||||||
|
player: Player,
|
||||||
|
key: String
|
||||||
|
): List<String>
|
||||||
|
{
|
||||||
|
var locale = player.locale().toString()
|
||||||
|
val langMap = languages[ locale ]
|
||||||
|
|
||||||
|
if ( langMap == null ) {
|
||||||
|
locale = defaultLanguage
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = File( plugin.dataFolder, "languages/$locale.yml" )
|
||||||
|
val config = YamlConfiguration.loadConfiguration( file )
|
||||||
|
return if (config.contains( key )) config.getStringList( key ) else listOf("<red>Missing List: $key</red>")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getComponent(
|
||||||
|
player: Player,
|
||||||
|
key: String,
|
||||||
|
placeholders: Map<String, String>
|
||||||
|
): Component
|
||||||
|
{
|
||||||
|
val raw = getRawMessage( player, key )
|
||||||
|
val tags = placeholders.map { (k, v) -> Placeholder.parsed( k, v ) }
|
||||||
|
return miniMessage.deserialize( raw, *tags.toTypedArray() )
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.config
|
|
||||||
|
|
||||||
import club.mcscrims.core.config.annotations.ConfigClass
|
|
||||||
import club.mcscrims.core.config.annotations.ConfigField
|
|
||||||
|
|
||||||
@ConfigClass(
|
|
||||||
name = "messages",
|
|
||||||
description = "Messages configuration",
|
|
||||||
version = "1.0"
|
|
||||||
)
|
|
||||||
data class MessageConfig(
|
|
||||||
@ConfigField(name = "default", description = "Default messages")
|
|
||||||
val defaultMessages: Map<String, String> = getDefaultMessages(),
|
|
||||||
|
|
||||||
@ConfigField(name = "commands", description = "Command messages")
|
|
||||||
val commandMessages: Map<String, String> = getCommandMessages(),
|
|
||||||
|
|
||||||
@ConfigField(name = "death", description = "Death messages")
|
|
||||||
val deathMessages: Map<String, List<String>> = getDeathMessages(),
|
|
||||||
|
|
||||||
@ConfigField(name = "kits", description = "Kit messages")
|
|
||||||
val kitMessages: Map<String, KitConfig> = getKitMessages(),
|
|
||||||
|
|
||||||
@ConfigField(name = "kits-default", description = "Default kit messages")
|
|
||||||
val defaultKitMessages: Map<String, String> = getDefaultKitMessages()
|
|
||||||
) {
|
|
||||||
|
|
||||||
data class KitConfig(
|
|
||||||
val name: String = "",
|
|
||||||
val description: List<String>,
|
|
||||||
val items: List<KitItemConfig>,
|
|
||||||
val messages: Map<String, String>
|
|
||||||
)
|
|
||||||
|
|
||||||
data class KitItemConfig(
|
|
||||||
val itemName: String,
|
|
||||||
val playStyleNames: Map<String, String>
|
|
||||||
)
|
|
||||||
|
|
||||||
fun getAllMessages(): Map<String, String>
|
|
||||||
{
|
|
||||||
return defaultMessages + commandMessages + defaultKitMessages + kitMessages.flatMap { it.value.messages.entries }.associate { it.key to it.value }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getListMessages(): Map<String, List<String>>
|
|
||||||
{
|
|
||||||
return deathMessages
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getKitItemNames(
|
|
||||||
kit: String,
|
|
||||||
itemKey: String
|
|
||||||
): Map<String, String>?
|
|
||||||
{
|
|
||||||
return kitMessages[ kit ]?.items?.find { it.itemName == itemKey }?.playStyleNames
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDefaultMessages(): Map<String, String> = mapOf(
|
|
||||||
"default.prefix" to "<gradient:dark_green:green>McScrims</gradient> <dark_gray>┃</dark_gray><reset>",
|
|
||||||
"default.no_permission" to "%prefix% <red>You don't have permission to do that!</red>",
|
|
||||||
"default.player_not_found" to "%prefix% <red>This player could not be found!</red>",
|
|
||||||
"default.command_cooldown" to "%prefix% <red>Please wait {time} seconds before using this command again!</red>",
|
|
||||||
"default.reload" to "%prefix% <green>Successfully reloaded the plugin.</green>",
|
|
||||||
"default.only_players" to "%prefix% <red>Only players can execute this command.</red>"
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getCommandMessages(): Map<String, String> = mapOf(
|
|
||||||
"commands.unknown" to "%prefix% <red>Unknown subcommand: {unknown}</red> \n%prefix% <gray>Use /{command} for an overview.</gray>"
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getDeathMessages(): Map<String, List<String>> = mapOf(
|
|
||||||
"player" to listOf(
|
|
||||||
"<black>☠</black> <red>{player} was killed by {killer}!</red>"
|
|
||||||
),
|
|
||||||
"entity" to listOf(
|
|
||||||
"<black>☠</black> <red>{player} was killed by {entity}!</red>"
|
|
||||||
),
|
|
||||||
"world" to listOf(
|
|
||||||
"<black>☠</black> <red>{player} has died!</red>"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getDefaultKitMessages(): Map<String, String> = mapOf(
|
|
||||||
"kits.missingHits" to ""
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getKitMessages(): Map<String, MessageConfig.KitConfig> = mapOf(
|
|
||||||
"anchor" to MessageConfig.KitConfig(
|
|
||||||
name = "<dark_gray>Anchor</dark_gray>",
|
|
||||||
description = listOf(
|
|
||||||
"Create an anchor where",
|
|
||||||
"you are lookin and gain no",
|
|
||||||
"knockback in your radius."
|
|
||||||
),
|
|
||||||
items = listOf(MessageConfig.KitItemConfig(
|
|
||||||
itemName = "anvil",
|
|
||||||
playStyleNames = mapOf(
|
|
||||||
"offensive" to "<gray>Anchor (right-click)</gray>",
|
|
||||||
"defensive" to "<gray>Anchor (right-click)</gray>"
|
|
||||||
)
|
|
||||||
)),
|
|
||||||
messages = mapOf(
|
|
||||||
"tooFarAway" to "%prefix% <red>You can only place your anchor in a {radius} block radius!</red>",
|
|
||||||
"alreadyActivated" to "%prefix% <red>You have already placed an anchor!</red>",
|
|
||||||
"broken" to "%prefix% "
|
|
||||||
)
|
|
||||||
),
|
|
||||||
"armorer" to MessageConfig.KitConfig(
|
|
||||||
name = "<gray>Armorer</gray>",
|
|
||||||
description = listOf(
|
|
||||||
"Gain a stronger armor the",
|
|
||||||
"more kills you gain. Every 2",
|
|
||||||
"kills your armor gets better.",
|
|
||||||
"All the way up to iron."
|
|
||||||
),
|
|
||||||
items = emptyList(),
|
|
||||||
messages = mapOf(
|
|
||||||
"upgrade.normal" to "%prefix% <green>Your armor has been upgraded to {armorType}.</green>",
|
|
||||||
"upgrade.enchanted" to "%prefix% <purple>Your armor has been enchanted.</purple>"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
"blackpanther" to MessageConfig.KitConfig(
|
|
||||||
name = "<gradient:purple:blue>Black Panther</gradient>",
|
|
||||||
description = listOf(
|
|
||||||
"Use your abilities to either",
|
|
||||||
"do more damage and push enemies",
|
|
||||||
"away or jump on enemies and",
|
|
||||||
"give them instant damage."
|
|
||||||
),
|
|
||||||
items = listOf(
|
|
||||||
MessageConfig.KitItemConfig(
|
|
||||||
itemName = "blackDye",
|
|
||||||
playStyleNames = mapOf(
|
|
||||||
"offensive" to "<dark_gray>Push</dark_gray> <gray>(right-click)</gray>",
|
|
||||||
"defensive" to "<purple>Wakanda Forever!</purple> <gray>(right-click)</gray>"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
MessageConfig.KitItemConfig(
|
|
||||||
itemName = "blazePowder",
|
|
||||||
playStyleNames = mapOf(
|
|
||||||
"offensive" to "<yellow>Extra Damage</yellow> <gray>(right-click)</gray>",
|
|
||||||
"defensive" to "<yellow>Extra Damage</yellow> <gray>(right-click)</gray>"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
messages = mapOf(
|
|
||||||
"wakandaForever.hit" to "%prefix% <purple>You have hit {hit} players with WAKANDA FOREVER!</purple>",
|
|
||||||
"extraDamage.activated" to "%prefix% <green>Your extra damage is now activated.</green>",
|
|
||||||
"extraDamage.deactivated" to "%prefix% <red>Your extra damage is now deactivated.</red>"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
"blitzcrank" to MessageConfig.KitConfig(
|
|
||||||
name = "<gradient:orange:yellow>Blitzcrank</gradient>",
|
|
||||||
description = listOf(
|
|
||||||
"Use your abilities to",
|
|
||||||
"slow down enemies and",
|
|
||||||
"either stun or hook them."
|
|
||||||
),
|
|
||||||
items = listOf(
|
|
||||||
MessageConfig.KitItemConfig(
|
|
||||||
itemName = "hots",
|
|
||||||
playStyleNames = mapOf(
|
|
||||||
"defensive" to "<blue>Slow</blue> <gray>(right-click)</gray>",
|
|
||||||
"offensive" to "<blue>Slow</blue> <gray>(right-click)</gray>"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
MessageConfig.KitItemConfig(
|
|
||||||
itemName = "fishingrod",
|
|
||||||
playStyleNames = mapOf(
|
|
||||||
"defensive" to "<gold>Hook</gold> <gray>(right-click)</gray>",
|
|
||||||
"offensive" to "<gold>Hook</gold> <gray>(right-click)</gray>"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
MessageConfig.KitItemConfig(
|
|
||||||
itemName = "pufferfish",
|
|
||||||
playStyleNames = mapOf(
|
|
||||||
"defensive" to "<yellow>Stun</yellow> <gray>(right-click)</gray>",
|
|
||||||
"offensive" to "<yellow>Stun</yellow> <gray>(right-click)</gray>"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
messages = mapOf(
|
|
||||||
"ultimate.target" to "%prefix% <yellow>You have been slowed by {player}!</yellow>",
|
|
||||||
"ultimate.player" to "%prefix% <blue>You have slowed {nearby} players.</blue>",
|
|
||||||
"no_player_in_sight" to "%prefix% <red>There is no player in your radius and/or sight to hook!</red>",
|
|
||||||
"hook.player" to "%prefix% <gold>You have hooked {player}!</gold>",
|
|
||||||
"hook.target" to "%prefix% <gold>You have been hooked to a Blitzcrank!</gold>",
|
|
||||||
"stun.target" to "%prefix% <light_blue>You have been stunned!</light_blue>",
|
|
||||||
"stun.player" to "%prefix% <light_blue>You have stunned {nearby} nearby players.</light_blue>"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.config
|
|
||||||
|
|
||||||
import club.mcscrims.core.config.DurationEntry
|
|
||||||
import club.mcscrims.core.config.DurationType
|
|
||||||
import club.mcscrims.core.config.annotations.ConfigClass
|
|
||||||
import club.mcscrims.core.config.annotations.ConfigField
|
|
||||||
import club.mcscrims.core.config.annotations.DefaultValue
|
|
||||||
import club.mcscrims.core.network.NetworkConfig
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
|
|
||||||
@ConfigClass(
|
|
||||||
name = "config",
|
|
||||||
description = "Main plugin configuration",
|
|
||||||
version = "1.0"
|
|
||||||
)
|
|
||||||
data class PluginConfig(
|
|
||||||
@ConfigField(name = "debug", description = "Enable debug mode")
|
|
||||||
@DefaultValue("false")
|
|
||||||
val debug: Boolean = false,
|
|
||||||
|
|
||||||
@ConfigField(name = "language", description = "Default player language")
|
|
||||||
@DefaultValue("en_US")
|
|
||||||
val language: String = "en_US",
|
|
||||||
|
|
||||||
@ConfigField(name = "restart_time", description = "Time after server restarts if playerList is empty")
|
|
||||||
@DefaultValue("3")
|
|
||||||
val restartTime: Int = 3,
|
|
||||||
|
|
||||||
@ConfigField(name = "network", description = "Network configuration for server communication")
|
|
||||||
val network: NetworkConfig = NetworkConfig(),
|
|
||||||
|
|
||||||
@ConfigField(name = "cooldown", description = "Default cooldown for kit items")
|
|
||||||
@DefaultValue("30")
|
|
||||||
val cooldown: Int = 30,
|
|
||||||
|
|
||||||
@ConfigField(name = "needed_hits", description = "Default needed hits for kit items")
|
|
||||||
@DefaultValue("15")
|
|
||||||
val neededHits: Int = 15,
|
|
||||||
|
|
||||||
@ConfigField(name = "world", description = "World configuration")
|
|
||||||
val world: WorldConfig = WorldConfig(),
|
|
||||||
|
|
||||||
@ConfigField(name = "announcement", description = "Announcement configuration")
|
|
||||||
val announcement: Map<String, Any> = getAnnouncementConfiguration(),
|
|
||||||
|
|
||||||
@ConfigField(name = "game", description = "Game configuration")
|
|
||||||
val game: GameConfig = GameConfig()
|
|
||||||
) {
|
|
||||||
|
|
||||||
data class WorldConfig(
|
|
||||||
val name: String = "Default",
|
|
||||||
val border: Map<String, Double> = getBorderConfiguration()
|
|
||||||
)
|
|
||||||
|
|
||||||
data class GameConfig(
|
|
||||||
val name: String = "SpeedHG",
|
|
||||||
val variantName: String = "Solo - Single Kit",
|
|
||||||
val minimumPlayers: Int = 2,
|
|
||||||
val competitiveGame: Boolean = false,
|
|
||||||
val competitiveCommands: List<String> = emptyList(),
|
|
||||||
val playerStates: Map<String, StateConfig> = getPlayerStates(),
|
|
||||||
val recraftNerf: Map<String, Any> = getRecraftNerf(),
|
|
||||||
val teams: Map<String, Any> = getTeams(),
|
|
||||||
val blockedKits: List<String> = emptyList(),
|
|
||||||
val blockedPerks: List<String> = emptyList(),
|
|
||||||
val perks: Map<String, Any> = getPerks()
|
|
||||||
)
|
|
||||||
|
|
||||||
fun isDurationIncreasing(
|
|
||||||
entry: DurationEntry
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
return entry.type == DurationType.INCREASING
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDuration(
|
|
||||||
playerState: String
|
|
||||||
): DurationEntry
|
|
||||||
{
|
|
||||||
return (getPlayerStates()[ playerState ]?.duration as DurationEntry )
|
|
||||||
}
|
|
||||||
|
|
||||||
data class StateConfig(
|
|
||||||
val duration: Any,
|
|
||||||
val scoreboard: String
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPlayerStates() = mapOf(
|
|
||||||
"waiting" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.FIXED, -1 ),
|
|
||||||
"Waiting - %time%"
|
|
||||||
),
|
|
||||||
"pre_start" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.FIXED, 300 ),
|
|
||||||
"Waiting - %time%"
|
|
||||||
),
|
|
||||||
"immunity" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.FIXED, 90 ),
|
|
||||||
"Playing - %time%"
|
|
||||||
),
|
|
||||||
"battle" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.INCREASING ),
|
|
||||||
"Playing - %time%"
|
|
||||||
),
|
|
||||||
"feast" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.FIXED, 300 ),
|
|
||||||
"Playing - %time%"
|
|
||||||
),
|
|
||||||
"deathmatch" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.INCREASING ),
|
|
||||||
"Playing - %time%"
|
|
||||||
),
|
|
||||||
"end" to PluginConfig.StateConfig(
|
|
||||||
DurationEntry( DurationType.FIXED, 60 ),
|
|
||||||
"Ending - %time%"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getRecraftNerf() = mapOf(
|
|
||||||
"enabled" to false,
|
|
||||||
"max_amount" to 64,
|
|
||||||
"before_state" to "FEAST"
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getTeams() = mapOf(
|
|
||||||
"enabled" to false,
|
|
||||||
"maximum_players" to 2
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getPerks() = mapOf(
|
|
||||||
"maximum_amount" to 2
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getBorderConfiguration() = mapOf(
|
|
||||||
"size" to 1000.0,
|
|
||||||
"warning_distance" to 5.0,
|
|
||||||
"damage" to 5.0,
|
|
||||||
"decrease" to 100.0
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getAnnouncementConfiguration() = mapOf(
|
|
||||||
"enabled" to true,
|
|
||||||
"after" to 10,
|
|
||||||
"minimumPlayers" to 6
|
|
||||||
)
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.database
|
|
||||||
|
|
||||||
import club.mcscrims.core.database.mongodb.MongoConnection
|
|
||||||
import club.mcscrims.core.database.mongodb.MongoRepository
|
|
||||||
import com.mongodb.client.model.Filters
|
|
||||||
import com.mongodb.client.model.Updates
|
|
||||||
import org.bson.codecs.pojo.annotations.BsonId
|
|
||||||
import org.bson.codecs.pojo.annotations.BsonProperty
|
|
||||||
import org.bson.conversions.Bson
|
|
||||||
import org.bson.types.ObjectId
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB-Entity für einen Spieler
|
|
||||||
*/
|
|
||||||
data class KitPlayer(
|
|
||||||
@BsonId
|
|
||||||
val id: ObjectId = ObjectId(),
|
|
||||||
|
|
||||||
@BsonProperty
|
|
||||||
val uuid: String,
|
|
||||||
|
|
||||||
@BsonProperty
|
|
||||||
val isAlive: Boolean,
|
|
||||||
|
|
||||||
@BsonProperty
|
|
||||||
val unlockedKits: List<String>,
|
|
||||||
|
|
||||||
@BsonProperty
|
|
||||||
val server: String
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB-Repository für Spieler-Daten
|
|
||||||
*/
|
|
||||||
class PlayerRepository(
|
|
||||||
connection: MongoConnection
|
|
||||||
): MongoRepository<KitPlayer>( connection, "kit_players", KitPlayer::class.java ) {
|
|
||||||
|
|
||||||
override fun getId(
|
|
||||||
entity: KitPlayer
|
|
||||||
): ObjectId
|
|
||||||
{
|
|
||||||
return entity.id
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setId(
|
|
||||||
entity: KitPlayer,
|
|
||||||
id: ObjectId
|
|
||||||
): KitPlayer
|
|
||||||
{
|
|
||||||
return entity.copy( id = id )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun entityToUpdateDocument(
|
|
||||||
entity: KitPlayer
|
|
||||||
): Bson = Updates.combine(
|
|
||||||
Updates.set("isAlive", entity.isAlive),
|
|
||||||
Updates.set("unlockedKits", entity.unlockedKits),
|
|
||||||
Updates.set("server", entity.server)
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Findet einen Spieler anhand seiner UUID
|
|
||||||
*/
|
|
||||||
suspend fun findByUuid(
|
|
||||||
uuid: UUID
|
|
||||||
): KitPlayer?
|
|
||||||
{
|
|
||||||
val filter = Filters.eq("uuid", uuid.toString())
|
|
||||||
return findFirst(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Findet alle lebenden Spieler für einen Server
|
|
||||||
*/
|
|
||||||
suspend fun findAlivePlayers(
|
|
||||||
server: String
|
|
||||||
): List<KitPlayer>
|
|
||||||
{
|
|
||||||
val filter = Filters.and(
|
|
||||||
Filters.eq("server", server),
|
|
||||||
Filters.eq("isAlive", true)
|
|
||||||
)
|
|
||||||
return find(filter, Bukkit.getMaxPlayers())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktualisiert den Alive-Status eines Spielers
|
|
||||||
*/
|
|
||||||
suspend fun updateAliveStatus(
|
|
||||||
uuid: UUID,
|
|
||||||
isAlive: Boolean
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq("uuid", uuid.toString())
|
|
||||||
val update = Updates.set("isAlive", isAlive)
|
|
||||||
connection.updateOne(collectionName, filter, update)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktualisiert den Server eines Spielers
|
|
||||||
*/
|
|
||||||
suspend fun updateServer(
|
|
||||||
uuid: UUID,
|
|
||||||
server: String
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq("uuid", uuid.toString())
|
|
||||||
val update = Updates.set("server", server)
|
|
||||||
connection.updateOne(collectionName, filter, update)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktualisiert die freigeschalteten Kits eines Spielers
|
|
||||||
*/
|
|
||||||
suspend fun updateUnlockedKits(
|
|
||||||
uuid: UUID,
|
|
||||||
unlockedKits: List<String>
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq("uuid", uuid.toString())
|
|
||||||
val update = Updates.set("unlockedKits", unlockedKits)
|
|
||||||
connection.updateOne(collectionName, filter, update)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.database
|
|
||||||
|
|
||||||
import club.mcscrims.core.database.mongodb.MongoConnection
|
|
||||||
import club.mcscrims.core.database.mongodb.MongoRepository
|
|
||||||
import com.mongodb.client.model.Aggregates
|
|
||||||
import com.mongodb.client.model.Filters
|
|
||||||
import com.mongodb.client.model.Sorts
|
|
||||||
import com.mongodb.client.model.Updates
|
|
||||||
import kotlinx.coroutines.flow.toList
|
|
||||||
import org.bson.codecs.pojo.annotations.BsonId
|
|
||||||
import org.bson.codecs.pojo.annotations.BsonProperty
|
|
||||||
import org.bson.conversions.Bson
|
|
||||||
import org.bson.types.ObjectId
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB-Entity für die Stats von einem Spieler
|
|
||||||
*/
|
|
||||||
data class PlayerStats(
|
|
||||||
@BsonId
|
|
||||||
val id: ObjectId? = null,
|
|
||||||
|
|
||||||
@BsonProperty("uuid")
|
|
||||||
val uuid: String,
|
|
||||||
|
|
||||||
@BsonProperty("kills")
|
|
||||||
val kills: Int,
|
|
||||||
|
|
||||||
@BsonProperty("deaths")
|
|
||||||
val deaths: Int,
|
|
||||||
|
|
||||||
@BsonProperty("wins")
|
|
||||||
val wins: Int,
|
|
||||||
|
|
||||||
@BsonProperty("gamesPlayed")
|
|
||||||
val gamesPlayed: Int,
|
|
||||||
|
|
||||||
@BsonProperty("unathleticIndex")
|
|
||||||
val unathleticIndex: Double,
|
|
||||||
|
|
||||||
@BsonProperty("ironFarmed")
|
|
||||||
val ironFarmed: Double
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB-Repository für Stats-Daten
|
|
||||||
*/
|
|
||||||
class StatsRepository(
|
|
||||||
connection: MongoConnection
|
|
||||||
): MongoRepository<PlayerStats>( connection, "player_stats", PlayerStats::class.java ) {
|
|
||||||
|
|
||||||
override fun getId(
|
|
||||||
entity: PlayerStats
|
|
||||||
): ObjectId?
|
|
||||||
{
|
|
||||||
return entity.id
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setId(
|
|
||||||
entity: PlayerStats,
|
|
||||||
id: ObjectId
|
|
||||||
): PlayerStats
|
|
||||||
{
|
|
||||||
return entity.copy( id = id )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun entityToUpdateDocument(
|
|
||||||
entity: PlayerStats
|
|
||||||
): Bson = Updates.combine(
|
|
||||||
Updates.set( "kills", entity.kills ),
|
|
||||||
Updates.set( "deaths", entity.deaths ),
|
|
||||||
Updates.set( "wins", entity.wins ),
|
|
||||||
Updates.set( "gamesPlayed", entity.gamesPlayed ),
|
|
||||||
Updates.set( "unathleticIndex", entity.unathleticIndex ),
|
|
||||||
Updates.set( "ironFarmed", entity.ironFarmed )
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Findet einen Spieler anhand seiner UUID
|
|
||||||
*/
|
|
||||||
suspend fun findByUuid(
|
|
||||||
uuid: UUID
|
|
||||||
): PlayerStats?
|
|
||||||
{
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
return findFirst( filter )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Findet Top-Spieler nach Kills
|
|
||||||
*/
|
|
||||||
suspend fun findTopPlayersByKills(
|
|
||||||
limit: Int = 10
|
|
||||||
): List<PlayerStats>
|
|
||||||
{
|
|
||||||
return connection.getCollection( collectionName ).aggregate(listOf(
|
|
||||||
Aggregates.sort(Sorts.descending( "kills" )),
|
|
||||||
Aggregates.limit( limit )
|
|
||||||
), PlayerStats::class.java ).toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Findet Top-Spieler nach Deaths
|
|
||||||
*/
|
|
||||||
suspend fun findTopPlayersByDeaths(
|
|
||||||
limit: Int = 10
|
|
||||||
): List<PlayerStats>
|
|
||||||
{
|
|
||||||
return connection.getCollection( collectionName ).aggregate(listOf(
|
|
||||||
Aggregates.sort(Sorts.ascending( "deaths" )),
|
|
||||||
Aggregates.limit( limit )
|
|
||||||
), PlayerStats::class.java ).toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Findet Top-Spieler nach Wins
|
|
||||||
*/
|
|
||||||
suspend fun findTopPlayersByWins(
|
|
||||||
limit: Int = 10
|
|
||||||
): List<PlayerStats>
|
|
||||||
{
|
|
||||||
return connection.getCollection( collectionName ).aggregate(listOf(
|
|
||||||
Aggregates.sort(Sorts.descending( "wins" )),
|
|
||||||
Aggregates.limit( limit )
|
|
||||||
), PlayerStats::class.java ).toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt Kills zu einem Spieler hinzu
|
|
||||||
*/
|
|
||||||
suspend fun addKills(
|
|
||||||
uuid: UUID,
|
|
||||||
kills: Int
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
val update = Updates.inc( "kills", kills )
|
|
||||||
connection.updateOne( collectionName, filter, update )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt Deaths zu einem Spieler hinzu
|
|
||||||
*/
|
|
||||||
suspend fun addDeaths(
|
|
||||||
uuid: UUID,
|
|
||||||
deaths: Int
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
val update = Updates.inc( "deaths", deaths )
|
|
||||||
connection.updateOne( collectionName, filter, update )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt Wins zu einem Spieler hinzu
|
|
||||||
*/
|
|
||||||
suspend fun addWins(
|
|
||||||
uuid: UUID,
|
|
||||||
wins: Int
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
val update = Updates.inc( "wins", wins )
|
|
||||||
connection.updateOne( collectionName, filter, update )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt Spiele zu einem Spieler hinzu
|
|
||||||
*/
|
|
||||||
suspend fun addGames(
|
|
||||||
uuid: UUID,
|
|
||||||
gamesPlayed: Int
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
val update = Updates.inc( "gamesPlayed", gamesPlayed )
|
|
||||||
connection.updateOne( collectionName, filter, update )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt Unathletic-Index zu einem Spieler hinzu
|
|
||||||
*/
|
|
||||||
suspend fun addUnathleticIndex(
|
|
||||||
uuid: UUID,
|
|
||||||
unathleticIndex: Double
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
val update = Updates.inc( "unathleticIndex", unathleticIndex )
|
|
||||||
connection.updateOne( collectionName, filter, update )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt Eisen zu einem Spieler hinzu
|
|
||||||
*/
|
|
||||||
suspend fun addIronFarmed(
|
|
||||||
uuid: UUID,
|
|
||||||
ironFarmed: Double
|
|
||||||
) {
|
|
||||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
|
||||||
val update = Updates.inc( "ironFarmed", ironFarmed )
|
|
||||||
connection.updateOne( collectionName, filter, update )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,138 +1,370 @@
|
|||||||
package club.mcscrims.speedhg.game
|
package club.mcscrims.speedhg.game
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
import club.mcscrims.speedhg.game.impl.BattleState
|
import club.mcscrims.speedhg.util.sendMsg
|
||||||
import club.mcscrims.speedhg.game.impl.DeathmatchState
|
import club.mcscrims.speedhg.util.trans
|
||||||
import club.mcscrims.speedhg.game.impl.EndState
|
import net.kyori.adventure.title.Title
|
||||||
import club.mcscrims.speedhg.game.impl.FeastState
|
import org.bukkit.*
|
||||||
import club.mcscrims.speedhg.game.impl.ImmunityState
|
import org.bukkit.attribute.Attribute
|
||||||
import club.mcscrims.speedhg.game.impl.PreStartState
|
|
||||||
import club.mcscrims.speedhg.game.impl.WaitingState
|
|
||||||
import org.bukkit.Location
|
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.util.BoundingBox
|
import org.bukkit.event.EventHandler
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.potion.PotionEffect
|
||||||
|
import org.bukkit.potion.PotionEffectType
|
||||||
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
class GameManager(
|
class GameManager(
|
||||||
private val plugin: SpeedHG
|
private val plugin: SpeedHG
|
||||||
) {
|
): Listener {
|
||||||
|
|
||||||
private var currentState: GameState? = null
|
var currentState: GameState = GameState.LOBBY
|
||||||
internal val gameStateTypes = ConcurrentHashMap<GameStateTypes, GameState>()
|
private set
|
||||||
|
|
||||||
private val winners = ArrayList<Player>()
|
var timer = 0
|
||||||
|
|
||||||
internal lateinit var feastLocation: Location
|
val alivePlayers = mutableSetOf<UUID>()
|
||||||
internal lateinit var feastBox: BoundingBox
|
|
||||||
internal var feastHeight: Int = 1
|
|
||||||
|
|
||||||
fun initialize()
|
private var gameTask: BukkitTask? = null
|
||||||
|
|
||||||
|
// Einstellungen aus Config (gecached für Performance)
|
||||||
|
private val minPlayers = plugin.config.getInt("game.min-players", 2)
|
||||||
|
private val lobbyTime = plugin.config.getInt("game.lobby-time", 60)
|
||||||
|
private val invincibilityTime = plugin.config.getInt("game.invincibility-time", 60)
|
||||||
|
private val startBorder = plugin.config.getDouble("game.border-start", 300.0)
|
||||||
|
private val endBorder = plugin.config.getDouble("game.border-end", 20.0)
|
||||||
|
// Zeit in Sekunden, bis Border komplett klein ist (z.B. 10 Min)
|
||||||
|
private val borderShrinkTime = plugin.config.getLong("game.border-shrink-time", 600)
|
||||||
|
|
||||||
|
init {
|
||||||
|
plugin.server.pluginManager.registerEvents( this, plugin )
|
||||||
|
|
||||||
|
gameTask = Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||||
|
gameLoop()
|
||||||
|
}, 20L, 20L )
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun gameLoop()
|
||||||
{
|
{
|
||||||
currentState = WaitingState(
|
when( currentState )
|
||||||
this,
|
{
|
||||||
plugin,
|
GameState.LOBBY ->
|
||||||
plugin.schedulerManager,
|
{
|
||||||
plugin.pluginConfig.data.getDuration( "waiting" ).seconds
|
if ( Bukkit.getOnlinePlayers().size >= minPlayers )
|
||||||
)
|
{
|
||||||
|
setGameState( GameState.STARTING )
|
||||||
|
timer = lobbyTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gameStateTypes[ GameStateTypes.WAITING ] = currentState!!
|
GameState.STARTING ->
|
||||||
gameStateTypes[ GameStateTypes.PRE_START ] = PreStartState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "pre_start" ).seconds )
|
{
|
||||||
gameStateTypes[ GameStateTypes.IMMUNITY ] = ImmunityState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "immunity" ).seconds )
|
if ( Bukkit.getOnlinePlayers().size < minPlayers )
|
||||||
gameStateTypes[ GameStateTypes.BATTLE ] = BattleState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "battle" ).seconds )
|
{
|
||||||
gameStateTypes[ GameStateTypes.FEAST ] = FeastState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "feast" ).seconds )
|
setGameState( GameState.LOBBY )
|
||||||
gameStateTypes[ GameStateTypes.DEATHMATCH ] = DeathmatchState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "deathmatch" ).seconds )
|
Bukkit.getOnlinePlayers().forEach { player ->
|
||||||
gameStateTypes[ GameStateTypes.END ] = EndState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "end" ).seconds )
|
player.sendMsg( "game.start-aborted" )
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
timer--
|
||||||
currentState?.onEnter( null )
|
|
||||||
} catch ( e: Exception ) {
|
if (timer in listOf( 60, 30, 10, 5, 4, 3, 2, 1 ))
|
||||||
plugin.logger.severe("Error during onEnter for state ${currentState?.name}: ${e.message}")
|
{
|
||||||
e.printStackTrace()
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.sendMsg( "timer.lobby", "time" to timer.toString() )
|
||||||
|
p.playSound( p.location, Sound.BLOCK_NOTE_BLOCK_HAT, 1f, 1f )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( timer <= 0 )
|
||||||
|
startGame()
|
||||||
|
}
|
||||||
|
|
||||||
|
GameState.INVINCIBILITY ->
|
||||||
|
{
|
||||||
|
timer--
|
||||||
|
|
||||||
|
if ( timer <= 0 )
|
||||||
|
startFighting()
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.sendActionBar(p.trans( "timer.actionbar-invincibility", "time" to timer.toString() ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameState.INGAME ->
|
||||||
|
{
|
||||||
|
timer++
|
||||||
|
updateCompass()
|
||||||
|
checkWin()
|
||||||
|
}
|
||||||
|
|
||||||
|
GameState.ENDING ->
|
||||||
|
{
|
||||||
|
timer--
|
||||||
|
|
||||||
|
if ( timer <= 0 )
|
||||||
|
Bukkit.shutdown()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun transitionTo(
|
fun setGameState(
|
||||||
stateType: GameStateTypes
|
newState: GameState
|
||||||
) {
|
) {
|
||||||
val previousState = currentState
|
this.currentState = newState
|
||||||
val nextState = gameStateTypes[ stateType ]!!
|
}
|
||||||
|
|
||||||
try {
|
private fun startGame()
|
||||||
currentState?.onExit( nextState )
|
{
|
||||||
} catch ( e: Exception ) {
|
setGameState( GameState.INVINCIBILITY )
|
||||||
plugin.logger.severe("Error during onExit for state ${currentState?.name}: ${e.message}")
|
timer = invincibilityTime
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( nextState is FeastState )
|
val world = Bukkit.getWorld( "world" ) ?: return
|
||||||
{
|
world.time = 0
|
||||||
feastLocation = nextState.feastLocation
|
world.setStorm( false )
|
||||||
feastBox = nextState.feastBox
|
|
||||||
feastHeight = nextState.feastHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
currentState = nextState
|
val border = world.worldBorder
|
||||||
|
border.center = Location( world, 0.0, 0.0, 0.0 )
|
||||||
|
border.size = startBorder
|
||||||
|
border.damageBuffer = 0.0
|
||||||
|
border.damageAmount = 1.0
|
||||||
|
|
||||||
try {
|
val speedEffect = PotionEffect(
|
||||||
nextState.onEnter( previousState )
|
PotionEffectType.SPEED,
|
||||||
} catch ( e: Exception ) {
|
timer,
|
||||||
plugin.logger.severe("Error during onEnter for state ${nextState.name}: ${e.message}")
|
0,
|
||||||
e.printStackTrace()
|
false,
|
||||||
}
|
false,
|
||||||
}
|
true
|
||||||
|
)
|
||||||
|
|
||||||
fun addWinners(
|
val hasteEffect = PotionEffect(
|
||||||
vararg winners: Player
|
PotionEffectType.HASTE,
|
||||||
|
timer,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
alivePlayers.clear()
|
||||||
|
Bukkit.getOnlinePlayers().forEach { player ->
|
||||||
|
alivePlayers.add( player.uniqueId )
|
||||||
|
|
||||||
|
player.gameMode = GameMode.SURVIVAL
|
||||||
|
player.health = player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.value ?: 20.0
|
||||||
|
player.foodLevel = 20
|
||||||
|
player.inventory.clear()
|
||||||
|
player.activePotionEffects.forEach { player.removePotionEffect( it.type ) }
|
||||||
|
player.addPotionEffects(listOf( speedEffect, hasteEffect ))
|
||||||
|
|
||||||
|
teleportRandomly( player, world, startBorder / 2 )
|
||||||
|
|
||||||
|
// TODO: Kit Items geben
|
||||||
|
// plugin.kitManager.giveKit( player )
|
||||||
|
|
||||||
|
player.inventory.addItem(ItemStack( Material.COMPASS ))
|
||||||
|
player.sendMsg( "game.started" )
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach { player ->
|
||||||
|
player.sendMsg( "game.invincibility-start" )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startFighting()
|
||||||
|
{
|
||||||
|
setGameState( GameState.INGAME )
|
||||||
|
timer = 0 // Reset Timer für "Ingame"
|
||||||
|
|
||||||
|
val world = Bukkit.getWorld( "world" ) ?: return
|
||||||
|
world.worldBorder.setSize( endBorder, borderShrinkTime )
|
||||||
|
|
||||||
|
plugin.antiRunningManager.resetTimers()
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.sendMsg( "game.fighting-started" )
|
||||||
|
p.playSound( p.location, Sound.ENTITY_ENDER_DRAGON_GROWL, 1f, 1f )
|
||||||
|
|
||||||
|
p.showTitle(Title.title(
|
||||||
|
p.trans( "title.fight-main" ),
|
||||||
|
p.trans( "title.fight-sub" )
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPlayerEliminated(
|
||||||
|
player: Player,
|
||||||
|
killer: Player?
|
||||||
) {
|
) {
|
||||||
winners.forEach { this.winners.add( it ) }
|
if (!alivePlayers.contains( player.uniqueId )) return
|
||||||
|
|
||||||
|
alivePlayers.remove( player.uniqueId )
|
||||||
|
player.gameMode = GameMode.SPECTATOR
|
||||||
|
|
||||||
|
player.inventory.contents.filterNotNull().forEach {
|
||||||
|
player.world.dropItemNaturally( player.location, it )
|
||||||
|
}
|
||||||
|
|
||||||
|
val msgKey = if ( killer != null ) "game.death-killed" else "game.death-pve"
|
||||||
|
val killerName = killer?.name ?: "Environment"
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.sendMsg( msgKey, "player" to player.name, "killer" to killerName, "left" to alivePlayers.size.toString() )
|
||||||
|
}
|
||||||
|
|
||||||
|
checkWin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWinners(): List<Player> = winners.toList()
|
private fun checkWin()
|
||||||
|
|
||||||
fun getCurrentState(): GameState? = currentState
|
|
||||||
|
|
||||||
fun getCurrentStateType(): GameStateTypes? = gameStateTypes.filter { it.value.name == currentState?.name }.keys.firstOrNull()
|
|
||||||
|
|
||||||
fun isRunning(): Boolean
|
|
||||||
{
|
{
|
||||||
return getCurrentStateType() == GameStateTypes.IMMUNITY ||
|
if ( currentState != GameState.INGAME && currentState != GameState.INVINCIBILITY ) return
|
||||||
getCurrentStateType() == GameStateTypes.BATTLE ||
|
|
||||||
getCurrentStateType() == GameStateTypes.FEAST ||
|
if ( alivePlayers.size <= 1 )
|
||||||
getCurrentStateType() == GameStateTypes.DEATHMATCH
|
{
|
||||||
|
val winnerUUID = alivePlayers.firstOrNull()
|
||||||
|
val winnerName = if ( winnerUUID != null ) Bukkit.getPlayer( winnerUUID )?.name ?: "N/A" else "N/A"
|
||||||
|
endGame( winnerName )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBeforeFeast(): Boolean
|
private fun endGame(
|
||||||
{
|
winnerName: String
|
||||||
return getCurrentStateType() == GameStateTypes.WAITING ||
|
) {
|
||||||
getCurrentStateType() == GameStateTypes.PRE_START ||
|
setGameState( GameState.ENDING )
|
||||||
getCurrentStateType() == GameStateTypes.IMMUNITY ||
|
timer = 15
|
||||||
(getCurrentStateType() == GameStateTypes.BATTLE &&
|
|
||||||
!( currentState as BattleState ).afterFeast )
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.showTitle(Title.title(
|
||||||
|
p.trans( "title.win-main", "winner" to winnerName ),
|
||||||
|
p.trans( "title.win-sub" )
|
||||||
|
))
|
||||||
|
p.sendMsg( "game.win-chat", "winner" to winnerName )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBefore(
|
// --- Helfer Methoden ---
|
||||||
stateType: GameStateTypes
|
|
||||||
): Boolean
|
private fun teleportRandomly(
|
||||||
{
|
player: Player,
|
||||||
return getCurrentStateType()?.points!! < stateType.points
|
world: World,
|
||||||
|
maxRadius: Double
|
||||||
|
) {
|
||||||
|
var loc: Location
|
||||||
|
var safe = false
|
||||||
|
var attempts = 0
|
||||||
|
|
||||||
|
do {
|
||||||
|
val x = Random.nextDouble( -maxRadius, maxRadius )
|
||||||
|
val z = Random.nextDouble( -maxRadius, maxRadius )
|
||||||
|
val y = world.getHighestBlockYAt( x.toInt(), z.toInt() ) + 1.0
|
||||||
|
loc = Location( world, x, y, z )
|
||||||
|
|
||||||
|
val block = loc.block.type
|
||||||
|
val below = loc.subtract( 0.0, 1.0, 0.0 ).block.type
|
||||||
|
|
||||||
|
if ( below.isSolid && below != Material.LAVA && below != Material.CACTUS && block == Material.AIR )
|
||||||
|
safe = true
|
||||||
|
attempts++
|
||||||
|
} while ( !safe && attempts < 20 )
|
||||||
|
|
||||||
|
player.teleport(loc.add( 0.0, 1.0, 0.0 ))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shutdown()
|
private fun updateCompass()
|
||||||
{
|
{
|
||||||
currentState?.onExit( null )
|
val players = Bukkit.getOnlinePlayers().filter { alivePlayers.contains( it.uniqueId ) }
|
||||||
currentState = null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
for ( p in players )
|
||||||
|
{
|
||||||
|
var nearest: Player? = null
|
||||||
|
var minDistance = Double.MAX_VALUE
|
||||||
|
|
||||||
enum class GameStateTypes(
|
for ( target in players )
|
||||||
val points: Int
|
{
|
||||||
) {
|
if ( p == target ) continue
|
||||||
WAITING( 0 ),
|
|
||||||
PRE_START( 1 ),
|
val dist = p.location.distanceSquared( target.location )
|
||||||
IMMUNITY( 2 ),
|
if ( dist < minDistance )
|
||||||
BATTLE( 3 ),
|
{
|
||||||
FEAST( 4 ),
|
minDistance = dist
|
||||||
DEATHMATCH( 5 ),
|
nearest = target
|
||||||
END( 6 )
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( nearest != null )
|
||||||
|
p.compassTarget = nearest.location
|
||||||
|
else
|
||||||
|
p.compassTarget = p.world.spawnLocation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Event Listener Integration ---
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onDeath(
|
||||||
|
event: PlayerDeathEvent
|
||||||
|
) {
|
||||||
|
if ( currentState == GameState.INGAME || currentState == GameState.INVINCIBILITY )
|
||||||
|
{
|
||||||
|
event.deathMessage( null )
|
||||||
|
event.drops.clear()
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask( plugin ) { ->
|
||||||
|
event.entity.spigot().respawn()
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayerEliminated( event.entity, event.entity.killer )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onQuit(
|
||||||
|
event: PlayerQuitEvent
|
||||||
|
) {
|
||||||
|
if (alivePlayers.contains( event.player.uniqueId ))
|
||||||
|
{
|
||||||
|
if ( currentState == GameState.INGAME || currentState == GameState.INVINCIBILITY )
|
||||||
|
{
|
||||||
|
val lastDamageCause = event.player.lastDamageCause
|
||||||
|
|
||||||
|
if ( lastDamageCause != null && lastDamageCause is EntityDamageByEntityEvent )
|
||||||
|
{
|
||||||
|
val attacker = lastDamageCause.damager
|
||||||
|
|
||||||
|
if ( attacker is Player )
|
||||||
|
{
|
||||||
|
onPlayerEliminated( event.player, attacker )
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayerEliminated( event.player, null ) // PVE Tod
|
||||||
|
}
|
||||||
|
else alivePlayers.remove( event.player.uniqueId )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onDamage(
|
||||||
|
event: EntityDamageEvent
|
||||||
|
) {
|
||||||
|
if ( currentState == GameState.INVINCIBILITY && event.entity is Player )
|
||||||
|
event.isCancelled = true
|
||||||
|
|
||||||
|
if ( currentState == GameState.LOBBY || currentState == GameState.STARTING || currentState == GameState.ENDING )
|
||||||
|
event.isCancelled = true // Nie Schaden in Lobby/Ende
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,109 +1,9 @@
|
|||||||
package club.mcscrims.speedhg.game
|
package club.mcscrims.speedhg.game
|
||||||
|
|
||||||
import club.mcscrims.core.config.DurationType
|
enum class GameState {
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
LOBBY, // Warten auf Spieler
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
STARTING, // Countdown läuft
|
||||||
import club.mcscrims.spigot.scheduler.TaskRegistration
|
INVINCIBILITY, // Schutzzeit (Spieler verteilt, kein Schaden)
|
||||||
import org.bukkit.Bukkit
|
INGAME, // Kampfphase (Schaden an, Border schrumpft)
|
||||||
import org.bukkit.entity.Player
|
ENDING // Gewinner steht fest, Server startet neu
|
||||||
import org.bukkit.scheduler.BukkitTask
|
}
|
||||||
|
|
||||||
abstract class GameState(
|
|
||||||
val name: String,
|
|
||||||
protected val gameManager: GameManager,
|
|
||||||
protected val plugin: SpeedHG,
|
|
||||||
protected val schedulerManager: SchedulerManager,
|
|
||||||
protected val durationSeconds: Int? = null
|
|
||||||
) {
|
|
||||||
|
|
||||||
private var tickTask: BukkitTask? = null
|
|
||||||
private var remainingSeconds: Int = durationSeconds ?: 0
|
|
||||||
private var isActive: Boolean = false
|
|
||||||
|
|
||||||
open fun onEnter(
|
|
||||||
previous: GameState?
|
|
||||||
) {
|
|
||||||
isActive = true
|
|
||||||
remainingSeconds = durationSeconds ?: 0
|
|
||||||
|
|
||||||
if ( durationSeconds != null )
|
|
||||||
startTicking()
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun onTick()
|
|
||||||
|
|
||||||
abstract fun onEndOfDuration()
|
|
||||||
|
|
||||||
open fun onExit(
|
|
||||||
next: GameState?
|
|
||||||
) {
|
|
||||||
isActive = false
|
|
||||||
stopTicking()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startTicking()
|
|
||||||
{
|
|
||||||
tickTask = Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
|
||||||
if ( !isActive )
|
|
||||||
{
|
|
||||||
stopTicking()
|
|
||||||
return@runTaskTimer
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onTick()
|
|
||||||
} catch ( e: Exception ) {
|
|
||||||
plugin.logger.severe("Error during onTick for state $name: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( durationSeconds != null && remainingSeconds > 0 )
|
|
||||||
{
|
|
||||||
if (plugin.pluginConfig.data.getDuration( name ).type == DurationType.INCREASING )
|
|
||||||
{
|
|
||||||
remainingSeconds++
|
|
||||||
return@runTaskTimer
|
|
||||||
}
|
|
||||||
|
|
||||||
remainingSeconds--
|
|
||||||
|
|
||||||
if ( remainingSeconds == 0)
|
|
||||||
try {
|
|
||||||
onEndOfDuration()
|
|
||||||
} catch ( e: Exception ) {
|
|
||||||
plugin.logger.severe("Error during onEndOfDuration for state $name: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 20L, 20L )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun stopTicking() {
|
|
||||||
tickTask?.cancel()
|
|
||||||
tickTask = null
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun broadcast(
|
|
||||||
messageKey: String,
|
|
||||||
vararg placeholders: Pair<String, String>
|
|
||||||
) {
|
|
||||||
plugin.chatManager.broadcast( messageKey, *placeholders )
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun forAlivePlayers(
|
|
||||||
action: (Player) -> Unit
|
|
||||||
) {
|
|
||||||
Bukkit.getOnlinePlayers()
|
|
||||||
.filter { !it.isDead }
|
|
||||||
.forEach { player ->
|
|
||||||
try {
|
|
||||||
action( player )
|
|
||||||
} catch ( e: Exception ) {
|
|
||||||
plugin.logger.warning("Error executing action for player ${player.name}: ${e.message}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRemainingSeconds(): Int = remainingSeconds
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
|
|
||||||
class BattleState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "battle", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
var afterFeast: Boolean = false
|
|
||||||
|
|
||||||
override fun onEnter(
|
|
||||||
previous: GameState?
|
|
||||||
) {
|
|
||||||
super.onEnter( previous )
|
|
||||||
Bukkit.getOnlinePlayers().forEach( Player::clearActivePotionEffects )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTick()
|
|
||||||
{
|
|
||||||
val win = checkForWinners()
|
|
||||||
|
|
||||||
when( getRemainingSeconds() )
|
|
||||||
{
|
|
||||||
300 ->
|
|
||||||
{
|
|
||||||
gameManager.gameStateTypes[ GameStateTypes.BATTLE ] = this
|
|
||||||
gameManager.transitionTo( GameStateTypes.FEAST )
|
|
||||||
afterFeast = true
|
|
||||||
}
|
|
||||||
|
|
||||||
1800 ->
|
|
||||||
{
|
|
||||||
if ( !win )
|
|
||||||
{
|
|
||||||
gameManager.transitionTo( GameStateTypes.DEATHMATCH )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfDuration() {}
|
|
||||||
|
|
||||||
private fun checkForWinners(): Boolean
|
|
||||||
{
|
|
||||||
val players = Bukkit.getOnlinePlayers().filter { !it.isDead }
|
|
||||||
|
|
||||||
if ( players.size > 1 )
|
|
||||||
return false
|
|
||||||
|
|
||||||
gameManager.addWinners( players.first() )
|
|
||||||
gameManager.transitionTo( GameStateTypes.END )
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.speedhg.game.impl.PreStartState.AnnouncementType
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Location
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.Statistic
|
|
||||||
import org.bukkit.potion.PotionEffect
|
|
||||||
import org.bukkit.potion.PotionEffectType
|
|
||||||
|
|
||||||
class DeathmatchState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "deathmatch", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
private val world = plugin.worldManager.getWorld()
|
|
||||||
private val pitLocation = Location( world, 0.0, 1.0, 0.0 )
|
|
||||||
|
|
||||||
override fun onTick()
|
|
||||||
{
|
|
||||||
checkForWinners()
|
|
||||||
|
|
||||||
when( getRemainingSeconds() )
|
|
||||||
{
|
|
||||||
0 ->
|
|
||||||
{
|
|
||||||
plugin.chatManager.broadcast( "gameStates.deathmatch.started" )
|
|
||||||
circle()
|
|
||||||
schedulerManager.runLater( 10L ) { randomTeleport() }
|
|
||||||
}
|
|
||||||
|
|
||||||
600 -> announce( AnnouncementType.MINUTES, 5 )
|
|
||||||
660 -> announce( AnnouncementType.MINUTES, 4 )
|
|
||||||
720 -> announce( AnnouncementType.MINUTES, 3 )
|
|
||||||
780 -> announce( AnnouncementType.MINUTES, 2 )
|
|
||||||
840 -> announce( AnnouncementType.MINUTES, 1 )
|
|
||||||
870 -> announce( AnnouncementType.SECONDS, 30 )
|
|
||||||
885 -> announce( AnnouncementType.SECONDS, 15 )
|
|
||||||
890 -> announce( AnnouncementType.SECONDS, 10 )
|
|
||||||
895 -> announce( AnnouncementType.SECONDS, 5 )
|
|
||||||
896 -> announce( AnnouncementType.SECONDS, 4 )
|
|
||||||
897 -> announce( AnnouncementType.SECONDS, 3 )
|
|
||||||
898 -> announce( AnnouncementType.SECONDS, 2 )
|
|
||||||
899 -> announce( AnnouncementType.SECONDS, 1 )
|
|
||||||
|
|
||||||
900 -> try {
|
|
||||||
onEndOfDuration()
|
|
||||||
} catch ( e: Exception ) {
|
|
||||||
plugin.logger.severe("Error during onEndOfDuration for state $name: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfDuration()
|
|
||||||
{
|
|
||||||
val winner = Bukkit.getOnlinePlayers().stream()
|
|
||||||
.filter { !it.isDead }
|
|
||||||
.map { it.getStatistic( Statistic.PLAYER_KILLS ) to it }
|
|
||||||
.max(compareBy { it.first })
|
|
||||||
.get().second
|
|
||||||
|
|
||||||
gameManager.addWinners( winner )
|
|
||||||
gameManager.transitionTo( GameStateTypes.END )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkForWinners(): Boolean
|
|
||||||
{
|
|
||||||
val players = Bukkit.getOnlinePlayers().filter { !it.isDead }
|
|
||||||
|
|
||||||
if ( players.size > 1 )
|
|
||||||
return false
|
|
||||||
|
|
||||||
gameManager.addWinners( players.first() )
|
|
||||||
gameManager.transitionTo( GameStateTypes.END )
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun announce(
|
|
||||||
type: AnnouncementType,
|
|
||||||
time: Int
|
|
||||||
) {
|
|
||||||
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
|
|
||||||
broadcast( "gameStates.deathmatch.ending$arg", "{time}" to time.toString() )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun randomTeleport()
|
|
||||||
{
|
|
||||||
forAlivePlayers { player ->
|
|
||||||
player.addPotionEffect(PotionEffect( PotionEffectType.RESISTANCE, 40, 20 ))
|
|
||||||
|
|
||||||
val loc = pitLocation.clone()
|
|
||||||
loc.x = (( pitLocation.blockX - 15 )..( pitLocation.blockX + 15 )).random().toDouble()
|
|
||||||
loc.z = (( pitLocation.blockZ - 15 )..( pitLocation.blockZ + 15 )).random().toDouble()
|
|
||||||
loc.y = world!!.getHighestBlockYAt( loc.blockX, loc.blockZ ).toDouble()
|
|
||||||
player.teleport( loc )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun circle()
|
|
||||||
{
|
|
||||||
val highestLocation = plugin.worldManager.highestLocationWithRadius( pitLocation, 30 )
|
|
||||||
plugin.worldEditUtils.createCylinder( world!!, pitLocation, 30.0, highestLocation.blockY, Material.AIR, true )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.spigot.chat.getDisplayName
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
|
|
||||||
class EndState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "end", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
override fun onEnter(
|
|
||||||
previous: GameState?
|
|
||||||
) {
|
|
||||||
super.onEnter( previous )
|
|
||||||
val winners = gameManager.getWinners()
|
|
||||||
|
|
||||||
if ( winners.size > 1 )
|
|
||||||
plugin.chatManager.broadcast( "gameStates.end.multipleWinners", "{winners}" to winners.joinToString { it.getDisplayName } )
|
|
||||||
else if ( winners.size == 1 )
|
|
||||||
plugin.chatManager.broadcast( "gameStates.end.oneWinner", "{winner}" to winners.first().getDisplayName )
|
|
||||||
else
|
|
||||||
plugin.chatManager.broadcast( "gameStates.end.noWinners" )
|
|
||||||
|
|
||||||
runBlocking { winners.forEach {
|
|
||||||
plugin.statsRepository.addWins( it.uniqueId, 1 )
|
|
||||||
} }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTick() {}
|
|
||||||
|
|
||||||
override fun onEndOfDuration()
|
|
||||||
{
|
|
||||||
Bukkit.shutdown()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.speedhg.game.impl.PreStartState.AnnouncementType
|
|
||||||
import club.mcscrims.speedhg.util.RandomCollection
|
|
||||||
import club.mcscrims.spigot.item.ItemBuilder
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
|
||||||
import org.bukkit.Location
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.block.Chest
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.inventory.meta.PotionMeta
|
|
||||||
import org.bukkit.potion.PotionEffect
|
|
||||||
import org.bukkit.potion.PotionEffectType
|
|
||||||
import org.bukkit.util.BoundingBox
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class FeastState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "feast", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
private val world = plugin.worldManager.getWorld()
|
|
||||||
private val random = Random()
|
|
||||||
|
|
||||||
internal var feastLocation: Location
|
|
||||||
internal var feastBox: BoundingBox
|
|
||||||
internal var feastHeight: Int = 1
|
|
||||||
|
|
||||||
init
|
|
||||||
{
|
|
||||||
this.feastLocation = getLocation()
|
|
||||||
this.feastHeight = plugin.worldManager.highestLocationWithRadius( feastLocation, 11 ).blockY + 3
|
|
||||||
this.feastBox = BoundingBox.of( feastLocation, 11.0, feastHeight.toDouble(), 11.0 )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEnter(
|
|
||||||
previous: GameState?
|
|
||||||
) {
|
|
||||||
super.onEnter( previous )
|
|
||||||
circle()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTick()
|
|
||||||
{
|
|
||||||
when( getRemainingSeconds() )
|
|
||||||
{
|
|
||||||
300 -> announce( AnnouncementType.MINUTES, 5 )
|
|
||||||
240 -> announce( AnnouncementType.MINUTES, 4 )
|
|
||||||
180 -> announce( AnnouncementType.MINUTES, 3 )
|
|
||||||
120 -> announce( AnnouncementType.MINUTES, 2 )
|
|
||||||
60 -> announce( AnnouncementType.MINUTES, 1 )
|
|
||||||
30 -> announce( AnnouncementType.SECONDS, 30 )
|
|
||||||
15 -> announce( AnnouncementType.SECONDS, 15 )
|
|
||||||
10 -> announce( AnnouncementType.SECONDS, 10 )
|
|
||||||
5 -> announce( AnnouncementType.SECONDS, 5 )
|
|
||||||
4 -> announce( AnnouncementType.SECONDS, 4 )
|
|
||||||
3 -> announce( AnnouncementType.SECONDS, 3 )
|
|
||||||
2 -> announce( AnnouncementType.SECONDS, 2 )
|
|
||||||
1 -> announce( AnnouncementType.SECONDS, 1 )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfDuration()
|
|
||||||
{
|
|
||||||
plugin.chatManager.broadcast( "feast.started",
|
|
||||||
"{x}" to feastLocation.blockX.toString(),
|
|
||||||
"{y}" to feastLocation.blockY.toString(),
|
|
||||||
"{z}" to feastLocation.blockZ.toString()
|
|
||||||
)
|
|
||||||
|
|
||||||
chests()
|
|
||||||
gameManager.transitionTo( GameStateTypes.BATTLE )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun chests()
|
|
||||||
{
|
|
||||||
feastLocation.clone().block.type = Material.ENCHANTING_TABLE
|
|
||||||
|
|
||||||
val chestLocations = arrayOfNulls<Location>( 12 )
|
|
||||||
|
|
||||||
chestLocations[0] = feastLocation.clone().add( 1.0, 0.0, 1.0 )
|
|
||||||
chestLocations[1] = feastLocation.clone().add( -1.0, 0.0, 1.0 )
|
|
||||||
chestLocations[2] = feastLocation.clone().add( -1.0, 0.0, -1.0 )
|
|
||||||
chestLocations[3] = feastLocation.clone().add( 1.0, 0.0, -1.0 )
|
|
||||||
chestLocations[4] = feastLocation.clone().add( 2.0, 0.0, 2.0 )
|
|
||||||
chestLocations[5] = feastLocation.clone().add( 0.0, 0.0, 2.0 )
|
|
||||||
chestLocations[6] = feastLocation.clone().add( -2.0, 0.0, 2.0 )
|
|
||||||
chestLocations[7] = feastLocation.clone().add( 2.0, 0.0, 0.0 )
|
|
||||||
chestLocations[8] = feastLocation.clone().add( -2.0, 0.0, 0.0 )
|
|
||||||
chestLocations[9] = feastLocation.clone().add( 2.0, 0.0, -2.0 )
|
|
||||||
chestLocations[10] = feastLocation.clone().add( 0.0, 0.0, -2.0 )
|
|
||||||
chestLocations[11] = feastLocation.clone().add( -2.0, 0.0, -2.0 )
|
|
||||||
|
|
||||||
Arrays.stream( chestLocations ).forEach { it!!.block.type = Material.CHEST }
|
|
||||||
|
|
||||||
val diamondItems = RandomCollection<ItemStack>()
|
|
||||||
diamondItems.add( 1.0, ItemStack( Material.DIAMOND_BOOTS ))
|
|
||||||
diamondItems.add( 1.0, ItemStack( Material.DIAMOND_CHESTPLATE ))
|
|
||||||
diamondItems.add( 1.0, ItemStack( Material.DIAMOND_SWORD ))
|
|
||||||
|
|
||||||
val ironItems = RandomCollection<ItemStack>()
|
|
||||||
ironItems.add( 1.0, ItemStack( Material.IRON_BOOTS ))
|
|
||||||
ironItems.add( 1.0, ItemStack( Material.IRON_LEGGINGS ))
|
|
||||||
ironItems.add( 1.0, ItemStack( Material.IRON_CHESTPLATE ))
|
|
||||||
ironItems.add( 1.0, ItemStack( Material.IRON_HELMET ))
|
|
||||||
ironItems.add( 1.0, ItemStack( Material.IRON_SWORD ))
|
|
||||||
|
|
||||||
val netheriteItems = RandomCollection<ItemStack>()
|
|
||||||
netheriteItems.add( 1.0, ItemStack( Material.NETHERITE_INGOT ))
|
|
||||||
netheriteItems.add( 1.0, ItemStack( Material.SMITHING_TABLE ))
|
|
||||||
|
|
||||||
val sizeableItems = RandomCollection<ItemStack>()
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.RED_MUSHROOM ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.BROWN_MUSHROOM ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.BOWL ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.CACTUS ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.COCOA_BEANS ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.MUSHROOM_STEW ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.LAPIS_LAZULI ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.ARROW ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.COOKED_BEEF ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.COOKED_PORKCHOP ))
|
|
||||||
sizeableItems.add( 1.0, ItemStack( Material.COOKED_CHICKEN ))
|
|
||||||
|
|
||||||
val singleItems = RandomCollection<ItemStack>()
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.BOW ))
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.COBWEB ))
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.FLINT_AND_STEEL ))
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.TNT ))
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.ENDER_PEARL ))
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.LAVA_BUCKET ))
|
|
||||||
singleItems.add( 1.0, ItemStack( Material.WATER_BUCKET ))
|
|
||||||
|
|
||||||
val strengthPotion = ItemStack( Material.SPLASH_POTION )
|
|
||||||
val effect = PotionEffect( PotionEffectType.STRENGTH, (60..240).random(), 0 )
|
|
||||||
strengthPotion.editMeta { ( it as PotionMeta ).addCustomEffect( effect, true ) }
|
|
||||||
|
|
||||||
singleItems.add( 1.0, strengthPotion )
|
|
||||||
|
|
||||||
val cleanser = ItemBuilder( plugin, Material.SUGAR )
|
|
||||||
.name(LegacyComponentSerializer.legacySection().serialize(plugin.chatFormatter.format( "feast.cleanser.name" )))
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
singleItems.add( 1.0, cleanser )
|
|
||||||
|
|
||||||
val lootPool = RandomCollection<RandomCollection<ItemStack>>()
|
|
||||||
lootPool.add( 17.5, ironItems )
|
|
||||||
lootPool.add( 6.8, diamondItems )
|
|
||||||
lootPool.add( 33.0, sizeableItems )
|
|
||||||
lootPool.add( 33.0, singleItems )
|
|
||||||
lootPool.add( 1.5, netheriteItems )
|
|
||||||
|
|
||||||
for ( location in chestLocations )
|
|
||||||
{
|
|
||||||
val chest = location!!.block.state as Chest
|
|
||||||
|
|
||||||
for ( i in 0..( 6..12 ).random() )
|
|
||||||
{
|
|
||||||
val randomItemCollection = lootPool.getRandom()
|
|
||||||
val itemList = randomItemCollection.random().getRandom()
|
|
||||||
|
|
||||||
for ( item in itemList )
|
|
||||||
{
|
|
||||||
if ( randomItemCollection == sizeableItems )
|
|
||||||
item.amount = ( 1..16 ).random()
|
|
||||||
|
|
||||||
chest.inventory.setItem(random.nextInt( 26 - 1 ) + 1, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun announce(
|
|
||||||
type: AnnouncementType,
|
|
||||||
time: Int
|
|
||||||
) {
|
|
||||||
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
|
|
||||||
broadcast( "gameStates.feast.starting$arg", "{time}" to time.toString() )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun circle()
|
|
||||||
{
|
|
||||||
plugin.worldEditUtils.createCylinder( world!!, feastLocation, 11.0, feastHeight, Material.GRASS_BLOCK, false )
|
|
||||||
plugin.worldEditUtils.createCylinder( world, feastLocation.add( 0.0, 1.0, 0.0 ), 11.0, feastHeight, Material.AIR, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLocation(): Location
|
|
||||||
{
|
|
||||||
val x = ( -100..100 ).random()
|
|
||||||
val z = ( -100..100 ).random()
|
|
||||||
|
|
||||||
val highestY = world!!.getHighestBlockYAt( x, z )
|
|
||||||
|
|
||||||
if ( highestY >= 70 )
|
|
||||||
return getLocation()
|
|
||||||
|
|
||||||
return Location( world, x.toDouble(), highestY.toDouble() + 5.0, z.toDouble() )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.speedhg.game.impl.PreStartState.AnnouncementType
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.potion.PotionEffect
|
|
||||||
import org.bukkit.potion.PotionEffectType
|
|
||||||
|
|
||||||
class ImmunityState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "immunity", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
override fun onEnter(
|
|
||||||
previous: GameState?
|
|
||||||
) {
|
|
||||||
super.onEnter( previous )
|
|
||||||
|
|
||||||
val effects = listOf(
|
|
||||||
PotionEffect( PotionEffectType.HASTE, durationSeconds?.times( 20 ) ?: 0, 0 ),
|
|
||||||
PotionEffect( PotionEffectType.SPEED, durationSeconds?.times( 20 ) ?: 0, 0 )
|
|
||||||
)
|
|
||||||
|
|
||||||
val players = Bukkit.getOnlinePlayers()
|
|
||||||
players.forEach { it.addPotionEffects( effects ) }
|
|
||||||
|
|
||||||
for ( player in players )
|
|
||||||
{
|
|
||||||
player.inventory.clear()
|
|
||||||
player.inventory.armorContents = emptyArray()
|
|
||||||
|
|
||||||
player.inventory.setItem( 8, ItemStack( Material.COMPASS ))
|
|
||||||
|
|
||||||
plugin.kitManager.startKitForPlayer( player )
|
|
||||||
TODO( "Give perks" )
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcast( "gameStates.immunity.warnings.butterfly" )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTick()
|
|
||||||
{
|
|
||||||
when( getRemainingSeconds() )
|
|
||||||
{
|
|
||||||
180 -> announce( AnnouncementType.MINUTES, 3 )
|
|
||||||
120 -> announce( AnnouncementType.MINUTES, 2 )
|
|
||||||
60 -> announce( AnnouncementType.MINUTES, 1 )
|
|
||||||
30 -> announce( AnnouncementType.SECONDS, 30 )
|
|
||||||
15 -> announce( AnnouncementType.SECONDS, 15 )
|
|
||||||
10 -> announce( AnnouncementType.SECONDS, 10 )
|
|
||||||
5 -> announce( AnnouncementType.SECONDS, 5 )
|
|
||||||
4 -> announce( AnnouncementType.SECONDS, 4 )
|
|
||||||
3 -> announce( AnnouncementType.SECONDS, 3 )
|
|
||||||
2 -> announce( AnnouncementType.SECONDS, 2 )
|
|
||||||
1 -> announce( AnnouncementType.SECONDS, 1 )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfDuration()
|
|
||||||
{
|
|
||||||
broadcast( "gameStates.immunity.ended" )
|
|
||||||
gameManager.transitionTo( GameStateTypes.BATTLE )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun announce(
|
|
||||||
type: AnnouncementType,
|
|
||||||
time: Int
|
|
||||||
) {
|
|
||||||
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
|
|
||||||
broadcast( "gameStates.immunity.ending$arg", "{time}" to time.toString() )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Location
|
|
||||||
|
|
||||||
class PreStartState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "pre_start", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
private lateinit var previous: GameState
|
|
||||||
|
|
||||||
override fun onEnter(
|
|
||||||
previous: GameState?
|
|
||||||
) {
|
|
||||||
super.onEnter( previous )
|
|
||||||
|
|
||||||
if ( previous != null )
|
|
||||||
this.previous = previous
|
|
||||||
}
|
|
||||||
|
|
||||||
var isStarting: Boolean = false
|
|
||||||
|
|
||||||
override fun onTick()
|
|
||||||
{
|
|
||||||
val playerSize = Bukkit.getOnlinePlayers().size
|
|
||||||
|
|
||||||
if ( playerSize < plugin.pluginConfig.data.game.minimumPlayers )
|
|
||||||
{
|
|
||||||
isStarting = false
|
|
||||||
gameManager.transitionTo( GameStateTypes.WAITING )
|
|
||||||
}
|
|
||||||
else isStarting = true
|
|
||||||
|
|
||||||
if ( !isStarting )
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( getRemainingSeconds() == 15 )
|
|
||||||
teleport()
|
|
||||||
|
|
||||||
when( getRemainingSeconds() )
|
|
||||||
{
|
|
||||||
300 -> announce( AnnouncementType.MINUTES, 5 )
|
|
||||||
240 -> announce( AnnouncementType.MINUTES, 4 )
|
|
||||||
180 -> announce( AnnouncementType.MINUTES, 3 )
|
|
||||||
120 -> announce( AnnouncementType.MINUTES, 2 )
|
|
||||||
60 -> announce( AnnouncementType.MINUTES, 1 )
|
|
||||||
30 -> announce( AnnouncementType.SECONDS, 30 )
|
|
||||||
15 -> announce( AnnouncementType.SECONDS, 15 )
|
|
||||||
10 -> announce( AnnouncementType.SECONDS, 10 )
|
|
||||||
5 -> announce( AnnouncementType.SECONDS, 5 )
|
|
||||||
4 -> announce( AnnouncementType.SECONDS, 4 )
|
|
||||||
3 -> announce( AnnouncementType.SECONDS, 3 )
|
|
||||||
2 -> announce( AnnouncementType.SECONDS, 2 )
|
|
||||||
1 -> announce( AnnouncementType.SECONDS, 1 )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfDuration()
|
|
||||||
{
|
|
||||||
broadcast( "gameStates.preStart.started" )
|
|
||||||
isStarting = false
|
|
||||||
gameManager.transitionTo( GameStateTypes.IMMUNITY )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onExit(
|
|
||||||
next: GameState?
|
|
||||||
) {
|
|
||||||
super.onExit( next )
|
|
||||||
Bukkit.getOnlinePlayers().forEach { it.inventory.clear() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun announce(
|
|
||||||
type: AnnouncementType,
|
|
||||||
time: Int
|
|
||||||
) {
|
|
||||||
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
|
|
||||||
broadcast( "gameStates.preStart.starting$arg", "{time}" to time.toString() )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun teleport()
|
|
||||||
{
|
|
||||||
for ( player in Bukkit.getOnlinePlayers() )
|
|
||||||
{
|
|
||||||
val world = player.world
|
|
||||||
val loc = Location( world, 0.0, world.getHighestBlockYAt( 0, 0 ).toDouble(), 0.0 )
|
|
||||||
player.teleport( loc )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum class AnnouncementType {
|
|
||||||
MINUTES, SECONDS
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.game.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.game.GameState
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
|
|
||||||
class WaitingState(
|
|
||||||
gameManager: GameManager,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
schedulerManager: SchedulerManager,
|
|
||||||
durationSeconds: Int? = null
|
|
||||||
) : GameState( "waiting", gameManager, plugin, schedulerManager, durationSeconds ) {
|
|
||||||
|
|
||||||
private var secondsCounter: Int = 0
|
|
||||||
|
|
||||||
override fun onTick()
|
|
||||||
{
|
|
||||||
val playerSize = Bukkit.getOnlinePlayers().size
|
|
||||||
|
|
||||||
if ( playerSize < plugin.pluginConfig.data.game.minimumPlayers )
|
|
||||||
if ( secondsCounter == 15 )
|
|
||||||
{
|
|
||||||
broadcast( "gameStates.waiting.awaiting_players", "{min_players}" to plugin.pluginConfig.data.game.minimumPlayers.toString() )
|
|
||||||
secondsCounter = 0
|
|
||||||
}
|
|
||||||
else secondsCounter++
|
|
||||||
else gameManager.transitionTo( GameStateTypes.PRE_START )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEndOfDuration() {}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
package club.mcscrims.speedhg.game.modules
|
||||||
|
|
||||||
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
|
import club.mcscrims.speedhg.game.GameState
|
||||||
|
import club.mcscrims.speedhg.util.sendMsg
|
||||||
|
import club.mcscrims.speedhg.util.trans
|
||||||
|
import net.kyori.adventure.bossbar.BossBar
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Sound
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
|
import org.bukkit.potion.PotionEffect
|
||||||
|
import org.bukkit.potion.PotionEffectType
|
||||||
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
class AntiRunningManager(
|
||||||
|
private val plugin: SpeedHG
|
||||||
|
): Listener
|
||||||
|
{
|
||||||
|
|
||||||
|
private val lastCombatAction = ConcurrentHashMap<UUID, Long>()
|
||||||
|
|
||||||
|
private val warningBar = BossBar.bossBar(
|
||||||
|
Component.text("FIGHT!"),
|
||||||
|
1.0f,
|
||||||
|
BossBar.Color.RED,
|
||||||
|
BossBar.Overlay.PROGRESS
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||||
|
checkPlayers()
|
||||||
|
}, 20L, 20L )
|
||||||
|
|
||||||
|
plugin.server.pluginManager.registerEvents( this, plugin )
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onDamage(
|
||||||
|
event: EntityDamageByEntityEvent
|
||||||
|
) {
|
||||||
|
if (plugin.gameManager.currentState != GameState.INGAME)
|
||||||
|
return
|
||||||
|
|
||||||
|
val victim = event.entity
|
||||||
|
val attacker = event.damager
|
||||||
|
|
||||||
|
if ( victim is Player && attacker is Player)
|
||||||
|
{
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
lastCombatAction[ victim.uniqueId ] = now
|
||||||
|
lastCombatAction[ attacker.uniqueId ] = now
|
||||||
|
|
||||||
|
removePunishment( victim )
|
||||||
|
removePunishment( attacker )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPlayers()
|
||||||
|
{
|
||||||
|
if (plugin.gameManager.currentState != GameState.INGAME)
|
||||||
|
return
|
||||||
|
|
||||||
|
val config = plugin.config.getConfigurationSection( "anti-runner" ) ?: return
|
||||||
|
if (!config.getBoolean( "enabled" )) return
|
||||||
|
|
||||||
|
val radius = config.getDouble( "check-radius" )
|
||||||
|
val maxYDiff = config.getDouble( "ignore-vertical-distance", 15.0 )
|
||||||
|
val ignoreCaveMix = config.getBoolean( "ignore-cave-surface-mix", true )
|
||||||
|
|
||||||
|
val warnTime = config.getLong( "warn-time" ) * 1000
|
||||||
|
val punishTime = config.getLong( "punish-time" ) * 1000
|
||||||
|
|
||||||
|
val players = Bukkit.getOnlinePlayers().filter { it.gameMode == GameMode.SURVIVAL }
|
||||||
|
|
||||||
|
for ( player in players )
|
||||||
|
{
|
||||||
|
val nearbyEnemy = players
|
||||||
|
.filter { other ->
|
||||||
|
other != player &&
|
||||||
|
other.world == player.world &&
|
||||||
|
other.location.distanceSquared( player.location ) <= ( radius * radius )
|
||||||
|
}
|
||||||
|
.minByOrNull { it.location.distanceSquared( player.location ) }
|
||||||
|
|
||||||
|
if ( nearbyEnemy == null )
|
||||||
|
{
|
||||||
|
resetPlayerTimer( player )
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val yDiff = abs(player.location.y - nearbyEnemy.location.y)
|
||||||
|
|
||||||
|
if ( yDiff > maxYDiff )
|
||||||
|
{
|
||||||
|
resetPlayerTimer( player )
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ignoreCaveMix && player.world.isDayTime )
|
||||||
|
{
|
||||||
|
val lightA = player.location.block.lightFromSky
|
||||||
|
val lightB = nearbyEnemy.location.block.lightFromSky
|
||||||
|
|
||||||
|
val isPlayerOutside = lightA > 12
|
||||||
|
val isEnemyInCave = lightB < 4
|
||||||
|
|
||||||
|
val isPlayerInCave = lightA < 4
|
||||||
|
val isEnemyOutside = lightB > 12
|
||||||
|
|
||||||
|
if (( isPlayerOutside && isEnemyInCave ) || ( isPlayerInCave && isEnemyOutside ))
|
||||||
|
{
|
||||||
|
resetPlayerTimer( player )
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val lastCombat = lastCombatAction.getOrDefault( player.uniqueId, System.currentTimeMillis() )
|
||||||
|
val timeDiff = System.currentTimeMillis() - lastCombat
|
||||||
|
|
||||||
|
if ( timeDiff > warnTime )
|
||||||
|
player.showBossBar(warningBar.name(player.trans( "antirunner.warning" )))
|
||||||
|
else
|
||||||
|
player.hideBossBar( warningBar )
|
||||||
|
|
||||||
|
if ( timeDiff > punishTime )
|
||||||
|
applyPunishment( player )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyPunishment(
|
||||||
|
player: Player
|
||||||
|
) {
|
||||||
|
player.addPotionEffect(
|
||||||
|
PotionEffect(
|
||||||
|
/* type = */ PotionEffectType.SLOWNESS,
|
||||||
|
/* duration = */ 60,
|
||||||
|
/* amplifier = */ 2,
|
||||||
|
/* ambient = */ false,
|
||||||
|
/* particles = */ false,
|
||||||
|
/* icon = */ true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
player.addPotionEffect(
|
||||||
|
PotionEffect(
|
||||||
|
/* type = */ PotionEffectType.GLOWING,
|
||||||
|
/* duration = */ 60,
|
||||||
|
/* amplifier = */ 0,
|
||||||
|
/* ambient = */ false,
|
||||||
|
/* particles = */ false,
|
||||||
|
/* icon = */ false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!player.hasPotionEffect( PotionEffectType.GLOWING ))
|
||||||
|
{
|
||||||
|
player.sendMsg( "antirunner.punish" )
|
||||||
|
player.playSound( player.location, Sound.ENTITY_ZOMBIE_VILLAGER_CURE, 1f, 0.5f )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removePunishment(
|
||||||
|
player: Player
|
||||||
|
) {
|
||||||
|
player.removePotionEffect( PotionEffectType.SLOWNESS )
|
||||||
|
player.removePotionEffect( PotionEffectType.GLOWING )
|
||||||
|
player.hideBossBar( warningBar )
|
||||||
|
|
||||||
|
lastCombatAction[ player.uniqueId ] = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetPlayerTimer(
|
||||||
|
player: Player
|
||||||
|
) {
|
||||||
|
lastCombatAction[ player.uniqueId ] = System.currentTimeMillis()
|
||||||
|
player.hideBossBar( warningBar )
|
||||||
|
|
||||||
|
if (player.hasPotionEffect( PotionEffectType.GLOWING ))
|
||||||
|
removePunishment( player )
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetTimers()
|
||||||
|
{
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers()
|
||||||
|
.filter { it.gameMode == GameMode.SURVIVAL }
|
||||||
|
.forEach {
|
||||||
|
lastCombatAction[ it.uniqueId ] = now
|
||||||
|
it.hideBossBar( warningBar )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityResult
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
|
|
||||||
abstract class AbstractKit(
|
|
||||||
val id: String,
|
|
||||||
val displayName: Component,
|
|
||||||
val description: List<Component>,
|
|
||||||
val icon: Material,
|
|
||||||
val playStyle: PlayStyle,
|
|
||||||
protected val plugin: SpeedHG,
|
|
||||||
protected val abilityContext: AbilityContext,
|
|
||||||
protected val gameManager: GameManager
|
|
||||||
) {
|
|
||||||
|
|
||||||
lateinit var config: Map<String, Double>
|
|
||||||
val items = mutableListOf<ItemStack>()
|
|
||||||
|
|
||||||
abstract fun onSelect( player: Player )
|
|
||||||
|
|
||||||
abstract fun onStart( player: Player )
|
|
||||||
|
|
||||||
abstract fun onHit( attacker: Player, victim: Player, event: EntityDamageByEntityEvent )
|
|
||||||
|
|
||||||
abstract fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent )
|
|
||||||
|
|
||||||
abstract fun onInteract( player: Player, event: PlayerInteractEvent )
|
|
||||||
|
|
||||||
abstract fun onMove( player: Player, event: PlayerMoveEvent )
|
|
||||||
|
|
||||||
open fun cleanup(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
abilityContext.clearPlayerData( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun hasCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
return abilityContext.getRemainingCooldown( player, key ) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun startCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String,
|
|
||||||
seconds: Int
|
|
||||||
) {
|
|
||||||
abilityContext.cooldownManager.startCooldown( player, key, seconds )
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun getRemainingCooldown(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Double
|
|
||||||
{
|
|
||||||
return abilityContext.getRemainingCooldown( player, key )
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun getHits(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
): Int
|
|
||||||
{
|
|
||||||
return abilityContext.getHits(player, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun resetHits(
|
|
||||||
player: Player,
|
|
||||||
key: String
|
|
||||||
) {
|
|
||||||
abilityContext.hitCounterManager.resetHits( player, key )
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun abilityResult(
|
|
||||||
player: Player,
|
|
||||||
abilityKey: String,
|
|
||||||
requiredHits: Int? = null,
|
|
||||||
cooldownSeconds: Int? = null
|
|
||||||
): AbilityResult {
|
|
||||||
return abilityContext.canUseAbility( player, abilityKey, requiredHits, cooldownSeconds )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class PlayStyle {
|
|
||||||
OFFENSIVE, DEFENSIVE
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class KitMetaData {
|
|
||||||
IN_GLADIATOR,
|
|
||||||
GLADIATOR_BLOCK,
|
|
||||||
IS_ANVIL,
|
|
||||||
IS_BLACK_PANTHER,
|
|
||||||
BP_EXTRA_DAMAGE,
|
|
||||||
VOODOO_HOLD,
|
|
||||||
ICEMAGE_SNOWBALL,
|
|
||||||
ICEMAGE_SPEED;
|
|
||||||
|
|
||||||
fun getKey(): String
|
|
||||||
{
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit
|
|
||||||
|
|
||||||
import org.bukkit.inventory.Inventory
|
|
||||||
import org.bukkit.inventory.InventoryHolder
|
|
||||||
|
|
||||||
class KitInventoryHolder(
|
|
||||||
val page: Int
|
|
||||||
) : InventoryHolder {
|
|
||||||
|
|
||||||
private lateinit var inventory: Inventory
|
|
||||||
|
|
||||||
override fun getInventory(): Inventory = inventory
|
|
||||||
|
|
||||||
fun setInventory(
|
|
||||||
inventory: Inventory
|
|
||||||
) {
|
|
||||||
this.inventory = inventory
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.SpeedHG.Companion.content
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.Sound
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
|
||||||
import org.bukkit.event.inventory.InventoryDragEvent
|
|
||||||
|
|
||||||
class KitInventoryListener(
|
|
||||||
private val plugin: SpeedHG,
|
|
||||||
private val kitManager: KitManager,
|
|
||||||
private val kitInventoryManager: KitInventoryManager
|
|
||||||
) : Listener {
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInventoryClick(
|
|
||||||
event: InventoryClickEvent
|
|
||||||
) {
|
|
||||||
val holder = event.inventory.holder
|
|
||||||
|
|
||||||
if ( holder !is KitInventoryHolder )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
|
|
||||||
val player = event.whoClicked as? Player ?: return
|
|
||||||
val clickedItem = event.currentItem ?: return
|
|
||||||
|
|
||||||
if ( clickedItem.type == Material.AIR )
|
|
||||||
return
|
|
||||||
|
|
||||||
when( event.rawSlot )
|
|
||||||
{
|
|
||||||
45 -> {
|
|
||||||
if ( holder.page > 1 )
|
|
||||||
{
|
|
||||||
player.playSound( player.location, Sound.UI_BUTTON_CLICK, 1f, 1f )
|
|
||||||
kitInventoryManager.openKitInventory( player, holder.page - 1 )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
49 -> {
|
|
||||||
player.playSound( player.location, Sound.UI_BUTTON_CLICK, 1f, 0.8f )
|
|
||||||
player.closeInventory()
|
|
||||||
}
|
|
||||||
53 -> {
|
|
||||||
val totalKits = kitManager.getAllKits().size
|
|
||||||
val totalPages = ( totalKits + 27 ) / 28
|
|
||||||
if ( holder.page < totalPages )
|
|
||||||
{
|
|
||||||
player.playSound( player.location, Sound.UI_BUTTON_CLICK, 1f, 1f )
|
|
||||||
kitInventoryManager.openKitInventory( player, holder.page + 1 )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in 10..43 -> {
|
|
||||||
val allKits = kitManager.getAllKits().toList()
|
|
||||||
val startIndex = ( holder.page - 1 ) * 28
|
|
||||||
val endIndex = ( startIndex + 28 ).coerceAtMost( allKits.size )
|
|
||||||
val kitsOnPage = allKits.subList( startIndex, endIndex )
|
|
||||||
|
|
||||||
val kitSlots = listOf(
|
|
||||||
10, 11, 12, 13, 14, 15, 16,
|
|
||||||
19, 20, 21, 22, 23, 24, 25,
|
|
||||||
28, 29, 30, 31, 32, 33, 34,
|
|
||||||
37, 38, 39, 40, 41, 42, 43
|
|
||||||
)
|
|
||||||
|
|
||||||
val slotIndex = kitSlots.indexOf( event.rawSlot )
|
|
||||||
if ( slotIndex != -1 && slotIndex < kitsOnPage.size )
|
|
||||||
{
|
|
||||||
val selectedKit = kitsOnPage[slotIndex]
|
|
||||||
|
|
||||||
if (kitManager.selectKit( player, selectedKit.id ))
|
|
||||||
{
|
|
||||||
player.playSound( player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1.2f )
|
|
||||||
plugin.chatManager.sendMessage(
|
|
||||||
player,
|
|
||||||
"kits.selected",
|
|
||||||
"{kit}" to selectedKit.displayName.content()
|
|
||||||
)
|
|
||||||
kitInventoryManager.openKitInventory( player, holder.page )
|
|
||||||
} else {
|
|
||||||
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInventoryDrag(
|
|
||||||
event: InventoryDragEvent
|
|
||||||
) {
|
|
||||||
val holder = event.inventory.holder
|
|
||||||
|
|
||||||
if ( holder is KitInventoryHolder )
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor
|
|
||||||
import net.kyori.adventure.text.format.TextDecoration
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.enchantments.Enchantment
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.inventory.ItemFlag
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
|
|
||||||
class KitInventoryManager(
|
|
||||||
private val plugin: SpeedHG,
|
|
||||||
private val kitManager: KitManager
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val kitsPerPage = 28
|
|
||||||
private val rows = 6
|
|
||||||
|
|
||||||
fun openKitInventory(
|
|
||||||
player: Player,
|
|
||||||
page: Int = 1
|
|
||||||
) {
|
|
||||||
val allKits = kitManager.getAllKits().toList()
|
|
||||||
val totalPages = ( allKits.size + kitsPerPage - 1 ) / kitsPerPage
|
|
||||||
val validPage = page.coerceIn( 1, totalPages.coerceAtLeast( 1 ))
|
|
||||||
|
|
||||||
val holder = KitInventoryHolder( validPage )
|
|
||||||
val title = Component.text("Kits - Page $validPage/$totalPages")
|
|
||||||
.color( NamedTextColor.DARK_PURPLE )
|
|
||||||
.decoration( TextDecoration.BOLD, true )
|
|
||||||
|
|
||||||
val inventory = Bukkit.createInventory( holder, rows * 9, title )
|
|
||||||
holder.setInventory( inventory )
|
|
||||||
|
|
||||||
fillBorder( inventory )
|
|
||||||
fillKits( inventory, allKits, validPage, player )
|
|
||||||
fillNavigationItems( inventory, validPage, totalPages )
|
|
||||||
|
|
||||||
player.openInventory( inventory )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fillBorder(
|
|
||||||
inventory: org.bukkit.inventory.Inventory
|
|
||||||
) {
|
|
||||||
val borderItem = createBorderItem()
|
|
||||||
|
|
||||||
for ( i in 0..8 )
|
|
||||||
inventory.setItem( i, borderItem )
|
|
||||||
|
|
||||||
for ( i in 45..53 )
|
|
||||||
inventory.setItem( i, borderItem )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fillKits(
|
|
||||||
inventory: org.bukkit.inventory.Inventory,
|
|
||||||
allKits: List<AbstractKit>,
|
|
||||||
page: Int,
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
val startIndex = ( page - 1 ) * kitsPerPage
|
|
||||||
val endIndex = ( startIndex + kitsPerPage ).coerceAtMost( allKits.size )
|
|
||||||
val kitsOnPage = allKits.subList( startIndex, endIndex )
|
|
||||||
|
|
||||||
val selectedKit = kitManager.getSelectedKit( player )
|
|
||||||
|
|
||||||
val kitSlots = listOf(
|
|
||||||
10, 11, 12, 13, 14, 15, 16,
|
|
||||||
19, 20, 21, 22, 23, 24, 25,
|
|
||||||
28, 29, 30, 31, 32, 33, 34,
|
|
||||||
37, 38, 39, 40, 41, 42, 43
|
|
||||||
)
|
|
||||||
|
|
||||||
kitsOnPage.forEachIndexed { index, kit ->
|
|
||||||
if ( index < kitSlots.size )
|
|
||||||
{
|
|
||||||
val isSelected = selectedKit?.id == kit.id
|
|
||||||
val kitItem = createKitItem( kit, isSelected, player )
|
|
||||||
inventory.setItem(kitSlots[ index ], kitItem )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fillNavigationItems(
|
|
||||||
inventory: org.bukkit.inventory.Inventory,
|
|
||||||
page: Int,
|
|
||||||
totalPages: Int
|
|
||||||
) {
|
|
||||||
if ( page > 1 )
|
|
||||||
inventory.setItem( 45, createPreviousPageItem() )
|
|
||||||
|
|
||||||
inventory.setItem( 49, createCloseItem() )
|
|
||||||
|
|
||||||
if ( page < totalPages )
|
|
||||||
inventory.setItem( 53, createNextPageItem() )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createBorderItem(): ItemStack
|
|
||||||
{
|
|
||||||
val item = ItemStack( Material.GRAY_STAINED_GLASS_PANE )
|
|
||||||
val meta = item.itemMeta
|
|
||||||
meta.displayName(Component.text( " " ))
|
|
||||||
item.itemMeta = meta
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createKitItem(
|
|
||||||
kit: AbstractKit,
|
|
||||||
isSelected: Boolean,
|
|
||||||
player: Player
|
|
||||||
): ItemStack
|
|
||||||
{
|
|
||||||
val item = ItemStack( kit.icon )
|
|
||||||
val meta = item.itemMeta
|
|
||||||
|
|
||||||
meta.displayName(kit.displayName.decoration( TextDecoration.ITALIC, false ))
|
|
||||||
|
|
||||||
val lore = mutableListOf<Component>()
|
|
||||||
|
|
||||||
if ( isSelected ) {
|
|
||||||
lore.add(
|
|
||||||
Component.text("✔ Currently Selected")
|
|
||||||
.color( NamedTextColor.GREEN )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
lore.add(
|
|
||||||
Component.text("Click to select")
|
|
||||||
.color( NamedTextColor.YELLOW )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
lore.add( Component.empty() )
|
|
||||||
|
|
||||||
kit.description.forEach { line ->
|
|
||||||
lore.add(
|
|
||||||
line.color( NamedTextColor.GRAY )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canUseKit( player, kit )) {
|
|
||||||
if ( isSelected )
|
|
||||||
{
|
|
||||||
meta.addEnchant( Enchantment.UNBREAKING, 1, true )
|
|
||||||
meta.addItemFlags( ItemFlag.HIDE_ENCHANTS )
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lore.add( Component.empty() )
|
|
||||||
lore.add(
|
|
||||||
Component.text("⚠ Locked")
|
|
||||||
.color( NamedTextColor.RED )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
.decoration( TextDecoration.BOLD, true )
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
meta.lore( lore )
|
|
||||||
meta.addItemFlags( ItemFlag.HIDE_ATTRIBUTES )
|
|
||||||
item.itemMeta = meta
|
|
||||||
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createPreviousPageItem(): ItemStack
|
|
||||||
{
|
|
||||||
val item = ItemStack( Material.ARROW )
|
|
||||||
val meta = item.itemMeta
|
|
||||||
meta.displayName(
|
|
||||||
Component.text("← Previous Page")
|
|
||||||
.color( NamedTextColor.YELLOW )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
)
|
|
||||||
item.itemMeta = meta
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createNextPageItem(): ItemStack
|
|
||||||
{
|
|
||||||
val item = ItemStack( Material.ARROW )
|
|
||||||
val meta = item.itemMeta
|
|
||||||
meta.displayName(
|
|
||||||
Component.text("Next Page →")
|
|
||||||
.color( NamedTextColor.YELLOW )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
)
|
|
||||||
item.itemMeta = meta
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createCloseItem(): ItemStack
|
|
||||||
{
|
|
||||||
val item = ItemStack( Material.BARRIER )
|
|
||||||
val meta = item.itemMeta
|
|
||||||
meta.displayName(
|
|
||||||
Component.text("Close")
|
|
||||||
.color( NamedTextColor.RED )
|
|
||||||
.decoration( TextDecoration.ITALIC, false )
|
|
||||||
)
|
|
||||||
item.itemMeta = meta
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canUseKit(
|
|
||||||
player: Player,
|
|
||||||
kit: AbstractKit
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
val unlockedKits = mutableListOf<String>()
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
val kitPlayer = plugin.playerRepository.findByUuid( player.uniqueId )
|
|
||||||
if ( kitPlayer != null ) unlockedKits.addAll( kitPlayer.unlockedKits )
|
|
||||||
}
|
|
||||||
|
|
||||||
return unlockedKits.contains( kit.id )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.Sound
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.block.BlockBreakEvent
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
|
|
||||||
class KitListener(
|
|
||||||
private val plugin: SpeedHG,
|
|
||||||
private val kitManager: KitManager
|
|
||||||
) : Listener {
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onDamage(
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
val attacker = event.damager as? Player ?: return
|
|
||||||
val victim = event.entity as? Player ?: return
|
|
||||||
|
|
||||||
if (kitManager.getSelectedKit( attacker ) != null )
|
|
||||||
kitManager.triggerHit( attacker, victim, event )
|
|
||||||
|
|
||||||
if (kitManager.getSelectedKit( victim ) != null )
|
|
||||||
kitManager.triggerDamaged( victim, attacker, event )
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerInteract(
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
val player = event.player
|
|
||||||
|
|
||||||
if (kitManager.getSelectedKit( player ) != null )
|
|
||||||
kitManager.triggerInteract( player, event )
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerMove(
|
|
||||||
event: PlayerMoveEvent
|
|
||||||
) {
|
|
||||||
val player = event.player
|
|
||||||
|
|
||||||
if (kitManager.getSelectedKit( player ) != null )
|
|
||||||
kitManager.triggerMove( player, event )
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onAnvilBreak(
|
|
||||||
event: BlockBreakEvent
|
|
||||||
) {
|
|
||||||
if ( !plugin.gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val block = event.block
|
|
||||||
|
|
||||||
if ( block.type != Material.ANVIL ||
|
|
||||||
!block.hasMetadata( KitMetaData.IS_ANVIL.getKey() ))
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
|
|
||||||
block.type = Material.AIR
|
|
||||||
block.removeMetadata( KitMetaData.IS_ANVIL.getKey(), plugin )
|
|
||||||
|
|
||||||
block.world.playSound( block.location, Sound.ENTITY_IRON_GOLEM_DEATH, 3f, 3f )
|
|
||||||
plugin.chatManager.broadcast( "kits.anchor.messages.broken" )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.kit.impl.AnchorKit
|
|
||||||
import club.mcscrims.speedhg.kit.impl.ArmorerKit
|
|
||||||
import club.mcscrims.speedhg.kit.impl.BlackPantherKit
|
|
||||||
import club.mcscrims.speedhg.kit.impl.BlitzcrankKit
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
import java.util.UUID
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
class KitManager(
|
|
||||||
private val plugin: SpeedHG
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val kits = ConcurrentHashMap<String, AbstractKit>()
|
|
||||||
private val selectedKits = ConcurrentHashMap<UUID, AbstractKit>()
|
|
||||||
|
|
||||||
fun initialize()
|
|
||||||
{
|
|
||||||
registerKit(
|
|
||||||
kitClass = AnchorKit::class.java,
|
|
||||||
id = "anchor",
|
|
||||||
displayName = plugin.chatFormatter.format( "kits.anchor.displayName" ),
|
|
||||||
description = plugin.chatFormatter.formatList( "kits.anchor.lore" ),
|
|
||||||
icon = Material.ANVIL
|
|
||||||
)
|
|
||||||
|
|
||||||
registerKit(
|
|
||||||
kitClass = ArmorerKit::class.java,
|
|
||||||
id = "armorer",
|
|
||||||
displayName = plugin.chatFormatter.format( "kits.armorer.displayName" ),
|
|
||||||
description = plugin.chatFormatter.formatList( "kits.armorer.lore" ),
|
|
||||||
icon = Material.IRON_CHESTPLATE
|
|
||||||
)
|
|
||||||
|
|
||||||
registerKit(
|
|
||||||
kitClass = BlackPantherKit::class.java,
|
|
||||||
id = "blackpanther",
|
|
||||||
displayName = plugin.chatFormatter.format( "kits.blackpanther.displayName" ),
|
|
||||||
description = plugin.chatFormatter.formatList( "kits.blackpanther.lore" ),
|
|
||||||
icon = Material.DRAGON_EGG
|
|
||||||
)
|
|
||||||
|
|
||||||
registerKit(
|
|
||||||
kitClass = BlitzcrankKit::class.java,
|
|
||||||
id = "blitzcrank",
|
|
||||||
displayName = plugin.chatFormatter.format( "kits.blitzcrank.displayName" ),
|
|
||||||
description = plugin.chatFormatter.formatList( "kits.blitzcrank.lore" ),
|
|
||||||
icon = Material.FISHING_ROD
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun registerKit(
|
|
||||||
kitClass: Class<out AbstractKit>,
|
|
||||||
id: String,
|
|
||||||
displayName: Component,
|
|
||||||
description: List<Component>,
|
|
||||||
icon: Material
|
|
||||||
) {
|
|
||||||
val constructor = kitClass.getDeclaredConstructor(
|
|
||||||
String::class.java,
|
|
||||||
Component::class.java,
|
|
||||||
List::class.java,
|
|
||||||
Material::class.java,
|
|
||||||
PlayStyle::class.java,
|
|
||||||
SpeedHG::class.java,
|
|
||||||
AbilityContext::class.java,
|
|
||||||
GameManager::class.java
|
|
||||||
)
|
|
||||||
|
|
||||||
val kit = constructor.newInstance(
|
|
||||||
id,
|
|
||||||
displayName,
|
|
||||||
description,
|
|
||||||
icon,
|
|
||||||
PlayStyle.DEFENSIVE,
|
|
||||||
plugin,
|
|
||||||
plugin.abilityContext,
|
|
||||||
plugin.gameManager
|
|
||||||
)
|
|
||||||
|
|
||||||
kit.config = plugin.kitConfig.data.getConfigForKit( kit.id )
|
|
||||||
kits[kit.id.lowercase()] = kit
|
|
||||||
plugin.logger.info("Registered kit: ${kit.displayName} (${kit.id})")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getKit(
|
|
||||||
id: String
|
|
||||||
): AbstractKit?
|
|
||||||
{
|
|
||||||
return kits[id.lowercase()]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAllKits(): Collection<AbstractKit>
|
|
||||||
{
|
|
||||||
return kits.values
|
|
||||||
}
|
|
||||||
|
|
||||||
fun selectKit(
|
|
||||||
player: Player,
|
|
||||||
kitId: String
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
val kit = getKit( kitId ) ?: return false
|
|
||||||
|
|
||||||
val previousKit = selectedKits[player.uniqueId]
|
|
||||||
previousKit?.cleanup( player )
|
|
||||||
|
|
||||||
selectedKits[player.uniqueId] = kit
|
|
||||||
|
|
||||||
try {
|
|
||||||
kit.onSelect( player )
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.severe("Error during onSelect for kit ${kit.id} and player ${player.name}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSelectedKit(
|
|
||||||
player: Player
|
|
||||||
): AbstractKit?
|
|
||||||
{
|
|
||||||
return selectedKits[player.uniqueId]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun startKitForPlayer(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
val kit = selectedKits[player.uniqueId] ?: return
|
|
||||||
|
|
||||||
try {
|
|
||||||
kit.onStart( player )
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.severe("Error during onStart for kit ${kit.id} and player ${player.name}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun triggerHit(
|
|
||||||
attacker: Player,
|
|
||||||
victim: Player,
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
val kit = selectedKits[attacker.uniqueId] ?: return
|
|
||||||
|
|
||||||
try {
|
|
||||||
kit.onHit( attacker, victim, event )
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.severe("Error during onHit for kit ${kit.id} and player ${attacker.name}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun triggerDamaged(
|
|
||||||
attacker: Player,
|
|
||||||
victim: Player,
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
val kit = selectedKits[victim.uniqueId] ?: return
|
|
||||||
|
|
||||||
try {
|
|
||||||
kit.onDamaged( attacker, victim, event )
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.severe("Error during onDamaged for kit ${kit.id} and player ${victim.name}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun triggerInteract(
|
|
||||||
player: Player,
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
val kit = selectedKits[player.uniqueId] ?: return
|
|
||||||
|
|
||||||
try {
|
|
||||||
kit.onInteract( player, event )
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.severe("Error during onInteract for kit ${kit.id} and player ${player.name}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun triggerMove(
|
|
||||||
player: Player,
|
|
||||||
event: PlayerMoveEvent
|
|
||||||
) {
|
|
||||||
val kit = selectedKits[player.uniqueId] ?: return
|
|
||||||
|
|
||||||
try {
|
|
||||||
kit.onMove( player, event )
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.severe("Error during onMove for kit ${kit.id} and player ${player.name}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearPlayerSelection(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
val kit = selectedKits.remove( player.uniqueId )
|
|
||||||
kit?.cleanup( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAll()
|
|
||||||
{
|
|
||||||
selectedKits.values.forEach { kit ->
|
|
||||||
plugin.server.onlinePlayers.forEach { player ->
|
|
||||||
if ( selectedKits[player.uniqueId] == kit ) kit.cleanup( player )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selectedKits.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.SpeedHG.Companion.content
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.kit.AbstractKit
|
|
||||||
import club.mcscrims.speedhg.kit.KitMetaData
|
|
||||||
import club.mcscrims.speedhg.kit.PlayStyle
|
|
||||||
import club.mcscrims.spigot.item.ItemBuilder
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.Location
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.Sound
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.block.Action
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue
|
|
||||||
import java.util.UUID
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
class AnchorKit(
|
|
||||||
id: String,
|
|
||||||
displayName: Component,
|
|
||||||
description: List<Component>,
|
|
||||||
icon: Material,
|
|
||||||
playStyle: PlayStyle,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
abilityContext: AbilityContext,
|
|
||||||
gameManager: GameManager
|
|
||||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
|
||||||
|
|
||||||
private lateinit var anvilItem: ItemStack
|
|
||||||
|
|
||||||
private val extraDamage: Double = plugin.kitConfig.data.anchor[ "offensive extra damage" ]!!
|
|
||||||
|
|
||||||
private val radius = if ( playStyle == PlayStyle.DEFENSIVE ) 7.5 else 5.0
|
|
||||||
private val anvilList = ConcurrentHashMap<UUID, Location>()
|
|
||||||
|
|
||||||
override fun onSelect( player: Player ) {}
|
|
||||||
|
|
||||||
override fun onStart(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
anvilItem = ItemBuilder( plugin, Material.ANVIL )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "anchor", "anvil" )!![ playStyle.name.lowercase() ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
items.add( anvilItem )
|
|
||||||
player.inventory.setItem( 0, anvilItem )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHit(
|
|
||||||
attacker: Player,
|
|
||||||
victim: Player,
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
if (!anvilList.contains( attacker.uniqueId ))
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( playStyle != PlayStyle.OFFENSIVE )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.damage += extraDamage
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDamaged(
|
|
||||||
attacker: Player,
|
|
||||||
victim: Player,
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
if (!anvilList.contains( attacker.uniqueId ))
|
|
||||||
return
|
|
||||||
|
|
||||||
victim.velocity.setX( 0.0 )
|
|
||||||
victim.velocity.setZ( 0.0 )
|
|
||||||
victim.world.playSound( victim.location, Sound.BLOCK_ANVIL_HIT, 3f, 3f )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onInteract(
|
|
||||||
player: Player,
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val action = event.action
|
|
||||||
|
|
||||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
|
||||||
action != Action.RIGHT_CLICK_BLOCK )
|
|
||||||
return
|
|
||||||
|
|
||||||
val item = event.item ?: return
|
|
||||||
|
|
||||||
if ( item != anvilItem )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
|
|
||||||
val eyeLocation = player.eyeLocation
|
|
||||||
|
|
||||||
if (eyeLocation.distance( player.location ) > radius )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.anchor.messages.tooFarAway" )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anvilList.contains( player.uniqueId ))
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.anchor.messages.alreadyActivated" )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = abilityContext.canUseAbility( player, "anchor-anvil", 15 )
|
|
||||||
|
|
||||||
if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val anvilLoc = eyeLocation.toBlockLocation()
|
|
||||||
anvilLoc.add( 0.0, 1.0, 0.0 )
|
|
||||||
|
|
||||||
anvilLoc.block.type = Material.ANVIL
|
|
||||||
anvilLoc.block.setMetadata( KitMetaData.IS_ANVIL.getKey(), FixedMetadataValue( plugin, true ))
|
|
||||||
|
|
||||||
anvilList[ player.uniqueId ]= anvilLoc
|
|
||||||
|
|
||||||
plugin.schedulerManager.runLater( 20 * 30L ) {
|
|
||||||
if (anvilList.contains( player.uniqueId ))
|
|
||||||
{
|
|
||||||
anvilList.remove( player.uniqueId )
|
|
||||||
anvilLoc.block.type = Material.AIR
|
|
||||||
anvilLoc.block.removeMetadata( KitMetaData.IS_ANVIL.getKey(), plugin )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMove(
|
|
||||||
player: Player,
|
|
||||||
event: PlayerMoveEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val anvilLoc = anvilList[ player.uniqueId ]
|
|
||||||
?: return
|
|
||||||
|
|
||||||
if (player.location.distance( anvilLoc ) <= radius )
|
|
||||||
return
|
|
||||||
|
|
||||||
player.teleport( player.location )
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.kit.AbstractKit
|
|
||||||
import club.mcscrims.speedhg.kit.PlayStyle
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.Sound
|
|
||||||
import org.bukkit.Statistic
|
|
||||||
import org.bukkit.enchantments.Enchantment
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class ArmorerKit(
|
|
||||||
id: String,
|
|
||||||
displayName: Component,
|
|
||||||
description: List<Component>,
|
|
||||||
icon: Material,
|
|
||||||
playStyle: PlayStyle,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
abilityContext: AbilityContext,
|
|
||||||
gameManager: GameManager
|
|
||||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
|
||||||
|
|
||||||
private val killsUntilNew: Double = plugin.kitConfig.data.armorer[ "kills until new armor" ]!!
|
|
||||||
|
|
||||||
override fun onSelect( player: Player ) {}
|
|
||||||
|
|
||||||
override fun onStart( player: Player ) {}
|
|
||||||
|
|
||||||
override fun onHit(
|
|
||||||
attacker: Player,
|
|
||||||
victim: Player,
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( victim.health > 0.0 )
|
|
||||||
return
|
|
||||||
|
|
||||||
val kills = attacker.getStatistic( Statistic.PLAYER_KILLS )
|
|
||||||
|
|
||||||
if (( kills.toDouble() / killsUntilNew ) % 2 != 0.0 )
|
|
||||||
return
|
|
||||||
|
|
||||||
upgradeArmor( attacker, kills )
|
|
||||||
attacker.playSound( attacker, Sound.BLOCK_NOTE_BLOCK_PLING, 1f, 1f )
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
|
||||||
|
|
||||||
override fun onInteract( player: Player, event: PlayerInteractEvent ) {}
|
|
||||||
|
|
||||||
override fun onMove( player: Player, event: PlayerMoveEvent ) {}
|
|
||||||
|
|
||||||
private fun upgradeArmor(
|
|
||||||
player: Player,
|
|
||||||
killCount: Int
|
|
||||||
) {
|
|
||||||
val kills = killsUntilNew.roundToInt()
|
|
||||||
|
|
||||||
val armorType = when( killCount / kills )
|
|
||||||
{
|
|
||||||
1, 2 -> ArmorType.LEATHER
|
|
||||||
3, 4 -> ArmorType.CHAINMAIL
|
|
||||||
5, 6 -> ArmorType.GOLD
|
|
||||||
7, 8 -> ArmorType.IRON
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
|
|
||||||
val enchanted = ( killCount / kills ) % 2 == 0
|
|
||||||
|
|
||||||
val armor = createArmor( armorType, enchanted )
|
|
||||||
player.inventory.armorContents = arrayOf( null, armor[0], null, armor[1] )
|
|
||||||
|
|
||||||
if ( !enchanted )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.armorer.messages.upgrade.normal", "{armorType}" to armorType.name )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.armorer.upgrade.enchanted" )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createArmor(
|
|
||||||
type: ArmorType,
|
|
||||||
enchanted: Boolean
|
|
||||||
) = listOf(
|
|
||||||
ItemStack( type.materialChestplate ).apply {
|
|
||||||
if ( enchanted ) addEnchantment( Enchantment.PROTECTION, 1 )
|
|
||||||
},
|
|
||||||
ItemStack( type.materialBoots ).apply {
|
|
||||||
if ( enchanted ) addEnchantment( Enchantment.PROTECTION, 1 )
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
enum class ArmorType(
|
|
||||||
val materialChestplate: Material,
|
|
||||||
val materialBoots: Material
|
|
||||||
) {
|
|
||||||
LEATHER( Material.LEATHER_CHESTPLATE, Material.LEATHER_BOOTS ),
|
|
||||||
CHAINMAIL( Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_BOOTS ),
|
|
||||||
GOLD( Material.GOLDEN_CHESTPLATE, Material.GOLDEN_BOOTS ),
|
|
||||||
IRON( Material.IRON_CHESTPLATE, Material.IRON_BOOTS )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,276 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.kit.AbstractKit
|
|
||||||
import club.mcscrims.speedhg.kit.KitMetaData
|
|
||||||
import club.mcscrims.speedhg.kit.PlayStyle
|
|
||||||
import club.mcscrims.spigot.item.ItemBuilder
|
|
||||||
import club.mcscrims.spigot.util.GroundDetector
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.GameMode
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.Particle
|
|
||||||
import org.bukkit.entity.EnderPearl
|
|
||||||
import org.bukkit.entity.EntityType
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.block.Action
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue
|
|
||||||
import org.bukkit.potion.PotionEffect
|
|
||||||
import org.bukkit.potion.PotionEffectType
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable
|
|
||||||
import org.bukkit.util.Vector
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class BlackPantherKit(
|
|
||||||
id: String,
|
|
||||||
displayName: Component,
|
|
||||||
description: List<Component>,
|
|
||||||
icon: Material,
|
|
||||||
playStyle: PlayStyle,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
abilityContext: AbilityContext,
|
|
||||||
gameManager: GameManager
|
|
||||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
|
||||||
|
|
||||||
private lateinit var blackDye: ItemStack
|
|
||||||
private lateinit var blazePowder: ItemStack
|
|
||||||
|
|
||||||
private val extraDamageAddition = plugin.kitConfig.data.blackPanther[ "extra damage on top" ]!!
|
|
||||||
private val defaultRadius = plugin.kitConfig.data.blackPanther[ "default hit radius" ]!!
|
|
||||||
private val explosionMultiplier = plugin.kitConfig.data.blackPanther[ "explosion multiplier" ]!!
|
|
||||||
|
|
||||||
override fun onSelect( player: Player ) {}
|
|
||||||
|
|
||||||
override fun onStart(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
when( playStyle )
|
|
||||||
{
|
|
||||||
PlayStyle.DEFENSIVE ->
|
|
||||||
{
|
|
||||||
blackDye = ItemBuilder( plugin, Material.BLACK_DYE )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "blackpanther", "blackDye" )!![ "null" ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
items.add( blackDye )
|
|
||||||
player.inventory.setItem( 0, blackDye )
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayStyle.OFFENSIVE ->
|
|
||||||
{
|
|
||||||
blackDye = ItemBuilder( plugin, Material.BLACK_DYE )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "blackpanther", "blackDye" )!![ playStyle.name.lowercase() ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
blazePowder = ItemBuilder( plugin, Material.BLAZE_POWDER )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "blackpanther", "blazePowder" )!![ playStyle.name.lowercase() ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
items.addAll(listOf( blackDye, blazePowder ))
|
|
||||||
player.inventory.setItem( 0, blackDye )
|
|
||||||
player.inventory.setItem( 1, blazePowder )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHit(
|
|
||||||
attacker: Player,
|
|
||||||
victim: Player,
|
|
||||||
event: EntityDamageByEntityEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
if (!attacker.hasMetadata( KitMetaData.BP_EXTRA_DAMAGE.getKey() ))
|
|
||||||
return
|
|
||||||
|
|
||||||
event.damage += extraDamageAddition
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
|
||||||
|
|
||||||
override fun onInteract(
|
|
||||||
player: Player,
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val action = event.action
|
|
||||||
|
|
||||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
|
||||||
action != Action.RIGHT_CLICK_BLOCK )
|
|
||||||
return
|
|
||||||
|
|
||||||
val item = event.item ?: return
|
|
||||||
|
|
||||||
if ( item != blackDye &&
|
|
||||||
item != blazePowder )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
|
|
||||||
when( item.type )
|
|
||||||
{
|
|
||||||
Material.BLACK_DYE ->
|
|
||||||
{
|
|
||||||
val result = abilityContext.canUseAbility( player, "blackDye-blackPanther", 15 )
|
|
||||||
|
|
||||||
if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( playStyle == PlayStyle.DEFENSIVE )
|
|
||||||
{
|
|
||||||
launchAndDash( player )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
push( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
Material.BLAZE_POWDER ->
|
|
||||||
{
|
|
||||||
val result = abilityContext.canUseAbility( player, "blazePowder-blackPanther", 15 )
|
|
||||||
|
|
||||||
if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
extraDamage( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMove( player: Player, event: PlayerMoveEvent ) {}
|
|
||||||
|
|
||||||
private fun push(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
plugin.getAlivePlayers().stream()
|
|
||||||
.filter { it != player }
|
|
||||||
.filter { it.location.distance( player.location ) <= defaultRadius }
|
|
||||||
.forEach { nearby ->
|
|
||||||
val pushDirection = nearby.location.toVector().subtract( player.location.toVector() ).normalize()
|
|
||||||
pushDirection.multiply( 1.0 )
|
|
||||||
pushDirection.setY( 0.5 )
|
|
||||||
nearby.velocity = pushDirection
|
|
||||||
|
|
||||||
val enderPearl = player.world.spawnEntity( player.location, EntityType.ENDER_PEARL ) as EnderPearl
|
|
||||||
enderPearl.velocity = pushDirection
|
|
||||||
enderPearl.setMetadata( KitMetaData.IS_BLACK_PANTHER.getKey(), FixedMetadataValue( plugin, true ))
|
|
||||||
|
|
||||||
object : BukkitRunnable()
|
|
||||||
{
|
|
||||||
|
|
||||||
override fun run()
|
|
||||||
{
|
|
||||||
if (GroundDetector.isOnGround( nearby ))
|
|
||||||
{
|
|
||||||
this.cancel()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nearby.world.spawnParticle( Particle.END_ROD, nearby.location, 5, 0.2, 0.2, 0.2 )
|
|
||||||
}
|
|
||||||
|
|
||||||
}.runTaskTimer( plugin, 0L, 2L )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launchAndDash(
|
|
||||||
player: Player,
|
|
||||||
upwardVelocity: Double = 2.2,
|
|
||||||
waitTicks: Long = 60L,
|
|
||||||
dashSpeed: Double = 2.8,
|
|
||||||
horizontalOnly: Boolean = true,
|
|
||||||
yBoost: Double = 0.2,
|
|
||||||
noFallDamageMillis: Double = 1.0
|
|
||||||
) {
|
|
||||||
if ( !player.isOnline ) return
|
|
||||||
if ( player.isInsideVehicle ) player.leaveVehicle()
|
|
||||||
if ( player.gameMode == GameMode.SPECTATOR ) return
|
|
||||||
|
|
||||||
player.velocity = Vector( 0.0, upwardVelocity, 0.0 )
|
|
||||||
player.fallDistance = 0f
|
|
||||||
|
|
||||||
if ( noFallDamageMillis > 0 )
|
|
||||||
player.addPotionEffect(PotionEffect( PotionEffectType.RESISTANCE, ( noFallDamageMillis * 20 ).toInt(), 999, false, false, false ))
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskLater( plugin, { ->
|
|
||||||
val p = Bukkit.getPlayer( player.uniqueId ) ?: return@runTaskLater
|
|
||||||
if ( !p.isOnline ) return@runTaskLater
|
|
||||||
|
|
||||||
var dir = p.eyeLocation.direction
|
|
||||||
if ( horizontalOnly ) dir = Vector( dir.x, 0.0, dir.z )
|
|
||||||
dir = if ( dir.lengthSquared() < 1e-6 ) Vector( 0, 0, 0 ) else dir.normalize()
|
|
||||||
|
|
||||||
val dash = dir.multiply( dashSpeed ).add(Vector( 0.0, yBoost, 0.0 ))
|
|
||||||
p.velocity = dash
|
|
||||||
}, max( 0L, waitTicks ))
|
|
||||||
|
|
||||||
object : BukkitRunnable()
|
|
||||||
{
|
|
||||||
|
|
||||||
override fun run()
|
|
||||||
{
|
|
||||||
if (GroundDetector.isOnGround( player ))
|
|
||||||
{
|
|
||||||
player.world.createExplosion(
|
|
||||||
player.location,
|
|
||||||
explosionMultiplier.roundToInt().toFloat(),
|
|
||||||
false, true
|
|
||||||
)
|
|
||||||
|
|
||||||
val alivePlayers = plugin.getAlivePlayers().stream()
|
|
||||||
.filter { it != player }
|
|
||||||
.filter { it.location.distance( player.location ) <= defaultRadius }
|
|
||||||
.toList()
|
|
||||||
|
|
||||||
alivePlayers.forEach { nearby ->
|
|
||||||
nearby.damage( 6.0, player )
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blackPanther.messages.wakandaForever.hit", "{hit}" to alivePlayers.size.toString() )
|
|
||||||
this.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}.runTaskTimer( plugin, max( 0L, waitTicks ) + 5L, 5L )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extraDamage(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
player.setMetadata( KitMetaData.BP_EXTRA_DAMAGE.getKey(), FixedMetadataValue( plugin, true ))
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blackPanther.messages.extraDamage.activated" )
|
|
||||||
|
|
||||||
plugin.schedulerManager.runLater( 12 * 30L ) {
|
|
||||||
|
|
||||||
player.removeMetadata( KitMetaData.BP_EXTRA_DAMAGE.getKey(), plugin )
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blackPanther.messages.extraDamage.deactivated" )
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.kit.impl
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.SpeedHG.Companion.content
|
|
||||||
import club.mcscrims.speedhg.ability.AbilityContext
|
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
|
||||||
import club.mcscrims.speedhg.kit.AbstractKit
|
|
||||||
import club.mcscrims.speedhg.kit.PlayStyle
|
|
||||||
import club.mcscrims.speedhg.util.DirectionUtil
|
|
||||||
import club.mcscrims.spigot.chat.getDisplayName
|
|
||||||
import club.mcscrims.spigot.item.ItemBuilder
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.block.Action
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.potion.PotionEffect
|
|
||||||
import org.bukkit.potion.PotionEffectType
|
|
||||||
import org.bukkit.util.Vector
|
|
||||||
|
|
||||||
class BlitzcrankKit(
|
|
||||||
id: String,
|
|
||||||
displayName: Component,
|
|
||||||
description: List<Component>,
|
|
||||||
icon: Material,
|
|
||||||
playStyle: PlayStyle,
|
|
||||||
plugin: SpeedHG,
|
|
||||||
abilityContext: AbilityContext,
|
|
||||||
gameManager: GameManager
|
|
||||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
|
||||||
|
|
||||||
override fun onSelect( player: Player ) {}
|
|
||||||
|
|
||||||
private lateinit var hotsItem: ItemStack
|
|
||||||
private lateinit var fishingRodItem: ItemStack
|
|
||||||
private lateinit var pufferfishItem: ItemStack
|
|
||||||
|
|
||||||
override fun onStart(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
hotsItem = ItemBuilder( plugin, Material.HEART_OF_THE_SEA )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "blitzcrank", "hots" )!![ playStyle.name.lowercase() ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
items.add( hotsItem )
|
|
||||||
player.inventory.setItem( 0, hotsItem )
|
|
||||||
|
|
||||||
when( playStyle )
|
|
||||||
{
|
|
||||||
PlayStyle.DEFENSIVE ->
|
|
||||||
{
|
|
||||||
fishingRodItem = ItemBuilder( plugin, Material.FISHING_ROD )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "blitzcrank", "fishingrod" )!![ playStyle.name.lowercase() ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
items.add( fishingRodItem )
|
|
||||||
player.inventory.setItem( 1, fishingRodItem )
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayStyle.OFFENSIVE ->
|
|
||||||
{
|
|
||||||
pufferfishItem = ItemBuilder( plugin, Material.PUFFERFISH )
|
|
||||||
.name(plugin.messageConfig.data.getKitItemNames( "blitzcrank", "pufferfish" )!![ playStyle.name.lowercase() ]!!)
|
|
||||||
.unbreakable( true )
|
|
||||||
.hideAttributes()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
items.add( pufferfishItem )
|
|
||||||
player.inventory.setItem( 1, pufferfishItem )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHit( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
|
||||||
|
|
||||||
override fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
|
||||||
|
|
||||||
// Ultimate
|
|
||||||
private val ultimateDamage = plugin.kitConfig.data.blitzcrank[ "ultimate damage" ]!!
|
|
||||||
private val ultimateRadius = plugin.kitConfig.data.blitzcrank[ "ultimate radius" ]!!
|
|
||||||
private val ultimateStunDuration = plugin.kitConfig.data.blitzcrank[ "ultimate stun duration" ]!!
|
|
||||||
|
|
||||||
// Hook
|
|
||||||
private val hookRange = plugin.kitConfig.data.blitzcrank[ "hook range" ]!!
|
|
||||||
|
|
||||||
// Stun
|
|
||||||
private val stunHeight = plugin.kitConfig.data.blitzcrank[ "stun height" ]!!
|
|
||||||
private val stunRadius = plugin.kitConfig.data.blitzcrank[ "stun radius" ]!!
|
|
||||||
private val stunSlowDuration = plugin.kitConfig.data.blitzcrank[ "stun slow duration" ]!!
|
|
||||||
|
|
||||||
override fun onInteract(
|
|
||||||
player: Player,
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val action = event.action
|
|
||||||
|
|
||||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
|
||||||
action != Action.RIGHT_CLICK_BLOCK )
|
|
||||||
return
|
|
||||||
|
|
||||||
val item = event.item ?: return
|
|
||||||
|
|
||||||
if ( item != hotsItem &&
|
|
||||||
item != fishingRodItem &&
|
|
||||||
item != pufferfishItem )
|
|
||||||
return
|
|
||||||
|
|
||||||
when( item.type )
|
|
||||||
{
|
|
||||||
Material.HEART_OF_THE_SEA ->
|
|
||||||
{
|
|
||||||
val result = abilityContext.canUseAbility( player, "hots-blitzcrank", 15 )
|
|
||||||
|
|
||||||
if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ultimate( player, ultimateRadius )
|
|
||||||
}
|
|
||||||
|
|
||||||
Material.FISHING_ROD ->
|
|
||||||
{
|
|
||||||
val result = abilityContext.canUseAbility( player, "hook-blitzcrank", 15 )
|
|
||||||
|
|
||||||
if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hookPlayer( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
Material.PUFFERFISH ->
|
|
||||||
{
|
|
||||||
val result = abilityContext.canUseAbility( player, "stun-blitzcrank", 15 )
|
|
||||||
|
|
||||||
if ( result.missingHits > 0 )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stunNearby( player, stunRadius )
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMove( player: Player, event: PlayerMoveEvent ) {}
|
|
||||||
|
|
||||||
private fun ultimate(
|
|
||||||
player: Player,
|
|
||||||
radius: Double
|
|
||||||
) {
|
|
||||||
val nearbyPlayers = player.world.getNearbyPlayers( player.location, radius )
|
|
||||||
|
|
||||||
nearbyPlayers.forEach { nearby ->
|
|
||||||
|
|
||||||
nearby.damage( ultimateDamage, player )
|
|
||||||
|
|
||||||
nearby.addPotionEffect(PotionEffect(
|
|
||||||
PotionEffectType.SLOWNESS,
|
|
||||||
ultimateStunDuration.toInt() * 20,
|
|
||||||
255,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
))
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( nearby, "kits.blitzcrank.messages.ultimate.target", "{player}" to player.getDisplayName )
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.ultimate.player", "{nearby}" to nearbyPlayers.size.toString() )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hookPlayer(
|
|
||||||
player: Player
|
|
||||||
) {
|
|
||||||
val target = DirectionUtil.getTargetPlayerInLineOfSight( player, hookRange, 0.5 )
|
|
||||||
|
|
||||||
if ( target == null )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.no_player_in_sight" )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val hookDirection = target.location.toVector().add( player.location.toVector() ).normalize()
|
|
||||||
hookDirection.multiply( 1.0 )
|
|
||||||
hookDirection.setY( 0.5 )
|
|
||||||
target.velocity = hookDirection
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.hook.player", "{player}" to target.getDisplayName )
|
|
||||||
plugin.chatManager.sendMessage( target, "kits.blitzcrank.messages.hook.target" )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun stunNearby(
|
|
||||||
player: Player,
|
|
||||||
radius: Double
|
|
||||||
) {
|
|
||||||
val nearbyPlayers = player.world.getNearbyPlayers( player.location, radius )
|
|
||||||
|
|
||||||
nearbyPlayers.forEach { nearby ->
|
|
||||||
|
|
||||||
val velocity = nearby.velocity
|
|
||||||
velocity.add(Vector( 0.0, stunHeight, 0.0 ))
|
|
||||||
nearby.velocity = velocity
|
|
||||||
|
|
||||||
nearby.addPotionEffect(PotionEffect(
|
|
||||||
PotionEffectType.SLOWNESS,
|
|
||||||
20 * stunSlowDuration.toInt(),
|
|
||||||
4, false, false, false
|
|
||||||
))
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( nearby, "kits.blitzcrank.messages.stun.target" )
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.stun.player", "{nearby}" to nearbyPlayers.size.toString() )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package club.mcscrims.speedhg.listener
|
||||||
|
|
||||||
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
|
import club.mcscrims.speedhg.game.GameState
|
||||||
|
import club.mcscrims.speedhg.util.getDisplayName
|
||||||
|
import club.mcscrims.speedhg.util.sendMsg
|
||||||
|
import club.mcscrims.speedhg.util.trans
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.title.Title
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
|
||||||
|
class ConnectListener : Listener {
|
||||||
|
|
||||||
|
private val plugin = SpeedHG.instance
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onJoin(
|
||||||
|
event: PlayerJoinEvent
|
||||||
|
) {
|
||||||
|
val player = event.player
|
||||||
|
event.joinMessage( null )
|
||||||
|
|
||||||
|
if ( plugin.gameManager.currentState == GameState.INGAME ||
|
||||||
|
plugin.gameManager.currentState == GameState.INVINCIBILITY )
|
||||||
|
return
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.sendMsg( "game.join", "<name>" to player.name )
|
||||||
|
}
|
||||||
|
|
||||||
|
player.showTitle(Title.title(
|
||||||
|
player.trans( "player.welcome" ),
|
||||||
|
Component.empty()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onQuit(
|
||||||
|
event: PlayerQuitEvent
|
||||||
|
) {
|
||||||
|
val player = event.player
|
||||||
|
event.quitMessage( null )
|
||||||
|
|
||||||
|
if ( plugin.gameManager.currentState == GameState.INGAME ||
|
||||||
|
plugin.gameManager.currentState == GameState.INVINCIBILITY )
|
||||||
|
return
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
|
p.sendMsg( "game.quit", "<name>" to player.name )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,62 +1,47 @@
|
|||||||
package club.mcscrims.speedhg.listener
|
package club.mcscrims.speedhg.listener
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
import club.mcscrims.speedhg.game.GameManager
|
import club.mcscrims.speedhg.game.GameState
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
import club.mcscrims.speedhg.util.sendMsg
|
||||||
import club.mcscrims.speedhg.util.DirectionUtil
|
|
||||||
import club.mcscrims.spigot.chat.getDisplayName
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.Sound
|
import org.bukkit.Sound
|
||||||
import org.bukkit.attribute.Attribute
|
import org.bukkit.attribute.Attribute
|
||||||
import org.bukkit.entity.Entity
|
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.entity.Projectile
|
|
||||||
import org.bukkit.entity.Tameable
|
|
||||||
import org.bukkit.event.Event
|
import org.bukkit.event.Event
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.event.block.Action
|
|
||||||
import org.bukkit.event.block.BlockBreakEvent
|
import org.bukkit.event.block.BlockBreakEvent
|
||||||
import org.bukkit.event.block.BlockPlaceEvent
|
import org.bukkit.event.block.BlockPlaceEvent
|
||||||
import org.bukkit.event.block.BlockSpreadEvent
|
|
||||||
import org.bukkit.event.block.LeavesDecayEvent
|
import org.bukkit.event.block.LeavesDecayEvent
|
||||||
import org.bukkit.event.enchantment.EnchantItemEvent
|
import org.bukkit.event.enchantment.EnchantItemEvent
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
import org.bukkit.event.entity.EntityDamageEvent
|
|
||||||
import org.bukkit.event.entity.FoodLevelChangeEvent
|
import org.bukkit.event.entity.FoodLevelChangeEvent
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent
|
|
||||||
import org.bukkit.event.inventory.ClickType
|
import org.bukkit.event.inventory.ClickType
|
||||||
import org.bukkit.event.inventory.CraftItemEvent
|
import org.bukkit.event.inventory.CraftItemEvent
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||||
import org.bukkit.event.inventory.InventoryOpenEvent
|
import org.bukkit.event.inventory.InventoryOpenEvent
|
||||||
import org.bukkit.event.inventory.InventoryType
|
import org.bukkit.event.inventory.InventoryType
|
||||||
import org.bukkit.event.player.PlayerAttemptPickupItemEvent
|
|
||||||
import org.bukkit.event.player.PlayerBucketEmptyEvent
|
|
||||||
import org.bukkit.event.player.PlayerDropItemEvent
|
import org.bukkit.event.player.PlayerDropItemEvent
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerItemDamageEvent
|
import org.bukkit.event.player.PlayerItemDamageEvent
|
||||||
import org.bukkit.event.player.PlayerJoinEvent
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
import org.bukkit.event.player.PlayerQuitEvent
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
import org.bukkit.inventory.EnchantingInventory
|
import org.bukkit.inventory.EnchantingInventory
|
||||||
import org.bukkit.inventory.EquipmentSlot
|
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.Damageable
|
import org.bukkit.inventory.meta.Damageable
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
class GameStateListener(
|
class GameStateListener : Listener {
|
||||||
private val plugin: SpeedHG,
|
|
||||||
private val gameManager: GameManager
|
private val plugin = SpeedHG.instance
|
||||||
) : Listener {
|
private val gameManager = plugin.gameManager
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onLeavesDecay(
|
fun onLeavesDecay(
|
||||||
event: LeavesDecayEvent
|
event: LeavesDecayEvent
|
||||||
) {
|
) {
|
||||||
if ( gameManager.isRunning() )
|
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||||
|
gameManager.currentState == GameState.INGAME )
|
||||||
return
|
return
|
||||||
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
@@ -68,40 +53,29 @@ class GameStateListener(
|
|||||||
) {
|
) {
|
||||||
val player = event.player
|
val player = event.player
|
||||||
|
|
||||||
if ( gameManager.getCurrentStateType() == GameStateTypes.FEAST )
|
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||||
{
|
gameManager.currentState == GameState.INGAME )
|
||||||
val block = event.block
|
|
||||||
|
|
||||||
if (!gameManager.feastBox.contains( block.location.toVector() ))
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( gameManager.isRunning() )
|
|
||||||
return
|
return
|
||||||
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||||
}
|
}
|
||||||
|
|
||||||
private val beforeInvisMaterials = setOf(
|
private val beforeInvisMaterials = mapOf(
|
||||||
Material.OAK_LOG,
|
Material.OAK_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.DARK_OAK_LOG,
|
Material.DARK_OAK_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.BIRCH_LOG,
|
Material.BIRCH_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.ACACIA_LOG,
|
Material.ACACIA_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.JUNGLE_LOG,
|
Material.JUNGLE_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.SPRUCE_LOG,
|
Material.SPRUCE_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.STONE
|
Material.STONE to Sound.BLOCK_STONE_BREAK
|
||||||
)
|
)
|
||||||
|
|
||||||
private val alwaysMaterials = setOf(
|
private val alwaysMaterials = mapOf(
|
||||||
Material.RED_MUSHROOM,
|
Material.RED_MUSHROOM to Sound.BLOCK_GRASS_BREAK,
|
||||||
Material.BROWN_MUSHROOM,
|
Material.BROWN_MUSHROOM to Sound.BLOCK_GRASS_BREAK,
|
||||||
Material.COCOA_BEANS,
|
Material.COCOA_BEANS to Sound.BLOCK_WOOD_BREAK,
|
||||||
Material.CACTUS
|
Material.CACTUS to Sound.BLOCK_WOOL_BREAK
|
||||||
)
|
)
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -110,35 +84,26 @@ class GameStateListener(
|
|||||||
) {
|
) {
|
||||||
val player = event.player
|
val player = event.player
|
||||||
|
|
||||||
if ( !gameManager.isRunning() )
|
if ( gameManager.currentState != GameState.INVINCIBILITY &&
|
||||||
|
gameManager.currentState != GameState.INGAME )
|
||||||
{
|
{
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val block = event.block
|
val block = event.block
|
||||||
|
|
||||||
if ( gameManager.getCurrentStateType() == GameStateTypes.FEAST )
|
if ( gameManager.currentState == GameState.INVINCIBILITY &&
|
||||||
|
beforeInvisMaterials.containsKey( block.type ))
|
||||||
{
|
{
|
||||||
if (!gameManager.feastBox.contains( block.location.toVector() ))
|
pickupBlock( event, player )
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( gameManager.getCurrentStateType() == GameStateTypes.IMMUNITY &&
|
if (alwaysMaterials.containsKey( block.type ))
|
||||||
beforeInvisMaterials.contains( block.type ))
|
|
||||||
{
|
{
|
||||||
pickup( event, player )
|
pickupBlock( event, player )
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alwaysMaterials.contains( block.type ))
|
|
||||||
{
|
|
||||||
pickup( event, player )
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,46 +113,51 @@ class GameStateListener(
|
|||||||
event.block.type = Material.AIR
|
event.block.type = Material.AIR
|
||||||
event.block.tick()
|
event.block.tick()
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "build.no_diamonds" )
|
player.sendMsg( "build.no_diamonds" )
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( block.type == Material.IRON_ORE && gameManager.isBeforeFeast() )
|
// TODO: add feast check
|
||||||
|
if ( block.type == Material.IRON_ORE && TODO( "Add before feast check" ))
|
||||||
{
|
{
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
plugin.chatManager.sendMessage( player, "build.no_iron_before_feast" )
|
player.sendMsg( "build.no_iron_before_feast" )
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
||||||
}
|
}
|
||||||
else if ( block.type == Material.IRON_ORE && !gameManager.isBeforeFeast() )
|
else if ( block.type == Material.IRON_ORE && TODO( "Add after feast check" ))
|
||||||
{
|
{
|
||||||
runBlocking { plugin.statsRepository.addIronFarmed( player.uniqueId, 0.1 ) }
|
// TODO: add 0.1 to ironFarmed in database
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pickup(
|
private fun pickupBlock(
|
||||||
event: BlockBreakEvent,
|
event: BlockBreakEvent,
|
||||||
player: Player
|
player: Player
|
||||||
) {
|
) {
|
||||||
|
val block = event.block
|
||||||
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
|
val sound = if (beforeInvisMaterials.containsKey( block.type ))
|
||||||
|
beforeInvisMaterials[ block.type ]!!
|
||||||
|
else alwaysMaterials[ block.type ]!!
|
||||||
|
|
||||||
if (!hasInventorySpace( player ))
|
if (!hasInventorySpace( player ))
|
||||||
{
|
{
|
||||||
event.block.drops.forEach { player.world.dropItem( event.block.location, it ) }
|
block.drops.forEach { player.world.dropItem( block.location, it ) }
|
||||||
event.block.type = Material.AIR
|
player.playSound( player.location, sound, 1f, 1f )
|
||||||
|
block.type = Material.AIR
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
event.block.drops.forEach { player.inventory.addItem( it ) }
|
block.drops.forEach { player.inventory.addItem( it ) }
|
||||||
event.block.type = Material.AIR
|
player.playSound( player.location, sound, 1f, 1f )
|
||||||
|
block.type = Material.AIR
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasInventorySpace(
|
private fun hasInventorySpace( player: Player ): Boolean
|
||||||
player: Player
|
= player.inventory.any { it == null || it.type == Material.AIR }
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
return player.inventory.any { it == null || it.type == Material.AIR }
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onDropItem(
|
fun onDropItem(
|
||||||
@@ -195,75 +165,15 @@ class GameStateListener(
|
|||||||
) {
|
) {
|
||||||
val player = event.player
|
val player = event.player
|
||||||
|
|
||||||
if ( !gameManager.isRunning() )
|
if ( gameManager.currentState != GameState.INVINCIBILITY &&
|
||||||
|
gameManager.currentState != GameState.INGAME )
|
||||||
{
|
{
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val kit = plugin.kitManager.getSelectedKit( player )
|
// TODO: add kit item check
|
||||||
?: return
|
|
||||||
|
|
||||||
val items = kit.items.ifEmpty { return }
|
|
||||||
|
|
||||||
if (items.contains( event.itemDrop.itemStack ))
|
|
||||||
{
|
|
||||||
event.isCancelled = true
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPickupItem(
|
|
||||||
event: PlayerAttemptPickupItemEvent
|
|
||||||
) {
|
|
||||||
if ( gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInteractCompass(
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
if ( !gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val player = event.player
|
|
||||||
val action = event.action
|
|
||||||
|
|
||||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
|
||||||
action != Action.RIGHT_CLICK_BLOCK )
|
|
||||||
return
|
|
||||||
|
|
||||||
val item = event.item
|
|
||||||
?: return
|
|
||||||
|
|
||||||
if ( item.type != Material.COMPASS )
|
|
||||||
return
|
|
||||||
|
|
||||||
val nearestPlayer = Bukkit.getOnlinePlayers().stream()
|
|
||||||
.filter { other -> other != player }
|
|
||||||
.map { other -> other.location.distance( player.location ) to other }
|
|
||||||
.filter { pair -> pair.first > 5.0 }
|
|
||||||
.toList()
|
|
||||||
.firstOrNull()
|
|
||||||
?.second
|
|
||||||
|
|
||||||
if ( nearestPlayer == null )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "compass.no_nearby_players" )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
player.compassTarget = nearestPlayer.location
|
|
||||||
|
|
||||||
val direction = DirectionUtil.getDirectionToPlayer( player, nearestPlayer )
|
|
||||||
var actionBar = plugin.chatFormatter.format( "compass.actionBar" )
|
|
||||||
actionBar = actionBar.replaceText { it.match( "<direction>" ).replacement( direction ).once() }
|
|
||||||
plugin.chatManager.getAudience( player ).sendActionBar( actionBar )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val swordNerf = 0.5
|
private val swordNerf = 0.5
|
||||||
@@ -277,11 +187,7 @@ class GameStateListener(
|
|||||||
fun onDamageEntity(
|
fun onDamageEntity(
|
||||||
event: EntityDamageByEntityEvent
|
event: EntityDamageByEntityEvent
|
||||||
) {
|
) {
|
||||||
val damager = event.damager
|
val damager = event.damager as? Player ?: return
|
||||||
|
|
||||||
if ( damager !is Player )
|
|
||||||
return
|
|
||||||
|
|
||||||
val itemName = damager.inventory.itemInMainHand.type.name
|
val itemName = damager.inventory.itemInMainHand.type.name
|
||||||
|
|
||||||
if (itemName.endsWith( "_SWORD" ))
|
if (itemName.endsWith( "_SWORD" ))
|
||||||
@@ -312,26 +218,16 @@ class GameStateListener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onJoin(
|
fun onJoin( event: PlayerJoinEvent ) { disableHitCooldown( event.player ) }
|
||||||
event: PlayerJoinEvent
|
|
||||||
) {
|
|
||||||
disableCooldown( event.player )
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onQuit(
|
fun onQuit( event: PlayerQuitEvent ) { disableHitCooldown( event.player ) }
|
||||||
event: PlayerQuitEvent
|
|
||||||
) {
|
|
||||||
disableCooldown( event.player )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun disableCooldown(
|
private fun disableHitCooldown(
|
||||||
player: Player
|
player: Player
|
||||||
) {
|
) {
|
||||||
val attackSpeed = player.getAttribute( Attribute.GENERIC_ATTACK_SPEED )
|
val attackSpeed = player.getAttribute( Attribute.GENERIC_ATTACK_SPEED )
|
||||||
|
if ( attackSpeed != null ) attackSpeed.baseValue = 40.0
|
||||||
if ( attackSpeed != null )
|
|
||||||
attackSpeed.baseValue = 40.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lapisLazuli = Material.LAPIS_LAZULI
|
private val lapisLazuli = Material.LAPIS_LAZULI
|
||||||
@@ -354,10 +250,9 @@ class GameStateListener(
|
|||||||
val item = event.currentItem
|
val item = event.currentItem
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
// prevent taking it out
|
|
||||||
if ( item.type == lapisLazuli && event.rawSlot == 1 )
|
if ( item.type == lapisLazuli && event.rawSlot == 1 )
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
else if ( event.cursor.type == lapisLazuli && event.click == ClickType.DOUBLE_CLICK)
|
else if ( event.cursor.type == lapisLazuli && event.click == ClickType.DOUBLE_CLICK )
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,52 +280,12 @@ class GameStateListener(
|
|||||||
( inventory as EnchantingInventory ).secondary = ItemStack( lapisLazuli, 64 )
|
( inventory as EnchantingInventory ).secondary = ItemStack( lapisLazuli, 64 )
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInteractSoup(
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
val player = event.player
|
|
||||||
val action = event.action
|
|
||||||
|
|
||||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
|
||||||
action != Action.RIGHT_CLICK_BLOCK )
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( !event.hasItem() ||
|
|
||||||
event.material != Material.MUSHROOM_STEW )
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( event.hand == EquipmentSlot.OFF_HAND )
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( player.health < requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )!!.defaultValue))
|
|
||||||
{
|
|
||||||
player.health = min( player.health + 7, requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )!!.defaultValue))
|
|
||||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
|
||||||
}
|
|
||||||
else if ( player.foodLevel < 20 )
|
|
||||||
{
|
|
||||||
player.foodLevel += 6
|
|
||||||
player.saturation += 7
|
|
||||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onEntityDamage(
|
|
||||||
event: EntityDamageEvent
|
|
||||||
) {
|
|
||||||
if ( gameManager.isRunning() )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onFoodLevelChange(
|
fun onFoodLevelChange(
|
||||||
event: FoodLevelChangeEvent
|
event: FoodLevelChangeEvent
|
||||||
) {
|
) {
|
||||||
if ( gameManager.isRunning() )
|
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||||
|
gameManager.currentState == GameState.INGAME )
|
||||||
return
|
return
|
||||||
|
|
||||||
event.foodLevel = 20
|
event.foodLevel = 20
|
||||||
@@ -441,244 +296,40 @@ class GameStateListener(
|
|||||||
fun onCraftItem(
|
fun onCraftItem(
|
||||||
event: CraftItemEvent
|
event: CraftItemEvent
|
||||||
) {
|
) {
|
||||||
if ( !gameManager.isRunning() )
|
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||||
return
|
gameManager.currentState == GameState.INGAME )
|
||||||
|
|
||||||
val player = event.whoClicked
|
|
||||||
|
|
||||||
if ( player !is Player )
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
val player = event.whoClicked as? Player ?: return
|
||||||
val item = event.recipe.result
|
val item = event.recipe.result
|
||||||
|
|
||||||
|
if ( event.isShiftClick )
|
||||||
|
{
|
||||||
|
player.sendMsg( "craft.no_shift_click" )
|
||||||
|
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if ( item.type == Material.SHIELD )
|
if ( item.type == Material.SHIELD )
|
||||||
{
|
{
|
||||||
if ( event.isShiftClick )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "craft.no_shift_click" )
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
event.result = Event.Result.DENY
|
event.result = Event.Result.DENY
|
||||||
plugin.chatManager.sendMessage( player, "craft.no_shield" )
|
player.sendMsg( "craft.no_shield" )
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!item.type.name.contains( "iron", true ))
|
if (!item.type.name.contains( "iron", true ))
|
||||||
return
|
return
|
||||||
|
|
||||||
if ( gameManager.isBeforeFeast() )
|
// TODO: add before feast check and deny item crafting
|
||||||
{
|
|
||||||
event.result = Event.Result.DENY
|
|
||||||
plugin.chatManager.sendMessage( player, "craft.no_iron_before_feast" )
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( item.type.maxDurability > 0 )
|
if ( item.type.maxDurability > 0 )
|
||||||
{
|
{
|
||||||
item.editMeta { meta -> ( meta as Damageable ).damage /= 2 }
|
item.editMeta { meta -> ( meta as Damageable ).damage /= 2 }
|
||||||
plugin.chatManager.sendMessage( player, "craft.iron_nerf" )
|
player.sendMsg( "craft.iron_nerf" )
|
||||||
}
|
}
|
||||||
|
|
||||||
runBlocking { plugin.statsRepository.addIronFarmed( player.uniqueId, 0.1 ) }
|
// TODO: add 0.1 to ironFarmed in database
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInteractCleanse(
|
|
||||||
event: PlayerInteractEvent
|
|
||||||
) {
|
|
||||||
if ( gameManager.isBeforeFeast() )
|
|
||||||
return
|
|
||||||
|
|
||||||
val player = event.player
|
|
||||||
val action = event.action
|
|
||||||
|
|
||||||
val item = event.item ?: return
|
|
||||||
val block = event.clickedBlock
|
|
||||||
|
|
||||||
if ( block != null && gameManager.feastBox.contains( block.location.toVector() ))
|
|
||||||
{
|
|
||||||
event.isCancelled = true
|
|
||||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
|
||||||
action != Action.RIGHT_CLICK_BLOCK )
|
|
||||||
return
|
|
||||||
|
|
||||||
if ( item.type != Material.SUGAR ||
|
|
||||||
!item.itemMeta.isUnbreakable )
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
|
|
||||||
player.inventory.removeItemAnySlot( item )
|
|
||||||
player.clearActivePotionEffects()
|
|
||||||
|
|
||||||
plugin.chatManager.sendMessage( player, "feast.cleanser.cleaned" )
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onBucketEmpty(
|
|
||||||
event: PlayerBucketEmptyEvent
|
|
||||||
) {
|
|
||||||
if ( gameManager.getCurrentStateType() != GameStateTypes.FEAST )
|
|
||||||
return
|
|
||||||
|
|
||||||
val location = event.blockClicked.location.toVector()
|
|
||||||
|
|
||||||
if (!gameManager.feastBox.contains( location ))
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onLiquidSpread(
|
|
||||||
event: BlockSpreadEvent
|
|
||||||
) {
|
|
||||||
if ( gameManager.getCurrentStateType() != GameStateTypes.FEAST )
|
|
||||||
return
|
|
||||||
|
|
||||||
val block = event.block
|
|
||||||
|
|
||||||
if ( !block.isLiquid )
|
|
||||||
return
|
|
||||||
|
|
||||||
if (!gameManager.feastBox.contains( block.location.toVector() ))
|
|
||||||
return
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class DeathType {
|
|
||||||
PLAYER,
|
|
||||||
ENTITY,
|
|
||||||
WORLD
|
|
||||||
}
|
|
||||||
|
|
||||||
private val playerDeathMessages: Int = plugin.messageConfig.data.deathMessages["player"]!!.size
|
|
||||||
private val entityDeathMessages: Int = plugin.messageConfig.data.deathMessages["entity"]!!.size
|
|
||||||
private val worldDeathMessages: Int = plugin.messageConfig.data.deathMessages["world"]!!.size
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onDeath(
|
|
||||||
event: PlayerDeathEvent
|
|
||||||
) {
|
|
||||||
val player = event.entity
|
|
||||||
suppressEvent( event )
|
|
||||||
|
|
||||||
val lastDamageCause = player.lastDamageCause
|
|
||||||
var killer: Entity? = null
|
|
||||||
var deathType = DeathType.WORLD
|
|
||||||
|
|
||||||
if ( lastDamageCause is EntityDamageByEntityEvent )
|
|
||||||
{
|
|
||||||
val damager = lastDamageCause.damager
|
|
||||||
|
|
||||||
if ( damager !is Player )
|
|
||||||
{
|
|
||||||
if ( damager is Projectile )
|
|
||||||
{
|
|
||||||
if ( damager.shooter is Player )
|
|
||||||
{
|
|
||||||
deathType = DeathType.PLAYER
|
|
||||||
killer = damager.shooter as Player
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
deathType = DeathType.ENTITY
|
|
||||||
killer = damager.shooter as Entity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( damager is Tameable && damager.isTamed && damager.owner is Player )
|
|
||||||
{
|
|
||||||
deathType = DeathType.PLAYER
|
|
||||||
killer = damager.owner as Player
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
deathType = DeathType.ENTITY
|
|
||||||
killer = damager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
deathType = DeathType.PLAYER
|
|
||||||
killer = damager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( killer != null && killer is Player )
|
|
||||||
{
|
|
||||||
killer.exp += 0.5f
|
|
||||||
runBlocking { plugin.statsRepository.addKills( killer.uniqueId, 1 ) }
|
|
||||||
}
|
|
||||||
|
|
||||||
when( deathType )
|
|
||||||
{
|
|
||||||
DeathType.PLAYER ->
|
|
||||||
{
|
|
||||||
val random = this.random.nextInt( 0, playerDeathMessages )
|
|
||||||
|
|
||||||
val message = plugin.chatFormatter.formatList( "death.player",
|
|
||||||
"{player}" to player.getDisplayName, "{killer}" to (killer as Player).getDisplayName
|
|
||||||
)[ random ]
|
|
||||||
|
|
||||||
for ( p in Bukkit.getOnlinePlayers() )
|
|
||||||
plugin.chatManager.sendInteractiveMessage( p, message )
|
|
||||||
}
|
|
||||||
|
|
||||||
DeathType.ENTITY ->
|
|
||||||
{
|
|
||||||
val random = this.random.nextInt( 0, entityDeathMessages )
|
|
||||||
|
|
||||||
val message = plugin.chatFormatter.formatList( "death.entity",
|
|
||||||
"{player}" to player.getDisplayName, "{entity}" to killer!!.type.name
|
|
||||||
)[ random ]
|
|
||||||
|
|
||||||
for ( p in Bukkit.getOnlinePlayers() )
|
|
||||||
plugin.chatManager.sendInteractiveMessage( p, message )
|
|
||||||
}
|
|
||||||
|
|
||||||
DeathType.WORLD ->
|
|
||||||
{
|
|
||||||
val random = this.random.nextInt( 0, worldDeathMessages )
|
|
||||||
|
|
||||||
val message = plugin.chatFormatter.formatList( "death.world",
|
|
||||||
"{player}" to player.getDisplayName
|
|
||||||
)[ random ]
|
|
||||||
|
|
||||||
for ( p in Bukkit.getOnlinePlayers() )
|
|
||||||
plugin.chatManager.sendInteractiveMessage( p, message )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun suppressEvent(
|
|
||||||
event: PlayerDeathEvent
|
|
||||||
) {
|
|
||||||
val player = event.entity
|
|
||||||
|
|
||||||
event.deathMessage( null )
|
|
||||||
|
|
||||||
event.setShouldDropExperience( false )
|
|
||||||
|
|
||||||
event.setShouldPlayDeathSound( false )
|
|
||||||
player.world.strikeLightningEffect( player.location )
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
plugin.statsRepository.addDeaths( player.uniqueId, 1 )
|
|
||||||
plugin.playerRepository.updateAliveStatus( player.uniqueId, false )
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( player.isOnline )
|
|
||||||
player.kick(plugin.chatFormatter.format( "death.kick" ))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.listener
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import club.mcscrims.speedhg.util.LuckPermsUtils
|
|
||||||
import club.mcscrims.speedhg.util.TimeUtils
|
|
||||||
import com.lunarclient.apollo.Apollo
|
|
||||||
import com.lunarclient.apollo.event.ApolloListener
|
|
||||||
import com.lunarclient.apollo.event.Listen
|
|
||||||
import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent
|
|
||||||
import com.lunarclient.apollo.mods.impl.ModFreelook
|
|
||||||
import com.lunarclient.apollo.mods.impl.ModMinimap
|
|
||||||
import com.lunarclient.apollo.mods.impl.ModSnaplook
|
|
||||||
import com.lunarclient.apollo.mods.impl.ModTeamView
|
|
||||||
import com.lunarclient.apollo.mods.impl.ModWaypoints
|
|
||||||
import com.lunarclient.apollo.module.modsetting.ModSettingModule
|
|
||||||
import com.lunarclient.apollo.module.richpresence.RichPresenceModule
|
|
||||||
import com.lunarclient.apollo.module.richpresence.ServerRichPresence
|
|
||||||
import com.lunarclient.apollo.module.serverrule.ServerRuleModule
|
|
||||||
import com.lunarclient.apollo.module.staffmod.StaffMod
|
|
||||||
import com.lunarclient.apollo.module.staffmod.StaffModModule
|
|
||||||
import com.lunarclient.apollo.player.ApolloPlayer
|
|
||||||
|
|
||||||
class LunarClientListener(
|
|
||||||
private val plugin: SpeedHG
|
|
||||||
) : ApolloListener {
|
|
||||||
|
|
||||||
private val modSettingModule = Apollo.getModuleManager().getModule( ModSettingModule::class.java )
|
|
||||||
private val staffModModule = Apollo.getModuleManager().getModule( StaffModModule::class.java )
|
|
||||||
|
|
||||||
private val richPresenceModule = Apollo.getModuleManager().getModule( RichPresenceModule::class.java )
|
|
||||||
|
|
||||||
private val serverRuleModule = Apollo.getModuleManager().getModule( ServerRuleModule::class.java )
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.handle( ApolloRegisterPlayerEvent::class.java, this::onApolloRegister )
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listen
|
|
||||||
fun onApolloRegister(
|
|
||||||
event: ApolloRegisterPlayerEvent
|
|
||||||
) {
|
|
||||||
val player = event.player
|
|
||||||
|
|
||||||
setModSettings( player )
|
|
||||||
setRichPresence( player )
|
|
||||||
setServerRules( player )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setServerRules(
|
|
||||||
player: ApolloPlayer
|
|
||||||
) {
|
|
||||||
serverRuleModule.options.set( player, ServerRuleModule.COMPETITIVE_GAME, plugin.pluginConfig.data.game.competitiveGame )
|
|
||||||
serverRuleModule.options.set( player, ServerRuleModule.COMPETITIVE_COMMANDS, plugin.pluginConfig.data.game.competitiveCommands )
|
|
||||||
serverRuleModule.options.set( player, ServerRuleModule.ANTI_PORTAL_TRAPS, true )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setRichPresence(
|
|
||||||
player: ApolloPlayer
|
|
||||||
) {
|
|
||||||
val teamMaxSize = plugin.pluginConfig.data.game.teams["maximum_players"] as? Int ?: 2
|
|
||||||
|
|
||||||
val playerState = when( plugin.gameManager.getCurrentStateType() )
|
|
||||||
{
|
|
||||||
GameStateTypes.WAITING -> plugin.pluginConfig.data.game.playerStates[ "waiting" ]?.scoreboard ?: "N/A"
|
|
||||||
GameStateTypes.PRE_START -> plugin.pluginConfig.data.game.playerStates[ "pre_start" ]?.scoreboard ?: "N/A"
|
|
||||||
GameStateTypes.IMMUNITY -> plugin.pluginConfig.data.game.playerStates[ "immunity" ]?.scoreboard ?: "N/A"
|
|
||||||
GameStateTypes.BATTLE -> plugin.pluginConfig.data.game.playerStates[ "battle" ]?.scoreboard ?: "N/A"
|
|
||||||
GameStateTypes.FEAST -> plugin.pluginConfig.data.game.playerStates[ "feast" ]?.scoreboard ?: "N/A"
|
|
||||||
GameStateTypes.DEATHMATCH -> plugin.pluginConfig.data.game.playerStates[ "deathmatch" ]?.scoreboard ?: "N/A"
|
|
||||||
GameStateTypes.END -> plugin.pluginConfig.data.game.playerStates[ "end" ]?.scoreboard ?: "N/A"
|
|
||||||
else -> throw IllegalStateException("Current game state is null!")
|
|
||||||
}
|
|
||||||
|
|
||||||
val presence = ServerRichPresence.builder()
|
|
||||||
.gameName( plugin.pluginConfig.data.game.name )
|
|
||||||
.gameState( plugin.gameManager.getCurrentStateType()!!.name )
|
|
||||||
.gameVariantName( plugin.pluginConfig.data.game.variantName )
|
|
||||||
.playerState(playerState.replace( "%time%", TimeUtils.scoreboardTimeFromState() ))
|
|
||||||
.teamCurrentSize( 0 ) // TODO: Add team manager
|
|
||||||
.teamMaxSize( teamMaxSize )
|
|
||||||
.build()
|
|
||||||
|
|
||||||
richPresenceModule.overrideServerRichPresence( player, presence )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setModSettings(
|
|
||||||
player: ApolloPlayer
|
|
||||||
) {
|
|
||||||
if (LuckPermsUtils.hasPermission( player.uniqueId, "mcscrims.staff" ))
|
|
||||||
staffModModule.enableStaffMods( player, listOf( StaffMod.XRAY ))
|
|
||||||
else
|
|
||||||
staffModModule.disableAllStaffMods( player )
|
|
||||||
|
|
||||||
if (LuckPermsUtils.hasPermission( player.uniqueId, "speedhg.bypass.modSettings" ))
|
|
||||||
return
|
|
||||||
|
|
||||||
modSettingModule.options.set( player, ModMinimap.ENABLED, false )
|
|
||||||
modSettingModule.options.set( player, ModFreelook.ENABLED, false )
|
|
||||||
modSettingModule.options.set( player, ModSnaplook.ENABLED, false )
|
|
||||||
modSettingModule.options.set( player, ModWaypoints.ENABLED, false )
|
|
||||||
modSettingModule.options.set( player, ModTeamView.ENABLED, true )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package club.mcscrims.speedhg.listener
|
||||||
|
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.attribute.Attribute
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.EventPriority
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent
|
||||||
|
import org.bukkit.inventory.EquipmentSlot
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class SoupListener : Listener {
|
||||||
|
|
||||||
|
@EventHandler(
|
||||||
|
priority = EventPriority.HIGHEST,
|
||||||
|
ignoreCancelled = true
|
||||||
|
)
|
||||||
|
fun onSoup(
|
||||||
|
event: PlayerInteractEvent
|
||||||
|
) {
|
||||||
|
val player = event.player
|
||||||
|
val action = event.action
|
||||||
|
|
||||||
|
if ( !action.isRightClick )
|
||||||
|
return
|
||||||
|
|
||||||
|
if ( !event.hasItem() ||
|
||||||
|
event.material != Material.MUSHROOM_STEW )
|
||||||
|
return
|
||||||
|
|
||||||
|
if ( event.hand == EquipmentSlot.OFF_HAND )
|
||||||
|
return
|
||||||
|
|
||||||
|
if ( player.health < requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.defaultValue ))
|
||||||
|
{
|
||||||
|
player.health = min( player.health + 7, requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.defaultValue ))
|
||||||
|
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
||||||
|
}
|
||||||
|
else if ( player.foodLevel < 20 )
|
||||||
|
{
|
||||||
|
player.foodLevel += 6
|
||||||
|
player.saturation += 7
|
||||||
|
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.recraft
|
|
||||||
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
|
|
||||||
|
|
||||||
class Recraft {
|
|
||||||
|
|
||||||
private val recraftMaterials = listOf(
|
|
||||||
RecraftMaterial( 1, arrayOf( Material.RED_MUSHROOM, Material.BROWN_MUSHROOM )),
|
|
||||||
RecraftMaterial( 1, arrayOf( Material.COCOA_BEANS )),
|
|
||||||
RecraftMaterial( 1, arrayOf( Material.CACTUS ))
|
|
||||||
)
|
|
||||||
|
|
||||||
fun calcRecraft(
|
|
||||||
vararg items: ItemStack?
|
|
||||||
) {
|
|
||||||
recraftMaterials.forEach( RecraftMaterial::reset )
|
|
||||||
|
|
||||||
for ( item in items )
|
|
||||||
{
|
|
||||||
if ( item == null )
|
|
||||||
return
|
|
||||||
|
|
||||||
for ( recraftMaterial in recraftMaterials )
|
|
||||||
{
|
|
||||||
val type = item.type
|
|
||||||
|
|
||||||
if (recraftMaterial.containsKey( type ))
|
|
||||||
recraftMaterial[ type ] = recraftMaterial.getOrDefault( type , 0 ) + item.amount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun decrease(
|
|
||||||
player: Player,
|
|
||||||
amount: Int
|
|
||||||
) {
|
|
||||||
val lowestMaterials = mutableListOf<Material>()
|
|
||||||
|
|
||||||
for ( recraftMaterial in recraftMaterials )
|
|
||||||
if ( recraftMaterial.getLowestMaterial() != null )
|
|
||||||
lowestMaterials.add( recraftMaterial.getLowestMaterial()!! )
|
|
||||||
|
|
||||||
var highestMaterial: Material? = null
|
|
||||||
var i = 0f
|
|
||||||
|
|
||||||
for ( lowestMaterial in lowestMaterials )
|
|
||||||
{
|
|
||||||
val recraftMaterial = byMaterial( lowestMaterial )
|
|
||||||
|
|
||||||
if (recraftMaterial!![ lowestMaterial ]!! * recraftMaterial.getMaterialValue() > i )
|
|
||||||
{
|
|
||||||
i = recraftMaterial[ lowestMaterial ]!! * recraftMaterial.getMaterialValue()
|
|
||||||
highestMaterial = lowestMaterial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val recraftMaterial = byMaterial( highestMaterial!! )
|
|
||||||
recraftMaterial?.decrease( highestMaterial, amount )
|
|
||||||
|
|
||||||
for ( item in player.inventory.contents )
|
|
||||||
{
|
|
||||||
if ( item == null )
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ( item.type == highestMaterial )
|
|
||||||
{
|
|
||||||
item.amount -= amount
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun byMaterial(
|
|
||||||
material: Material
|
|
||||||
): RecraftMaterial?
|
|
||||||
{
|
|
||||||
return recraftMaterials.stream().filter { it.containsKey( material ) }.findFirst().orElse( null )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRecraftPoints(): Float
|
|
||||||
{
|
|
||||||
var points = 0f
|
|
||||||
|
|
||||||
for ( recraftMaterial in recraftMaterials )
|
|
||||||
points += recraftMaterial.getPoints()
|
|
||||||
|
|
||||||
return points
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.recraft
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import club.mcscrims.speedhg.game.GameStateTypes
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable
|
|
||||||
|
|
||||||
class RecraftInspector(
|
|
||||||
private val plugin: SpeedHG
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val beforeState = plugin.pluginConfig.data.game.recraftNerf[ "before_state" ] as String
|
|
||||||
private val recraftNerfEnabled = plugin.pluginConfig.data.game.recraftNerf[ "enabled" ] as Boolean
|
|
||||||
private val maxRecraftAmount = plugin.pluginConfig.data.game.recraftNerf[ "max_amount" ] as Double
|
|
||||||
|
|
||||||
fun startRunnable()
|
|
||||||
{
|
|
||||||
if ( !recraftNerfEnabled )
|
|
||||||
return
|
|
||||||
|
|
||||||
object : BukkitRunnable() {
|
|
||||||
|
|
||||||
val gameStateType = GameStateTypes.valueOf( beforeState.uppercase() )
|
|
||||||
|
|
||||||
override fun run()
|
|
||||||
{
|
|
||||||
if (!plugin.gameManager.isBefore( gameStateType ))
|
|
||||||
{
|
|
||||||
this.cancel()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getOnlinePlayers().stream()
|
|
||||||
.filter { !it.isDead }
|
|
||||||
.forEach { player ->
|
|
||||||
val recraft = Recraft()
|
|
||||||
recraft.calcRecraft( *player.inventory.contents )
|
|
||||||
|
|
||||||
if ( recraft.getRecraftPoints() > maxRecraftAmount )
|
|
||||||
{
|
|
||||||
plugin.chatManager.sendMessage( player, "recraftNerf.too_much" )
|
|
||||||
|
|
||||||
while ( recraft.getRecraftPoints() > maxRecraftAmount )
|
|
||||||
recraft.decrease( player, 1 )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}.runTaskTimer( plugin, 10L, 20L )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.recraft
|
|
||||||
|
|
||||||
import org.bukkit.Material
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
class RecraftMaterial(
|
|
||||||
val maxSoupAmount: Int,
|
|
||||||
val materials: Array<Material>
|
|
||||||
): ConcurrentHashMap<Material, Int>() {
|
|
||||||
|
|
||||||
fun getPoints(): Float
|
|
||||||
{
|
|
||||||
return getOrDefault( getLowestMaterial(), 0 ).toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun decrease(
|
|
||||||
material: Material,
|
|
||||||
amount: Int,
|
|
||||||
) {
|
|
||||||
put( material, get( material )!! - amount )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getLowestMaterial(): Material?
|
|
||||||
{
|
|
||||||
if ( size > 1 )
|
|
||||||
{
|
|
||||||
if (values.stream().anyMatch { int -> int == 0 })
|
|
||||||
return null
|
|
||||||
|
|
||||||
val materialIntegerEntry = entries.stream().min(Comparator.comparingInt { it.value })
|
|
||||||
return materialIntegerEntry.map { it.key }.orElse( null )
|
|
||||||
}
|
|
||||||
else return keys.stream().findFirst().orElse( null )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMaterialValue() = ( maxSoupAmount / size ).toFloat()
|
|
||||||
|
|
||||||
fun reset()
|
|
||||||
{
|
|
||||||
replaceAll { _, _ -> 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.recraft
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.NamespacedKey
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.inventory.ShapelessRecipe
|
|
||||||
|
|
||||||
object RecraftUtils {
|
|
||||||
|
|
||||||
fun registerRecipes()
|
|
||||||
{
|
|
||||||
val soup = ItemStack( Material.MUSHROOM_STEW )
|
|
||||||
|
|
||||||
val cocoRecipe = ShapelessRecipe(NamespacedKey.minecraft( "cocoa_soup" ), soup )
|
|
||||||
cocoRecipe.addIngredient( Material.COCOA_BEANS )
|
|
||||||
cocoRecipe.addIngredient( Material.BOWL )
|
|
||||||
|
|
||||||
val cactiRecipe = ShapelessRecipe(NamespacedKey.minecraft( "cacti_soup" ), soup )
|
|
||||||
cactiRecipe.addIngredient( Material.CACTUS )
|
|
||||||
cactiRecipe.addIngredient( Material.BOWL )
|
|
||||||
|
|
||||||
Bukkit.addRecipe( cocoRecipe )
|
|
||||||
Bukkit.addRecipe( cactiRecipe )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package club.mcscrims.speedhg.scoreboard
|
||||||
|
|
||||||
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
|
import club.mcscrims.speedhg.game.GameState
|
||||||
|
import club.mcscrims.speedhg.util.trans
|
||||||
|
import club.mcscrims.speedhg.util.transList
|
||||||
|
import fr.mrmicky.fastboard.adventure.FastBoard
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.Statistic
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class ScoreboardManager(
|
||||||
|
private val plugin: SpeedHG
|
||||||
|
): Listener {
|
||||||
|
|
||||||
|
private val boards = ConcurrentHashMap<UUID, FastBoard>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||||
|
updateAllBoards()
|
||||||
|
}, 0L, 10L )
|
||||||
|
|
||||||
|
plugin.server.pluginManager.registerEvents( this, plugin )
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onJoin(
|
||||||
|
event: PlayerJoinEvent
|
||||||
|
) {
|
||||||
|
val board = FastBoard( event.player )
|
||||||
|
board.updateTitle(event.player.trans( "scoreboard.title" ))
|
||||||
|
boards[ event.player.uniqueId ] = board
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onQuit(
|
||||||
|
event: PlayerQuitEvent
|
||||||
|
) {
|
||||||
|
boards.remove( event.player.uniqueId )?.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAllBoards()
|
||||||
|
{
|
||||||
|
boards.forEach { (key, value) ->
|
||||||
|
val player = Bukkit.getPlayer( key )
|
||||||
|
|
||||||
|
if ( player != null )
|
||||||
|
updateBoard( player, value )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBoard(
|
||||||
|
player: Player,
|
||||||
|
board: FastBoard
|
||||||
|
) {
|
||||||
|
val gm = plugin.gameManager
|
||||||
|
val state = gm.currentState
|
||||||
|
|
||||||
|
board.updateTitle(player.trans( "scoreboard.title" ))
|
||||||
|
|
||||||
|
val online = Bukkit.getOnlinePlayers().size.toString()
|
||||||
|
val max = Bukkit.getMaxPlayers().toString()
|
||||||
|
val kitName = "None" // TODO
|
||||||
|
|
||||||
|
val lines: List<Component>
|
||||||
|
|
||||||
|
if ( state == GameState.LOBBY || state == GameState.STARTING )
|
||||||
|
{
|
||||||
|
val timeString = if ( state == GameState.STARTING ) formatTime( gm.timer ) else "Waiting..."
|
||||||
|
|
||||||
|
lines = player.transList( "scoreboard.lobby", mapOf(
|
||||||
|
"online" to online,
|
||||||
|
"max" to max,
|
||||||
|
"kit" to kitName,
|
||||||
|
"time" to timeString
|
||||||
|
))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val timeString = formatTime( gm.timer )
|
||||||
|
val alive = gm.alivePlayers.size.toString()
|
||||||
|
val kills = player.getStatistic( Statistic.PLAYER_KILLS ).toString()
|
||||||
|
val border = String.format( "%.0f", player.world.worldBorder.size )
|
||||||
|
|
||||||
|
lines = player.transList( "scoreboard.ingame", mapOf(
|
||||||
|
"timer" to timeString,
|
||||||
|
"alive" to alive,
|
||||||
|
"kills" to kills,
|
||||||
|
"border" to border,
|
||||||
|
"kit" to kitName
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
board.updateLines( lines )
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun formatTime(
|
||||||
|
seconds: Int
|
||||||
|
): String
|
||||||
|
{
|
||||||
|
val m = seconds / 60
|
||||||
|
val s = seconds % 60
|
||||||
|
return String.format( "%02d:%02d", m, s )
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
101
src/main/kotlin/club/mcscrims/speedhg/util/AbilityUtils.kt
Normal file
101
src/main/kotlin/club/mcscrims/speedhg/util/AbilityUtils.kt
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package club.mcscrims.speedhg.util
|
||||||
|
|
||||||
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
|
import org.bukkit.Color
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.Particle
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable
|
||||||
|
import org.bukkit.util.Vector
|
||||||
|
import java.util.function.Consumer
|
||||||
|
|
||||||
|
object AbilityUtils {
|
||||||
|
|
||||||
|
private val plugin = SpeedHG.instance
|
||||||
|
|
||||||
|
fun createBeam(
|
||||||
|
startLocation: Location,
|
||||||
|
direction: Vector,
|
||||||
|
particle: Particle,
|
||||||
|
range: Double,
|
||||||
|
step: Double,
|
||||||
|
onHit: (Player) -> Unit
|
||||||
|
) {
|
||||||
|
val normalizedDirection = direction.normalize()
|
||||||
|
|
||||||
|
object : BukkitRunnable()
|
||||||
|
{
|
||||||
|
var traveledDistance = 0.0
|
||||||
|
var currentLocation = startLocation.clone()
|
||||||
|
|
||||||
|
override fun run()
|
||||||
|
{
|
||||||
|
if ( traveledDistance >= range)
|
||||||
|
{
|
||||||
|
this.cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLocation.world.spawnParticle( particle, currentLocation, 5, 0.0, 0.0, 0.0, 0.0 )
|
||||||
|
|
||||||
|
val nearestPlayer = currentLocation.world.getNearbyEntities( currentLocation, 0.5, 0.5, 0.5 )
|
||||||
|
.filterIsInstance<Player>().minByOrNull { it.location.distance( currentLocation ) }
|
||||||
|
|
||||||
|
if ( nearestPlayer != null )
|
||||||
|
{
|
||||||
|
onHit( nearestPlayer )
|
||||||
|
this.cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLocation.add(normalizedDirection.multiply( step ))
|
||||||
|
traveledDistance += step
|
||||||
|
}
|
||||||
|
|
||||||
|
}.runTaskTimer( plugin, 0L, 1L )
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawParticleLine(
|
||||||
|
startLocation: Location,
|
||||||
|
endLocation: Location,
|
||||||
|
particle: Particle,
|
||||||
|
steps: Int,
|
||||||
|
dustColor: Color
|
||||||
|
) {
|
||||||
|
if ( steps <= 0 ) throw IllegalArgumentException( "Steps must be greater than 0." )
|
||||||
|
val world = startLocation.world ?: throw IllegalStateException( "World cannot be null." )
|
||||||
|
if ( startLocation.world != endLocation.world ) throw IllegalStateException( "Locations must be in the same world." )
|
||||||
|
|
||||||
|
val diffX = ( endLocation.x - startLocation.x ) / steps
|
||||||
|
val diffY = ( endLocation.y - startLocation.y ) / steps
|
||||||
|
val diffZ = ( endLocation.z - startLocation.z ) / steps
|
||||||
|
|
||||||
|
for ( i in 0..steps )
|
||||||
|
{
|
||||||
|
val x = startLocation.x + diffX * i
|
||||||
|
val y = startLocation.y + diffY * i
|
||||||
|
val z = startLocation.z + diffZ * i
|
||||||
|
|
||||||
|
world.spawnParticle( particle, x, y, z, 1, Particle.DustOptions( dustColor, 1f ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runForNearbyPlayers(
|
||||||
|
player: Player,
|
||||||
|
radius: Double,
|
||||||
|
filter: (Player) -> Boolean,
|
||||||
|
runnable: Consumer<in Player>
|
||||||
|
): MutableCollection<Player>
|
||||||
|
{
|
||||||
|
if ( radius <= 0.0 ) throw IllegalArgumentException( "Radius must be greater than 0.0." )
|
||||||
|
|
||||||
|
val world = player.world
|
||||||
|
val nearbyPlayers = world.getNearbyPlayers( player.location, radius ).filter( filter )
|
||||||
|
.filter { it != player && it.gameMode == GameMode.SURVIVAL }.toMutableList()
|
||||||
|
|
||||||
|
nearbyPlayers.forEach( runnable )
|
||||||
|
return nearbyPlayers
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.util
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.util.Vector
|
|
||||||
import kotlin.math.atan2
|
|
||||||
|
|
||||||
object DirectionUtil {
|
|
||||||
|
|
||||||
private val plugin = SpeedHG.instance
|
|
||||||
private val directions = arrayOf("north", "northEast", "east", "southEast", "south", "southWest", "west", "northWest")
|
|
||||||
|
|
||||||
fun getDirectionToPlayer(
|
|
||||||
player: Player,
|
|
||||||
nearestPlayer: Player
|
|
||||||
): Component
|
|
||||||
{
|
|
||||||
val yaw = getDirection( player, nearestPlayer )
|
|
||||||
var normalizedYaw = yaw % 360
|
|
||||||
|
|
||||||
if ( normalizedYaw < 0 )
|
|
||||||
normalizedYaw += 360
|
|
||||||
|
|
||||||
val index = (( normalizedYaw + 22.5 ) / 45 ).toInt() % 8
|
|
||||||
return plugin.chatFormatter.format( "compass.directions.${directions[ index ]}" )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDirection(
|
|
||||||
fromPlayer: Player,
|
|
||||||
toPlayer: Player
|
|
||||||
): Double
|
|
||||||
{
|
|
||||||
val fromLocation = fromPlayer.location
|
|
||||||
val toLocation = toPlayer.location
|
|
||||||
|
|
||||||
val directionVector = Vector( toLocation.x - fromLocation.x, 0.0, toLocation.z - fromLocation.z ).normalize()
|
|
||||||
|
|
||||||
val angle = atan2( directionVector.x, directionVector.z )
|
|
||||||
val yaw = Math.toDegrees( angle )
|
|
||||||
|
|
||||||
var adjustedYaw = yaw + 180
|
|
||||||
|
|
||||||
if ( adjustedYaw < 0)
|
|
||||||
adjustedYaw += 360
|
|
||||||
|
|
||||||
return adjustedYaw
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTargetPlayerInLineOfSight(
|
|
||||||
player: Player,
|
|
||||||
maxDistance: Double,
|
|
||||||
width: Double
|
|
||||||
): Player?
|
|
||||||
{
|
|
||||||
val direction = player.eyeLocation.direction.normalize()
|
|
||||||
val origin = player.eyeLocation.toVector()
|
|
||||||
val world = player.world
|
|
||||||
|
|
||||||
val nearbyPlayers = world.getNearbyEntitiesByType( Player::class.java, player.location, maxDistance, maxDistance, maxDistance )
|
|
||||||
|
|
||||||
return nearbyPlayers
|
|
||||||
.filter { it.uniqueId != player.uniqueId }
|
|
||||||
.filter { nearby ->
|
|
||||||
val nearbyLocation = nearby.location.add( 0.0, 0.5, 0.0 ).toVector()
|
|
||||||
|
|
||||||
val toEntitiy = nearbyLocation.subtract( origin )
|
|
||||||
|
|
||||||
val distanceAlongLine = toEntitiy.dot( direction )
|
|
||||||
if ( distanceAlongLine !in 0.0..maxDistance ) return@filter false
|
|
||||||
|
|
||||||
val perpendicularDistance = toEntitiy.subtract(direction.multiply( distanceAlongLine )).length()
|
|
||||||
perpendicularDistance <= width
|
|
||||||
}
|
|
||||||
.minByOrNull { it.location.distanceSquared( player.location ) }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
55
src/main/kotlin/club/mcscrims/speedhg/util/Extensions.kt
Normal file
55
src/main/kotlin/club/mcscrims/speedhg/util/Extensions.kt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package club.mcscrims.speedhg.util
|
||||||
|
|
||||||
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
private val langManager get() = SpeedHG.instance.languageManager
|
||||||
|
|
||||||
|
private val legacySerializer = LegacyComponentSerializer.builder()
|
||||||
|
.character('§')
|
||||||
|
.hexColors()
|
||||||
|
.useUnusualXRepeatedCharacterHexFormat()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
fun Player.sendMsg(
|
||||||
|
key: String,
|
||||||
|
vararg placeholders: Pair<String, String>
|
||||||
|
) {
|
||||||
|
val component = langManager.getComponent( this, key, placeholders.toMap() )
|
||||||
|
this.sendMessage( component )
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.trans(
|
||||||
|
key: String,
|
||||||
|
vararg placeholders: Pair<String, String>
|
||||||
|
): Component
|
||||||
|
{
|
||||||
|
return langManager.getComponent( this, key, placeholders.toMap() )
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.transList(
|
||||||
|
key: String,
|
||||||
|
placeholders: Map<String, String>
|
||||||
|
): List<Component>
|
||||||
|
{
|
||||||
|
val rawList = langManager.getRawMessageList( this, key )
|
||||||
|
|
||||||
|
return rawList.map { line ->
|
||||||
|
var replaced = line
|
||||||
|
placeholders.forEach { (k, v) ->
|
||||||
|
replaced = replaced.replace( "<$k>", v )
|
||||||
|
}
|
||||||
|
MiniMessage.miniMessage().deserialize( replaced )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Component.toLegacyString(): String
|
||||||
|
{
|
||||||
|
return legacySerializer.serialize( this )
|
||||||
|
}
|
||||||
|
|
||||||
|
val Player.getDisplayName: String
|
||||||
|
get() = legacySerializer.serialize( this.displayName() )
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.util
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import net.luckperms.api.cacheddata.CachedDataManager
|
|
||||||
import net.luckperms.api.model.group.Group
|
|
||||||
import net.luckperms.api.model.user.User
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
object LuckPermsUtils {
|
|
||||||
|
|
||||||
private val plugin = SpeedHG.instance
|
|
||||||
private val luckPerms = plugin.luckPerms
|
|
||||||
|
|
||||||
fun getUser(
|
|
||||||
player: Player
|
|
||||||
): User?
|
|
||||||
{
|
|
||||||
return luckPerms.userManager.getUser( player.uniqueId )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun editUser(
|
|
||||||
player: Player,
|
|
||||||
action: (User) -> Unit
|
|
||||||
) {
|
|
||||||
luckPerms.userManager.loadUser( player.uniqueId ).thenAcceptAsync( action )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getGroup(
|
|
||||||
groupName: String
|
|
||||||
): Group?
|
|
||||||
{
|
|
||||||
return luckPerms.groupManager.getGroup( groupName )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCachedData(
|
|
||||||
player: Player
|
|
||||||
): CachedDataManager?
|
|
||||||
{
|
|
||||||
return getUser( player )?.cachedData
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasPermission(
|
|
||||||
uniqueId: UUID,
|
|
||||||
permission: String
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
val cachedData = luckPerms.userManager.loadUser( uniqueId ).get().cachedData
|
|
||||||
return cachedData.permissionData.checkPermission( permission ).asBoolean()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasPermission(
|
|
||||||
player: Player,
|
|
||||||
permission: String
|
|
||||||
): Boolean
|
|
||||||
{
|
|
||||||
return getCachedData( player )?.permissionData?.checkPermission( permission )?.asBoolean()
|
|
||||||
?: player.hasPermission( permission )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.util
|
|
||||||
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class RandomCollection<E> {
|
|
||||||
|
|
||||||
private val map = TreeMap<Double, List<E>>()
|
|
||||||
private val names = hashMapOf<List<E>, String>()
|
|
||||||
|
|
||||||
private val random = Random()
|
|
||||||
private var total = 0.0
|
|
||||||
|
|
||||||
fun add(
|
|
||||||
weight: Double,
|
|
||||||
result: E
|
|
||||||
) {
|
|
||||||
if ( weight <= 0 ) return
|
|
||||||
total += weight
|
|
||||||
map[ total ] = listOf( result )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(
|
|
||||||
name: String,
|
|
||||||
weight: Double,
|
|
||||||
result: E
|
|
||||||
) {
|
|
||||||
if ( weight <= 0 ) return
|
|
||||||
total += weight
|
|
||||||
map[ total ] = listOf( result )
|
|
||||||
names[listOf( result )] = name
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(
|
|
||||||
weight: Double,
|
|
||||||
result: List<E>
|
|
||||||
) {
|
|
||||||
if ( weight <= 0 ) return
|
|
||||||
total += weight
|
|
||||||
map[ total ] = result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(
|
|
||||||
name: String,
|
|
||||||
weight: Double,
|
|
||||||
result: List<E>
|
|
||||||
) {
|
|
||||||
if ( weight <= 0 ) return
|
|
||||||
total += weight
|
|
||||||
map[ total ] = result
|
|
||||||
names[ result ] = name
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getName(
|
|
||||||
key: E
|
|
||||||
): String
|
|
||||||
{
|
|
||||||
return names.getOrDefault(listOf( key ), "" )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getName(
|
|
||||||
key: List<E>
|
|
||||||
): String
|
|
||||||
{
|
|
||||||
return names.getOrDefault( key, "" )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRandom(): List<E>
|
|
||||||
{
|
|
||||||
val value = random.nextDouble() * total
|
|
||||||
return map.higherEntry( value ).value
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.util
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
|
|
||||||
object TimeUtils {
|
|
||||||
|
|
||||||
private val plugin = SpeedHG.instance
|
|
||||||
|
|
||||||
fun scoreboardTimeFromState(): String
|
|
||||||
{
|
|
||||||
val currentTime = plugin.gameManager.getCurrentState()?.getRemainingSeconds()
|
|
||||||
?: throw IllegalArgumentException("Remaining seconds for state is null!")
|
|
||||||
return scoreboardTime( currentTime )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun scoreboardTime(
|
|
||||||
totalSeconds: Int
|
|
||||||
): String
|
|
||||||
{
|
|
||||||
val hours = totalSeconds / 3600
|
|
||||||
val minutes = (totalSeconds % 3600) / 60
|
|
||||||
val seconds = totalSeconds % 60
|
|
||||||
|
|
||||||
if ( totalSeconds > 3600 )
|
|
||||||
return String.format( "%02d:%02d:%02d", hours, minutes, seconds )
|
|
||||||
return String.format( "%02d:%02d", minutes, seconds )
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
package club.mcscrims.speedhg.world
|
|
||||||
|
|
||||||
import club.mcscrims.speedhg.SpeedHG
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.GameRule
|
|
||||||
import org.bukkit.Location
|
|
||||||
import org.bukkit.World
|
|
||||||
import org.popcraft.chunky.api.ChunkyAPI
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class WorldManager(
|
|
||||||
private val plugin: SpeedHG
|
|
||||||
) {
|
|
||||||
|
|
||||||
private var worldName = "world"
|
|
||||||
private lateinit var world: World
|
|
||||||
|
|
||||||
fun highestLocationWithRadius(
|
|
||||||
center: Location,
|
|
||||||
radius: Int
|
|
||||||
): Location
|
|
||||||
{
|
|
||||||
getWorld()
|
|
||||||
val minX = center.blockX - radius
|
|
||||||
val minZ = center.blockZ - radius
|
|
||||||
val maxX = center.blockX + radius
|
|
||||||
val maxZ = center.blockZ + radius
|
|
||||||
|
|
||||||
var highestY = center.blockY
|
|
||||||
var highestX = minX
|
|
||||||
var highestZ = minZ
|
|
||||||
|
|
||||||
for ( x in minX..maxX )
|
|
||||||
for ( z in minZ..maxZ )
|
|
||||||
{
|
|
||||||
val y = world.getHighestBlockYAt( x, z )
|
|
||||||
|
|
||||||
if ( y > highestY )
|
|
||||||
{
|
|
||||||
highestY = y
|
|
||||||
highestX = x
|
|
||||||
highestZ = z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val highest = Location( world, highestX.toDouble(), highestY.toDouble(), highestZ.toDouble() )
|
|
||||||
return highest
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DELETION >>
|
|
||||||
*/
|
|
||||||
|
|
||||||
fun deleteWorld()
|
|
||||||
{
|
|
||||||
getWorld()
|
|
||||||
Bukkit.unloadWorld( worldName, false )
|
|
||||||
val folder = File( worldName )
|
|
||||||
deleteFolder( folder )
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deleteFolder(
|
|
||||||
folder: File
|
|
||||||
) {
|
|
||||||
val files = folder.listFiles()
|
|
||||||
|
|
||||||
if ( files != null )
|
|
||||||
for ( f in files )
|
|
||||||
{
|
|
||||||
if ( f.isDirectory )
|
|
||||||
deleteFolder( f )
|
|
||||||
else
|
|
||||||
f.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
folder.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WORLD >>
|
|
||||||
*/
|
|
||||||
|
|
||||||
lateinit var spawnLocation: Location
|
|
||||||
var borderDecrease: Double = 100.0
|
|
||||||
|
|
||||||
fun setupWorld()
|
|
||||||
{
|
|
||||||
val world = getWorld() ?: return
|
|
||||||
plugin.logger.info("Setting up world...")
|
|
||||||
|
|
||||||
// BORDER >>
|
|
||||||
|
|
||||||
plugin.logger.info("Setting up world... [STAGE [1]: WORLDBORDER]")
|
|
||||||
|
|
||||||
spawnLocation = Location( world, 0.0, world.getHighestBlockYAt( 0, 0).toDouble(), 0.0 )
|
|
||||||
world.worldBorder.center = spawnLocation
|
|
||||||
|
|
||||||
world.worldBorder.size = plugin.pluginConfig.data.world.border["size"]!!
|
|
||||||
world.worldBorder.warningDistance = plugin.pluginConfig.data.world.border["warning_distance"]!!.toInt()
|
|
||||||
world.worldBorder.damageAmount = plugin.pluginConfig.data.world.border["damage"]!!
|
|
||||||
|
|
||||||
borderDecrease = plugin.pluginConfig.data.world.border["decrease"]!!
|
|
||||||
|
|
||||||
// GAMERULES >>
|
|
||||||
|
|
||||||
plugin.logger.info("Setting up world... [Stage [2]: GAMERULES]")
|
|
||||||
|
|
||||||
world.setGameRule( GameRule.ANNOUNCE_ADVANCEMENTS, false )
|
|
||||||
world.setGameRule( GameRule.DO_INSOMNIA, false )
|
|
||||||
world.setGameRule( GameRule.DISABLE_RAIDS, true )
|
|
||||||
world.setGameRule( GameRule.DO_PATROL_SPAWNING, false )
|
|
||||||
world.setGameRule( GameRule.DO_TRADER_SPAWNING, false )
|
|
||||||
|
|
||||||
// CHUNKY >>
|
|
||||||
|
|
||||||
// plugin.logger.info("Setting up world... [Stage [3]: CHUNKY]")
|
|
||||||
// val chunky = Bukkit.getServicesManager().load( ChunkyAPI::class.java )
|
|
||||||
//
|
|
||||||
// if ( chunky == null || chunky.version() != 0 )
|
|
||||||
// {
|
|
||||||
// plugin.isReady = true
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val radius = world.worldBorder.size / 2
|
|
||||||
//
|
|
||||||
// chunky.startTask( worldName, "square", 0.0, 0.0, radius, radius, "concentric" )
|
|
||||||
// chunky.onGenerationComplete { plugin.isReady = true }
|
|
||||||
//
|
|
||||||
// plugin.server.dispatchCommand( Bukkit.getConsoleSender(), "chunky silent" )
|
|
||||||
|
|
||||||
// FINISH >>
|
|
||||||
|
|
||||||
plugin.logger.info("World has been set up!")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setWorld(
|
|
||||||
worldName: String
|
|
||||||
): World?
|
|
||||||
{
|
|
||||||
this.worldName = worldName
|
|
||||||
val world = Bukkit.getWorld( worldName )
|
|
||||||
|
|
||||||
if ( world != null )
|
|
||||||
this.world = world
|
|
||||||
|
|
||||||
return world
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getWorld(): World?
|
|
||||||
{
|
|
||||||
return if ( !::world.isInitialized )
|
|
||||||
try {
|
|
||||||
setWorld( plugin.pluginConfig.data.world.name )
|
|
||||||
} catch ( _: Exception ) { null }
|
|
||||||
else this.world
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,94 +1,21 @@
|
|||||||
#
|
#
|
||||||
# |-----| |-----| |-----| |-----| |---\ | | |-----|
|
# SpeedHG v1.0.0 by McScrims-Network
|
||||||
# | | | | | | \ | | |
|
# https://github.com/McScrims-Network
|
||||||
# |-----| |-----| |---| |---| | | |-----| | |--|
|
|
||||||
# | | | | | / | | | |
|
|
||||||
# |-----| | |-----| |-----| |---/ | | |-----|
|
|
||||||
# v1.0.0 by TDSTOS
|
|
||||||
#
|
#
|
||||||
# Organization: McScrims-Network (https://github.com/McScrims-Network/)
|
|
||||||
# Owner: TDSTOS (https://github.com/TDSTOS)
|
|
||||||
# Contributors: stavgun (https://github.com/stavgun)
|
|
||||||
#
|
|
||||||
|
|
||||||
debug: false
|
|
||||||
language: 'en_US'
|
|
||||||
|
|
||||||
restart_time: 3
|
|
||||||
|
|
||||||
network:
|
|
||||||
enabled: false
|
|
||||||
serverId: 'server-1'
|
|
||||||
type: REDIS
|
|
||||||
redis:
|
|
||||||
host: 'localhost'
|
|
||||||
port: 6379
|
|
||||||
user: 'default'
|
|
||||||
password: ''
|
|
||||||
database: 0
|
|
||||||
timeout: 5000
|
|
||||||
poolSize: 10
|
|
||||||
|
|
||||||
cooldown: 30
|
|
||||||
needed_hits: 15
|
|
||||||
|
|
||||||
world:
|
|
||||||
name: 'Default'
|
|
||||||
border:
|
|
||||||
size: 1000.0
|
|
||||||
warning_distance: 5.0
|
|
||||||
damage: 5.0
|
|
||||||
decrease: 100.0
|
|
||||||
|
|
||||||
game:
|
game:
|
||||||
name: 'SpeedHG'
|
min-players: 2
|
||||||
variantName: 'Solo - Single Kit'
|
lobby-time: 60
|
||||||
|
invincibility-time: 60
|
||||||
|
border-start: 300.0
|
||||||
|
border-end: 20.0
|
||||||
|
border-shrink-time: 600 # 10 Minuten
|
||||||
|
|
||||||
minimumPlayers: 8
|
anti-runner:
|
||||||
|
enabled: true
|
||||||
competitiveGame: false
|
check-radius: 20.0
|
||||||
competitiveCommands:
|
warn-time: 15
|
||||||
- 'server'
|
punish-time: 25
|
||||||
- 'servers'
|
# Einstellungen für die Cave-Erkennung
|
||||||
- 'hub'
|
ignore-vertical-distance: 15.0 # Wenn Höhenunterschied > 15, Timer ignorieren
|
||||||
- 'lobby'
|
ignore-cave-surface-mix: true # Ignorieren, wenn einer Sonne hat und der andere nicht
|
||||||
- 'l'
|
|
||||||
|
|
||||||
playerStates:
|
|
||||||
waiting:
|
|
||||||
scoreboard: 'Waiting - %time%'
|
|
||||||
duration: "FIXED:-1"
|
|
||||||
preStart:
|
|
||||||
scoreboard: 'Waiting - %time%'
|
|
||||||
duration: "FIXED:300"
|
|
||||||
immunity:
|
|
||||||
scoreboard: 'Playing - %time%'
|
|
||||||
duration: "FIXED:90"
|
|
||||||
battle:
|
|
||||||
scoreboard: 'Playing - %time%'
|
|
||||||
duration: "INCREASING"
|
|
||||||
feast:
|
|
||||||
scoreboard: 'Playing - %time%'
|
|
||||||
duration: "FIXED:300"
|
|
||||||
deathmatch:
|
|
||||||
scoreboard: 'Playing - %time%'
|
|
||||||
duration: "INCREASING"
|
|
||||||
end:
|
|
||||||
scoreboard: 'Ending - %time%'
|
|
||||||
duration: "FIXED:60"
|
|
||||||
|
|
||||||
recraftNerf:
|
|
||||||
enabled: false
|
|
||||||
maxAmount: 64
|
|
||||||
beforeState: 'FEAST'
|
|
||||||
|
|
||||||
teams:
|
|
||||||
enabled: false
|
|
||||||
maximumPlayers: 2
|
|
||||||
|
|
||||||
blockedKits: []
|
|
||||||
|
|
||||||
blockedPerks: []
|
|
||||||
|
|
||||||
perks:
|
|
||||||
maximumAmount: 2
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"connectionString": "",
|
|
||||||
"host": "localhost",
|
|
||||||
"port": 27017,
|
|
||||||
"database": "minecraft",
|
|
||||||
"username": "root",
|
|
||||||
"password": "pass",
|
|
||||||
"authDatabase": "admin",
|
|
||||||
"ssl": false,
|
|
||||||
"replicaSet": "",
|
|
||||||
"connectionTimeout": 30,
|
|
||||||
"poolSize": 10
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
anchor:
|
|
||||||
offensive extra damage: 1.0
|
|
||||||
|
|
||||||
armorer:
|
|
||||||
kills until new armor: 2.0
|
|
||||||
|
|
||||||
blackpanther:
|
|
||||||
enderpearl hit damage: 3.0
|
|
||||||
extra damage on top: 0.5
|
|
||||||
default hit radius: 3.0
|
|
||||||
explosion multiplier: 3.0
|
|
||||||
|
|
||||||
gladiator:
|
|
||||||
cage radius: 23.0
|
|
||||||
cage height: 10.0
|
|
||||||
wither effect after x seconds: 180.0
|
|
||||||
|
|
||||||
goblin:
|
|
||||||
bunker radius: 10.0
|
|
||||||
bunker time until disappear: 15.0
|
|
||||||
knockback and pullin radius: 7.0
|
|
||||||
kit steal time: 60.0
|
|
||||||
soup steal chance: 20.0
|
|
||||||
|
|
||||||
icemage:
|
|
||||||
chance for slowness: 2.0
|
|
||||||
|
|
||||||
poseidon:
|
|
||||||
default hit radius: 3.0
|
|
||||||
lightning hit damage: 4.0
|
|
||||||
|
|
||||||
rattlesnake:
|
|
||||||
maximum jump distance: 10.0
|
|
||||||
speed duration: 10.0
|
|
||||||
poison duration: 8.0
|
|
||||||
maximum negative effect duration: 16.0
|
|
||||||
default jump radius: 10.0
|
|
||||||
|
|
||||||
tesla:
|
|
||||||
disable push at height: 50.0
|
|
||||||
default thunder radius: 5.0
|
|
||||||
push strength: 1.0
|
|
||||||
fire tick duration: 5.0
|
|
||||||
time until thunder disables: 7.0
|
|
||||||
thunder damage: 1.5
|
|
||||||
|
|
||||||
voodoo:
|
|
||||||
default curse radius: 3.0
|
|
||||||
maximum effect duration: 15.0
|
|
||||||
clicked players minimum health: 10.0
|
|
||||||
voodoo hold duration: 5.0
|
|
||||||
chance for wither effect: 5.0
|
|
||||||
|
|
||||||
perks:
|
|
||||||
knockback:
|
|
||||||
knockback strength: 1.5
|
|
||||||
pullin:
|
|
||||||
pullin strength: 0.5
|
|
||||||
radiusincrease:
|
|
||||||
new radius: 5.0
|
|
||||||
34
src/main/resources/languages/en_US.yml
Normal file
34
src/main/resources/languages/en_US.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# SpeedHG v1.0.0 by McScrims-Network
|
||||||
|
# https://github.com/McScrims-Network
|
||||||
|
#
|
||||||
|
|
||||||
|
default:
|
||||||
|
prefix: '<gradient:dark_green:gold>McScrims</gradient> <dark_gray>|</dark_gray> <reset>'
|
||||||
|
|
||||||
|
game:
|
||||||
|
join: '<prefix><green><name></green> <gray>has joined the game.</gray>'
|
||||||
|
quit: '<prefix><red><name></red> <gray>has quit the game.</gray>'
|
||||||
|
|
||||||
|
player:
|
||||||
|
welcome: 'Welcome to <gradient:red:gold>SpeedHG</gradient>!'
|
||||||
|
|
||||||
|
scoreboard:
|
||||||
|
title: '<gradient:gold:yellow><bold>SpeedHG</bold></gradient>'
|
||||||
|
lobby:
|
||||||
|
- "<gray><st> "
|
||||||
|
- "Spieler: <green><online>/<max>"
|
||||||
|
- "Kit: <yellow><kit>"
|
||||||
|
- ""
|
||||||
|
- "<gray>Waiting for start..."
|
||||||
|
- ""
|
||||||
|
- "<yellow>play.mcscrims.club"
|
||||||
|
ingame:
|
||||||
|
- "<gray><st> "
|
||||||
|
- "Time: <green><timer>"
|
||||||
|
- "Players: <red><alive>"
|
||||||
|
- "Kills: <green><kills>"
|
||||||
|
- ""
|
||||||
|
- "Border: <red><border>"
|
||||||
|
- ""
|
||||||
|
- "<yellow>play.mcscrims.club"
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#
|
|
||||||
# |-----| |-----| |-----| |-----| |---\ | | |-----|
|
|
||||||
# | | | | | | \ | | |
|
|
||||||
# |-----| |-----| |---| |---| | | |-----| | |--|
|
|
||||||
# | | | | | / | | | |
|
|
||||||
# |-----| | |-----| |-----| |---/ | | |-----|
|
|
||||||
# v1.0.0 by TDSTOS
|
|
||||||
#
|
|
||||||
# Organization: McScrims-Network (https://github.com/McScrims-Network/)
|
|
||||||
# Owner: TDSTOS (https://github.com/TDSTOS)
|
|
||||||
# Contributors: stavgun (https://github.com/stavgun)
|
|
||||||
#
|
|
||||||
|
|
||||||
default:
|
|
||||||
prefix: '<gradient:dark_green:green>McScrims</gradient> <dark_gray>┃</dark_gray><reset>'
|
|
||||||
no_permission: '%prefix% <red>You don''t have permission to do that!</red>'
|
|
||||||
player_not_found: '%prefix% <red>This player could not be found!</red>'
|
|
||||||
command_cooldown: '%prefix% <red>Please wait {time} seconds before using this command again!</red>'
|
|
||||||
|
|
||||||
commands:
|
|
||||||
unknown: |-
|
|
||||||
%prefix% <red>Unknown subcommand: {unknown}</red>
|
|
||||||
%prefix% <gray>Use /{command} for an overview.</gray>
|
|
||||||
@@ -6,9 +6,4 @@ api-version: '1.21'
|
|||||||
depend:
|
depend:
|
||||||
- "WorldEdit"
|
- "WorldEdit"
|
||||||
- "Apollo-Bukkit"
|
- "Apollo-Bukkit"
|
||||||
- "McScrims-CoreSystem"
|
- "McScrims-CoreSystem"
|
||||||
|
|
||||||
commands:
|
|
||||||
kits:
|
|
||||||
description: Open the kit selection menu
|
|
||||||
usage: /kits
|
|
||||||
Reference in New Issue
Block a user