MinecraftでRPGサーバーを開発してみて得たこと



こんにちは、[Atlantis Server](http://atlantis-mc.net/)というマインクラフトのRPGサーバーでDeveloperをやっているReyADというものです。
2016年の12月からRPGサーバーの開発をしています。この記事ではその開発を通して得た知見をまとめてみます。

# Minecraftとは？

> 『Minecraft』（マインクラフト）は、Notch（マルクス・ペルソン）と彼の会社（Mojang AB）の社員が開発したサンドボックスゲームである。ブロックを地面や空中に配置し、自由な形の建造物等を作っていくゲームである。日本では一般的に「マイクラ」と略される。
> https://ja.wikipedia.org/wiki/Minecraft

最近ではものづくりができるということで、教育用にフォーカスされて注目されていますが、
PvP、アドベンチャー等といった楽しみ方もあります。

Minecraftには大きく２つ種類があり

* Java Edition
* Bedrock Edition

とあります。
Java EditionとはMinecraft最初のバージョンです。2017年に呼び方が変わりました。（一部の界隈では批判的な意見がありました。）
Bedrock EditionとはMicrosoftがMinecraftを買収した後に、ゼロから作り直したバージョンです。PS4やXboxなどのコンソール版やWin10版がこちらとなります。
認識としては、世の中に最初に出たバージョンがJava、最近のものがBedrockとなっています。

## Minecraftサーバー

マインクラフトのワールドをサーバーに作り、そのサーバーのアドレスにアクセスすれば、複数人で同じマインクラフトのワールドで遊ぶことができます。
JavaとBedrock両方ともサーバーを立てることが出来ます

## サーバーMOD（プラグイン）

マインクラフトサーバーでもMODを使って遊ぶことができます。
これらのMODはプラグインと呼ばれています。
以下のような種類があります。

* Java Editon
  * Spigot
  * Sponge
* Bedrock Edition
  * Pocket Mine
  * Nukkit

# Atlantisとは

ここで私がやっているプロジェクトについて説明します。
アーキエイジや黒い砂漠のようなMMORPGの世界をMinecraftで実現する事が目的です。
そこではPvPや生産、経済というような要素が作られる予定です。
対象のプラットフォームはJava Editionです。

要求されるものとしては

* MinecraftワールドにRPGの世界を建築する
* 経済や生産などMinecraftにはないシステムをサーバーMODで実現させる
  * データベース、インフラなど色々と考える必要がある
* これらを複数人のチームをマネジメントしながら完成させる

これらの要求を効率的に実現するために、開発環境、建築ツール、チームマネジメント等色々行いました。

# チームについて

現在、開発で集まってくれたメンバーは「給料は発生しない、ボランティア」であり、
「リアルでの面識はない」という条件が全員に当てはまります。
そのため、以下のような問題が発生しました。

* 作業の強要がしにくい
* 個人の成長などを意識して仕事を割り振ったりできない
  * いつでもやめられる状況であるため

ボランティア集団にありがちな問題ですが、現状これの明確な解決方法はよくわからないです。
いまのところ、いい雰囲気にする、ロードマップを明確にするというような方法をとっています。

## Discord

メンバーの情報共有はDiscordを導入しました。
Slackと迷いましたが、導入した人がゲーマーだったので選定する間もなくDiscordを使っています。

メリット
* 無料で使える
* メッセージ上限がない

デメリット
* Integrationのサポートが少ない
  * Slackはこのあたりは優秀
* 返信機能、引用機能、スレッドなどの機能が無い

ということで、お金が出せる状況であればSlack一択ではないのかなと思います。
このプロジェクトではお金が出せないので、Discordをつかってます。


## BackLog

Discordだけだと以下のような課題が発生しました

* 誰が何やってるかわからない
  * わからないから何も作業しないというメンバーが多発
* 議論に結論がついたのかがわからない
  * 非同期コミュニケーションなので、いつまでたっても議論が終わらないということがありました
* ログを追うのが大変
  * 何を見ればいいのかわからなくなってしまうことがありました
* スケジュール管理ができない

と言った問題があり、主に建築チーム（後述します）で作業が進まないという深刻な状態になりました。

このような背景からBackLogを導入しました。

![タイトルなし.png](https://qiita-image-store.s3.amazonaws.com/0/152986/3cc9c120-fa9b-2dad-eef7-86581154b3c6.png)

まだ試験段階ですが、誰が何をやっているかがある程度わかるようになったと思います。

# 開発について

Spigotを使って開発を行っています。
筆者自身が開発関係の取りまとめをおこないました。

## マインクラフトプラグインの開発界隈の状況について

マインクラフトの開発コミュニティは以下のようになっています

* 殆どのプロジェクトはJavaが主流
  * レガシーなJavaが多いです
* Mavenが主流
* Eclipseが主流
* 日本、海外問わず、ドキュメントが不足している
  * フォーラムにかかれているってのがおおい
  * オープンソースのプロジェクトも少ない
* Minecraftのコード自体に負債が多いため、Spigotなどのフレームワークにも負債があり、使いにくいところが多々ある
* モダンなライブラリを導入されていない

という状況となっていました

## 構築した開発環境

開発環境、ライブラリは以下を導入しました

* 開発言語はKotlin
* Gradleを使ってビルドする
* GitHubをつかって開発をする
* IntelliJ　IDEAで統一する
* Retrofit、Dagger、RxJavaなどモダンなライブラリを導入した

## GitHub

殆どのメンバーがgitを理解していない状況だったので、とにかく勉強してもらいました。
GitHub-flowに乗っ取ったプルリクエスト形式で開発を進めています。

## Kotlin

Kotlinを使うことにより、以下のような恩恵を受けることができます

* Null安全
* 簡略化して記述できる
* Kotlin extensions

Spigotでは歴史的経緯から技術的負債を多くコードに抱えているので、Kotlin Extensionsをつかって、
自分たちでメソッドを定義して完結に書くことができたのが良かったです

## IntelliJ IDEA

IntelliJ IDEAをチーム内で統一して使うことにしました。

* 何か詰まったりしたら、とりあえずレクチャーできるというのが大きいです
  * 筆者がIntelliJ IDEAをつかってるから、ゴリ押しで使って欲しい的なお願いをしたわけでもない
* リフォーマットのルールを合わせられるので、変なDiffが発生しない

## RxJava
非同期処理はRxJavaを使って実現しました。
主にスキルなどのエフェクトをRxJavaを使って書いています。

```kotlin
Observable.interval(10, TimeUnit.MILLISECONDS)
                .takeWhile { it < 130 }
                .subscribe { drawEffect(it) }
```

![2017-09-13_00.48.09.png](https://qiita-image-store.s3.amazonaws.com/0/152986/26611103-024f-a337-8270-c4fc20917230.png)

魔法陣の例

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">パーティクルで魔法陣つくってみた <a href="https://t.co/IFkzkqd2rb">pic.twitter.com/IFkzkqd2rb</a></p>&mdash; ReyAD (@ReyADayer) <a href="https://twitter.com/ReyADayer/status/877174041890521096?ref_src=twsrc%5Etfw">2017年6月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr"><a href="https://t.co/lM2mE0e1JP">pic.twitter.com/lM2mE0e1JP</a></p>&mdash; ReyAD (@ReyADayer) <a href="https://twitter.com/ReyADayer/status/903658756407308289?ref_src=twsrc%5Etfw">2017年9月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">敵をターゲットしたらスキルを使う、攻撃されたらスキルを使うという単純なAIでもそれっぽい動きにはなった<br><br>自律するにはもっと、地形の把握、敵の偏差などのパラメータを加えないとダメだと思う <a href="https://t.co/2jjTUsJ7Wn">pic.twitter.com/2jjTUsJ7Wn</a></p>&mdash; ReyAD (@ReyADayer) <a href="https://twitter.com/ReyADayer/status/910519733677461504?ref_src=twsrc%5Etfw">2017年9月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Exposed

Jetbrains製のSQLライブラリのExposedを使いました。

https://github.com/JetBrains/Exposed

RPGをつくる上でプレイヤーの情報を保存するにあたり、MySQLを使うので、導入しました。

```kotlin
class PlayerJob(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<PlayerJob>(PlayerJobs)

    var job by PlayerJobs.job
    var level by PlayerJobs.level
    var exp by PlayerJobs.exp
    var playerStatus by PlayerStatus referencedOn PlayerJobs.playerStatus
}
```

当初はJDBCをつかって実装していたのですが、関連付けのあたりが辛くなってきたので、Exposedは非常に便利でした。

## Dagger

DIコンテナを使ってプラグインを書きました。Dagger導入しているところが他にないので、Androidのプロジェクトを参考に以下のように導入しています。

```kotlin
class SamplePlugin: JavaPlugin() {

    lateinit var component: PluginComponent

    override fun onEnable() {
        component = DaggerPluginComponent.builder().application(this).build()
    }
}
```

```kotlin
@Component(modules = [PluginModule::class])
interface PluginComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: JavaPlugin): Builder

        fun build(): PluginComponent
    }

    fun inject(plugin: SamplePlugin)
}
```

いまは試験的に導入しているのですが、下記のようなクラスはコンポーネントに含める事ができると思います。

* Retrofitの通信周り
* ExposedをつかってSQL問い合わせ
* disposableなどのRxJavaのクラス



# 建築について

RPGのワールドを作るためにマインクラフトで建築物を作っていきます。

![2017-10-08_21.54.53.png](https://qiita-image-store.s3.amazonaws.com/0/152986/541b905a-57bd-24a4-915c-9ce007d83a9e.png)

ブロックで街や地形を作り、そこにNPCやMOBを配置していきます。

![2017-10-28_16.17.12.png](https://qiita-image-store.s3.amazonaws.com/0/152986/3f14a61c-0ece-61bc-7d89-e1fc1e7d6360.png)

## World Edit

https://dev.bukkit.org/projects/worldedit

![sW4qN.png](https://qiita-image-store.s3.amazonaws.com/0/152986/c8a8d19e-f4c7-4b88-059b-abe709fb66d7.png)


ブロックのコピーペーストができるサーバーMODです。
これを使うことによって建築のスピードが大幅に上がります。

できること
* コピーペースト
* 立体の生成
* 繰り返しペースト

などです。

## Voxel Sniper

https://dev.bukkit.org/projects/voxelsniper

ほぼ全て、WorldEditで完結しますが、自然な造形を行うときはVoxelSniperが便利です

![use-minecraft-world-editing-software-voxelsniper.w1456.jpg](https://qiita-image-store.s3.amazonaws.com/0/152986/9869e8f7-3ec4-b683-a251-59f84bd75609.jpeg)

ブロックを盛り上げたり、削ったりすることができるので、
山や川、湖など地形を造形するのに便利です。


## Discordで通知

![スクリーンショット 2017-12-24 23.50.18.png](https://qiita-image-store.s3.amazonaws.com/0/152986/8dd7580d-ee24-2eba-51c6-3aad9fa5bbd6.png)

サーバー内で誰が作業をしているのか、どのようなコマンドを実行したのかをDiscordで表示するようにしました。
これによって次のようなメリットが有りました

* メンバーのログイン率、何をしているかがある程度分かる
* WorldEditのコマンドなどが間接的に学べる
  * //replace stone 60%181:8,20%159:1,20%159:14 等
  * WorldEditの使い方を教えるときにも便利

一応公開しています
https://github.com/AtlantisMinecraft/DiscordBot

# インフラ

完成していないので、インフラ周りはまだ未定です。
このあたりのノウハウがまだないので、これから勉強していく予定です。

今のところAWSやConohaなどを使っています。

# まとめ

単純にゲームを作るとなるとプログラミングの知識だけが必要という単純なものではなく

* チームで進めるにあたり、情報共有しやすい環境
* 技術的負債を残さないような言語選定、ライブラリ選定
* 単純作業の効率化

これらがすごく重要なんだなと思いました。
またデータベースのことも考えながら負荷も意識して、ゲームのエフェクトやモブを作るという
一人でいろんなことを考えながら開発するってのも面白かったです。

まだ完成は遠いですが、頑張っていきたいと思います。

# 最後に

人員を募集していますので、興味がある方は下記の応募フォームから応募おねがいします＞＜

http://atlantis-mc.net/contact/staff