Ngoài việc truy cập cửa hàng dữ liệu từ Engine API trong Studio hoặc các trò chơi trực tiếp (DataStoreService), bạn có thể sử dụng Open Cloud APIs để truy cập cửa hàng dữ liệu tiêu chuẩn và cửa hàng dữ liệu có thứ tự từ các script bên ngoài và các công cụ khác.
Truy cập Open Cloud vào cửa hàng dữ liệu của bạn mở ra nhiều trường hợp sử dụng tiềm năng, bao gồm:
- Một cổng hỗ trợ khách hàng cho phép nhóm của bạn trực tiếp xử lý các yêu cầu hỗ trợ, chẳng hạn như sửa đổi kho đồ của người dùng hoặc phát hành hoàn tiền
- Bảng xếp hạng toàn cầu mà bạn có thể hiển thị trên một trang web bên ngoài
- Cập nhật lược đồ với các script đọc các mục từ cửa hàng dữ liệu hiện tại, ánh xạ nó đến lược đồ mới và ghi các mục trở lại một cửa hàng dữ liệu mới
Các ví dụ trên trang này minh họa cách xây dựng một cổng hỗ trợ kho đồ người dùng và một bảng xếp hạng bên ngoài với Node.js và Python, nhưng hãy sử dụng ngôn ngữ mà bạn thích; Open Cloud APIs hỗ trợ bất kỳ ngôn ngữ lập trình nào có thể gửi yêu cầu HTTP.
Sự khác biệt so với Engine API
Mặc dù Open Cloud APIs truy cập cùng một cửa hàng dữ liệu cơ bản và tương tự như làm việc với DataStoreService, có một vài sự khác biệt chính:
ID vũ trụ: Không giống như Engine API, Open Cloud APIs là không trạng thái và có thể đến từ bất kỳ đâu, vì vậy bạn luôn phải cung cấp ID vũ trụ, định danh duy nhất của trò chơi của bạn.
Quyền riêng biệt cho việc tạo và cập nhật: Engine API tạo các mục mới nếu chúng không tồn tại khi bạn gọi DataStore:SetAsync(), nhưng các phương thức Open Cloud cho việc tạo và cập nhật các mục là riêng biệt. Quyền riêng biệt có thể an toàn hơn và linh hoạt hơn trong một số tình huống. Ví dụ, bạn có thể muốn công cụ hỗ trợ khách hàng của bạn chỉ có thể chỉnh sửa hồ sơ của một người dùng hiện có, không tạo một hồ sơ mới.
Tuần tự hóa dữ liệu: Tất cả các điểm cuối Open Cloud yêu cầu bạn tuần tự hóa dữ liệu trước khi gửi. Tuần tự hóa có nghĩa là chuyển đổi một đối tượng thành một chuỗi. Giải tuần tự hóa là ngược lại, chuyển đổi một chuỗi thành một đối tượng. Engine API tự động tuần tự hóa và giải tuần tự hóa nội dung mục, nhưng đối với Open Cloud, bạn phải tự tạo hoặc phân tích mục của mình từ và đến JSON.
Số không hữu hạn
Các mục cửa hàng dữ liệu được viết thông qua Engine API có thể chứa các số Luau không hữu hạn. Bởi vì JSON không thể đại diện cho những số này, các phản hồi Open Cloud thay thế chúng bằng các đối tượng JSON được gán nhãn trong giá trị mục trả về:
- Vô cực dương (inf): {"m": null, "t": "numeric", "v": "inf"}
- Vô cực âm (-inf): {"m": null, "t": "numeric", "v": "-inf"}
- NaN (nan): {"m": null, "t": "numeric", "v": "nan"}
Quyền
Cửa hàng dữ liệu thường lưu trữ thông tin nhạy cảm, chẳng hạn như hồ sơ người dùng và tiền ảo. Để duy trì an ninh, mỗi phương thức Open Cloud có các quyền tương ứng, được gọi là phạm vi, mà bạn phải thêm vào khóa API của mình, chẳng hạn như phạm vi universe-datastores.control:list cho phương thức Danh sách Cửa hàng Dữ liệu. Nếu bạn không thêm các quyền cần thiết, yêu cầu API của bạn sẽ trả về một lỗi. Xem tài liệu tham khảo để biết các phạm vi cần thiết cho mỗi điểm cuối.
Để biết thêm thông tin về việc quản lý quyền, xem Quản lý khóa API.
Cổng hỗ trợ kho đồ người dùng
Ví dụ này sử dụng một cửa hàng dữ liệu có tên Inventory và một lược đồ cho mỗi mục là "userId": {"currency": number, "weapon": string, "level": number}. Khóa là userId.
Các phạm vi cần thiết
Khi tạo một Khóa API cho ví dụ này, hãy thêm các phạm vi sau vào khóa của bạn:
- universe-datastores.objects:list
- universe-datastores.objects:read
- universe-datastores.objects:update
Tùy chọn, thêm quyền chỉ cho cửa hàng dữ liệu Inventory, đặt một hạn chế địa chỉ IP và đặt một ngày hết hạn.
Thêm script cho cổng hỗ trợ kho đồ người dùng
Sau khi tạo khóa API với các quyền cần thiết cho ứng dụng ví dụ, bạn có thể tạo một script để thực hiện các yêu cầu đến các điểm cuối. Các script này lấy 10 mục đầu tiên trong cửa hàng dữ liệu, tăng giá trị currency cho mỗi mục lên 10, và sau đó cập nhật từng mục. Đối với một cửa hàng dữ liệu lớn hơn, bạn sẽ cần xử lý phân trang bằng cách sử dụng các tham số truy vấn maxPageSize và pageToken.
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('Biến môi trường API_KEY chưa được thiết lập.');
}
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) // Thân phải là một chuỗi
});
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\nĐang xử lý mục: ${path}`);
const currentData = await getEntry(path);
currentData.value.currency += 10;
const payload = { value: currentData.value };
const updateResponse = await updateEntry(path, payload);
console.log(`Trạng thái: ${updateResponse.status}`);
console.log(`Phản hồi: ${await updateResponse.text()}`);
}
} catch (error) {
console.error('Đã xảy ra lỗi trong quá trình thực thi:', error);
}
})();Để kiểm tra, hãy thiết lập biến môi trường API_KEY, cài đặt các phụ thuộc và chạy script:
export API_KEY=<your_key>
node incrementCurrency.jsBảng xếp hạng bên ngoài
Ví dụ này tạo một danh sách người dùng đã được định nghĩa trước cho mục đích demo, nhưng để nó hữu ích trong một trò chơi thực tế, bạn sẽ cần một cửa hàng dữ liệu thực tế của người dùng.
Các phạm vi cần thiết
Khi tạo một Khóa API cho ví dụ này, hãy thêm các phạm vi sau vào khóa của bạn:
- universe.ordered-data-store.scope.entry:read
- universe.ordered-data-store.scope.entry:write
Thêm script cho bảng xếp hạng
Sau khi tạo khóa API với các quyền cần thiết cho ứng dụng ví dụ, bạn có thể tạo một script để thực hiện các yêu cầu đến các điểm cuối. Các script này thêm một số mục mẫu vào cửa hàng dữ liệu có thứ tự với các số ngẫu nhiên và sau đó lấy chúng từ giá trị cao nhất đến thấp nhất. Đối với một cửa hàng dữ liệu lớn hơn, bạn sẽ cần xử lý phân trang bằng cách sử dụng các tham số truy vấn maxPageSize và pageToken.
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(`Lỗi 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('Lỗi: Biến môi trường API_KEY chưa được thiết lập.');
process.exit(1);
}
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
console.log('Đang tạo dữ liệu mẫu...');
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(`Không thể tạo mục cho "${name}": ${error.message}`);
}
}
console.log('\nĐang lấy danh sách mục đã sắp xếp...');
try {
const playerScoresResponse = await listOrderedEntries(universeId, orderedDataStoreId);
console.log(playerScoresResponse.status);
const responseText = await playerScoresResponse.text();
console.log(responseText);
} catch (error) {
console.error(`Không thể liệt kê các mục: ${error.message}`);
}
}
main();Để kiểm tra, hãy thiết lập biến môi trường API_KEY, cài đặt các phụ thuộc và chạy script:
export API_KEY=<your_key>
node leaderboard.js