Os armazéns de dados são um serviço que você pode usar para salvar e carregar dados persistentes dos jogadores em diferentes sessões de jogo. Eles armazenam informações importantes, como o progresso ou inventário de um jogador, e permitem que você as recupere para o jogador na próxima vez que ele entrar no seu jogo. Sem os armazéns de dados, um jogador perderia todo o seu progresso sempre que saísse do jogo.
Existem dois tipos de armazéns de dados: padrão e ordenados. Este tutorial usa armazéns de dados padrão, que armazenam dados como números, strings e tabelas que não precisam ser classificados ou ordenados.
Usando o tutorial de armazém de dados Gold Rush - Início no arquivo .rbxl como ponto de partida e o tutorial de armazém de dados Gold Rush - Completo como referência, este tutorial fornece a base necessária para salvar o progresso do jogador e criar jogos mais consistentes, incluindo orientações sobre:
- Salvar e carregar a quantidade de ouro que um jogador coletou.
- Atualizar a interface do usuário para exibir o inventário de ouro do jogador.
- Salvar automaticamente o inventário de ouro do jogador a cada 30 segundos.
- Salvar a posição do jogador quando ele sai do jogo.
- Restaurar a posição do jogador quando ele voltar ao jogo.
Ao final deste tutorial, você deve ter dois scripts com armazéns de dados dentro de ServerScriptService:
- Um script atualizado GoldManager que rastreia, carrega e salva automaticamente o ouro do jogador.
- Um script atualizado PositionManager que salva a posição do jogador quando ele sai do jogo e restaura sua posição quando ele volta ao jogo.

Habilitar o acesso do Studio aos serviços de API
Os armazéns de dados não são armazenados localmente no seu dispositivo, então seu jogo depende da comunicação servidor-a-servidor com o backend da Roblox para usá-los. Por padrão, o Studio restringe essa comunicação para evitar abusos ou usos acidentais. O acesso aos serviços de API no Studio está desativado até que você o habilite explicitamente para garantir que apenas jogos confiáveis possam ler e gravar nos servidores de backend da Roblox.
Para habilitar o acesso do Studio aos serviços de API para que você possa usar armazéns de dados:
- Abra o arquivo do tutorial de armazém de dados Gold Rush - Início no Studio e crie uma cópia local.
- De volta ao Studio, vá em Arquivo ⟩ Configurações da Experiência ⟩ Segurança.
- Ative Habilitar Acesso do Studio aos Serviços de API.
- Salve suas alterações.
Criar um armazém de dados padrão
Ao criar um armazém de dados, você deve sempre chamar o DataStoreService a partir de um Script do lado do servidor. Isso é importante porque:
- A Roblox bloqueia todo o acesso ao armazém de dados do cliente, de modo que apenas o servidor tem permissão para acessar e modificar dados persistentes de jogadores.
- Scripts do lado do servidor são executados em um ambiente centralizado, garantindo que os dados lidos e gravados no seu armazém de dados sejam precisos e válidos.
- Como os scripts do lado do cliente são executados no dispositivo do jogador, qualquer jogador poderia potencialmente explorar o jogo e roubar ou sobrescrever os dados de outros jogadores se o cliente tivesse acesso aos seus armazéns de dados.
Você também deve dar um nome exclusivo ao seu armazém de dados para manter seus dados organizados e prevenir sobreposições ou conflitos entre diferentes armazéns de dados. Neste tutorial, o armazém de dados que salva e armazena o inventário de ouro do jogador é chamado de PlayerGold.
Para criar o armazém de dados PlayerGold:
Abra o script GoldManager existente em ServerScriptService.

