- firebase の unity 向け sdk は ios / android 用で webgl 向けはない
- firebase の js 向け sdk を利用して csharp 側から js を実行するしかない
- 状態の push は csharp から js function を call して firebase に push する
- 状態の subscribe は js から csharp function を call して state を変更する
WebGL: Interacting with browser scripting
Unity(WebGL)でC#の関数からブラウザー側のJavaScript関数を呼び出すまたはその逆(JS⇒C#)に関する知見(プラグイン形式[.jslib])
- 大前提 webgl ビルド後じゃないと js 動かせない
- unity editor にブラウザエミュレートはなく、今んとこ入る予定もなさそう
- ビルド通すために「unity editor platform なら動かさない」分岐が必要
- 開発ビルド > スクリプトのみビルド (patch build) で頑張るのが一番早そう
- 外部依存は webgl build 用の template の index.html で cdn から取るなりする
- jslib から window 参照できるのでそこに入れる感じ
- jspre ファイルなら es6 で書ける
- js => csharp に非同期処理の結果を返すようなケースは SendMessage しないと無理そう
js 側がでかいなら、iOS / Android の SDK で emulator につないで開発 ... とかが必要そう。
↑ 検証したい
基本的な数値型は、変換を必要とせずに、関数パラメーターで JavaScript に渡すことができます。他のデータ型は、emscripten ヒープ内のポインターとして渡されます (実際には JavaScript の大きな配列です)。文字列の場合は、Pointer_stringify ヘルパー関数を使用して JavaScript 文字列に変換できます。文字列値を返すには、メモリを割り当てるために _malloc を呼び出し、JavaScript 文字列を書き込むために stringToUTF8 ヘルパー関数を呼び出す必要があります。文字列が戻り値の場合は、il2cpp ランタイムがメモリ解放の処理をします。プリミティブ型の配列の場合、emscripten はメモリを表すさまざまなサイズの整数、符号なし整数、浮動小数点のヒープに対して、異なる ArrayBufferViews を提供します。 HEAP8、HEAPU8、HEAP16、HEAPU16、HEAP32、HEAPU32、HEAPF32、HEAPF64 などです。 WebGL のテクスチャにアクセスするために、emscripten は GL.textures 配列を提供し Unity から WebGL テクスチャオブジェクトへネイティブのテクスチャ ID をマッピングします。WebGL 関数は、emscripten の WebGL コンテキストGLctx で呼び出すことができます。
- 数値はそのまま引数として渡せる、数値以外は変換をかます必要がある
- csharp => js に文字列を渡すなら js 側で
Pointer_stringify()
で変換 - js => csharp に文字列を渡すなら
_malloc()
で文字列の長さ分メモリバッファを確保してからstringToUTF8()
で変換してバッファを返却 - 非同期で値を返す、みたいなことは仕様上できないっぽいので SendMessage で unity のメソッドを読んで、そこに引数渡すのがいいみたい
ざっと見て Newtonsoft.Json
なんかで Json のやりとりに徹底したほうが楽そう。
<!-- webgl build template index.html -->
<head>
<!-- firebase -->
<script src="https://www.gstatic.com/firebasejs/8.2.10/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.2.10/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.3.0/firebase-database.js"></script>
<script>
// initialize
var firebase = window.firebase;
firebase.initializeApp({
apiKey: 'xxx',
authDomain: 'xxx',
databaseURL: 'xxx',
projectId: 'xxx',
});
// emulator setting
if (window.location.hostname === 'localhost') {
firebase.database().useEmulator('localhost', 9000);
}
</script>
<body>
<canvas id="unity-canvas" style="background: #333"></canvas>
<script>
var unityInstance = null;
createUnityInstance(
document.querySelector("#unity-canvas"),
{
dataUrl: "Build/{{{ DATA_FILENAME }}}",
frameworkUrl: "Build/{{{ FRAMEWORK_FILENAME }}}",
codeUrl: "Build/{{{ CODE_FILENAME }}}",
streamingAssetsUrl: "StreamingAssets",
companyName: "{{{ COMPANY_NAME }}}",
productName: "{{{ PRODUCT_NAME }}}",
productVersion: "{{{ PRODUCT_VERSION }}}",
}
).then(instance => {
unityInstance = instance;
});
</script>
</body>
</head>
// Assets/Plugins/Firebase.jslib
mergeInto(LibraryManager.library, {
fetchState: function () {
firebase.database()
.ref('game-state')
.get()
.then(function (snapshot) {
const json = (function () {
return snapshot.exists()
? JSON.stringify(snapshot.val())
: '';
})();
unityInstance.SendMessage('Firebase', 'SyncState', json);
});
},
// 引数に default 値入れると build コケるので注意
pushState: function (json) {
firebase.database()
.ref('game-state')
.set(JSON.parse(Pointer_stringify(json)));
},
});
using Newtonsoft.Json;
using UnityEngine;
using System.Runtime.InteropServices;
public class Firebase: MonoBehaviour {
[DllImport("__Internal")]
private static extern void fetchState();
[DllImport("__Internal")]
private static extern void pushState(string json);
public void Start() {
if (Application.platform != RuntimePlatform.WebGLPlayer)
{
return;
}
fetchState();
}
// static method だと sendmessage できないので注意
public void SyncState(string json)
{
object state = JsonConvert.DeserializeObject(json);
Debug.Log(JsonConvert.SerializeObject(state));
// あとは csharp 側の変数に代入するなりなんなり
}
}