This commit is contained in:
disclearing 2022-09-06 21:35:47 +01:00
parent 32682243f2
commit 40b186170b
446 changed files with 26667 additions and 0 deletions

7
Shitty HCF/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
/gradlew.bat
/gradlew
/gradle/
/build/
/.idea/
/.gradle/
/libs/

81
Shitty HCF/build.gradle Normal file
View File

@ -0,0 +1,81 @@
plugins {
id "org.jetbrains.kotlin.kapt" version "$kotlin_version" apply true
id "org.jetbrains.kotlin.jvm" version "$kotlin_version"
id "com.github.johnrengelman.shadow" version "$shadow_version"
}
this.group = 'cc.fyre.hcf'
this.version = '1.0-SNAPSHOT'
this.description = 'hcf'
this.targetCompatibility = '1.8'
this.sourceCompatibility = '1.8'
shadowJar {
classifier = null
}
repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs 'libs'
}
}
apply plugin: "kotlin"
apply plugin: "kotlin-kapt"
apply plugin: 'maven-publish'
dependencies {
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
compileOnly "com.squareup.okhttp3:okhttp:$okhttp_version"
compileOnly "com.squareup.moshi:moshi-kotlin:$moshi_version"
compileOnly "com.squareup.moshi:moshi-adapters:$moshi_version"
compileOnly "cc.fyre.circuit:circuit:$circuit_version"
compileOnly "cc.fyre.core:bukkit:1.1-SNAPSHOT"
compileOnly "cc.fyre.modsuite:bukkit:1.0-SNAPSHOT"
compileOnly "cc.fyre.shard:v1_7:1.0-SNAPSHOT"
compileOnly "net.hylist:spigot-server:$spigot_version"
compileOnly "redis.clients:jedis:$redis_version"
compileOnly "com.squareup.retrofit2:retrofit:$retrofit_version"
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compileOnly 'com.comphenix.protocol:ProtocolLib:4.4.0'
implementation "org.mongodb:mongo-java-driver:$mongo_version"
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
}
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin/'
}
this.tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
shadowJar {
shadowJar.archiveName = this.name + "-" + this.version + ".jar"
}
publishing {
publications {
shadow(MavenPublication) {
publication -> project.shadow.component(publication)
}
}
}

View File

@ -0,0 +1,10 @@
moshi_version=1.12.0
redis_version=3.6.3
mongo_version=3.12.10
shadow_version=5.2.0
okhttp_version=4.9.1
kotlin_version=1.5.21
circuit_version=1.0-SNAPSHOT
retrofit_version=2.9.0
retrofit_converter_version=2.9.0
spigot_version=1.7.10-R0.1-SNAPSHOT

View File

@ -0,0 +1,2 @@
rootProject.name = 'hcf'

View File

@ -0,0 +1,191 @@
package cc.fyre.hcf
import cc.fyre.core.server.ServerModule
import cc.fyre.hcf.ability.AbilityModule
import cc.fyre.hcf.combatlogger.CombatLoggerModule
import cc.fyre.hcf.death.DeathModule
import cc.fyre.hcf.deathmessage.DeathMessageModule
import cc.fyre.hcf.map.engine.HCFNameTagAdapter
import cc.fyre.hcf.map.engine.HCFScoreboardAdapter
import cc.fyre.hcf.map.engine.HCFTabAdapter
import cc.fyre.hcf.faction.Faction
import cc.fyre.hcf.faction.FactionModule
import cc.fyre.hcf.faction.FactionType
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.hcf.game.GameFaction
import cc.fyre.hcf.game.GameModule
import cc.fyre.hcf.game.GameType
import cc.fyre.hcf.game.capture.CaptureZoneFaction
import cc.fyre.hcf.game.capture.type.CitadelFaction
import cc.fyre.hcf.game.capture.type.ConquestFaction
import cc.fyre.hcf.game.capture.type.FuryFaction
import cc.fyre.hcf.game.capture.type.KOTHFaction
import cc.fyre.hcf.game.other.DTCFaction
import cc.fyre.hcf.map.MapModule
import cc.fyre.hcf.mountain.MountainFaction
import cc.fyre.hcf.mountain.MountainModule
import cc.fyre.hcf.mountain.MountainType
import cc.fyre.hcf.mountain.type.CaveMountain
import cc.fyre.hcf.mountain.type.GlowstoneMountain
import cc.fyre.hcf.pillar.PillarModule
import cc.fyre.hcf.pvpclass.PvPClassModule
import cc.fyre.hcf.statistic.StatisticModule
import cc.fyre.hcf.timer.TimerModule
import cc.fyre.shard.command.CommandHandler
import cc.fyre.shard.moshi.MoshiUtil
import cc.fyre.shard.nametag.NameTagHandler
import cc.fyre.shard.scoreboard.ScoreboardHandler
import cc.fyre.shard.tab.TabHandler
import com.mongodb.MongoClient
import com.mongodb.client.MongoDatabase
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
import org.bukkit.Bukkit
import org.bukkit.plugin.Plugin
import org.bukkit.plugin.java.JavaPlugin
import org.github.paperspigot.PaperSpigotConfig
import org.spigotmc.SpigotConfig
import redis.clients.jedis.JedisPool
/**
* @project hcf
*
* @date 04/04/2020
* @author xanderume@gmail.com
*/
class HCF : JavaPlugin() {
private var kitMap: Plugin? = null
private var shutdown = false
private val modules = mutableListOf<HCFModule>()
private lateinit var mongoDB: MongoDatabase
private lateinit var mongoPool: MongoClient
private lateinit var redisPool: JedisPool
override fun onEnable() {
instance = this
this.redisPool = JedisPool()
this.mongoPool = MongoClient()
this.mongoDB = this.mongoPool.getDatabase(ServerModule.getServerId())
MoshiUtil.rebuild{
it.add(
PolymorphicJsonAdapterFactory.of(Faction::class.java,"TYPE")
.withSubtype(PlayerFaction::class.java,FactionType.PLAYER.name)
.withSubtype(SystemFaction::class.java,FactionType.SYSTEM.name)
)
it.add(
PolymorphicJsonAdapterFactory.of(MountainFaction::class.java,"MOUNTAIN")
.withSubtype(CaveMountain::class.java,MountainType.CAVE.name)
.withSubtype(GlowstoneMountain::class.java,MountainType.GLOWSTONE.name)
)
it.add(PolymorphicJsonAdapterFactory.of(GameFaction::class.java,FactionType.GAME.name)
.withSubtype(DTCFaction::class.java,GameType.DTC.name)
.withSubtype(KOTHFaction::class.java,GameType.KOTH.name)
)
it.add(PolymorphicJsonAdapterFactory.of(CaptureZoneFaction::class.java,"CAPTURE_ZONE")
.withSubtype(KOTHFaction::class.java,GameType.KOTH.name)
.withSubtype(FuryFaction::class.java,GameType.FURY.name)
.withSubtype(ConquestFaction::class.java,GameType.CONQUEST.name)
)
it.add(PolymorphicJsonAdapterFactory.of(KOTHFaction::class.java,GameType.KOTH.name)
.withSubtype(CitadelFaction::class.java,GameType.CITADEL.name)
)
}
this.registerModule(MapModule)
this.registerModule(DeathModule)
this.registerModule(TimerModule)
this.registerModule(PillarModule)
this.registerModule(FactionModule)
this.registerModule(AbilityModule)
this.registerModule(PvPClassModule)
this.registerModule(StatisticModule)
this.registerModule(GameModule)
this.registerModule(MountainModule)
this.registerModule(DeathMessageModule)
this.registerModule(CombatLoggerModule)
SpigotConfig.instantRespawn = true
SpigotConfig.reduceArmorDamage = true
SpigotConfig.brewingMultiplier = 4
SpigotConfig.smeltingMultiplier = 4
TabHandler.setAdapter(HCFTabAdapter)
NameTagHandler.setAdapter(HCFNameTagAdapter)
ScoreboardHandler.setAdapter(HCFScoreboardAdapter)
CommandHandler.registerAll(this)
PaperSpigotConfig.strengthEffectModifier = 0.3
this.modules.forEach{it.onLateLoad(this)}
this.server.scheduler.runTaskTimerAsynchronously(this,{this.modules.forEach{it.onSave(this)}},HCFModule.SAVE_INTERVAL,HCFModule.SAVE_INTERVAL)
}
override fun onDisable() {
this.shutdown = true
this.modules.forEach{
it.shutdown(this)
}
// has to be last
this.mongoPool.close()
this.redisPool.close()
}
fun registerModule(module: HCFModule) {
this.modules.add(module)
module.init(this)
module.getCommands().forEach{CommandHandler.registerClass(it)}
module.getAdapters().forEach{CommandHandler.registerAdapter(it.key,it.value)}
module.getListeners().forEach{Bukkit.getServer().pluginManager.registerEvents(it,this)}
this.modules.add(module)
}
fun isKitMap():Boolean {
if (this.kitMap == null) {
this.kitMap = Bukkit.getPluginManager().getPlugin("KitMap") ?: null
}
return this.kitMap != null && this.kitMap!!.isEnabled
}
fun isInShutdownState():Boolean {
return this.shutdown
}
fun getMongoDB():MongoDatabase {
return this.mongoDB
}
fun getRedisPool():JedisPool {
return this.redisPool
}
companion object {
lateinit var instance: HCF
}
}

View File

@ -0,0 +1,24 @@
package cc.fyre.hcf
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import org.bukkit.event.Listener
interface HCFModule {
fun init(core: HCF)
fun shutdown(core: HCF)
fun onSave(core: HCF) {}
fun onLateLoad(core: HCF) {}
fun getCommands():List<Class<*>>
fun getAdapters():Map<Class<*>, ParameterAdapter<*>>
fun getListeners():List<Listener>
companion object {
const val SAVE_INTERVAL = 5L * (60L * 20L)
}
}

View File

@ -0,0 +1,142 @@
package cc.fyre.hcf.ability
import cc.fyre.core.api.ApiHandler
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.event.AbilityUseEvent
import cc.fyre.shard.util.item.ItemBuilder
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.PacketAdapter
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.potion.PotionEffectType
import kotlin.collections.ArrayList
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
abstract class Ability(val id: String, val cooldown: Long) : Listener {
private var enabled = true
lateinit var item: ItemStack
lateinit var idLowerCase: String
fun init() {
this.item = this.build()
this.idLowerCase = this.id.lowercase()
}
private fun build():ItemStack {
return ItemBuilder.copyOf(this.getItemStack()).name(this.getDisplayName()).lore(this.getFullDescription()).build()
}
open fun getCrate():String {
return "${ChatColor.DARK_PURPLE}${ChatColor.BOLD}Items"
}
open fun getFullDescription():List<String> {
val lore = arrayListOf<String>()
lore.add(" ")
lore.addAll(this.getDescription())
lore.add(" ")
lore.add("${ChatColor.GRAY}Available at: ${ChatColor.YELLOW}${ChatColor.BOLD}${ChatColor.UNDERLINE}${ApiHandler.getStoreUrl()}")
return lore
}
fun isEnabled():Boolean {
return this.enabled
}
fun setEnabled(value: Boolean) {
if (this.enabled == value) {
return
}
if (value) {
Bukkit.getServer().pluginManager.registerEvents(this,HCF.instance)
} else {
HandlerList.unregisterAll(this)
}
this.enabled = value
}
abstract fun getUses():Int
abstract fun getPrice():Int
abstract fun getItemStack():ItemStack
abstract fun getDisplayName():String
abstract fun getDescription():ArrayList<String>
abstract fun onPlayerInteract(event: PlayerInteractEvent)
open fun isSpawnTag():Boolean {
return false
}
open fun isInteractAble():Boolean {
return true
}
open fun isScoreboardDisplay():Boolean {
return true
}
protected fun callEvent(player: Player):AbilityUseEvent {
return this.callEvent(player,player.location)
}
protected fun callEvent(player: Player,location: Location):AbilityUseEvent {
return AbilityUseEvent(this,player,location).call()
}
fun isSimilar(stack: ItemStack?): Boolean {
if (stack == null) {
return false
}
if (stack.typeId != this.item.typeId) {
return false
}
if (stack.hasItemMeta() != this.item.hasItemMeta()) {
return false
}
return Bukkit.getServer().itemFactory.equals(stack.itemMeta,this.item.itemMeta)
}
fun getDisplayName(player: Player):String {
if (player.hasPotionEffect(PotionEffectType.INVISIBILITY)) {
return "???"
}
return ProfileHandler.getDisplayNameById(player.uniqueId)
}
companion object {
val COUNTDOWN_COLORS = mapOf(
5 to ChatColor.DARK_GREEN,
4 to ChatColor.GREEN,
3 to ChatColor.RED,
2 to ChatColor.GOLD,
1 to ChatColor.YELLOW
)
}
}

View File

@ -0,0 +1,85 @@
package cc.fyre.hcf.ability
import cc.fyre.hcf.HCF
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import com.comphenix.protocol.ProtocolLibrary
import com.google.common.collect.HashBasedTable
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
import java.lang.Exception
import java.util.*
import kotlin.math.max
object AbilityHandler {
private val abilities = mutableMapOf<String, Ability>()
private val abilitiesByItem = mutableMapOf<Material,MutableList<Ability>>()
private val cooldowns = HashBasedTable.create<UUID,String,Long>()
fun register(ability: Ability) {
ability.init()
this.abilities[ability.idLowerCase] = ability
this.abilitiesByItem.getOrPut(ability.item.type) { mutableListOf() }.add(ability)
Bukkit.getServer().pluginManager.registerEvents(ability,HCF.instance)
}
fun getAllAbilities():List<Ability> {
return this.abilities.values.toList()
}
fun getAbilityById(id: String): Ability? {
return this.abilities[id.lowercase()]
}
fun getAbilityByItemStack(item: ItemStack): Ability? {
if (item.itemMeta == null || item.itemMeta.lore == null || item.itemMeta.displayName == null) {
return null
}
val byType = this.abilitiesByItem[item.type]
if (byType == null || byType.isEmpty()) {
return null
}
return byType.firstOrNull{it.item.durability == item.durability
&& it.item.itemMeta.lore.size == item.itemMeta.lore.size
&& it.item.itemMeta.displayName == item.itemMeta.displayName
}
}
fun getCooldown(uuid: UUID,ability: Ability):Long {
if (!this.cooldowns.contains(uuid,ability.idLowerCase)) {
return TimerHandler.getRemaining(uuid, TimerType.PARTNER_ITEM)
}
return max(
this.cooldowns[uuid,ability.idLowerCase]!! - System.currentTimeMillis(),
TimerHandler.getRemaining(uuid, TimerType.PARTNER_ITEM)
)
}
fun setCooldown(uuid: UUID, ability: Ability, duration: Long = ability.cooldown) {
if (duration <= 0L) {
this.cooldowns.remove(uuid,ability.idLowerCase)
} else {
this.cooldowns.put(uuid,ability.idLowerCase,System.currentTimeMillis() + duration)
}
}
fun getAllCooldowns(uuid: UUID):Map<Ability,Long> {
return this.cooldowns.row(uuid).entries
.associate{this.abilities[it.key]!! to (it.value - System.currentTimeMillis())}
.filter{it.value > 0L}
}
}

View File

@ -0,0 +1,69 @@
package cc.fyre.hcf.ability
import cc.fyre.hcf.HCF
import cc.fyre.hcf.HCFModule
import cc.fyre.hcf.ability.command.AbilityCommand
import cc.fyre.hcf.ability.command.AbilityGiveCommand
import cc.fyre.hcf.ability.command.AbilityCooldownCommand
import cc.fyre.hcf.ability.command.parameter.AbilityParameterProvider
import cc.fyre.hcf.ability.pocketbard.PocketBard
import cc.fyre.hcf.ability.pocketbard.PocketBardAbility
import cc.fyre.hcf.ability.pocketbard.PocketBardType
import cc.fyre.hcf.ability.listener.AbilityListener
import cc.fyre.hcf.ability.type.*
import cc.fyre.hcf.ability.type.invisibility.Invisibility
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import org.bukkit.event.Listener
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object AbilityModule : HCFModule {
override fun init(core: HCF) {
AbilityHandler.register(PocketBard)
for (type in PocketBardType.values()) {
AbilityHandler.register(PocketBardAbility(type))
}
AbilityHandler.register(Combo)
AbilityHandler.register(Rocket)
AbilityHandler.register(Grapple)
AbilityHandler.register(EggPort)
AbilityHandler.register(TimeWarp)
AbilityHandler.register(NinjaStar)
AbilityHandler.register(AntiPearl)
AbilityHandler.register(FocusMode)
AbilityHandler.register(Invisibility)
AbilityHandler.register(AntiBuildBone)
}
override fun shutdown(core: HCF) {}
override fun getCommands(): List<Class<*>> {
return listOf(
AbilityCommand::class.java,
AbilityGiveCommand::class.java,
AbilityCooldownCommand::class.java
)
}
override fun getAdapters(): Map<Class<*>, ParameterAdapter<*>> {
return mapOf(
Ability::class.java to AbilityParameterProvider
)
}
override fun getListeners(): List<Listener> {
return listOf(
AbilityListener
)
}
}

View File

@ -0,0 +1,15 @@
package cc.fyre.hcf.ability.command
import cc.fyre.hcf.ability.menu.AbilityMenu
import cc.fyre.shard.command.data.command.Command
import org.bukkit.entity.Player
object AbilityCommand {
@JvmStatic
@Command(names = ["ability","partneritem","partneritems"],permission = "")
fun execute(sender: Player) {
AbilityMenu().open(sender)
}
}

View File

@ -0,0 +1,29 @@
package cc.fyre.hcf.ability.command
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.hcf.ability.Ability
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.shard.command.data.parameter.impl.PlayerParameterAdapter
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
object AbilityCooldownCommand {
@JvmStatic
@Command(names = ["ability cooldown","partneritem cooldown"],permission = "hcf.command.ability.cooldown")
fun execute(sender: CommandSender,
@Parameter(name = "ability")ability: Ability,
@Parameter(name = "player",defaultValue = PlayerParameterAdapter.SELF_KEY_WORD)target: Player
) {
if (sender !is Player || sender.uniqueId != target.uniqueId) {
sender.sendMessage("${ChatColor.GOLD}You have reset ${ProfileHandler.getDisplayNameById(target.uniqueId)}${ChatColor.GOLD}'s ${ability.getDisplayName()}${ChatColor.GOLD} cooldown.")
}
AbilityHandler.setCooldown(target.uniqueId,ability,0L)
}
}

View File

@ -0,0 +1,37 @@
package cc.fyre.hcf.ability.command
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.hcf.ability.Ability
import cc.fyre.shard.command.data.parameter.impl.PlayerParameterAdapter
import cc.fyre.shard.util.item.ItemBuilder
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object AbilityGiveCommand {
const val PERMISSION = "hcf.command.ability.give"
@JvmStatic
@Command(names = ["ability give","partneritem give"],permission = PERMISSION)
fun execute(sender: CommandSender,
@Parameter(name = "ability")ability: Ability,
@Parameter(name = "amount",defaultValue = "1")amount: Int,
@Parameter(name = "player",defaultValue = PlayerParameterAdapter.SELF_KEY_WORD)target: Player
) {
if (sender !is Player || sender.uniqueId != target.uniqueId) {
sender.sendMessage("${ChatColor.GOLD}You gave ${ProfileHandler.getDisplayNameById(target.uniqueId)}${ChatColor.RED} $amount ${ability.getDisplayName()}${ChatColor.GOLD}'s}.")
}
target.inventory.addItem(ItemBuilder.copyOf(ability.item.clone()).amount(amount).build())
}
}

View File

@ -0,0 +1,34 @@
package cc.fyre.hcf.ability.command.parameter
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.hcf.ability.Ability
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object AbilityParameterProvider : ParameterAdapter<Ability?> {
override fun transform(sender: CommandSender,source: String): Ability? {
val toReturn = AbilityHandler.getAbilityById(source)
if (toReturn == null) {
sender.sendMessage(ChatColor.RED.toString() + "Ability " + ChatColor.YELLOW + source + ChatColor.RED + " not found.")
return null
}
return toReturn
}
override fun tabComplete(player: Player, flags: Set<String>, source: String): List<String> {
return AbilityHandler.getAllAbilities().filter{it.idLowerCase.startsWith(source,true)}.map{it.id}
}
}

View File

@ -0,0 +1,43 @@
package cc.fyre.hcf.ability.event
import cc.fyre.hcf.ability.Ability
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.event.Cancellable
import org.bukkit.event.Event
import org.bukkit.event.HandlerList
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
class AbilityUseEvent(val ability: Ability, val player: Player, val location: Location = player.location, var cooldown: Long = ability.cooldown) : Event(),Cancellable {
private var cancelled = false
override fun isCancelled(): Boolean {
return this.cancelled
}
override fun setCancelled(value: Boolean) {
this.cancelled = value
}
override fun getHandlers(): HandlerList {
return handlerList
}
fun call():AbilityUseEvent {
Bukkit.getServer().pluginManager.callEvent(this)
return this
}
companion object {
@JvmStatic val handlerList = HandlerList()
}
}

View File