Sob os outros serviços na parte superior do script, inicialize o DataStoreService e chame GetDataStore com a string "PlayerGold".
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")
Salvar e carregar dados do jogador
Os armazéns de dados são compostos por chaves, que identificam dados, e valores, que armazenam dados.
| Chave | Valor | |
|---|---|---|
| Descrição | Uma chave é um identificador único que você pode usar para acessar um pedaço específico de dados. As chaves permitem que você organize seus dados para que possa gerenciá-los e depurá-los facilmente. | Um valor é o dado real que você deseja salvar ou carregar, como o inventário de um jogador ou suas configurações. Os valores permitem que você armazene o progresso entre as sessões, bem como recupere os dados do jogador na próxima vez que ele entrar no seu jogo. |
| Formatos permitidos | Somente strings. | Podem ser números, strings, booleanos ou tabelas. |
| Exemplos | "Player_A", "TopScore", "GameSetting" | 100, "Level_5", true, {gold = 100, level = 5} |
Neste tutorial, a chave é o userId do jogador e o valor é a quantidade de ouro que ele coletou. Para usar essa chave e valor para salvar e carregar os dados do jogador:
No script GoldManager, adicione uma função auxiliar chamada saveGold para salvar o ouro do jogador no armazém de dados PlayerGold.
local function saveGold(userId, value)local success, err = pcall(function()-- `userId` é o ID único do jogador-- `value` é a quantidade de ouro a ser salva para aquele jogadorgoldStore:SetAsync(userId, value)end)end- OPCIONALAdicione um aviso à função saveGold que imprime a ID do jogador e uma mensagem de erro. Embora não seja obrigatório, esse passo é uma boa prática para facilitar a depuração caso sua função falhe.local function saveGold(userId, value)local success, err = pcall(function()-- `userId` é o ID único do jogador-- `value` é a quantidade de ouro a ser salva para aquele jogadorgoldStore:SetAsync(userId, value)end)if not success thenwarn("[ERRO DE SALVAMENTO] Não foi possível salvar o ouro de", userId, ":", err)endend
Modifique o evento onPlayerAdded para carregar o ouro do jogador quando ele entrar no jogo pela primeira vez. A função onPlayerAdded atualizada:
- Tenta carregar o conteúdo dentro do armazém de dados PlayerGold. Ele retorna ou o ouro salvo do jogador ou um valor de 0 se o jogador não tiver ouro ou não tiver jogado o jogo antes.
- Fornece um registro de depuração para ajudá-lo a depurar seu código mais facilmente. Esse registro de depuração inclui o ouro salvo do jogador que está entrando, ou uma mensagem de erro se onPlayerAdded não estiver conseguindo acessar o armazém de dados.
- Atualiza a interface do usuário para exibir o ouro salvo do jogador na tela.
local function onPlayerAdded(player)local userId = player.UserIdlocal success, storedGold = pcall(function()return goldStore:GetAsync(userId)end)if success thenlocal currentGold = storedGold or 0playerGold[userId] = currentGolduiEvent:FireClient(player, {gold = currentGold,doTween = false,showAlert = not success})elseuiEvent:FireClient(player, { showAlert = true })warn("Não foi possível carregar ouro para", player.Name)endendModifique o evento onPlayerRemoving para chamar a função saveGold que você criou anteriormente e salvar o ouro do jogador quando ele deixar o jogo.
local function onPlayerRemoving(player)local userId = player.UserIdif playerGold[userId] thensaveGold(userId, playerGold[userId])endend
Salvar dados do jogador automaticamente
Salvar automaticamente os dados de um jogador é uma boa prática porque protege o jogador de perder seus dados. Se você salvar os dados do jogador apenas quando ele deixar o jogo com onPlayerRemoving, pode perder seu progresso mais recente se ele se desconectar inesperadamente do servidor.
Para salvar automaticamente os dados do jogador:
Crie uma nova constante para determinar com que frequência você deseja que seu jogo salve automaticamente os dados do jogador. Uma constante é uma variável cujo valor não muda enquanto o jogo está em execução. Você pode usar essa constante para se referir ao intervalo de salvamento automático ao longo do seu script e ajustar facilmente a frequência de salvamento automático.
-- Este número está em segundoslocal AUTOSAVE_INTERVAL = 30Adicione uma coroutine de salvamento automático à função onPlayerAdded existente para criar um loop em segundo plano que roda enquanto o jogador estiver dentro do jogo. Uma coroutine é uma função que roda de forma assíncrona; ela pode pausar em determinados pontos, retomar de onde parou e rodar em paralelo com outras partes do seu script sem bloqueá-las.
Neste script, o loop em segundo plano de salvamento automático espera pelo número de segundos em sua constante AUTOSAVE_INTERVAL, e então chama a função saveGold que você criou anteriormente.
coroutine.wrap(function()while player.Parent dotask.wait(AUTOSAVE_INTERVAL)if playerGold[userId] thenprint("[SALVAMENTO AUTOMÁTICO] Salvando", playerGold[userId], "ouro para", player.Name)saveGold(userId, playerGold[userId])endendend)()
Salvar e carregar a posição do jogador
Para salvar a posição de um jogador, trabalhe com o Character em vez do objeto Player em si. O Character de um jogador representa seu modelo físico no mundo 3D e possui as coordenadas de sua posição e orientação atuais, enquanto o objeto Player representa apenas a conta do usuário.
Como os armazéns de dados só podem salvar tipos de dados básicos como números, strings e tabelas, você não pode armazenar diretamente objetos complexos como valores Vector3 ou CFrame. Para salvar a posição de um jogador, você precisa dividi-la em três números separados (as coordenadas X, Y e Z) e salvá-los individualmente. Ao carregar a posição mais tarde, você pode reconstruir o Vector3 usando as coordenadas salvas.
Para salvar e carregar a posição do personagem:
Abra o script PositionManager existente em ServerScriptService.
Na parte superior do script, inicialize o DataStoreService e chame GetDataStore com a string "PlayerPosition".
local DataStoreService = game:GetService("DataStoreService")local positionStore = DataStoreService:GetDataStore("PlayerPosition")Adicione uma função auxiliar chamada savePosition que recebe o userId de um jogador e uma posição Vector3. Como você não pode salvar valores Vector3 diretamente, converta a posição em uma tabela de números X, Y, Z.
local function savePosition(player, position)local userId = player.UserIdlocal success, err = pcall(function()positionStore:SetAsync(userId, {position.X, position.Y, position.Z})end)end- OPCIONALAdicione um aviso à função savePosition que imprime uma mensagem de erro e o nome do jogador para quem você falhou em salvar a posição. Embora não seja obrigatório, esse passo é uma boa prática para facilitar a depuração caso sua função falhe.local function savePosition(player, position)local userId = player.UserIdlocal success, err = pcall(function()positionStore:SetAsync(userId, {position.X, position.Y, position.Z})end)if not success thenwarn("Não foi possível salvar a posição de", player.Name, ":", err)endend
Adicione outra função auxiliar chamada loadPosition para carregar as coordenadas salvas de um jogador no armazém de dados PlayerPosition. Use PivotTo para restaurar a posição do personagem no mundo. Como a posição salva do jogador é retornada como uma tabela, você tem que reconstruir um Vector3 e então convertê-lo em um CFrame para mover o personagem.
local function loadPosition(userId, character)local userId = player.UserIdlocal success, savedCoords = pcall(function()return positionStore:GetAsync(userId)end)if success and savedCoords thenlocal pos = Vector3.new(savedCoords[1], savedCoords[2], savedCoords[3])print("Posição restaurada para", player.Name)character:PivotTo(CFrame.new(pos))elseif not success thenwarn("Não foi possível carregar a posição de", player.Name)endendModifique o evento onPlayerAdded para configurar a lógica de posição para cada jogador que entra no seu jogo. Dentro da função onPlayerAdded atualizada:
- CharacterAdded chama loadPosition para restaurar a última localização conhecida do personagem quando o personagem de um jogador nasce.
- CharacterRemoving chama savePosition para salvar a posição atual do personagem do jogador se ele for removido do jogo.
- GetPivot obtém a localização exata do personagem no mundo no momento em que ele é removido.
local function onPlayerAdded(player)local userId = player.UserIdplayer.CharacterAdded:Connect(function(character)loadPosition(player, character)end)player.CharacterRemoving:Connect(function(character)local pos = character:GetPivot().PositionsavePosition(player, pos)end)endPlayer.PlayerAdded:Connect(onPlayerAdded)
Código final
Veja os seguintes snippets de código para os scripts completos GoldManager e PositionManager. Você pode colá-los e executá-los diretamente no arquivo Gold Rush - tutorial de salvamento de dados - Início no Studio.
GoldManager
-- Obter serviços
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local DataStoreService = game:GetService("DataStoreService")
-- Evento remoto para atualizar a interface do usuário
local uiEvent = ReplicatedStorage:WaitForChild("UIEvent")
-- Armazém de dados para salvar os pedaços de ouro do jogador
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- Tabela para armazenar os pedaços de ouro do jogador para uma única sessão
local playerGold = {}
-- Constantes
local GOLD_VALUE = 10 -- Quanto vale cada pedaço de ouro
local GOLD_REGEN_DELAY = 2 -- O atraso antes que um pedaço reapareça (em segundos)
local AUTOSAVE_INTERVAL = 30 -- Com que frequência os pedaços do jogador são salvos (em segundos)
-- Função para lidar com o jogador coletando um pedaço de ouro
local function processGoldTouch(chunk, player)
-- Esconder o pedaço quando o jogador o coleta
chunk.Parent = nil
-- Adicionar o pedaço à pontuação de ouro da sessão do jogador
local userId = player.UserId
playerGold[userId] = (playerGold[userId] or 0) + GOLD_VALUE
print(player.Name, "agora tem", playerGold[userId], "ouro")
-- Atualizar a interface do usuário para refletir a nova pontuação de ouro para esta sessão
uiEvent:FireClient(player, {
gold = playerGold[userId],
doTween = true,
showAlert = false
})
-- Esperar um pouco e depois reaparecer o pedaço de ouro que foi coletado
task.delay(GOLD_REGEN_DELAY, function()
chunk.Parent = workspace.GoldChunks
end)
end
-- Loop através de todas as partes etiquetadas como "Gold" e conectá-las à detecção de toque
for _, chunk in ipairs(CollectionService:GetTagged("Gold")) do
chunk.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
processGoldTouch(chunk, player)
end
end)
end
-- Função para salvar o ouro do jogador no armazém de dados
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
end)
if not success then
warn("Não foi possível salvar o ouro de", player.Name, ":", err)
end
end
-- Função para lidar com o jogador entrando no jogo
local function onPlayerAdded(player)
local userId = player.UserId
print(player.Name, "entrou no jogo")
-- Tentar carregar o ouro do jogador do armazém de dados
local success, storedGold = pcall(function()
return goldStore:GetAsync(userId)
end)
if success then
-- Definir a pontuação de ouro da sessão atual usando o valor do armazém de dados para o jogador
local currentGold = storedGold or 0
playerGold[userId] = currentGold
-- Atualizar a interface do usuário com o valor do armazém de dados para o jogador
uiEvent:FireClient(player, {
gold = currentGold,
doTween = false,
showAlert = false
})
print("Carregado", currentGold, "de ouro para", player.Name)
else
-- Notificar o jogador que seu ouro não pôde ser carregado
uiEvent:FireClient(player, { showAlert = true })
warn("Não foi possível carregar ouro para", player.Name)
end
-- Iniciar a coroutine de salvamento automático para salvar o ouro do jogador a cada 30 segundos
coroutine.wrap(function()
while player.Parent do
task.wait(AUTOSAVE_INTERVAL)
if playerGold[userId] then
saveGold(player, playerGold[userId])
print("Salvando automaticamente", playerGold[userId], "de ouro para", player.Name)
end
end
end)()
end
-- Função para lidar com o jogador saindo do jogo
local function onPlayerRemoving(player)
local userId = player.UserId
print(player.Name, "saiu do jogo")
-- Verificar se o ouro do jogador foi rastreado
if playerGold[userId] then
-- Salvar o ouro do jogador no armazém de dados antes de sair
saveGold(player, playerGold[userId])
end
end
-- Conectar os eventos de entrada e saída dos jogadores
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
PositionManager
-- Obter serviços
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- Armazém de dados para salvar a posição do jogador
local positionStore = DataStoreService:GetDataStore("PlayerPosition")
-- Função para salvar a posição do jogador como uma tabela de {X, Y, Z}
local function savePosition(player, position)
local userId = player.UserId
local success, err = pcall(function()
positionStore:SetAsync(userId, {position.X, position.Y, position.Z})
end)
if not success then
warn("Não foi possível salvar a posição de", player.Name, ":", err)
end
end
-- Função para carregar a última posição salva do jogador e mover seu personagem
local function loadPosition(player, character)
local userId = player.UserId
local success, savedCoords = pcall(function()
return positionStore:GetAsync(userId)
end)
if success and savedCoords then
local pos = Vector3.new(savedCoords[1], savedCoords[2], savedCoords[3])
print("Posição restaurada para", player.Name)
character:PivotTo(CFrame.new(pos))
elseif not success then
warn("Não foi possível carregar a posição de", player.Name)
end
end
-- Função para lidar com o jogador entrando no jogo
local function onPlayerAdded(player)
local userId = player.UserId
-- Tentar carregar a posição do jogador quando seu personagem nascer
player.CharacterAdded:Connect(function(character)
loadPosition(player, character)
end)
-- Salvar a posição do jogador quando seu personagem for removido
player.CharacterRemoving:Connect(function(character)
local pos = character:GetPivot().Position
savePosition(player, pos)
end)
end
Players.PlayerAdded:Connect(onPlayerAdded)