晦涩的Unity Firebase实时数据库错误:“不支持自定义运行循环”?

时间:2018-07-11 20:57:29

标签: firebase unity3d firebase-realtime-database

我目前正在尝试为Unity建立一个自定义的编辑器工具,该工具利用Firebase实时数据库。该工具将允许某人右键单击检查器中的场景资产,然后选择“锁定”或“解锁”场景。在我们的Firebase数据库中,此锁定由字典表示,每个场景名称作为键,每个值“锁定”或“解锁”。这种功能将在以后扩展,但是现在,我只是在尝试进行设置,以便实际上可以连接并使用Firebase实时数据库。

我查看了Realtime数据库的Firebase Quickstart Unity项目(该功能类似于排行榜),发现它运行良好。我可以用应用数据库的URL替换项目中的数据库URL,当我输入值时,它们就会出现在实时数据库中。

因此,我将自定义编辑器脚本的代码基于快速入门中的代码。实际上,我复制粘贴了大部分内容。我将发布脚本本身,然后描述收到的错误以及给出错误的行:

    using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Firebase;
using Firebase.Unity.Editor;
using Firebase.Database;

[CustomEditor(typeof(SceneAsset))]
[ExecuteInEditMode]
public class SceneLockingEditor : Editor
{
    static string sceneName;
    DependencyStatus dependencyStatus = DependencyStatus.UnavailableOther;

