데이터 저장소 사용 가이드

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

Studio 또는 라이브 서버에서 Engine API를 사용하여 DataStoreService에 액세스하고 표준주문형 데이터 저장소에 액세스하고 사용할 수 있는 Open Cloud API를 사용하여 외부 스크립트와 도구에서 세분화된 액세스 및 보안 제어로 액세스하고 사용할 수 있습니다.

사용

다음과 같은 API를 사용하여 작업 흐름의 여러 영역을 개선할 수 있습니다.

  • 고객 지원 포털 : 데이터 저장소는 사용자 인벤토리의 아이템이나 스킬 포인트와 같은 영구적인 사용자 리소스를 저장하는 데 유용합니다.때때로 지원 센터위해 이러한 리소스를 업데이트해야 합니다.Studio를 사용하거나 경험에 수동으로 참여하는 대신, 고객 지원 담당자가 사용자 인벤토리 보기 및 수정 및 환불 발행과 같은 고객 지원 요청을 직접 처리할 수 있도록 웹 응용 프로그램을 빌드할 수 있습니다.

  • LiveOps 대시보드 : API를 사용하여 LiveOps 대시보드를 빌드하여 라이브 작업의 효율성을 향상시킬 수 있습니다.예를 들어, 이벤트를 사전에 예약하고, 데이터 상점구성 데이터의 일부로 기능 플래그에 숨기고, 이벤트를 게시하기 위해 플래그를 전환할 시간을 설정할 수 있습니다.경험 서버는 이벤트를 시작하기 위해 플래그를 읽어 이 변경을 감지할 수 있습니다.

  • 외부 리더보드 : Roblox 외부에서 경험을 홍보하려면 레이스의 리더보드와 같은 경험의 정보를 실시간으로 가져와 외부 웹사이트에 표시할 수 있습니다.웹사이트가 HTTP를 통해 주기적으로 최신 데이터를 요청하고 웹 페이지를 업데이트할 수 있도록 주문한 데이터 저장소에 읽기 전용 액세스를 부여할 수 있습니다.

  • 데이터 마이그레이션 자동화 : 데이터는 경험이 진화함에 따라 변경되거나 업데이트될 수 있습니다(예: 새로운 기능을 수용하기 위해 데이터 스키마를 업그레이드하기).기존 사용자 데이터를 손실하지 않으려면 데이터 저장소를 오래된 스키마에서 새로운 스키마로 마이그레이션해야 하는 경우가 있습니다.현재 데이터 저장소에서 각 항목을 읽고, 데이터를 새 스키마로 매핑하고, 새 데이터 저장소에 항목을 다시 쓰는 외부 스크립트를 작성하여 데이터 마이그레이션을 자동화할 수 있습니다.

엔진 API와의 차이점

오픈 클라우드 API가 DataStoreService와 유사하긴 하지만, 몇 가지 핵심 차이점이 있습니다.

  • 유니버스 ID 및 데이터 저장소 이름 : 엔진 API와 달리 오픈 클라우드 API는 상태가 없으며 어디서나 올 수 있으므로 항상 경험의 고유 식별자인 유니버스 ID 와 데이터 저장소 이름 을 전송해야 합니다.우주 ID를 가져오는 방법에 대한 자세한 정보는 우주 ID를 참조하십시오.

  • 생성 및 업데이트에 대한 별도 권한 : 엔진 API는 호출할 때 DataStore:SetAsync() 없으면 새 항목을 생성하지만, 항목 생성 및 업데이트에 대한 오픈 클라우드 메서드는 별도입니다.특정 상황에서 별도 권한은 더 안전하고 유연할 수 있습니다.예를 들어, 기존 사용자의 프로필을 편집할 수 있지만 새 사용자의 프로필을 생성할 수 없는 고객 지원 도구를 만들 수 있습니다.

  • 데이터 직렬화 : 모든 오픈 클라우드 끝점은 네트워크 전송 전에 모든 데이터를 직렬화해야 합니다.직렬화는 개체를 문자열로 변환하는 것을 의미합니다.역렬화는 반대(문자열을 개체로 변환)입니다.엔진 API는 입력 콘텐츠를 자동으로 직렬화하고 디직렬화하지만, 오픈 클라우드의 경우 입력 데이터를 JSON으로 생성하거나 분석해야 합니다.

보안 권한