@ -0,0 +1,124 @@
package cc.fyre.hcf.ability.listener
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.hcf.ability.event.AbilityUseEvent
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import cc.fyre.shard.util.TimeUtil
import org.bukkit.ChatColor
import org.bukkit.Sound
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerItemDamageEvent
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object AbilityListener : Listener {
@EventHandler(priority = EventPriority.HIGHEST)
private fun onPlayerInteract(event: PlayerInteractEvent) {
if (event.action == Action.LEFT_CLICK_BLOCK || event.action == Action.LEFT_CLICK_AIR) {
return
}
if (event.item == null) {
return
}
val ability = AbilityHandler.getAbilityByItemStack(event.item) ?: return
if (!ability.isInteractAble()) {
return
}
if (ability.cooldown > 0L) {
val cooldown = AbilityHandler.getCooldown(event.player.uniqueId,ability)
if (cooldown > 0) {
event.isCancelled = true
event.player.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${if (cooldown > 60000L) TimeUtil.formatIntoDetailedString(cooldown) else TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
event.player.updateInventory()
return
}
}
ability.onPlayerInteract(event)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onAbilityUse(event: AbilityUseEvent) {
if (event.isCancelled) {
return
}
AbilityHandler.setCooldown(event.player.uniqueId,event.ability)
if (event.ability.isSpawnTag()) {
TimerHandler.addTimer(event.player.uniqueId, TimerType.SPAWN_TAG)
}
if (event.ability.cooldown > 0L) {
TimerHandler.addTimer(event.player.uniqueId, TimerType.PARTNER_ITEM)
}
if (event.ability.getUses() == -1) {
return
}
if (event.ability.getUses() <= 1) {
if (event.player.itemInHand.amount == 1) {
event.player.itemInHand = null
} else {
event.player.itemInHand.amount = event.player.itemInHand.amount - 1
}
return
}
val durability = event.player.itemInHand.type.maxDurability / event.ability.getUses()
if (event.player.itemInHand.durability + durability >= event.player.itemInHand.type.maxDurability) {
if (event.player.itemInHand.amount == 1) {
event.player.itemInHand = null
} else {
event.player.itemInHand.amount = event.player.itemInHand.amount - 1
}
event.player.world.playSound(event.player.location,Sound.ITEM_BREAK,1.0F,1.0F)
} else {
event.player.itemInHand.durability = (event.player.itemInHand.durability + durability).toShort()
}
event.player.updateInventory()
}
@EventHandler(priority = EventPriority.LOWEST)
private fun onItemDamage(event: PlayerItemDamageEvent) {
if (AbilityHandler.getAbilityByItemStack(event.item) == null) {
return
}
if (event.damage <= 0) {
return
}
event.isCancelled = true
event.player.updateInventory()
}
}

View File

@ -0,0 +1,54 @@
package cc.fyre.hcf.ability.menu
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.ability.command.AbilityGiveCommand
import cc.fyre.shard.menu.button.Button
import cc.fyre.shard.menu.type.ConfirmMenu
import cc.fyre.shard.util.item.ItemBuilder
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
import java.util.function.Predicate
class AbilityButton(private val ability: Ability) : Button() {
override fun getItem(player: Player): ItemStack {
if (!this.ability.isEnabled()) {
return ItemBuilder.of(Material.BEDROCK)
.name("${ChatColor.RED}${ChatColor.BOLD}${ChatColor.STRIKETHROUGH}${ChatColor.stripColor(this.ability.getDisplayName())}")
.lore(this.ability.getFullDescription())
.build()
}
return this.ability.item
}
override fun onClick(player: Player, event: InventoryClickEvent) {
if (!player.hasPermission(AbilityGiveCommand.PERMISSION)) {
return
}
if (event.click == ClickType.MIDDLE) {
object : ConfirmMenu("${if (ability.isEnabled()) "Disable" else "Enable"}?", Predicate{value ->
if (value) {
ability.setEnabled(!ability.isEnabled())
}
AbilityMenu().open(player)
return@Predicate true
}) {
}.open(player)
return
}
player.inventory.addItem(this.ability.item)
}
}

View File

@ -0,0 +1,21 @@
package cc.fyre.hcf.ability.menu
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.shard.menu.Menu
import cc.fyre.shard.menu.button.Button
import org.bukkit.entity.Player
class AbilityMenu : Menu() {
override fun getTitle(player: Player): String {
return "Abilities"
}
override fun getButtons(player: Player): MutableMap<Int, Button> {
return AbilityHandler.getAllAbilities()
.withIndex()
.associate{it.index to AbilityButton(it.value)}
.toMutableMap()
}
}

View File

@ -0,0 +1,49 @@
package cc.fyre.hcf.ability.pocketbard
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.ability.Ability
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object PocketBard : Ability("pocketbard",0L) {
const val AMOUNT = 5
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemBuilder.of(Material.INK_SACK).data(14).build()
}
override fun getDisplayName(): String {
return "${ChatColor.GOLD}${ChatColor.BOLD}Pocket Bard"
}
override fun getDescription(): ArrayList<String> {
val description = arrayListOf<String>()
description.add("${ChatColor.GOLD}Receive ${ChatColor.RED}${ChatColor.BOLD}$AMOUNT${ChatColor.GOLD} portable bard effects!")
return description
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
PocketBardMenu.open(event.player)
}
}

View File

@ -0,0 +1,85 @@
package cc.fyre.hcf.ability.pocketbard
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.faction.FactionMetadata
import cc.fyre.hcf.map.sotw.SOTWHandler
import cc.fyre.hcf.pvpclass.PvPClassHandler
import cc.fyre.hcf.pvpclass.event.type.BardEffectEvent
import cc.fyre.hcf.pvpclass.type.bard.BardClass
import cc.fyre.hcf.pvpclass.type.bard.effect.BardEnergyEffect
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import cc.fyre.shard.util.TimeUtil
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import java.util.concurrent.TimeUnit
class PocketBardAbility(private val type: PocketBardType) : Ability("pocketbard_${type.name.lowercase()}",TimeUnit.MINUTES.toMillis(2L)) {
private val bardEffect = BardEnergyEffect(this.type.material,0,null,this.type.effect)
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 1000
}
override fun isSpawnTag(): Boolean {
return true
}
override fun isScoreboardDisplay(): Boolean {
return false
}
override fun getItemStack(): ItemStack {
return ItemStack(this.type.material)
}
override fun getDisplayName(): String {
return this.type.getDisplayName().split(" ")[0]
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Give you and your teammates",
"${ChatColor.RED}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(((this.type.effect.duration / 20) - 1) * 1000L)}${ChatColor.GOLD} of ${this.type.getDisplayName()}${ChatColor.GOLD}!"
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
event.isCancelled = true
if (FactionMetadata.SAFE_ZONE.isValidAtLocation(event.player.location)) {
event.player.sendMessage("${ChatColor.RED}Pocket effects cannot be used while in spawn.")
return
}
if (TimerHandler.hasTimer(event.player.uniqueId,TimerType.PVP_TIMER)) {
event.player.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} whilst having an active PvP Timer!")
return
}
if (SOTWHandler.isActive() && SOTWHandler.isProtected(event.player)) {
event.isCancelled = true
event.player.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} whilst having an active SOTW Timer!")
return
}
if (this.callEvent(event.player).isCancelled) {
return
}
val players = BardClass.getNearbyPlayers(event.player,BardClass.DEFAULT_RADIUS,this.type.effect).toMutableList()
players.forEach{PvPClassHandler.addPotionEffect(it,this.type.effect)}
players.remove(event.player)
Bukkit.getServer().pluginManager.callEvent(BardEffectEvent(event.player,players,this.bardEffect))
}
}

View File

@ -0,0 +1,49 @@
package cc.fyre.hcf.ability.pocketbard
import cc.fyre.shard.menu.button.Button
import cc.fyre.shard.util.item.ItemBuilder
import org.bukkit.ChatColor
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
class PocketBardButton(private val type: PocketBardType) : Button() {
override fun getItem(player: Player): ItemStack {
return ItemBuilder.of(this.type.material)
.name(this.type.getDisplayName())
.build()
}
override fun onClick(player: Player, event: InventoryClickEvent) {
var pocketBard: ItemStack? = null
for (content in player.inventory.contents.filterNotNull().sortedBy{it.amount}) {
if (PocketBard.isSimilar(content)) {
pocketBard = content
break
}
}
if (pocketBard == null) {
player.closeInventory()
player.sendMessage("${ChatColor.RED}You have no more pocket bards!")
return
}
if (pocketBard.amount <= 1) {
player.inventory.removeItem(pocketBard)
player.closeInventory()
} else {
pocketBard.amount = pocketBard.amount - 1
}
player.inventory.addItem(ItemBuilder.copyOf(this.type.getAbility().item.clone())
.amount(PocketBard.AMOUNT)
.build()
)
}
}

View File

@ -0,0 +1,38 @@
package cc.fyre.hcf.ability.pocketbard
import cc.fyre.shard.menu.Menu
import cc.fyre.shard.menu.button.Button
import org.bukkit.entity.Player
object PocketBardMenu : Menu() {
// Static menu, no point in recreating everything
private const val SIZE = 3*9
private const val TITLE = "Select an effect."
private val BUTTONS = mutableMapOf<Int, Button>(
11 to PocketBardButton(PocketBardType.SPEED),
12 to PocketBardButton(PocketBardType.JUMP_BOOST),
13 to PocketBardButton(PocketBardType.STRENGTH),
14 to PocketBardButton(PocketBardType.RESISTANCE),
15 to PocketBardButton(PocketBardType.REGENERATION),
)
override fun isFill(player: Player, buttons: Map<Int, Button>): Boolean {
return true
}
override fun getSize(player: Player, buttons: Map<Int, Button>): Int {
return SIZE
}
override fun getTitle(player: Player): String {
return TITLE
}
override fun getButtons(player: Player): MutableMap<Int, Button> {
return BUTTONS
}
}

View File

@ -0,0 +1,38 @@
package cc.fyre.hcf.ability.pocketbard
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.shard.util.NumberUtil
import cc.fyre.shard.util.bukkit.PotionUtil
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.potion.PotionEffect
import org.bukkit.potion.PotionEffectType
enum class PocketBardType(val material: Material, val effect: PotionEffect, private var ability: PocketBardAbility? = null, private var displayName: String? = null) {
SPEED(Material.SUGAR,PotionEffect(PotionEffectType.SPEED,6*20,2)),
JUMP_BOOST(Material.FEATHER,PotionEffect(PotionEffectType.JUMP,6*20,6)),
STRENGTH(Material.BLAZE_POWDER,PotionEffect(PotionEffectType.INCREASE_DAMAGE,5*20,1)),
RESISTANCE(Material.IRON_INGOT,PotionEffect(PotionEffectType.DAMAGE_RESISTANCE,6*20,2)),
REGENERATION(Material.GHAST_TEAR,PotionEffect(PotionEffectType.REGENERATION,6*20,2));
//INVISIBILITY(Material.INK_SACK,PotionEffect(PotionEffectType.INVISIBILITY,46 *20,0));
fun getAbility():PocketBardAbility {
if (this.ability == null) {
this.ability = AbilityHandler.getAbilityById("pocketbard_${this.name.lowercase()}")!! as PocketBardAbility
}
return this.ability!!
}
fun getDisplayName():String {
if (this.displayName == null) {
this.displayName = "${PotionUtil.getColor(this.effect.type)}${ChatColor.BOLD}${PotionUtil.getName(this.effect.type)} ${NumberUtil.toRoman(this.effect.amplifier + 1)}"
}
return this.displayName!!
}
}

View File

@ -0,0 +1,170 @@
package cc.fyre.hcf.ability.type
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.hcf.ability.Ability
import cc.fyre.shard.util.TimeUtil
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.block.Action
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object AntiBuildBone : Ability("antibuild",TimeUnit.SECONDS.toMillis(90L)) {
private val hits = mutableMapOf<UUID,HashMap<UUID,AtomicInteger>>()
override fun getUses(): Int {
return 4
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.BONE)
}
override fun getDisplayName(): String {
return "${ChatColor.YELLOW}${ChatColor.BOLD}Anti-Build Bone"
}
override fun getDescription():ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Hit a player ${ChatColor.RED}${ChatColor.BOLD}$HIT_AMOUNT times ${ChatColor.GOLD}to prevent them",
"${ChatColor.GOLD}from placing blocks for ${ChatColor.YELLOW}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(PLACE_COOLDOWN)}${ChatColor.GOLD}."
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {}
@EventHandler(priority = EventPriority.LOWEST)
private fun onBlockPlace(event: BlockPlaceEvent) {
if (event.isCancelled) {
return
}
val cooldown = getCooldown(event.player)
if (cooldown <= 0L) {
return
}
event.isCancelled = true
event.player.sendMessage("${ChatColor.RED}You cannot do this for another ${ChatColor.BOLD}${TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
}
@EventHandler(priority = EventPriority.LOWEST)
private fun onPlayerInteract2(event: PlayerInteractEvent) {
if (event.action != Action.RIGHT_CLICK_BLOCK || event.clickedBlock == null || event.clickedBlock.type != Material.FENCE_GATE && !event.clickedBlock.type.name.contains("DOOR")) {
return
}
val cooldown = getCooldown(event.player)
if (cooldown <= 0L) {
return
}
event.isCancelled = true
event.player.sendMessage("${ChatColor.RED}You cannot do this for another ${ChatColor.BOLD}${TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
}
override fun isInteractAble(): Boolean {
return false
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
if (event.isCancelled) {
return
}
val player = event.entity
if (player !is Player || event.damager !is Player) {
return
}
val damager = event.damager as Player
if (!this.isSimilar(damager.itemInHand)) {
return
}
var cooldown = AbilityHandler.getCooldown(damager.uniqueId,this)
if (cooldown > 0) {
event.isCancelled = true
damager.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${if (cooldown > 60000L) TimeUtil.formatIntoDetailedString(cooldown) else TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
damager.updateInventory()
return
}
cooldown = getCooldown(player)
if (cooldown > 0L) {
damager.sendMessage("${this.getDisplayName(player)}${ChatColor.RED} is already on a block up cooldown for another ${ChatColor.BOLD}${TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
return
}
this.hits.putIfAbsent(damager.uniqueId,HashMap())
this.hits[damager.uniqueId]!!.putIfAbsent(player.uniqueId,AtomicInteger())
if (this.hits[damager.uniqueId]!![player.uniqueId]!!.get() < HIT_AMOUNT) {
return
}
if (this.callEvent(damager).isCancelled) {
return
}
damager.sendMessage("${ChatColor.GOLD}You have hit ${this.getDisplayName(player)} with a ${this.getDisplayName()}${ChatColor.GOLD}.")
player.sendMessage("${ChatColor.GOLD}You have been hit with a ${this.getDisplayName()}${ChatColor.GOLD} and cannot place blocks for ${ChatColor.YELLOW}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(
PLACE_COOLDOWN
)}${ChatColor.GOLD}.")
this.hits[damager.uniqueId]!!.remove(player.uniqueId)
cache[player.uniqueId] = System.currentTimeMillis()
}
private val cache = mutableMapOf<UUID,Long>()
private const val HIT_AMOUNT = 3
private const val PLACE_COOLDOWN = 15_000L
fun getCooldown(player: Player):Long {
if (!this.cache.containsKey(player.uniqueId)) {
return 0L
}
return (this.cache[player.uniqueId]!! + PLACE_COOLDOWN) - System.currentTimeMillis()
}
}

View File

@ -0,0 +1,102 @@
package cc.fyre.hcf.ability.type
import cc.fyre.shard.util.TimeUtil
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.block.Action
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 01/01/2021
* @author xanderume@gmail.com
*/
object AntiPearl : Ability("antipearl",TimeUnit.MINUTES.toMillis(3L)) {
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 2500
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.EYE_OF_ENDER)
}
override fun getDisplayName(): String {
return "${ChatColor.RED}${ChatColor.BOLD}Anti Pearl"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Hit a player to put them on",
"${ChatColor.GOLD}pearl cooldown for ${ChatColor.YELLOW}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(TimerType.ENDER_PEARL.duration)}${ChatColor.GOLD}."
)
}
override fun isInteractAble(): Boolean {
return false
}
override fun onPlayerInteract(event: PlayerInteractEvent) {}
@EventHandler(priority = EventPriority.NORMAL)
private fun onPlayerInteract2(event: PlayerInteractEvent) {
if (event.action == Action.LEFT_CLICK_AIR || event.action == Action.LEFT_CLICK_BLOCK || event.action == Action.PHYSICAL) {
return
}
if (event.item == null || !this.isSimilar(event.item)) {
return
}
event.isCancelled = true
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
if (event.isCancelled || event.entity !is Player || event.damager !is Player) {
return
}
val player = event.entity as Player
val damager = event.damager as Player
if (!this.isSimilar(damager.itemInHand)) {
return
}
val cooldown = AbilityHandler.getCooldown(damager.uniqueId,this)
if (cooldown > 0) {
damager.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
damager.updateInventory()
return
}
if (this.callEvent(damager).isCancelled) {
return
}
TimerHandler.addTimer(event.entity.uniqueId, TimerType.ENDER_PEARL)
player.sendMessage("${ChatColor.GOLD}You have been hit with an ${this.getDisplayName()}${ChatColor.GOLD}.")
damager.sendMessage("${ChatColor.GOLD}You have hit ${this.getDisplayName(player)}${ChatColor.RED} with an ${this.getDisplayName()}${ChatColor.RED}.")
}
}

View File

@ -0,0 +1,84 @@
package cc.fyre.hcf.ability.type
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.faction.type.SystemFaction
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.block.Action
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.metadata.FixedMetadataValue
import java.util.concurrent.TimeUnit
object AntiTrap : Ability("antitrap",TimeUnit.MINUTES.toMillis(5L)) {
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 10_000
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.BEACON)
}
override fun getDisplayName(): String {
return "${ChatColor.DARK_AQUA}${ChatColor.BOLD}Anti-Trap"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Place this beacon to prevent all blocks",
"${ChatColor.GOLD}within an ${ChatColor.RED}${ChatColor.BOLD}$RADIUS block ${ChatColor.GOLD} from being placed",
"${ChatColor.GOLD}for a period of ${ChatColor.YELLOW}${ChatColor.BOLD}$DURATION seconds${ChatColor.GOLD}.",
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {}
@EventHandler(priority = EventPriority.MONITOR)
private fun onBlockPlace(event: BlockPlaceEvent) {
if (!event.player.itemInHand.isSimilar(this.item)) {
return
}
val faction = FactionHandler.getFactionByLocation(event.block.location)
if (faction is SystemFaction) {
return
}
if (this.callEvent(event.player).isCancelled) {
event.isCancelled = true
return
}
event.block.setMetadata(METADATA,FixedMetadataValue(HCF.instance,HITS))
event.isCancelled = false
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onPlayerInteract2(event: PlayerInteractEvent) {
if (event.action != Action.LEFT_CLICK_BLOCK) {
return
}
if (event.clickedBlock == null || event.clickedBlock.type != Material.BEACON) {
return
}
}
private const val HITS = 10
private const val RADIUS = 8
private const val DURATION = 30
private const val METADATA = "ANTI_TRAP"
}

View File

@ -0,0 +1,122 @@
package cc.fyre.hcf.ability.type
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.Ability
import cc.fyre.shard.util.NumberUtil
import cc.fyre.shard.util.TimeUtil
import cc.fyre.shard.util.bukkit.PotionUtil
import cc.fyre.shard.util.item.ItemBuilder
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.entity.Projectile
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.potion.PotionEffect
import org.bukkit.potion.PotionEffectType
import org.bukkit.scheduler.BukkitRunnable
import org.bukkit.scheduler.BukkitTask
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.ArrayList
object Combo : Ability("combo",TimeUnit.MINUTES.toMillis(4L)) {
private val hits = mutableMapOf<UUID,AtomicInteger>()
private val tasks = mutableMapOf<UUID,BukkitTask>()
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 4000
}
override fun getItemStack(): ItemStack {
return ItemBuilder.of(Material.RAW_FISH)
.data(3)
.build()
}
override fun getDisplayName(): String {
return "${ChatColor.RED}${ChatColor.BOLD}Combo"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Begin a ${ChatColor.YELLOW}${ChatColor.BOLD}${DURATION_PERIOD} second ${ChatColor.GOLD}period where each",
"${ChatColor.GOLD}hit results in a second of ${PotionUtil.getDisplayName(EFFECT_TYPE)} ${NumberUtil.toRoman(EFFECT_AMPLIFIER)}${ChatColor.GOLD}.",
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
if (this.callEvent(event.player).isCancelled) {
return
}
this.hits[event.player.uniqueId] = AtomicInteger()
this.tasks[event.player.uniqueId] = object : BukkitRunnable() {
override fun run() {
this@Combo.tasks.remove(event.player.uniqueId)
this@Combo.hits.remove(event.player.uniqueId)?.get()?.also{
if (it <= 0) {
return@also
}
if (!event.player.isOnline) {
return@also
}
var duration = it
if (duration > DURATION_LIMIT) {
duration = DURATION_LIMIT
}
event.player.addPotionEffect(PotionEffect(EFFECT_TYPE, (duration * 20),EFFECT_AMPLIFIER - 1))
event.player.sendMessage("${this@Combo.getDisplayName()}${ChatColor.GOLD} has activated you now have ${ChatColor.YELLOW}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(duration * 1000L)}${ChatColor.GOLD} of ${PotionUtil.getDisplayName(
EFFECT_TYPE
)} ${NumberUtil.toRoman(EFFECT_AMPLIFIER)}${ChatColor.GOLD}.")
}
}
}.runTaskLater(HCF.instance,DURATION_PERIOD * 20L)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
val damager = if (event.damager is Player) {
event.damager as Player
} else if (event.damager is Projectile && ((event.damager as Projectile).shooter) is Player) {
(event.damager as Projectile).shooter as Player
} else {
null
} ?: return
if (event.entity.uniqueId == damager.uniqueId) {
return
}
if (!this.hits.containsKey(damager.uniqueId)) {
return
}
this.hits[damager.uniqueId]!!.incrementAndGet()
}
val EFFECT_TYPE: PotionEffectType = PotionEffectType.INCREASE_DAMAGE
const val EFFECT_AMPLIFIER: Int = 2
const val DURATION_LIMIT = 8
private const val DURATION_PERIOD = 10L
}

