Skip to content

Commit af9abb0

Browse files
Merge pull request #96 from RuiPereiraDev/placeholders
Add placeholders for player ping, kills and deaths
2 parents 45080df + d54273f commit af9abb0

2 files changed

Lines changed: 89 additions & 28 deletions

File tree

bukkit/src/main/kotlin/com/r4g3baby/simplescore/bukkit/scoreboard/VarReplacer.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package com.r4g3baby.simplescore.bukkit.scoreboard
33
import com.r4g3baby.simplescore.BukkitPlugin
44
import com.r4g3baby.simplescore.api.scoreboard.VarReplacer
55
import com.r4g3baby.simplescore.bukkit.util.Adventure
6+
import com.r4g3baby.simplescore.bukkit.util.getPlayerPing
67
import com.r4g3baby.simplescore.bukkit.util.lazyReplace
78
import com.r4g3baby.simplescore.core.util.translateColorCodes
89
import me.clip.placeholderapi.PlaceholderAPI
10+
import org.bukkit.Statistic
911
import org.bukkit.entity.Player
1012
import kotlin.math.max
1113
import kotlin.math.min
@@ -17,17 +19,18 @@ class VarReplacer(plugin: BukkitPlugin) : VarReplacer<Player> {
1719
override fun replace(text: String, viewer: Player): String {
1820
var result = if (usePlaceholderAPI) PlaceholderAPI.setPlaceholders(viewer, text) else text
1921

20-
result = result.lazyReplace("%player_name%") { viewer.name }
22+
result = result
23+
.lazyReplace("%player_name%") { viewer.name }
2124
.lazyReplace("%player_displayname%") { viewer.displayName }
2225
.lazyReplace("%player_uuid%") { viewer.uniqueId.toString() }
2326
.lazyReplace("%player_level%") { viewer.level.toString() }
24-
.lazyReplace("%player_gamemode%") { viewer.gameMode.name.lowercase().replaceFirstChar { it.titlecase() } }
27+
.lazyReplace("%player_gamemode%") { getGameMode(viewer) }
2528
.lazyReplace("%player_health%") { viewer.health.roundToInt().toString() }
2629
.lazyReplace("%player_maxhealth%") { viewer.maxHealth.roundToInt().toString() }
27-
.lazyReplace("%player_hearts%") {
28-
val hearts = min(10, max(0, ((viewer.health / viewer.maxHealth) * 10).roundToInt()))
29-
"&c${"".repeat(hearts)}&0${"".repeat(10 - hearts)}"
30-
}
30+
.lazyReplace("%player_hearts%") { getHearts(viewer) }
31+
.lazyReplace("%player_ping%") { getPing(viewer) }
32+
.lazyReplace("%player_kills%") { viewer.getStatistic(Statistic.PLAYER_KILLS).toString() }
33+
.lazyReplace("%player_deaths%") { viewer.getStatistic(Statistic.DEATHS).toString() }
3134
.lazyReplace("%player_world%") { viewer.world.name }
3235
.lazyReplace("%player_world_online%") { viewer.world.players.size.toString() }
3336
.lazyReplace("%server_online%") { viewer.server.onlinePlayers.size.toString() }
@@ -36,4 +39,18 @@ class VarReplacer(plugin: BukkitPlugin) : VarReplacer<Player> {
3639
result = Adventure.parseToString(result)
3740
return translateColorCodes(result)
3841
}
39-
}
42+
43+
private fun getGameMode(player: Player): String {
44+
return player.gameMode.name.lowercase().replaceFirstChar { it.titlecase() }
45+
}
46+
47+
private val fullHearts = Array(11) { "".repeat(it) }
48+
private fun getHearts(player: Player): String {
49+
val hearts = min(10, max(0, ((player.health / player.maxHealth) * 10).roundToInt()))
50+
return "&c${fullHearts[hearts]}&0${fullHearts[10 - hearts]}"
51+
}
52+
53+
private fun getPing(player: Player): String {
54+
return getPlayerPing.apply(player).toString()
55+
}
56+
}
Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,76 @@
11
package com.r4g3baby.simplescore.bukkit.util
22