데이터 저장소는 사용자 프로필 및 가상 통화와 같은 민감한 정보를 종종 저장합니다.보안을 유지하기 위해 각 Open Cloud API에는 목록 API에 대한 List Keys 권한과 같이 API 키에 추가해야 하는 해당 필수 권한이 있습니다.필요한 권한을 추가하지 않으면 API 호출에 오류가 반환됩니다.각 작업에 필요한 특정 권한은 표준주문형 데이터 저장소의 API 참조를 참조하십시오.

API 키를 구성할 때 , 특정 경험 내의 각 데이터 저장소에 대해 읽음, 쓰기 및 목록 항목과 같은 세부 권한을 설정하거나 경험 내의 모든 데이터 저장소를 읽거나 쓰도록 키를 줄 수 있습니다.모든 데이터 저장소를 노출하는 대신 도구에 필요한 데이터 저장소 하위 집합에 대한 액세스를 제한할 수도 있습니다.키가 유출되는 경우 영향을 완화합니다.

빌드 도구

선택한 언어를 사용하여 데이터 저장소용 오픈 클라우드 API로 도구를 빌드하여 작업 요구 사항을 충족할 수 있습니다.다음 예제에서는 표준 데이터 저장소와 순서가 지정된 데이터 저장소를 사용하여 Python에서 사용자 인벤토리 지원 포털을 빌드하는 프로세스와 외부 영구 리더보드를 사용하여 순서가 지정된 데이터 저장소를 사용하여 외부 영구 리더보드를 걸어갑니다.

사용자 인벤토리 지원 포털

이 섹션에서는 사용자 인벤토리 지원 포털을 구축하는 구체적인 예제를 제공하여 사용자의 인벤토리 하위 집합을 나열하고 읽고, 편집하고 경험의 데이터 상점업데이트할 수 있습니다.

이 예제에서는 팔로잉가정합니다:

  • 사용자 인벤토리를 저장하는 데이터 저장소의 이름은 Inventory입니다.

  • 각 데이터 항목의 데이터 스키마는 "userId": {"currency": number, "weapon": string, "level": number} 입니다. 키는 userId 입니다.

  • Python 스크립트는 접두사에 따라 사용자 인벤토리의 하위 집합을 나열하고, 프로모션을 위해 가상 통화를 10으로 늘리고, 데이터를 업데이트합니다.

높은 레벨API 키 권한을 추가하고 스크립트를 추가하여 파이썬 앱을 빌드할 수 있습니다.

데이터 저장소에 대한 API 키 권한 추가

이 예제에 대해 API 키를 생성할 때 다음 설정을 수행하십시오:

  1. 액세스 권한 섹션의 API 시스템 선택 메뉴에서 유니버스 데이터 저장소를 선택합니다.

  2. (옵션) 데이터 저장소 섹션에서 API 작업을 특정 데이터 저장소에 대해 선택합니다.

    1. 특정 데이터 저장소 작업을 활성화 토글합니다.기본적으로 다섯 개의 데이터 저장소가 자동으로 불러오다 + 데이터 저장소 목록에 추가 버튼을 통해 추가 데이터 저장소를 추가할 수 있습니다.
    2. 데이터 상점이름 옆에 드롭다운 화살표를 선택한 다음 데이터 저장소에 액세스할 수 있는 API 작업을 선택합니다.
  3. 전체 경험에 대한 API 작업을 선택합니다.

    1. 클릭하십시오 경험 선택을 추가하려면 드롭다운을 클릭하고 경험을 선택합니다.
    2. 경험 운영에서 드롭다운 화살표를 클릭하고 API에 추가하려는 작업을 선택합니다 .이 예제에서는 전체 경험에 대해 읽기 항목 선택 , 업데이트 항목 선택 , 및 목록 항목 키 를 선택합니다.
  4. 보안 섹션에서 CIDR 표기법을 사용하여 IP 액세스를 키에 명시적으로 설정하고 만료 날짜를 명시적으로 설정하여 키가 해당 날짜 이후에 자동으로 작동을 중지합니다.이 예제에서는 먼저 로컬 테스트를 수행할 계획이 있는 경우 IP 제한을 0.0.0.0/0 으로 설정하여 만료 기간을 30일 로 설정하여 제거할 수 있습니다.

사용자 인벤토리 지원 포털에 대한 스크립트 추가

예제 앱에 필요한 권한으로 API 키를 만든 후, 앱 기능을 수행하기 위해 JavaScript 코드를 추가해야 합니다.파일은 방법을 정의하는 방법을 보여줍니다 , , 그리고 방법을 보여줍니다.update_inventory.js 파일은 정의된 메서드를 사용하여 사용자 인벤토리의 하위 집합을 나열하고, 각 사용자에 대한 가상 통화를 증가시키고, 데이터를 업데이트합니다.

