К основному содержанию
скилл CX Codex

roblox-datastores · gamedev-skills — скилл для Claude Code: DataStore без потерь

Учит агента сохранять данные игрока в Roblox через DataStoreService: загрузка на входе, сохранение на выходе и в BindToClose, ретраи. Пригодится, когда прогресс теряется.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-datastores -a claude-code
Открыть на GitHub

Что делает roblox-datastores

Скилл задаёт рабочий цикл для серверного кода: GetDataStore по имени стора, ключ вида "Player_" .. player.UserId, загрузка на PlayerAdded, сохранение на PlayerRemoving и на BindToClose. Внутри готовые паттерны на Luau: чтение в pcall, запись через UpdateAsync, ретрай с backoff, счётчик на IncrementAsync, лидерборд на OrderedDataStore с GetSortedAsync.

Главная мысль про отказоустойчивость. Если GetAsync упал по сети, скилл велит помечать сессию и не сохранять вовсе, иначе дефолты затрут настоящий прогресс. По той же причине SetAsync не годится для read-modify-write: два сервера перетирают ключ. Это повод проверить свой обработчик PlayerAdded, если на обнуление уже жаловались.

Перед первым запуском включите Studio Access to API Services в настройках опубликованного места, а тестируйте на отдельном плейсе: Studio бьёт по тем же живым данным, что и игроки. Работает только из серверных Script, из LocalScript нет. Общий Luau, ремоуты и разбиение клиент/сервер скилл не разбирает, для этого есть roblox-luau.

Какие задачи решает

  • Загрузить монеты и инвентарь игрока при входе на сервер
  • Пережить выключение сервера без потери прогресса через BindToClose
  • Переписать сохранение с SetAsync на UpdateAsync, чтобы два сервера не перетирали ключ
  • Собрать лидерборд по монетам на OrderedDataStore
  • Обернуть сетевые вызовы в pcall и добавить ретраи

Примеры запросов агенту

  • Напиши серверный Script, который грузит монеты игрока через GetAsync под pcall и сохраняет их на PlayerRemoving.
  • Сделай лидерборд по монетам на OrderedDataStore и покажи топ-10 через GetSortedAsync.
  • Потерял прогресс при рестарте сервера — добавь сохранение на BindToClose и защиту от перезаписи дефолтами.

Как установить roblox-datastores

1Через Skills CLI (Vercel)

npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-datastores -a claude-code

2Вручную: положить файлы

~/.claude/skills/roblox-datastores/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/roblox-datastores/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора77

game-jam Помогает спланировать разработку игры под дедлайн геймджема: распределить часы, урезать лишние механики и подготовить релиз к отправке. CX Codex +1 5 700установок unity-animation Ведёт агента по Animator Controllers в Unity 6.3 LTS: параметры, переходы, blend trees, слои и humanoid IK. Пригодится, когда один персонаж должен ходить, прыгать и целиться из общей стейт-машины. CX Codex +1 5 800установок threejs-gltf-loading Загружает glTF и GLB в three.js и проигрывает запечённые клипы через AnimationMixer, включая сжатые DRACO, Meshopt и KTX2. Пригодится, когда модель вроде загрузилась, а на экране пусто. CX Codex +1 5 600установок unity-physics Помогает настроить 3D-физику в Unity 6.3 LTS: движение через Rigidbody, рейкасты, триггеры и слои коллизий. Пригодится при написании скриптов перемещения и проверок сцены. CX Codex +1 5 600установок unity-input-system Скилл для Claude Code, который настраивает ввод в Unity 6.3 LTS через Input System: action maps, PlayerInput, чтение значений в C#. CX Codex +1 5 700установок unity-scriptableobjects Помогает проектировать архитектуру данных в Unity 6.3 LTS на базе ScriptableObject. Настраивает общие переменные, каналы событий и реестры без менеджеров-одиночек. CX Codex +1 5 700установок phaser-arcade-physics Настраивает перемещение, прыжки и столкновения в 2D-играх на Phaser 4 через физический движок Arcade Physics. Помогает писать контроллеры и собирать группы объектов. CX Codex +1 5 500установок threejs-scene-setup Настраивает базовую сцену three.js и помогает найти причины пустого или чёрного canvas. Нужен при старте проекта, ресайзе, цикле рендеринга и OrbitControls. CX Codex +1 5 500установок

Другие версии roblox-datastores

Похожие

roblox-server-data TabooHarmony Скилл для работы с общими данными между серверами Roblox: лидерборды, рассылки, MemoryStore, сезоны и гильдии. CX Codex +1 1 700установок roblox-game-development greedychipmunk Скилл для разработки игр на Roblox: помогает писать скрипты на Luau, собирать игровые системы и готовить проект к релизу. CX Codex +1 2 200установок roblox-security TabooHarmony Скилл проверяет серверный код Roblox на уязвимости, дюпы валюты и доверие клиенту. Пригодится перед релизом плейса или при аудите RemoteEvent и сохранений. CX Codex +1 1 900установок roblox-animation nonlooped Скилл для анимаций персонажей Roblox: треки, IK-позы, события по маркерам и твины интерфейса. Пригодится, когда нужно собрать локомоцию или эмоцию и не сломать приоритеты. CX Codex +1 392установок roblox-mcp nonlooped Скилл подключает ИИ-клиент к Roblox Studio по MCP: агент читает дерево игры, правит скрипты, запускает Luau и плейтест. CX Codex +1 317установок mm2-roblox-analytics-toolkit reason-machines Скилл для аналитики Murder Mystery 2: инвентарь, статистика матчей и разбор стратегий через ИИ-рекомендации. Пригодится, если ведёте учёт скинов и хотите видеть винрейт по ролям. CX Codex +1 2 400установок

