【问题标题】:Cloud load failed with error code 7 using Unity GoolePlayGames plugin使用 Unity GoolePlayGames 插件的云加载失败,错误代码 7
【发布时间】:2014-12-09 07:19:47
【问题描述】:

我在设备上调试期间收到以下日志

错误:

*** [Play Games Plugin DLL]  ERROR: Cloud load failed with status code 7

基本上OnStateLoaded() 回调函数总是返回布尔值success = false,我不知道原因。

插件调试日志中提到的只是“云加载失败,状态码为 7”。

【问题讨论】:

    标签: unity3d google-play-services google-play-games


    【解决方案1】:

    根据android doc,7 是一个通用的“开发者错误”,见https://developer.android.com/reference/com/google/android/gms/appstate/AppStateStatusCodes.html#STATUS_DEVELOPER_ERROR

    我尝试了一个快速示例,一切正常。这是我的步骤:

    1. 在游戏控制台中创建了一个新游戏 (https://play.google.com/apps/publish)
    2. 确保已设置保存的游戏 开启
    3. 链接了一个记住应用程序 ID 的 Android 应用程序 (标题后的数字)和包裹ID
    4. 在 Unity 中创建了一个新项目
    5. 添加了玩游戏插件(资产/导入包.../自定义 包)
    6. 设置应用程序 ID(Google Play 游戏/Android 设置...)
    7. 将平台切换到 Android(文件/构建设置...)
    8. 设置播放器设置(包标识符和密钥库信息)
    9. 向相机添加了新的脚本组件
    10. 保存所有内容并点击构建并运行。

      以下是内容:

      using UnityEngine;
      using System.Collections;
      using GooglePlayGames;
      using GooglePlayGames.BasicApi;
      using System;
      
      public class SaveSample : MonoBehaviour {
      
      System.Action<bool> mAuthCallback;
      GameData slot0;
      
      
      void Start () {
          slot0 = new GameData(0,"waiting for login....");
          mAuthCallback = (bool success) => { 
              if (success) {
                  Debug.Log("Authentication was successful!");
                  slot0.Data  =" loading....";
                  slot0.LoadState();
              }
              else {
                  Debug.LogWarning("Authentication failed!");
              }
           };
      
           // make Play Games the default social implementation
           PlayGamesPlatform.Activate();
      
           // enable debug logs 
           PlayGamesPlatform.DebugLogEnabled = true;
      
           //Login explicitly for this sample, usually this would be silent
           PlayGamesPlatform.Instance.Authenticate(mAuthCallback, false);         
      }
      
      protected void OnGUI() {
      
          Screen.fullScreen = true;
          int buttonHeight = Screen.height / 20;
          int buttonWidth = Screen.width / 5;  
          GUI.skin.label.fontSize = 60;
          GUI.skin.button.fontSize = 60;
      
          Rect statusRect = new Rect(10,20,Screen.width,100);
          Rect dataRect  = new Rect( 10, 150, Screen.width,100);
          Rect b1Rect = new Rect(10, 400, buttonWidth, buttonHeight);
          Rect b2Rect = new Rect(b1Rect.x + 20 + buttonWidth,
                                 b1Rect.y, buttonWidth, buttonHeight);
      
          if(!Social.localUser.authenticated) {
              if(GUI.Button(b1Rect, "Signin")) {
                  Social.localUser.Authenticate(mAuthCallback);
              }
          }
          else {
              // logged in, so show the load button and the contents of the saved data.
              if(GUI.Button(b1Rect, "Load")) {
                  slot0.LoadState();
              }
              GUI.Label(dataRect, slot0.Data);
          }
      
          if(GUI.Button(b2Rect, "Save")) {
              // just save a string, incrementing the number on the end.
              int idx = slot0.Data.IndexOf("_");
              if (idx > 0) {
                  int val = Convert.ToInt32(slot0.Data.Substring(idx+1));
                  val++;
                  slot0.Data = "Save_" + val;
              }
              else {
                  slot0.Data = "Save_0";
              }
              slot0.SaveState();
          }
      
          GUI.Label(statusRect, slot0.State);
      }
      
      // Class to handle save/load callbacks.
      public class GameData : OnStateLoadedListener {
      
          int slot;
          string data;
          string state;
      
          public GameData(int slot, string data) {
              this.slot = slot;
              this.data = data;
              this.state = "Initialized, modified";
      
          }
      
          public void LoadState() {
              this.state += ", loading";
              ((PlayGamesPlatform)Social.Active).LoadState(0, this);
          }
      
          public void SaveState() {
              byte[] bytes = new byte[data.Length * sizeof(char)];
              System.Buffer.BlockCopy(data.ToCharArray(), 0, bytes, 0, bytes.Length);
              this.state += ", saving";
              ((PlayGamesPlatform) Social.Active).UpdateState(slot, bytes, this);
              }
      
          public void OnStateLoaded(bool success, int slot, byte[] data) {
              if (success) {
                  Debug.Log ("Save game slot : " + slot + " loaded: " + data);
                  if (data != null) {
                      char[] chars = new char[data.Length / sizeof(char)];
                      System.Buffer.BlockCopy(data, 0, chars, 0, data.Length);
                      this.data = new string(chars);
                          this.state = "loaded";
                  } else {
                          Debug.Log ("Saved data is null");
                          this.data = "";
                          this.state = "loaded, but empty";
                  }
              } else {
                  // handle failure
                  Debug.LogWarning ("Save game slot : " + slot + " failed!: ");
                  this.data = "";
                  this.state = "loading failed!";
              }
          }
      
          public byte[] OnStateConflict(int slot, byte[] local, byte[] server) {
              // resolve conflict and return a byte[] representing the
              // resolved state.
              Debug.LogWarning("Conflict in saved data!");
      
              state = "conflicted";
              // merge or resolve using app specific logic, here
              byte[] resolved =  local.Length > server.Length ? local : server;
              char[] chars = new char[resolved.Length / sizeof(char)];
              System.Buffer.BlockCopy(resolved, 0, chars, 0, resolved.Length);
              this.data = new string(chars);
      
              return resolved;
           }
      
           public void OnStateSaved(bool success, int slot) {
               Debug.Log ("Save game slot : " + slot + " success: " + success);
               state = "saved";
           }
      
           public string Data {
               get {
                  return data;
               }
      
               set {
                  data = value;
                  state += ", modified";
               }
      
           }
      
           public int Slot {
               get {
                  return slot;
               }
      
           }
      
           public string State {
              get {
                  return state;
              }
           }
      }
      

      }

    【讨论】:

    • 文档中给出的常量值是否等同于状态码?没想到!
    • 云保存似乎对我有用。尽管许可证检查失败,云是否可以保存工作?
    • 也可能是一般的“开发者错误”,见developer.android.com/reference/com/google/android/gms/appstate/…
    • 有点混乱。如果我什至不确定原因,我该如何调试?
    • 首先非常感谢您为我进行了测试。我今天在我的项目中尝试了你的代码,猜猜发生了什么,和我的代码完全一样。保存工作正常,但加载失败!这太奇怪了,我到底做错了什么??
    【解决方案2】:

    错误代码 7 是因为 Cloud Save API 已被弃用,目前只有使用该 API 的现有游戏才能访问。 Unity 插件版本 0.9.11 已更新为使用 SavedGames API。

    我尝试了一个快速示例,一切正常。这是我的步骤:

    1. 在游戏控制台中创建了一个新游戏 (https://play.google.com/apps/publish)
    2. 确保已保存游戏设置为开启
    3. 链接了一个记住应用程序 ID 的 Android 应用程序 (标题后面的数字)和包 ID 创建了一个新的 Unity 中的项目
    4. 添加了玩游戏插件(资产/导入 包.../自定义包)
    5. 设置应用程序 ID(Google Play 游戏/Android 设置...)
    6. 将平台切换到 Android(文件/构建 设置...)
    7. 设置播放器设置(包标识符和 密钥库信息)
    8. 为相机添加了一个新的脚本组件 已保存 一切,然后点击构建并运行。

    这是我的脚本: 使用 UnityEngine; 使用 System.Collections; 使用 GooglePlayGames; 使用 GooglePlayGames.BasicApi; 使用系统; 使用 GooglePlayGames.BasicApi.SavedGame;

    public class SaveSample : MonoBehaviour {
    
    
        System.Action<bool> mAuthCallback;
    
        GameData slot0;
    
        bool mSaving;
        private Texture2D mScreenImage;
    
        // Use this for initialization
        void Start () {
    
            slot0 = new GameData("New game");
            mAuthCallback = (bool success) => {
    
                if (success) {
                    Debug.Log("Authentication was successful!");
                    slot0.State = "Click load or save";
                }
                else {
                    Debug.LogWarning("Authentication failed!");
                }
    
          };
    
    
            PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
                .EnableSavedGames()
                .Build();
            PlayGamesPlatform.InitializeInstance(config);
    
            // Activate the Play Games platform. This will make it the default
            // implementation of Social.Active
            PlayGamesPlatform.Activate();
    
            // enable debug logs (note: we do this because this is a sample; on your production
            // app, you probably don't want this turned on by default, as it will fill the user's
            // logs with debug info).
            PlayGamesPlatform.DebugLogEnabled = true;
    
            //Login explicitly for this sample, usually this would be silent
            PlayGamesPlatform.Instance.Authenticate(mAuthCallback, false);
    
    
        }
    
        public void CaptureScreenshot() {
            mScreenImage = new Texture2D(Screen.width, Screen.height);
            mScreenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
            mScreenImage.Apply();
        }
    
        protected virtual void OnGUI() {
    
            Screen.fullScreen = true;
    
            int buttonHeight = Screen.height / 20;
            int buttonWidth = Screen.width / 5;
    
            GUI.skin.label.fontSize = 60;
            GUI.skin.button.fontSize = 60;
    
    
            Rect statusRect = new Rect(10,20,Screen.width,200);
            Rect dataRect  = new Rect( 10, 250, Screen.width,100);
    
            Rect b1Rect = new Rect(10, 800, buttonWidth, buttonHeight);
            Rect b2Rect = new Rect(b1Rect.x + 20 + buttonWidth, b1Rect.y, buttonWidth, buttonHeight);
    
            if(!Social.localUser.authenticated) {
                if(GUI.Button(b1Rect, "Signin")) {
                    Social.localUser.Authenticate(mAuthCallback);
                }
            }
            else {
                if(GUI.Button(b1Rect, "Load")) {
                    mSaving = false;
                    ((PlayGamesPlatform)Social.Active).SavedGame.ShowSelectSavedGameUI("Select game to load",
                                                                                       4,false,false,SavedGameSelected);
                }
    
                GUI.Label(dataRect, slot0.Data);
            }
    
            if(GUI.Button(b2Rect, "Save")) {
                int idx = slot0.Data.IndexOf("_");
                if (idx > 0) {
                    int val = Convert.ToInt32(slot0.Data.Substring(idx+1));
                    val++;
                    slot0.Data = "Save_" + val;
                }
                else {
                    slot0.Data = "Save_0";
                }
                mSaving = true;
                CaptureScreenshot();
                ((PlayGamesPlatform)Social.Active).SavedGame.ShowSelectSavedGameUI("Save game progress",
                                                                                   4,true,true,SavedGameSelected);
            }
    
            GUI.Label(statusRect, slot0.State);
    
        }
    
    
        public void SavedGameSelected(SelectUIStatus status, ISavedGameMetadata game) {
    
            if (status == SelectUIStatus.SavedGameSelected) {
                string filename = game.Filename;
                Debug.Log("opening saved game:  " + game);
                if(mSaving && (filename == null || filename.Length == 0)) {
                    filename = "save" + DateTime.Now.ToBinary();
                }
                if (mSaving) {
                    slot0.State = "Saving to " + filename;
                }
                else {
                    slot0.State = "Loading from " + filename;
                }
                //open the data.
                ((PlayGamesPlatform)Social.Active).SavedGame.OpenWithAutomaticConflictResolution(filename,
                                                                                                 DataSource.ReadCacheOrNetwork,
                                                                                                 ConflictResolutionStrategy.UseLongestPlaytime,
                                                                                                 SavedGameOpened);
            } else {
                Debug.LogWarning("Error selecting save game: " + status);
            }
    
        }
    
        public void SavedGameOpened(SavedGameRequestStatus status, ISavedGameMetadata game) {
            if(status == SavedGameRequestStatus.Success) {
                if( mSaving) {
                    slot0.State = "Opened, now writing";
                    byte[] pngData = (mScreenImage!=null) ?mScreenImage.EncodeToPNG():null;
                    Debug.Log("Saving to " + game);
                    byte[] data = slot0.ToBytes();
                    TimeSpan playedTime = slot0.TotalPlayingTime;
                    SavedGameMetadataUpdate.Builder builder =  new 
                        SavedGameMetadataUpdate.Builder()
                            .WithUpdatedPlayedTime(playedTime)
                            .WithUpdatedDescription("Saved Game at " + DateTime.Now);
    
                    if (pngData != null) {
                        Debug.Log("Save image of len " + pngData.Length);
                        builder = builder.WithUpdatedPngCoverImage(pngData);
                    }
                    else {
                        Debug.Log ("No image avail");
                    }
                    SavedGameMetadataUpdate updatedMetadata  = builder.Build();
                    ((PlayGamesPlatform)Social.Active).SavedGame.CommitUpdate(game,updatedMetadata,data,SavedGameWritten);
                } else {
                    slot0.State = "Opened, reading...";
                    ((PlayGamesPlatform)Social.Active).SavedGame.ReadBinaryData(game,SavedGameLoaded);
                }
            } else {
                Debug.LogWarning("Error opening game: " + status);
            }
        }
    
        public void SavedGameLoaded(SavedGameRequestStatus status, byte[] data) {
            if (status == SavedGameRequestStatus.Success) {
                Debug.Log("SaveGameLoaded, success=" + status);
                slot0 = GameData.FromBytes(data);
            } else {
                Debug.LogWarning("Error reading game: " + status);
            }
        }
    
    
        public void SavedGameWritten(SavedGameRequestStatus status, ISavedGameMetadata game) {
            if(status == SavedGameRequestStatus.Success) {
                Debug.Log ("Game " + game.Description + " written");
                slot0.State = "Saved!";
            } else {
                Debug.LogWarning("Error saving game: " + status);
            }
        }
    
    
        public class GameData  {
    
            private TimeSpan mPlayingTime;
            private DateTime mLoadedTime;
            string mData;
            string mState;
    
            static readonly string HEADER = "GDv1";
    
            public GameData(string data) {
    
                mData = data;
                mState = "Initialized, modified";
                mPlayingTime = new TimeSpan();
                mLoadedTime = DateTime.Now;
    
            }
    
            public TimeSpan TotalPlayingTime {
                get {
                    TimeSpan delta = DateTime.Now.Subtract(mLoadedTime);
                    return mPlayingTime.Add(delta);
                }
            }
    
            public override string ToString () {
                string s = HEADER + ":" + mData;
                s += ":" + TotalPlayingTime.TotalMilliseconds;
                return s;
            }
    
            public byte[] ToBytes() {
                return System.Text.ASCIIEncoding.Default.GetBytes(ToString());
            }
    
    
            public static GameData FromBytes (byte[] bytes) {
                return FromString(System.Text.ASCIIEncoding.Default.GetString(bytes));
            }
    
            public static GameData FromString (string s) {
                GameData gd = new GameData("initializing from string");
                string[] p = s.Split(new char[] { ':' });
                if (!p[0].StartsWith(HEADER)) {
                    Debug.LogError("Failed to parse game data from: " + s);
                    return gd;
                }
                gd.mData = p[1];
                double val = Double.Parse(p[2]);
                gd.mPlayingTime = TimeSpan.FromMilliseconds(val>0f?val:0f);
    
                gd.mLoadedTime = DateTime.Now;
                gd.mState = "Loaded successfully";
                return gd;
            }
    
            public string Data {
                get {
                    return mData;
                }
    
                set {
                    mData = value;
                    mState += ", modified";
                }
    
            }
    
            public string State {
                get {
                    return mState;
                }
    
                set {
                    mState = value;
                }
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-03
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 1970-01-01
      • 2021-04-28
      相关资源
      最近更新 更多