0. 初めに
build.gradle
や plugin.yml
の設定は終わらせた前提で進めます。
プロジェクトを作成する を参考にメインクラスを作るまで終わらせておいてください。
また、コマンドを作成して進めていきます。
詳しい説明は 2.2 コマンドを新しく作る でしていますので省略します。
1. plugin.yml にコマンドを登録する
commands:
timer:
usage: "/<command> [Seconds]"
description: "カウントダウンします"
このようなコマンドを登録しておきます。
秒数を引数としています。
2. 準備する
メッセージに色をつけたいので、getColored
を用意しておきましょう。
object Util {
fun getColored(text: String): String {
return ChatColor.translateAlternateColorCodes('&', text)
}
}
3. コマンドの処理を書く
CommandExecutor
を継承した TimerCommand
というオブジェクトを作成します。
object TimerCommand: CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
}
}
引数の処理をしましょう。整数を受け取るので getOrNull
と toIntOrNull
を使います。
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
val seconds = args.getOrNull(0)?.toIntOrNull()
if(seconds == null){
sender.sendMessage(getColored("&c秒数を入力してください"))
return true
}
}
まずはスケジューラーを使えるようになりましょう。
4. スケジューラーを使う
スケジューラー というものは、**「何秒後に実行」や「何秒毎に実行」**といった処理を行う時に使うものです。
この処理はプラグインに紐づけて行われるので、関数の引数として JavaPlugin
を必要とします。
基本的には JavaPlugin
を継承している Main.kt
でしか関数を呼び出せません。
しかし、それではとても不便です。その為に、JavaPlugin
を変数として保持しておきましょう。
class Main: JavaPlugin() {
companion object {
lateinit var plugin: JavaPlugin
}
override fun onEnable() {
plugin = this
}
}
lateinit var
を使うと 後で初期化される変数 として定義できるので、エラーが出ません。
しかし、これはエラーを無視させているようなものなので多用することはオススメ出来ません。
今回は、プラグインが有効にならなければ plugin
にアクセスされることがないのでこれを使っています。
使い方を紹介します。
・1秒後にメッセージを出す場合
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
Bukkit.broadcastMessage("1秒経ちました")
}, 20)
runTaskLater
は 遅れて処理を行うというものです。
第1引数として JavaPlugin
を渡します。
第2引数として 行う処理を書きます。 Runnable {}
の中括弧の中に書きます。
第3引数として 遅らせる時間を書きます。 単位は Tick
になっています。
Tick | 秒 |
---|---|
20 | 1 |
1 | 0.05 |
・15秒毎にメッセージを出す場合
Bukkit.getScheduler().runTaskTimer(plugin, Runnable {
Bukkit.broadcastMessage("10秒毎に実行しています")
}, 0, 15 * 20)
第1,2,3引数は runTaskLater
と同じです。
第4引数として 実行の間隔を書きます。単位は Tick
です。
何秒というのを書きたいのであれば、* 20
を書くのがオススメです。
わざわざ電卓を叩いて計算する必要はありません。
・5秒毎にメッセージを出し、3回で終了する場合
今回の内容に似ています。しかし、これが一番難しいのです。
何故なら書き方が大きく変わるからです。処理内でキャンセルできる書き方があります。
勿論、これで統一すればどんな内容にも対応できます。
fun repeat3times(){
var runCount = 0
object: BukkitRunnable() {
override fun run() {
if(runCount < 3){
Bukkit.broadcastMessage("${runCount + 1} 回目の実行です")
runCount ++
} else {
cancel()
}
}
}.runTaskTimer(plugin, 0, 5 * 20)
}
Runnable
を使っていると、cancel()
は使えません。
そして、この書き方は無名クラスというものですが、スケジューラーの定型として覚えてしまって大丈夫です。
実は、runTaskLater
と Runnable
を使って同じようなことができるんです。
この書き方は直感的ではないと思う人もいるかもしれないので、
説明を聞いて分からなかった人は上の書き方をすることをオススメします。
fun repeat3times(){
repeat(3)
}
private fun repeat(sumRunCount: Int, remainRunCount: Int = sumRunCount){
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
if(0 < remainRunCount){
val runCount = sumRunCount - remainRunCount
Bukkit.broadcastMessage("${runCount + 1} 回目の実行です")
repeat(sumRunCount, remainRunCount - 1)
}
}, 5 * 20)
}
remainRunCount: Int = sumRunCount
関数の引数にはデフォルト値を決めておくことができます。
今回であれば、repeat(3)
と書いたら repeat(3, 3)
となります。
repeat(sumRunCount, remainRunCount - 1)
で remainCount
を1減らしています。
結果的に remainRunCount
は0になるので、if(0 < remainRunCount)
のおかげで repeat
が実行されなくなるのです。
5. タイトルを送る
こんな感じに表示するためには player.sendTitle
というものが使えます。
サーバーの全員に送るので、Bukkit.getOnlinePlayers().forEach { player -> }
を使います。
private fun sendTitle(seconds: Int){
Bukkit.getOnlinePlayers().forEach { player ->
player.sendTitle(getColored("&9&l$seconds"), "", 0, 15, 0)
}
}
引数として秒数を受け取ります。
では、これらを使って実際にタイマーを作ってみましょう。
6. カウントダウンタイマーを作る
私は、runTaskTimer
を使った書き方でやってみます。
private fun countDownUsingLoop(seconds: Int){
var remainSeconds = seconds
object: BukkitRunnable() {
override fun run() {
if(0 < remainSeconds){
sendTitle(remainSeconds)
remainSeconds --
} else {
cancel()
}
}
}.runTaskTimer(plugin, 0, 20)
}
先ほどのプログラムとほとんど同じなので、説明は省略します。
これを onCommand
に実装したら終了です。
object TimerCommand: CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
val seconds = args.getOrNull(0)?.toIntOrNull()
if(seconds == null){
sender.sendMessage(getColored("&c秒数を入力してください"))
return true
}
countDownUsingLoop(seconds)
return true
}
private fun sendTitle(seconds: Int){
Bukkit.getOnlinePlayers().forEach { player ->
player.sendTitle(getColored("&9&l$seconds"), "", 0, 15, 0)
}
}
private fun countDownUsingLoop(seconds: Int){
var remainSeconds = seconds
object: BukkitRunnable() {
override fun run() {
if(0 < remainSeconds){
sendTitle(remainSeconds)
remainSeconds --
} else {
cancel()
}
}
}.runTaskTimer(plugin, 0, 20)
}
}
runTaskLater
を使った書き方も出来る人はやってみましょう。
関数名を変えて両方ともテストしてみるといいでしょう。
7. コマンドを登録する
class Main: JavaPlugin() {
companion object {
lateinit var plugin: JavaPlugin
}
override fun onEnable() {
plugin = this
registerCommand("timer", TimerCommand)
}
private fun registerCommand(label: String, executor: CommandExecutor){
val command = getCommand(label)
if(command != null){
command.setExecutor(executor)
logger.info("/$label を登録しました")
} else {
logger.severe("/$label を登録できませんでした")
}
}
}
では、サーバーでテストしてみましょう。
お疲れ様でした。