إدارة بياناتك باستخدام إصدار البيانات، القوائم، والتخزين المؤقت.
إصدار البيانات
يحدث إصدار البيانات عند تعيين، تحديث، وزيادة البيانات. الدوال SetAsync(), UpdateAsync(), و IncrementAsync() تنشئ نسخ احتياطية بإصدار من بياناتك باستخدام أول كتابة لكل مفتاح في كل ساعة UTC. الكتابات المتتالية لمفتاح في نفس ساعة UTC تكتب بيانات سابقة بشكل دائم.
تعتبر النسخ الاحتياطية بالإصدار منتهية الصلاحية بعد 30 يومًا من كتابة جديدة تستبدلها. النسخة الأخيرة لا تنتهي أبداً.
تؤدي الدوال التالية عمليات إصدار البيانات:
| الدالة | الوصف |
|---|---|
يسرد جميع الإصدارات لمفتاح عن طريق إرجاع مثيل DataStoreVersionPages يمكنك استخدامه لاستعراض جميع أرقام الإصدارة. يمكنك تصفية الإصدارات باستخدام نطاق زمني. | |
يسترجع إصدارًا محددًا لمفتاح باستخدام رقم إصدار المفتاح. | |
يحذف إصدارًا محددًا لمفتاح. تقوم هذه الدالة أيضًا بإنشاء إصدار قبر مع الاحتفاظ بالإصدار السابق. على سبيل المثال، إذا قمت باستدعاء RemoveAsync("User_1234") ثم حاولت استدعاء GetAsync("User_1234")، ستحصل على nil. ومع ذلك، يمكنك استخدام ListVersionsAsync() و GetVersionAsync() لاسترجاع إصدارات أقدم من البيانات. |
يمكنك استخدام إصدار البيانات لمعالجة طلبات المستخدمين. إذا أبلغ مستخدم عن حدوث مشكلة في 2020-10-09T01:42، يمكنك إعادة بياناته إلى إصدار سابق باستخدام المثال التالي:
local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local DATA_STORE_KEY = "User_1234"
local maxDate = DateTime.fromUniversalTime(2020, 10, 09, 01, 42)
-- يحصل على الإصدار الأقرب إلى الوقت المعطى
local listSuccess, pages = pcall(function()
return gameStore:ListVersionsAsync(DATA_STORE_KEY, Enum.SortDirection.Descending, nil, maxDate.UnixTimestampMillis)
end)
if listSuccess then
local items = pages:GetCurrentPage()
if #items > 0 then
-- يقرأ الإصدار الأقرب
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- يستعيد القيمة الحالية عن طريق استبدالها بأقرب إصدار
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- لم يتم العثور على أي إدخالات
end
end
لقطات
تتيح لك واجهة برمجة التطبيقات لقطات بيانات المتاجر المفتوحة أخذ لقطة لجميع متاجر البيانات في لعبة مرة واحدة في اليوم. قبل نشر أي تحديث للعبة يغير منطق تخزين البيانات لديك، تأكد من أخذ لقطة. يضمن أخذ لقطة أن لديك أحدث بيانات متاحة من الإصدار السابق للعبة.
على سبيل المثال، بدون لقطة، إذا قمت بنشر تحديث في 3:30 UTC يسبب تلف البيانات، ستقوم البيانات التالفة باستبدال أي بيانات مكتوبة بين 3:00-3:30 UTC. ومع ذلك، إذا قمت بأخذ لقطة في 3:29 UTC، فإن البيانات التالفة لن تستبدل أي شيء مكتوب قبل 3:29 UTC، وتبقى أحدث البيانات لجميع المفاتيح المكتوبة بين 3:00-3:29 UTC.
القوائم والبادئات
تتيح لك متاجر البيانات إدراج البيانات حسب البادئة. على سبيل المثال، يمكنك الإدراج حسب أول n حرف من الاسم، مثل "d" أو "do" أو "dog" لأي مفتاح أو متجر بيانات مع بادئة "dog".
يمكنك تحديد بادئة عند إدراج جميع متاجر البيانات أو المفاتيح، وستحصل على كائنات تتطابق مع تلك البادئة فقط. تعيد كل من دوال ListDataStoresAsync() و ListKeysAsync() كائن DataStoreListingPages يمكنك استخدامه لاستعراض القائمة.
| الدالة | الوصف |
|---|---|
| ListDataStoresAsync() | يسرد جميع متاجر البيانات. |
| ListKeysAsync() | يسرد جميع المفاتيح في متجر البيانات. |
النطاقات
يمكنك تنظيم المفاتيح في متجر البيانات بمزيد من التفصيل عن طريق تعيين سلسلة فريدة كنطاق للمعامل الثاني لـ GetDataStore(). النطاق الافتراضي (إذا لم يتم إعطاء نطاق) هو global. يتم تلقائيًا إضافة النطاق في بداية جميع المفاتيح في جميع العمليات المنفذة على متجر البيانات.
| المفتاح | النطاق |
|---|---|
| houses/User_1234 | houses |
| pets/User_1234 | pets |
| inventory/User_1234 | inventory |
يحدد الجمع بين اسم متجر البيانات، النطاق، والمفتاح مفتاحًا فريدًا. جميع القيم الثلاثة مطلوبة لتحديد مفتاح مع نطاق. على سبيل المثال، يمكنك قراءة مفتاح النطاق global المسمى User_1234 كالتالي:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
إذا كان المفتاح User_1234 له نطاق gold، يمكنك فقط قراءته كالتالي:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory", "gold")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
خاصية AllScopes
تحتوي DataStoreOptions على خاصية AllScopes التي تتيح لك إرجاع المفاتيح من جميع النطاقات في قائمة. يمكنك بعد ذلك استخدام خاصية KeyName لعنصر القائمة لعمليات متجر البيانات الشائعة مثل قراءة البيانات باستخدام GetAsync() و إزالة البيانات باستخدام RemoveAsync().
عند استخدام خاصية AllScopes، يجب أن تكون المعامل الثاني لـ GetDataStore() سلسلة فارغة ("").
local DataStoreService = game:GetService("DataStoreService")local options = Instance.new("DataStoreOptions")options.AllScopes = truelocal ds = DataStoreService:GetDataStore("DS1", "", options)
إذا قمت بتمكين خاصية AllScopes وأنشأت مفتاحًا جديدًا في متجر البيانات، يجب عليك دائمًا تحديد نطاق لذلك المفتاح بتنسيق نطاق/اسم المفتاح. إذا لم تفعل، فإن واجهات برمجة التطبيقات سترمي خطأ. على سبيل المثال، gold/player_34545 مقبول مع الذهب كنطاق، ولكن player_34545 يؤدي إلى خطأ.
| global/K1 | house/K1 |
| global/L2 | house/L2 |
| global/M3 | house/M3 |
التخزين المؤقت
استخدم التخزين المؤقت لتخزين البيانات مؤقتًا من متاجر البيانات لتحسين الأداء وتقليل عدد الطلبات المقدمة إلى الخادم. على سبيل المثال، يمكن للعبة تخزين نسخة من بياناتها حتى تتمكن من الوصول إلى تلك البيانات بسرعة دون الحاجة إلى إجراء مكالمة أخرى إلى متجر البيانات.
ينطبق التخزين المؤقت على التعديلات التي تجريها على مفاتيح متجر البيانات باستخدام:
لا تقوم GetVersionAsync()، ListVersionsAsync()، ListKeysAsync()، و ListDataStoresAsync() بتنفيذ التخزين المؤقت وتقوم دائمًا بجلب أحدث البيانات من خدمة الخلفية.
بشكل افتراضي، تستخدم المحرك GetAsync() لتخزين القيم التي تسترجعها من الخلفية في ذاكرة مؤقتة محلية لمدة أربع ثوانٍ. أيضًا بشكل افتراضي، تعيد طلبات GetAsync() المفاتيح المخزنة في ذاكرة التخزين المؤقت القيمة المخزنة بدلاً من متابعة الاستعلام إلى الخلفية. طلباتك لـ GetAsync() التي تعيد قيمة مخزنة لا تعتبر ضمن حدود الخادم وحدود الإنتاجية.
تقوم جميع مكالمات GetAsync() التي تسترجع قيمة غير مخزنة من الخلفية بتحديث الذاكرة المؤقتة على الفور وإعادة تشغيل مؤقت الأربع ثوانٍ.
تعطيل التخزين المؤقت
لتعطيل التخزين المؤقت والابتعاد عن استخدام الذاكرة المؤقتة لاسترجاع أحدث قيمة من الخوادم، أضف المعامل DataStoreGetOptions إلى مكالمة GetAsync() وقم بتعيين خاصية UseCache إلى false لجعل طلبك يتجاهل أي مفاتيح في الذاكرة المؤقتة.
يكون تعطيل التخزين المؤقت مفيدًا إذا كان لديك عدة خوادم تكتب إلى مفتاح بتردد عالي وتحتاج إلى الحصول على أحدث قيمة من الخوادم. ومع ذلك، يمكن أن يتسبب ذلك في استهلاك المزيد من حدود وأحجام متاجر البيانات الخاصة بك، نظرًا لأن طلبات GetAsync() التي تتجاوز التخزين المؤقت تُعتبر دائمًا ضمن حدود الإنتاجية وحدود الخادم الخاصة بك.
للقراءات الفورية بعد الكتابة، استخدم GetAsync() مع DataStoreGetOptions.UseCache = false. بشكل افتراضي، تستخدم GetAsync() ذاكرة تخزين مؤقت محلية لمدة أربع ثوانٍ، لذا يمكن أن تعيد القراءة العادية للتحقق بيانات قديمة.
هذا مهم بشكل خاص بعد عمليات الكتابة مثل استدعاء UpdateAsync(), SetAsync(), IncrementAsync(), أو RemoveAsync() التي تُرجع خطأ. في هذه الحالات، يحتاج كودك لتحديد ما إذا كان يجب إعادة المحاولة، أو استرداد الأموال، أو اتخاذ إجراء تصحيحي آخر.
يوضح المثال التالي كيفية تجاوز التخزين المؤقت عند التحقق من نتيجة الكتابة:
local ok = pcall(function()
store:UpdateAsync(key, transform)
end)
if not ok then
local options = Instance.new("DataStoreGetOptions")
options.UseCache = false
local success, value = pcall(function()
return store:GetAsync(key, options)
end)
if success then
-- اتخاذ القرار بناءً على حالة الخلفية، وليس الحالة المخزنة
end
end
التسلسل
تخزن DataStoreService البيانات بتنسيق JSON. عند حفظ بيانات Luau في الاستوديو، تستخدم روبلوكس عملية تسمى التسلسل لتحويل تلك البيانات إلى JSON لحفظها في متاجر البيانات. ثم تقوم روبلوكس بتحويل بياناتك مرة أخرى إلى Luau وتعيدها إليك في عملية أخرى تسمى فك التسلسل.
يدعم التسلسل وفك التسلسل أنواع بيانات Luau التالية:
- الأرقام
- يجب ألا تخزن القيم الرقمية الخاصة inf، -inf، و nan، لأن هذه القيم لا تتوافق مع معايير JSON. لا يمكنك الوصول إلى المفاتيح التي تحتوي على هذه القيم مع بيانات Open Cloud.
- الجداول
- يجب أن تحتوي الجداول فقط على أنواع بيانات مدعومة أخرى
- يتم تحويل المفاتيح الرقمية إلى سلاسل نصية إذا كانت طول الجدول 0
إذا حاولت تخزين نوع بيانات لا تدعمه عملية التسلسل، فإنك إما:
- تفشل في تخزين نوع البيانات هذا وتحصل على رسالة خطأ.
- تنجح في تخزين نوع البيانات هذا كـ nil.
لتصحيح السبب في تخزين نوع بياناتك كـ nil، يمكنك استخدام دالة JSONEncode. عندما تقوم بتمرير نوع بيانات Luau الخاص بك إلى هذه الدالة، تستقبله مرة أخرى بالشكل الذي كانت روبلوكس ستخزنه باستخدام متاجر البيانات، مما يتيح لك معاينة البيانات المسترجعة والتحقق منها.