【Spigot】Bukkitプラグインの作り方講座 - ブロックの操作
【Spigot】Bukkitプラグインの作り方講座 - インベントリにアイテムを入れる
インベントリを持っているエンティティにはInventoryHolder
インターフェースが継承されています。
InventoryHolder
インターフェースを持っているのはエンティティだけではなく、チェストなどのブロックにもあります。
```
@EventHandler
public void onInventoryOpen(InventoryOpenEvent e) {
e.getInventory().addItem(new ItemStack(Material.DIAMOND_BLOCK));
}
```
インベントリを開くたび、インベントリにダイヤブロックが追加されます。
なお、チェストだけでなく、かまど、エンチャントテーブル、エンチャントテーブルを閉じたときに自分のインベントリ、エンダーチェスト、シュルカーボックス、ディスペンサー、トラップチェスト、ホッパー、ドロッパー、チェスト付きトロッコ、ホッパー付きトロッコで動作しました。
e.getInventory().setItem(9, new ItemStack(Material.GOLD_INGOT, 3));
インベントリには必ずスロットにインデックスが振られており、左上から右上、下の段に行って左から右の順に0からの番号が振られています。
以上の例では9番目、つまり二段目の一番左のスロットに金インゴットを3つ配置します。
なお、この状態でかまどなどの9番目のスロットがない場合はエラーが発生しますので、e.getInventory().getSize()
でスロットの数を確認してください。
インベントリを開いたプレイヤーのインベントリに鉄インゴットを追加するには以下のコードを書きます。
e.getPlayer().getInventory().addItem(new ItemStack(Material.IRON_INGOT));
if (e.getInventory().getHolder() instanceof Chest) {
((Chest) e.getInventory().getHolder()).getBlock().breakNaturally(new ItemStack(Material.STONE_AXE));
}
以上のコードは、開いたインベントリがチェストであることを判定し、そのチェストを石斧を使って破壊します。破壊するプレイヤーなどはいませんが、プレイヤーが破壊した状態と同じことが起こります。
チェストであることを判定しているので、チェストのブロックを取得することができます。
【Spigot】Bukkitプラグインの作り方講座 - はじめに
Bukkitプラグインとは
- Bukkitとは、ゲーム「Minecraft」のサーバーModの一つ。
- Bukkitには、プラグインを入れることで通常の「バニラサーバー」では出来ない機能を追加できる。
- プラグインはModのようにブロックやアイテムを追加することは出来ない。
- 2017年現在多くのサーバーがBukkitにて稼働しており、プラグインによって経済や要素が追加されている。
- Bukkitは現在更新及び公開が停止しているが、その派生版としてSpigotが存在しBukkitと同様に使用でき、加えて多くの機能が追加されている。ただし、プラグイン開発ではBukkitとSpigotに一部違いがあるため注意が必要。今回はSpigotを使用する。
- Minecraftはプログラミング言語「Java」でできている。ModやBukkitプラグインも同様。
プラグインで出来ること、出来ないこと
出来ること:黒
出来ないこと:赤
- ブロックやアイテム、エンティティの操作や挙動を変える
- 新しい見た目のブロックやアイテム、エンティティの追加
- インベントリの操作や挙動を変える
- 新しい見た目のGUIの追加
- コマンドの追加
- 地形・構造物編集、ワールド作成・管理
- 爆破耐性
- お金、ミニゲームなどの追加
- 別の場所にワープする
- タブキーで表示するプレイヤーリストを書き換える
- クラフトレシピを追加する
- サーバーリストに表示する説明を設定する、などなど...
以上にあげたのはほんの一例で、
プラグインの域を出れば、ウェブと連携したワールドマップや、チャット機能など、Javaでできることを組み合わせることができるため、
出来ることは無限にあります。
上記でできないことはForgeModでできますが、
ForgeModは参加するすべてのプレイヤーがModを導入しないといけない点に注意してください。
ブロックの見た目などを変えるにはリソースパックで実現できますが、
既存のものを変えずに新しく追加することはプラグインではできません。
ちなみに、Bukkitは現在更新及び公開が停止しており、
現在使用されているものはBukkitの派生版であるSpigotです。
SpigotはBukkitの機能に加え、多くの機能が追加されています。
ただし、バージョンにより一部違いがあるため注意が必要です。
ここではSpigotを使用します。
他にも、CauldronというForgeModとプラグインを併用するサーバーModも存在します。
はじめに
読者の皆さんには、
Javaを学ばないとプラグインが作れない、と考えるかもしれませんが、
それではプラグインを作るという目標を失い、
挫折してしまいます。
ですからこの講座でプラグインの作り方とともにJavaに慣れていってください。
プラグインで出来ることはたくさんありますので、
楽しいプラグインをどんどん作りましょう!
注意点
- プログラミングについては詳しく解説していませんので、気になることは調べてください。
- ここでは、開発環境にIntelliJ IDEA、またはeclipseを使用しますが、Windows以外では表示や操作が異なる場合があります。
- 内容によっては、Bukkitのバージョンにより異なる可能性があります。
- ここではポート開放のやり方や、ネットに関する詳しいことは説明しません。
【Spigot】Bukkitプラグインの作り方講座 - テレポート、ベクトル操作
今回は、エンティティを移動します。
エンティティをテレポートさせる
エンティティをテレポートさせるには、
entity.teleport(entity)
entity.teleport(location)
を使います。
引数にEntity型を入れる場合は、そのエンティティの場所に、
Location型(org.bukkit.Location)を入れる場合は、その場所に瞬間移動します。
エンティティの座標を取得するには、entity.getLocation()
を使います。
@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
Entity entity = e.getEntity();
Location loc = entity.getLocation();
loc.setY(loc.getY() + 3);
entity.teleport(loc);
}
上の例では、getY()で取得したY座標に3を足して、loc.setY(y)
でY座標を設定しています。
つまり、エンティティがダメージを受けると、3ブロック上に瞬間移動します。
瞬間移動なので、木に埋まったりしてしまいます。
ベクトルを操作して、移動させる
最後に、ベクトルを操作して、移動させます。
ベクトルは、数学では「大きさと向きを持った量」とされています。
平面で例えると、
原点から点[vx,vy]まで矢印が伸びているとします。
この矢印をベクトルと言います。
この時、原点から点までのvx量とvy量がベクトルの持つ大きさです。
そしてこの量によって向きが決まるわけです。
ベクトルは3Dでも使われており、 x,y,z で構成されています。
xは横方向、yは縦方向、zは前後方向の量です。
ベクトルがよくわからない人はこちら: ベクトル解析 - [物理のかぎしっぽ]
@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
Entity entity = e.getEntity();Entity entity = e.getEntity();
entity.setVelocity(new Vector(0f, 2f, 0f));
}
上の例ではダメージを受けたエンティティがトンでいきます。
ベクトル量の調整がちょっと難しかったりします。(1だとなかなか飛びません。10だと果てしなくトンでいきます)
他にも出来ることは山ほどあるので、色々試してみて下さい。
【Spigot】Bukkitプラグインの作り方講座 - ダメージを与える
今回はEventシステムを使って、エンティティにダメージを与えます。
エンティティにダメージを与える
Entity entity = e.getEntity();
if (entity instanceof LivingEntity) {
double damage = 1.0;
((LivingEntity) entity).damage(damage);
}
エンティティにダメージを与えるには、LivingEntityにキャストする必要があります。
LivingEntity.damage(double damage)
でダメージを与えることが出来ます。
LivingEntity.damage(double damage, Entity damager)
でダメージを与えるエンティティを指定することも出来ます。
【Spigot】Bukkitプラグインの作り方講座 - ダメージの制御
今回はEventシステムを使って、エンティティのダメージを制御します。
エンティティのダメージを制御する
@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
double damage = e.getDamage();
e.setDamage(damage * 2);
}
いきなりコードです。
上のコードではEntityDamageEventを使用しています。
EntityDamageEventはエンティティがダメージを受けた時に発動するイベントです。
上のコードではエンティティが受けるダメージを二倍にしています。
ダメージを受けるエンティティを取得するには、e.getEntity()
でEntityインターフェースを返します。
ダメージが関係していますが、返すのはLivingEntityインターフェースではないので注意して下さい。
エンティティの種類を取得するには、
Entity entity = e.getEntity();
EntityType type = entity.getType();
又は、e.getEntityType()
でEntityType型を返します。
当然ですがこのイベントでダメージを受けるエンティティはプレイヤーも含まれます。
先程のコードではプレイヤーも二倍のダメージを受けてしまいます。
プレイヤーを除外するには以下のようなコードになります。
@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
double damage = e.getDamage();
EntityType type = e.getEntityType();
if (type != EntityType.PLAYER) {
e.setDamage(damage * 2);
}
}
また前回同様、多くのイベントでイベントのキャンセルをすることが出来ます。
これを使用してプレイヤーが攻撃を受けないようにする事もできます。
if (type == EntityType.PLAYER) {
e.setCancelled(true);
}
このイベントは攻撃する側がどんなものであっても発動します。
攻撃する側をエンティティに限定したい場合は、EntityDamageByEntityEventを使うと良いです。
逆にエンティティ以外に限定したい場合は、EntityDamageByBlockEventを使います。
EntityDamageEventで、攻撃するものが何なのか調べたい場合は、e.getCause()
を使用します。
EntityDamageByEntityEventの場合は、e.getDamager()
を使って攻撃したエンティティを取得できます。
EntityDamageByBlockEntityではサボテンに刺された時や、奈落に落ちた時などに発生します。
サボテンの場合など、e.getDamager()
でブロックを取得できますが、
奈落などの場合は対象のブロックがない場合があるので注意が必要です。
【Spigot】Bukkitプラグインの作り方講座 - Eventシステムの利用
Eventシステムとは、「プレイヤーがログインした」、「ブロックが破壊された」、「エンティティがダメージを受けた」などといったイベント発生時に行う処理を記載できます。
Eventシステムを使う
まず、org.bukkit.event.Listener
インターフェースを継承したクラスを作成して下さい。
(メインクラスに継承しても構いません)
そしたら、onEnable()
内に以下のコードを書いて下さい。
getServer().getPluginManager().registerEvents(this, this);
第一引数はListener、第二引数はJavaPlugin(メインクラス)です。
これでプラグインにEventシステムが使えるようになりました。
次に、「Listenerを継承したクラス」にイベントを追加します。
新しく関数を追加します。この時の関数名はなんでも良いです。
新しく追加した関数の引数にはイベントのクラスを書きます。
最後に関数に@EventHandler
アノテーションを追加して下さい。
今回はPlayerJoinEvent
を使用してプレイヤーのログインメッセージを変更します。
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
e.setJoinMessage("プレイヤーがログインしました: " + e.getPlayer().getName());
}
PlayerJoinEvent.setJoinMessage(String)でログインメッセージを変更しています。
e.getPlayer()でプレイヤーを取得し、getName()でプレイヤー名を取得しています。
getName()はプレイヤーの本来の名前です。プレイヤーの表示名はgetDisplayName()で取得できます。
プレイヤーの表示名を設定するにはsetDisplayName(String)を使用します。
メインクラスに書いた場合の例:
package io.github.densyakun.bukkit.test;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin implements Listener {
@Override
public void onEnable() {
getServer().getPluginManager().registerEvents(this, this);
System.out.println("プラグインが有効になりました");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (label.equalsIgnoreCase("test")) {
sender.sendMessage("コマンドが実行されました");
}
return true;
}
@Override
public void onDisable() {
System.out.println("プラグインが無効になりました");
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
e.setJoinMessage("プレイヤーがログインしました: " + e.getPlayer().getName());
}
}
これでイベントを追加することが出来ました。
エクスポートして、プラグインをサーバーに入れます。
このように表示されていればOKです。
Eventシステムの活用
最後に、Eventシステムを活用します。
このようなイベントを追加して下さい。
@EventHandler
public void onPlayerJoin(BlockBreakEvent e) {
Block b = e.getBlock();
if (b.getType() == Material.GRASS) {
e.setCancelled(true);
b.setType(Material.SAND);
}
}
BlockBreakEvent
はプレイヤーがブロックを破壊した時に実行されるイベントです。
これを使って草ブロックを破壊すると砂に変わります。
ブロックに関係するイベントはBlockEvent
を継承しています。
BlockEvent.getBlock()
でブロックを取得できます。
Block.getType()
はブロックの素材をMaterial
型で返します。
if (b.getType() == Material.GRASS)
Material.GRASS
と判定して草ブロックであるかどうかを判別しています。
e.setCancelled(true);
イベントをキャンセルすることで砂に変える時にブロックを破壊されないようになります。
b.setType(material);
これを使ってブロックの素材を砂に設定します。
マテリアルの一覧はこちら(バージョンにより異なる可能性があります)
実際にやってみます。
※暗い。
今回はEventシステムの活用について解説しました。