    protected virtual void OnEnable()
    {
        Debug.Log("OnEnable Called");
        sceneName = target.name;

        FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
            dependencyStatus = task.Result;
            if (dependencyStatus == DependencyStatus.Available)
            {
                InitializeFirebase();
            }
            else
            {
                Debug.LogError(
                    "Could not resolve all Firebase dependencies: " + dependencyStatus);
            }
        });
    }

    // Initialize the Firebase database:
    protected virtual void InitializeFirebase()
    {
        Debug.Log("Initializing Firebase");
        FirebaseApp app = FirebaseApp.DefaultInstance;
        app.SetEditorDatabaseUrl(CENSORING MY DATABASE SORRY);
        if (app.Options.DatabaseUrl != null) app.SetEditorDatabaseUrl(app.Options.DatabaseUrl);
    }

    static TransactionResult SceneLockTransaction(MutableData mutableData)
    {
        List<object> sceneLocks = mutableData.Value as List<object>;

        if (sceneLocks == null)
        {
            sceneLocks = new List<object>();
        }

        if(mutableData.ChildrenCount > 0)
        {
            //Look at every child in the scene locks directory.
            foreach (var child in sceneLocks)
            {
                Debug.Log("Checking next child.");

                if (!(child is Dictionary<string, object>))
                    continue;

                //If we find the scene we're looking for...
                Debug.Log("Checking if the scene has the name we want");
                foreach(string key in ((Dictionary<string, object>)child).Keys)
                {
                    Debug.Log("Key: " + key);
                }
                if(((Dictionary<string, object>)child).ContainsKey(sceneName))
                {
                    string childLockStatus = (string)((Dictionary<string, object>)child)["lockStatus"];
                    //If the scene is already locked, just abort.
                    if (childLockStatus == "locked")
                    {
                        Debug.Log("Scene is already locked. Abort.");
                        return TransactionResult.Abort();
                    }
                    else
                    {
                        Debug.Log("Scene existed in the database and was not locked. Locking it.");
                        // If the scene existed in the database but was not locked, we will lock it.
                        ((Dictionary<string, object>)child)[sceneName] = "locked";

                        // You must set the Value to indicate data at that location has changed.
                        mutableData.Value = sceneLocks;
                        return TransactionResult.Success(mutableData);
                    }
                }
            }
        }
        Debug.Log("Scene did not exist in the database. Adding it as locked.");
        // If the scene didn't exist in the database before, we will add it as locked.
        Dictionary<string, object> newSceneLock = new Dictionary<string, object>();
        newSceneLock[sceneName] = "locked";
        sceneLocks.Add(newSceneLock);

        // You must set the Value to indicate data at that location has changed.
        mutableData.Value = sceneLocks;
        return TransactionResult.Success(mutableData);

    }

    static TransactionResult SceneUnlockTransaction(MutableData mutableData)
    {
        List<object> sceneLocks = mutableData.Value as List<object>;

        if (sceneLocks == null)
        {
            sceneLocks = new List<object>();
        }

        if (mutableData.ChildrenCount > 0)
        {
            //Look at every child in the scene locks directory.
            foreach (var child in sceneLocks)
            {
                Debug.Log("Checking next child.");

                if (!(child is Dictionary<string, object>))
                    continue;

                //If we find the scene we're looking for...
                Debug.Log("Checking if the scene has the name we want");
                foreach (string key in ((Dictionary<string, object>)child).Keys)
                {
                    Debug.Log("Key: " + key);
                }
                if (((Dictionary<string, object>)child).ContainsKey(sceneName))
                {
                    string childLockStatus = (string)((Dictionary<string, object>)child)["lockStatus"];
                    //If the scene is already locked, just abort.
                    if (childLockStatus == "unlocked")
                    {
                        Debug.Log("Scene is already unlocked. Abort.");
                        return TransactionResult.Abort();
                    }
                    else
                    {
                        Debug.Log("Scene existed in the database and was locked. Unlocking it.");
                        // If the scene existed in the database but was not locked, we will lock it.
                        ((Dictionary<string, object>)child)[sceneName] = "unlocked";

                        // You must set the Value to indicate data at that location has changed.
                        mutableData.Value = sceneLocks;
                        return TransactionResult.Success(mutableData);
                    }
                }
            }
        }
        Debug.Log("Scene did not exist in the database. Adding it as unlocked.");
        // If the scene didn't exist in the database before, we will add it as locked.
        Dictionary<string, object> newSceneLock = new Dictionary<string, object>();
        newSceneLock[sceneName] = "unlocked";
        sceneLocks.Add(newSceneLock);

        // You must set the Value to indicate data at that location has changed.
        mutableData.Value = sceneLocks;
        return TransactionResult.Success(mutableData);

    }

    static public void AddSceneLock()
    {
        Debug.Log("Attempting to add scene lock to database.");
        DatabaseReference reference = FirebaseDatabase.DefaultInstance.GetReference("SceneLocks");

        Debug.Log("Running Transaction...");
        // Use a transaction to ensure that we do not encounter issues with
        // simultaneous updates that otherwise might create more than MaxScores top scores.
        reference.RunTransaction(SceneLockTransaction)
          .ContinueWith(task => {
              if (task.Exception != null)
              {
                  Debug.Log(task.Exception.ToString());
              }
              else if (task.IsCompleted)
              {
                  Debug.Log("Transaction complete.");
              }
          });
    }

    static public void RemoveSceneLock()
    {
        Debug.Log("Attempting to add scene lock to database.");

        DatabaseReference reference = FirebaseDatabase.DefaultInstance.GetReference("SceneLocks");

        Debug.Log("Running Transaction...");
        // Use a transaction to ensure that we do not encounter issues with
        // simultaneous updates that otherwise might create more than MaxScores top scores.
        reference.RunTransaction(SceneUnlockTransaction)
          .ContinueWith(task => {
              if (task.Exception != null)
              {
                  Debug.Log(task.Exception.ToString());
              }
              else if (task.IsCompleted)
              {
                  Debug.Log("Transaction complete.");
              }
          });
    }

    [MenuItem("CONTEXT/SceneAsset/Lock Scene", false, 0)]
    public static void LockScene()
    {
        Debug.Log("LockScene Called for scene " + sceneName + ".");
        AddSceneLock();
    }

    [MenuItem("CONTEXT/SceneAsset/Unlock Scene", false, 0)]
    public static void UnlockScene()
    {
        Debug.Log("UnlockScene Called for scene " + sceneName + ".");
        RemoveSceneLock();
    }
}

错误总是来自此行:

FirebaseDatabase.DefaultInstance.GetReference("SceneLocks");

任何与“ FirebaseDatabase.DefaultInstance”有关的行都将引发以下两个错误之一

错误1:

InvalidOperationException: SyncContext not initialized.
Firebase.Unity.UnitySynchronizationContext.get_Instance ()
Firebase.Platform.PlatformInformation.get_SynchronizationContext ()
Firebase.FirebaseApp.get_ThreadSynchronizationContext ()
Firebase.Database.DotNet.DotNetPlatform+SynchronizationContextTarget..ctor ()
Firebase.Database.DotNet.DotNetPlatform.NewEventTarget (Firebase.Database.Internal.Core.Context c)
Firebase.Database.Internal.Core.Context.EnsureEventTarget ()
Firebase.Database.Internal.Core.Context.InitServices ()
Firebase.Database.Internal.Core.Context.Freeze ()
Firebase.Database.Internal.Core.RepoManager.CreateLocalRepo (Firebase.Database.Internal.Core.Context ctx, Firebase.Database.Internal.Core.RepoInfo info, Firebase.Database.FirebaseDatabase firebaseDatabase)
Firebase.Database.Internal.Core.RepoManager.CreateRepo (Firebase.Database.Internal.Core.Context ctx, Firebase.Database.Internal.Core.RepoInfo info, Firebase.Database.FirebaseDatabase firebaseDatabase)
Firebase.Database.FirebaseDatabase.EnsureRepo ()
Firebase.Database.FirebaseDatabase.get_RootReference ()
SceneLockingEditor.OnInspectorGUI () (at Assets/Bitloft/SCRIPTS/Editor/SceneLockingEditor.cs:37)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor[] editors, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1242)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

错误2:

Exception: Custom Run loops are not supported!
Firebase.Database.Internal.Core.Context.GetExecutorService ()
Firebase.Database.Internal.Core.Context.GetConnectionContext ()
Firebase.Database.Internal.Core.Context.NewPersistentConnection (Firebase.Database.Internal.Connection.HostInfo info, IDelegate delegate_)
Firebase.Database.Internal.Core.Repo..ctor (Firebase.Database.Internal.Core.RepoInfo repoInfo, Firebase.Database.Internal.Core.Context ctx, Firebase.Database.FirebaseDatabase firebaseDatabase)
Firebase.Database.Internal.Core.RepoManager.CreateLocalRepo (Firebase.Database.Internal.Core.Context ctx, Firebase.Database.Internal.Core.RepoInfo info, Firebase.Database.FirebaseDatabase firebaseDatabase)
Firebase.Database.Internal.Core.RepoManager.CreateRepo (Firebase.Database.Internal.Core.Context ctx, Firebase.Database.Internal.Core.RepoInfo info, Firebase.Database.FirebaseDatabase firebaseDatabase)
Firebase.Database.FirebaseDatabase.EnsureRepo ()
Firebase.Database.FirebaseDatabase.get_RootReference ()
SceneLockingEditor.OnInspectorGUI () (at Assets/Bitloft/SCRIPTS/Editor/SceneLockingEditor.cs:37)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor[] editors, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1242)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

它总是一个错误或另一个错误,我无法确定是什么导致出现一个错误而不是另一个错误。这两个错误都会停止我要对数据库执行的任何操作,这意味着我根本无法与数据库进行交互。

我看了一些快速入门项目,并观看了一些有关人们设置Firebase来处理其项目的视频,但我似乎无法确定在此过程中我搞砸了什么。我已将google-services.json导入unity项目。快速入门项目可以很好地与我的数据库进行交互。只是这个特定的脚本不起作用。我在Google的任何地方都找不到任何提及这两个错误的信息。我什至联系了Firebase官方支持部门,他们无法就错误的含义或可能导致的错误提供任何建议。

我认为一个问题可能出在我的初始化功能上。而不是:

FirebaseApp app = FirebaseApp.DefaultInstance;

我发现也许我应该使用带有自定义名称的FirebaseApp.Create(),但这会导致在同一行上引发相同的错误。我不知如何处理这个问题。我不知道还有其他犯过这些特定错误的人,并且在过去几天中,我已经做了很多尝试,尝试了各种不同的方法来访问数据库。如果有人知道我在这里做错了什么,或者是什么原因导致了这些错误(以及如何解决这些错误),我将真的表示感谢。

1 个答案:

答案 0 :(得分:0)

首先,您应该使用具有唯一名称的FirebaseApp的新实例来初始化firebase。我是这样的:

class Post
 has_many :comments
end

class Comment
 belongs_to :post
end

第二个是与此firebaseApp实例的设置引用(DatabaseReference,StorageReference等),并且仅在FirebaseApp.CheckAndFixDependenciesAsync()之后使用它

总体代码如下:

FirebaseApp firebaseApp = FirebaseApp.Create(
    FirebaseApp.DefaultInstance.Options, 
    "FIREBASE_EDITOR");

我有同样的错误。我花了几个小时解决了这个问题,对我有用