Además de acceder a los almacenes de datos desde la API del Motor en Studio o en juegos en vivo (DataStoreService), puedes utilizar las API de Open Cloud para acceder a almacenes de datos estándar y almacenes de datos ordenados desde scripts externos y otras herramientas.
El acceso de Open Cloud a tus almacenes de datos desbloquea muchos casos de uso potenciales, incluidos:
- Un portal de soporte al cliente que permite a tu equipo manejar directamente las solicitudes de soporte, como modificar inventarios de usuarios o emitir reembolsos
- Clasificaciones globales que puedes mostrar en un sitio web externo
- Actualizaciones de esquema con scripts que leen entradas del almacén de datos actual, las mapean al nuevo esquema y escriben las entradas en un nuevo almacén de datos
Los ejemplos en esta página demuestran cómo construir un portal de soporte de inventario de usuario y una clasificación externa con Node.js y Python, pero utiliza el lenguaje que prefieras; las API de Open Cloud son compatibles con cualquier lenguaje de programación que pueda enviar una solicitud HTTP.
Diferencias con la API del Motor
Aunque las API de Open Cloud acceden a los mismos almacenes de datos subyacentes y son similares a trabajar con DataStoreService, hay algunas diferencias clave:
ID del universo: A diferencia de la API del Motor, las API de Open Cloud son sin estado y pueden provenir de cualquier lugar, por lo que siempre debes proporcionar el ID del universo, el identificador único de tu juego.
Permisos separados para crear y actualizar: La API del Motor crea nuevas entradas si no existen cuando llamas a DataStore:SetAsync(), pero los métodos de Open Cloud para crear y actualizar entradas son separados. Los permisos separados pueden ser más seguros y flexibles en ciertas situaciones. Por ejemplo, es posible que desees que tu herramienta de soporte al cliente solo pueda editar el perfil de un usuario existente, no crear uno nuevo.
Serialización de datos: Todos los puntos finales de Open Cloud requieren que serialices los datos antes de enviarlos. La serialización significa convertir un objeto en una cadena. La deserialización es lo opuesto, convertir una cadena en un objeto. La API del Motor serializa y deserializa el contenido de las entradas automáticamente, pero para Open Cloud, debes generar o analizar tu entrada hacia y desde JSON por tu cuenta.
Permisos
Los almacenes de datos a menudo almacenan información sensible, como perfiles de usuario y moneda virtual. Para mantener la seguridad, cada método de Open Cloud tiene permisos correspondientes, llamados ámbitos, que debes agregar a tu clave de API, como el ámbito universe-datastores.control:list para el método List Data Stores. Si no agregas los permisos requeridos, tu llamada a la API devuelve un error. Consulta la documentación de referencia para los ámbitos requeridos para cada punto final.
Para obtener más información sobre la gestión de permisos, consulta Manage API keys.
Portal de soporte de inventario de usuario
Este ejemplo utiliza un almacén de datos llamado Inventory y un esquema para cada entrada de "userId": {"currency": number, "weapon": string, "level": number}. La clave es userId.
Ámbitos requeridos
Al crear una clave API para este ejemplo, agrega los siguientes ámbitos a tu clave:
- universe-datastores.objects:list
- universe-datastores.objects:read
- universe-datastores.objects:update
Opcionalmente, agrega los permisos solo para el almacén de datos Inventory, establece una restricción de dirección IP y establece una fecha de expiración.
Agregar scripts para el portal de soporte de inventario de usuario
Después de crear la clave API con los permisos requeridos para la aplicación de ejemplo, puedes crear un script para realizar solicitudes a los puntos finales. Estos scripts obtienen las primeras 10 entradas en el almacén de datos, incrementan el valor de currency para cada uno en 10 y luego actualizan cada entrada. Para un almacén de datos más grande, deberías lidiar con paginación utilizando los parámetros de consulta maxPageSize y pageToken.
incrementCurrency.js
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('La variable de entorno API_KEY no está configurada.');
}
const apiHeaderKey = 'x-api-key';
const universeId = '';
const dataStoreId = 'Inventory';
const baseUrl = 'https://apis.roblox.com/cloud/v2/';
async function listEntries(universe, dataStore) {
const listPath = `universes/${universe}/data-stores/${dataStore}/entries`;
const url = baseUrl + listPath;
const response = await fetch(url, {
headers: { [apiHeaderKey]: apiKey }
});
return response.json();
}
async function getEntry(path) {
const url = baseUrl + path;
const response = await fetch(url, {
headers: { [apiHeaderKey]: apiKey }
});
return response.json();
}
async function updateEntry(path, payload) {
const url = baseUrl + path;
const response = await fetch(url, {
method: 'PATCH',
headers: {
[apiHeaderKey]: apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload) // El cuerpo debe ser una cadena
});
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\nProcesando entrada: ${path}`);
const currentData = await getEntry(path);
currentData.value.currency += 10;
const payload = { value: currentData.value };
const updateResponse = await updateEntry(path, payload);
console.log(`Estado: ${updateResponse.status}`);
console.log(`Respuesta: ${await updateResponse.text()}`);
}
} catch (error) {
console.error('Se produjo un error durante la ejecución:', error);
}
})();
Para probar, establece la variable de entorno API_KEY, instala las dependencias y ejecuta el script:
export API_KEY=<your_key>node incrementCurrency.js
Clasificación externa persistente
Este ejemplo crea una lista predefinida de usuarios con fines de demostración, pero para que sea útil en un juego real, necesitarías un almacén de datos real de usuarios.
Ámbitos requeridos
Al crear una clave API para este ejemplo, agrega los siguientes ámbitos a tu clave:
- universe.ordered-data-store.scope.entry:read
- universe.ordered-data-store.scope.entry:write
Agregar scripts para la clasificación
Después de crear la clave API con los permisos requeridos para la aplicación de ejemplo, puedes crear un script para realizar solicitudes a los puntos finales. Estos scripts agregan algunas entradas de muestra al almacén de datos ordenado con números aleatorios y luego las recuperan de mayor a menor valor. Para un almacén de datos más grande, deberías lidiar con paginación utilizando los parámetros de consulta maxPageSize y pageToken.
leaderboard.js
const apiKey = process.env.API_KEY;
const apiHeaderKey = 'x-api-key';
const universeId = '';
const orderedDataStoreId = 'PlayerScores';
const scopeId = 'global';
const baseUrl = 'https://apis.roblox.com/cloud/v2/';
async function createOrderedEntry(universe, orderedDataStore, entryId, payload) {
const createPath = `universes/${universe}/ordered-data-stores/${orderedDataStore}/scopes/${scopeId}/entries`;
const url = new URL(baseUrl + createPath);
url.searchParams.append('id', entryId);
const response = await fetch(url, {
method: 'POST',
headers: {
[apiHeaderKey]: apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Error de API (${response.status}): ${errorText}`);
}
return response.text();
}
async function listOrderedEntries(universe, orderedDataStore) {
const listPath = `universes/${universe}/ordered-data-stores/${orderedDataStore}/scopes/${scopeId}/entries`;
const url = new URL(baseUrl + listPath);
url.searchParams.append('orderBy', 'value desc');
return fetch(url, {
headers: {
[apiHeaderKey]: apiKey,
},
});
}
async function main() {
if (!apiKey) {
console.error('Error: La variable de entorno API_KEY no está configurada.');
process.exit(1);
}
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
console.log('Creando datos de muestra...');
for (const name of entryNames) {
try {
const randomValue = Math.floor(Math.random() * 50) + 1;
const payload = { value: randomValue };
const responseText = await createOrderedEntry(universeId, orderedDataStoreId, name, payload);
console.log(responseText);
} catch (error) {
console.error(`Falló al crear la entrada para "${name}": ${error.message}`);
}
}
console.log('\nObteniendo lista ordenada de entradas...');
try {
const playerScoresResponse = await listOrderedEntries(universeId, orderedDataStoreId);
console.log(playerScoresResponse.status);
const responseText = await playerScoresResponse.text();
console.log(responseText);
} catch (error) {
console.error(`Falló al listar entradas: ${error.message}`);
}
}
main();
Para probar, establece la variable de entorno API_KEY, instala las dependencias y ejecuta el script:
export API_KEY=<your_key>node leaderboard.js