Zarządzaj swoimi danymi za pomocą wersjonowania, listowania i buforowania.
Wersjonowanie
Wersjonowanie ma miejsce, gdy ustawiasz, aktualizujesz i inkrementujesz dane. Funkcje SetAsync(), UpdateAsync(), i IncrementAsync() tworzą wersjonowane kopie zapasowe twoich danych, używając pierwszego zapisu do każdego klucza w każdej godzinie UTC. Kolejne zapisy do klucza w tej samej godzinie UTC trwale nadpisują poprzednie dane.
Wersjonowane kopie zapasowe wygasają 30 dni po tym, jak nowy zapis je nadpisze. Najnowsza wersja nigdy nie wygasa.
Poniższe funkcje wykonują operacje wersjonowania:
| Funkcja | Opis |
|---|---|
Wyświetla wszystkie wersje dla klucza, zwracając instancję DataStoreVersionPages, którą możesz użyć do enumeracji wszystkich numerów wersji. Możesz filtrować wersje, używając zakresu czasowego. | |
Pobiera konkretną wersję klucza, używając numeru wersji klucza. | |
Usuwa konkretną wersję klucza. Ta funkcja tworzy również wersję nagrobkową, zachowując poprzednią wersję. Na przykład, jeśli wywołasz RemoveAsync("User_1234"), a następnie spróbujesz wywołać GetAsync("User_1234"), otrzymasz nil. Możesz jednak nadal używać ListVersionsAsync() i GetVersionAsync(), aby pobrać starsze wersje danych. |
Możesz używać wersjonowania do obsługi żądań użytkowników. Jeśli użytkownik zgłosi, że problem wystąpił o 2020-10-09T01:42, możesz przywrócić dane do poprzedniej wersji, używając poniższego przykładu:
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)
-- Pobiera wersję najbliższą podanemu czasowi
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
-- Odczytuje najbliższą wersję
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- Przywraca bieżącą wartość, nadpisując ją najbliższą wersją
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- Nie znaleziono wpisów
end
endMigawki
Snapshot Data Stores Open Cloud API pozwala na wykonanie migawki wszystkich magazynów danych w grze raz dziennie. Przed opublikowaniem jakiejkolwiek aktualizacji gry, która zmienia logikę przechowywania danych, upewnij się, że wykonałeś migawkę. Wykonanie migawki gwarantuje, że masz najnowsze dane dostępne z poprzedniej wersji gry.
Na przykład, bez migawki, jeśli opublikujesz aktualizację o 3:30 UTC, która powoduje uszkodzenie danych, uszkodzone dane nadpiszą wszelkie dane zapisane między 3:00 a 3:30 UTC. Jeśli jednak wykonasz migawkę o 3:29 UTC, uszkodzone dane nie nadpiszą niczego zapisanego przed 3:29 UTC, a najnowsze dane dla wszystkich kluczy zapisanych między 3:00 a 3:29 UTC zostaną zachowane.
Listowanie i prefiksy
Magazyny danych pozwalają na listowanie według prefiksu. Na przykład, listowanie według pierwszych n znaków nazwy, takich jak "d", "do" lub "dog" dla dowolnego klucza lub magazynu danych z prefiksem "dog".
Możesz określić prefiks podczas listowania wszystkich magazynów danych lub kluczy i otrzymać tylko obiekty, które pasują do tego prefiksu. Funkcje ListDataStoresAsync() oraz ListKeysAsync() zwracają obiekt DataStoreListingPages, który możesz użyć do enumeracji listy.
| Funkcja | Opis |
|---|---|
| ListDataStoresAsync() | Wyświetla wszystkie magazyny danych. |
| ListKeysAsync() | Wyświetla wszystkie klucze w magazynie danych. |
Zakresy
Możesz dalej organizować klucze w magazynie danych, ustawiając unikalny ciąg jako zakres dla drugiego parametru GetDataStore(). Domyślny zakres (jeśli nie podano zakresu) to global. Zakres jest automatycznie dodawany na początku wszystkich kluczy we wszystkich operacjach wykonywanych na magazynie danych.
| Klucz | Zakres |
|---|---|
| houses/User_1234 | houses |
| pets/User_1234 | pets |
| inventory/User_1234 | inventory |
Kombinacja nazwy magazynu danych, zakresu i klucza unikalnie identyfikuje klucz. Wszystkie trzy wartości są wymagane do zidentyfikowania klucza z zakresem. Na przykład, możesz odczytać klucz o zakresie global nazwany User_1234 jako:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)Jeśli klucz User_1234 ma zakres gold, możesz go odczytać tylko jako:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory", "gold")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)Właściwość AllScopes
DataStoreOptions zawiera właściwość AllScopes, która pozwala na zwrócenie kluczy ze wszystkich zakresów w liście. Możesz następnie użyć właściwości KeyName elementu listy do wspólnych operacji na magazynie danych, takich jak odczytywanie danych za pomocą GetAsync() i usuwanie danych za pomocą RemoveAsync().
Kiedy używasz właściwości AllScopes, drugi parametr GetDataStore() musi być pustym ciągiem ("").
local DataStoreService = game:GetService("DataStoreService")
local options = Instance.new("DataStoreOptions")
options.AllScopes = true
local ds = DataStoreService:GetDataStore("DS1", "", options)Jeśli włączysz właściwość AllScopes i utworzysz nowy klucz w magazynie danych, musisz zawsze określić zakres dla tego klucza w formacie zakres/klucz. Jeśli tego nie zrobisz, API zgłosi błąd. Na przykład, gold/player_34545 jest akceptowalne z gold jako zakresem, ale player_34545 prowadzi do błędu.
| global/K1 | house/K1 |
| global/L2 | house/L2 |
| global/M3 | house/M3 |
Buforowanie
Używaj buforowania, aby tymczasowo przechowywać dane z magazynów danych, aby poprawić wydajność i zmniejszyć liczbę żądań wysyłanych do serwera. Na przykład, gra może buforować kopię swoich danych, aby mogła szybko uzyskać dostęp do tych danych bez konieczności ponownego wywoływania magazynu danych.
Buforowanie dotyczy modyfikacji, które wprowadzasz do kluczy magazynu danych, używając:
GetVersionAsync(), ListVersionsAsync(), ListKeysAsync(), oraz ListDataStoresAsync() nie implementują buforowania i zawsze pobierają najnowsze dane z zaplecza usługi.
Domyślnie silnik używa GetAsync(), aby przechowywać wartości, które pobierasz z zaplecza w lokalnym buforze przez cztery sekundy. Również domyślnie, żądania GetAsync() dla buforowanych kluczy zwracają buforowaną wartość zamiast kontynuować do zaplecza. Twoje żądania GetAsync(), które zwracają buforowaną wartość, nie liczą się do twoich limitów serwera i limitów przepustowości.
Wszystkie wywołania GetAsync(), które pobierają wartość, która nie jest buforowana z zaplecza, natychmiast aktualizują bufor i restartują czterosekundowy licznik.
Wyłącz buforowanie
Aby wyłączyć buforowanie i zrezygnować z używania bufora do pobierania najnowszej wartości z serwerów, dodaj parametr DataStoreGetOptions do swojego wywołania GetAsync() i ustaw właściwość UseCache na false, aby sprawić, że twoje żądanie zignoruje wszelkie klucze w buforze.
Wyłączenie buforowania jest przydatne, jeśli masz wiele serwerów zapisujących do klucza z dużą częstotliwością i potrzebujesz uzyskać najnowszą wartość z serwerów. Może to jednak spowodować, że zużyjesz więcej swoich limitów i kwot magazynów danych, ponieważ żądania GetAsync(), które omijają buforowanie, zawsze liczą się do twoich limitów przepustowości i serwera.
Aby natychmiast zweryfikować odczyty po zapisie, użyj GetAsync() z DataStoreGetOptions.UseCache = false. Domyślnie GetAsync() używa lokalnego czterosekundowego bufora, więc normalny odczyt weryfikacyjny może zwrócić przestarzałe dane.
Jest to szczególnie ważne po operacjach zapisu, takich jak UpdateAsync(), SetAsync(), IncrementAsync(), lub RemoveAsync(), które zwracają błąd. W takich przypadkach twój kod musi określić, czy ponownie spróbować, zwrócić pieniądze, czy podjąć inne działania korygujące.
Poniższy przykład pokazuje, jak omijać bufor podczas weryfikacji wyniku zapisu:
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
-- zdecyduj na podstawie stanu zaplecza, a nie stanu buforowanego
end
endSerializacja
DataStoreService przechowuje dane w formacie JSON. Kiedy zapisujesz dane Luau w Studio, Roblox używa procesu zwanego serializacją, aby przekształcić te dane w JSON, aby zapisać je w magazynach danych. Roblox następnie przekształca twoje dane z powrotem do Luau i zwraca je w innym procesie zwanym deserializacją.
Serializacja i deserializacja obsługują następujące typy danych Luau:
- Numbers
- Nie powinieneś przechowywać specjalnych wartości numerycznych inf, -inf i nan, ponieważ te wartości nie spełniają standardów JSON. Kiedy pobierasz wpis zawierający te wartości przez Open Cloud, odpowiedź reprezentuje je jako oznaczone obiekty JSON. Szczegóły znajdziesz w Liczby niefinansowe.
- Tables
- Tabele muszą zawierać tylko inne obsługiwane typy danych
- Klucze numeryczne są tłumaczone na ciągi, jeśli długość tabeli wynosi 0
Jeśli spróbujesz przechować typ danych, którego serializacja nie obsługuje, możesz:
- Nie udać się w przechowywaniu tego typu danych i otrzymać komunikat o błędzie.
- Udać się w przechowywaniu tego typu danych jako nil.
Aby debugować, dlaczego twój typ danych jest przechowywany jako nil, możesz użyć funkcji JSONEncode. Kiedy przekażesz swój typ danych Luau do tej funkcji, otrzymasz go z powrotem w formacie, w jakim Roblox by go przechował w magazynach danych, co pozwala ci podglądać i badać zwrócone dane.