Google সাইন-ইন API বন্ধ করার পর, আমরা ২০২৬ সালে গেমস v1 SDK সরিয়ে ফেলছি। ২০২৫ সালের ফেব্রুয়ারির পর, আপনি Google Play তে গেমস v1 SDK-এর সাথে নতুনভাবে সংহত করা শিরোনাম প্রকাশ করতে পারবেন না। আমরা আপনাকে এর পরিবর্তে গেমস v2 SDK ব্যবহার করার পরামর্শ দিচ্ছি।
পূর্ববর্তী গেম v1 ইন্টিগ্রেশন সহ বিদ্যমান শিরোনামগুলি কয়েক বছর ধরে কাজ করলেও, আপনাকে জুন 2025 থেকে v2 তে স্থানান্তরিত হতে উৎসাহিত করা হচ্ছে।
এই নির্দেশিকাটি Play Games Services v1 SDK ব্যবহারের জন্য। সর্বশেষ SDK সংস্করণ সম্পর্কে তথ্যের জন্য, v2 ডকুমেন্টেশন দেখুন।
এই নির্দেশিকাটি আপনাকে দেখায় যে কীভাবে Google Play Games Services দ্বারা প্রদত্ত Snapshot API ব্যবহার করে সংরক্ষিত গেম গেমটি বাস্তবায়ন করবেন। API গুলি com.google.android.gms.games.snapshot এবং com.google.android.gms.games প্যাকেজগুলিতে পাওয়া যাবে।
শুরু করার আগে
যদি আপনি ইতিমধ্যেই এটি না করে থাকেন, তাহলে Saved Games গেমের ধারণাগুলি পর্যালোচনা করা আপনার জন্য সহায়ক হতে পারে।
- গুগল প্লে কনসোলে আপনার গেমের জন্য সংরক্ষিত গেম সাপোর্ট সক্ষম করতে ভুলবেন না।
- অ্যান্ড্রয়েড নমুনা পৃষ্ঠায় সংরক্ষিত গেম কোড নমুনাটি ডাউনলোড করুন এবং পর্যালোচনা করুন।
- "গুণমান চেকলিস্ট" -এ বর্ণিত সুপারিশগুলির সাথে নিজেকে পরিচিত করুন।
স্ন্যাপশট ক্লায়েন্ট পান
স্ন্যাপশট API ব্যবহার শুরু করতে, আপনার গেমটিকে প্রথমে একটি SnapshotsClient অবজেক্ট পেতে হবে। আপনি Games.getSnapshotsClient() পদ্ধতিতে কল করে এবং বর্তমান প্লেয়ারের জন্য কার্যকলাপ এবং GoogleSignInAccount পাস করে এটি করতে পারেন। প্লেয়ার অ্যাকাউন্টের তথ্য কীভাবে পুনরুদ্ধার করবেন তা জানতে, Android Games-এ সাইন-ইন দেখুন।
ড্রাইভ স্কোপ নির্দিষ্ট করুন
সংরক্ষিত গেম স্টোরেজের জন্য স্ন্যাপশট API Google ড্রাইভ API-এর উপর নির্ভর করে। ড্রাইভ API অ্যাক্সেস করতে, Google সাইন-ইন ক্লায়েন্ট তৈরি করার সময় আপনার অ্যাপকে Drive.SCOPE_APPFOLDER স্কোপ নির্দিষ্ট করতে হবে।
আপনার সাইন-ইন কার্যকলাপের জন্য onResume() পদ্ধতিতে এটি কীভাবে করবেন তার একটি উদাহরণ এখানে দেওয়া হল:
private GoogleSignInClient mGoogleSignInClient; @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 OnCompleteListener<GoogleSignInAccount>() { @Override public void onComplete(@NonNull Task<GoogleSignInAccount> task) { if (task.isSuccessful()) { onConnected(task.getResult()); } else { // Player will need to sign-in explicitly using via UI } } }); }
সংরক্ষিত গেমগুলি প্রদর্শন করুন
আপনার গেম যেখানেই খেলোয়াড়দের অগ্রগতি সংরক্ষণ বা পুনরুদ্ধার করার বিকল্প প্রদান করে, আপনি সেখানেই স্ন্যাপশট API ইন্টিগ্রেট করতে পারেন। আপনার গেমটি নির্ধারিত সংরক্ষণ/পুনরুদ্ধার পয়েন্টগুলিতে এই বিকল্পটি প্রদর্শন করতে পারে অথবা খেলোয়াড়দের যেকোনো সময় অগ্রগতি সংরক্ষণ বা পুনরুদ্ধার করার অনুমতি দিতে পারে।
একবার খেলোয়াড়রা আপনার গেমে সংরক্ষণ/পুনরুদ্ধার বিকল্পটি নির্বাচন করলে, আপনার গেমটি ঐচ্ছিকভাবে একটি স্ক্রিন আনতে পারে যা খেলোয়াড়দের একটি নতুন সংরক্ষিত গেমের তথ্য প্রবেশ করতে বা পুনরুদ্ধার করার জন্য একটি বিদ্যমান সংরক্ষিত গেম নির্বাচন করতে অনুরোধ করে।
আপনার ডেভেলপমেন্টকে সহজ করার জন্য, স্ন্যাপশট API একটি ডিফল্ট সংরক্ষিত গেম নির্বাচন ব্যবহারকারী ইন্টারফেস (UI) প্রদান করে যা আপনি আউট-অফ-দ্য-বক্স ব্যবহার করতে পারেন। সংরক্ষিত গেম নির্বাচন UI খেলোয়াড়দের একটি নতুন সংরক্ষিত গেম তৈরি করতে, বিদ্যমান সংরক্ষিত গেমগুলির বিশদ দেখতে এবং পূর্ববর্তী সংরক্ষিত গেমগুলি লোড করতে দেয়।
ডিফল্ট সংরক্ষিত গেমস UI চালু করতে:
- ডিফল্ট সংরক্ষিত গেম নির্বাচন UI চালু করার জন্য একটি
IntentপেতেSnapshotsClient.getSelectSnapshotIntent()এ কল করুন। -
startActivityForResult()কল করুন এবংIntentপাস করুন। কলটি সফল হলে, গেমটি আপনার নির্দিষ্ট করা বিকল্পগুলির সাথে সংরক্ষিত গেম নির্বাচন UI প্রদর্শন করবে।
ডিফল্ট সংরক্ষিত গেম নির্বাচন UI কীভাবে চালু করবেন তার একটি উদাহরণ এখানে দেওয়া হল:
private static final int RC_SAVED_GAMES = 9009; private void showSavedGamesUI() { SnapshotsClient snapshotsClient = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(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); } }); }
যদি খেলোয়াড় একটি নতুন সংরক্ষিত গেম তৈরি করতে বা বিদ্যমান সংরক্ষিত গেম লোড করতে নির্বাচন করে, তাহলে UI Google Play Games Services-এ একটি অনুরোধ পাঠায়। অনুরোধটি সফল হলে, Google Play Games Services onActivityResult() কলব্যাকের মাধ্যমে সংরক্ষিত গেমটি তৈরি বা পুনরুদ্ধার করার জন্য তথ্য ফেরত পাঠায়। অনুরোধের সময় কোনও ত্রুটি ঘটেছে কিনা তা পরীক্ষা করার জন্য আপনার গেমটি এই কলব্যাকটিকে ওভাররাইড করতে পারে।
নিম্নলিখিত কোড স্নিপেটটি 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 // ... } } }
সংরক্ষিত গেমগুলি লিখুন
একটি সংরক্ষিত গেমে সামগ্রী সংরক্ষণ করতে:
-
SnapshotsClient.open()এর মাধ্যমে অ্যাসিঙ্ক্রোনাসভাবে একটি স্ন্যাপশট খুলুন। তারপর,SnapshotsClient.DataOrConflict.getData()কল করে টাস্কের ফলাফল থেকেSnapshotঅবজেক্টটি পুনরুদ্ধার করুন। -
SnapshotsClient.SnapshotConflictএর মাধ্যমে একটিSnapshotContentsইনস্ট্যান্স পুনরুদ্ধার করুন। - প্লেয়ারের ডেটা বাইট ফর্ম্যাটে সংরক্ষণ করতে
SnapshotContents.writeBytes()এ কল করুন। - আপনার সমস্ত পরিবর্তন লেখা হয়ে গেলে,
SnapshotsClient.commitAndClose()এ কল করে আপনার পরিবর্তনগুলি Google এর সার্ভারে পাঠান। মেথড কলে, আপনার গেমটি ঐচ্ছিকভাবে Google Play Games Services কে খেলোয়াড়দের কাছে এই সংরক্ষিত গেমটি কীভাবে উপস্থাপন করতে হবে তা জানাতে অতিরিক্ত তথ্য প্রদান করতে পারে। এই তথ্যটি একটিSnapshotMetaDataChangeঅবজেক্টে উপস্থাপন করা হয়, যা আপনার গেমSnapshotMetadataChange.Builderব্যবহার করে তৈরি করে।
নিম্নলিখিত স্নিপেটটি দেখায় যে আপনার গেমটি কীভাবে একটি সংরক্ষিত গেমে পরিবর্তন আনতে পারে:
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 = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(this)); // Commit the operation return snapshotsClient.commitAndClose(snapshot, metadataChange); }
আপনার অ্যাপ SnapshotsClient.commitAndClose() কল করার সময় যদি প্লেয়ারের ডিভাইসটি কোনও নেটওয়ার্কের সাথে সংযুক্ত না থাকে, তাহলে Google Play Games Services ডিভাইসে স্থানীয়ভাবে সংরক্ষিত গেমের ডেটা সংরক্ষণ করে। ডিভাইসটি পুনরায় সংযোগ করার পরে, Google Play Games Services স্থানীয়ভাবে ক্যাশে করা সংরক্ষিত গেমের পরিবর্তনগুলি Google এর সার্ভারে সিঙ্ক করে।
সংরক্ষিত গেম লোড করুন
বর্তমানে সাইন-ইন করা প্লেয়ারের জন্য সংরক্ষিত গেমগুলি পুনরুদ্ধার করতে:
-
SnapshotsClient.open()এর মাধ্যমে অ্যাসিঙ্ক্রোনাসভাবে একটি স্ন্যাপশট খুলুন। তারপর,SnapshotsClient.DataOrConflict.getData()কল করে টাস্কের ফলাফল থেকেSnapshotঅবজেক্টটি পুনরুদ্ধার করুন। বিকল্পভাবে, আপনার গেমটি সংরক্ষিত গেম নির্বাচন UI এর মাধ্যমে একটি নির্দিষ্ট স্ন্যাপশট পুনরুদ্ধার করতে পারে, যেমনটি Display saved games এ বর্ণিত হয়েছে। -
SnapshotsClient.SnapshotConflictএর মাধ্যমেSnapshotContentsইনস্ট্যান্সটি পুনরুদ্ধার করুন। - স্ন্যাপশটের বিষয়বস্তু পড়তে
SnapshotContents.readFully()এ কল করুন।
নিম্নলিখিত স্নিপেটটি দেখায় কিভাবে আপনি একটি নির্দিষ্ট সংরক্ষিত গেম লোড করতে পারেন:
Task<byte[]> loadSnapshot() { // Display a progress dialog // ... // Get the SnapshotsClient from the signed in account. SnapshotsClient snapshotsClient = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(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. // ... } }); }
সংরক্ষিত গেমের দ্বন্দ্বগুলি পরিচালনা করুন
আপনার গেমে স্ন্যাপশট API ব্যবহার করার সময়, একই সংরক্ষিত গেমটিতে একাধিক ডিভাইসের জন্য পঠন এবং লেখা সম্ভব। যদি কোনও ডিভাইস সাময়িকভাবে তার নেটওয়ার্ক সংযোগ হারিয়ে ফেলে এবং পরে পুনরায় সংযোগ স্থাপন করে, তাহলে এটি ডেটা দ্বন্দ্বের কারণ হতে পারে যার ফলে খেলোয়াড়ের স্থানীয় ডিভাইসে সংরক্ষিত সংরক্ষিত গেমটি Google এর সার্ভারে সংরক্ষিত রিমোট সংস্করণের সাথে সিঙ্কের বাইরে চলে যায়।
স্ন্যাপশটস এপিআই একটি দ্বন্দ্ব সমাধান প্রক্রিয়া প্রদান করে যা পঠন-সময়ে উভয় সেটের দ্বন্দ্বপূর্ণ সংরক্ষিত গেম উপস্থাপন করে এবং আপনাকে আপনার গেমের জন্য উপযুক্ত একটি সমাধান কৌশল বাস্তবায়ন করতে দেয়।
যখন Google Play Games Services ডেটা দ্বন্দ্ব শনাক্ত করে, তখন SnapshotsClient.DataOrConflict.isConflict() পদ্ধতিটি true এর মান প্রদান করে। এই ক্ষেত্রে, SnapshotsClient.SnapshotConflict ক্লাসটি সংরক্ষিত গেমের দুটি সংস্করণ প্রদান করে:
- সার্ভার ভার্সন : গুগল প্লে গেমস সার্ভিসেসের কাছে প্লেয়ারের ডিভাইসের জন্য সঠিক বলে পরিচিত সবচেয়ে হালনাগাদ সংস্করণ; এবং
- স্থানীয় সংস্করণ : প্লেয়ারের কোনও একটি ডিভাইসে একটি পরিবর্তিত সংস্করণ সনাক্ত করা হয়েছে যাতে বিরোধপূর্ণ সামগ্রী বা মেটাডেটা রয়েছে। এটি আপনি যে সংস্করণটি সংরক্ষণ করার চেষ্টা করেছিলেন তার মতো নাও হতে পারে।
আপনার গেমটিকে অবশ্যই প্রদত্ত সংস্করণগুলির মধ্যে একটি বেছে নিয়ে অথবা দুটি সংরক্ষিত গেম সংস্করণের ডেটা একত্রিত করে দ্বন্দ্ব কীভাবে সমাধান করবেন তা নির্ধারণ করতে হবে।
সংরক্ষিত গেমের দ্বন্দ্ব সনাক্ত এবং সমাধান করতে:
-
SnapshotsClient.open()কল করুন। টাস্কের ফলাফলে একটিSnapshotsClient.DataOrConflictক্লাস রয়েছে। -
SnapshotsClient.DataOrConflict.isConflict()পদ্ধতিটি কল করুন। ফলাফলটি যদি সত্য হয়, তাহলে আপনার একটি দ্বন্দ্ব সমাধান করতে হবে। - একটি SnapshotsClient.snapshotConflict ইনস্ট্যান্স পুনরুদ্ধার করতে
SnapshotsClient.snapshotConflictSnapshotsClient.DataOrConflict.getConflict()এ কল করুন। - সনাক্ত করা দ্বন্দ্বকে অনন্যভাবে শনাক্তকারী দ্বন্দ্ব আইডি পুনরুদ্ধার করতে
SnapshotsClient.SnapshotConflict.getConflictId()এ কল করুন। পরে দ্বন্দ্ব সমাধানের অনুরোধ পাঠাতে আপনার গেমের এই মানটির প্রয়োজন। - স্থানীয় সংস্করণটি পেতে
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()এ কল করুন। - সার্ভার ভার্সন পেতে
SnapshotsClient.SnapshotConflict.getSnapshot()এ কল করুন। - সংরক্ষিত গেমের দ্বন্দ্ব সমাধান করতে, আপনি যে সংস্করণটি সার্ভারে চূড়ান্ত সংস্করণ হিসেবে সংরক্ষণ করতে চান তা নির্বাচন করুন এবং এটি
SnapshotsClient.resolveConflict()পদ্ধতিতে পাস করুন।
নিম্নলিখিত স্নিপেটটি দেখায় এবং উদাহরণ দেয় যে আপনার গেমটি কীভাবে একটি সংরক্ষিত গেমের দ্বন্দ্ব মোকাবেলা করতে পারে, সর্বশেষ সংরক্ষিত গেমটিকে সংরক্ষণের জন্য চূড়ান্ত সংস্করণ হিসাবে নির্বাচন করে:
private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10; Task<Snapshot> processSnapshotOpenResult(SnapshotsClient.DataOrConflict<Snapshot> result, final int retryCount) { if (!result.isConflict()) { // There was no conflict, so return the result of the source. TaskCompletionSource<Snapshot> 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 Games.getSnapshotsClient(theActivity, GoogleSignIn.getLastSignedInAccount(this)) .resolveConflict(conflict.getConflictId(), resolvedSnapshot) .continueWithTask( new Continuation< SnapshotsClient.DataOrConflict<Snapshot>, Task<Snapshot>>() { @Override public Task<Snapshot> then( @NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> 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("Could not resolve snapshot conflicts"); } } }); }
সংরক্ষিত গেমগুলি দ্বন্দ্ব সমাধানের জন্য পরিবর্তন করুন
আপনি যদি একাধিক সংরক্ষিত গেম থেকে ডেটা একত্রিত করতে চান অথবা একটি বিদ্যমান Snapshot পরিবর্তন করে সার্ভারে সমাধান করা চূড়ান্ত সংস্করণ হিসেবে সংরক্ষণ করতে চান, তাহলে এই পদক্ষেপগুলি অনুসরণ করুন:
-
SnapshotsClient.open()এ কল করুন। - একটি নতুন
SnapshotContentsঅবজেক্ট পেতেSnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()এ কল করুন। -
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()এবংSnapshotsClient.SnapshotConflict.getSnapshot()থেকে ডেটা পূর্ববর্তী ধাপেরSnapshotContentsঅবজেক্টের সাথে মার্জ করুন। - ঐচ্ছিকভাবে, মেটাডেটা ক্ষেত্রগুলিতে কোনও পরিবর্তন থাকলে একটি
SnapshotMetadataChangeইনস্ট্যান্স তৈরি করুন। -
SnapshotsClient.resolveConflict()কল করুন। আপনার মেথড কলে, প্রথম আর্গুমেন্ট হিসেবেSnapshotsClient.SnapshotConflict.getConflictId()এবং দ্বিতীয় এবং তৃতীয় আর্গুমেন্ট হিসেবেSnapshotMetadataChangeএবংSnapshotContentsঅবজেক্টগুলি প্রবেশ করান। - যদি
SnapshotsClient.resolveConflict()কলটি সফল হয়, তাহলে API সার্ভারেSnapshotঅবজেক্টটি সংরক্ষণ করে এবং আপনার স্থানীয় ডিভাইসে Snapshot অবজেক্টটি খোলার চেষ্টা করে।- যদি কোনও দ্বন্দ্ব থাকে, তাহলে
SnapshotsClient.DataOrConflict.isConflict()trueপ্রদান করে। এই ক্ষেত্রে, আপনার গেমটি ধাপ ২-এ ফিরে যাবে এবং দ্বন্দ্ব সমাধান না হওয়া পর্যন্ত স্ন্যাপশট পরিবর্তন করার পদক্ষেপগুলি পুনরাবৃত্তি করবে। - যদি কোনও দ্বন্দ্ব না থাকে, তাহলে
SnapshotsClient.DataOrConflict.isConflict()falseপ্রদান করে এবংSnapshotঅবজেক্টটি আপনার গেমটি পরিবর্তন করার জন্য উন্মুক্ত থাকে।
- যদি কোনও দ্বন্দ্ব থাকে, তাহলে