Synamon’s Engineer blog

Synamonでは、VR空間に複数人が同時に接続可能で、多彩な標準機能を搭載している『NEUTRANS』という独自のVRシステムを開発しています。ビジネスなどの現場でも使いやすいよう、独自の機能や技術を日々追究しています。このブログでは、『NEUTRANS』開発の裏側にあるVR技術と、それを支えるUnityやC#といった技術の話を書いていきます。

PUN Classic → PUN 2アップデート手順覚書

こんにちは。株式会社Synamonのエンジニアの岡村(@Sokuhatiku)です。

今年の1月頃に、Gotanda.unity#10 というイベントがあったのですが、そちらに初登壇LT枠で登壇させて頂き、PUN2をお勧めして参りました。

最近、ようやく弊社内でとあるプロジェクトのPUN(PUN Classic)→ PUN2へのアップデートを決行しました。今回はその際の手順や詰まったポイントを覚書しておきます。

移行のメリット

以下のLT資料をご覧ください。 learning.unity3d.jp

資料の要点は、

  • プロジェクトがフォルダ構造、名前空間、アセンブリ的に綺麗になる。
  • APIが洗練される。

です。

(注意)移行するかどうかの判断

既存のプロジェクトをPUN2にアップデートする利点は、現時点では上記のみです。新しい機能が増えたり、性能が大きく向上することはありません。PUN(PUN Classic)のサポートは今後も継続して行われるので*1、すぐに使えなくなるという事もありません。プロジェクトによってはアップデートコストの方が高くついてしまうため、アップデートを行うかどうかは慎重に判断してください。

(新規プロジェクトを立ち上げるのであればPUN2にした方がよいと思います。)

今回作業したプロジェクトは、長期の運用を前提としていたため、アップデートに踏み切りました。

移行に適している環境

PUN→PUN2では名前空間の変更、コールバックの変更など、様々な破壊的変更が含まれています。既存のソースのPUNに対する依存は出来るだけ少ないほうが良いでしょう。

  • PUNに対する直接の依存を避けている環境
  • コード量が少ない環境

逆に、

  • PUNをソースコード中のあちこちで直接触っている環境
  • 特に、Photon.PunBehaviourを使い、PunBehaviourが提供するコールバックも利用している環境

は辛いです。PUNへの参照が増えるほどソースコードの修正が辛くなるので覚悟しましょう。

弊社では

弊社でPhotonを使っているプロダクトは、ネットワーク接続時以外のほぼ全てのAPIを一段階ラップして使用していました。

これは過去に他のネットワークエンジンへの置き換えを検討していた為であるのですが、今回それのお陰でPUN→PUN2の移行も楽になり、思いがけぬ副産物でした。


それでは、以下より実際の作業の流れを追って説明していきます。

作業前には必ずgitにコミット等、バックアップを取ってください。

作業環境

  • Unity 2018.3.11f1
  • PUN 1.95 → 2.9
  • PUN Voice 1.18.1 → 2.5.1

※ 全て2019年4月8日時点の最新版。

ステップ

  • PUNの削除
  • PUN2のインポート
  • プロジェクトの修正

(注意)PUNのアセットを編集して使っている場合

以降の作業に入る前に、編集して使っているアセットを洗い出すことをお勧めします。大事なアセットがある場合は、事前にPhotonとは関係のない場所に退避、もしくは編集した項目をどこかに控えておきましょう。