Рядом в теме «Геймдев и 3D: Unity, Unreal, Godot, Blender»

Всё по теме «Геймдев и 3D: Unity, Unreal, Godot, Blender» →

Вопросы о roblox-datastores

Как установить roblox-datastores в Claude Code?

Выполните npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-datastores -a claude-code. Скилл появится в ~/.claude/skills/roblox-datastores/SKILL.md.

Что делает roblox-datastores?

Даёт агенту паттерны для DataStoreService: загрузка на входе, сохранение на выходе и при выключении сервера, pcall вокруг сетевых вызовов, ретраи и лидерборды на OrderedDataStore.

Чем это отличается от roblox-luau?

roblox-luau про общий Luau, сервисы и ремоуты. Этот скилл берёт только персистентность: GetAsync, SetAsync, UpdateAsync, BindToClose и OrderedDataStore.

Исходный текст

SKILL.md · Apache-2.0
---
name: roblox-datastores
description: >
  Persist player data in Roblox with DataStoreService: GetDataStore, GetAsync/
  SetAsync/UpdateAsync/IncrementAsync wrapped in pcall, load-on-join and
  save-on-leave plus BindToClose, retries, and OrderedDataStore leaderboards. Use
  when saving or loading persistent data in a Roblox experience — when the user
  mentions DataStore, DataStoreService, GetAsync, SetAsync, UpdateAsync, save player
  data, or leaderboards. For general Luau scripting use roblox-luau.
---

# Roblox DataStores

Persist data across sessions in Roblox with `DataStoreService`: loading on join,
saving on leave and shutdown, safe updates, retries, and ordered stores for
leaderboards. Server-side only.

## When to use

- Use to save/load player progress (coins, inventory, levels), build persistent
  leaderboards, or fix data loss, overwrites, and throttling.
- Use when server code calls `DataStoreService`, `GetDataStore`, `GetAsync`,
  `SetAsync`, `UpdateAsync`, or `GetOrderedDataStore`.

**When *not* to use:** general scripting, services, remotes, the client/server
split → `roblox-luau`. High-frequency temporary state (matchmaking, per-round) →
memory stores (a different service). Engine-agnostic persistence theory →
`save-systems`.

## Core workflow

1. **Enable Studio access once.** In a published place, File → Experience Settings →
   Security → *Enable Studio Access to API Services* (use a separate test place; Studio
   hits the same live data as players). DataStores work only from server `Script`s,
   never `LocalScript`s.
2. **Get a store, then read/write by key.** `DataStoreService:GetDataStore("Name")`;
   key per player is usually `"Player_" .. player.UserId`.
3. **Wrap every call in `pcall`.** `GetAsync`/`SetAsync`/`UpdateAsync` are network
   calls that can fail; an unguarded failure errors the thread and risks data loss.
4. **Load on `PlayerAdded`, save on `PlayerRemoving`, and also `BindToClose`.** A
   leaving player and a shutting-down server both need a final save.
5. **Prefer `UpdateAsync` for read-modify-write** (multi-server safe) over `SetAsync`
   (blind overwrite). On a failed load, do **not** overwrite with defaults — abort
   the save so you don't wipe good data.
6. **Use `OrderedDataStore` for ranked data** (leaderboards) via `GetSortedAsync`.
   Test by joining, changing data, rejoining, and confirming it persisted.

## Patterns

### 1. Load on join (pcall-guarded)

```lua
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local store = DataStoreService:GetDataStore("PlayerData")

local DEFAULT = { Coins = 0, Level = 1 }

Players.PlayerAdded:Connect(function(player)
    local key = "Player_" .. player.UserId
    local ok, data = pcall(function()
        return store:GetAsync(key)
    end)

    if not ok then
        -- Load FAILED (network). Do not treat as a new player; flag so we never save
        -- over their real data with defaults.
        warn("Load failed for", player.Name, data)
        player:SetAttribute("DataLoaded", false)
        return
    end

    player:SetAttribute("DataLoaded", true)
    local profile = data or DEFAULT          -- nil == genuinely new player
    applyToLeaderstats(player, profile)
end)
```

### 2. Save with UpdateAsync (multi-server safe)

