2016-07-13 2 views
0

В моей игре у меня есть игровая валюта, и я хочу сохранить ее ценность в облаке. Я решил использовать Google Saved Games API. Все работает отлично, но когда я сохраняю данные в моментальных снимках, а затем читаю их, когда игра снова запускается, у меня возникают конфликты, даже когда я нахожусь на одном устройстве. Теперь я сохраняю состояние валюты после каждого изменения, поэтому, когда игрок бьет или получает некоторые «монеты». Я думаю, что это может быть очень часто, и службы не могут справиться с этим, потому что, когда я в автономном режиме (без подключения к сети), все работает хорошо и быстро, но когда я в сети (подключен к Wi-fi), работаю с Снэпшоты медленнее, и, как я уже сказал, у меня возникают конфликты с сохраненными данными и сохраненными ранее сохраненными данными (я регистрирую все значения ...). Иногда я получаю даже 5 конфликтов. У меня есть 3 функции для работы с сохраненными играми. Один для чтения данных, один для сохранения данных и один для проверки конфликтов:Android Google Сохраненные игры неожиданные конфликты

Чтение данных:

private void readSavedGame(final String snapshotName) { 
    AsyncTask<Void, Void, Boolean> readingTask = new AsyncTask<Void, Void, Boolean>() { 
     @Override 
     protected Boolean doInBackground(Void... params) { 
      Snapshots.OpenSnapshotResult result = Games.Snapshots.open(mGoogleApiClient, snapshotName, false).await(); 

      Snapshot snapshot = processSnapshotOpenResult(result, 0); 

      if(snapshot != null) { 
       try { 
        updateGameData(snapshot.getSnapshotContents().readFully()); 
        Log.d(TAG, "Updating game: "+String.valueOf(coins)+"..."); 
        return true; 
       } catch (IOException e) { 
        Log.d(TAG, "Error: " + e.getMessage()); 
       } 
      } 

      return false; 
     } 

     @Override 
     protected void onPostExecute(Boolean result) { 
      super.onPostExecute(result); 

      if(result) Log.d(TAG, "Game state read successfully..."); 
      else Log.d(TAG, "Error while reading game state..."); 

      updateUi(); 
     } 
    }; 

    readingTask.execute(); 
} 

Сохранение данных:

private void writeSavedGame(final String snapshotName, final byte[] data) { 
    AsyncTask<Void, Void, Boolean> updateTask = new AsyncTask<Void, Void, Boolean>() { 
     @Override 
     protected Boolean doInBackground(Void... params) { 
      Snapshots.OpenSnapshotResult result = Games.Snapshots.open(
        mGoogleApiClient, snapshotName, false).await(); 

      Snapshot snapshot = processSnapshotOpenResult(result, 0); 

      if(snapshot != null) { 
       snapshot.getSnapshotContents().writeBytes(getGameData()); 
       Log.d(TAG, "Saving: "+String.valueOf(coins)+"..."); 

       Snapshots.CommitSnapshotResult commitSnapshotResult = Games.Snapshots.commitAndClose(mGoogleApiClient, snapshot, SnapshotMetadataChange.EMPTY_CHANGE).await(); 

       if(commitSnapshotResult.getStatus().isSuccess()) return true; 
      } 

      return false; 
     } 

     @Override 
     protected void onPostExecute(Boolean result) { 
      if (result) Log.d(TAG, "Game was saved successfully...."); 
      else Log.d(TAG, "Error while saving game state..."); 
     } 
    }; 

    updateTask.execute(); 
} 

Проверка конфликтов или обращенияOpenSnapshotResult

Snapshot processSnapshotOpenResult(Snapshots.OpenSnapshotResult result, int retryCount) { 
    Snapshot mResolvedSnapshot = null; 
    retryCount++; 

    int status = result.getStatus().getStatusCode(); 
    Log.i(TAG, "Save Result status: " + status); 

    if (status == GamesStatusCodes.STATUS_OK) { 
     Log.d(TAG, "No conflict, SNAPSHOT is OK"); 
     return result.getSnapshot(); 
    } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) { 
     return result.getSnapshot(); 
    } 
    else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) { 
     Log.d(TAG, "Conflict: "+String.valueOf(retryCount)); 

     Snapshot snapshot = result.getSnapshot(); 
     Snapshot conflictSnapshot = result.getConflictingSnapshot(); 

     // Resolve between conflicts by selecting the newest of the conflicting snapshots. 
     mResolvedSnapshot = snapshot; 

     if (snapshot.getMetadata().getLastModifiedTimestamp() < 
       conflictSnapshot.getMetadata().getLastModifiedTimestamp()) { 
      mResolvedSnapshot = conflictSnapshot; 
     } 

     try { 
      Log.d(TAG, "Snapshot data: "+new String(snapshot.getSnapshotContents().readFully())); 
      Log.d(TAG, "Conflicting data: "+new String(conflictSnapshot.getSnapshotContents().readFully())); 
     } catch (IOException e) { 
      Log.e(TAG, "ERROR WHILE READING SPAPSHOTS CONTENTS..."); 
     } 


     Snapshots.OpenSnapshotResult resolveResult = Games.Snapshots.resolveConflict(
       mGoogleApiClient, result.getConflictId(), mResolvedSnapshot).await(); 

     if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES) { 
      // Recursively attempt again 
      return processSnapshotOpenResult(resolveResult, retryCount); 
     } else { 
      // Failed, log error and show Toast to the user 
      String message = "Could not resolve snapshot conflicts"; 
      Log.e(TAG, message); 
      //Toast.makeText(getBaseContext(), message, Toast.LENGTH_LONG).show(); 
     } 

    } 

    // Fail, return null. 
    return null; 
} 

Принципы конфликтов хорошо объясняются here. Мой код основан на official docs implementations и samples.

Поэтому, когда вы в автономном режиме, все работает отлично, но при подключении я получаю конфликты на одном устройстве ... Возможно, я очень часто обновляю сохраненную игру, и службы не могут ее обработать. Есть идеи? Благодарю.

+0

Вы разрешили это? Я столкнулся с той же проблемой. Тот же код отлично работает на iCloud, но в Google он генерирует случайные конфликты. Связано ли это с частотой экономии? «Разумная частота» документов ничего не значит. – mcmorry

ответ

0

Как обсуждалось в Saved Games - Conflict resolution

Как правило, конфликты данных происходят, когда экземпляр приложения не в состоянии достигнуть сервис Сохраненные игры при попытке загрузить данные или сохранить его. В общем случае лучший способ избежать конфликтов данных - всегда загружать последние данные из службы при запуске приложения или возобновлять и сохранять данные на службу с разумной частотой.

В дополнение к этому, рекомендуется также следовать за Best practices for implementing saved games, чтобы предоставить наилучший продукт вашим игрокам.

Также, чтобы узнать, как реализовать сохраненные игры для вашей платформы, см. Ресурсы, приведенные в Client implementations.

Смежные вопросы