見出し画像

マインクラフト内のチャットを翻訳するプラグインを作った話

某Discordサーバーでなんか役に立てること無いかなあって思って、
英語話者がちょいちょいいるイメージがあり、
Pluginの作り方を思い出すのにちょうどいいと思って、
今回はわりかしとっつきやすいであろうチャット周りのPluginを作ってみることにした。

環境

  • PaperMC 1.19.4

  • Windows

  • IntelliJ IDEA 2023.1.1

流れ

だいたいこんなかんじ

PluginからAPI叩いて翻訳された返答をチャットに流す至ってシンプルな流れ。

準備1 GASの用意

GASでGoogle翻訳のAPIを叩くものを作る必要があったので、

ちょうどいいのがありまして。
これを使いました。
自分のGoogleアカウントで作り直して、
デプロイして準備完了

準備2 IntelliJ IDEA の環境構築

ここらへんから少しUIは変わってるけどだいたい同じ。
Minecraftの拡張機能をインストールして、
あと日本語化もとりあえず入れた。
プロジェクトの作り方もだいたいざっくり解説動画とか見ながら適当に。

コード

① src/main/java/org.tlanslate2jp/Translate2jp

// src/main/java/org.tlanslate2jp/Translate2jp

package org.tlanslate2jp;

import org.bukkit.Server;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

public final class Tlanslate2jp extends JavaPlugin {

    @Override
    public void onEnable() {
        // Plugin startup logic
        getLogger().info("plugin loaded・");
        Server server = this.getServer();
        PluginManager pluginManager = server.getPluginManager();
        pluginManager.registerEvents(new ChatListener(), this);
    }

    @Override
    public void onDisable() {
        // Plugin shutdown logic
    }
}

② src/main/java/org.tlanslate2jp/ChatListener

変数 TRANSLATE_API_URL にデプロイしたAPIのURLを入れて下さい。

//src/main/java/org.tlanslate2jp/ChatListener
//こんなにimportいらないかも。

package org.tlanslate2jp;

import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;




public class ChatListener implements Listener{

    private static final String TRANSLATE_API_URL = "https://script.google.com/macros/s/******/exec";

    @EventHandler
    public void onPlayerChat(AsyncChatEvent event) {

        Component message = event.message();


        Bukkit.getLogger().info(String.valueOf(message));
        String chatmsg = PlainTextComponentSerializer.plainText().serialize(message);

        // 特定の条件やパターンに一致するかを確認し、APIを呼び出してレスポンスを取得する処理
        if (chatmsg.startsWith("!2jp")) {
            String textToTranslate = chatmsg.substring(5);
            String translatedText = translateText(textToTranslate);

            if(translatedText != null){
                Bukkit.getServer().sendMessage(Component.text(translatedText));
            } else {
                Bukkit.getLogger().warning("翻訳に失敗しました。");
            }
        }
    }
    private String translateText(String text){
        try{
            String encodedText = URLEncoder.encode(text, StandardCharsets.UTF_8);
            String apiUrl = TRANSLATE_API_URL + "?text=" + encodedText + "&source=en&target=ja";

            URL url = new URL(apiUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setInstanceFollowRedirects(true);
            connection.setRequestMethod("GET");

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                StringBuilder response = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();

                String jsonResponse = response.toString();
                JSONParser parser = new JSONParser();
                String jsontext = null;
                try {
                    JSONObject json = (JSONObject) parser.parse(jsonResponse);

                    jsontext = (String) json.get("text");
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                return jsontext;
            } else {
                Bukkit.getLogger().warning("翻訳APIリクエストが失敗しました。" + responseCode);
            }

            connection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

スタックしたところ

こんぽおねんと・・・?

chatのイベントが起きたときのComponentっていうオブジェクトがよくわからなくて、めっちゃ調べた。
なんとなくMinecraftのチャットメッセージの独特なオブジェクトってことがわかった。

シュレディンガーのビルド

IntelliJ IDEAのビルドが必ず1回目はマルチバイト文字のエラーを起こす。
でもなぜか2回やると通る。動けばいいかな、と。

灯台下暗し

jarファイル作成のビルドってどっからやるねんって探してしまった。
右側のカラムに普通にあって己の視野の狭さに血吐くとこだった。

気づき・あとがき

今回非推奨になってるメソッドが多くてなんやねんって箇所がいっぱいあった。海外フォーラム、マジありがとう。解決にはならんかったけど。
やっぱり今回も公式ドキュメント読み込んだほうが確実だった。
でも、公式ドキュメントの関連した箇所をChatGPTに入力して、コード作成のお手伝いをしてもらった。
PythonとかRubyとか色んな言語触ってるからか記法がこんがらがったりしてるからそういうときAIは助かるなあ、としみじみ。
今回は以上。
それでは。

最後までお読みいただき、ありがとうございます。 今後もたくさんの方に読んでいただけるよう精進します。 活動継続にあたりサポートをいただけると、 私のモチベーション維持やクオリティ向上に繋がります。 頂いたサポートはクリエイターとしての活動費にさせて頂きます。 ぜひお願い致します。