View File

@ -0,0 +1,156 @@
package cc.fyre.hcf.ability.type
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.game.GameFaction
import cc.fyre.hcf.map.eotw.EOTWHandler
import cc.fyre.hcf.map.sotw.SOTWHandler
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.World
import org.bukkit.entity.Egg
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.entity.ProjectileLaunchEvent
import org.bukkit.event.player.PlayerEggThrowEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.metadata.FixedMetadataValue
import java.util.*
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object EggPort : Ability("eggport",TimeUnit.SECONDS.toMillis(16L)) {
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemBuilder.of(Material.EGG).build()
}
override fun getDisplayName(): String {
return "${ChatColor.LIGHT_PURPLE}${ChatColor.BOLD}Eggport"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Swap locations with a player",
"${ChatColor.GOLD}within a ${ChatColor.RED}${ChatColor.BOLD}$DISTANCE block${ChatColor.GOLD} radius."
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {}
@EventHandler(priority = EventPriority.MONITOR)
private fun onProjectileLaunch(event: ProjectileLaunchEvent) {
if (event.entity !is Egg || event.entity.shooter !is Player) {
return
}
val player = event.entity.shooter as Player
if (!this.isSimilar(player.itemInHand)) {
return
}
if (TimerHandler.hasTimer(player.uniqueId, TimerType.PVP_TIMER)) {
event.isCancelled = true
player.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} whilst having an active PvP Timer!")
return
}
if (SOTWHandler.isActive() && SOTWHandler.isProtected(player)) {
event.isCancelled = true
player.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} whilst being SOTW protected!")
return
}
if (EOTWHandler.isActive()) {
event.isCancelled = true
player.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} during EOTW!")
return
}
if (player.world.environment != World.Environment.NORMAL) {
event.isCancelled = true
player.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} in the ${if (player.world.environment == World.Environment.THE_END) "The End" else "Nether"}!")
return
}
if (this.callEvent(player).isCancelled) {
event.isCancelled = true
return
}
event.entity.setMetadata(METADATA,FixedMetadataValue(HCF.instance,player.uniqueId.toString()))
}
@EventHandler(priority = EventPriority.LOWEST)
private fun onEggThrow(event: PlayerEggThrowEvent) {
if (this.item.type != Material.EGG) {
return
}
if (!event.egg.hasMetadata(METADATA)) {
return
}
event.isHatching = false
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamage(event: EntityDamageByEntityEvent) {
if (event.entity !is Player || event.damager !is Egg || !event.damager.hasMetadata(METADATA)) {
return
}
if (event.isCancelled) {
return
}
val shooter = HCF.instance.server.getPlayer(UUID.fromString(event.damager.getMetadata(METADATA)[0].asString())) ?: return
val faction = FactionHandler.getFactionByLocation(event.entity.location)
if (faction is GameFaction && faction.isActive()) {
shooter.sendMessage("${ChatColor.RED}You cannot use a ${this.getDisplayName()}${ChatColor.RED} whilst ${faction.getDisplayName(shooter)}${ChatColor.RED} is active!")
return
}
if (shooter.location.distance(event.entity.location) > DISTANCE) {
shooter.sendMessage("${ChatColor.RED}That player is not within a ${ChatColor.WHITE}$DISTANCE ${ChatColor.RED}block radius!")
return
}
val entityLocation = event.entity.location.clone()
val shooterLocation = shooter.location.clone()
shooter.teleport(entityLocation)
(event.entity as Player).teleport(shooterLocation)
(event.entity as Player).sendMessage("${ChatColor.GREEN}Poof! You were hit by a ${this.getDisplayName()}${ChatColor.GREEN}!")
}
private const val DISTANCE = 15
const val METADATA = "EGGPORT"
}

View File

@ -0,0 +1,102 @@
package cc.fyre.hcf.ability.type
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.pvpclass.PvPClassHandler
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import cc.fyre.hcf.timer.listener.ArcherMarkListener
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.entity.Projectile
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
object FocusMode : Ability("focusmode",TimeUnit.MINUTES.toMillis(3L)) {
private val lastDamage = mutableMapOf<UUID,UUID>()
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 5000
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.GOLD_NUGGET)
}
override fun getDisplayName(): String {
return "${ChatColor.YELLOW}${ChatColor.BOLD}Focus Mode"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Right click to deal ${ChatColor.RED}${ChatColor.BOLD}${ArcherMarkListener.INCREASE_DAMAGE}% ${ChatColor.GOLD}more damage to",
"${ChatColor.GOLD}the last person you hit for ${ChatColor.YELLOW}${ChatColor.BOLD}${TimerType.ARCHER_MARK.duration / 1000L} seconds${ChatColor.GOLD}."
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
val uuid = this.lastDamage[event.player.uniqueId] ?: return
val player = Bukkit.getServer().getPlayer(uuid)
if (player == null) {
event.player.sendMessage("${ChatColor.RED}This player is no longer online.")
return
}
val pvpClass = PvPClassHandler.getPvPClassByPlayer(player.uniqueId)
if (pvpClass != null) {
event.player.sendMessage("${ProfileHandler.getDisplayNameById(player.uniqueId)}${ChatColor.RED} is in a ${pvpClass.getName()} class and cannot be focused.")
return
}
if (TimerHandler.hasTimer(player.uniqueId,TimerType.ARCHER_MARK)) {
event.player.sendMessage("${ProfileHandler.getDisplayNameById(player.uniqueId)} ${ChatColor.RED}is currently ${ChatColor.GOLD}${ChatColor.BOLD}Archer Marked${ChatColor.RED} and cannot be focused.")
return
}
if (this.callEvent(event.player).isCancelled) {
return
}
TimerHandler.addTimer(player.uniqueId,TimerType.ARCHER_MARK)
player.sendMessage("${ChatColor.GOLD}You have been hit with a ${this.getDisplayName()}${ChatColor.GOLD} you will now take ${ChatColor.RED}${ArcherMarkListener.INCREASE_DAMAGE}%${ChatColor.GOLD} more damage.")
event.player.sendMessage("${ChatColor.GOLD}You have used your ${this.getDisplayName()}${ChatColor.GOLD} on ${ProfileHandler.getDisplayNameById(player.uniqueId)}${ChatColor.GOLD} they will now take ${ChatColor.RED}${ArcherMarkListener.INCREASE_DAMAGE}${ChatColor.GOLD} more damage.")
this.lastDamage.remove(event.player.uniqueId)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
val damager = if (event.damager is Player) {
event.damager as Player
} else if (event.damager is Projectile && ((event.damager as Projectile).shooter) is Player) {
(event.damager as Projectile).shooter as Player
} else {
null
} ?: return
if (event.entity.uniqueId == damager.uniqueId) {
return
}
this.lastDamage[damager.uniqueId] = event.entity.uniqueId
}
}

View File

@ -0,0 +1,121 @@
package cc.fyre.hcf.ability.type
import cc.fyre.hcf.ability.AbilityHandler
import cc.fyre.shard.util.TimeUtil
import cc.fyre.hcf.ability.Ability
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.block.Block
import org.bukkit.block.BlockFace
import org.bukkit.entity.LivingEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.player.PlayerFishEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object Grapple : Ability("grapple",TimeUnit.SECONDS.toMillis(40L)) {
override fun getUses(): Int {
return 8
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.FISHING_ROD)
}
override fun getDisplayName(): String {
return "${ChatColor.GREEN}${ChatColor.BOLD}Grapple"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Pull yourself towards this rod."
)
}
override fun isInteractAble(): Boolean {
return false
}
override fun onPlayerInteract(event: PlayerInteractEvent) {}
@EventHandler(priority = EventPriority.LOWEST)
private fun onPlayerFish(event: PlayerFishEvent) {
if (event.isCancelled) {
return
}
if (!this.isSimilar(event.player.itemInHand)) {
return
}
if (event.state == PlayerFishEvent.State.FISHING) {
return
}
val cooldown = AbilityHandler.getCooldown(event.player.uniqueId,this)
if (cooldown > 0) {
event.hook.remove()
event.player.sendMessage("${ChatColor.RED}You cannot use this for another ${ChatColor.BOLD}${if (cooldown > 60000L) TimeUtil.formatIntoDetailedString(cooldown) else TimeUtil.formatIntoFancy(cooldown)}${ChatColor.RED}.")
event.player.updateInventory()
return
}
val hooked = event.hook ?: return
if (event.caught != null) {
event.hook.remove()
return
}
val location = event.player.location
val hookedLocation = hooked.location
if (!(this.isEligible(hookedLocation.block) || this.isEligible(hookedLocation.block.getRelative(BlockFace.UP)) || this.isEligible(hookedLocation.block.getRelative(BlockFace.DOWN)))) {
return
}
if (this.callEvent(event.player,hookedLocation).isCancelled) {
return
}
event.player.world.playSound(event.player.player.location,Sound.ZOMBIE_INFECT,0.5F,1.8F)
event.player.velocity = Vector(hookedLocation.x - location.x,hookedLocation.y - location.y,hookedLocation.z - location.z).multiply(
VELOCITY
)
event.expToDrop = 0
hooked.remove()
if (event.caught == null || event.caught is LivingEntity) {
return
}
event.caught.remove()
}
private fun isEligible(block: Block): Boolean {
return !(block.type == Material.AIR || block.type == Material.STATIONARY_WATER || block.type == Material.WATER)
}
private const val VELOCITY = 0.25
}

View File

@ -0,0 +1,148 @@
package cc.fyre.hcf.ability.type
import cc.fyre.shard.util.TimeUtil
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.Ability
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.entity.Projectile
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.scheduler.BukkitRunnable
import java.util.*
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object NinjaStar : Ability("ninjastar",TimeUnit.MINUTES.toMillis(4L)) {
private val attackerToPlayer = mutableMapOf<UUID,UUID>()
private val playerToAttacker = mutableMapOf<UUID,LastDamageEntry>()
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.NETHER_STAR)
}
override fun getDisplayName(): String {
return "${ChatColor.AQUA}${ChatColor.BOLD}Ninja Star"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Teleport to the last person that",
"${ChatColor.GOLD}hit you within the last ${ChatColor.YELLOW}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(
SPAN
)}${ChatColor.GOLD}!",
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
val entry = this.playerToAttacker[event.player.uniqueId]
if (entry == null || entry.getTimeAgo() > SPAN) {
event.player.sendMessage("${ChatColor.RED}You have not been hit within the last ${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString(
SPAN
)}${ChatColor.RED}!")
return
}
if (this.callEvent(event.player).isCancelled) {
return
}
object : BukkitRunnable() {
private var ticks = DURATION_SECONDS
private val player = event.player
private val target = HCF.instance.server.getPlayer(entry.uuid)
override fun run() {
if (this.player == null || !this.player.isOnline) {
this.cancel()
return
}
if (this.ticks <= 0) {
this.player.teleport(if (this.target != null && this.target.isOnline) this.target.location.clone() else entry.location.clone())
this.cancel()
return
}
this.player.sendMessage("${COUNTDOWN_COLORS[this.ticks]}${this.ticks--}..")
}
}.runTaskTimer(HCF.instance,0L,20L)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onPlayerDeath(event: PlayerDeathEvent) {
val removed = this.attackerToPlayer.remove(event.entity.uniqueId) ?: return
this.playerToAttacker.remove(removed)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
if (event.isCancelled) {
return
}
if (event.entity !is Player || event.damager !is Player) {
return
}
var damager: Player? = null
if (event.damager is Player) {
damager = event.damager as Player
}
if (event.damager is Projectile && !event.damager.hasMetadata(EggPort.METADATA) && (event.damager as Projectile).shooter is Player) {
damager = (event.damager as Projectile).shooter as Player
}
if (damager == null) {
return
}
this.attackerToPlayer[damager.uniqueId] = event.entity.uniqueId
this.playerToAttacker[event.entity.uniqueId] = LastDamageEntry(System.currentTimeMillis(),event.damager.uniqueId,event.damager.location)
}
class LastDamageEntry(val time: Long,val uuid: UUID,val location: Location) {
fun getTimeAgo():Long {
return System.currentTimeMillis() - this.time
}
}
val SPAN = TimeUnit.SECONDS.toMillis(30L)
const val DURATION_SECONDS = 5
}

View File

