Gestiona tus datos utilizando versionado, listado y cacheo.
Versionado
El versionado ocurre cuando configuras, actualizas e incrementas datos. Las funciones SetAsync(), UpdateAsync(), y IncrementAsync() crean copias de seguridad versionadas de tus datos utilizando la primera escritura en cada clave en cada hora UTC. Las escrituras sucesivas a una clave en la misma hora UTC sobrescriben permanentemente los datos anteriores.
Las copias de seguridad versionadas caducan 30 días después de que una nueva escritura las sobrescriba. La última versión nunca caduca.
Las siguientes funciones realizan operaciones de versionado:
| Función | Descripción |
|---|---|
Lista todas las versiones para una clave devolviendo una instancia de DataStoreVersionPages que puedes usar para enumerar todos los números de versión. Puedes filtrar versiones utilizando un rango de tiempo. | |
Recupera una versión específica de una clave utilizando el número de versión de la clave. | |
Elimina una versión específica de una clave. Esta función también crea una versión de tumba manteniendo la versión anterior. Por ejemplo, si llamas a RemoveAsync("User_1234") y luego intentas llamar a GetAsync("User_1234"), obtendrás nil. Sin embargo, aún puedes usar ListVersionsAsync() y GetVersionAsync() para recuperar versiones anteriores de los datos. |
Puedes utilizar el versionado para gestionar solicitudes de usuario. Si un usuario informa que ocurrió un problema a las 2020-10-09T01:42, puedes revertir los datos a una versión anterior utilizando el siguiente ejemplo:
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)
-- Obtiene la versión más cercana al tiempo 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
-- Lee la versión más cercana
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- Restaura el valor actual sobrescribiéndolo con la versión más cercana
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- No se encontraron entradas
end
end
Instantáneas
La Snapshot Data Stores Open Cloud API te permite tomar una instantánea de todos los almacenes de datos en un juego una vez al día. Antes de publicar cualquier actualización de juego que cambie tu lógica de almacenamiento de datos, asegúrate de tomar una instantánea. Tomar una instantánea garantiza que tengas los datos más recientes disponibles de la versión anterior del juego.
Por ejemplo, sin una instantánea, si publicas una actualización a las 3:30 UTC que causa corrupción de datos, los datos corruptos sobrescriben cualquier dato escrito entre las 3:00 y las 3:30 UTC. Sin embargo, si tomas una instantánea a las 3:29 UTC, los datos corruptos no sobrescriben nada escrito antes de las 3:29 UTC, y los datos más recientes para todas las claves escritas entre las 3:00 y las 3:29 UTC se preservan.
Listado y prefijos
Los almacenes de datos te permiten listar por prefijo. Por ejemplo, listar por los primeros n caracteres de un nombre, como "d", "do" o "dog" para cualquier clave o almacén de datos con un prefijo de "dog".
Puedes especificar un prefijo al listar todos los almacenes de datos o claves y obtener de vuelta solo objetos que coincidan con ese prefijo. Tanto ListDataStoresAsync() como ListKeysAsync() devuelven un objeto DataStoreListingPages que puedes usar para enumerar la lista.
| Función | Descripción |
|---|---|
| ListDataStoresAsync() | Lista todos los almacenes de datos. |
| ListKeysAsync() | Lista todas las claves en un almacén de datos. |
Ámbitos
Puedes organizar las claves en un almacén de datos configurando una cadena única como un ámbito para el segundo parámetro de GetDataStore(). El ámbito por defecto (si no se proporciona ningún ámbito) es global. El ámbito se agrega automáticamente al inicio de todas las claves en todas las operaciones realizadas en el almacén de datos.
| Clave | Ámbito |
|---|---|
| houses/User_1234 | houses |
| pets/User_1234 | pets |
| inventory/User_1234 | inventory |
La combinación del nombre del almacén de datos, el ámbito y la clave identifica de manera única una clave. Los tres valores son necesarios para identificar una clave con un ámbito. Por ejemplo, puedes leer una clave con ámbito global llamada User_1234 como:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
Si la clave User_1234 tiene un ámbito de gold, sin embargo, solo puedes leerla como:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory", "gold")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
Propiedad AllScopes
DataStoreOptions contiene una propiedad AllScopes que te permite devolver claves de todos los ámbitos en una lista. Luego puedes usar la propiedad KeyName de un elemento de la lista para operaciones comunes del almacén de datos como leer datos con GetAsync() y eliminar datos con RemoveAsync().
Cuando usas la propiedad AllScopes, el segundo parámetro de GetDataStore() debe ser una cadena vacía ("").
local DataStoreService = game:GetService("DataStoreService")local options = Instance.new("DataStoreOptions")options.AllScopes = truelocal ds = DataStoreService:GetDataStore("DS1", "", options)
Si habilitas la propiedad AllScopes y creas una nueva clave en el almacén de datos, siempre debes especificar un ámbito para esa clave en el formato de ámbito/nombredelaclave. Si no lo haces, las APIs lanzarán un error. Por ejemplo, gold/player_34545 es aceptable con gold como ámbito, pero player_34545 provoca un error.
| global/K1 | house/K1 |
| global/L2 | house/L2 |
| global/M3 | house/M3 |
Cacheo
Utiliza el cacheo para almacenar temporalmente datos de los almacenes de datos para mejorar el rendimiento y reducir el número de solicitudes realizadas al servidor. Por ejemplo, un juego puede cachear una copia de sus datos para que pueda acceder rápidamente a esos datos sin tener que hacer otra llamada al almacén de datos.
El cacheo se aplica a las modificaciones que realizas a las claves del almacén de datos utilizando:
- GetAsync() para leer datos.
- SetAsync() para crear datos.
- RemoveAsync() para eliminar datos.
GetVersionAsync(), ListVersionsAsync(), ListKeysAsync(), y ListDataStoresAsync() no implementan cacheo y siempre obtienen los datos más recientes del servicio en segundo plano.
Por defecto, el motor utiliza GetAsync() para almacenar los valores que recuperas del backend en un caché local durante cuatro segundos. También por defecto, las solicitudes GetAsync() para claves cacheadas devuelven el valor cacheado en lugar de continuar hacia el backend. Tus solicitudes GetAsync() que devuelven un valor cacheado no cuentan para tus límites de servidor y límites de rendimiento.
Todas las llamadas a GetAsync() que recuperan un valor que no se está cacheando desde el backend actualizan inmediatamente la caché y reinician el temporizador de cuatro segundos.
Desactivar cacheo
Para desactivar el cacheo y optar por no utilizar el caché para obtener el valor más actualizado de los servidores, agrega el parámetro DataStoreGetOptions a tu llamada GetAsync() y establece la propiedad UseCache en false para hacer que tu solicitud ignore cualquier clave en el caché.
Desactivar el cacheo es útil si tienes múltiples servidores escribiendo en una clave con alta frecuencia y necesitas obtener el valor más reciente de los servidores. Sin embargo, puede hacer que consumas más de tus límites y cuotas de almacenes de datos, ya que las solicitudes GetAsync() que evitan el cacheo siempre cuentan para tus límites de rendimiento y de servidor.
Para lecturas de verificación inmediatas después de una escritura, utiliza GetAsync() con DataStoreGetOptions.UseCache = false. Por defecto, GetAsync() utiliza un caché local de cuatro segundos, por lo que una lectura de verificación normal puede devolver datos obsoletos.
Esto es especialmente importante después de operaciones de escritura como UpdateAsync(), SetAsync(), IncrementAsync(), o RemoveAsync() que devuelven un error. En estos casos, tu código necesita determinar si debe reintentarlo, reembolsar o tomar otra acción correctiva.
El siguiente ejemplo muestra cómo evitar el caché al verificar el resultado de una escritura:
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
-- decide en función del estado del backend, no del estado cacheado
end
end
Serialización
El DataStoreService almacena datos en formato JSON. Cuando guardas datos de Luau en Studio, Roblox utiliza un proceso llamado serialización para convertir esos datos en JSON para guardarlos en almacenes de datos. Luego, Roblox convierte tus datos de vuelta a Luau y te los devuelve en otro proceso llamado deserialización.
La serialización y deserialización admiten los siguientes tipos de datos de Luau:
- Números
- No debes almacenar los valores numéricos especiales inf, -inf y nan, porque estos valores no cumplen con los estándares JSON. No puedes acceder a claves que contengan estos valores con Open Cloud.
- Tablas
- Las tablas deben contener únicamente otros tipos de datos admitidos.
- Las claves numéricas se traducen a cadenas si la longitud de la tabla es 0.
Si intentas almacenar un tipo de dato que la serialización no admite, puedes:
- Fallar al almacenar ese tipo de dato y recibir un mensaje de error.
- Tener éxito en almacenar ese tipo de dato como nil.
Para depurar por qué tu tipo de dato se está almacenando como nil, puedes usar la función JSONEncode. Cuando pasas tu tipo de dato de Luau a esta función, recibes de vuelta el formato que Roblox habría almacenado en los almacenes de datos, lo que te permite previsualizar e investigar los datos devueltos.