xluaをwebGLで動かす方法

2021.3.4

公式でサポートされてるはずなんですが、ビルドエラーになったり、実行時エラーになったりと怪しいです

ビルドエラー

: error: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wreserved-user-defined-literal]
snprintf(temp, sizeof(temp), "%"PRIu64, n);
Unity2021.2.12 用demo 导出webgl报错 · Issue #969 · Tencent/xLua
因为要用到webgl的ASTC的图片属性 所以要使用2012.2.12 但是导出webgl失败 报错信息如下 Building Library\Bee\artifacts\WebGL\GameAssembly.\master_WebGL_wasm\u9l0_xlua_webgl.o failed with output...
C++11: Invalid Suffix on Literal Warning/Error
I recently came across this unexpected error when compiling C++ code using Clang:

同梱されているwebGLPluginに問題があります。c++11流儀に合ってないらしいです(c++11としてコンパイルしてる誰だろう?

issueの方で解法ありますが、スペース仕込めばいいです

snprintf(temp, sizeof(temp), "%" PRIu64, n);

実行時エラー(luaの関数をC# callbackに持ってる場合発生

try to dispose a LuaEnv with C# callback!
xLua/Assets/XLua/Doc/Faq_EN.md at master · Tencent/xLua
xLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc. - Tencent/xLua

これ、FAQで書かれてる有名なエラー…ではありません

ソースコード読んで分かりましたが、xluaはLuaEnvをdisposeしたときにデストラクタに依存した処理を書いています

さて、C#でデストラクタが呼ばれるタイミングはファイナライザスレッドに依存してます。さすがにそれではまずいので、

GC.Collect();
GC.WaitForPendingFinalizers();

のように、メインスレッド止めてファイナライザ終わるまで待ってます。

https://forum.unity.com/threads/gc-collect-in-webgl.856849/

ところがwebGLではGCの挙動が異なり、そもそもGC.Collect呼んでも何も起きません。つまりファイナライザ待ってもデストラクタ呼ばれません。(挙動的にはフレームの終わりの方で呼ばれるようです…もしくは次のフレームの最初か?

結果として、LuaEnvに関連したC# callbackの開放ができず上記エラーが発生してます

対策

LuaEnv.Dispose()の前に手動でC# callbackをxlua系から解放します。ソースコードの改造が必要です

List<DelegateBridge> delegate_bridgesDelBuffer = new List<DelegateBridge>();
public void PreDisposeDelegateBridges()
        {
            delegate_bridgesDelBuffer.Clear();

            foreach (var kv in delegate_bridges)
            {
                var b = kv.Value.Target as DelegateBridge;
                if(b != null)
                {
                    delegate_bridgesDelBuffer.Add(b);
                }
            }
            foreach (var d in delegate_bridgesDelBuffer)
            {
                d.Dispose();
            }
        }
public void PreDisposeDelageteBrdiges()
        {
            translator.PreDisposeDelegateBridges();
        }

こんな感じでダサイですが、Dispose前に呼べば正常に動作します。まあでも誰かがissueなりプルリクなりだしてるんじゃないかなぁと思います。