MultiMCをFreeBSDに移植しました

平成30年6月6日 FreeBSD ports に受け入れてもらえました!

ゲームの中には珍しく、マインクラフトが少数派OSに優しいと言えます。長年ランチャーもゲームそのものもSolarisでも動かし続けてきたのですが、非Javaの公式ランチャーが出た今は対策を考えないといけなくなりました。従来のJavaランチャーがまだ使えると雖も設定が面倒臭いし、いつまで使えるか分からないし、特に長い目で見れば非公式ランチャーにした方が楽でしょう。最近デスクトップとして使っているFreeBSDのportsを覗いてみると公式ランチャーはやっぱり孤児状態のようです。

幸いに、MultiMCというQtベースの非公式ランチャーがあり、その名の通り複数のインスタンスを管理しやすくするだけでなく、拡張の管理もログ閲覧も清潔なインタフェースで提供してくれます。少数派OSに少数派ランチャーというかなりマイナー志向の私の勝手ですが、無事使えるのかな?

ライブラリの自動ダウンロードを無効化

そのままコンパイルしたら一応動いてくれますが、実際に使える状態になりません。インスタンスを起動してみると、Linux用ライブラリを参照しようとして転がってしまいます。このライブラリはマインクラフト用語でいうnativesの一つでず。マインクラフトランチャーは(多分、パッケージマネジャーのないMacやWindowsユーザの便宜を図るため)Mojangから自動的にゲーム要素をダウンロードする仕組みになっています。この作業にはゲームそのもののjarだけでなく、nativesも含まれるのでFreeBSDのような予期しなかったプラットフォーム上で注意が必要です。実は、nativesの中にはパッケージとして導入できるlwjglしか必須ではないのでnativesの自動ダウンロードを無効化するだけで済む筈です。でもどうやってLinux用ライブラリがダウンロードされてしまうのか?ソースを見てみましょう。

#ifdef Q_OS_WIN32
#define currentSystem Os_Windows
#else
#ifdef Q_OS_MAC
#define currentSystem Os_OSX
#else
#define currentSystem Os_Linux
#endif

以上の定義はnativesの自動ダウンロードで使われます。Q_OS_*はQtによる定義で、勿論Q_OS_FREEBSDなども使用可能ですが、ここでWindowsかmacOSかLinuxしか想定されていません。それだけでなく、予期しなかったプラットフォームを全てLinuxとして扱うため、Linux用ライブラリを使おうとしてしまったのです。Os_*定義はプラットフォームごとのnativesを記述するjsonファイルの参照に使われ、ここのnativesをダウンロードする必要のない場合はOs_FreeBSDを定義すればjsonファイルの内容と一致しなくなり、何もダウンロードされずに解決。

唯一のnativeであるlwjglが見つかるように、natives_dirをシステムパスに変えないといけません。

 QString MinecraftInstance::getNativePath() const
 {
+#if defined(Q_OS_FREEBSD)
+       QDir natives_dir("/usr/local/lib/lwjgl2.9.3/");
+#else
        QDir natives_dir(FS::PathCombine(instanceRoot(), "natives/"));
+#endif
        return natives_dir.absolutePath();
 }

システム情報の読み取り

次にメモリ容量の照会が問題です。Linux前提のコードは/proc/meminfoからメモリ容量を読み込もうとしますのでFreeBSDでは0が返されて、GUIでXmXを設定するスピンボタンが非アクティブになってしまいます。メモリの最大限を上げられないとゲームが実行できないとほぼ変わりません。XmX設定が使えない

代わりにsysctlを参照する関数を書くことで直せます。PrintInstanceInfoなどゲーム実行と直接関係のないところでも似た問題がありますのでそこも取り敢えず直しておきました。

#elif defined Q_OS_FREEBSD
char buff[512];
FILE *fp = popen("sysctl hw.physmem", "r");
if (fp != NULL)
{
        while(fgets(buff, 512, fp) != NULL)
        {
                std::string str(buff);
                uint64_t mem = std::stoull(str.substr(12, std::string::npos));
                return mem * 1024ull;
        }
}
#endif

最後に残っているのは少々の#ifdef Q_OS_LINUX#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)にするような簡単な作業だけです。

portとして片付ける

MultiMCの開発者は一般的なUnix系システムに相応しくないバンドル式が好んでいるらしいが、lin-systemというインストール方式も用意してくれています。これで随分簡単なMakefileでパッケージ化できます。詳しくはFreshPortsへどうぞ。バイナリパッケージをそのままインストールしたい方はうちの野良リポジトリを是非使って下さい。

平成30年6月25日 最終更新