dataStoresMethods.js

const fetch = require('node-fetch');
class DataStores {
constructor() {
this._baseUrl =
'https://apis.roblox.com/datastores/v1/universes/{universeId}';
this._apiKey = process.env.API_KEY;
this._universeId = 'UNIVERSE_ID';
this.ATTR_HDR = 'Roblox-entry-Attributes';
this.USER_ID_HDR = 'Roblox-entry-UserIds';
this._objectsUrl = `${this._baseUrl}${this._universeId}/standard-datastores/datastore/entries/entry`;
this._incrementUrl = `${this._objectsUrl}/increment`;
this._listObjectsUrl = `${this._baseUrl}${this._universeId}/standard-datastores/datastore/entries`;
}
async _getHeaders() {
return { 'x-api-key': this._apiKey };
}
async getEntry(datastore, objectKey, scope = null) {
const url = `${
this._objectsUrl
}?datastoreName=${datastore}&entryKey=${objectKey}&scope=${scope || ''}`;
const response = await fetch(url, { headers: await this._getHeaders() });
const data = await response.json();
return data;
}
async listEntries(datastore, scope = null, prefix = '', limit = 100) {
const url = `${this._listObjectsUrl}?datastoreName=${datastore}&scope=${scope}&prefix=${prefix}&limit=${limit}`;
const response = await fetch(url, { headers: await this._getHeaders() });
const data = await response.json();
return data;
}
async incrementEntry(datastore, objectKey, incrementBy, scope = null) {
const url = `${
this._incrementUrl
}?datastoreName=${datastore}&entryKey=${objectKey}&incrementBy=${incrementBy}&scope=${
scope || ''
}`;
const response = await fetch(url, {
method: 'POST',
headers: await this._getHeaders(),
});
const data = await response.json();
return data;
}
}
module.exports = DataStores;
updateInventory.js

const DataStores = require('./dataStoresMethods');
const dataStoresApi = new DataStores();
// Set up
const datastoreName = 'Inventory';
// List keys for a subset of users
dataStoresApi.listEntries(datastoreName).then((keys) => {
console.log(keys);
});
// Read inventory for each user
for (let x = 0; x < 5; x++) {
const updatedObjectKey = `User_${x + 1}`;
dataStoresApi.getEntry(datastoreName, updatedObjectKey).then((value) => {
console.log(
`${updatedObjectKey} has ${value.gems} gems in their inventory`
);
});
}
// Update the currency of each user by 10
for (let x = 0; x < 5; x++) {
const updatedObjectKey = `User_${x + 1}`;
dataStoresApi
.incrementEntry(datastoreName, updatedObjectKey, 10)
.then((value) => {
console.log(
`${updatedObjectKey} now has ${value.robux} robux in their inventory`
);
});
}

테스트하려면 API_KEY 환경 변수를 설정하고 JavaScript 파일을 실행하십시오:


export API_KEY=... \
node updateInventory.js

외부 영구 리더보드

이 섹션에서는 사용자 정보가 순서대로 저장된 데이터 저장소에 나열되고 읽을 수 있으며, 편집을 수행한 후 외부 웹사이트에 게시하여 프로모션수 있는 실제 외부 영구 리더보드 생성 예제를 살펴봅니다.

이 예제에서는 팔로잉가정합니다:

  • 코드 샘플은 데모 목적으로 미리 정의된 사용자 이름 목록을 생성합니다.자체 응용 프로그램의 경우 경험의 실제 사용자 목록을 사용해야 합니다.

  • 코드 샘플은 데모 목적으로 경험에 참여하는 각 사용자에게 50점을 추가합니다.자체 응용 프로그램의 경우 경험 디자인에 따라 규칙을 정의해야 합니다.

높은 레벨API 키 권한을 추가하고 스크립트를 추가하여 파이썬 앱을 빌드할 수 있습니다.

주문형 데이터 저장소에 대한 API 키 권한 추가

예제 앱은 기능을 수행하기 위해 4개의 메서드가 필요합니다: List , Create , UpdateIncrement , 따라서 다음 API 키 권한을 추가해야 합니다:

  • 읽기 방법에 대해 list 메서드를 읽습니다.
  • Write for Create , UpdateIncrement 메서드.

