Nukkit in Kotlin #3
第三回目です。#2はこちら
やること
今回はAPIについて解説します。
外部APIの利用
他プラグインが提供しているAPIは多くありますが、今回はoneborn
さんのEconomyAPI
を使用します。
多くのプラグインはServiceManager
というAPIを提供するための機能を使っておりません。もちろんもれなくEconomyAPI
も例外ではなく、その上PluginBaseを継承したクラスにいろいろとメソッドを追加してしまっています。利用側としてはたまったものではありませんが、広く使われているらしいので我慢しましょう。
ServiceManager
については自作APIの作り方で解説します。
まず、EconomyAPIをインストールするためにbuild.gradle.kts
の一部を以下のように変更してください。変更する個所は適宜変えてもらっても構いません。
repositories {
jcenter()
maven {
url = uri("https://repo.nukkitx.com/main/")
}
maven {
url = uri("http://jenkins.onebone.me/plugin/repository/everything/") //リポジトリがあるurl
}
}
dependencies {
implementation(kotlin("stdlib"))
compileOnly("me.onebone", "economyapi", "2.0.1")
compileOnly("cn.nukkit", "nukkit", "1.0-SNAPSHOT") //グループID, アーティファクトID, バージョン
}
nukkit {
main = "com.example.sample.SamplePlugin"
api = listOf("1.0.9")
authors = listOf("your name")
depend = listOf("EconomyAPI")
}
build.gradle.kts
を変更する以外は大したことは行っていません。
リポジトリを指定し、dependencies
で対象のプロジェクトの情報をcompileOnly
の引数に指定します。
package com.example.sample
import cn.nukkit.event.EventHandler
import cn.nukkit.event.Listener
import cn.nukkit.event.player.PlayerJoinEvent
import me.onebone.economyapi.EconomyAPI
class LoginBonusListener : Listener {
@EventHandler
fun onPlayerJoin(event: PlayerJoinEvent) {
EconomyAPI.getInstance().addMoney(event.player, 10);
}
}
だいたいの使い方はGitHubなどに記載されています。
自作APIの作成
こちらが本記事のメインです。
API作成の手順は少し特殊です。
外部にはインターフェースのみ公開し、実装は漏らさないようにしましょう。
ディレクトリの構成は下記になります。
Sample/
├plugin/
│ ├src/main/kotlin/com/example/sample/
│ │ ├SamplePlugin.kt
│ │ └SampleServiceImpl.kt
│ └build.gradle.kts
├interface/
│ ├src/main/kotlin/com/example/sample/SampleService.kt //インターフェース
│ └build.gradle.kts
├build.gradle.kts
├setting.gradle.kts
├...
複数のプロジェクトが一つにまとまっているマルチプロジェクト構成です。プロジェクトごとに分けても構いません。
基本的にbuild.gradle.ktsが存在するディレクトリの名前がサブプロジェクト名になります。
ServiceManager
を使って外部に公開する際は、インターフェースとそれを実装したクラスを用意します。利用側が使うのはインターフェースのみです。
rootProject.name = "Sample"
include("plugin", "interface")
includeにサブプロジェクトの名前を一つ一つ指定していきます。
plugins {
kotlin("jvm") version "1.3.61"
id("com.github.johnrengelman.shadow") version "5.2.0"
}
allprojects {
group = "com.example"
repositories {
jcenter()
maven {
url = uri("https://repo.nukkitx.com/main/")
}
}
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
rootディレクトリ直下にあるbuild.gradle.ktsにはプロジェクト全体の設定などを主に書きます。
プラグイン本体をビルドするためのスクリプトです。
plugins {
kotlin("jvm")
id("com.github.johnrengelman.shadow")
id("net.minecrell.plugin-yml.nukkit") version "0.3.0"
}
version = "0.1.0"
tasks.shadowJar {
archiveBaseName.set("Sample") //成果物の名前 これがないとサブプロジェクトのディレクトリ名で名前が出力されてしまう
}
dependencies {
implementation(kotlin("stdlib"))
compileOnly(project(":interface")) //サブプロジェクトへの依存関係。project(":<サブプロジェクト名>")で指定できる
compileOnly("cn.nukkit", "nukkit", "1.0-SNAPSHOT")
}
nukkit {
name = "Sample"
main = "com.example.sample.SamplePlugin"
api = listOf("1.0.9")
author = "UramnOIL"
}
外部公開用のインターフェースをビルドするためのスクリプトです。
plugins {
kotlin("jvm")
id("com.github.johnrengelman.shadow")
}
version = "0.1.0"
tasks.shadowJar {
archiveBaseName.set("SampleInterface") //成果物の名前 これがないとサブプロジェクトのディレクトリ名で名前が出力されてしまう
}
dependencies {
compileOnly(kotlin("stdlib")) //外部に公開するプロジェクトのStdlibはcompileOnlyで指定する implementationで指定するとIDEで依存関係を解決できなくなる
compileOnly("cn.nukkit", "nukkit", "1.0-SNAPSHOT")
}
ここまでがGradle側の設定です。
Gradleを初めて使う方には地獄の作業だと思います。コピペで構いません。
package com.example.sample
import cn.nukkit.Player
interface SampleService {
fun sendHoge(player: Player)
}
外部公開用のインターフェースです。コンストラクタにリポジトリ等を渡しサービス上で操作するのが基本ですが、今回は簡単にPlayer
とString
引数に取るメソッドを一つだけ用意します。
package com.example.sample
import cn.nukkit.Player
class SampleServiceImpl : SampleService {
override hoge(player: Player) {
player.sendMessage("Hoge")
}
}
インターフェースに対し実際に行う処理を書きます。
package com.uramnoil.ktform
import cn.nukkit.plugin.PluginBase
import cn.nukkit.plugin.service.ServicePriority
class KtFormPlugin : PluginBase() {
override fun onEnable() {
server.serviceManager.register(SampleService::class.java, SampleServiceImpl(), this, ServicePriority.Normal)
}
}
サービスを登録します。
ServiceManager#register()の第一引数にはインターフェースのClass
クラス、第二引数にはインターフェースを実装したクラスのインスタンス、第三引数にはサービスを提供しているプラグインクラスのインスタンス、第四引数にはServicePriorityを渡します。
ビルド
./gradlew :plugin:shadowJar
./gradlew :interface:shadowJar
それぞれplugin
サブプロジェクトとinterface
サブプロジェクトの成果物を生成します。
これでAPIを提供するプラグインは完成です。
ServiceManagerを使いサービスを取得する
新しくプラグインを作ります。
####ディレクトリ構成
Sample2/
├libs/compile_only/Sample-1.0.0-all.jar
├...
Sample2
ディレクトリにlibs/compile_only
ディレクトリを作成し、interface
サブプロジェクトで生成した成果物を配置します。
plugins {
kotlin("jvm") version "1.3.60"
id("net.minecrell.plugin-yml.nukkit") version "0.3.0"
id("com.github.johnrengelman.shadow") version "5.2.0"
}
group = "com.example"
version = "1.0-SNAPSHOT"
repositories {
jcenter()
maven {
url = uri("https://repo.nukkitx.com/main/")
}
}
dependencies {
implementation(kotlin("stdlib"))
compileOnly("cn.nukkit:nukkit:1.0-SNAPSHOT")
compileOnly(fileTree("libs/compile_only"))
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
nukkit {
name = "Sample2"
main = "com.example.sample2.Sample2Plugin"
api = listOf("1.0.9")
authors = listOf("your name")
depend = listOf("Sample")
}
#1で記述したbuild.gradle.kts
を新しいプラグイン用に調整したものです。
compileOnly(fileTree("libs/compile_only"))
で依存関係に含めるディレクトリを指定します。
package com.example.sample2
import cn.nukkit.event.EventHandler
import cn.nukkit.event.Listener
import cn.nukkit.event.player.PlayerJoinEvent
import cn.nukkit.plugin.service.RegisteredServiceProvider
import com.example.sample.SampleService
class HogeListener() : Listener {
val sampleService = Server.getInstance().serviceManager.getProvider(SampleService::class.java)
@EventHandler
fun onPlayerJoin(event: PlayerJoinEvent) {
sampleService.provider.sendHoge(event.player)
}
}
ServiceManager#getProvider()の第一引数にインターフェースのClassクラスを渡すとそのインターフェースに対応したインスタンスを保持したRegisteredServiceProviderが返ってきます。RegisteredServiceProvider#getProvider()
でサービスクラスを取得し操作を行ってください。
package com.example.sample2
import import cn.nukkit.plugin.PluginBase
class Sample2Plugin() : PluginBase() {
override fun onEnable() {
server.pluginManager.registerEvents(HogeListener(), this)
}
}
./gradlew shadowJar
を実行すると成果物が生成されます。
まとめ
結構ボリュームはありますが、この手順を踏むことで利用者へ簡単に機能を提供することができます。
宣伝
これを使えばNukkitプラグインをもっと楽に、Kotlinらしく記述することができます。