إضافة ألعاب محفوظة إلى لعبتك

بعد إيقاف Google Sign-In API نهائيًا، سنزيل الإصدار v1 من حزمة تطوير البرامج (SDK) الخاصة بـ "خدمات ألعاب Play". في عام 2026. بعد فبراير 2025، لن يكون بإمكانك نشر الألعاب التي تتكامل مع الإصدار v2 من حزمة SDK الخاصة بـ "خدمات ألعاب Play". ننصحك باستخدام الإصدار v2 حزمة SDK الخاصة بـ "خدمات ألعاب Play". بدلاً من ذلك.
مع أنّ التطبيقات الحالية التي تتكامل مع الإصدار v1 من حزمة SDK الخاصة بـ "خدمات ألعاب Play" ستستمر في العمل لعدّة سنوات، ننصحك بالانتقال إلى الإصدار v2 بدءًا من يونيو 2025.
هذا الدليل مخصّص لاستخدام الإصدار v1 من حزمة SDK الخاصة بـ "خدمات ألعاب Play". حزمة SDK الخاصة بالإصدار 2 من "خدمات ألعاب Play" للتطبيقات بلغة +CC غير متاحة بعد.

يوضّح لك هذا الدليل كيفية حفظ بيانات مستوى تقدّم اللاعب في اللعبة وتحميلها باستخدام خدمة "حفظ التقدم في الألعاب" في تطبيق بلغة ++C يمكنك استخدام هذه الخدمة لتحميل مستوى تقدّم اللاعب في اللعبة وحفظه تلقائيًا في أي وقت أثناء اللعب. يمكن أن تتيح هذه الخدمة أيضًا للاعبين تشغيل واجهة مستخدم لتعديل أو استعادة لعبة محفوظة حالية أو إنشاء لعبة جديدة.

قبل البدء

إذا لم يسبق لك إجراء ذلك، قد يكون من المفيد مراجعة مفاهيم "الألعاب المحفوظة".

قبل البدء في كتابة الرموز البرمجية باستخدام Saved Games API، يجب:

تنسيقات البيانات والتوافق مع منصات متعددة

يجب أن تكون بيانات &quot;حفظ التقدم في الألعاب&quot; التي تحفظها على خوادم Google بالتنسيق std::vector<uint8_t>. تتولّى خدمة &quot;الألعاب المحفوظة&quot; ترميز بياناتك لضمان التوافق مع مختلف المنصات، ويمكن لتطبيقات Android قراءة هذه البيانات نفسها كمصفوفة بايت بدون أي مشاكل في التوافق مع مختلف المنصات.

تجنَّب استخدام تنسيقات خاصة بمنصة معيّنة عند اختيار تنسيق بيانات &quot;حفظ التقدم في الألعاب&quot; ننصحك بشدة باستخدام تنسيق بيانات، مثل XML أو JSON، يتوافق مع مكتبات متعددة على منصات متعددة.

تفعيل خدمة &quot;حفظ التقدم في الألعاب&quot;

قبل استخدام خدمة &quot;حفظ التقدم في الألعاب&quot;، عليك أولاً تفعيل إمكانية الوصول إليها. لإجراء ذلك، استدعِ EnableSnapshots() عند إنشاء الخدمة باستخدام gpg::GameServices::Builder. سيؤدي ذلك إلى تفعيل نطاقات المصادقة الإضافية التي تتطلّبها خدمة &quot;حفظ التقدم في الألعاب&quot; في حدث المصادقة التالي.

عرض بيانات &quot;حفظ التقدم في الألعاب&quot;

في لعبتك، يمكنك توفير خيار يفعله اللاعبون لحفظ الألعاب المحفوظة أو استعادتها. عندما يحدد اللاعبون هذا الخيار، يجب أن تُظهر لعبتك شاشة تعرض خانات الحفظ الحالية، وأن تسمح للاعبين إما بالحفظ في إحدى هذه الخانات أو التحميل منها، أو إنشاء لعبة محفوظة جديدة. استخدِم الطريقة التالية لإجراء ذلك:

  SnapshotManager::ShowSelectUIOperation(...)

