Gerencie seus dados usando versionamento, listagem e cache.
Versionamento
O versionamento ocorre quando você define, atualiza e incrementa dados. As funções SetAsync(), UpdateAsync() e IncrementAsync() criam backups versionados de seus dados usando a primeira escrita para cada chave a cada hora UTC. Escritas sucessivas para uma chave na mesma hora UTC substituem permanentemente os dados anteriores.
Backups versionados expiram 30 dias após uma nova escrita sobrescrever eles. A versão mais recente nunca expira.
As seguintes funções executam operações de versionamento:
| Função | Descrição |
|---|---|
Lista todas as versões para uma chave retornando uma instância de DataStoreVersionPages que você pode usar para enumerar todos os números de versão. Você pode filtrar versões usando um intervalo de tempo. | |
Recupera uma versão específica de uma chave usando o número da versão da chave. | |
Deleta uma versão específica de uma chave. Esta função também cria uma versão de tumba enquanto retém a versão anterior. Por exemplo, se você chamar RemoveAsync("User_1234") e depois tentar chamar GetAsync("User_1234"), você recebe nil de volta. No entanto, você ainda pode usar ListVersionsAsync() e GetVersionAsync() para recuperar versões mais antigas dos dados. |
Você pode usar o versionamento para lidar com solicitações de usuários. Se um usuário relatar que um problema ocorreu em 2020-10-09T01:42, você pode reverter os dados para uma versão anterior usando o seguinte exemplo:
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)
-- Obtém a versão mais próxima do tempo dado
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
-- Lê a versão mais próxima
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- Restaura o valor atual sobrescrevendo-o com a versão mais próxima
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- Nenhuma entrada encontrada
end
end
Capturas de tela
A API da Nuvem do Data Store de Captura permite que você tire uma captura de todos os armazéns de dados em um jogo uma vez por dia. Antes de publicar qualquer atualização do jogo que mude sua lógica de armazenamento de dados, certifique-se de tirar uma captura. Tirar uma captura garante que você tenha os dados mais recentes disponíveis da versão anterior do jogo.
Por exemplo, sem uma captura, se você publicar uma atualização às 3:30 UTC que cause corrupção de dados, os dados corrompidos sobrescreverão qualquer dado escrito entre 3:00-3:30 UTC. No entanto, se você tirar uma captura às 3:29 UTC, os dados corrompidos não sobrescreverão nada escrito antes de 3:29 UTC, e os dados mais recentes para todas as chaves escritas entre 3:00-3:29 UTC são preservados.
Listagem e prefixos
Os armazéns de dados permitem que você liste por prefixo. Por exemplo, listar pelos primeiros n caracteres de um nome, como "d", "do" ou "dog" para qualquer chave ou armazém de dados com um prefixo de "dog".
Você pode especificar um prefixo ao listar todos os armazéns de dados ou chaves, e receber apenas objetos que correspondem a esse prefixo. Tanto as funções ListDataStoresAsync() quanto ListKeysAsync() retornam um objeto DataStoreListingPages que você pode usar para enumerar a lista.
| Função | Descrição |
|---|---|
| ListDataStoresAsync() | Lista todos os armazéns de dados. |
| ListKeysAsync() | Lista todas as chaves em um armazém de dados. |
Escopos
Você pode organizar ainda mais as chaves em um armazém de dados definindo uma string única como um escopo para o segundo parâmetro de GetDataStore(). O escopo padrão (se nenhum escopo for dado) é global. O escopo é automaticamente precedido ao início de todas as chaves em todas as operações realizadas no armazém de dados.
| Chave | Escopo |
|---|---|
| houses/User_1234 | houses |
| pets/User_1234 | pets |
| inventory/User_1234 | inventory |
A combinação do nome do armazém de dados, escopo e chave identifica exclusivamente uma chave. Todos os três valores são necessários para identificar uma chave com um escopo. Por exemplo, você pode ler uma chave com escopo global chamada User_1234 como:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
Se a chave User_1234 tiver um escopo de gold, no entanto, você só pode lê-la como:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory", "gold")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
Propriedade AllScopes
DataStoreOptions contém uma propriedade AllScopes que permite retornar chaves de todos os escopos em uma lista. Você pode então usar a propriedade KeyName de um item da lista para operações comuns de armazém de dados, como ler dados com GetAsync() e remover dados com RemoveAsync().
Quando você usa a propriedade AllScopes, o segundo parâmetro de GetDataStore() deve ser uma string vazia ("").
local DataStoreService = game:GetService("DataStoreService")local options = Instance.new("DataStoreOptions")options.AllScopes = truelocal ds = DataStoreService:GetDataStore("DS1", "", options)
Se você habilitar a propriedade AllScopes e criar uma nova chave no armazém de dados, você deve sempre especificar um escopo para essa chave no formato escopo/nomeDaChave. Se você não fizer isso, as APIs gerarão um erro. Por exemplo, gold/player_34545 é aceitável com gold como escopo, mas player_34545 leva a um erro.
| global/K1 | house/K1 |
| global/L2 | house/L2 |
| global/M3 | house/M3 |
Cache
Use o cache para armazenar temporariamente dados de armazéns de dados para melhorar o desempenho e reduzir o número de solicitações feitas ao servidor. Por exemplo, um jogo pode armazenar em cache uma cópia de seus dados para que possa acessar esses dados rapidamente sem precisar fazer outra chamada ao armazém de dados.
O cache se aplica a modificações que você faz em chaves de armazém de dados usando:
- GetAsync() para ler dados.
- SetAsync() para criar dados.
- UpdateAsync() para atualizar dados.
- RemoveAsync() para remover dados.
GetVersionAsync(), ListVersionsAsync(), ListKeysAsync() e ListDataStoresAsync() não implementam cache e sempre buscam os dados mais recentes do backend do serviço.
Por padrão, o motor usa GetAsync() para armazenar valores que você recupera do backend em um cache local por quatro segundos. Além disso, por padrão, as solicitações de GetAsync() por chaves em cache retornam o valor em cache em vez de continuar para o backend. Suas solicitações GetAsync() que retornam um valor em cache não contam para seus limites de servidor e limites de throughput.
Todas as chamadas GetAsync() que recuperam um valor que não está sendo armazenado em cache no backend atualizam o cache imediatamente e reiniciam o timer de quatro segundos.
Desativar cache
Para desativar o cache e optar por não usar o cache para recuperar o valor mais atualizado dos servidores, adicione o parâmetro DataStoreGetOptions à sua chamada GetAsync() e defina a propriedade UseCache como false para fazer sua solicitação ignorar quaisquer chaves no cache.
Desativar o cache é útil se você tiver múltiplos servidores escrevendo para uma chave com alta frequência e precisar obter o valor mais recente dos servidores. No entanto, isso pode fazer com que você consuma mais de seus limites e cotas de armazéns de dados, já que as solicitações de GetAsync() que ignoram o cache sempre contam para seus limites de throughput e servidores.
Para leituras de verificação imediatas após uma escrita, use GetAsync() com DataStoreGetOptions.UseCache = false. Por padrão, GetAsync() usa um cache local de quatro segundos, então uma leitura de verificação normal pode retornar dados desatualizados.
Isso é especialmente importante após operações de escrita como UpdateAsync(), SetAsync(), IncrementAsync() ou RemoveAsync() que retornam um erro. Nesses casos, seu código precisa determinar se deve tentar novamente, reembolsar ou tomar outra ação corretiva.
O seguinte exemplo mostra como ignorar o cache ao verificar o resultado de uma escrita:
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
-- decidir com base no estado do backend, não no estado em cache
end
end
Serialização
O DataStoreService armazena dados em formato JSON. Quando você salva dados Luau no Studio, a Roblox utiliza um processo chamado serialização para converter esses dados em JSON para salvá-los em armazéns de dados. A Roblox então converte seus dados de volta para Luau e os retorna a você em outro processo chamado desserialização.
A serialização e a desserialização suportam os seguintes tipos de dados Luau:
- Números
- Você não deve armazenar os valores numéricos especiais inf, -inf e nan, pois esses valores não estão em conformidade com os padrões JSON. Você não pode acessar chaves que contêm esses valores com Open Cloud.
- Tabelas
- Tabelas devem conter apenas outros tipos de dados suportados
- Chaves numéricas são traduzidas em strings se o comprimento da tabela é 0
Se você tentar armazenar um tipo de dado que a serialização não suporta, você pode:
- Falhar em armazenar aquele tipo de dado e receber uma mensagem de erro.
- Ter sucesso em armazenar aquele tipo de dado como nil.
Para depurar por que seu tipo de dado está sendo armazenado como nil, você pode usar a função JSONEncode. Quando você passa seu tipo de dado Luau para essa função, você o recebe de volta no formato que a Roblox teria armazenado com armazéns de dados, o que permite que você visualize e investigue os dados retornados.