Claude CodeでMinecraftのPaperプラグインを作る — ビルドとサーバー起動を検証ループに
Paperプラグインを、Gradleビルドとローカルサーバーのログで合否が読める形にして、Claude Codeに書かせて直させる手順。plugin.ymlの落とし穴と権限設定の例つきです。
Claude CodeでMinecraftのPaperプラグインを作る — ビルドとサーバー起動を検証ループに
Paperは、Minecraftサーバーのプラグインを動かすためのサーバーソフトウェアです。プラグインはJavaで書き、Gradleでビルドして、Paperサーバーのpluginsディレクトリに置いて動かします。Claude Codeに任せやすいのは、この流れのうち「ビルドが通るか」と「サーバーがプラグインを読み込めたか」を文字で確かめられる部分です。
この記事では、PaperのProject setupガイドに沿って、ビルドとサーバー起動を検証の手段にする反復の組み方を説明します。ゲーム内で実際に動かして確かめる部分は、手元に残ります。
Claude Codeに渡すPaperプロジェクトの前提
PaperのProject setupガイドは、IntelliJ IDEAを前提にGradleのKotlin DSLで説明しています。Mavenも使えますが、Maven側は非推奨の扱いです。Claude Codeに作らせるときも、Gradle Kotlin DSLで揃えると、公式の例とそのまま突き合わせられます。
build.gradle.kts にはPaperのリポジトリと依存を書きます。ガイドの例は次のとおりです。
repositories {
maven(url = "https://repo.papermc.io/repository/maven-public/") {
name = "papermc"
}
}
dependencies {
compileOnly("io.papermc.paper:paper-api:26.3.build.+")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
}見るべき点は3つあります。
compileOnly: Paper本体はサーバー側にあるので、プラグインのJARには含めません26.3.build.+: 末尾の+を、{VERSION}.build.25-stableのようなビルド識別子に置き換えると特定ビルドを指せます- Javaのツールチェーン: 例ではJava 25です。Minecraft 26.1より前(1.21.11以下)では
{VERSION}-R0.1-SNAPSHOTという別の版表記だったと説明しています
ソースの置き場所は src/main/java と src/main/resources です。パッケージは、自分のドメインを逆にした名前(com.example など)にプロジェクト名を続けます。ドメインがなければGitHubのユーザー名を使う、という案内もあります。
メインクラスの最小例
ガイドのメインクラスは、JavaPlugin を継承し、onEnable でイベントリスナーを登録する形です。参加したプレイヤーに挨拶を送ります。
package com.example.paperplugin;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
public final class ExamplePlugin extends JavaPlugin implements Listener {
@Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().sendPlainMessage("Hello, " + event.getPlayer().getName() + "!");
}
}メインクラスの名前は Main にしないよう勧められています。プラグイン名に合わせた ExamplePlugin のような名前にします。これはClaude Codeに最初に渡す指示として、CLAUDE.mdに書いておく価値があります。
paperweightが要るのはサーバー内部に触るときだけ
paperweightはPaperのビルド用ツール群の名前で、そのうちpaperweight-userdevは、サーバー内部のコード(NMS)に開発中から触るためのGradleプラグインです。
イベントやコマンドなどのAPIだけで書けるプラグインは、上の paper-api への依存で足ります。userdevを入れるときは、Paper APIへの依存を外します。dev bundleの依存にAPIが含まれるためです。
plugins {
id("io.papermc.paperweight.userdev") version "2.0.0-beta.24"
}
dependencies {
paperweight.paperDevBundle("26.3.build.+")
}もう1点、バージョンによる違いがあります。Minecraft 26.1以降、Paperは難読化されたプラグインをサポートしません。そのためdev bundleでの再難読化(reobfJar)は26.1以降で動きません。1.21.11以下の記述を見つけたClaude Codeが reobfJar を足してきたら、対象のバージョンを確かめてください。
パッチ適用の失敗で paperweightUserdevSetup が落ちるときは、paperweight.javaLauncher に別のJavaバージョンを指定する方法がuserdevのページに載っています。
plugin.ymlはサーバーの読み込み時に効く
src/main/resources/plugin.yml は、ビルドが通っても間違いに気づけない場所です。サーバーが起動してはじめて、読み込みの成否がログに出ます。plugin.ymlのページの例は次のとおりです。
name: Example-Plugin
version: 1.0.0
main: com.example.paperplugin.ExamplePlugin
description: An example plugin
author: PaperMC
api-version: '26.3'必須項目は name、version、main の3つです。検証のときに見る項目を表にまとめます。
| 項目 | 起きること |
|---|---|
main | 起きることメインクラスをパッケージ名つきで書く。ずれるとクラスを見つけられない |
api-version | 起きること省略するとレガシーなプラグインとして読み込まれ、警告がコンソールに出る |
api-version | 起きること指定より古いサーバーは、プラグインの読み込みを拒否する |
depend | 起きること依存先のプラグインが見つからないと、自分のプラグインは読み込まれない |
prefix | 起きること設定すると、ログ上のプラグイン名の代わりに表示される |
api-version の有効な範囲は、1.13から26.3と書かれています。prefix を設定するとログでの見え方が変わるので、ログを読んで合否を判定する運用では、prefix を勝手に足さないよう指示しておくと混乱しません。
ビルドとサーバー起動を回す
ここからが検証ループの本体です。Project setupガイドは、ビルド後の動作確認のために、Run-Task Gradleプラグインを紹介しています。Paperサーバーを自動でダウンロードして起動してくれます。
plugins {
id("xyz.jpenilla.run-paper") version "VERSION"
}
tasks {
runServer {
minecraftVersion("1.21.8")
}
}VERSION には、Gradleプラグインポータルの最新版を入れます。README上の必須設定は minecraftVersion だけで、プラグインのJAR(shadowJarがあればそちら)は自動で使われます。ここに書かれた 1.21.8 はREADMEの例なので、実際に動かすMinecraftのバージョンは自分のプロジェクトの対象に合わせてください。
これでループは次の2段になります。
Claude Codeに回させる検証の2段
- 1
ビルドを通す
./gradlew buildを実行し、コンパイルエラーを読んで直します。JARの出力先はbuild/libsです。 - 2
サーバーで読み込ませる
./gradlew runServerを実行し、ログにプラグインの有効化と警告が出ていないかを読みます。
サーバーは止まらないコマンドとして扱う
runServer はサーバーを起動したまま待ち続けるため、前面で実行するとBashツールがそこで止まったままになります。Claude Codeにはこの種のコマンドのための仕組みが2つあります。
- バックグラウンド実行: Bashツールの
run_in_background: trueで起動すれば、Claudeは作業を続けられます。起動したタスクは/tasksで一覧と停止ができます - Monitorツール: バックグラウンドのコマンドを走らせ、出力の各行をClaudeに返します。ログを見張って、エラーが出たところで反応させる使い方です
Monitorには期限があります。既定は5分で、最大30分です。サーバーの起動確認なら足りる長さですが、長時間のテストプレイには向きません。Monitorが実行するコマンドには、Bashと同じ権限ルールが適用されます。
権限は検証に必要な範囲に絞る
ビルドとサーバー起動を自動で回すなら、コマンドごとに許可を与えます。.claude/settings.json に書く一例を示します。
{
"permissions": {
"allow": [
"Bash(./gradlew build *)",
"Bash(./gradlew runServer *)",
"Bash(./gradlew --stop)"
],
"deny": [
"Bash(./gradlew publish *)"
]
}
}権限ルールの注意点がいくつかあります。評価は拒否、確認、許可の順で、拒否に当たれば許可で上書きできません。末尾の * の前にスペースを置くと、引数なしの ./gradlew build にも一致します。また、./gradlew build && ./gradlew runServer のように複合したコマンドは、各サブコマンドが別々に判定されます。publish のような公開系のタスクを拒否しておくのは、サーバー検証とは別の安全弁です。
CLAUDE.mdに書いておく運用ルール
検証の手順は、プロジェクトのCLAUDE.mdに条件つきで書くと、毎回の指示が要らなくなります。書き方の一例です。
## Paperプラグイン
- メインクラス名は `Main` にしない。プラグイン名に合わせる
- 変更後は `./gradlew build` を実行し、通らなければ直す
- build が通ったら `./gradlew runServer` をバックグラウンドで起動し、ログを読む
- ログに警告やプラグインの読み込みエラーがあれば、plugin.yml を先に疑う
- plugin.yml の `api-version` と `main` は、変更のたびに build.gradle.kts と突き合わせる
- 確認が終わったら起動したサーバーを止めるGradleの出力を絞るコツはClaude CodeでGradleビルドを回すで扱っています。ビルドとサーバー起動の2段を決まった手順にしたければ、Claude Code Hooks完全ガイドの仕組みで自動化する方法もあります。
同じ型の別エコシステム
Gradleのタスクで「構成検査 → ビルド → 実機起動」を段階にするのは、JetBrainsプラグインでも同じ発想です。違いは実機の扱いで、IDEの画面を開くか、ログを出すサーバーを起動するかで、後者はClaude Codeが出力から判断できる範囲が広くなります。IDE側の手順はClaude CodeでJetBrainsプラグインを開発する記事にあります。
ログで確かめきれない部分と、デバッグ
サーバーのログで見えるのは、読み込みの成否と、プラグイン自身が出した出力です。イベントの挙動を確かめるには、Debuggingのページが勧めるとおり、System.out.println よりもプラグインのロガー(getSLF4JLogger())を使います。どのプラグインのログか分かりやすいためです。
ログを足すたびに再ビルドとサーバー再起動が必要になるのが、このやり方の弱点です。一時停止して変数を見たいときは、リモートデバッガを使います。runServer を使っている場合は、同ページの案内どおり jvmArgs("-Ddisable.watchdog=true") を足します。ブレークポイントで止めている間、サーバーはtickを進めません。既定のウォッチドッグは、10秒tickがないとスレッドダンプを出し、60秒で止めるためです。開発用のサーバーに限って使い、本番では無効にしません。
また、参加したプレイヤーを写す動作確認(PlayerJoinEvent の挨拶など)は、ゲームクライアントで接続しないと確認できません。Vanillaクライアントは30秒間サーバーから何も届かないと切断するので、デバッガで長く止めると接続も切れます。この部分は人が確認する前提で、Claude Codeには「ログ上でプラグインが有効になった」ところまでを完了の条件として渡すのが現実的です。
起動後にClaude Codeへ読ませるログの切り分け
起動ログを読ませるときは、「何を見て成功とするか」を先に決めておきます。プラグインが有効になったことを示す行が出る、api-version の警告が出ない、依存先のプラグインが見つからない旨のメッセージが出ない、の3点が目安です。どれかが外れたら、まず plugin.yml を疑い、次にメインクラスの完全修飾名を見直します。コードのバグを疑うのはそのあとです。ビルドが通っていてもサーバーが読み込めない場合の原因は、多くがこの設定側にあるためです。
まとめ
Paperプラグインは、./gradlew build の成否と、runServer のログの2つで、Claude Codeが合否を読める状態にできます。APIだけで足りるなら paper-api の compileOnly で十分で、paperweight-userdevはサーバー内部に触る場合にだけ加えます。ゲーム内の動作確認は人の側に残る、と割り切ると、Claude Codeに任せる範囲が決まります。
関連する記事
Claude Code をもっと見る →Claude Codeとは — できること・料金・始め方と使い方の全体像
Claude CodeでScrapyのスクレイパーを作る — robots.txt遵守とcontracts検証
Claude CodeでROS 2パッケージを作る — colcon buildとlaunch_testの反復
Claude CodeでPySparkのジョブを書く — local[2]のpytestで検証する手順
Claude CodeでPower Platformのソリューションを編集する手順 — pac solution
Claude CodeでOpenTofuを使う — validateとplanだけ許可する権限設計