2015年1月29日木曜日

Unity Free版を骨の髄までしゃぶりつくすハック - .NET Socketなんて怖くない!

私は貧乏である。少なくともリッチマンではない。

よってUnity Free版を使っているのだが、Free版でAndroid/iOS向けにコンパイルしようとすると、思わぬ罠が待っていることがある。

それは .NET Socket は、Android/iOS向けにはPro Onlyな機能であることだ。

さらにまずいことに、Unityにおいては、プロジェクトをモバイル向けにコンパイルする際に.NET Socketへの参照を持つdllやコードが「プロジェクト内」に1つでも存在すると、Pro Onlyであるという旨…は特に出ず、コンパイルエラーだとだけ表示する。

これだけであれば、モバイルオンリーで制作中の場合特段の問題にはならない。.NET Socketへの参照を拾わないように、注意深く作っていけば良い。

問題は次のような例にある。


  • モバイルとPC両対応のゲームを1つのPJ内で作っていて、PCで.NET Socketへの参照がある
  • モバイル向けにはPCとは違う画面構成だが、ゲームとして共通であるので1つのPJで作っていて、PJ内のPC向けに.NET Socketへの参照がある
  • モバイルでのネットワークゲームを作っていて(UnityのNetwork ViewはFreeでもモバイル向けにコンパイル可能だ)ネットワークコードの都合上(RPC等を使うと、どうしても1PJにサーバとクライアントの同居状態がほしくなる)でサーバプログラムも同じPJで作っており、サーバプログラム側で、既存プラットフォームとの接続等で.NET Socketへの参照がある
つまり、モバイル版には.NET Socketを注意深く使わないようにしたが、非モバイルを対象に諸般の都合により.NET Socketあるいはそれへの参照を持つライブラリが必要になってしまった場合、である。

このようなとき、Unityはどうするかといえば、私の試した限りでは、モバイル向けのシーンにアタッチされてるスクリプトの一切に.NET Socketへの参照あるいは.NET Socketへの参照を持つライブラリへの参照が含まれていなくても、もっと言えば、PJに.NET Socketへの参照を持つdllが混じった時点で、モバイル向けにコンパイルが不能となった。

つまり、この時点でプロジェクトはお手上げ、大幅な修正をする必要になる。あるいはPro版を購入する必要がある。

…だがちょっと待ってほしい。本当にそうだろうか?本当に大幅な修正がいるのだろうか?

私たちはモバイル向けに.NET Socketを使おうとしてない。だというのに、Pro版が要るのだろうか?

そんなことはない。私は巧妙なハックにより、これを解決する策を見出した。

ただし、これがUnityライセンス契約的に正当かどうかについて、私は保証できない。実際にプロジェクトでこの手法を取る際には注意してほしい。

以下のようにする。

.NET Socketへの参照や.NET Socketへの参照を持つライブラリへの参照をするusingを、次のように囲う。

#if !(UNITY_ANDROID || UNITY_IPHONE)
//usingたち
#endif

同様に、.NET Socketへの参照や、参照をもつライブラリへの参照をするコードの、クラス本体の内部を、丸ごと囲う。

public class NetworkCode : MonoBehaviour {
#if !(UNITY_ANDROID || UNITY_IPHONE)
//コードの本体たち
#endif
}

このようにする。

さらに、その.NET Socket参照をするコードを、参照するコード、つまりかかわりのあるコードの部分を、注意深く同様に囲う。

これをしないと、既存のメソッドコードがないことになるので、まずプロジェクト自体のコンパイルができず、問題となる。

そして、Unity上で実行する際に、上記のコードによってサーバシーンやPC向けシーンが不具合を起こさないように、Build SettingsからSwitch PlatformでAndroid/iOS以外にしておく。

もしモバイル向けシーンをUnity上で実行するなら、逆にSwitch PlatformをAndroid/iOSに設定しておくと良い。

この操作をすることで、.NET Socketへの参照や、その参照を持つライブラリ(dll)を削除できる。もしAndroid向けにビルドする時は、アセットフォルダからこれを一時的にどこかに移動しよう。何度も移動するのは面倒だから、.batなり.shなりを作ると良いかもしれない。

その後、Android/iOS向けにコンパイルすれば、Unityはエラーを出さないはずだ。PC/サーバシーンをコンパイルしたいときは、先ほど一時的に移動したものをアセットフォルダに戻してコンパイルすればいい。

途中から変更したり、何度もするなら面倒かもしれないが、初めからこれを意図して設計したり、バッチやシェルスクリプトを書いたりすれば、そう問題はないはずだ。そもそもAndroid向けにコンパイルなんて1日に100回も200回もやったりはしないはずだ。

以上、Unity Free版を骨の髄までしゃぶりつくすハック、第一弾だった。第二段があるかはわからないが、もしネタが出たら書きたいと思う。