Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package com.r4g3baby.simplescore.bukkit.scoreboard
import com.r4g3baby.simplescore.BukkitPlugin
import com.r4g3baby.simplescore.api.scoreboard.VarReplacer
import com.r4g3baby.simplescore.bukkit.util.Adventure
import com.r4g3baby.simplescore.bukkit.util.getPlayerPing
import com.r4g3baby.simplescore.bukkit.util.lazyReplace
import com.r4g3baby.simplescore.core.util.translateColorCodes
import me.clip.placeholderapi.PlaceholderAPI
import org.bukkit.Statistic
import org.bukkit.entity.Player
import kotlin.math.max
import kotlin.math.min
Expand All @@ -17,17 +19,18 @@ class VarReplacer(plugin: BukkitPlugin) : VarReplacer<Player> {
override fun replace(text: String, viewer: Player): String {
var result = if (usePlaceholderAPI) PlaceholderAPI.setPlaceholders(viewer, text) else text

result = result.lazyReplace("%player_name%") { viewer.name }
result = result
.lazyReplace("%player_name%") { viewer.name }
.lazyReplace("%player_displayname%") { viewer.displayName }
.lazyReplace("%player_uuid%") { viewer.uniqueId.toString() }
.lazyReplace("%player_level%") { viewer.level.toString() }
.lazyReplace("%player_gamemode%") { viewer.gameMode.name.lowercase().replaceFirstChar { it.titlecase() } }
.lazyReplace("%player_gamemode%") { getGameMode(viewer) }
.lazyReplace("%player_health%") { viewer.health.roundToInt().toString() }
.lazyReplace("%player_maxhealth%") { viewer.maxHealth.roundToInt().toString() }
.lazyReplace("%player_hearts%") {
val hearts = min(10, max(0, ((viewer.health / viewer.maxHealth) * 10).roundToInt()))
"&c${"❤".repeat(hearts)}&0${"❤".repeat(10 - hearts)}"
}
.lazyReplace("%player_hearts%") { getHearts(viewer) }
.lazyReplace("%player_ping%") { getPing(viewer) }
.lazyReplace("%player_kills%") { viewer.getStatistic(Statistic.PLAYER_KILLS).toString() }
.lazyReplace("%player_deaths%") { viewer.getStatistic(Statistic.DEATHS).toString() }
.lazyReplace("%player_world%") { viewer.world.name }
.lazyReplace("%player_world_online%") { viewer.world.players.size.toString() }
.lazyReplace("%server_online%") { viewer.server.onlinePlayers.size.toString() }
Expand All @@ -36,4 +39,18 @@ class VarReplacer(plugin: BukkitPlugin) : VarReplacer<Player> {
result = Adventure.parseToString(result)
return translateColorCodes(result)
}
}

private fun getGameMode(player: Player): String {
return player.gameMode.name.lowercase().replaceFirstChar { it.titlecase() }
}

private val fullHearts = Array(11) { "❤".repeat(it) }
private fun getHearts(player: Player): String {
val hearts = min(10, max(0, ((player.health / player.maxHealth) * 10).roundToInt()))
return "&c${fullHearts[hearts]}&0${fullHearts[10 - hearts]}"
}

private fun getPing(player: Player): String {
return getPlayerPing.apply(player).toString()
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,76 @@
package com.r4g3baby.simplescore.bukkit.util

import com.r4g3baby.simplescore.api.scoreboard.data.Provider
import com.r4g3baby.simplescore.bukkit.protocol.util.Utils
import com.r4g3baby.simplescore.core.util.Reflection
import org.bukkit.entity.Player
import org.bukkit.plugin.Plugin
import java.util.function.Function

fun String.lazyReplace(oldValue: String, newValueFunc: () -> String): String {
run {
var occurrenceIndex: Int = indexOf(oldValue, 0, true)
if (occurrenceIndex < 0) return this

val newValue = newValueFunc()

val oldValueLength = oldValue.length
val searchStep = oldValueLength.coerceAtLeast(1)
val newLengthHint = length - oldValueLength + newValue.length
if (newLengthHint < 0) throw OutOfMemoryError()
val stringBuilder = StringBuilder(newLengthHint)

var i = 0
do {
stringBuilder.append(this, i, occurrenceIndex).append(newValue)
i = occurrenceIndex + oldValueLength
if (occurrenceIndex >= length) break
occurrenceIndex = indexOf(oldValue, occurrenceIndex + searchStep, true)
} while (occurrenceIndex > 0)
return stringBuilder.append(this, i, length).toString()
var occurrenceIndex = this.indexOf(oldValue, ignoreCase = true)
if (occurrenceIndex < 0) return this

val newValue = newValueFunc()
val oldValueLength = oldValue.length

val newLengthHint = this.length - oldValueLength + newValue.length
if (newLengthHint < 0) throw OutOfMemoryError()

var cursor = 0
val stringBuilder = StringBuilder(newLengthHint)
while (occurrenceIndex >= 0) {
stringBuilder.append(this, cursor, occurrenceIndex).append(newValue)

cursor = occurrenceIndex + oldValueLength
occurrenceIndex = this.indexOf(oldValue, cursor, ignoreCase = true)
}

if (cursor < this.length) {
stringBuilder.append(this, cursor, this.length)
}

return stringBuilder.toString()
}

fun bukkitProvider(plugin: Plugin): Provider {
return Provider(plugin.name)
}
}

@JvmField
val getPlayerPing = object : Function<Player, Int> {
private val getPingMethod: Reflection.MethodInvoker? = try {
Reflection.getMethodByName(Player::class.java, "getPing")
} catch (_: Exception) { null }

private val getPlayerHandle: Reflection.MethodInvoker?
private val pingField: Reflection.FieldAccessor?

init {
if (getPingMethod == null) {
getPlayerHandle = try {
val craftPlayer = Reflection.getClass("${Utils.OBC}.entity.CraftPlayer")
Reflection.getMethodByName(craftPlayer, "getHandle")
} catch (_: Exception) { null }

pingField = try {
val entityPlayer = Reflection.findClass(
"net.minecraft.server.level.ServerPlayer",
"net.minecraft.server.level.EntityPlayer", "${Utils.NMS}.EntityPlayer"
)
Reflection.getField(entityPlayer, Int::class.java, filter = { field -> field.name == "ping" })
} catch (_: Exception) { null }
} else {
getPlayerHandle = null
pingField = null
}
}

override fun apply(player: Player): Int {
return when {
getPingMethod != null -> getPingMethod.invoke(player) as? Int ?: -1
getPlayerHandle != null && pingField != null -> pingField.get(getPlayerHandle.invoke(player)) as? Int ?: -1
else -> -1
}
}
}