歩数計で歩数を計測してMinecraftに反映させるプラグインを作る。

## はじめに
今回は大学でM5Stack Core2を利用したMinecraftのプラグインの作り方を学んだので、復習の意味も込めて、オリジナルのプラグインを作成してみました。
初めての記事で拙い部分があると思いますがご了承ください。
## 対象者
Minecraftのプラグインに興味があるって人の役に立てばと思います。
プラグイン作成のための環境構築については割愛します。

## 仕組み
m5stack Core2で歩数を計測して、mqtt通信でnode-redに歩数を送ります。その後websocketでMinecraftに歩数を送信して、歩数に応じてプレイヤーに経験値を付与するようなプラグインを作ります。
今回はMinecraftのプラグインについてメインで書いていこうと思うので、歩数の取り方やnode-redについての説明は割愛させていただきます。

## M5Core2側
歩数計を作成する際に参考にさせていただいたサイト
https://qiita.com/ufoo68/items/d0d12c666a19405c5625

## WebSocketとは
WebSocketとは、ブラウザとウェブサーバーとの間で双方向通信を行うための規格です。
httpは一つのコネクションでリクエストしか送れず、クライアント側からしかれクエストを送れないのに対して、WebSocketは双方が**オンライン状態を維持すれば、双方向通信が可能になります。**（多分こんな感じだと思う）
今回はOkhttp3を使用しました。

Okhttpの公式ページ
https://square.github.io/okhttp/

## コード
```java
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;

public final class MinecraftPlaguin extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    @Override
    public void onDisable() {
        webSocketClient.close();
    }
    World world;
    String url;
    WebSocketClient webSocketClient;
    public MinecraftPlaguin() {
        this.world = getServer().getWorld("world");
    }

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label,String[] args){
        if(command.getName().equalsIgnoreCase("walk")){
            this.url = WebSocketサーバーのURLを記入;
            Player player = Bukkit.getPlayer(sender.getName());
            webSocketClient = new WebSocketClient(url,player);
            webSocketClient.connect();
            sender.sendMessage("start");
        }

        if(command.getName().equalsIgnoreCase("walk_stop")){
            webSocketClient.close();
            sender.sendMessage("stop");
        }
        return false;
    }
}

```
onEnable()関数はプラグインが起動したときに動くコードです。
このコードではgetServerで現在のサーバーを取得して、そこからプラグインと連携するためのプラグインマネージャーを取得、そこからregisterEventsでプラグインを登録します。
resigterEvents(this,this)となっているのは、registerEventsは引数にListnerとPluginを取るので、JavaPluginを継承して、Listenerを実装しているMinecraftPlaguinそのものを引数に指定しているからです。

onDisable()関数はサーバーが終了するときに動くコードです。
ここではwebsocketを終了しています。

onCommand()関数はコマンド操作に関する処理を記述しています。
今回のプラグインではwalkというコマンドを打つと歩数を取得。
walk_stopと打つと歩数の取得を終了して、歩数に応じて経験値を与えるようになっています。

コマンドを設定するにはplugin.ymlに追加したいコマンドを記述します。
```yml
name: minecraftPlaguin
version: '${project.version}'
main: パッケージ.MinecraftPlaguin
api-version: '1.20'

commands:
  walk:
    description: escription
  walk_stop:
    description: escription
```


細かい部分はAPIを見てもらえればいいと思うのですが、簡単に説明すると、senderのgetNameメソッドでプレイヤーの名前を入手し、それを利用してPlayerのインスタンスを取得しています。そしてそれをwebsocketClientに渡しています。

```java
import com.google.gson.Gson;
import okhttp3.*;
import okhttp3.WebSocket;
import org.jetbrains.annotations.NotNull;
import org.bukkit.entity.Player;

public class WebSocketClient {
    String url; //WebSocketサーバーのURL
    int nowStep;
    int preStep = 0;
    int steps = 0;
    Player player;
    private static WebSocket webSocket;
    Gson gson = new Gson();

    public WebSocketClient(String url,Player player){
        this.url = url;
        this.player = player;
    }

    //websocket接続が開いたときや、閉じた時の処理を記入する
    WebSocketListener listener = new WebSocketListener() {
        @Override
        public void onClosed(@NotNull okhttp3.WebSocket webSocket, int code, @NotNull String reason) {
            System.out.println("接続終了");
            player.giveExpLevels(steps);
        }

        @Override
        public void onMessage(@NotNull okhttp3.WebSocket webSocket, @NotNull String text) {
            System.out.println("onMessage");
                Step step = gson.fromJson(text,Step.class);
                nowStep = Integer.parseInt(step.steps);
                if(preStep != 0) {
                    steps += (nowStep - preStep);
                }
                if(nowStep-preStep!=0) {
                    player.sendMessage(String.valueOf(steps));
                }
                preStep = nowStep;
        }

        @Override
        public void onOpen(@NotNull okhttp3.WebSocket webSocket, @NotNull Response response) {
            System.out.println("接続開始");
        }
    };

    public void connect(){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        webSocket = client.newWebSocket(request,listener);
    }

    public void close(){
        webSocket.close(1000,"Closing connection");
    }

}

```

こちらはWebSocket通信をするためのクラスです。
connect()関数を呼び出すと、指定したurlとWebSocketで通信することが出来ます。

```java
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
```
この二行はOkhttpでhttp通信する場合と同じです。
```java
webSocket = client.newWebSocket(request,listener);
```
このコードでは先ほどのrequestとWebSocketListenerを引数に取ることで、WebSocketのインスタンスを取得できます。

ここで引数として渡しているlistenerは
```java
WebSocketListener listener = new WebSocketListener() {
...
```
で定義してあります。
@onClosedでは接続が終了した時の処理、
@onMessageでは通信中の処理、
@onOpenでは接続開始時の処理を記述する。

今回はnode-redから歩数をjson形式で受け取り、接続が開始してからの歩数を計測しています。

```java
public class Step{
    public String steps;
    public Step(String steps){
        this.steps = steps;
    }
}

```

こちらではStepクラスを定義しています。

## 実際に動かす
walkコマンドを入力した時
![スクリーンショット 2023-12-18 041341.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/4dd2dc7a-a2ba-f40e-9eab-f5b129a51fde.png)

歩数を計測している時
![スクリーンショット 2023-12-18 041516.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/929f3f5b-3b01-a346-7295-ffcaa7db797c.png)

walk_stopコマンドを入力した時
![スクリーンショット 2023-12-18 041625.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/85516f2d-23f6-c249-c9f7-ae80014ee0e3.png)
![スクリーンショット 2023-12-18 041544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/e13c1ca8-c51c-c991-06e5-e80205517ea1.png)

![スクリーンショット 2023-12-18 041632.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/fb4c5bb9-0833-2a96-a6fe-f850992a75af.png)

ちゃんと14歩分レベルが増えている

## 感想
今回の記事を書くにあたって、WebSocketやプラグインの作成方法について、さらに理解を深めることが出来たと思う。
あと、公式リファレンスなどを見て、自分が探している情報が見つかった時はやっぱりうれしいなと思った。

## 参考
https://hub.spigotmc.org/javadocs/spigot/

https://qiita.com/ufoo68/items/d0d12c666a19405c5625

https://square.github.io/okhttp/