```lua
-- UpdateAsync reads the latest value, then writes what the callback returns.
-- The callback MUST NOT yield (no task.wait, no further Async calls inside it), and it
-- can run more than once if another server writes the key first, so keep it pure.
local function savePlayer(player)
    -- Save only after a confirmed load. `~= true` also covers a player who leaves while
    -- GetAsync is still in flight (attribute still nil), which `== false` would miss.
    if player:GetAttribute("DataLoaded") ~= true then return end
    local key = "Player_" .. player.UserId
    local newData = gatherDataFor(player)    -- a plain table of serializable values

    local ok, err = pcall(function()
        store:UpdateAsync(key, function(old)
            -- merge/decide here; return nil to cancel the write
            return newData
        end)
    end)
    if not ok then warn("Save failed for", player.Name, err) end
end
```

### 3. Save on leave AND on shutdown

```lua
Players.PlayerRemoving:Connect(savePlayer)

-- BindToClose runs when the server shuts down; save everyone still in.
-- The server waits at most 30 seconds for it, so save in parallel and yield until done.
game:BindToClose(function()
    local players = Players:GetPlayers()
    local remaining = #players
    if remaining == 0 then return end
    for _, player in players do
        task.spawn(function()
            savePlayer(player)
            remaining -= 1
        end)
    end
    while remaining > 0 do task.wait() end
end)
```

### 4. Retry with backoff (transient failures)

```lua
local function withRetry(fn, attempts)
    attempts = attempts or 3
    for i = 1, attempts do
        local ok, result = pcall(fn)
        if ok then return true, result end
        if i < attempts then task.wait(2 ^ i) end   -- 2s, 4s, ... backoff
    end
    return false
end

local ok, data = withRetry(function() return store:GetAsync(key) end)
```

Retry only operations that are safe to repeat. A failed write is not proof the write did
not happen: the server may simply have missed the response. Re-running an `UpdateAsync`
that writes the full saved state is harmless; re-running `IncrementAsync` can add twice.
When the outcome matters, confirm it with an uncached read (`DataStoreGetOptions` with
`UseCache = false`) before retrying.

### 5. Increment a counter

```lua
-- IncrementAsync is a convenience for integer read-modify-write (still wrap it).
local ok, newTotal = pcall(function()
    return store:IncrementAsync("Visits_" .. player.UserId, 1)
end)
```

### 6. Leaderboard with OrderedDataStore

```lua
local boards = DataStoreService:GetOrderedDataStore("Coins")

-- Write a player's score (call when it changes, not every frame).
pcall(function() boards:SetAsync("Player_" .. player.UserId, coins) end)

-- Read the top 10, descending.
local ok, pages = pcall(function()
    return boards:GetSortedAsync(false, 10)   -- ascending=false → highest first
end)
if ok then
    for rank, entry in ipairs(pages:GetCurrentPage()) do
        print(rank, entry.key, entry.value)   -- entry.value is the number
    end
end
```

## Pitfalls

- **Unhandled failure wipes progress** → always `pcall` Async calls; on a failed
  *load*, mark the session and refuse to *save* so defaults never overwrite real data.
- **`SetAsync` race between servers** → two servers writing the same key can clobber
  each other. Use `UpdateAsync` for read-modify-write so each write sees the latest.
- **Yielding inside the `UpdateAsync` callback** → the callback can't call
  `task.wait` or other Async functions; compute the new value beforehand and return it.
- **Side effects inside the `UpdateAsync` callback** → Roblox re-runs the callback when
  another server changed the key between read and write, so granting items, firing
  remotes, or incrementing counters there can happen twice. Act after the call returns.
- **Saving a player who left mid-load** → `PlayerRemoving` can fire while `GetAsync` is
  still yielding. Gate saves on "load succeeded", not on "load did not fail".
- **No `BindToClose` save** → players in the server at shutdown lose unsaved progress;
  add `game:BindToClose` and wait for saves to finish within its budget.
- **Throttling / "too many requests"** → respect per-key and per-minute limits; don't
  save on every value change. Batch and save on a timer / on leave. `GetAsync` is
  cached for about four seconds, so immediate re-reads may be stale. Studio Run mode
  uses its own lower static limits; Roblox recommends testing rate limits in Team Create.
- **Storing non-serializable values** → only JSON-serializable data persists: numbers,
  strings, booleans, and tables with string/number keys. `Instance`s, `Vector3`,
  `CFrame`, and functions do not — serialize them to plain tables first.
- **Testing without API access** → DataStore requests in Studio error (writes report
  `StudioAccessToApisNotAllowed`) until *Enable Studio Access to API Services* is on (and
  they don't work from a `LocalScript`).
- **`DataStoreKeyInfo` is nil for ordered stores** → `OrderedDataStore` doesn't
  support versioning/metadata; use a regular `DataStore` when you need those.

## References

- For session locking (preventing duplicate data across servers), versioning/
  metadata with `DataStoreSetOptions`, ordered-store pagination
  (`AdvanceToNextPageAsync`), the key error codes and request limits, and
  Right-to-be-Forgotten compliance, read `references/sessions-and-limits.md`.

## Related skills

- `roblox-luau` — services, instances, events, and the server/client model.
- `save-systems` — engine-agnostic serialization, slots, and migration.

© gamedev-skills · Apache-2.0 · gamedev-skills/awesome-gamedev-agent-skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой