commit 4b2e24f6b9ce5958849f718d2c2e7cf6c6538edc Author: mii443 Date: Wed Jun 18 00:40:53 2025 +0900 Initial commit: Minecraft Scala Plugin Template - Complete Scala SpigotMC plugin template - Docker development environment - Sample commands (/hello, /info) and event handlers - Development scripts for easy server management - Comprehensive README and documentation 🤖 Generated with Claude Code diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..12da29c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +target/ +project/target/ +.git/ +.gitignore +*.md +dev-server.sh +docker-compose.yml +server-data/ +server-logs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51c3dbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +# Scala/sbt build files +target/ +project/target/ +project/project/ +.bsp/ + +# IDE files +.idea/ +.vscode/ +*.iml +*.ipr +*.iws +.metals/ +.bloop/ + +# sbt plugins and cache +.sbt/ +.cache-main +.cache-tests + +# Logs +*.log +logs/ +server-logs/ + +# Server data (world files) +server-data/ +world/ +world_nether/ +world_the_end/ + +# Runtime files +eula.txt +server.properties +ops.txt +whitelist.txt +banned-*.txt +usercache.json +usernamecache.json + +# Backup files +*.old +*.bak +*~ + +# OS specific files +.DS_Store +Thumbs.db +Desktop.ini + +# Docker volumes +data/ + +# Temporary files +tmp/ +temp/ +*.tmp +*.temp + +# Environment files +.env +.env.local \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f1f82a6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM openjdk:21-jdk-slim + +WORKDIR /minecraft + +# Install wget to download server jar +RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/* + +# Download Spigot 1.21.5 server jar +RUN wget -O server.jar https://getbukkit.org/get/cNW08KHVlCEwof2IkXbxXIKeDPbfgMBU + +# Create plugins directory +RUN mkdir -p plugins + +# Copy server configuration files (optional) +# COPY server-files/ ./ + +# Accept EULA +RUN echo "eula=true" > eula.txt + +# Create basic server.properties +RUN echo "server-port=25565" > server.properties && \ + echo "online-mode=false" >> server.properties && \ + echo "spawn-protection=0" >> server.properties && \ + echo "max-players=10" >> server.properties && \ + echo "difficulty=peaceful" >> server.properties && \ + echo "gamemode=creative" >> server.properties && \ + echo "pvp=false" >> server.properties && \ + echo "enable-command-block=true" >> server.properties + +EXPOSE 25565 + +# Start script +CMD ["java", "-Xmx2G", "-Xms1G", "-jar", "server.jar", "nogui"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b13c03d --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# Minecraft Scala Plugin Template + +🎮 ScalaでSpigotMCプラグインを開発するためのテンプレートです。 + +## 特徴 + +- 🛠️ **Scala + SpigotMC**: ScalaでMinecraftプラグインを開発 +- 🐳 **Docker開発環境**: 簡単にテスト用サーバーを起動 +- 🔄 **ホットリロード**: プラグインの変更を即座に反映 +- 📦 **完全なビルド環境**: sbtでのビルドとパッケージング + +## クイックスタート + +1. **テンプレートをクローン** + ```bash + git clone https://github.com/yourusername/minecraft-scala-plugin-template.git + cd minecraft-scala-plugin-template + ``` + +2. **開発サーバーを起動** + ```bash + ./dev-server.sh start + ``` + +3. **Minecraftクライアントで接続** + - サーバーアドレス: `localhost:25565` + - オフラインモードで動作します + +## 開発コマンド + +```bash +# サーバー起動(プラグインも自動ビルド) +./dev-server.sh start + +# プラグイン再ビルド+サーバー再起動 +./dev-server.sh restart + +# サーバー停止 +./dev-server.sh stop + +# ログ確認 +./dev-server.sh logs + +# Minecraftサーバーコンソールにattach +./dev-server.sh attach + +# サーバーのbashシェルに接続 +./dev-server.sh console + +# 完全リビルド +./dev-server.sh rebuild +``` + +## プロジェクト構造 + +``` +minecraft-scala-plugin-template/ +├── src/main/scala/com/example/plugin/ +│ └── MinecraftScalaPlugin.scala # メインプラグインクラス +├── src/main/resources/ +│ └── plugin.yml # プラグイン設定 +├── build.sbt # sbtビルド設定 +├── docker-compose.yml # Docker設定 +├── Dockerfile # サーバーイメージ +├── dev-server.sh # 開発用スクリプト +└── README.md +``` + +## サンプル機能 + +このテンプレートには以下のサンプル機能が含まれています: + +### コマンド +- `/hello` - 挨拶メッセージを表示 +- `/info` - プレイヤー情報を表示 + +### イベントハンドラ +- プレイヤー参加時のウェルカムメッセージ +- プレイヤー退出時のログ出力 + +## カスタマイズ + +### プラグイン名を変更 +1. `build.sbt` の `name` を変更 +2. `src/main/resources/plugin.yml` の `name` と `main` クラス名を変更 +3. パッケージ名とクラス名を変更 + +### 新機能の追加 +1. `src/main/scala/com/example/plugin/MinecraftScalaPlugin.scala` を編集 +2. 新しいコマンドやイベントハンドラを追加 +3. `./dev-server.sh restart` で変更を反映 + +## ビルド + +### 手動ビルド +```bash +sbt clean package +``` + +### JAR出力場所 +``` +target/scala-2.13/minecraft-scala-plugin_2.13-1.0.0.jar +``` + +## 要件 + +- Docker & Docker Compose +- Java 8以上(sbt用) +- Minecraft Java Edition(テスト用) + +## ライセンス + +このテンプレートは自由に使用・改変できます。 + +## 参考資料 + +- [SpigotMC API Documentation](https://hub.spigotmc.org/javadocs/spigot/) +- [Bukkit Plugin Tutorial](https://bukkit.fandom.com/wiki/Plugin_Tutorial) +- [Scala Documentation](https://docs.scala-lang.org/) \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..05a64a1 --- /dev/null +++ b/build.sbt @@ -0,0 +1,20 @@ +ThisBuild / version := "1.0.0" +ThisBuild / scalaVersion := "2.13.12" + +lazy val root = (project in file(".")) + .settings( + name := "minecraft-scala-plugin", + resolvers ++= Seq( + "spigot-repo" at "https://hub.spigotmc.org/nexus/content/repositories/snapshots/", + "sonatype" at "https://oss.sonatype.org/content/repositories/snapshots/" + ), + libraryDependencies ++= Seq( + "org.spigotmc" % "spigot-api" % "1.21.5-R0.1-SNAPSHOT" % "provided" + ), + assembly / assemblyMergeStrategy := { + case PathList("META-INF", xs @ _*) => MergeStrategy.discard + case x => MergeStrategy.first + }, + assembly / assemblyJarName := s"${name.value}-${version.value}.jar" + ) + diff --git a/dev-server.sh b/dev-server.sh new file mode 100755 index 0000000..898997f --- /dev/null +++ b/dev-server.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# Minecraft Plugin Development Server Script + +set -e + +echo "🎮 Minecraft Plugin Development Server" +echo "======================================" + +# Function to build plugin +build_plugin() { + echo "📦 Building plugin..." + sbt clean package + + # Check if jar exists + if [ ! -f "target/scala-2.13/minecraft-scala-plugin_2.13-1.0.0.jar" ]; then + echo "❌ Plugin jar not found! Build failed." + exit 1 + fi + + echo "✅ Plugin built successfully!" +} + +# Create necessary directories +mkdir -p server-data server-logs + +# Start/restart the server +case "${1:-start}" in + "start") + build_plugin + echo "🚀 Starting development server..." + docker compose up -d + echo "✅ Server started! Connect to localhost:25565" + echo "📜 To view logs: docker compose logs -f" + echo "🛑 To stop: ./dev-server.sh stop" + ;; + "stop") + echo "🛑 Stopping development server..." + docker compose down + echo "✅ Server stopped!" + ;; + "restart") + echo "🔄 Restarting development server..." + build_plugin + docker compose down + docker compose up -d + echo "✅ Server restarted!" + ;; + "logs") + echo "📜 Showing server logs..." + docker compose logs -f + ;; + "console") + echo "💻 Connecting to server console..." + docker exec -it minecraft-dev-server /bin/bash + ;; + "attach") + echo "📎 Attaching to Minecraft server console..." + echo "💡 To detach: Press Ctrl+P then Ctrl+Q" + docker attach minecraft-dev-server + ;; + "rebuild") + echo "🔨 Rebuilding everything..." + build_plugin + docker compose down + docker compose build --no-cache + docker compose up -d + echo "✅ Complete rebuild finished!" + ;; + *) + echo "Usage: $0 {start|stop|restart|logs|console|attach|rebuild}" + echo "" + echo "Commands:" + echo " start - Build plugin and start server" + echo " stop - Stop the server" + echo " restart - Rebuild plugin and restart server" + echo " logs - View server logs" + echo " console - Connect to server console (bash)" + echo " attach - Attach to Minecraft server console" + echo " rebuild - Complete rebuild (server + plugin)" + exit 1 + ;; +esac diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f096579 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3.8' + +services: + minecraft-server: + build: . + container_name: minecraft-dev-server + ports: + - "25565:25565" + volumes: + - ./target/scala-2.13/minecraft-scala-plugin_2.13-1.0.0.jar:/minecraft/plugins/minecraft-scala-plugin.jar + - ./server-data:/minecraft/world + - ./server-logs:/minecraft/logs + environment: + - JAVA_OPTS=-Xmx2G -Xms1G + stdin_open: true + tty: true + restart: unless-stopped + networks: + - minecraft-net + +networks: + minecraft-net: + driver: bridge \ No newline at end of file diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..bbb0b60 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.11.2 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..ad1389c --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.3") \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..99529bc --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,35 @@ +name: MinecraftScalaPlugin +version: 1.0.0 +main: com.example.plugin.MinecraftScalaPlugin +api-version: 1.21 +author: YourName +description: A Minecraft plugin written in Scala + +commands: + hello: + description: Sends a hello message to the player + usage: /hello + permission: scalaplugin.hello + permission-message: You don't have permission to use this command! + + info: + description: Shows player information + usage: /info + permission: scalaplugin.info + permission-message: You don't have permission to use this command! + +permissions: + scalaplugin.hello: + description: Allows use of the hello command + default: true + + scalaplugin.info: + description: Allows use of the info command + default: true + + scalaplugin.*: + description: Gives access to all ScalaPlugin commands + children: + scalaplugin.hello: true + scalaplugin.info: true + default: op \ No newline at end of file diff --git a/src/main/scala/com/example/plugin/MinecraftScalaPlugin.scala b/src/main/scala/com/example/plugin/MinecraftScalaPlugin.scala new file mode 100644 index 0000000..cb1a62d --- /dev/null +++ b/src/main/scala/com/example/plugin/MinecraftScalaPlugin.scala @@ -0,0 +1,74 @@ +package com.example.plugin + +import org.bukkit.plugin.java.JavaPlugin +import org.bukkit.event.{EventHandler, Listener} +import org.bukkit.event.player.{PlayerJoinEvent, PlayerQuitEvent} +import org.bukkit.command.{Command, CommandExecutor, CommandSender} +import org.bukkit.entity.Player +import org.bukkit.ChatColor + +class MinecraftScalaPlugin extends JavaPlugin with Listener { + + override def onEnable(): Unit = { + getLogger.info("Scala Minecraft Plugin has been enabled!") + + // Register events + getServer.getPluginManager.registerEvents(this, this) + + // Register commands + Option(getCommand("hello")).foreach(_.setExecutor(new HelloCommand)) + Option(getCommand("info")).foreach(_.setExecutor(new InfoCommand)) + } + + override def onDisable(): Unit = { + getLogger.info("Scala Minecraft Plugin has been disabled!") + } + + @EventHandler + def onPlayerJoin(event: PlayerJoinEvent): Unit = { + val player = event.getPlayer + val message = s"${ChatColor.GREEN}Welcome ${player.getName} to the server!" + player.sendMessage(message) + getLogger.info(s"Player ${player.getName} joined the server") + } + + @EventHandler + def onPlayerQuit(event: PlayerQuitEvent): Unit = { + val player = event.getPlayer + getLogger.info(s"Player ${player.getName} left the server") + } +} + +class HelloCommand extends CommandExecutor { + override def onCommand(sender: CommandSender, command: Command, label: String, args: Array[String]): Boolean = { + sender match { + case player: Player => + player.sendMessage(s"${ChatColor.YELLOW}Hello ${player.getName}! This is a Scala plugin!") + true + case _ => + sender.sendMessage("This command can only be used by players!") + true + } + } +} + +class InfoCommand extends CommandExecutor { + override def onCommand(sender: CommandSender, command: Command, label: String, args: Array[String]): Boolean = { + sender match { + case player: Player => + val info = Seq( + s"${ChatColor.AQUA}=== Server Info ===", + s"${ChatColor.WHITE}Player: ${player.getName}", + s"${ChatColor.WHITE}World: ${player.getWorld.getName}", + s"${ChatColor.WHITE}Location: ${player.getLocation.getBlockX}, ${player.getLocation.getBlockY}, ${player.getLocation.getBlockZ}", + s"${ChatColor.WHITE}Health: ${player.getHealth}/${player.getMaxHealth}", + s"${ChatColor.WHITE}Food Level: ${player.getFoodLevel}/20" + ) + info.foreach(player.sendMessage) + true + case _ => + sender.sendMessage("This command can only be used by players!") + true + } + } +} \ No newline at end of file