1+ package io.github.rothes.esu.bukkit.module.essentialcommands
2+
3+ import io.github.rothes.esu.bukkit.user.PlayerUser
4+ import io.github.rothes.esu.bukkit.util.ComponentBukkitUtils.player
5+ import io.github.rothes.esu.bukkit.util.extension.ListenerExt.register
6+ import io.github.rothes.esu.bukkit.util.extension.ListenerExt.unregister
7+ import io.github.rothes.esu.bukkit.util.version.Versioned
8+ import io.github.rothes.esu.core.configuration.ConfigurationPart
9+ import io.github.rothes.esu.core.configuration.data.MessageData
10+ import io.github.rothes.esu.core.configuration.data.MessageData.Companion.message
11+ import io.github.rothes.esu.core.configuration.meta.Comment
12+ import io.github.rothes.esu.core.module.CommonFeature
13+ import io.github.rothes.esu.core.module.configuration.BaseFeatureConfiguration
14+ import io.github.rothes.esu.core.user.User
15+ import io.github.rothes.esu.core.util.ComponentUtils.component
16+ import io.github.rothes.esu.core.util.ComponentUtils.unparsed
17+ import org.bukkit.entity.Player
18+ import org.bukkit.event.EventHandler
19+ import org.bukkit.event.Listener
20+ import org.bukkit.event.player.PlayerQuitEvent
21+ import org.incendo.cloud.bukkit.parser.PlayerParser
22+ import org.incendo.cloud.kotlin.MutableCommandBuilder
23+ import org.incendo.cloud.kotlin.extension.commandBuilder
24+ import org.incendo.cloud.kotlin.extension.getOrNull
25+ import org.incendo.cloud.parser.standard.FloatParser
26+ import org.incendo.cloud.suggestion.SuggestionProvider
27+ import java.util.concurrent.ConcurrentHashMap
28+
29+ object Speed : BaseCommand<Speed.Config, Speed.Lang>() {
30+
31+ init {
32+ registerFeature(WalkSpeed )
33+ registerFeature(FlySpeed )
34+ }
35+
36+ private val speedHandler by Versioned (NmsPlayerSpeedHandler ::class .java)
37+
38+ override fun onEnable () {
39+ registerSpeedCommands(" speed" ) { player ->
40+ if (player.isFlying) FlySpeed else WalkSpeed
41+ }
42+ }
43+
44+ private fun CommonFeature <* , * >.registerSpeedCommands (rootName : String , getter : (Player ) -> SpeedCommand <out SpeedType >) {
45+ withCommandManager {
46+ commandBuilder(rootName + " Get" ) {
47+ permission(cmdShortPerm())
48+ handler { ctx ->
49+ val sender = ctx.sender()
50+ val player = ctx.getOrSupplyDefault(" player" ) { (sender as PlayerUser ).player }
51+ getter(player).getSpeed(sender, player)
52+ }.regCmd()
53+
54+ permission(cmdShortPerm(" others" ))
55+ optional(" player" , PlayerParser .playerParser())
56+ regCmd()
57+ }
58+ commandBuilder(rootName) {
59+ permission(cmdShortPerm())
60+
61+ handler { ctx ->
62+ val sender = ctx.sender()
63+ val player = ctx.getOrSupplyDefault(" player" ) { (sender as PlayerUser ).player }
64+ val speedCommand = getter(player)
65+ val value = ctx.getOrNull(" value" ) ? : speedCommand.defaultValue
66+ speedCommand.setSpeed(sender, value, player)
67+ }
68+
69+ fun argType (scope : MutableCommandBuilder <User >.() -> Unit ) {
70+ copy {
71+ scope()
72+ regCmd()
73+
74+ permission(cmdShortPerm(" others" ))
75+ optional(" player" , PlayerParser .playerParser())
76+ regCmd()
77+ }
78+ }
79+
80+ argType {
81+ literal(" reset" )
82+ }
83+ argType {
84+ required(" value" , FloatParser .floatParser()) {
85+ suggestionProvider(SuggestionProvider .blockingStrings { ctx, _ ->
86+ val sender = ctx.sender()
87+ val player = if (sender is PlayerUser ) sender.player else null
88+ val current = if (player != null ) with (getter(player)) { player.speed } else 0.1f
89+ listOf (current.toString())
90+ })
91+ }
92+ }
93+ }
94+ }
95+ }
96+
97+ data class Config (
98+ @Comment("""
99+ Reset speed for players leaving the server or on disable.
100+ If not enabled, modified speed may exist forever.
101+ """ )
102+ val autoResetSpeed : Boolean = true ,
103+ ): BaseFeatureConfiguration(true )
104+
105+ data class Lang (
106+ val speedGet : MessageData = " <pc><capitalize:'<type>'> speed of <pdc><player><pc> is <pdc><value><pc>." .message,
107+ val speedSet : MessageData = " <pc>Set <type> speed of <pdc><player><pc> to <pdc><value><pc>." .message,
108+ )
109+
110+ interface NmsPlayerSpeedHandler {
111+ fun getWalkSpeed (bukkitPlayer : Player ): Float
112+ fun getFlySpeed (bukkitPlayer : Player ): Float
113+ fun setWalkSpeed (bukkitPlayer : Player , speed : Float )
114+ fun setFlySpeed (bukkitPlayer : Player , speed : Float )
115+ }
116+
117+ abstract class SpeedCommand <L : SpeedType > : BaseCommand <Unit , L >() {
118+
119+ abstract var Player .speed: Float
120+ abstract val defaultValue: Float
121+ private val changed = ConcurrentHashMap .newKeySet<Player >()
122+ private val listener = Listeners ()
123+
124+ fun getSpeed (sender : User , player : Player ) {
125+ sender.message(
126+ Speed .lang, { speedGet }, player(player), unparsed(" value" , player.speed),
127+ component(" type" , sender.buildMiniMessage(lang, { typeName })),
128+ )
129+ }
130+
131+ fun setSpeed (sender : User , speed : Float , player : Player ) {
132+ player.speed = speed
133+ sender.message(
134+ Speed .lang, { speedSet }, player(player), unparsed(" value" , speed),
135+ component(" type" , sender.buildMiniMessage(lang, { typeName })),
136+ )
137+ changed.add(player)
138+ }
139+
140+ override fun onEnable () {
141+ registerSpeedCommands(name) { this }
142+ listener.register()
143+ }
144+
145+ override fun onDisable () {
146+ super .onDisable()
147+ listener.unregister()
148+ if (Speed .config.autoResetSpeed) {
149+ for (player in changed) {
150+ player.speed = defaultValue
151+ }
152+ }
153+ changed.clear()
154+ }
155+
156+ inner class Listeners : Listener {
157+ @EventHandler
158+ fun onQuit (event : PlayerQuitEvent ) {
159+ if (changed.remove(event.player) && Speed .config.autoResetSpeed)
160+ event.player.speed = defaultValue
161+ }
162+ }
163+ }
164+
165+ abstract class SpeedType (val typeName : String ) : ConfigurationPart
166+
167+ object WalkSpeed : SpeedCommand<WalkSpeed.WalkSpeedType>() {
168+
169+ override var Player .speed: Float
170+ get() = speedHandler.getWalkSpeed(this )
171+ set(value) { speedHandler.setWalkSpeed(this , value) }
172+ override val defaultValue: Float = 0.1f
173+
174+ class WalkSpeedType : SpeedType (" walk" )
175+
176+ }
177+
178+ object FlySpeed : SpeedCommand<FlySpeed.FlySpeedType>() {
179+
180+ override var Player .speed: Float
181+ get() = speedHandler.getFlySpeed(this )
182+ set(value) { speedHandler.setFlySpeed(this , value) }
183+ override val defaultValue: Float = 0.05f
184+
185+ class FlySpeedType : SpeedType (" fly" )
186+
187+ }
188+
189+ }
0 commit comments