編集されがちなアセット(独断)

  • Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset
    • appID等、サーバーへの接続設定
  • Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs
    • 独自型をPhotonで送受信する為のシリアライズ、デシリアライズ処理
  • Assets/Photon Unity Networking/Demos/*
    • PUNのサンプルアセット
  • Assets/PUNVoice/DemoVoice/*
    • PUN Voiceのサンプルアセット
  • Assets/Plugins/PhotonVoiceApi/Platforms/Unity/MicWrapper.cs
    • Microphoneクラスの競合回避

また、PUN2のインポート時に、退避したはずのアセットが更新されてしまう事があります。PUN2のアセットは全てAssets/Photon以下にインストールされます。インポート画面上でそれ以外の場所のファイルを更新しようとしているのに気づいたら、ファイルの更新チェックを外して下さい。

f:id:Sokuhatiku:20190410163239p:plain
Photonフォルダの外にあるファイルは全てチェックを外す
ただし、この場合、該当アセットのAPI変更に対する対応は自力で行う必要があります。

PUNの削除

Assets直下で削除すべきフォルダは以下の3つです。

  • Assets/Photon Unity Networking
  • Assets/PhotonChatApi
  • Assets/PUNVoice

Pluginsフォルダ内のアセットの削除

PUN Classic及び、PUN VoiceはAssets/Pluginsフォルダを使用しています。昔はライブラリファイルをこのフォルダ以下に置く必要があったのですが、現在のUnityのバージョンでは不要となっています。PUN2では一切Pluginsフォルダを使用しませんので、中に入っているPUNのアセットを全て削除してしまいましょう。

Pulginsフォルダに含まれているdllファイルは、Unityに読み込まれている間は削除できません。UnityEditorを一旦終了してから作業しましょう。

Pluginsフォルダ内における、PUN及びPUN Voiceが追加するファイルは以下の通りです。

(*が付いているものはPUNが追加したファイル。それ以外はPUN Voice。)

Plugins
│  opus-COPYING
│  *Photon3Unity3D.dll
│  *Photon3Unity3D.xml
│  *release_history.txt
│  
├─Android
│  │  
│  └─libs
│      │  audioinaec.aar
│      │  
│      ├─arm64-v8a
│      │      libopus_egpv.so
│      │      libwebrtc-audio.so
│      │      
│      ├─armeabi-v7a
│      │      libopus_egpv.so
│      │      
│      └─x86
│              libopus_egpv.so
│              
├─AudioIn.bundle
│  │  
│  └─Contents
│      │  Info.plist
│      │  
│      ├─MacOS
│      │      AudioIn
│      │      
│      └─_CodeSignature
│              CodeResources
│              
├─iOS
│  │  libopus_egpv.a
│  │  
│  └─Photon
│          AudioIn.h
│          AudioIn.mm
│          ForceToSpeaker.h
│          ForceToSpeaker.m
│          iOSStub.c
│          
├─libspeexdsp.bundle
│  │  build.txt
│  │  
│  └─Contents
│      │  Info.plist
│      │  
│      └─MacOS
│              libspeexdsp
│              
├─Metro
│      *Photon3Unity3D.dll
│      *Photon3Unity3D.pri
│      
├─opus_egpv.bundle
│  │  
│  └─Contents
│      │  Info.plist
│      │  
│      └─MacOS
│              opus_egpv
│              
├─PhotonLoadbalancingApi
│      Extensions.cs
│      FriendInfo.cs
│      LoadBalancingClient.cs
│      LoadBalancingPeer.cs
│      PhotonPing.cs
│      Player.cs
│      Room.cs
│      RoomInfo.cs
│      WebRpc.cs
│      
├─PhotonVoiceApi
│  │  LoadBalancingFrontend.cs
│  │  
│  ├─Core
│  │  │  AudioUtil.cs
│  │  │  ObjectPool.cs
│  │  │  OpusCodec.cs
│  │  │  SpeexProcessor.cs
│  │  │  Voice.cs
│  │  │  VoiceAudio.cs
│  │  │  VoiceClient.cs
│  │  │  VoiceCodec.cs
│  │  │  VoiceFramed.cs
│  │  │  VoiceInfo.cs
│  │  │  VoiceSourceAdapter.cs
│  │  │  
│  │  └─POpusCodec
│  │      │  OpusDecoder.cs
│  │      │  OpusEncoder.cs
│  │      │  OpusException.cs
│  │      │  OpusWrapper.cs
│  │      │  
│  │      └─Enums
│  │              Bandwidth.cs
│  │              Channels.cs
│  │              Complexity.cs
│  │              Delay.cs
│  │              ForceChannels.cs
│  │              OpusApplicationType.cs
│  │              OpusCtlGetRequest.cs
│  │              OpusCtlSetRequest.cs
│  │              OpusStatusCode.cs
│  │              SamplingRate.cs
│  │              SignalHint.cs
│  │              
│  └─Platforms
│      │  
│      └─Unity
│              AndroidAudioInAEC.cs
│              AppleAudioInPusher.cs
│              AppleAudioInReader.cs
│              AudioClipWrapper.cs
│              AudioInEnumerator.cs
│              AudioOutCapture.cs
│              AudioStreamPlayer.cs
│              IOSAudioForceToSpeaker.cs
│              MicWrapper.cs
│              SpeexDSP.cs
│              WindowsAudioIn.cs
│              
├─WebSocket
│      *websocket-sharp.dll
│      *websocket-sharp.README
│      *WebSocket.cs
│      *WebSocket.jslib
│      
├─WSA
│  │  
│  ├─ARM
│  │      opus_egpv.dll
│  │      
│  ├─x64
│  │      opus_egpv.dll
│  │      
│  └─x86
│          opus_egpv.dll
│          
├─x86
│      AudioIn.dll
│      libopus_egpv.so
│      opus_egpv.dll
│      
└─x86_64
        AudioIn.dll
        libopus_egpv.so
        libspeexdsp.dll
        opus_egpv.dll
        

PUN2のインポート

削除が終わったら、UnityEditorを立ち上げ、PUN2をインポートします。

Photonのスクリプトが全て無くなった為、コンパイルエラーが多数出ているかと思いますが、いったん無視します。AssetStoreからPUN2及びPhoton Voice2のパッケージをダウンロード、インポートしましょう。

プロジェクトの修正

コンパイルエラーの修正及びAPI変更への対応を行います。 修正内容は多岐に渡りますので、基本的な修正内容は公式の移行ガイドを参照してください。ここでは、移行作業で特に引っかかった箇所を紹介します。

PhotonNetwork.ConnectUsingSettings()が引数を取らなくなった

この関数はPhotonServerSettingsで設定された内容を利用してPhotonへの接続を行うものです。PUNでは第一引数でGameVersionを指定する必要があるのですが、PUN2では引数を受け取らないよう変更されました。GameVersionの指定もPhotonServerSettings上で行うよう変更されています。

ちなみに、PhotonNetwork.GameVersionというプロパティがあり、サーバー接続時のGameVersionにはこの値が使われるのですが、ConnectUsingSettings()関数の実行時、PhotonServerSettings内の値で上書きされてしまうことに注意して下さい。ここを間違えると、別のバージョンに設定したつもりでも同じ部屋に繋がるようになってしまいます。簡単な対策としては、接続前にPhotonNetwork.PhotonServerSettings.AppSettings.AppVersionを書き換えるようにすると良いようです。

各種拡張メソッドがグローバル名前空間から消えた

PUNは拡張メソッドをいくつか提供しています。それらの関数は名前空間で区切られておらず、PUNに依存していないはずのコードが知らず知らずのうちに依存していた……!という事態が起こりやすくなっていました。PUN2では、これらはPhoton.Pun及びPhoton.Realtime名前空間内に整理され、移動しました。依存していたコードはエラーになってしまいます。

Photon.Pun名前空間に移動した拡張メソッド

  • ParameterInfo[] GetCachedParemeters(this MethodInfo mo)
  • PhotonView[] GetPhotonViewsInChildren(this UnityEngine.GameObject go)
  • PhotonView GetPhotonView(this UnityEngine.GameObject go)
  • bool AlmostEquals(this Vector3 target, Vector3 second, float sqrMagnitudePrecision)
  • bool AlmostEquals(this Vector2 target, Vector2 second, float sqrMagnitudePrecision)
  • bool AlmostEquals(this Quaternion target, Quaternion second, float maxAngle)
  • bool AlmostEquals(this float target, float second, float floatDiff)

Photon.Realtime名前空間に移動した拡張メソッド

  • void Merge(this IDictionary target, IDictionary addHash)
  • void MergeStringKeys(this IDictionary target, IDictionary addHash)
  • string ToStringFull(this IDictionary origin)
  • string ToStringFull(this object[] data)
  • Hashtable StripToStringKeys(this IDictionary original)
  • void StripKeysWithNullValues(this IDictionary original)
  • bool Contains(this int[] target, int nr)

廃止された拡張メソッド

  • bool GetActive(this GameObject target)

元からPhotonへの参照を持っているべき箇所であれば、名前空間とアセンブリ参照を足してやることで復活させる事が出来ます。そうでない場合は自分たちの名前空間内に同じメソッドを定義してやることで修正すると良いかと思います。

以上

PUN→PUN2のアップデート手順の覚え書きでした。今回アップデートしたプロジェクトは元々PUNへの依存が少なかった為比較的楽に移行出来ました。他のプロジェクトも同じように移行できるか分かりませんが、少しでも参考になれば幸いです。