تتيح واجهة مستخدم &quot;حفظ التقدم في الألعاب&quot; للاعبين إنشاء لعبة محفوظة جديدة، وعرض تفاصيل حول الألعاب المحفوظة الحالية، وتحميل الألعاب المحفوظة السابقة.

  SnapshotManager::SnapshotSelectUIResponse response;
  if (IsSuccess(response.status)) {
  if (response.data.Valid()) {
    LogI("Description: %s", response.data.Description().c_str());
    LogI("FileName %s", response.data.FileName().c_str());
    //Opening the snapshot data
    
  } else {
    LogI("Creating new snapshot");
    
  }
} else {
  LogI("ShowSelectUIOperation returns an error %d", response.status);
}

يوضّح المثال التالي كيفية عرض واجهة المستخدم التلقائية لـ &quot;حفظ التقدم في الألعاب&quot; والتعامل مع خيار اللاعب:

  service_->Snapshots().ShowSelectUIOperation(
  ALLOW_CREATE_SNAPSHOT,
  ALLOW_DELETE_SNAPSHOT,
  MAX_SNAPSHOTS,
  SNAPSHOT_UI_TITLE,
  [this](gpg::SnapshotManager::SnapshotSelectUIResponse const & response) {
  
      }

إذا كانت قيمة ALLOW_CREATE_SNAPSHOT في المثال أعلاه true وقيمة MAX_SNAPSHOTS أكبر من العدد الفعلي لملفات حفظ التقدّم التي أنشأها المستخدم حاليًا، ستوفّر واجهة المستخدم التلقائية لهذه الملفات للاعبين زرًا لإنشاء ملف جديد بدلاً من اختيار آخر حالي (عندما يظهر الزر، يكون في أسفل واجهة المستخدم). عندما ينقر أحد اللاعبين على هذا الزر، يكون الرد SnapshotSelectUIResponse صالحًا ولكن لا يتضمّن أي بيانات.

فتح الألعاب المحفوظة وقراءتها

للوصول إلى لعبة محفوظة وقراءة محتواها أو تعديله، عليك أولاً فتح العنصر SnapshotMetadata الذي يمثّل هذه اللعبة المحفوظة. بعد ذلك، استدعِ الطريقة SnapshotManager::Read*().

يوضّح المثال التالي كيفية فتح لعبة محفوظة:

  LogI("Opening file");
  service_->Snapshots()
  .Open(current_snapshot_.FileName(),
               gpg::SnapshotConflictPolicy::BASE_WINS,
        [this](gpg::SnapshotManager::OpenResponse const & response) {
           LogI("Reading file");
           gpg::SnapshotManager::ReadResponse responseRead =
           service_->Snapshots().ReadBlocking(response.data);
          
        }

رصد تعارض البيانات وحلّها

عند فتح عنصر SnapshotMetadata، ترصد خدمة &quot;حفظ التقدم في الألعاب&quot; ما إذا كانت هناك لعبة محفوظة متعارضة. قد يحدث تعارض في البيانات عندما تكون اللعبة المحفوظة والمخزَّنة على جهاز اللاعب غير متزامنة مع النسخة المخزَّنة على خوادم Google.

تحدّد سياسة التعارض التي تضعها عند فتح لعبة محفوظة الطريقة التي تحلّ بها خدمة "&quot;حفظ التقدم في الألعاب&quot; تعارض البيانات تلقائيًا. يمكن أن تكون السياسة واحدة مما يلي:

سياسة التعارض الوصف
SnapshotConflictPolicy::MANUAL تشير إلى أنّه يجب ألا تتّخذ خدمة &quot;حفظ التقدم في الألعاب&quot; أي إجراءات لحل المشاكل. بدلاً من ذلك، ستنفّذ لعبتك عملية دمج مخصّص.
SnapshotConflictPolicy::LONGEST_PLAYTIME تشير إلى أنّ خدمة &quot;حفظ التقدم في الألعاب&quot; يجب أن تختار اللعبة المحفوظة التي تتضمّن أكبر قيمة لوقت اللعب.
SnapshotConflictPolicy::BASE_WINS تشير إلى أنّ خدمة "&quot;حفظ التقدم في الألعاب&quot; يجب أن تختار النسخة الأساسية المحفوظة.
SnapshotConflictPolicy::REMOTE_WINS تشير إلى أنّ خدمة &quot;حفظ التقدم في الألعاب&quot; يجب أن تختار آخر نسخة محفوظة. آخر نسخة محفوظة هي نسخة محفوظة رُصدت على أحد أجهزة اللاعب وتحمل طابعًا زمنيًا أحدث من النسخة الأساسية

إذا حدّدت سياسة تعارض غير GPGSnapshotConflictPolicyManual، ستدمج خدمة &quot;حفظ التقدم في الألعاب&quot; اللعبة المحفوظة وتعرض النسخة المعدَّلة من خلال قيمة SnapshotManager::OpenResponse الناتجة. يمكن أن تفتح لعبتك ملف اللعبة المحفوظة، وتعدّل بياناتها، ثم تستدعي الطريقة SnapshotManager::Commit(...)‎ لحفظ اللعبة على خوادم Google.

تنفيذ عملية دمج مخصّصة

إذا حدّدت SnapshotConflictPolicy::MANUAL كسياسة التعارض، يجب أن تحلّ لعبتك أي تعارض في البيانات يتم رصده قبل إجراء المزيد من عمليات القراءة أو الكتابة على اللعبة المحفوظة.

في هذه الحالة، عند رصد تعارض في البيانات، تعرض الخدمة المَعلمات التالية من خلال SnapshotManager::OpenResponse:

  • conflict_id لتحديد هذا التعارض بشكل فريد (ستستخدم هذه القيمة عند إرسال الإصدار النهائي من اللعبة المحفوظة)
  • نسخة اللعبة الأساسية المتعارض مع اللعبة المحفوظة
  • تمثّل هذه السمة آخر نسخة للعبة المحفوظة والمتعارضة مع النسخة الأساسية

يجب أن تحدّد لعبتك البيانات التي سيتم حفظها، ثم تستدعي طريقة SnapshotManager::ResolveConflictBlocking() لتنفيذ/حلّ النسخة النهائية على خوادم Google.

    //Resolve conflict
    gpg::SnapshotManager::OpenResponse resolveResponse =
        manager.ResolveConflictBlocking(openResponse.conflict_base, metadata_change,
                                  openResponse.conflict_id);

تعديل بيانات الألعاب المحفوظة

لتعديل بيانات لعبة محفوظة، عليك أولاً فتح عنصر SnapshotMetadata الذي يمثّل اللعبة المحفوظة، ثم حلّ أي تعارضات في البيانات تم رصدها، ثم استدعاء طريقة SnapshotManager::Commit() لتنفيذ تغييرات اللعبة المحفوظة.

يوضّح المثال التالي كيفية تغيير لعبة محفوظة أو تأكيد التغييرات.

  1. أولاً، افتح الملف الذي تريد تعديله، وتأكَّد من حلّ جميع التعارضات من خلال اختيار النسخة الأساسية.

    service_->Snapshots().Open(
          file_name,
          gpg::SnapshotConflictPolicy::BASE_WINS,
          [this](gpg::SnapshotManager::OpenResponse const &response) {
            if (IsSuccess(response.status)) {
              // metadata : gpg::SnapshotMetadata
              metadata = response.data;
            } else {
              // Handle snapshot open error here
            }
          });
    
  2. بعد ذلك، أنشئ تغييرًا في اللعبة المحفوظة يتضمّن بيانات الصورة المستخدَمة في صورة الغلاف:

    gpg::SnapshotMetadataChange::Builder builder;
    gpg::SnapshotMetadataChange metadata_change =
        builder.SetDescription("CollectAllTheStar savedata")
                 .SetCoverImageFromPngData(pngData).Create();
    
  3. وأخيرًا، نفِّذ تغييرات اللعبة المحفوظة.

    gpg::SnapshotManager::CommitResponse commitResponse =
        service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());
    

    تحتوي مَعلمة البيانات على جميع بيانات حفظ اللعبة التي تخزّنها. يتضمّن التغيير أيضًا بيانات وصفية إضافية للعبة المحفوظة، مثل الوقت الذي تم لعبه ووصف للعبة المحفوظة.

إذا اكتملت عملية التنفيذ بنجاح، يمكن للاعبين الاطّلاع على اللعبة المحفوظة في واجهة مستخدم &quot;حفظ التقدم في الألعاب&quot;.