この記事は、traPアドベントカレンダー2019 33日目の記事です。
はじめまして、19のあずです。班やプロジェクトには所属してません。まぁ、どっちも@Nullable
なので耐えますね。
今日は僕の趣味の一つであるSpigotのPlugin開発の大まかな流れについて書きます。
今回作ったのは階段にたむろするヤンキーになれる機能を追加したプラグインです。割と有名な機能で既にChairs等のプラグインが公開されてはいますが、なぜかお世話になってるサーバーで動かなかった(らしい)ので作りました。
SpigotとPluginについて
SpigotとかPluginとかってなんだよ、ってなりますよね。まぁ聞いて下さい。
いきなりですがみなさん、Minecraftのサーバーを建てたい!!って思ったことありますか?
もちろん公式サーバーを使っても良いのですが、世の中には人の建築物を大爆発させるのが趣味な【検閲済み】野郎がいます。キレていいです。
その建築物を直す際、みなさんならばどうしますか?
ブロックを1つ1つ置き直すのも一つの手かもしれませんが、時間がかかりすぎます。鼻からスパゲティ食べる訓練をしたほうが明らかにアドです。
もし、ロールバック機能があればコマンドでらくらく直せますね? 午後の紅茶を午前に飲みながら優雅に過ごせますね?
そんな 拡張機能(Plugin) を追加することのできるサーバーの一つにSpigotってのがあるわけですよ。やったね、また賢くなれましたね。
ただ、ほしい機能を持つPluginが必ずしもあるか、と言われると微妙です。
まぁ、無かったらその機能は…残念ですが……諦めろと……
私は言いません
無ければ作ればいいんです。僕の母親のお爺ちゃんのお孫さんの息子さんが言ってました。
必要なもの
ここでは、SpigotのPluginを作るにあたり、必要そうなものを以下に挙げてみます。
- ggり力
- Javaの知識
- Minecraftの知識
- 制作意欲
- バグにメゲナイ!!ショゲナイ!!泣いちゃダメ~!! いけいけ【検閲済み】ちゃーん!!の精神
ggり力
おそらく、これが一番大切です。ちなみに僕の友人にこのことを言ったら「胡散臭すぎて草」と言われました辛い。
特に、変なPluginを作る人は†英語力†も必要になります。たいてい、僕たちの起こす問題は外人兄貴がSpigotのフォーラムにて先に質問しています。
いいですか、外人兄貴は僕たちをひとつ上のステージに引き上げてくれます。大好きです、外人兄貴。(唐突の告白)
ちなみに僕は皆無です。とりあえずhow toってつけておけ。
Javaの知識
ここでも妥協をするな、と言いたいところですが、僕は皆無です。Enum型を えなむ って呼んだり、Char型を ちゃー って読む程度には無知です。
そんな僕でも3~4年位開発できてるので、まぁいいんじゃないんですかね?
Minecraftの知識
ここは質にこだわるべきです。ちなみに僕は皆無です。金人参は良いぞ。
制作意欲
これがあると開発が圧倒的に楽になります。メンタルis精神力!!
ちなみに僕は皆無です。虚無から意欲を錬成せよ。
バグに(ry
メンタルis精神力!!
ちなみに僕は皆無です。杏仁豆腐メンタルです。
さて、必要なものは揃っていますか?
揃って無くても作ってみましょう
Step1 プラグインの仕様を考えよう
階段に座る機能は無いので、色々つかって座ってる風を再現します。殆どのイス系のプラグインでは、階段の中に矢を埋めて、その矢に座らせています。今回作ったのも全く同じ仕組みです。
Step2 組んでみる
Spigot(Bukkit)は所謂イベントドリブンっていうやつです。かなり多くのイベントがBukkitで用意されています。(ブロックの設置・破壊からチャンクの読み込み、気候の変化まで)
今回はブロックをクリックした、というイベントに反応させます。
(中略)
というわけでなんやかんやできました。重要なところだけ載せてます。
Block block = event.getClickedBlock(); //クリックしたブロックの取得
String dataStr = "[half=bottom]"; //階段は下付きになっているか
BlockData data = Bukkit.createBlockData(block.getType(), dataStr);
if(block.getBlockData().matches(data)) {//dataStrと一致するか
event.setCancelled(true);
if(player.isGliding()) {//エリトラで滑空中なら滑空をキャンセル
player.setGliding(false);
}
Arrow arrow = (Arrow) player.getWorld().spawnEntity(block.getLocation().add(new Vector(0.5, 0, 0.5)), EntityType.ARROW);//矢をうまいこと階段の中に埋め込む
arrow.setGravity(false);//重力無視
arrow.setInvulnerable(true);//無敵
arrow.addPassenger(player);//プレイヤーを矢に乗っける
reloadArrow(arrow);
これがreloadArrow()の中身です
new BukkitRunnable() {//スケジューラーってやつです
@Override
public void run() {
boolean hasPlayer = false;
for(Entity e : arrow.getPassengers()) {//矢に乗ってるエンティティ全部を調べます
if(e == null) {//よくわからんけど取れなかったら飛ばします
continue;
}
if(Objects.equals(e.getType(), EntityType.PLAYER)) {
//プレイヤーがいたらhasPlayerをtrueにしてやります
hasPlayer = true;
}
}
try {
if((arrow.getLocation().subtract(new Vector(0.5, 0, 0.5)).getBlock().getBlockData() instanceof Stairs) && (Objects.equals(arrow.getLocation().add(new Vector(-0.5, 1, -0.5)).getBlock().getType(), Material.AIR)) && hasPlayer) {
/*(条件文汚い)
・矢が埋まってる座標のブロックは階段かどうか
・階段の上は空気であるかどうか
・プレイヤーは乗っているか
上記3つがすべて揃ったときのみ、矢が延命され、再度reloadArrow()が呼び出されます
*/
arrow.setTicksLived(1);
reloadArrow(arrow);
}
else {
arrow.remove();
}
}
catch(Exception e) {
arrow.remove();
}
}
}.runTaskLater(AzulePlugin.getInstance(), 10);//10Tick(1Tickは1/20秒)後に実行します
Step3 バグをひたすら潰す
頑張りましょう。頑張れば頑張るほど、頑張れます。
Step4 ツイッターで自慢しよう!!
僕はツイッターしてませんけど
†完成した†
というわけでこんな感じに階段に座り込んじゃうことができます
ただ、やっぱまだ改善すべき点はあります
改善すべき点
階段からモクモク煙が出る
ArrowクラスにsetColor(Color)っていうのがあるので、これにnullをあげる & try-catchで挟んであげればモクモクは消えます…が、エラーを握りつぶすことになるのでやりたくないです。今度考えます。
他にもこんなのが作れます
プラグインはすごいんです。
発想次第でこんな感じにミニマムブロックを作ることだってできます。
最後に
はい、すっごくガバガバな内容の記事で各方面から怒られそうですが、プラグイン作るのは楽しいよっていうお話でした。みんなもプラグインを作ろうね!!!
明日12/3の担当は @tarorynさん @Eruさんのお二人です。お楽しみに!!!
参考
これからマイクラ鯖を建てたい人に言いたい事
(https://jyn.jp/to-begin-minecraft-server/#Spigot)