이 예제에서 API 키를 만들 때 다음 작업을 수행하십시오:

  1. 액세스 권한 섹션의 API 시스템 선택 메뉴에서 순서대로 데이터 저장소를 선택합니다.

  2. 대상 경험에서 주문형 데이터 저장소를 읽고 쓰기 위한 API 작업 권한을 추가합니다.

    1. 클릭하십시오 경험 선택을 추가하려면 드롭다운을 클릭하고 대상 경험을 선택합니다.
    2. 경험 운영에서 드롭다운을 확장하여 읽기쓰기 작업을 선택합니다.
  3. 보안 섹션에서 CIDR 표기법을 사용하여 IP 액세스를 키에 명시적으로 설정하고 만료 날짜를 명시적으로 설정하여 키가 해당 날짜 이후에 자동으로 작동을 중지합니다.이 예제에서는 먼저 로컬 테스트를 수행할 계획이 있는 경우 IP 제한을 0.0.0.0/0 으로 설정하여 만료 기간을 30일 로 설정하여 제거할 수 있습니다.

리더보드에 스크립트 추가

예제 앱에 필요한 권한으로 API 키를 만든 후, 앱 기능을 수행하기 위해 JavaScript 코드를 추가해야 합니다.

The 파일은 방법을 정의하는 방법을 보여줍니다 , , 및 방법을 보여줍니다.leaderboard.js 파일은 정의된 메서드를 사용하여 순서도 데이터 저장소의 사용자 항목, 점수 표시, 승리 사용자의 점수 증가 및 리더보드 업데이트를 생성합니다.leaderboard.js 파일은 우주 ID, API 도메인 및 API 키를 구성하기 위한 config.json 파일도 가져옵니다.

ordered_data_stores.js

const axios = require('axios');
const fs = require('fs');
class DataStores {
constructor(configFile) {
this._config = JSON.parse(fs.readFileSync(configFile, 'utf-8'));
}
_H() {
return {
'x-api-key': this._config.api_key,
'Content-Type': 'application/json',
};
}
async list(
datastore,
scope,
pageSize = 10,
orderBy = '',
filter = '',
exclusiveStartKey = ''
) {
const url = `${this._config.api_key_url}universes/${this._config.universe_id}/orderedDataStores/${datastore}/scopes/${scope}/entries`;
const response = await axios.get(url, {
headers: this._H(),
params: {
max_page_size: pageSize,
order_by: orderBy,
filter: filter,
page_token: exclusiveStartKey,
},
});
return response.data;
}
async create(datastore, scope, entry, data) {
const url = `${this._config.api_key_url}universes/${this._config.universe_id}/orderedDataStores/${datastore}/scopes/${scope}/entries`;
const payload = JSON.stringify({ value: 11 });
const response = await axios.post(url, payload, {
headers: this._H(),
params: { id: entry },
});
return response.data;
}
async increment(datastore, scope, entry, incrementBy) {
const url = `${this._config.api_key_url}universes/${this._config.universe_id}/orderedDataStores/${datastore}/scopes/${scope}/entries/${entry}:increment`;
const payload = JSON.stringify({ amount: incrementBy });
const response = await axios.post(url, payload, { headers: this._H() });
return response.data;
}
}
leaderboard.js

const leaderboardEndpoints = require('./ordered_data_stores');
const datastores = new leaderboardEndpoints.DataStores('config.json');
// Variables
const orderedDataStore = 'PlayerScores';
const scope = 'global';
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
// Create an entry and give each new player 50 points for joining the game
entryNames.forEach(async (name) => {
await datastores.create(orderedDataStore, scope, name, 50);
});
// Display the players' scores
datastores.list(orderedDataStore, scope).then((playerScores) => {
console.log(playerScores);
});
// Increment the first player's score for winning the game
datastores.increment(orderedDataStore, scope, entryNames[0], 100);
// Increment all the players' scores for participating in the game
entryNames.forEach(async (name) => {
await datastores.increment(orderedDataStore, scope, name, 10);
});
// Display the updated leaderboard
datastores.list(orderedDataStore, scope).then((updatedPlayerScores) => {
console.log(updatedPlayerScores);
});
구성

{
"universe_id": "",
"api_key_url": "https://apis.roblox.com/datastores/ordered-v1/"
"api_key": ""
}

테스트하려면 API_KEY하고 leaderboard.js:


export API_KEY=... \
node leaderboard.js

테스트를 완료한 후 Roblox 외부 웹사이트에 리더보드를 게시하거나 임베드하여 더 많은 도달을 얻을 수 있습니다.