Gespeicherte Spiele für Android-Spiele

In diesem Leitfaden erfahren Sie, wie Sie gespeicherte Spiele mithilfe der Snapshots API, die von den Google Play-Spieldiensten bereitgestellt wird. Die APIs finden Sie in der com.google.android.gms.games.snapshot und com.google.android.gms.games Pakete.

Hinweis

Informationen zu dieser Funktion finden Sie in der Übersicht über gespeicherte Spiele

Snapshot-Client abrufen

Damit Sie die Snapshots API verwenden können, muss Ihr Spiel zuerst eine SnapshotsClient-Objekt. Rufen Sie dazu die Methode Games.getSnapshotsClient() und übergeben die Aktivitäten.

Drive-Bereich angeben

Die Snapshots API basiert auf der Google Drive API. für gespeicherten Spielspeicher. Für den Zugriff auf die Drive API muss in Ihrer App die Drive.SCOPE_APPFOLDER beim Erstellen des Google Log-in-Clients.

Hier ist ein Beispiel, wie Sie dies im onResume() für Ihre Anmeldeaktivitäten:

@Override
protected void onResume() {
  super.onResume();
  signInSilently();
}

private void signInSilently() {
  GoogleSignInOptions signInOption =
      new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
          // Add the APPFOLDER scope for Snapshot support.
          .requestScopes(Drive.SCOPE_APPFOLDER)
          .build();

  GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption);
  signInClient.silentSignIn().addOnCompleteListener(this,
      new OnCompleteListenerG<oogleSignInAccount(>) {
        @Override
        public void onComplete(@NonNull TaskG<oogleSignInAccount >task) {
          if (task.isSuccessful()) {
            onConnected(task.getResult());
          } else {
            // Player will need to sign-in explicitly using via UI
          }
        }
      });
}

Gespeicherte Spiele anzeigen

Du kannst die Snapshots API dort einbinden, wo dein Spiel Spielern die Option, den Fortschritt zu speichern oder wiederherzustellen. Möglicherweise wird in deinem Spiel Option an festgelegten Speicher-/Wiederherstellungspunkten oder erlauben Sie Spielern, Fortschritte zu erzielen.

Sobald Spieler die Option zum Speichern/Wiederherstellen in Ihrem Spiel ausgewählt haben, kann Ihr Spiel optional einen Bildschirm aufrufen, in dem die Spieler Informationen für ein neues gespeichertes oder ein gespeichertes Spiel zum Wiederherstellen auswählen.

Die Snapshots API bietet einen standardmäßigen Nutzer für die Auswahl gespeicherter Spiele, um die Entwicklung zu vereinfachen die Sie sofort verwenden können. Über die Benutzeroberfläche zur Auswahl gespeicherter Spiele ein neues gespeichertes Spiel erstellen, Details zu vorhandenen gespeicherten Spielen anzeigen und frühere gespeicherte Spiele laden.

So starten Sie die Standardbenutzeroberfläche für gespeicherte Spiele:

  1. Rufen Sie unter SnapshotsClient.getSelectSnapshotIntent() an, um eine Intent um die Standardoberfläche für die Auswahl gespeicherter Spiele zu starten.
  2. Anruf startActivityForResult() und diese übergeben. Intent Wenn der Anruf erfolgreich ist, zeigt das Spiel die Benutzeroberfläche zur Auswahl des gespeicherten Spiels sowie mit den von Ihnen angegebenen Optionen.

Hier ein Beispiel für den Start der Standardoberfläche für die Auswahl gespeicherter Spiele:

private static final int RC_SAVED_GAMES = 9009;

private void showSavedGamesUI() {
  SnapshotsClient snapshotsClient =
      PlayGames.getSnapshotsClient(this);
  int maxNumberOfSavedGamesToShow = 5;

  Task<Intent> intentTask = snapshotsClient.getSelectSnapshotIntent(
      "See My Saves", true, true, maxNumberOfSavedGamesToShow);

  intentTask.addOnSuccessListener(new OnSuccessListener<Intent>() {
    @Override
    public void onSuccess(Intent intent) {
      startActivityForResult(intent, RC_SAVED_GAMES);
    }
  });
}

