Penyimpanan data Open Cloud

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Selain mengakses penyimpanan data dari Engine API di Studio atau permainan langsung (DataStoreService), Anda dapat menggunakan Open Cloud API untuk mengakses standar dan penyimpanan data terurut dari skrip eksternal dan alat lainnya.

Akses Open Cloud ke penyimpanan data Anda membuka banyak kemungkinan penggunaan, termasuk:

  • Portal dukungan pelanggan yang memungkinkan tim Anda menangani permintaan dukungan secara langsung, seperti memodifikasi inventaris pengguna atau mengeluarkan pengembalian dana
  • Papan peringkat global yang dapat Anda tampilkan di situs web eksternal
  • Pembaruan skema dengan skrip yang membaca entri dari penyimpanan data saat ini, memetakan ke skema baru, dan menulis entri kembali ke penyimpanan data baru

Contoh di halaman ini menunjukkan cara membangun portal dukungan inventaris pengguna dan papan peringkat eksternal dengan Node.js dan Python, tetapi gunakan bahasa apa pun yang Anda suka; Open Cloud API mendukung bahasa pemrograman apa pun yang dapat mengirim permintaan HTTP.

Perbedaan dari Engine API

Meskipun Open Cloud API mengakses penyimpanan data yang sama dan mirip dengan bekerja dengan DataStoreService, ada beberapa perbedaan kunci:

  • ID Universe: Tidak seperti Engine API, Open Cloud API bersifat stateless dan dapat berasal dari mana saja, jadi Anda harus selalu menyediakan ID universe, pengidentifikasi unik dari permainan Anda.

  • Izin terpisah untuk membuat dan memperbarui: Engine API membuat entri baru jika tidak ada saat Anda memanggil DataStore:SetAsync(), tetapi metode Open Cloud untuk membuat dan memperbarui entri terpisah. Izin terpisah dapat lebih aman dan lebih fleksibel dalam situasi tertentu. Misalnya, Anda mungkin ingin alat dukungan pelanggan Anda hanya dapat mengedit profil pengguna yang sudah ada, bukan membuat yang baru.

  • Serialisasi data: Semua endpoint Open Cloud mengharuskan Anda untuk menserialisasi data sebelum mengirimkannya. Serialisasi berarti mengonversi objek menjadi string. Deserialisasi adalah kebalikannya, mengonversi string menjadi objek. Engine API menserialisasi dan mendeserialisasi konten entri secara otomatis, tetapi untuk Open Cloud, Anda harus menghasilkan atau mengurai entri Anda ke dan dari JSON sendiri.

Angka non-finite

Entri penyimpanan data yang ditulis melalui Engine API dapat berisi angka Luau non-finite. Karena JSON tidak dapat merepresentasikan angka ini, respons Open Cloud menggantinya dengan objek JSON bertag dalam nilai entri yang dikembalikan:

  • Positif tak terhingga (inf): {"m": null, "t": "numeric", "v": "inf"}
  • Negatif tak terhingga (-inf): {"m": null, "t": "numeric", "v": "-inf"}
  • NaN (nan): {"m": null, "t": "numeric", "v": "nan"}

Izin

Penyimpanan data sering menyimpan informasi sensitif, seperti profil pengguna dan mata uang virtual. Untuk menjaga keamanan, setiap metode Open Cloud memiliki izin yang sesuai, yang disebut scope, yang harus Anda tambahkan ke kunci API Anda, seperti scope universe-datastores.control:list untuk metode List Data Stores. Jika Anda tidak menambahkan izin yang diperlukan, panggilan API Anda akan mengembalikan kesalahan. Lihat dokumentasi referensi untuk scope yang diperlukan untuk setiap endpoint.

Untuk informasi lebih lanjut tentang mengelola izin, lihat Kelola kunci API.

Portal dukungan inventaris pengguna

Contoh ini menggunakan penyimpanan data bernama Inventory dan skema untuk setiap entri dari "userId": {"currency": number, "weapon": string, "level": number}. Kuncinya adalah userId.

Scope yang diperlukan

Saat membuat Kunci API untuk contoh ini, tambahkan scope berikut ke kunci Anda:

  • universe-datastores.objects:list
  • universe-datastores.objects:read
  • universe-datastores.objects:update

Opsional, tambahkan izin hanya untuk penyimpanan data Inventory, atur pembatasan alamat IP, dan atur tanggal kedaluwarsa.

Tambahkan skrip untuk portal dukungan inventaris pengguna

Setelah membuat kunci API dengan izin yang diperlukan untuk aplikasi contoh, Anda dapat membuat skrip untuk melakukan permintaan ke endpoint. Skrip ini mendapatkan 10 entri pertama di penyimpanan data, meningkatkan nilai currency untuk masing-masing sebesar 10, dan kemudian memperbarui setiap entri. Untuk penyimpanan data yang lebih besar, Anda perlu menangani paginasi menggunakan parameter kueri maxPageSize dan pageToken.

incrementCurrency.js
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('Variabel lingkungan API_KEY tidak disetel.');
}
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) // Badan harus berupa string
});
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\nMemproses entri: ${path}`);
const currentData = await getEntry(path);
currentData.value.currency += 10;
const payload = { value: currentData.value };
const updateResponse = await updateEntry(path, payload);
console.log(`Status: ${updateResponse.status}`);
console.log(`Respons: ${await updateResponse.text()}`);
}
} catch (error) {
console.error('Terjadi kesalahan selama eksekusi:', error);
}
})();

Untuk menguji, atur variabel lingkungan API_KEY, instal dependensi, dan jalankan skrip:

export API_KEY=<your_key>
node incrementCurrency.js

Papan peringkat eksternal yang persisten

Contoh ini membuat daftar pengguna yang telah ditentukan untuk tujuan demo, tetapi agar berguna dalam permainan nyata, Anda memerlukan penyimpanan data pengguna yang sebenarnya.

Scope yang diperlukan

Saat membuat Kunci API untuk contoh ini, tambahkan scope berikut ke kunci Anda:

  • universe.ordered-data-store.scope.entry:read
  • universe.ordered-data-store.scope.entry:write

Tambahkan skrip untuk papan peringkat

Setelah membuat kunci API dengan izin yang diperlukan untuk aplikasi contoh, Anda dapat membuat skrip untuk melakukan permintaan ke endpoint. Skrip ini menambahkan beberapa entri contoh ke penyimpanan data terurut dengan angka acak dan kemudian mengambilnya dari nilai tertinggi ke terendah. Untuk penyimpanan data yang lebih besar, Anda perlu menangani paginasi menggunakan parameter kueri maxPageSize dan 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(`Kesalahan 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('Kesalahan: Variabel lingkungan API_KEY tidak disetel.');
process.exit(1);
}
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
console.log('Membuat data contoh...');
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(`Gagal membuat entri untuk "${name}": ${error.message}`);
}
}
console.log('\nMengambil daftar entri yang terurut...');
try {
const playerScoresResponse = await listOrderedEntries(universeId, orderedDataStoreId);
console.log(playerScoresResponse.status);
const responseText = await playerScoresResponse.text();
console.log(responseText);
} catch (error) {
console.error(`Gagal untuk mendaftar entri: ${error.message}`);
}
}
main();

Untuk menguji, atur variabel lingkungan API_KEY, instal dependensi, dan jalankan skrip:

export API_KEY=<your_key>
node leaderboard.js
©2026 Roblox Corporation. Roblox, logo Roblox, dan Powering Imagination termasuk dalam merek dagang kami yang terdaftar dan tidak terdaftar di AS dan negara lainnya.