@ -0,0 +1,98 @@
package cc.fyre.hcf.ability.type
import cc.fyre.hcf.ability.Ability
import cc.fyre.shard.util.item.ItemBuilder
import org.bukkit.ChatColor
import org.bukkit.Effect
import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerQuitEvent
import org.bukkit.event.player.PlayerTeleportEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
import java.util.*
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object Rocket : Ability("rocket",TimeUnit.SECONDS.toMillis(60L)) {
private val cache = ArrayList<UUID>()
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemBuilder.of(Material.FIREWORK).build()
}
override fun getDisplayName(): String {
return "${ChatColor.DARK_RED}${ChatColor.BOLD}Rocket"
}
override fun getDescription():ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Launch yourself ${ChatColor.RED}${ChatColor.BOLD}20 blocks",
"${ChatColor.GOLD}up into the air with no fall damage!"
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
event.isCancelled = true
if (this.callEvent(event.player).isCancelled) {
return
}
event.player.world.playSound(event.player.location,Sound.FIREWORK_LAUNCH,0.0F,2.0F)
event.player.world.playEffect(event.player.location,Effect.MOBSPAWNER_FLAMES,20)
event.player.velocity = Vector(0.0,2.0,0.0)
this.cache.add(event.player.uniqueId)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onPlayerQuit(event: PlayerQuitEvent) {
this.cache.remove(event.player.uniqueId)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onPlayerTeleport(event: PlayerTeleportEvent) {
// mainly for when they pearl
this.cache.remove(event.player.uniqueId)
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onEntityDamage(event: EntityDamageEvent) {
if (event.entity !is Player) {
return
}
if (event.cause != EntityDamageEvent.DamageCause.FALL) {
return
}
if (!this.cache.remove(event.entity.uniqueId)) {
return
}
event.isCancelled = true
}
}

View File

@ -0,0 +1,132 @@
package cc.fyre.hcf.ability.type
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.Ability
import cc.fyre.hcf.timer.TimerType
import cc.fyre.hcf.timer.event.TimerExpireEvent
import cc.fyre.hcf.timer.event.TimerRemoveEvent
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.EnderPearl
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.ProjectileLaunchEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.scheduler.BukkitRunnable
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
/**
* @project hcf
*
* @date 31/12/2020
* @author xanderume@gmail.com
*/
object TimeWarp : Ability("timewarp",TimeUnit.SECONDS.toMillis(150L)) {
private val cache = mutableMapOf<UUID,Location>()
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 5000
}
override fun getItemStack(): ItemStack {
return ItemStack(Material.WATCH)
}
override fun getDisplayName(): String {
return "${ChatColor.DARK_PURPLE}${ChatColor.BOLD}Time Warp"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Travel back to where",
"${ChatColor.GOLD}you last threw a pearl!"
)
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
if (!this.cache.containsKey(event.player.uniqueId)) {
event.player.sendMessage("${ChatColor.RED}You have not thrown a pearl in the last ${ChatColor.BOLD}$SECONDS seconds${ChatColor.RED}.")
return
}
if (this.callEvent(event.player).isCancelled) {
return
}
event.player.sendMessage("${ChatColor.GOLD}You have used a ${this.getDisplayName()}${ChatColor.GOLD} teleporting you in ${ChatColor.RED}${ChatColor.BOLD}$TELEPORT_SECONDS seconds${ChatColor.GOLD}.")
object : BukkitRunnable() {
private var tick = TELEPORT_SECONDS
override fun run() {
if (!event.player.isOnline) {
this.cancel()
return
}
if (this.tick <= 0L) {
this.cancel()
event.player.teleport(this@TimeWarp.cache.remove(event.player.uniqueId))
return
}
event.player.sendMessage("${COUNTDOWN_COLORS[this.tick]}${this.tick--}..")
}
}.runTaskTimer(HCF.instance,0L,20L)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onProjectileLaunch(event: ProjectileLaunchEvent) {
if (event.isCancelled || event.entity !is EnderPearl) {
return
}
val shooter = event.entity.shooter
if (shooter !is Player) {
return
}
this.cache[shooter.uniqueId] = shooter.location.clone()
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onTimerRemove(event: TimerRemoveEvent) {
if (event.timer.type != TimerType.ENDER_PEARL) {
return
}
this.cache.remove(event.uuid)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onTimerExpire(event: TimerExpireEvent) {
if (event.timer.type != TimerType.ENDER_PEARL) {
return
}
this.cache.remove(event.uuid)
}
private const val SECONDS = 16
private const val TELEPORT_SECONDS = 3
}

View File

@ -0,0 +1,143 @@
package cc.fyre.hcf.ability.type.invisibility
import cc.fyre.shard.util.TimeUtil
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.HCF
import cc.fyre.hcf.ability.Ability
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import net.minecraft.server.v1_7_R4.ItemArmor
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.entity.PotionEffectExpireEvent
import org.bukkit.event.entity.PotionEffectRemoveEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.potion.PotionEffect
import org.bukkit.potion.PotionEffectType
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 13/12/2020
* @author xanderume@gmail.com
*/
object Invisibility : Ability("invisibility",TimeUnit.MINUTES.toMillis(5L)) {
init {
ProtocolLibrary.getProtocolManager().addPacketListener(InvisibilityListener)
}
override fun getUses(): Int {
return 1
}
override fun getPrice(): Int {
return 1000
}
override fun getItemStack(): ItemStack {
return ItemBuilder.of(Material.INK_SACK).build()
}
override fun getDisplayName(): String {
return "${ChatColor.GRAY}${ChatColor.BOLD}Invisibility"
}
override fun getDescription(): ArrayList<String> {
return arrayListOf(
"${ChatColor.GOLD}Hide your armor for ${ChatColor.YELLOW}${ChatColor.BOLD}${TimeUtil.formatIntoDetailedString((EFFECT.duration / 20) * 1000L)}${ChatColor.GOLD}!",
)
}
override fun isInteractAble(): Boolean {
return true
}
override fun onPlayerInteract(event: PlayerInteractEvent) {
if (this.callEvent(event.player).isCancelled) {
event.isCancelled = true
return
}
event.player.addPotionEffect(EFFECT,true)
sendPacket(event.player,Bukkit.getServer().onlinePlayers,true)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
if (event.isCancelled || event.entity !is Player || event.damager !is Player) {
return
}
val effect = (event.entity as Player).activePotionEffects.firstOrNull{it.type == EFFECT.type && it.amplifier == EFFECT.amplifier} ?: return
(event.entity as Player).removePotionEffect(effect.type)
(event.entity as Player).addPotionEffect(PotionEffect(effect.type,effect.duration,0))
(event.entity as Player).sendMessage("${ChatColor.RED}You have been hit and your armor is now visible!")
sendPacket(event.entity as Player,Bukkit.getServer().onlinePlayers,false)
}
@EventHandler(priority = EventPriority.LOWEST)
private fun onPotionEffectExpire(event: PotionEffectExpireEvent) {
onPotionEffectRemove(event)
}
@EventHandler(priority = EventPriority.LOWEST)
private fun onPotionEffectRemove(event: PotionEffectRemoveEvent) {
if (event.entity !is Player) {
return
}
if (event.effect.type != EFFECT.type || event.effect.amplifier != EFFECT.amplifier) {
return
}
val effect = (event.entity as Player).activePotionEffects.firstOrNull{it.type == EFFECT.type && it.amplifier == EFFECT.amplifier} ?: return
(event.entity as Player).removePotionEffect(effect.type)
(event.entity as Player).addPotionEffect(PotionEffect(effect.type,effect.duration,0))
(event.entity as Player).sendMessage("${ChatColor.RED}You have been hit and your armor is now visible!")
Bukkit.getServer().scheduler.runTask(HCF.instance) {
sendPacket(event.entity as Player,Bukkit.getServer().onlinePlayers,false)
}
}
private fun sendPacket(player: Player,collection: Collection<Player>,invisible: Boolean) {
val packets = ArrayList<PacketContainer>()
for (i in 0 until 4) {
val packet = PacketContainer(PacketType.Play.Server.ENTITY_EQUIPMENT)
packet.integers.write(0,player.entityId)
packet.integers.write(1,i + 1)
packet.itemModifier.write(0,if (invisible) ItemStack(Material.AIR) else player.inventory.armorContents[i])
packets.add(packet)
}
collection.filter{it.uniqueId != player.uniqueId}.forEach{packets.forEach{packet -> ProtocolLibrary.getProtocolManager().sendServerPacket(it,packet)}}
}
val EFFECT = PotionEffect(PotionEffectType.INVISIBILITY,8*60*20,2,false)
}

View File

@ -0,0 +1,36 @@
package cc.fyre.hcf.ability.type.invisibility
import cc.fyre.hcf.HCF
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.PacketAdapter
import com.comphenix.protocol.events.PacketEvent
import net.minecraft.server.v1_7_R4.ItemArmor
import org.bukkit.Material
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack
object InvisibilityListener : PacketAdapter(HCF.instance,PacketType.Play.Server.ENTITY_EQUIPMENT) {
override fun onPacketSending(event: PacketEvent) {
val id = event.packet.integers.read(0)
val itemStack = event.packet.itemModifier.read(0)
if (itemStack == null || itemStack.type == Material.AIR) {
return
}
if (CraftItemStack.asNMSCopy(itemStack).item !is ItemArmor) {
return
}
val player = HCF.instance.server.onlinePlayers.firstOrNull{it.entityId == id} ?: return
if (player.activePotionEffects.none{it.type == Invisibility.EFFECT.type && it.amplifier == Invisibility.EFFECT.amplifier}) {
return
}
event.isCancelled = true
}
}

View File

@ -0,0 +1,100 @@
package cc.fyre.hcf.combatlogger
import cc.fyre.hcf.HCF
import cc.fyre.hcf.combatlogger.kb.ZeroKBProfile
import cc.fyre.hcf.combatlogger.scheduler.CombatLoggerScheduler
import net.minecraft.server.v1_7_R4.*
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer
import org.bukkit.craftbukkit.v1_7_R4.event.CraftEventFactory
import org.bukkit.entity.Player
import org.bukkit.event.entity.EntityDeathEvent
import java.util.*
class CombatLogger(private val player: Player) : EntityVillager((player.location.world as CraftWorld).handle) {
private var scheduler: CombatLoggerScheduler? = null
fun spawn(player: Player) {
this.setLocation(player.location.x,player.location.y,player.location.z,player.location.yaw,player.location.pitch)
this.bukkitEntity.velocity = player.velocity
this.bukkitEntity.fallDistance = player.fallDistance
this.k = false
this.fromMobSpawner = true
this.health = player.health.toFloat()
this.kbProfile = ZeroKBProfile
this.customName = "${ChatColor.GRAY}(Combat-Logger) ${ChatColor.RED}${player.name}"
this.customNameVisible = true
this.world.addEntity(this)
this.scheduler = CombatLoggerScheduler(this)
this.scheduler!!.runTaskTimer(HCF.instance,20,20L)
}
fun getPlayer():Player {
return this.player
}
fun getPlayerId():UUID {
return this.player.uniqueId
}
override fun move(x: Double,y: Double,z: Double) {}
override fun collide(entity: Entity?) {}
override fun g(d0: Double, d1: Double, d2: Double) {}
override fun dropDeathLoot(flag: Boolean, i: Int) {}
override fun createChild(entity: EntityAgeable?): EntityAgeable? = null
fun kill() {
this.die(DamageSource.GENERIC)
this.scheduler?.cancel()
this.scheduler = null
this.destroyScheduler()
}
fun handleDeath(event: EntityDeathEvent) {
val handle = (this.player as CraftPlayer).handle
val contents = this.player.inventory.contents
.plus(this.player.inventory.armorContents)
.filter{it != null && it.type != Material.AIR}
.toList()
CraftEventFactory.callPlayerDeathEvent(
handle,
contents,
null,
this.player.world.getGameRuleValue("keepInventory").toBoolean()
)
this.player.inventory.clear()
this.player.inventory.armorContents = null
this.player.health = 0.0
Bukkit.getServer().scheduler.runTaskAsynchronously(HCF.instance) {
this.player.saveData()
}
this.destroyScheduler()
}
fun destroy() {
this.world.removeEntity(this)
}
private fun destroyScheduler() {
if (this.scheduler == null) {
return
}
this.scheduler!!.cancel()
this.scheduler = null
}
}

View File

@ -0,0 +1,79 @@
package cc.fyre.hcf.combatlogger
import org.bukkit.entity.*
import java.util.*
import java.util.concurrent.ConcurrentHashMap
/**
* @project hcf
*
* @date 13/09/2020
* @author xanderume@gmail.com
*/
object CombatLoggerHandler {
private val loggers = ConcurrentHashMap<UUID,CombatLogger>()
private val loggersById = ConcurrentHashMap<Int,CombatLogger>()
private val safetyProtection = ConcurrentHashMap.newKeySet<UUID>()
fun create(player: Player):CombatLogger {
var toReturn = this.loggers[player.uniqueId]
if (toReturn == null) {
toReturn = CombatLogger(player)
this.loggers[player.uniqueId] = toReturn
this.loggersById[toReturn.id] = toReturn
}
return toReturn
}
fun destroy(player: Player,kill: Boolean = false) {
val logger = this.loggers.remove(player.uniqueId)
if (logger != null) {
if (kill) {
logger.kill()
} else {
logger.destroy()
}
player.health = logger.health.toDouble()
this.loggersById.remove(logger.id)
}
this.safetyProtection.remove(player.uniqueId)
}
fun isCombatLogger(entity: Entity):Boolean {
return this.loggersById.contains(entity.entityId)
}
fun getLoggerByPlayer(uuid: UUID):CombatLogger? {
return this.loggers[uuid]
}
fun getLoggerByEntityId(id: Int):CombatLogger? {
return this.loggersById[id]
}
fun getAllLoggers():List<CombatLogger> {
return this.loggers.values.toList()
}
fun addSafetyProtection(uuid: UUID) {
this.safetyProtection.add(uuid)
}
fun hasSafetyProtection(uuid: UUID):Boolean {
return this.safetyProtection.remove(uuid)
}
const val RADIUS = 40.0
const val SECONDS = 25
}

View File

@ -0,0 +1,34 @@
package cc.fyre.hcf.combatlogger
import cc.fyre.hcf.HCF
import cc.fyre.hcf.HCFModule
import cc.fyre.hcf.combatlogger.listener.CombatLoggerListener
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import cc.fyre.shard.util.entity.EntityUtil
import org.bukkit.entity.EntityType
import org.bukkit.event.Listener
object CombatLoggerModule : HCFModule {
override fun init(core: HCF) {}
override fun shutdown(core: HCF) {
EntityUtil.registerEntity(CombatLogger::class.java,"Villager",EntityType.VILLAGER.typeId.toInt())
CombatLoggerHandler.getAllLoggers().forEach{it.destroy()}
}
override fun getCommands(): List<Class<*>> {
return listOf()
}
override fun getAdapters(): Map<Class<*>, ParameterAdapter<*>> {
return mapOf()
}
override fun getListeners(): List<Listener> {
return listOf(
CombatLoggerListener
)
}
}

View File

@ -0,0 +1,74 @@
package cc.fyre.hcf.combatlogger.kb
import cc.fyre.knockback.KnockbackProfile
/**
* @project hcf
*
* @date 13/09/2020
* @author xanderume@gmail.com
*/
object ZeroKBProfile : KnockbackProfile {
private const val name = "Zero"
private var friction = 0.1
private var vertical = 0.0
private var horizontal = 0.0
private var verticalLimit = 0.0
private var extraVertical = 0.0
private var extraHorizontal = 0.0
override fun getName():String {
return name
}
override fun getFriction(): Double {
return friction
}
override fun setFriction(friction: Double) {
this.friction = friction
}
override fun getHorizontal(): Double {
return horizontal
}
override fun setHorizontal(horizontal: Double) {
this.horizontal = horizontal
}
override fun getVertical(): Double {
return vertical
}
override fun setVertical(vertical: Double) {
this.vertical = vertical
}
override fun getVerticalLimit(): Double {
return verticalLimit
}
override fun setVerticalLimit(verticalLimit: Double) {
this.verticalLimit = verticalLimit
}
override fun getExtraHorizontal(): Double {
return extraHorizontal
}
override fun setExtraHorizontal(extraHorizontal: Double) {
this.extraHorizontal = extraHorizontal
}
override fun getExtraVertical(): Double {
return extraVertical
}
override fun setExtraVertical(extraVertical: Double) {
this.extraVertical = extraVertical
}
}

View File

@ -0,0 +1,206 @@
package cc.fyre.hcf.combatlogger.listener
import cc.fyre.hcf.combatlogger.CombatLoggerHandler
import cc.fyre.hcf.faction.Faction
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.hcf.faction.listener.FactionProtectionListener
import cc.fyre.hcf.timer.TimerType
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.hcf.combatlogger.CombatLogger
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.faction.FactionMetadata
import cc.fyre.hcf.map.sotw.SOTWHandler
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.modsuite.mod.ModHandler
import org.bukkit.ChatColor
import org.bukkit.GameMode
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftVillager
import org.bukkit.entity.Player
import org.bukkit.entity.Projectile
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.entity.EntityDeathEvent
import org.bukkit.event.entity.EntityInteractEvent
import org.bukkit.event.entity.EntityPortalEvent
import org.bukkit.event.player.PlayerInteractEntityEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
import org.bukkit.event.world.ChunkUnloadEvent
import java.util.*
/**
* @project hcf
*
* @date 13/09/2020
* @author xanderume@gmail.com
*/
object CombatLoggerListener : Listener {
@EventHandler(priority = EventPriority.NORMAL)
private fun onPlayerJoin(event: PlayerJoinEvent) {
CombatLoggerHandler.destroy(event.player)
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onChunkUnLoad(event: ChunkUnloadEvent) {
event.chunk.entities
.filter{!it.isDead && CombatLoggerHandler.isCombatLogger(it)}
.forEach{it.remove()}
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onEntityInteract(event: PlayerInteractEntityEvent) {
if (!CombatLoggerHandler.isCombatLogger(event.rightClicked)) {
return
}
event.isCancelled = true
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onEntityPortal(event: EntityPortalEvent) {
if (!CombatLoggerHandler.isCombatLogger(event.entity)) {
return
}
event.isCancelled = true
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onEntityInteract(event: EntityInteractEvent) {
val logger = CombatLoggerHandler.getLoggerByEntityId(event.entity.entityId) ?: return
val faction = FactionHandler.getFactionByLocation(event.block.location)
if (faction is PlayerFaction && (faction.isRaidable() || faction.isMember(logger.getPlayerId()))) {
return
}
if (FactionProtectionListener.DISALLOW_INTERACT.none{it == event.block.type}) {
return
}
event.isCancelled = true
}
@EventHandler(priority = EventPriority.HIGHEST)
private fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
if (event.isCancelled) {
return
}
val logger = CombatLoggerHandler.getLoggerByEntityId(event.entity.entityId) ?: return
var damager: Player? = null
if (event.damager is Player) {
damager = event.damager as Player
} else if (event.damager is Projectile && (event.damager as Projectile).shooter is Player) {
damager = (event.damager as Projectile).shooter as Player
}
if (damager == null) {
return
}
if (FactionMetadata.SAFE_ZONE.isValidAtLocation(event.entity.location) || FactionMetadata.SAFE_ZONE.isValidAtLocation(damager.location)) {
event.isCancelled = true
return
}
if (TimerHandler.hasTimer(damager.uniqueId,TimerType.PVP_TIMER)) {
damager.sendMessage("${ChatColor.RED}You cannot do this while your PvP Timer is active!")
damager.sendMessage("${ChatColor.RED}Type '${ChatColor.YELLOW}/pvp enable${ChatColor.RED}' to remove your timer.")
event.isCancelled = true
return
}
if (SOTWHandler.isActive() && SOTWHandler.isProtected(damager)) {
damager.sendMessage("${ChatColor.RED}You cannot do this while your SOTW Timer is active!")
damager.sendMessage("${ChatColor.RED}Type '${ChatColor.YELLOW}/sotw enable${ChatColor.RED}' to remove your timer.")
event.isCancelled = true
return
}
val id = logger.getPlayerId()
val faction = FactionHandler.getFactionByPlayer(damager.uniqueId)
if (faction != null && faction.isMember(id)) {
damager.sendMessage("${ChatColor.YELLOW}You cannot hurt ${if (faction.isMember(id)) ChatColor.DARK_GREEN else Faction.ALLY_COLOR}${UUIDHandler.getUsernameById(id)}${ChatColor.YELLOW}.")
event.isCancelled = true
return
}
TimerHandler.addTimer(damager.uniqueId,TimerType.SPAWN_TAG)
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onPlayerQuit(event: PlayerQuitEvent) {
if (event.player.isDead) {
return
}
if (CombatLoggerHandler.hasSafetyProtection(event.player.uniqueId)) {
return
}
if (event.player.gameMode == GameMode.CREATIVE || ModHandler.isInModMode(event.player.uniqueId) || ModHandler.isInVanish(event.player.uniqueId)) {
return
}
if (SOTWHandler.isActive() && SOTWHandler.isProtected(event.player)) {
return
}
if (TimerHandler.hasTimer(event.player.uniqueId,TimerType.PVP_TIMER)) {
return
}
if (FactionMetadata.SAFE_ZONE.isValidAtLocation(event.player.location)) {
return
}
val radius = CombatLoggerHandler.RADIUS
val faction = FactionHandler.getFactionByPlayer(event.player.uniqueId)
event.player.getNearbyEntities(radius,radius,radius).filterIsInstance<Player>().firstOrNull{
if (it.gameMode == GameMode.CREATIVE || ModHandler.isInModMode(it.uniqueId) || ModHandler.isInVanish(it.uniqueId)) {
return@firstOrNull false
}
if (SOTWHandler.isActive() && SOTWHandler.isProtected(it)) {
return@firstOrNull false
}
if (TimerHandler.hasTimer(it.uniqueId,TimerType.PVP_TIMER)) {
return@firstOrNull false
}
if (FactionMetadata.SAFE_ZONE.isValidAtLocation(it.location)) {
return@firstOrNull false
}
if (faction != null && faction.isMember(it)) {
return@firstOrNull false
}
return@firstOrNull true
}?.also{CombatLoggerHandler.create(event.player)}
}
@EventHandler(priority = EventPriority.NORMAL)
private fun onEntityDeath(event: EntityDeathEvent) {
CombatLoggerHandler.getLoggerByEntityId(event.entity.entityId)?.handleDeath(event)
}
}

View File

@ -0,0 +1,47 @@
package cc.fyre.hcf.combatlogger.scheduler
import cc.fyre.hcf.combatlogger.CombatLogger
import cc.fyre.shard.util.bukkit.NMSUtil
import cc.fyre.hcf.combatlogger.CombatLoggerHandler
import net.minecraft.server.v1_7_R4.EntityInsentient
import org.bukkit.ChatColor
import org.bukkit.World
import org.bukkit.entity.Entity
import org.bukkit.scheduler.BukkitRunnable
import java.util.*
/**
* @project hcf
*
* @date 13/09/2020
* @author xanderume@gmail.com
*/
class CombatLoggerScheduler(private val logger: CombatLogger) : BukkitRunnable() {
var remaining = CombatLoggerHandler.SECONDS
override fun run() {
if (this.remaining == 0) {
this.cancel()
CombatLoggerHandler.destroy(this.logger.getPlayer())
if (this.logger.bukkitEntity.isDead || !this.logger.bukkitEntity.isValid) {
return
}
this.logger.destroy()
return
}
if (this.logger.bukkitEntity.world.environment == World.Environment.THE_END && this.logger.bukkitEntity.location.blockY < 0) {
this.cancel()
this.logger.kill()
return
}
this.remaining--
}
}

View File

@ -0,0 +1,78 @@
package cc.fyre.hcf.death
import cc.fyre.hcf.HCF
import cc.fyre.hcf.death.loadout.DeathLoadout
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.bukkit.entity.Player
import java.util.*
/**
* @project hcf
*
* @date 14/09/2020
* @author xanderume@gmail.com
*/
@JsonClass(generateAdapter = true)
class Death(
@Json(name = "_id")
val id: UUID,
val player: UUID,
val reason: String
) {
var loadout: DeathLoadout? = null
var deathBanTime = 0L
constructor(id: UUID,player: Player,reason: String,killer: Player?):this(id,player.uniqueId,reason) {
// this.loadout = DeathLoadout(player)
if (killer != null) {
this.killer = killer.uniqueId
//this.killerLoadout = DeathLoadout(killer)
}
this.deathBanTime = DeathHandler.getBanTimeByPlayer(player)
}
val time = System.currentTimeMillis()
var killer: UUID? = null
var killerLoadout: DeathLoadout? = null
var reviver: UUID? = null
var revived: Long? = null
var refunder: UUID? = null
var refunded: Long? = null
fun isRevived(): Boolean {
return this.reviver != null && this.revived != null
}
fun setRevived(uuid: UUID) {
this.reviver = uuid
this.revived = System.currentTimeMillis()
}
fun isRefunded(): Boolean {
return this.refunder != null && this.refunded != null
}
fun setRefunded(uuid: UUID) {
this.refunder = uuid
this.refunded = System.currentTimeMillis()
}
fun isActive():Boolean {
return this.reviver == null && this.revived == null && this.deathBanTime != 0L && (this.time + this.deathBanTime) - System.currentTimeMillis() > 0L
}
fun getRemaining():Long {
return (this.time + this.deathBanTime) - System.currentTimeMillis()
}
}

View File

@ -0,0 +1,82 @@
package cc.fyre.hcf.death
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.hcf.HCF
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.faction.Faction
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.faction.FactionMetadata
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.hcf.game.GameHandler
import cc.fyre.hcf.map.MapHandler
import cc.fyre.hcf.map.sotw.SOTWHandler
import cc.fyre.hcf.statistic.StatisticHandler
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import java.util.*
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 14/09/2020
* @author xanderume@gmail.com
*/
object DeathHandler {
const val DEATH_SIGN_NAME = "§dDeath Sign"
fun isDeathBanned(uuid: UUID):Boolean {
return StatisticHandler.getStatistic(uuid,DeathStatistic).getValue()?.isActive() ?: false
}
fun getDeathSign(victim: Player,killer: Player):ItemStack {
val lore = ArrayList<String>()
lore.add("${ChatColor.DARK_RED}${victim.name}")
lore.add("${ChatColor.YELLOW}Slain By:")
lore.add("${ChatColor.GREEN}${killer.name}")
lore.add(GameHandler.DATE_FORMAT.format(Date()).replace(" AM","").replace(" PM",""))
return ItemBuilder.of(Material.SIGN).name(DEATH_SIGN_NAME).lore(lore).build()
}
fun getBanTimeByPlayer(player: Player):Long {
if (player.isOp) {
return 0L
}
if (SOTWHandler.isActive()) {
return TimeUnit.HOURS.toMillis(24L)
}
val faction = FactionHandler.getFactionByLocation(player.location)
if (faction is SystemFaction && faction.hasMetadata(FactionMetadata.SAFE_ZONE)) {
return 0L
}
val rank = ProfileHandler.getProfileById(player.uniqueId)?.rank
if (rank != null && rank.staff) {
return 0L
}
var toReturn = if (rank == null) DEFAULT_DEATHBAN else MapHandler.config.deathBans[rank.name.lowercase()] ?: DEFAULT_DEATHBAN
if (faction.getDeathbanStatus() == Faction.DeathbanStatus.NON_DEATHBAN && toReturn > NON_DEATHBAN_REGION_TIME) {
toReturn = NON_DEATHBAN_REGION_TIME
}
return toReturn
}
private val DEFAULT_DEATHBAN = TimeUnit.MINUTES.toMillis(60L)
private const val NON_DEATHBAN_REGION_TIME = 15 * 60_000L
}

View File

@ -0,0 +1,41 @@
package cc.fyre.hcf.death
import cc.fyre.hcf.HCF
import cc.fyre.hcf.HCFModule
import cc.fyre.hcf.death.command.DeathsCommand
import cc.fyre.hcf.death.command.KillsCommand
import cc.fyre.hcf.death.command.LastInvCommand
import cc.fyre.hcf.death.command.ReviveCommand
import cc.fyre.hcf.death.listener.DeathListener
import cc.fyre.hcf.statistic.StatisticRegistry
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import org.bukkit.event.Listener
object DeathModule : HCFModule {
override fun init(core: HCF) {
StatisticRegistry.register(DeathStatistic)
}
override fun shutdown(core: HCF) {}
override fun getCommands(): List<Class<*>> {
return listOf(
KillsCommand::class.java,
DeathsCommand::class.java,
ReviveCommand::class.java,
LastInvCommand::class.java,
)
}
override fun getAdapters(): Map<Class<*>, ParameterAdapter<*>> {
return mapOf()
}
override fun getListeners(): List<Listener> {
return listOf(
DeathListener
)
}
}

View File

@ -0,0 +1,91 @@
package cc.fyre.hcf.death
import cc.fyre.hcf.HCF
import cc.fyre.hcf.death.Death
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.shard.moshi.MoshiUtil
import cc.fyre.shard.util.MongoUtil
import com.mongodb.client.MongoCollection
import com.mongodb.client.model.Filters
import net.minecraft.util.com.google.common.cache.CacheBuilder
import org.bson.Document
import java.util.*
import java.util.concurrent.TimeUnit
/**
* @project hcf
*
* @date 16/11/2020
* @author xanderume@gmail.com
*/
object DeathRepository {
private val deathsByPlayer = CacheBuilder.newBuilder()
.expireAfterAccess(10L,TimeUnit.MINUTES)
.build<UUID,MutableList<Death>>()
private val deathsByKiller = CacheBuilder.newBuilder()
.expireAfterAccess(10L,TimeUnit.MINUTES)
.build<UUID,MutableList<Death>>()
private val collection: MongoCollection<Document> = HCF.instance.getMongoDB().getCollection("deaths")
fun deleteAll() {
for (entry in StatisticHandler.getAllStatistics(DeathStatistic)) {
if (entry.value.getValue() == null) {
continue
}
StatisticHandler.setStatistic(entry.key,DeathStatistic,null)
}
this.collection.drop()
}
fun updateById(death: Death) {
this.collection.updateOne(
Filters.eq("_id",death.id.toString()),
Document("\$set",Document.parse(MoshiUtil.instance.adapter(Death::class.java).toJson(death))),
MongoUtil.UPDATE_OPTIONS
)
if (death.killer != null) {
this.deathsByKiller.getIfPresent(death.killer!!)?.add(death)
}
this.deathsByPlayer.getIfPresent(death.player)?.add(death)
}
fun findAllByPlayer(player: UUID):List<Death> {
var toReturn = this.deathsByPlayer.getIfPresent(player)?.toList()
if (toReturn == null) {
val adapter = MoshiUtil.instance.adapter(Death::class.java)
toReturn = this.collection.find(Filters.eq("player",player.toString()))
.mapNotNull{adapter.fromJson(it.toJson(MongoUtil.RELAXED_WRITE_SETTING))}
.toList()
}
return toReturn
}
fun findAllByKiller(killer: UUID):List<Death> {
var toReturn = this.deathsByKiller.getIfPresent(killer)?.toList()
if (toReturn == null) {
val adapter = MoshiUtil.instance.adapter(Death::class.java)
toReturn = this.collection.find(Filters.and(Filters.exists("killer"),Filters.eq("killer",killer.toString())))
.mapNotNull{adapter.fromJson(it.toJson(MongoUtil.RELAXED_WRITE_SETTING))}
.toList()
}
return toReturn
}
}

View File

@ -0,0 +1,75 @@
package cc.fyre.hcf.death
import cc.fyre.core.profile.Profile
import cc.fyre.hcf.statistic.Statistic
import cc.fyre.hcf.statistic.StatisticOption
import cc.fyre.hcf.statistic.StatisticValue
import cc.fyre.shard.moshi.MoshiUtil
import cc.fyre.shard.util.MongoUtil
import org.bson.Document
object DeathStatistic : Statistic<Death?>() {
override fun getKey(): String {
return "deathban"
}
override fun getOptions(): List<StatisticOption<Death?>> {
return listOf()
}
override fun getDefaultValue(): StatisticValue<Death?> {
return object : StatisticValue<Death?> {
override fun getValue(): Death? {
return null
}
}
}
override fun getDisplayName(value: Death?): String {
return ""
}
override fun isSetting(): Boolean {
return false
}
override fun hasPermission(profile: Profile,value: Death?): Boolean {
return true
}
override fun getName(): String {
return ""
}
override fun getNextValue(value: Death?): Death? {
return null
}
override fun toBson(document: Document,value: Any) {
if (value !is Death) {
return
}
document.append(this.getKey(),Document.parse(MoshiUtil.instance.adapter(Death::class.java).toJson(value)))
}
override fun fromBson(document: Document): StatisticValue<Death?> {
return object : StatisticValue<Death?> {
override fun getValue(): Death? {
if (!document.containsKey(this@DeathStatistic.getKey())) {
return null
}
return MoshiUtil.instance.adapter(Death::class.java).fromJson(document.get(this@DeathStatistic.getKey(),Document::class.java).toJson(MongoUtil.RELAXED_WRITE_SETTING))
}
}
}
}

View File

@ -0,0 +1,25 @@
package cc.fyre.hcf.death.command
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.hcf.HCF
import cc.fyre.hcf.death.DeathRepository
import cc.fyre.hcf.death.menu.DeathsMenu
import org.bukkit.entity.Player
import java.util.*
/**
* @project hcf
*
* @date 18/09/2020
* @author xanderume@gmail.com
*/
object DeathsCommand {
@JvmStatic
@Command(names = ["deaths","refund"],async = true,permission = "hcf.command.deaths")
fun execute(player: Player,@Parameter(name = "player")uuid: UUID) {
DeathsMenu(uuid,DeathRepository.findAllByPlayer(uuid)).open(player)
}
}

View File

@ -0,0 +1,25 @@
package cc.fyre.hcf.death.command
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.hcf.HCF
import cc.fyre.hcf.death.DeathRepository
import cc.fyre.hcf.death.menu.DeathsMenu
import org.bukkit.entity.Player
import java.util.*
/**
* @project hcf
*
* @date 17/11/2020
* @author xanderume@gmail.com
*/
object KillsCommand {
@JvmStatic
@Command(names = ["kills"],async = true,permission = "hcf.command.kills")
fun execute(player: Player,@Parameter(name = "player")uuid: UUID) {
DeathsMenu(uuid,DeathRepository.findAllByKiller(uuid)).open(player)
}
}

View File

@ -0,0 +1,40 @@
package cc.fyre.hcf.death.command
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.hcf.HCF
import cc.fyre.core.profile.ProfileHandler
import cc.fyre.hcf.death.DeathStatistic
import cc.fyre.hcf.statistic.StatisticHandler
import org.bukkit.ChatColor
import org.bukkit.entity.Player
import java.util.*
/**
* @project hcf
*
* @date 28/11/2020
* @author xanderume@gmail.com
*/
object LastInvCommand {
@JvmStatic
@Command(names = ["lastinv"],permission = "hcf.command.lastinv")
fun execute(player: Player,@Parameter(name = "player")uuid: UUID) {
val death = StatisticHandler.getStatistic(uuid,DeathStatistic).getValue()
if (death?.loadout == null) {
player.sendMessage("${ChatColor.RED}No last inventory found for ${ProfileHandler.getDisplayNameById(uuid)}${ChatColor.RED}.")
return
}
player.inventory.contents = death.loadout!!.contents.toTypedArray()
player.inventory.armorContents = death.loadout!!.armor.toTypedArray()
player.activePotionEffects.forEach{player.removePotionEffect(it.type)}
player.updateInventory()
}
}

View File

@ -0,0 +1,70 @@
package cc.fyre.hcf.death.command
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.hcf.HCF
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.hcf.death.DeathRepository
import cc.fyre.hcf.death.DeathStatistic
import cc.fyre.hcf.map.eotw.EOTWHandler
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.hcf.statistic.type.LivesStatistic
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import java.util.*
/**
* @project hcf
*
* @date 16/09/2020
* @author xanderume@gmail.com
*/
object ReviveCommand {
const val MOD_PERMISSION = "hcf.command.revive.advanced"
@JvmStatic
@Command(names = ["revive","pvp revive","lives revive"],async = true)
fun execute(sender: CommandSender,@Parameter(name = "player")uuid: UUID) {
var lives = 0
if (sender is Player && !sender.hasPermission(MOD_PERMISSION)) {
if (EOTWHandler.isActive()) {
sender.sendMessage("${ChatColor.RED}You cannot use lives during EOTW.")
return
}
lives = StatisticHandler.getStatistic(sender.uniqueId,LivesStatistic).getValue()
if (lives <= 0) {
sender.sendMessage("${ChatColor.RED}You have no lives!")
return
}
}
val name = UUIDHandler.getUsernameById(uuid)
val death = StatisticHandler.getStatistic(uuid,DeathStatistic).getValue()
if (death == null || !death.isActive()) {
sender.sendMessage("${ChatColor.RED}$name is not death-banned!")
return
}
if (sender is Player && !sender.hasPermission(MOD_PERMISSION) && lives > 0) {
StatisticHandler.increaseStatistic(sender.uniqueId,LivesStatistic,-1)
}
death.setRevived(if (sender is Player) sender.uniqueId else UUIDHandler.CONSOLE_ID)
DeathRepository.updateById(death)
StatisticHandler.setStatistic(uuid,DeathStatistic,death)
sender.sendMessage("${ChatColor.YELLOW}Revived ${ChatColor.LIGHT_PURPLE}$name${ChatColor.YELLOW}!")
}
}

View File

@ -0,0 +1,129 @@
package cc.fyre.hcf.death.listener
import cc.fyre.core.server.ServerModule
import cc.fyre.core.server.message.ServerMessageType
import cc.fyre.shard.util.TimeUtil
import cc.fyre.hcf.HCF
import cc.fyre.hcf.death.Death
import cc.fyre.hcf.death.DeathHandler
import cc.fyre.hcf.death.DeathRepository
import cc.fyre.hcf.death.DeathStatistic
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.hcf.statistic.type.LivesStatistic
import cc.fyre.shard.util.bungee.BungeeUtil
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.block.Sign
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.AsyncPlayerPreLoginEvent
import org.bukkit.event.player.PlayerRespawnEvent
import java.util.*
import java.util.function.Predicate
/**
* @project hcf
*
* @date 14/09/2020
* @author xanderume@gmail.com
*/
object DeathListener : Listener {
@EventHandler(priority = EventPriority.HIGHEST)
private fun onAsyncPreLogin(event: AsyncPlayerPreLoginEvent) {
if (HCF.instance.isKitMap()) {
return
}
val death = StatisticHandler.getStatistic(event.uniqueId,DeathStatistic).getValue()
if (death == null || !death.isActive()) {
return
}
val lives = StatisticHandler.getStatistic(event.uniqueId,LivesStatistic).getValue()
if (lives != 0) {
StatisticHandler.increaseStatistic(event.uniqueId,LivesStatistic,-1)
return
}
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER,"${ChatColor.YELLOW}Come back in ${ChatColor.GOLD}${TimeUtil.formatIntoDetailedString(death.getRemaining())}${ChatColor.YELLOW}!")
}
@EventHandler(priority = EventPriority.HIGHEST)
private fun onPlayerDeath(event: PlayerDeathEvent) {
val death = Death(UUID.randomUUID(),event.entity,event.deathMessage,event.entity.killer)
if (event.entity.killer != null) {
event.entity.world.dropItemNaturally(event.entity.location,DeathHandler.getDeathSign(event.entity,event.entity.killer))
}
StatisticHandler.setStatistic(event.entity.uniqueId,DeathStatistic,death)
Bukkit.getServer().scheduler.runTaskAsynchronously(HCF.instance) {
DeathRepository.updateById(death)
}
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onPlayerRespawn(event: PlayerRespawnEvent) {
if (HCF.instance.isKitMap()) {
return
}
val death = StatisticHandler.getStatistic(event.player.uniqueId,DeathStatistic).getValue()
if (death == null || !death.isActive()) {
return
}
ServerModule.sendToBungee(event.player,ServerMessageType.SEND_TO_HUB,Predicate{
return@Predicate true
})
event.player.sendMessage("${ChatColor.YELLOW}Come back in ${ChatColor.GOLD}${TimeUtil.formatIntoDetailedString(death.getRemaining())}${ChatColor.YELLOW}!")
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onBlockPlace(event: BlockPlaceEvent) {
if (event.isCancelled) {
return
}
val item = event.player.itemInHand
if (!(item.type == Material.SIGN_POST || item.type == Material.WALL_SIGN)) {
return
}
if (!item.hasItemMeta() || !item.itemMeta.hasDisplayName() || item.itemMeta.displayName != DeathHandler.DEATH_SIGN_NAME || !item.itemMeta.hasLore()) {
return
}
val lore = item.itemMeta.lore
val state = event.block.state as Sign
for (i in 0..3) {
if (i > lore.lastIndex) {
break
}
state.setLine(i,lore[i])
}
state.update(true)
}
}

View File

@ -0,0 +1,42 @@
package cc.fyre.hcf.death.listener
import cc.fyre.circuit.data.Packet
import cc.fyre.circuit.data.PacketListener
import cc.fyre.circuit.data.PacketPriority
import cc.fyre.core.server.ServerModule
import cc.fyre.hcf.HCF
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.hcf.statistic.type.LivesStatistic
import cc.fyre.shard.moshi.json.JsonObject
import java.util.*
/**
* @project hcf
*
* @date 19/11/2020
* @author xanderume@gmail.com
*/
object DeathPacketListener : PacketListener {
/*TODO
@Packet(id = "HCF_LIFE_USE",priority = PacketPriority.LOWEST,forceLocal = true)
fun onUseLife(data: JsonObject) {
if (!ServerModule.getServerId().equals(data.getString("server"),true)) {
return
}
val uuid = UUID.fromString(data.getString("_id"))
val death = this.instance.deathHandler.cache[uuid]
// should never really be null but just in case
if (death != null) {
death.setRevived(uuid)
this.instance.deathHandler.repository.update(death)
}
StatisticHandler.increaseStatistic(uuid,LivesStatistic,-1)
}*/
}

View File

@ -0,0 +1,18 @@
package cc.fyre.hcf.death.loadout
import com.squareup.moshi.JsonClass
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
/**
* @project hcf
*
* @date 16/11/2020
* @author xanderume@gmail.com
*/
@JsonClass(generateAdapter = true)
data class DeathLoadout(val armor: List<ItemStack>, val contents: List<ItemStack>, val health: Double, val foodLevel: Int) {
constructor(player: Player):this(player.inventory.armorContents.filterNotNull().toList(),player.inventory.contents.filterNotNull().toList(),player.health,player.foodLevel)
}

View File

@ -0,0 +1,35 @@
package cc.fyre.hcf.death.menu
import cc.fyre.hcf.death.Death
import cc.fyre.hcf.death.menu.element.DeathElement
import cc.fyre.shard.menu.button.Button
import cc.fyre.shard.menu.type.paginated.PaginatedMenu
import org.bukkit.entity.Player
import java.util.*
import kotlin.collections.HashMap
/**
* @project hcf
*
* @date 18/09/2020
* @author xanderume@gmail.com
*/
class DeathsMenu(private val id: UUID,private val deaths: Collection<Death>) : PaginatedMenu() {
override fun getTitle(player: Player): String {
return "Deaths"
}
override fun getButtonsPerPage(player: Player): Int {
return 3*9
}
override fun getPagedButtons(player: Player): HashMap<Int, Button> {
return this.deaths
.sortedByDescending{it.time}
.withIndex()
.associate{it.index to DeathElement(it.value)}
.toMap(HashMap())
}
}

View File

@ -0,0 +1,43 @@
package cc.fyre.hcf.death.menu
import cc.fyre.hcf.death.Death
import cc.fyre.hcf.death.menu.element.DeathRefundElement
import cc.fyre.hcf.death.menu.element.DeathReviveElement
import cc.fyre.shard.menu.Menu
import cc.fyre.shard.menu.button.Button
import org.bukkit.entity.Player
/**
* @project hcf
*
* @date 19/09/2020
* @author xanderume@gmail.com
*/
class DeathsRefundMenu(private val death: Death) : Menu() {
override fun getSize(player: Player, buttons: Map<Int, Button>): Int {
return 5*9
}
override fun getTitle(player: Player): String {
return "Refund"
}
override fun getButtons(player: Player): MutableMap<Int, Button> {
val toReturn = mutableMapOf<Int,Button>()
this.death.loadout!!.contents.forEach{toReturn[toReturn.size] = Button.fromItem(it.clone())}
this.death.loadout!!.armor.withIndex().reversed().forEach{toReturn[36 + it.index] = Button.fromItem(it.value.clone())}
toReturn[44] = DeathRefundElement(this.death)
toReturn[43] = DeathReviveElement(this.death)
return toReturn
}
override fun isFill(player: Player, buttons: Map<Int, Button>): Boolean {
return true
}
}

View File

@ -0,0 +1,82 @@
package cc.fyre.hcf.death.menu.element
import cc.fyre.shard.util.TimeUtil
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.death.Death
import cc.fyre.hcf.death.menu.DeathsRefundMenu
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.shard.menu.button.Button
import org.apache.commons.lang.StringUtils
import org.bukkit.ChatColor
import org.bukkit.DyeColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
import java.util.*
import kotlin.collections.ArrayList
/**
* @project hcf
*
* @date 18/09/2020
* @author xanderume@gmail.com
*/
class DeathElement(private val death: Death) : Button() {
override fun getItem(player: Player): ItemStack {
var color = DyeColor.RED
if (this.death.isActive()) {
color = DyeColor.GREEN
} else {
if (!this.death.isRefunded()) {
color = DyeColor.YELLOW
}
}
val lore = ArrayList<String>()
lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
lore.add("${ChatColor.YELLOW}Reason: ${ChatColor.RED}${ChatColor.stripColor(this.death.reason)}")
if (this.death.deathBanTime != 0L) {
lore.add("${ChatColor.YELLOW}Duration: ${ChatColor.RED}${TimeUtil.formatIntoDetailedString(this.death.deathBanTime)}")
}
if (this.death.isRevived()) {
lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
lore.add("${ChatColor.RED}${ChatColor.BOLD}Revived")
lore.add(" ")
lore.add("${ChatColor.YELLOW}By: ${ChatColor.RED}${UUIDHandler.getUsernameById(this.death.reviver!!)}")
lore.add(" ")
lore.add("${ChatColor.GOLD}${TimeUtil.formatIntoCalendarString(Date(this.death.revived!!))}")
}
if (this.death.isRefunded()) {
lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
lore.add("${ChatColor.RED}${ChatColor.BOLD}Refunded")
lore.add(" ")
lore.add("${ChatColor.YELLOW}By: ${ChatColor.RED}${UUIDHandler.getUsernameById(this.death.refunder!!)}")
lore.add(" ")
lore.add("${ChatColor.GOLD}${TimeUtil.formatIntoCalendarString(Date(this.death.refunded!!))}")
}
if (!this.death.isRefunded()) {
lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
lore.add("${ChatColor.RED}Click to refund.")
}
lore.add("${ChatColor.GRAY}${ChatColor.STRIKETHROUGH}${StringUtils.repeat("-",18)}")
return ItemBuilder.of(Material.WOOL).name("${ChatColor.GOLD}${TimeUtil.formatIntoCalendarString(Date(this.death.time))}").data(color.woolData.toShort()).lore(lore).build()
}
override fun onClick(player: Player,event: InventoryClickEvent) {
DeathsRefundMenu(this.death).open(player)
}
}

View File

@ -0,0 +1,56 @@
package cc.fyre.hcf.death.menu.element
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.HCF
import cc.fyre.hcf.death.Death
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.hcf.death.DeathRepository
import cc.fyre.hcf.death.DeathStatistic
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.shard.menu.button.Button
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
/**
* @project hcf
*
* @date 19/09/2020
* @author xanderume@gmail.com
*/
class DeathRefundElement(private val death: Death) : Button() {
override fun getItem(player: Player): ItemStack {
return ItemBuilder.of(if (this.death.isRefunded()) Material.MINECART else Material.STORAGE_MINECART).name("${if (this.death.isRefunded()) ChatColor.RED else ChatColor.GREEN}${ChatColor.BOLD}Refund Inventory").build()
}
override fun onClick(player: Player,event: InventoryClickEvent) {
if (this.death.isRefunded()) {
player.sendMessage("${ChatColor.RED}This inventory has already been refunded.")
return
}
val target = HCF.instance.server.getPlayer(this.death.player)
if (target == null) {
player.sendMessage("${ChatColor.RED}${UUIDHandler.getUsernameById(this.death.player)} is not online.")
return
}
target.inventory.contents = this.death.loadout!!.contents.toTypedArray()
target.inventory.armorContents = this.death.loadout!!.armor.toTypedArray()
this.death.setRefunded(player.uniqueId)
Bukkit.getServer().scheduler.runTaskAsynchronously(HCF.instance) {
DeathRepository.updateById(this.death)
}
player.sendMessage("${ChatColor.GREEN}Refunded Inventory.")
}
}

View File

@ -0,0 +1,57 @@
package cc.fyre.hcf.death.menu.element
import cc.fyre.hcf.HCF
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.death.Death
import cc.fyre.hcf.death.DeathRepository
import cc.fyre.hcf.death.DeathStatistic
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.shard.menu.button.Button
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
/**
* @project hcf
*
* @date 19/09/2020
* @author xanderume@gmail.com
*/
class DeathReviveElement(private val death: Death) : Button() {
override fun getItem(player: Player): ItemStack {
return ItemBuilder.of(Material.BED).name("${if (this.death.isRevived()) ChatColor.RED else ChatColor.GREEN}${ChatColor.BOLD}Revive").build()
}
override fun onClick(player: Player,event: InventoryClickEvent) {
if (!this.death.isActive()) {
player.sendMessage("${ChatColor.RED}This death has already expired.")
return
}
if (this.death.isRevived()) {
player.sendMessage("${ChatColor.RED}This death has already been revived.")
return
}
this.death.setRevived(event.whoClicked.uniqueId)
Bukkit.getServer().scheduler.runTaskAsynchronously(HCF.instance) {
if (StatisticHandler.getStatistic(player.uniqueId, DeathStatistic).getValue()?.id == this.death.id) {
StatisticHandler.setStatistic(this.death.player, DeathStatistic,this.death)
}
DeathRepository.updateById(this.death)
}
player.sendMessage("${ChatColor.GREEN}Revived.")
return
}
}

View File

@ -0,0 +1,32 @@
package cc.fyre.hcf.deathmessage
import cc.fyre.shard.util.entity.EntityUtil
import org.apache.commons.lang.WordUtils
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Entity
import org.bukkit.entity.EntityType
import org.bukkit.entity.Player
import java.util.*
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
abstract class Damage(val uuid: UUID,val damage: Double) {
val time = System.currentTimeMillis()
fun getFormattedMessage(uuid: UUID):String {
return "${DeathMessageHandler.getFormat(uuid)}${ChatColor.YELLOW} ${this.getDeathMessage(uuid)}${ChatColor.YELLOW}."
}
abstract fun getDeathMessage(uuid: UUID):String
fun getTimeAgo():Long {
return System.currentTimeMillis() - this.time
}
}

View File

@ -0,0 +1,59 @@
package cc.fyre.hcf.deathmessage
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.hcf.statistic.type.KillsStatistic
import net.minecraft.util.com.google.common.cache.CacheBuilder
import org.bukkit.ChatColor
import org.bukkit.entity.Player
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object DeathMessageHandler {
private val damage = CacheBuilder.newBuilder()
.expireAfterAccess(10L,TimeUnit.MINUTES)
.build<UUID,ArrayList<Damage>>()
fun create(player: Player) {
this.damage.put(player.uniqueId,arrayListOf())
}
fun destroy(player: Player) {
this.damage.invalidate(player)
}
fun getAllDamageByPlayer(player: Player):List<Damage>? {
return this.damage.getIfPresent(player.uniqueId)
}
fun addDamageByPlayer(player: Player,damage: Damage) {
var cache = this.damage.getIfPresent(player.uniqueId)
if (cache == null) {
cache = arrayListOf()
this.damage.put(player.uniqueId,cache)
}
if (cache.size > MAX_ENTRIES) {
cache = cache.toTypedArray().copyOfRange(0,MAX_ENTRIES - 1).toCollection(arrayListOf())
}
cache.add(0,damage)
}
fun getFormat(uuid: UUID): String {
return "${ChatColor.RED}${UUIDHandler.getUsernameById(uuid)}${ChatColor.DARK_RED}[${StatisticHandler.getStatistic(uuid,KillsStatistic).getValue()}]"
}
private const val MAX_ENTRIES = 30
}

View File

@ -0,0 +1,39 @@
package cc.fyre.hcf.deathmessage
import cc.fyre.hcf.HCF
import cc.fyre.hcf.HCFModule
import cc.fyre.hcf.deathmessage.listener.DeathMessageListener
import cc.fyre.hcf.deathmessage.tracker.*
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import org.bukkit.event.Listener
object DeathMessageModule : HCFModule {
override fun init(core: HCF) {
}
override fun shutdown(core: HCF) {
}
override fun getCommands(): List<Class<*>> {
return listOf()
}
override fun getAdapters(): Map<Class<*>, ParameterAdapter<*>> {
return mapOf()
}
override fun getListeners(): List<Listener> {
return listOf(
PvPTracker,
BurnTracker,
FallTracker,
VoidTracker,
ArrowTracker,
EntityTracker,
GeneralTracker,
DeathMessageListener
)
}
}

View File

@ -0,0 +1,29 @@
package cc.fyre.hcf.deathmessage.event
import cc.fyre.hcf.deathmessage.Damage
import org.bukkit.entity.Player
import org.bukkit.event.HandlerList
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.player.PlayerEvent
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
class PlayerDamageEvent(val event: EntityDamageEvent,var damage: Damage) : PlayerEvent(event.entity as Player) {
fun getDamage():Double {
return this.event.getDamage(EntityDamageEvent.DamageModifier.BASE)
}
override fun getHandlers(): HandlerList {
return handlerList
}
companion object {
@JvmStatic val handlerList = HandlerList()
}
}

View File

@ -0,0 +1,104 @@
package cc.fyre.hcf.deathmessage.listener
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import cc.fyre.hcf.deathmessage.type.UnknownDamage
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.statistic.StatisticHandler
import cc.fyre.hcf.statistic.type.setting.DeathMessageSetting
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
import java.util.concurrent.TimeUnit
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object DeathMessageListener : Listener {
@EventHandler(priority = EventPriority.NORMAL)
private fun onPlayerJoin(event: PlayerJoinEvent) {
DeathMessageHandler.create(event.player)
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onPlayerDamage(event: PlayerDamageEvent) {
DeathMessageHandler.addDamageByPlayer(event.player,event.damage)
}
@EventHandler(priority = EventPriority.MONITOR,ignoreCancelled = true)
private fun onEntityDamage(event: EntityDamageEvent) {
if (event.entity !is Player) {
return
}
Bukkit.getServer().pluginManager.callEvent(PlayerDamageEvent(event,UnknownDamage(event.entity.uniqueId,event.getDamage(EntityDamageEvent.DamageModifier.BASE))))
}
@EventHandler(priority = EventPriority.LOWEST)
private fun onPlayerDeath(event: PlayerDeathEvent) {
var damage = DeathMessageHandler.getAllDamageByPlayer(event.entity)?.firstOrNull()
if (damage == null) {
damage = UnknownDamage(event.entity.uniqueId,1.0)
}
event.deathMessage = damage.getFormattedMessage(event.entity.uniqueId)
if (damage !is PlayerDamage) {
return
}
if (damage.getTimeAgo() > TimeUnit.MINUTES.toMillis(1L)) {
return
}
val damager = Bukkit.getServer().getPlayer(damage.attacker) ?: return
(event.entity as CraftPlayer).handle.killer = (damager as CraftPlayer).handle
}
@EventHandler(priority = EventPriority.MONITOR)
private fun onBroadcastMessage(event: PlayerDeathEvent) {
val faction = FactionHandler.getFactionByPlayer(event.entity.uniqueId)
Bukkit.getServer().onlinePlayers.filter{
if (event.entity.uniqueId == it.uniqueId) {
return@filter true
}
if (event.entity.killer != null && event.entity.killer.uniqueId == it.uniqueId) {
return@filter true
}
if (faction != null && faction.isFriendly(it)) {
return@filter true
}
return@filter StatisticHandler.getStatistic(it.uniqueId,DeathMessageSetting).getValue()
}.forEach{it.sendMessage(event.deathMessage)}
event.deathMessage = null
DeathMessageHandler.destroy(event.entity)
}
}

View File

@ -0,0 +1,63 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.ArrowDamage
import cc.fyre.hcf.deathmessage.type.mob.ArrowDamageByMob
import cc.fyre.hcf.deathmessage.type.player.ArrowDamageByPlayer
import org.bukkit.Location
import org.bukkit.entity.Arrow
import org.bukkit.entity.Entity
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.entity.EntityShootBowEvent
import org.bukkit.event.entity.ProjectileHitEvent
import java.util.*
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object ArrowTracker : Listener {
private val cache = mutableMapOf<UUID,Location>()
@EventHandler(priority = EventPriority.NORMAL)
private fun onEntityShootBow(event: EntityShootBowEvent) {
if (event.entity !is Player) {
return
}
this.cache[event.entity.uniqueId] = event.projectile.location
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
fun onPlayerDamage(event: PlayerDamageEvent) {
if (event.event !is EntityDamageByEntityEvent) {
return
}
if (event.event.damager !is Arrow) {
return
}
val shooter = (event.event.damager as Arrow).shooter
event.damage = when (shooter) {
is Player -> ArrowDamageByPlayer(event.player.uniqueId,event.getDamage(),shooter.uniqueId,this.cache.remove(shooter.uniqueId)?.distance(event.player.location) ?: 0.0)
is Entity -> ArrowDamageByMob(event.player.uniqueId,event.getDamage(),shooter as Entity)
else -> ArrowDamage(event.player.uniqueId,event.getDamage())
}
}
}

View File

@ -0,0 +1,57 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.BurnDamage
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import cc.fyre.hcf.deathmessage.type.player.BurnDamageByPlayer
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
import java.util.concurrent.TimeUnit
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object BurnTracker : Listener {
@EventHandler(priority = EventPriority.LOW)
private fun onPlayerDamage(event: PlayerDamageEvent) {
if (event.event.cause !== EntityDamageEvent.DamageCause.FIRE_TICK && event.event.cause !== EntityDamageEvent.DamageCause.LAVA) {
return
}
val damage = DeathMessageHandler.getAllDamageByPlayer(event.player)
var knocked = 0L
var knocker: PlayerDamage? = null
if (damage != null && damage.isNotEmpty()) {
damage.firstOrNull{it !is BurnDamage && it !is BurnDamageByPlayer && (it is PlayerDamage && (knocker == null || it.time > knocked))}.also{
if (it == null) {
return@also
}
knocker = it as PlayerDamage
knocked = it.time
}
}
event.damage = if (knocker != null && knocked + TimeUnit.MINUTES.toMillis(1L) > System.currentTimeMillis()) {
BurnDamageByPlayer(event.player.uniqueId,event.getDamage(),knocker!!.attacker)
} else {
BurnDamage(event.player.uniqueId,event.getDamage())
}
}
}

View File

@ -0,0 +1,36 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.mob.EntityDamage
import org.bukkit.entity.Arrow
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageByEntityEvent
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object EntityTracker : Listener {
@EventHandler(priority = EventPriority.LOW,ignoreCancelled = true)
private fun onPlayerDamage(event: PlayerDamageEvent) {
if (event.event !is EntityDamageByEntityEvent) {
return
}
if (event.event.damager is Player || event.event.damager is Arrow) {
return
}
event.damage = EntityDamage(event.player.uniqueId,event.getDamage(),event.event.damager)
}
}

View File

@ -0,0 +1,61 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.BurnDamage
import cc.fyre.hcf.deathmessage.type.FallDamage
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import cc.fyre.hcf.deathmessage.type.VoidDamage
import cc.fyre.hcf.deathmessage.type.player.BurnDamageByPlayer
import cc.fyre.hcf.deathmessage.type.player.FallDamageByPlayer
import cc.fyre.hcf.deathmessage.type.player.VoidDamageByPlayer
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
import java.util.concurrent.TimeUnit
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object FallTracker : Listener {
@EventHandler(priority = EventPriority.LOW)
private fun onPlayerDamage(event: PlayerDamageEvent) {
if (event.event.cause != EntityDamageEvent.DamageCause.FALL) {
return
}
val damage = DeathMessageHandler.getAllDamageByPlayer(event.player)
var knocked = 0L
var knocker: PlayerDamage? = null
if (damage != null && damage.isNotEmpty()) {
damage.firstOrNull{it !is FallDamage && it !is FallDamageByPlayer && (it is PlayerDamage && (knocker == null || it.time > knocked))}.also{
if (it == null) {
return@also
}
knocker = it as PlayerDamage
knocked = it.time
}
}
event.damage = if (knocker != null && knocked + TimeUnit.MINUTES.toMillis(1L) > System.currentTimeMillis()) {
FallDamageByPlayer(event.player.uniqueId,event.getDamage(),knocker!!.attacker)
} else {
FallDamage(event.player.uniqueId,event.getDamage())
}
}
}

View File

@ -0,0 +1,34 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.GeneralDamage
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object GeneralTracker : Listener {
@EventHandler(priority = EventPriority.LOW,ignoreCancelled = true)
fun onCustomPlayerDamage(event: PlayerDamageEvent) {
when (event.event.cause) {
EntityDamageEvent.DamageCause.WITHER -> event.damage = GeneralDamage(event.player.uniqueId,event.getDamage(),"withered away")
EntityDamageEvent.DamageCause.POISON -> event.damage = GeneralDamage(event.player.uniqueId,event.getDamage(),"was poisoned")
EntityDamageEvent.DamageCause.DROWNING -> event.damage = GeneralDamage(event.player.uniqueId,event.getDamage(),"drowned")
EntityDamageEvent.DamageCause.LIGHTNING ->event.damage = GeneralDamage(event.player.uniqueId,event.getDamage(),"was struck by lightning")
EntityDamageEvent.DamageCause.STARVATION -> event.damage = GeneralDamage(event.player.uniqueId,event.getDamage(),"starved to death")
EntityDamageEvent.DamageCause.SUFFOCATION -> event.damage = GeneralDamage(event.player.uniqueId,event.getDamage(),"suffocated")
}
}
}

View File

@ -0,0 +1,35 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.player.PvPDamage
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageByEntityEvent
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object PvPTracker : Listener {
@EventHandler(priority = EventPriority.LOW,ignoreCancelled = true)
private fun onPlayerDamage(event: PlayerDamageEvent) {
if (event.event !is EntityDamageByEntityEvent) {
return
}
if (event.event.damager !is Player) {
return
}
event.damage = PvPDamage(event.player.uniqueId,event.getDamage(),event.event.damager as Player)
}
}

View File

@ -0,0 +1,58 @@
package cc.fyre.hcf.deathmessage.tracker
import cc.fyre.hcf.HCF
import cc.fyre.hcf.deathmessage.Damage
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.event.PlayerDamageEvent
import cc.fyre.hcf.deathmessage.type.FallDamage
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import cc.fyre.hcf.deathmessage.type.VoidDamage
import cc.fyre.hcf.deathmessage.type.player.FallDamageByPlayer
import cc.fyre.hcf.deathmessage.type.player.VoidDamageByPlayer
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityDamageEvent
import java.util.concurrent.TimeUnit
/**
* @project engine
*
* @date 15/08/2020
* @author xanderume@gmail.com
*/
object VoidTracker : Listener {
@EventHandler(priority = EventPriority.LOW)
private fun onPlayerDamage(event: PlayerDamageEvent) {
if (event.event.cause != EntityDamageEvent.DamageCause.VOID) {
return
}
val damage = DeathMessageHandler.getAllDamageByPlayer(event.player)
var knocked = 0L
var knocker: PlayerDamage? = null
if (damage != null && damage.isNotEmpty()) {
damage.firstOrNull{it !is VoidDamage && it !is VoidDamageByPlayer && (it is PlayerDamage && (knocker == null || it.time > knocked))}.also{
if (it == null) {
return@also
}
knocker = it as PlayerDamage
knocked = it.time
}
}
event.damage = if (knocker != null && knocked + TimeUnit.MINUTES.toMillis(1L) > System.currentTimeMillis()) {
VoidDamageByPlayer(event.player.uniqueId,event.getDamage(),knocker!!.attacker)
} else {
VoidDamage(event.player.uniqueId,event.getDamage())
}
}
}

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
class ArrowDamage(damaged: UUID, damage: Double) : Damage(damaged,damage) {
override fun getDeathMessage(uuid: UUID): String {
return "was shot"
}
}

View File

@ -0,0 +1,12 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
class BurnDamage(damaged: UUID, damage: Double) : Damage(damaged,damage) {
override fun getDeathMessage(uuid: UUID): String {
return "burned to death"
}
}

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
class FallDamage(damaged: UUID, damage: Double) : Damage(damaged,damage) {
override fun getDeathMessage(uuid: UUID):String {
return "hit the ground too hard"
}
}

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
class GeneralDamage(damaged: UUID, damage: Double, private val message: String) : Damage(damaged,damage) {
override fun getDeathMessage(uuid: UUID): String {
return this.message
}
}

View File

@ -0,0 +1,7 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import org.bukkit.entity.EntityType
import java.util.*
abstract class MobDamage(uuid: UUID, damage: Double, val entityType: EntityType) : Damage(uuid,damage)

View File

@ -0,0 +1,6 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
abstract class PlayerDamage(uuid: UUID, damage: Double, val attacker: UUID) : Damage(uuid,damage)

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
class UnknownDamage(uuid: UUID, damage: Double) : Damage(uuid,damage) {
override fun getDeathMessage(uuid: UUID):String {
return "died"
}
}

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type
import cc.fyre.hcf.deathmessage.Damage
import java.util.*
class VoidDamage(damaged: UUID?, damage: Double) : Damage(damaged!!, damage) {
override fun getDeathMessage(uuid: UUID): String {
return "fell into the void"
}
}

View File

@ -0,0 +1,15 @@
package cc.fyre.hcf.deathmessage.type.mob
import cc.fyre.hcf.deathmessage.type.MobDamage
import cc.fyre.shard.util.entity.EntityUtil
import org.bukkit.ChatColor
import org.bukkit.entity.Entity
import java.util.*
class ArrowDamageByMob(damaged: UUID, damage: Double, attacker: Entity) : MobDamage(damaged,damage,attacker.type) {
override fun getDeathMessage(uuid: UUID):String {
return "was shot by a ${ChatColor.RED}${EntityUtil.getName(this.entityType)}"
}
}

View File

@ -0,0 +1,16 @@
package cc.fyre.hcf.deathmessage.type.mob
import cc.fyre.hcf.deathmessage.type.MobDamage
import cc.fyre.shard.util.entity.EntityUtil
import org.bukkit.ChatColor
import org.bukkit.entity.Entity
import java.util.*
class EntityDamage(damaged: UUID, damage: Double, entity: Entity) : MobDamage(damaged,damage,entity.type) {
override fun getDeathMessage(uuid: UUID):String {
return "was slain by a ${ChatColor.RED} ${EntityUtil.getName(this.entityType)}"
}
}

View File

@ -0,0 +1,18 @@
package cc.fyre.hcf.deathmessage.type.player
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import org.bukkit.ChatColor
import java.util.*
class ArrowDamageByPlayer(damaged: UUID, damage: Double, attacker: UUID, private val distance: Double) : PlayerDamage(damaged,damage,attacker) {
override fun getDeathMessage(uuid: UUID):String {
val distance = this.distance.toInt()
return "was shot by ${DeathMessageHandler.getFormat(this.attacker)}${ChatColor.YELLOW} from ${ChatColor.BLUE}${distance} block${if (distance == 1) "" else "s"}"
}
}

View File

@ -0,0 +1,14 @@
package cc.fyre.hcf.deathmessage.type.player
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import java.util.*
class BackStabDamageByPlayer(damaged: UUID, damage: Double, attacker: UUID) : PlayerDamage(damaged,damage,attacker) {
override fun getDeathMessage(uuid: UUID): String {
return "was backstabbed by ${DeathMessageHandler.getFormat(this.attacker)}"
}
}

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type.player
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import java.util.*
class BurnDamageByPlayer(damaged: UUID, damage: Double, attacker: UUID) : PlayerDamage(damaged,damage,attacker) {
override fun getDeathMessage(uuid: UUID): String {
return "burned to death thanks to ${DeathMessageHandler.getFormat(this.attacker)}"
}
}

View File

@ -0,0 +1,13 @@
package cc.fyre.hcf.deathmessage.type.player
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import java.util.*
class FallDamageByPlayer(damaged: UUID, damage: Double, attacker: UUID) : PlayerDamage(damaged,damage,attacker) {
override fun getDeathMessage(uuid: UUID): String {
return "hit the ground too hard thanks to ${DeathMessageHandler.getFormat(this.attacker)}"
}
}

View File

@ -0,0 +1,20 @@
package cc.fyre.hcf.deathmessage.type.player
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import org.apache.commons.lang.WordUtils
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.entity.Player
import java.util.*
class PvPDamage(damaged: UUID, damage: Double, attacker: Player) : PlayerDamage(damaged,damage,attacker.uniqueId) {
private var itemString = if (attacker.itemInHand.type == Material.AIR) "their firsts" else if (attacker.itemInHand.itemMeta.hasDisplayName()) ChatColor.stripColor(attacker.itemInHand.itemMeta.displayName) else WordUtils.capitalizeFully(attacker.itemInHand.type.name.replace('_', ' '))
override fun getDeathMessage(uuid: UUID): String {
return "was slain by ${DeathMessageHandler.getFormat(this.attacker)}${ChatColor.YELLOW} using ${ChatColor.RED}${this.itemString.trim{it <= ' '}}"
}
}

View File

@ -0,0 +1,14 @@
package cc.fyre.hcf.deathmessage.type.player
import cc.fyre.hcf.deathmessage.DeathMessageHandler
import cc.fyre.hcf.deathmessage.type.PlayerDamage
import java.util.*
class VoidDamageByPlayer(damaged: UUID, damage: Double, attacker: UUID) : PlayerDamage(damaged,damage,attacker) {
override fun getDeathMessage(uuid: UUID): String {
return "fell into the void thanks to ${DeathMessageHandler.getFormat(uuid)}"
}
}

View File

@ -0,0 +1,110 @@
package cc.fyre.hcf.faction
import cc.fyre.hcf.HCF
import cc.fyre.hcf.faction.claim.Claim
import cc.fyre.hcf.faction.event.FactionHQUpdateEvent
import com.lunarclient.bukkitapi.`object`.LCWaypoint
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.bukkit.ChatColor
import org.bukkit.Color
import org.bukkit.Location
import org.bukkit.command.CommandSender
import java.lang.IllegalStateException
import java.util.*
/**
* @project hcf
*
* @date 04/04/2020
* @author xanderume@gmail.com
*/
@JsonClass(generateAdapter = false)
abstract class Faction(
@Json(name = "_id")
val id: UUID,
var name: String,
val type: FactionType
) {
var hq: Location? = null
var claims = mutableListOf<Claim>()
var created = System.currentTimeMillis()
@Transient protected var wayPoint: LCWaypoint? = null
open fun init() {
if (this.hq == null) {
return
}
this.wayPoint = LCWaypoint(this.name,this.hq,Color.BLUE.asRGB(),true,true)
}
fun getHQ():Location? {
return this.hq
}
open fun setHQ(location: Location?) {
HCF.instance.server.pluginManager.callEvent(FactionHQUpdateEvent(this,this.hq,location))
this.hq = location
this.wayPoint = LCWaypoint(this.name,this.hq,Color.BLUE.asRGB(),true,true)
}
@JvmName("getWayPoint1")
fun getWayPoint():LCWaypoint? {
return this.wayPoint
}
fun addClaims(vararg claims: Claim) {
this.claims.addAll(claims.toSet())
this.flagForSave()
}
fun removeClaims(vararg claims: Claim) {
this.claims.removeAll(claims.toSet())
this.flagForSave()
}
fun flagForSave() {
FactionHandler.addUpdate(this.id)
}
abstract fun getDeathbanStatus(): DeathbanStatus
abstract fun sendInfo(sender: CommandSender)
abstract fun getDisplayName(faction: Faction):String
abstract fun getDisplayName(sender: CommandSender):String
open fun isConstant():Boolean {
return false
}
enum class DeathbanStatus(val displayName: String) {
DEATHBAN("${ChatColor.RED}Deathban"),
NON_DEATHBAN("${ChatColor.GREEN}Non-Deathban")
}
fun cloneWayPoint(color: Color,name: String? = this.name):LCWaypoint {
if (this.wayPoint == null) {
throw IllegalStateException("Cannot clone a null waypoint!")
}
return LCWaypoint(name,this.wayPoint!!.x,this.wayPoint!!.y,this.wayPoint!!.z,this.wayPoint!!.world,color.asRGB(),this.wayPoint!!.isForced,this.wayPoint!!.isVisible)
}
companion object {
const val MIN_NAME_LENGTH = 3
const val MAX_NAME_LENGTH = 16
val ALLY_COLOR = ChatColor.BLUE
val ENEMY_COLOR = ChatColor.RED
val FACTION_COLOR = ChatColor.GREEN
}
}

View File

@ -0,0 +1,186 @@
package cc.fyre.hcf.faction
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.hcf.HCF
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.hcf.faction.type.defaults.WarZoneFaction
import cc.fyre.hcf.faction.type.defaults.WildernessFaction
import cc.fyre.hcf.game.GameFaction
import cc.fyre.hcf.faction.claim.ClaimHandler
import cc.fyre.hcf.faction.service.TeamViewerService
import cc.fyre.hcf.faction.type.defaults.TheEndFaction
import cc.fyre.hcf.faction.type.defaults.TheNetherFaction
import cc.fyre.shard.util.StringUtil
import org.bukkit.Bukkit
import org.bukkit.GameMode
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.entity.Player
import java.text.DecimalFormat
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.regex.Pattern
/**
* @project hcf
*
* @date 04/04/2020
* @author xanderume@gmail.com
*/
object FactionHandler {
private val factions = ConcurrentHashMap<UUID,Faction>()
private val factionsByName = ConcurrentHashMap<String,Faction>()
private val factionsByType = ConcurrentHashMap<FactionType,ConcurrentHashMap.KeySetView<Faction,Boolean>>()
private val factionsByPlayer = ConcurrentHashMap<UUID,PlayerFaction>()
private val updateQueue = ConcurrentHashMap.newKeySet<UUID>()
private val deleteQueue = ConcurrentHashMap.newKeySet<UUID>()
fun init() {
FactionRepository.findAll().forEach{
this.factions[it.id] = it
this.factionsByName[it.name.lowercase()] = it
this.factionsByType.putIfAbsent(it.type,ConcurrentHashMap.newKeySet())
if (it is SystemFaction && it.type != FactionType.SYSTEM) {
this.factionsByType.getOrPut(FactionType.SYSTEM) {
ConcurrentHashMap.newKeySet()
}.add(it)
}
this.factionsByType[it.type]!!.add(it)
this.factionsByType.getOrPut(it.type) {
ConcurrentHashMap.newKeySet()
}.add(it)
if (it is PlayerFaction) {
it.members.keys.forEach{member -> this.factionsByPlayer[member] = it}
}
it.init()
}
Bukkit.getServer().scheduler.runTaskTimerAsynchronously(HCF.instance,TeamViewerService,40L,40L)
HCF.instance.logger.info("Loaded ${this.factions.size} ${StringUtil.pluralize("Faction",this.factions.size)} from MongoDB.")
}
fun getFactionById(uuid: UUID): Faction? {
return this.factions[uuid]
}
fun getFactionByName(name: String): Faction? {
return this.factionsByName[name.lowercase()]
}
fun getFactionByPlayer(player: UUID):PlayerFaction? {
return this.factionsByPlayer[player]
}
fun getFactionByArgument(argument: String): Faction? {
val foundByName = this.getFactionByName(argument)
if (foundByName != null) {
return foundByName
}
val id = UUIDHandler.getIdByUsername(argument) ?: return null
return this.factionsByPlayer[id]
}
fun getFactionByLocation(location: Location): Faction {
return ClaimHandler.getClaimDataByLocation(location)?.value ?: when {
location.world.environment == World.Environment.THE_END -> TheEndFaction
location.world.environment == World.Environment.NETHER -> TheNetherFaction
ClaimHandler.isWarZone(location) -> WarZoneFaction
else -> WildernessFaction
}
}
fun getAllFactions():Set<Faction> {
return this.factions.values.toSet()
}
fun getAllGameFactions():Set<GameFaction> {
return (this.factionsByType[FactionType.GAME] ?: setOf()).filterIsInstance<GameFaction>().toSet()
}
fun getAllSystemFactions():Set<SystemFaction> {
return (this.factionsByType[FactionType.SYSTEM] ?: setOf()).filterIsInstance<SystemFaction>().toSet()
}
fun getAllPlayerFactions():Set<PlayerFaction> {
return (this.factionsByType[FactionType.PLAYER] ?: setOf()).filterIsInstance<PlayerFaction>().toSet()
}
fun getActiveGameFactions():Set<GameFaction> {
return this.getAllGameFactions().filter{it.isActive()}.toSet()
}
fun update(faction: Faction) {
this.factions[faction.id] = faction
this.factionsByName[faction.name.lowercase()] = faction
this.factionsByType.getOrPut(faction.type) {
ConcurrentHashMap.newKeySet()
}.add(faction)
}
fun updateName(faction: Faction,name: String) {
this.factionsByName.remove(faction.name.lowercase())
this.factionsByName[name.lowercase()] = faction
}
fun destroy(faction: Faction) {
this.factions.remove(faction.id)
this.factionsByName.remove(faction.name.lowercase())
if (faction is SystemFaction && faction.type != FactionType.SYSTEM) {
this.factionsByType[FactionType.SYSTEM]?.remove(faction)
}
if (faction is PlayerFaction) {
faction.members.keys.forEach{this.factionsByPlayer.remove(it)}
}
this.factionsByType[faction.type]?.remove(faction)
this.updateQueue.remove(faction.id)
this.deleteQueue.add(faction.id)
}
fun addPlayer(player: UUID,faction: PlayerFaction) {
this.factionsByPlayer[player] = faction
}
fun removePlayer(player: UUID) {
this.factionsByPlayer.remove(player)
}
fun addUpdate(uuid: UUID) {
if (this.deleteQueue.contains(uuid)) {
return
}
this.updateQueue.add(uuid)
}
fun getAllUpdates():ConcurrentHashMap.KeySetView<UUID,Boolean> {
return this.updateQueue
}
fun getAllDeletes():ConcurrentHashMap.KeySetView<UUID,Boolean> {
return this.deleteQueue
}
fun isAdminOverride(player: Player):Boolean {
return player.gameMode == GameMode.CREATIVE && player.hasPermission("hcf.override")
}
val DTR_FORMAT = DecimalFormat("0.00")
val ALPHA_NUMERIC_PATTERN: Pattern = Pattern.compile("[^a-zA-Z0-9]")
}

View File

@ -0,0 +1,22 @@
package cc.fyre.hcf.faction
import cc.fyre.core.uuid.UUIDHandler
import cc.fyre.hcf.faction.type.player.ChatMode
import cc.fyre.hcf.faction.type.player.FactionRole
import com.squareup.moshi.JsonClass
import java.util.*
@JsonClass(generateAdapter = true)
data class FactionMember(
val uuid: UUID,
var role: FactionRole = FactionRole.MEMBER,
var chatMode: ChatMode = ChatMode.FACTION
) {
@Transient var online = false
fun getUsername():String {
return UUIDHandler.getUsernameById(this.uuid) ?: "null"
}
}

View File

@ -0,0 +1,33 @@
package cc.fyre.hcf.faction
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.shard.util.item.ItemBuilder
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
enum class FactionMetadata(val displayName: String,val icon: ItemStack) {
ROAD("${ChatColor.GOLD}Road", ItemBuilder.of(Material.RAILS).name("${ChatColor.GOLD}Road").build()),
SAFE_ZONE("${ChatColor.GREEN}Safe-Zone", ItemBuilder.of(Material.EMERALD_BLOCK).name("${ChatColor.GREEN}Safe Zone").build()),
NO_ENDER_PEARL("${ChatColor.DARK_PURPLE}No Pearling", ItemBuilder.of(Material.ENDER_PEARL).name("${ChatColor.DARK_PURPLE}Pearling").build());
fun isValidAtLocation(location: Location):Boolean {
val faction = FactionHandler.getFactionByLocation(location)
if (faction !is SystemFaction) {
return false
}
return faction.hasMetadata(this)
}
companion object {
val values = values()
}
}

View File

@ -0,0 +1,134 @@
package cc.fyre.hcf.faction
import cc.fyre.hcf.HCF
import cc.fyre.hcf.HCFModule
import cc.fyre.hcf.faction.claim.ClaimHandler
import cc.fyre.hcf.faction.claim.listener.ClaimListener
import cc.fyre.hcf.faction.claim.listener.ClaimPositionListener
import cc.fyre.hcf.faction.command.*
import cc.fyre.hcf.faction.command.admin.*
import cc.fyre.hcf.faction.command.captain.*
import cc.fyre.hcf.faction.command.coleader.*
import cc.fyre.hcf.faction.command.leader.FactionDisbandCommand
import cc.fyre.hcf.faction.command.leader.FactionLeaderCommand
import cc.fyre.hcf.faction.command.parameter.*
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.hcf.faction.listener.*
import cc.fyre.hcf.game.GameFaction
import cc.fyre.hcf.mountain.MountainFaction
import cc.fyre.shard.command.data.parameter.ParameterAdapter
import org.bukkit.event.Listener
object FactionModule : HCFModule {
override fun init(core: HCF) {
FactionHandler.init()
ClaimHandler.init()
}
override fun shutdown(core: HCF) {
FactionRepository.saveAll()
FactionRepository.deleteAll()
}
override fun onSave(core: HCF) {
FactionRepository.saveAll()
FactionRepository.deleteAll()
}
override fun getCommands(): List<Class<*>> {
return listOf(
FactionAcceptCommand::class.java,
FactionAnnouncementCommand::class.java,
FactionChatCommand::class.java,
FactionCreateCommand::class.java,
FactionDepositCommand::class.java,
FactionFocusCommand::class.java,
FactionHelpCommand::class.java,
FactionHQCommand::class.java,
FactionInfoCommand::class.java,
FactionLeaveCommand::class.java,
FactionListCommand::class.java,
FactionLocationCommand::class.java,
FactionLocationHomeCommand::class.java,
FactionMapCommand::class.java,
FactionRallyListener::class.java,
FactionRegenCommand::class.java,
FactionStuckCommand::class.java,
FactionTopCommand::class.java,
FactionAllyCommand::class.java,
FactionClaimCommand::class.java,
FactionInviteCommand::class.java,
FactionInviteRevokeCommand::class.java,
FactionKickCommand::class.java,
FactionSetHQCommand::class.java,
FactionWithdrawCommand::class.java,
FactionDemoteCommand::class.java,
FactionPromoteCommand::class.java,
FactionRenameCommand::class.java,
FactionUnAllyCommand::class.java,
FactionUnClaimCommand::class.java,
FactionDisbandCommand::class.java,
FactionLeaderCommand::class.java,
FactionBalanceAddCommand::class.java,
FactionBalanceRemoveCommand::class.java,
FactionBanCommand::class.java,
FactionBlacklistCommand::class.java,
FactionChatSpyAddCommand::class.java,
FactionChatSpyRemoveCommand::class.java,
FactionDisbandAllCommand::class.java,
FactionEditorCommand::class.java,
FactionForceDisbandCommand::class.java,
FactionMuteCommand::class.java,
FactionPointsAddCommand::class.java,
FactionPointsRemoveCommand::class.java,
FactionSetDTRCommand::class.java,
FactionSetDTRRegenCommand::class.java,
FactionTeleportCommand::class.java,
FactionFilterCommand::class.java,
FactionForceSetHQCommand::class.java,
FactionForceDisbandCommand::class.java
)
}
override fun getAdapters(): Map<Class<*>, ParameterAdapter<*>> {
return mapOf(
Faction::class.java to FactionParameterProvider,
GameFaction::class.java to GameFactionParameterProvider,
SystemFaction::class.java to SystemFactionParameterProvider,
PlayerFaction::class.java to PlayerFactionParameterProvider,
MountainFaction::class.java to MountainFactionParameterProvider
)
}
override fun getListeners(): List<Listener> {
return listOf(
FactionMapListener,
FactionMoveListener,
FactionChatListener,
FactionClaimListener,
FactionFocusListener,
FactionStaffListener,
FactionRallyListener,
FactionDeathListener,
FactionMemberListener,
FactionPistonListener,
FactionMetadataListener,
FactionSubclaimListener,
FactionWayPointListener,
FactionProtectionListener,
ClaimListener,
ClaimPositionListener
)
}
}

View File

@ -0,0 +1,83 @@
package cc.fyre.hcf.faction
import cc.fyre.hcf.HCF
import cc.fyre.shard.moshi.MoshiUtil
import cc.fyre.shard.util.MongoUtil
import cc.fyre.shard.util.StringUtil
import com.mongodb.client.model.DeleteOneModel
import com.mongodb.client.model.Filters
import com.mongodb.client.model.ReplaceOneModel
import com.mongodb.client.model.WriteModel
import org.bson.Document
import java.lang.Exception
/**
* @project hcf
*
* @date 17/11/2020
* @author xanderume@gmail.com
*/
object FactionRepository {
private val collection = HCF.instance.getMongoDB().getCollection("factions")
fun findAll():List<Faction> {
return this.collection.find().mapNotNull{MoshiUtil.instance.adapter(Faction::class.java).fromJson(it.toJson(MongoUtil.RELAXED_WRITE_SETTING))}
}
fun saveAll() {
val adapter = try {
MoshiUtil.instance.adapter(Faction::class.java)
} catch (ex: Exception) {
ex.printStackTrace()
return
}
val iterator = FactionHandler.getAllUpdates().iterator()
val bulkWrite = mutableListOf<WriteModel<Document>>()
while (iterator.hasNext()) {
val faction = FactionHandler.getFactionById(iterator.next())
if (faction != null) {
bulkWrite.add(ReplaceOneModel(
Filters.eq("_id",faction.id.toString()),
Document.parse(adapter.toJson(faction)),
MongoUtil.REPLACE_OPTIONS
))
}
iterator.remove()
}
if (bulkWrite.isEmpty()) {
return
}
this.collection.bulkWrite(bulkWrite)
HCF.instance.logger.info("Saved ${bulkWrite.size} ${StringUtil.pluralize("faction",bulkWrite.size)} to MongoDB.")
}
fun deleteAll() {
val iterator = FactionHandler.getAllDeletes().iterator()
val bulkWrite = mutableListOf<DeleteOneModel<Document>>()
while (iterator.hasNext()) {
bulkWrite.add(DeleteOneModel(Filters.eq("_id",iterator.next().toString())))
iterator.remove()
}
if (bulkWrite.isEmpty()) {
return
}
this.collection.bulkWrite(bulkWrite)
HCF.instance.logger.info("Deleted ${bulkWrite.size} factions from MongoDB.")
}
}

View File

@ -0,0 +1,10 @@
package cc.fyre.hcf.faction
enum class FactionType {
GAME,
PLAYER,
SYSTEM,
MOUNTAIN;
}

View File

@ -0,0 +1,207 @@
package cc.fyre.hcf.faction.claim
import cc.fyre.hcf.HCF
import cc.fyre.hcf.faction.Faction
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.faction.claim.coordinate.Coordinate
import cc.fyre.hcf.faction.claim.coordinate.CoordinateSet
import cc.fyre.shard.util.moshi.world.WorldSerializer
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.block.Block
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
/**
* @project hcf
*
* @date 04/04/2020
* @author xanderume@gmail.com
*/
@JsonClass(generateAdapter = true)
class Claim(
@WorldSerializer
val world: World,
x1: Int,
x2: Int,
z1: Int,
z2: Int,
) : Iterable<Coordinate> {
constructor(first: Location,second: Location):this(first.world,first.blockX,second.blockX,first.blockZ,second.blockZ)
@Json(name = "_id")
val id: UUID = UUID.randomUUID()
val x1 = min(x1,x2)
val x2 = max(x1,x2)
val z1 = min(z1,z2)
val z2 = max(z1,z2)
fun contains(world: String, x: Int,z: Int):Boolean {
return this.world.name == world && x >= this.x1 && x <= this.x2 && z >= this.z1 && z <= this.z2
}
fun contains(location: Location):Boolean {
return this.contains(location.world.name,location.blockX,location.blockZ)
}
fun getLower():Location {
return Location(this.world,this.x1.toDouble(),0.0,this.z1.toDouble())
}
fun getUpper():Location {
return Location(this.world,this.x2.toDouble(),256.0,this.z2.toDouble())
}
fun getCenter(): Location {
val x1 = this.x2 + 1
val z1 = this.z2 + 1
val location = Location(this.world,this.x1 + (x1 - this.x1) / 2.0,0.0,this.z1 + (z1 - this.z1) / 2.0)
return location.add(0.0,location.world.getHighestBlockYAt(location).toDouble(),0.0)
}
private fun expand(direction: Direction, amount: Int):Claim {
return when (direction) {
Direction.WEST -> Claim(this.world,this.x1,this.z2,this.z1,this.z2 + amount)
Direction.EAST -> Claim(this.world,this.x1,this.x2,this.z1 - amount,this.z2)
Direction.SOUTH -> Claim(this.world,this.x1,this.x2 + amount,this.z1,this.z2)
Direction.NORTH -> Claim(this.world,this.x1 - amount,this.x2,this.z1,this.z2)
else -> throw IllegalArgumentException("Invalid direction $direction")
}
}
fun outset(direction: Direction,amount: Int):Claim {
return when (direction) {
Direction.BOTH -> outset(Direction.HORIZONTAL,amount).outset(Direction.VERTICAL,amount)
Direction.VERTICAL -> expand(Direction.DOWN,amount).expand(Direction.UP,amount)
Direction.HORIZONTAL -> expand(Direction.NORTH,amount).expand(Direction.SOUTH,amount).expand(Direction.EAST,amount).expand(Direction.WEST,amount)
else -> throw IllegalArgumentException("Invalid direction $direction")
}
}
fun getCorners():Array<Location> {
return arrayOf(
Location(this.world,this.x1.toDouble(),0.0,this.z1.toDouble()),
Location(this.world,this.x2.toDouble(),0.0,this.z2.toDouble()),
Location(this.world,this.x1.toDouble(),0.0,this.z2.toDouble()),
Location(this.world,this.x2.toDouble(),0.0,this.z1.toDouble())
)
}
override fun equals(other: Any?): Boolean {
return other is Claim && this.getLower() == other.getLower() && this.getUpper() == other.getUpper()
}
override fun iterator():Iterator<Coordinate> {
return BorderIterator(this,this.x1,this.x2,this.z1,this.z2)
}
fun blockIterator():Iterator<Block> {
return CuboidBlockIterator(this.world,this.x1,0,this.z1,this.z1,256,this.z2)
}
override fun hashCode(): Int {
return Objects.hash(this.world.hashCode(),this.id.hashCode(),this.x1,this.x2,this.z1,this.z2)
}
// HCTeams can suck my dick nigga
class BorderIterator(val claim: Claim,x1: Int,x2: Int,z1: Int,z2: Int) : MutableIterator<Coordinate> {
private var x: Int = min(x1,x2)
private var z: Int = min(z1,z2)
private var next = true
private var direction = BorderDirection.POS_Z
private var minX: Int = this.claim.getLower().blockX
private var minZ: Int = this.claim.getLower().blockZ
private var maxX: Int = this.claim.getUpper().blockX
private var maxZ: Int = this.claim.getUpper().blockZ
override fun hasNext(): Boolean {
return this.next
}
override fun next():Coordinate {
if (this.direction == BorderDirection.POS_Z) {
if (++this.z == this.maxZ) {
this.direction = BorderDirection.POS_X
}
} else if (this.direction == BorderDirection.POS_X) {
if (++this.x == this.maxX) {
this.direction = BorderDirection.NEG_Z
}
} else if (this.direction == BorderDirection.NEG_Z) {
if (--this.z == this.minZ) {
this.direction = BorderDirection.NEG_X
}
} else if (this.direction == BorderDirection.NEG_X) {
if (--this.x == this.minX) {
this.next = false
}
}
return Coordinate(this.x,this.z)
}
override fun remove() {}
enum class BorderDirection {
POS_X,
POS_Z,
NEG_X,
NEG_Z
}
}
class CuboidBlockIterator(private val world: World, private val baseX: Int,private val baseY: Int,private val baseZ: Int, x2: Int, y2: Int, z2: Int) : MutableIterator<Block> {
private var x = 0
private var y = 0
private var z = 0
private val sizeX = abs(x2 - this.baseX) + 1
private val sizeY = abs(y2 - this.baseY) + 1
private val sizeZ = abs(z2 - this.baseZ) + 1
override fun hasNext(): Boolean {
return this.x < this.sizeX && this.y < this.sizeY && this.z < this.sizeZ
}
override fun next(): Block {
val block = this.world.getBlockAt(this.baseX + this.x,this.baseY + this.y,this.baseZ + this.z)
if (++this.x >= this.sizeX) {
if (++this.y >= this.sizeY) {
this.z++
this.y = 0
}
this.x = 0
}
return block
}
@Throws(UnsupportedOperationException::class)
override fun remove() {
throw UnsupportedOperationException()
}
}
enum class Direction {
NORTH,EAST,SOUTH,WEST,UP,DOWN,HORIZONTAL,VERTICAL,BOTH
}
}

View File

@ -0,0 +1,228 @@
package cc.fyre.hcf.faction.claim
import cc.fyre.hcf.faction.Faction
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.faction.claim.coordinate.CoordinateSet
import cc.fyre.hcf.faction.type.defaults.WildernessFaction
import cc.fyre.hcf.pillar.PillarHandler
import cc.fyre.hcf.pillar.PillarType
import com.google.common.collect.HashMultimap
import com.google.common.collect.Multimap
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.entity.Player
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.abs
object ClaimHandler {
private val buckets = ConcurrentHashMap<UUID,Multimap<CoordinateSet,Map.Entry<Claim,Faction>>>()
private val selections = mutableMapOf<UUID,ClaimSelection>()
fun init() {
Bukkit.getServer().worlds.forEach{this.buckets[it.uid] = HashMultimap.create()}
FactionHandler.getAllFactions().forEach{faction ->
faction.claims.forEach{claim ->
this.createClaimEntry(faction,claim)
}
}
}
fun createBucket(world: World) {
this.buckets[world.uid] = HashMultimap.create()
}
fun createClaimEntry(faction: Faction, claim: Claim) {
val step = 1 shl CoordinateSet.BITS
val entry = AbstractMap.SimpleEntry(claim,faction)
for (x in entry.key.x1..(entry.key.x2 + step) step step) {
for (z in entry.key.z1..(entry.key.z2 + step) step step) {
this.buckets[entry.key.world.uid]!!.put(CoordinateSet(x,z),entry)
}
}
}
fun getClaimDataByRadius(center: Location,x: Int,z: Int): Set<Map.Entry<Claim,Faction>> {
return this.getClaimDataByLocations(
Location(center.world,(center.blockX - x).toDouble(),0.0,(center.blockZ - z).toDouble()),
Location(center.world,(center.blockX + x).toDouble(),0.0,(center.blockZ + z).toDouble())
)
}
fun getClaimDataByLocation(location: Location):Map.Entry<Claim,Faction>? {
return this.buckets[location.world.uid]!![CoordinateSet(location.blockX,location.blockZ)]
.firstOrNull{it.key.contains(location)}
}
fun destroy(claim: Claim) {
val step = 1 shl CoordinateSet.BITS
for (x in claim.x1..(claim.x2 + step) step step) {
for (z in claim.z1..(claim.z2 + step) step step) {
val iterator = this.buckets[claim.world.uid]?.get(CoordinateSet(x,z))?.iterator() ?: continue
while (iterator.hasNext()) {
if (iterator.next().key == claim) {
iterator.remove()
}
}
}
}
}
fun getClaimDataByLocations(min: Location,max: Location):Set<Map.Entry<Claim,Faction>> {
val map = this.buckets[min.world.uid] ?: return setOf()
val step = 1 shl CoordinateSet.BITS
val regions = hashSetOf<Map.Entry<Claim,Faction>>()
for (x in min.blockX..(max.blockX + step) step step) {
for (z in min.blockZ..(max.blockZ + step) step step) {
val coordinate = CoordinateSet(x,z)
for (entry in map[coordinate]) {
if (regions.contains(entry)) {
continue
}
if (max.blockX >= entry.key.x1
&& min.blockX <= entry.key.x2
&& max.blockZ >= entry.key.z1
&& min.blockZ <= entry.key.z2
) {
regions.add(entry)
}
}
}
}
return regions
}
fun getAllSelections():MutableMap<UUID,ClaimSelection> {
return this.selections
}
fun getSelectionByPlayer(player: Player):ClaimSelection? {
return this.selections[player.uniqueId]
}
fun createSelection(slot: Int,player: Player,faction: Faction) {
if (this.selections.remove(player.uniqueId) != null) {
player.inventory.removeItem(ClaimSelection.ITEM)
PillarHandler.destroyPillars(player,PillarType.CLAIM_SELECTION)
}
player.inventory.setItem(slot,ClaimSelection.ITEM)
player.sendMessage("${ChatColor.GREEN}Gave you a claiming wand.")
this.selections[player.uniqueId] = ClaimSelection(faction)
}
fun destroySelection(player: Player, removeItem: Boolean = true):ClaimSelection? {
val selection = this.selections.remove(player.uniqueId)
if (selection != null && removeItem) {
player.inventory.removeItem(ClaimSelection.ITEM)
}
return selection
}
fun isClaimed(location: Location):Boolean {
if (this.isWarZone(location)) {
return true
}
return this.getClaimDataByLocation(location)?.key != null
}
fun getClaimByLocation(location: Location):Claim? {
return this.getClaimDataByLocation(location)?.key
}
fun containsOtherClaim(claim: Claim):Faction? {
if (abs(claim.x1 - claim.x2) == 0 || abs(claim.z1 - claim.z2) == 0) {
return null
}
val maxPoint: Location = claim.getUpper()
val minPoint: Location = claim.getLower()
for (x in minPoint.blockX..maxPoint.blockX) {
for (z in minPoint.blockZ..maxPoint.blockZ) {
val faction = FactionHandler.getFactionByLocation(Location(claim.world,x.toDouble(),80.0,z.toDouble()))
if (faction is WildernessFaction) {
continue
}
return faction
}
}
return null
}
fun getTouchingClaims(claim: Claim):HashSet<Claim> {
val touchingClaims = HashSet<Claim>()
for (coordinate in claim.outset(Claim.Direction.HORIZONTAL, BUFFER)) {
val loc = Location(
claim.world,
coordinate.x.toDouble(),
80.0,
coordinate.z.toDouble()
)
val claimAtLocation: Map.Entry<Claim,Faction>? = this.getClaimDataByLocation(loc)
if (claimAtLocation != null) {
touchingClaims.add(claimAtLocation.key)
}
}
return touchingClaims
}
fun isWarZone(location: Location):Boolean {
return abs(location.x) <= WARZONE_RADIUS
&& abs(location.z) <= WARZONE_RADIUS
}
fun isWilderness(location: Location):Boolean {
return abs(location.x) > WARZONE_RADIUS
|| abs(location.z) > WARZONE_RADIUS
}
const val MAX_CLAIMS = 2
const val MINIMUM_SIZE = 5
const val BUFFER = 1
const val WARZONE_RADIUS = 1000
const val WARZONE_RADIUS_BUILD = 350
}

View File

@ -0,0 +1,108 @@
package cc.fyre.hcf.faction.claim
import cc.fyre.shard.util.item.ItemBuilder
import cc.fyre.hcf.HCF
import cc.fyre.hcf.faction.Faction
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.faction.type.SystemFaction
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.event.block.Action
import kotlin.math.abs
/**
* @project hcf
*
* @date 04/04/2020
* @author xanderume@gmail.com
*/
class ClaimSelection(val faction: Faction) {
var first: Location? = null
var second: Location? = null
var lastUpdate: Long = 0
constructor(faction: Faction, first:Location, second: Location):this(faction) {
this.first = first
this.second = second
}
fun getFormattedMessage(action: Action,location: Location):Array<String?> {
val toReturn = arrayOfNulls<String>(2)
toReturn[0] = "${ChatColor.YELLOW}Set claim's location ${ChatColor.LIGHT_PURPLE}${if (action == Action.LEFT_CLICK_BLOCK) 1 else 2}${ChatColor.YELLOW} to ${ChatColor.GREEN}(${ChatColor.WHITE}${location.blockX}, ${location.blockY}, ${location.blockZ}${ChatColor.GREEN})${ChatColor.YELLOW}."
if (this.first != null && this.second != null) {
val price = this.getPrice()
val width = abs(this.first!!.blockX - this.second!!.blockX)
val length = abs(this.first!!.blockZ - this.second!!.blockZ)
toReturn[1] = "${ChatColor.YELLOW}Claim cost: ${if (this.faction is PlayerFaction && this.faction.balance < price) ChatColor.RED else ChatColor.GREEN}$${price}${ChatColor.YELLOW}, Current size: (${ChatColor.WHITE}$width, $length${ChatColor.YELLOW}), ${ChatColor.WHITE}${width * length}${ChatColor.YELLOW} blocks."
}
return toReturn
}
fun getPrice():Int {
if (this.faction is SystemFaction) {
return 0
}
var toReturn = 0.0
var modifier = PRICE_MODIFIER
val x: Int = abs(this.first!!.blockX - this.second!!.blockX)
val z: Int = abs(this.first!!.blockZ - this.second!!.blockZ)
var done = 0
var blocks = x * z
while (blocks > 0) {
done++
blocks--
toReturn += modifier
if (done == 250) {
done = 0
modifier += PRICE_MODIFIER
}
}
toReturn *= PRICE_MULTIPLIER
return toReturn.toInt()
}
companion object {
val ITEM = ItemBuilder.of(Material.WOOD_HOE)
.name("${ChatColor.GREEN}${ChatColor.ITALIC}Claiming Wand")
.lore(arrayListOf(
"",
"${ChatColor.YELLOW}Right Click ${ChatColor.GOLD}Air",
"${ChatColor.AQUA}- ${ChatColor.WHITE}Cancel current claim",
"",
"${ChatColor.YELLOW}Right/Left Click ${ChatColor.GOLD}Block",
"${ChatColor.AQUA}- ${ChatColor.WHITE}Select claim's corners",
"",
"${ChatColor.BLUE}Crouch ${ChatColor.YELLOW}Left Click ${ChatColor.GOLD}Block/Air",
"${ChatColor.AQUA}- ${ChatColor.WHITE}Confirm claim"
))
.build()
val PILLAR_MATERIAL = Material.EMERALD_BLOCK
val PRICE_MODIFIER = 0.4
val PRICE_MULTIPLIER = 0.8
}
}

View File

@ -0,0 +1,9 @@
package cc.fyre.hcf.faction.claim.coordinate
class Coordinate(var x: Int,var z: Int) {
override fun toString(): String {
return "${this.x}, ${this.z}"
}
}

View File

@ -0,0 +1,31 @@
package cc.fyre.hcf.faction.claim.coordinate
import java.util.*
class CoordinateSet(x: Int,z: Int) {
val x = x shr BITS
val z = z shr BITS
override fun equals(other: Any?): Boolean {
if (other == null || other !is CoordinateSet) {
return false
}
return other.x == x && other.z == z
}
override fun hashCode(): Int {
return Objects.hash(this.x,this.z)
}
override fun toString(): String {
return "[${this.x},${this.z}]"
}
companion object {
const val BITS = 6
}
}

View File

@ -0,0 +1,16 @@
package cc.fyre.hcf.faction.claim.listener
import cc.fyre.hcf.faction.claim.ClaimHandler
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.world.WorldLoadEvent
object ClaimListener : Listener {
@EventHandler(priority = EventPriority.NORMAL)
private fun onWorldLoad(event: WorldLoadEvent) {
ClaimHandler.createBucket(event.world)
}
}

View File

@ -0,0 +1,237 @@
package cc.fyre.hcf.faction.claim.listener
import cc.fyre.hcf.HCF
import cc.fyre.hcf.faction.claim.Claim
import cc.fyre.hcf.faction.claim.ClaimHandler
import cc.fyre.hcf.faction.claim.ClaimSelection
import cc.fyre.hcf.faction.event.FactionClaimEvent
import cc.fyre.hcf.faction.menu.system.SystemEditMenu
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.faction.type.SystemFaction
import cc.fyre.hcf.faction.type.player.FactionRole
import cc.fyre.hcf.map.eotw.EOTWHandler
import cc.fyre.hcf.pillar.PillarHandler
import cc.fyre.hcf.pillar.PillarType
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.player.PlayerInteractEvent
import kotlin.math.abs
/**
* @project hcf
*
* @date 03/06/2020
* @author xanderume@gmail.com
*/
object ClaimPositionListener : Listener {
@EventHandler(priority = EventPriority.LOWEST)
private fun onPlayerInteract(event: PlayerInteractEvent) {
if (event.item == null) {
return
}
if (!event.item.isSimilar(ClaimSelection.ITEM)) {
return
}
val selection = ClaimHandler.getSelectionByPlayer(event.player) ?: return
event.isCancelled = true
if (event.action == Action.RIGHT_CLICK_AIR) {
event.player.itemInHand = null
event.player.sendMessage("${ChatColor.RED}You have cancelled the claiming process.")
ClaimHandler.destroySelection(event.player,removeItem = false)
PillarHandler.destroyPillars(event.player, PillarType.CLAIM_SELECTION)
return
}
if (EOTWHandler.isActive() && (selection.faction !is SystemFaction || !event.player.isOp)) {
event.player.sendMessage("${ChatColor.RED}You cannot claim land whilst EOTW.")
event.isCancelled = true
return
}
if (event.action == Action.LEFT_CLICK_AIR) {
if (!event.player.isSneaking) {
return
}
if (selection.first == null || selection.second == null) {
event.player.sendMessage("${ChatColor.RED}You have not selected both corners of your claim yet!")
return
}
val price = selection.getPrice()
val claim = Claim(selection.first!!,selection.second!!)
if (selection.faction is PlayerFaction) {
if (selection.faction.claims.size >= ClaimHandler.MAX_CLAIMS) {
event.player.sendMessage("${ChatColor.RED}Your faction has the maximum amount of claims, which is ${ChatColor.WHITE}${ClaimHandler.MAX_CLAIMS}${ChatColor.RED}.")
return
}
if (selection.faction.getRole(event.player.uniqueId) == FactionRole.MEMBER) {
event.player.sendMessage("${ChatColor.RED}You must be at least a faction captain to claim land!")
return
}
if (selection.faction.balance < price) {
event.player.sendMessage("${ChatColor.RED}Your faction cannot afford this claim!")
return
}
if (selection.faction.isRaidable()) {
event.player.sendMessage("${ChatColor.RED}You can't claim land whilst your faction is raidable!")
return
}
val override = ClaimHandler.containsOtherClaim(claim)
if (override != null) {
event.player.sendMessage("${ChatColor.RED}This land is currently claimed by ${override.getDisplayName(event.player)}${ChatColor.RED} and cannot be claimed.")
return
}
val ignoreNearby : List<Claim>? = null
val touchingClaims: MutableSet<Claim> = ClaimHandler.getTouchingClaims(claim)
val teamClaims = touchingClaims.iterator()
var removedSelfClaims = false
while (teamClaims.hasNext()) {
val possibleClaim = teamClaims.next()
if (ignoreNearby != null && ignoreNearby.contains(possibleClaim)) {
removedSelfClaims = true
teamClaims.remove()
} else if (selection.faction.claims.contains(possibleClaim)) {
removedSelfClaims = true
teamClaims.remove()
}
}
if (selection.faction.claims.size != (0) && !removedSelfClaims
) {
event.player.sendMessage(ChatColor.RED.toString() + "All of your claims must be touching each other!")
return
}
if (touchingClaims.size > 1 || touchingClaims.size == 1 && !removedSelfClaims) {
event.player.sendMessage(ChatColor.RED.toString() + "Your claim must be at least 1 block away from enemy claims!")
return
}
}
event.player.itemInHand = null
selection.faction.addClaims(claim)
ClaimHandler.createClaimEntry(selection.faction,claim)
ClaimHandler.destroySelection(event.player,removeItem = false)
if (selection.faction is PlayerFaction) {
selection.faction.balance -= price
event.player.sendMessage("${ChatColor.YELLOW}Your faction's new balance is ${ChatColor.WHITE}$${selection.faction.balance} ${ChatColor.LIGHT_PURPLE}(Price: $${price})${ChatColor.YELLOW}.")
}
PillarHandler.destroyPillars(event.player,PillarType.CLAIM_SELECTION)
if (selection.faction is SystemFaction) {
SystemEditMenu(selection.faction).open(event.player)
}
event.player.sendMessage("${ChatColor.YELLOW}You have claimed this land for your faction!")
Bukkit.getServer().pluginManager.callEvent(FactionClaimEvent(event.player,claim,selection.faction))
return
}
if (event.clickedBlock == null) {
return
}
// prevent lag
if (selection.lastUpdate != 0L && (System.currentTimeMillis() - selection.lastUpdate) <= 200L) {
return
}
if (selection.faction is PlayerFaction) {
if (event.clickedBlock.location.world.environment != World.Environment.NORMAL) {
event.player.sendMessage("${ChatColor.RED}Land can only be claimed in the overworld.")
return
}
if (ClaimHandler.isWarZone(event.player.location)) {
event.player.sendMessage("${ChatColor.RED}You are currently in the Warzone and can't claim land here. The Warzone ends at ${ClaimHandler.WARZONE_RADIUS}.")
return
}
if (ClaimHandler.isClaimed(event.clickedBlock.location)) {
event.player.sendMessage("${ChatColor.RED}You can only claim land in the wilderness!")
return
}
val blockX = event.clickedBlock.location.blockX
val blockZ = event.clickedBlock.location.blockZ
val opposite = if (event.action == Action.LEFT_CLICK_BLOCK) selection.second else selection.first
if (opposite != null && ((abs(opposite.blockX - blockX) + 1) < ClaimHandler.MINIMUM_SIZE || (abs(opposite.blockZ - blockZ) + 1) < ClaimHandler.MINIMUM_SIZE)) {
event.player.sendMessage("${ChatColor.RED}Your claim is too small! The claim has to be at least ${ClaimHandler.MINIMUM_SIZE}x${ClaimHandler.MINIMUM_SIZE}!")
return
}
}
if (event.action == Action.LEFT_CLICK_BLOCK) {
if (selection.first != null) {
PillarHandler.destroyPillars(event.player, PillarType.CLAIM_SELECTION) {
it.location.blockX == selection.first!!.blockX && it.location.blockZ == selection.first!!.blockZ
}
}
selection.first = event.clickedBlock.location
} else {
if (selection.second != null) {
PillarHandler.destroyPillars(event.player, PillarType.CLAIM_SELECTION) {
it.location.blockX == selection.second!!.blockX && it.location.blockZ == selection.second!!.blockZ
}
}
selection.second = event.clickedBlock.location
}
selection.lastUpdate = System.currentTimeMillis()
selection.getFormattedMessage(event.action,event.clickedBlock.location).filterNotNull().forEach{event.player.sendMessage(it)}
val locations = ArrayList<Location>()
for (i in event.clickedBlock.location.blockY..event.clickedBlock.world.maxHeight) {
locations.add(Location(event.clickedBlock.world,event.clickedBlock.location.x,i.toDouble(),event.clickedBlock.location.z))
}
Bukkit.getServer().scheduler.runTask(HCF.instance) {
PillarHandler.createPillars(event.player,PillarType.CLAIM_SELECTION,locations,ClaimSelection.PILLAR_MATERIAL,true)
}
}
}

View File

@ -0,0 +1,67 @@
package cc.fyre.hcf.faction.command
import cc.fyre.shard.command.data.command.Command
import cc.fyre.shard.command.data.parameter.Parameter
import cc.fyre.hcf.HCF
import cc.fyre.hcf.faction.FactionHandler
import cc.fyre.hcf.faction.type.PlayerFaction
import cc.fyre.hcf.map.eotw.EOTWHandler
import cc.fyre.hcf.timer.TimerHandler
import cc.fyre.hcf.timer.TimerType
import cc.fyre.shard.command.data.option.Option
import org.bukkit.ChatColor
import org.bukkit.entity.Player
/**
* @project hcf
*
* @date 25/06/2020
* @author xanderume@gmail.com
*/
object FactionAcceptCommand {
@JvmStatic
@Command(names = ["faction join","fac join","f join","team join","t join","faction j","fac j","f j","team j","t j","faction accept","fac accept","f accept","team accept","t accept","faction a","fac a","f a","team a","t a"])
fun execute(player: Player,
@Option(value = ["f","force"],defaultValue = false,permission = "hcf.command.faction.accept.advanced",description = "Force join a faction.") force: Boolean,
@Parameter(name = "faction")faction: PlayerFaction) {
if (FactionHandler.getFactionByPlayer(player.uniqueId) != null) {
player.sendMessage("${ChatColor.RED}You are already in a faction!")
return
}
if (!force) {
if (!faction.invites.contains(player.uniqueId)) {
player.sendMessage("${ChatColor.RED}This faction has not invited you!")
return
}
if (faction.members.size >= PlayerFaction.MEMBER_LIMIT) {
player.sendMessage("${ChatColor.RED}${faction.name} is currently full!")
return
}
if (faction.isOnDTRFreeze()) {
player.sendMessage("${ChatColor.RED}You cannot join ${faction.name} as they are currently on DTR freeze!")
return
}
if (EOTWHandler.isActive()) {
player.sendMessage("${ChatColor.RED}You cannot join factions during EOTW.")
return
}
if (TimerHandler.hasTimer(player.uniqueId,TimerType.SPAWN_TAG)) {
player.sendMessage("${ChatColor.RED}You cannot join ${faction.name} as you are currently on spawn-tagged!")
return
}
}
faction.addMember(player)
faction.flagForSave()
}
}

Some files were not shown because too many files have changed in this diff Show More