משחקים שמורים

במדריך הזה נסביר איך להטמיע משחקים שמורים באמצעות ממשק ה-API של התמונות המיידיות שמופיע ב-SDK של Google Play Games Services ל-C++‎. ממשקי ה-API נכללים בחבילה PgsSnapshotsClient.

לפני שמתחילים

קבלת לקוח תמונות המצב

כדי להתחיל להשתמש ב-Snapshots API, המשחק שלכם צריך קודם לקבל אובייקט PgsSnapshotsClient. כדי לעשות את זה, מפעילים את השיטה PgsSnapshotsClient_create() ומעבירים את הפעילות ב-Android.

הערה: הפונקציות של C++ SDK מחזירות תוצאות באופן אסינכרוני באמצעות קריאות חוזרות (callbacks).

// Assuming 'android_activity' is a jobject referencing your Android Activity
PgsSnapshotsClient* snapshots_client = PgsSnapshotsClient_create(android_activity);

// ... use the client ...

// When done, destroy the client to free resources
// PgsSnapshotsClient_destroy(snapshots_client);

הצגת משחקים שמורים

אפשר לשלב את snapshots API בכל מקום במשחק שבו השחקנים יכולים לשמור או לשחזר את ההתקדמות שלהם. כדי לפשט את תהליך הפיתוח, ה-API של התמונות המיידיות מספק ממשק משתמש (UI) לבחירת משחקים שמורים שמוגדר כברירת מחדל. כדי להפעיל את ממשק המשתמש הזה, מתקשרים אל PgsSnapshotsClient_showSelectSnapshotUI.

// Callback function to handle the result of showing the UI
void OnShowSavedGamesUI(PgsStatusCode status_code, void* user_data) {
  if (status_code == PGS_STATUS_SUCCESS) {
    // UI was shown successfully. The player can now interact with it.
    // The game doesn't receive direct data back from this callback about
    // which snapshot was selected. Your game should typically provide options
    // to load or open snapshots by name after the UI is dismissed.
  } else {
    // Handle error or failure to show UI
  }
}

// Function to show the default Saved Games UI
void ShowSavedGamesUI(PgsSnapshotsClient* client, jobject activity) {
  const char* title = "See My Saves";
  bool allow_add_button = true;
  bool allow_delete_button = true;
  int max_snapshots = 5;

  PgsSnapshotsClient_showSelectSnapshotUI(
      client,
      activity,
      title,
      allow_add_button,
      allow_delete_button,
      max_snapshots,
      OnShowSavedGamesUI,
      NULL // user_data
  );
}

// Example usage:
// ShowSavedGamesUI(snapshots_client, android_activity);

כתיבת משחקים שמורים

כדי לשמור תוכן במשחק שמור:

  1. פותחים תמונה באמצעות PgsSnapshotsClient_open() באופן אסינכרוני. מציינים create_if_not_found כ-true אם רוצים ליצור שמירה חדשה.
  2. התוצאה מופיעה בPgsSnapshotsClient_OpenCallback. אם הפעולה תצליח ולא יהיה ניגוד, יופיע הסימן PgsSnapshot*.
  3. מכינים את הנתונים שרוצים לשמור כמערך בייטים (uint8_t*).
  4. יוצרים אובייקט PgsSnapshotMetadataChange* כדי לתאר את השמירה.
  5. מתקשרים אל PgsSnapshotsClient_commitAndClose כדי לשלוח את השינויים לשרתים של Google.

    // Callback for commitAndClose
    void OnSnapshotCommitted(PgsStatusCode status_code, PgsSnapshotMetadata* metadata, void* user_data) {
        if (status_code == PGS_STATUS_SUCCESS) {
        // Save successful
        if (metadata) {
        // Metadata for the committed snapshot
        PgsSnapshotMetadata_Release(metadata);
      }
    } else {
        // Handle error
      }
    }
    
    // Function to write data to a snapshot
    void WriteSnapshot(PgsSnapshotsClient* client, PgsSnapshot* snapshot,
                   const uint8_t* data, size_t data_size,
                   const char* description /*, Bitmap coverImage */) {
    
    PgsSnapshotMetadataChange* metadataChange = NULL; // Placeholder
    
      // Commit the operation
      PgsSnapshotsClient_commitAndClose(
          client,
          snapshot,
          metadataChange,
          data,
          data_size,
          OnSnapshotCommitted,
          NULL // user_data
      );
    
      // if (metadataChange) PgsSnapshotMetadataChange_Release(metadataChange);
    }
    
    // Callback for opening the snapshot before writing
    void OnSnapshotOpenForWrite(PgsStatusCode status_code,
                            PgsSnapshot* snapshot,
                            PgsSnapshotConflict* conflict,
                            void* user_data) {
      if (status_code == PGS_STATUS_SUCCESS) {
        if (snapshot) {
          // Successfully opened/created. Now write to it.
         const char* save_data_str = "MY_GAME_SAVE_DATA";
         const uint8_t* data = (const uint8_t*)save_data_str;
         size_t data_size = strlen(save_data_str);
    
          WriteSnapshot((PgsSnapshotsClient*)user_data, snapshot, data, data_size, "My Save Description");
          // PgsSnapshot_destroy(snapshot) is likely called after commitAndClose by the SDK
        } else if (conflict) {
          // Handle conflict before writing, or open with a policy that auto-resolves.
          PgsSnapshotConflict_destroy(conflict);
        }
      } else {
        // Handle error opening
      }
    }
    
    // Example: Open and write to a snapshot
    void OpenAndWriteExample(PgsSnapshotsClient* client, const char* snapshot_name) {
    PgsSnapshotsClient_open(
      client,
      snapshot_name,
      true, // create_if_not_found
      kPgsSnapshotConflictPolicyManual, // Or another policy
      OnSnapshotOpenForWrite,
      client // user_data
    );
    }