33
import com.r4g3baby.simplescore.api.scoreboard.data.Provider
4+
import com.r4g3baby.simplescore.bukkit.protocol.util.Utils
5+
import com.r4g3baby.simplescore.core.util.Reflection
6+
import org.bukkit.entity.Player
47
import org.bukkit.plugin.Plugin
8+
import java.util.function.Function
59

610
fun String.lazyReplace(oldValue: String, newValueFunc: () -> String): String {
7-
run {
8-
var occurrenceIndex: Int = indexOf(oldValue, 0, true)
9-
if (occurrenceIndex < 0) return this
10-
11-
val newValue = newValueFunc()
12-
13-
val oldValueLength = oldValue.length
14-
val searchStep = oldValueLength.coerceAtLeast(1)
15-
val newLengthHint = length - oldValueLength + newValue.length
16-
if (newLengthHint < 0) throw OutOfMemoryError()
17-
val stringBuilder = StringBuilder(newLengthHint)
18-
19-
var i = 0
20-
do {
21-
stringBuilder.append(this, i, occurrenceIndex).append(newValue)
22-
i = occurrenceIndex + oldValueLength
23-
if (occurrenceIndex >= length) break
24-
occurrenceIndex = indexOf(oldValue, occurrenceIndex + searchStep, true)
25-
} while (occurrenceIndex > 0)
26-
return stringBuilder.append(this, i, length).toString()
11+
var occurrenceIndex = this.indexOf(oldValue, ignoreCase = true)
12+
if (occurrenceIndex < 0) return this
13+
14+
val newValue = newValueFunc()
15+
val oldValueLength = oldValue.length
16+
17+
val newLengthHint = this.length - oldValueLength + newValue.length
18+
if (newLengthHint < 0) throw OutOfMemoryError()
19+
20+
var cursor = 0
21+
val stringBuilder = StringBuilder(newLengthHint)
22+
while (occurrenceIndex >= 0) {
23+
stringBuilder.append(this, cursor, occurrenceIndex).append(newValue)
24+
25+
cursor = occurrenceIndex + oldValueLength
26+
occurrenceIndex = this.indexOf(oldValue, cursor, ignoreCase = true)
2727
}
28+
29+
if (cursor < this.length) {
30+
stringBuilder.append(this, cursor, this.length)
31+
}
32+
33+
return stringBuilder.toString()
2834
}
2935

3036
fun bukkitProvider(plugin: Plugin): Provider {
3137
return Provider(plugin.name)
32-
}
38+
}
39+
40+
@JvmField
41+
val getPlayerPing = object : Function<Player, Int> {
42+
private val getPingMethod: Reflection.MethodInvoker? = try {
43+
Reflection.getMethodByName(Player::class.java, "getPing")
44+
} catch (_: Exception) { null }
45+
46+
private val getPlayerHandle: Reflection.MethodInvoker?
47+
private val pingField: Reflection.FieldAccessor?
48+
49+
init {
50+
if (getPingMethod == null) {
51+
getPlayerHandle = try {
52+
val craftPlayer = Reflection.getClass("${Utils.OBC}.entity.CraftPlayer")
53+
Reflection.getMethodByName(craftPlayer, "getHandle")
54+
} catch (_: Exception) { null }
55+
56+
pingField = try {
57+
val entityPlayer = Reflection.findClass(
58+
"net.minecraft.server.level.ServerPlayer",
59+
"net.minecraft.server.level.EntityPlayer", "${Utils.NMS}.EntityPlayer"
60+
)
61+
Reflection.getField(entityPlayer, Int::class.java, filter = { field -> field.name == "ping" })
62+
} catch (_: Exception) { null }
63+
} else {
64+
getPlayerHandle = null
65+
pingField = null
66+
}
67+
}
68+
69+
override fun apply(player: Player): Int {
70+
return when {
71+
getPingMethod != null -> getPingMethod.invoke(player) as? Int ?: -1
72+
getPlayerHandle != null && pingField != null -> pingField.get(getPlayerHandle.invoke(player)) as? Int ?: -1
73+
else -> -1
74+
}
75+
}
76+
}

0 commit comments

Comments
 (0)