Wenn der Spieler ein neues gespeichertes Spiel erstellen oder ein vorhandenes Spiel laden möchte, die UI eine Anfrage an die Play-Spieldienste sendet. Ist die Anfrage erfolgreich, Die Play-Spieldienste geben Informationen zum Erstellen oder Wiederherstellen des gespeicherten Spiels über onActivityResult() Callback des Nutzers an. Dein Spiel kann diesen Callback überschreiben, um zu prüfen, ob bei der Anfrage Fehler aufgetreten sind.

Das folgende Code-Snippet zeigt eine Beispielimplementierung eines onActivityResult():

private String mCurrentSaveName = "snapshotTemp";

/**
 * This callback will be triggered after you call startActivityForResult from the
 * showSavedGamesUI method.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
  if (intent != null) {
    if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) {
      // Load a snapshot.
      SnapshotMetadata snapshotMetadata =
          intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA);
      mCurrentSaveName = snapshotMetadata.getUniqueName();

      // Load the game data from the Snapshot
      // ...
    } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) {
      // Create a new snapshot named with a unique string
      String unique = new BigInteger(281, new Random()).toString(13);
      mCurrentSaveName = "snapshotTemp-" + unique;

      // Create the new snapshot
      // ...
    }
  }
}

Gespeicherte Spiele schreiben

So speichern Sie Inhalte in einem gespeicherten Spiel:

  1. Snapshot asynchron öffnen über SnapshotsClient.open()

  2. Rufen Sie die Snapshot-Objekt aus dem Ergebnis der Aufgabe durch Aufrufen von SnapshotsClient.DataOrConflict.getData()

  3. Abrufen einer SnapshotContents Instanz mit SnapshotsClient.SnapshotConflict

  4. Anruf SnapshotContents.writeBytes() um die Daten des Spielers im Byte-Format zu speichern.

  5. Sobald alle Änderungen geschrieben sind, rufen Sie SnapshotsClient.commitAndClose() um Ihre Änderungen an die Server von Google zu senden. Im Methodenaufruf kann Ihr Spiel optional zusätzliche Informationen angeben, um den Play-Spieldiensten mitzuteilen, dieses gespeicherte Spiel Spielern präsentieren. Diese Informationen werden in einem SnapshotMetaDataChange -Objekt, das in deinem Spiel mithilfe von SnapshotMetadataChange.Builder

Das folgende Snippet zeigt, wie Ihr Spiel Änderungen an einem gespeicherten Spiel vornehmen kann:

private Task<SnapshotMetadata> writeSnapshot(Snapshot snapshot,
                                             byte[] data, Bitmap coverImage, String desc) {

  // Set the data payload for the snapshot
  snapshot.getSnapshotContents().writeBytes(data);

  // Create the change operation
  SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()
      .setCoverImage(coverImage)
      .setDescription(desc)
      .build();

  SnapshotsClient snapshotsClient =
      PlayGames.getSnapshotsClient(this);

  // Commit the operation
  return snapshotsClient.commitAndClose(snapshot, metadataChange);
}

Wenn das Gerät des Players nicht mit einem Netzwerk verbunden ist, wenn Ihre App einen Anruf durchführt SnapshotsClient.commitAndClose(), Die Play-Spieldienste speichern die gespeicherten Spieldaten lokal auf dem Gerät. Nach Gerät wieder verbunden werden, synchronisiert die Play-Spieldienste die lokal im Cache gespeicherten Spieländerungen mit auf den Google-Servern.

Gespeicherte Spiele laden

So rufen Sie gespeicherte Spiele des aktuell angemeldeten Spielers ab:

  1. Snapshot asynchron öffnen mit SnapshotsClient.open()

  2. Etrieve the Snapshot -Objekt aus dem Ergebnis der Aufgabe heraus, indem Sie SnapshotsClient.DataOrConflict.getData() Alternativ kann Ihr Spiel auch eine bestimmte über die Benutzeroberfläche für die Auswahl gespeicherter Spiele, wie in Gespeicherte Spiele anzeigen

  3. Rufen Sie die SnapshotContents Instanz mit SnapshotsClient.SnapshotConflict

  4. Anruf SnapshotContents.readFully() um den Inhalt des Snapshots zu lesen.

Das folgende Snippet zeigt, wie Sie ein bestimmtes gespeichertes Spiel laden können:

Task<byte[]> loadSnapshot() {
  // Display a progress dialog
  // ...

  // Get the SnapshotsClient from the signed in account.
  SnapshotsClient snapshotsClient =
      PlayGames.getSnapshotsClient(this);

  // In the case of a conflict, the most recently modified version of this snapshot will be used.
  int conflictResolutionPolicy = SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED;

  // Open the saved game using its name.
  return snapshotsClient.open(mCurrentSaveName, true, conflictResolutionPolicy)
      .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
          Log.e(TAG, "Error while opening Snapshot.", e);
        }
      }).continueWith(new Continuation<SnapshotsClient.DataOrConflict<Snapshot>, byte[]>() {
        @Override
        public byte[] then(@NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task) throws Exception {
          Snapshot snapshot = task.getResult().getData();

          // Opening the snapshot was a success and any conflicts have been resolved.
          try {
            // Extract the raw data from the snapshot.
            return snapshot.getSnapshotContents().readFully();
          } catch (IOException e) {
            Log.e(TAG, "Error while reading Snapshot.", e);
          }

          return null;
        }
      }).addOnCompleteListener(new OnCompleteListener<byte[]>() {
        @Override
        public void onComplete(@NonNull Task<byte[]> task) {
          // Dismiss progress dialog and reflect the changes in the UI when complete.
          // ...
        }
      });
}

Konflikte bei gespeicherten Spielen beheben

Wenn Sie die Snapshots API in Ihrem Spiel verwenden, Lese- und Schreibzugriffe auf dasselbe Spiel ausgeführt werden. Für den Fall, dass ein die Netzwerkverbindung des Geräts vorübergehend getrennt und sich später wieder verbindet, kann dies Datenkonflikte verursachen, bei denen das gespeicherte Spiel auf dem lokalen Gerät eines Spielers gespeichert ist. nicht synchron mit der Remote-Version ist, die auf den Google-Servern gespeichert ist.

Die Snapshots API bietet einen Konfliktlösungsmechanismus, der sowohl Gruppen von in Konflikt stehenden gespeicherten Spielen zur Lesezeit und ermöglicht es Ihnen, eine Auflösung zu implementieren. die zu deinem Spiel passt.

Wenn die Play-Spieldienste einen Datenkonflikt feststellen, SnapshotsClient.DataOrConflict.isConflict() gibt den Wert true zurück. In diesem Fall liefert die Methode SnapshotsClient.SnapshotConflict gibt zwei Versionen des gespeicherten Spiels an:

  • Serverversion: Dies ist die aktuellste Version, die den Play-Spieldiensten die aktuelle Version für das Gerät des Spielers korrekt sein.

  • Lokale Version: Eine modifizierte Version, die auf einem der Geräte des Players erkannt wurde. die widersprüchliche Inhalte oder Metadaten enthalten. Dies ist möglicherweise nicht dasselbe wie das die Sie speichern wollten.

Dein Spiel muss entscheiden, wie der Konflikt gelöst werden soll, indem du eine der oder die Daten der beiden gespeicherten Spielversionen zusammenführen.

So erkennen und lösen Sie Konflikte bei gespeicherten Spielen:

  1. Anruf SnapshotsClient.open() Das Ergebnis der Aufgabe enthält die Klasse SnapshotsClient.DataOrConflict.

  2. Rufen Sie die Methode SnapshotsClient.DataOrConflict.isConflict()-Methode. Wenn das Ergebnis „true“ ist, müssen Sie einen Konflikt lösen.

  3. Anruf SnapshotsClient.DataOrConflict.getConflict() um eine SnaphotsClient.snapshotConflict Instanz.

  4. Anruf SnapshotsClient.SnapshotConflict.getConflictId() , um die Konflikt-ID abzurufen, die den erkannten Konflikt eindeutig identifiziert. Ihr Spiel benötigt diesen Wert, um später eine Konfliktlösungsanfrage zu senden.

  5. Anruf SnapshotsClient.SnapshotConflict.getConflictingSnapshot() um die lokale Version abzurufen.

  6. Anruf SnapshotsClient.SnapshotConflict.getSnapshot() um die Serverversion abzurufen.

  7. Um den Konflikt mit dem gespeicherten Spiel zu lösen, wähle eine Version aus, in der du das Spiel speichern möchtest dem Server als endgültige Version und übergeben sie an den SnapshotsClient.resolveConflict() .

Das folgende Snippet zeigt und beispielhaft, wie in Ihrem Spiel ein Konflikt mit einem gespeicherten Spiel behandelt werden könnte, indem Sie Das zuletzt geänderte gespeicherte Spiel wird als endgültige Version zum Speichern ausgewählt:

private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10;

TaskS<napshot >processSnapshotOpenResult(SnapshotsClient.DataOrConflictS<napshot >result,
                                         final int retryCount) {

  if (!result.isConflict()) {
    // There was no conflict, so return the result of the source.
    TaskCompletionSourceS<napshot >source = new TaskCompletionSource(<>);
    source.setResult(result.getData());
    return source.getTask();
  }

  // There was a conflict.  Try resolving it by selecting the newest of the conflicting snapshots.
  // This is the same as using RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED as a conflict resolution
  // policy, but we are implementing it as an example of a manual resolution.
  // One option is to present a UI to the user to choose which snapshot to resolve.
  SnapshotsClient.SnapshotConflict conflict = result.getConflict();

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

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

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

  return PlayGames.getSnapshotsClient(theActivity)
      .resolveConflict(conflict.getConflictId(), resolvedSnapshot)
      .continueWithTask(
          new Continuation
<              SnapshotsClient.DataOrConflictS<napshot,>
              TaskS<napshot(>>) {
            @Override
            public TaskS<napshot >then(
                @NonNull TaskS<napshotsClient.DataOrConflictS<napshot >>task)
                throws Exception {
              // Resolving the conflict may cause another conflict,
              // so recurse and try another resolution.
              if (retryCount  <MAX_SNAPSHOT_RESOLVE_RETRIES) {
                return processSnapshotOpenResult(task.getResult(), retryCount + 1);
              } else {
                throw new Exception(C"ould not resolve snapshot conflicts)";
              }
            }
          });
}

Gespeicherte Spiele bearbeiten

Wenn Sie Daten aus mehreren gespeicherten Spielen zusammenführen oder ein vorhandenes Snapshot, um die aufgelöste endgültige Version auf dem Server zu speichern, folgen Sie diesen Schritte:

  1. Anruf SnapshotsClient.open()

  2. Anruf SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent(), um ein neues SnapshotContents-Objekt.

  3. Führen Sie die Daten aus SnapshotsClient.SnapshotConflict.getConflictingSnapshot() und SnapshotsClient.SnapshotConflict.getSnapshot() in den SnapshotContents -Objekt aus dem vorherigen Schritt.

  4. Optional: Erstellen Sie ein SnapshotMetadataChange wenn Änderungen an den Metadatenfeldern vorgenommen wurden.

  5. Anruf SnapshotsClient.resolveConflict() Übergeben Sie in Ihrem Methodenaufruf SnapshotsClient.SnapshotConflict.getConflictId() als erstes Argument und der SnapshotMetadataChange und SnapshotContents Objekte, die Sie zuvor als zweites und jeweils ein drittes Argument.

  6. Wenn die SnapshotsClient.resolveConflict() erfolgreich ist, speichert die API das Snapshot-Objekt auf dem Server und versucht, das Snapshot-Objekt auf Ihrem lokalen Gerät zu öffnen.