First commit

This commit is contained in:
Laurin
2025-12-01 03:45:44 +01:00
commit 0daabe3de2
18 changed files with 1304 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
package club.mcscrims.speedhg
import club.mcscrims.core.config.ConfigData
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.config.MessageConfig
import club.mcscrims.speedhg.config.PluginConfig
import club.mcscrims.speedhg.database.StatsRepository
import club.mcscrims.spigot.chat.ChatFormatter
import club.mcscrims.spigot.chat.ChatManager
import club.mcscrims.spigot.network.SpigotNetworkManager
import com.mongodb.client.model.Indexes
import kotlinx.coroutines.runBlocking
import net.luckperms.api.LuckPerms
import org.bukkit.plugin.java.JavaPlugin
class SpeedHG : JavaPlugin() {
companion object {
internal lateinit var instance: SpeedHG
}
private lateinit var configLoader: ConfigLoader
internal lateinit var pluginConfig: ConfigData<PluginConfig>
internal lateinit var messageConfig: ConfigData<MessageConfig>
internal lateinit var databaseConfig: ConfigData<DatabaseConfig>
internal lateinit var chatManager: ChatManager<MessageConfig>
internal lateinit var chatFormatter: ChatFormatter<MessageConfig>
private lateinit var mongoManager: MongoManager
internal lateinit var statsRepository: StatsRepository
internal lateinit var networkManager: SpigotNetworkManager
internal lateinit var luckPerms: LuckPerms
override fun onEnable()
{
instance = this
loadConfigurations()
setupDatabase()
networkManager = SpigotNetworkManager.getInstance()!!
chatFormatter = ChatFormatter.create(
plugin = this,
configClass = MessageConfig::class,
messageExtractor = { config -> config.getAllMessages() }
)
chatManager = ChatManager.withCustomConfig( this, chatFormatter )
chatManager.initialize()
setupLuckPerms()
}
override fun onDisable()
{
mongoManager.shutdown()
networkManager.shutdown()
}
/*
* 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 )
// 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" ))
}
catch ( ex: Exception ) {
logger.warning( "Failed to create MongoDB indexes: ${ex.message}" )
return@runBlocking
}
}
logger.info( "Successfully enabled 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
)
databaseConfig = configLoader.loadConfig<DatabaseConfig>(
fileName = "database.json",
format = ConfigFormat.JSON,
autoReload = false
)
}
fun reloadConfigurations()
{
try
{
pluginConfig.reload()
messageConfig.reload()
databaseConfig.reload()
}
catch ( ex: Exception ) {
logger.severe( "Failed to reload configurations: ${ex.message}" )
}
}
}

View File

@@ -0,0 +1,122 @@
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 = "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
}
}
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 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 )
)

View File

@@ -0,0 +1,36 @@
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()
) {
fun getAllMessages(): Map<String, String>
{
return defaultMessages + commandMessages
}
}
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>"
)
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>"
)

View File

@@ -0,0 +1,104 @@
package club.mcscrims.speedhg.config
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
@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 = 8,
val competitiveGame: Boolean = false,
val competitiveCommands: List<String> = emptyList(),
val playerState: Map<String, String> = 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()
)
}
private fun getPlayerStates() = mapOf(
"waiting" to "Waiting - %time%",
"pre_start" to "Waiting - %time%",
"immunity" to "Playing - %time%",
"battle" to "Playing - %time%",
"feast" to "Playing - %time%",
"deathmatch" to "Playing - %time%",
"end" to "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
)

View File

@@ -0,0 +1,200 @@
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 )
}
}