טעינת משחקים שמורים

כדי לאחזר משחקים שמורים:

  1. פותחים את התמונה של מצב המערכת באופן אסינכרוני לפי שם באמצעות PgsSnapshotsClient_open().
  2. בPgsSnapshotsClient_OpenCallback, אם הפעולה הצליחה, מקבלים גישה לנתונים. ממשק ה-API מספק דרך לקבל את הנתונים והגודל של uint8_t*, אבל המסמך הזה לא מפרט את השיטה לקריאת בייטים מ-PgsSnapshot או מ-PgsSnapshotContents משויך.

    // Assuming functions exist to read data from PgsSnapshotContents
    // For example, PgsSnapshotContents* PgsSnapshot_getContents(PgsSnapshot* snapshot);
    // For example, bool PgsSnapshotContents_readFully(PgsSnapshotContents* contents, uint8_t** out_data, size_t* out_size);
    // For example, void PgsSnapshotContents_releaseData(uint8_t* data);
    
    void OnSnapshotOpenForRead(PgsStatusCode status_code,
                           PgsSnapshot* snapshot,
                           PgsSnapshotConflict* conflict,
                           void* user_data) {
        if (status_code == PGS_STATUS_SUCCESS) {
        if (snapshot) {
        // Successfully opened. Now read from it.
        // THE FOLLOWING IS HYPOTHETICAL based on common patterns:
        // PgsSnapshotContents* contents = PgsSnapshot_getContents(snapshot);
        // uint8_t* data = NULL;
        // size_t data_size = 0;
        // if (contents && PgsSnapshotContents_readFully(contents, &data, &data_size)) {
        //   // Successfully read data
        //   Log("Snapshot data loaded, size: %zu", data_size);
        //   ... process data ...
        //   PgsSnapshotContents_releaseData(data);
        // }
        // PgsSnapshotContents_destroy(contents); // If necessary
          PgsSnapshot_destroy(snapshot);
        } else if (conflict) {
          // Handle conflict
          Log("Snapshot open resulted in a conflict.");
          PgsSnapshotConflict_destroy(conflict);
        }
      } else {
        // Handle error opening
        Log("Error while opening Snapshot: %d", status_code);
      }
    }
    
    // Example: Load a specific saved game
    void LoadSnapshotByName(PgsSnapshotsClient* client, const char* snapshot_name) {
      int conflictResolutionPolicy = kPgsSnapshotConflictPolicyMostRecentlyModified;
    
      PgsSnapshotsClient_open(
          client,
          snapshot_name,
          false, // create_if_not_found
          conflictResolutionPolicy,
          OnSnapshotOpenForRead,
          NULL // user_data
      );
    }

טיפול בהתנגשויות במשחקים שמורים

כשמתבצעת קריאה חוזרת (callback) אל PgsSnapshotsClient_open, אם הפרמטר conflict לא שווה ל-NULL, נוצרת התנגשות. כדי לפתור את ההתנגשות, צריך להשתמש ב-PgsSnapshotsClient_resolveConflict.

/// @brief Asynchronously resolves a snapshot conflict.
///
/// @param snapshots_client The client handle.
/// @param conflict_id The ID of the conflict to resolve.
/// @param snapshot_id The ID of the snapshot to use for resolution.
/// @param metadata_change The metadata changes to apply to the snapshot, or
/// NULL for no changes.
/// @param contents The contents to resolve the conflict with.
/// @param callback Function to be called with result of asynchronous
/// operation. See PgsSnapshotsClient_OpenCallback.
/// @param user_data Arbitrary data pointer to be passed back to callback.
void PgsSnapshotsClient_resolveConflict(
    PgsSnapshotsClient* snapshots_client,
    const char* conflict_id,
    const char* snapshot_id,
    PgsSnapshotMetadataChange* metadata_change,
    PgsSnapshotContents* contents,
    PgsSnapshotsClient_OpenCallback callback,
    void* user_data);