Dữ liệu lưu trữ là một dịch vụ bạn có thể sử dụng để lưu và tải dữ liệu người chơi bền vững giữa các phiên người chơi khác nhau. Chúng lưu trữ thông tin quan trọng, như tiến trình hoặc kho đồ của người chơi, và cho phép bạn truy xuất thông tin đó cho người chơi vào lần tiếp theo họ tham gia trò chơi của bạn. Nếu không có dữ liệu lưu trữ, người chơi sẽ mất hết tiến trình của họ mỗi lần rời trò chơi.
Có hai loại dữ liệu lưu trữ: chuẩn và có thứ tự. Hướng dẫn này sử dụng dữ liệu lưu trữ chuẩn, lưu trữ dữ liệu như số, chuỗi và bảng mà không cần phải xếp hạng hoặc sắp xếp.
Sử dụng tệp hướng dẫn dữ liệu lưu trữ Gold Rush data store tutorial - Start .rbxl làm điểm khởi đầu và tệp hướng dẫn dữ liệu lưu trữ Gold Rush data store tutorial - Complete .rbxl làm tài liệu tham khảo, hướng dẫn này cung cấp cho bạn nền tảng cần thiết để lưu tiến trình người chơi và tạo ra những trò chơi nhất quán hơn, bao gồm hướng dẫn về:
- Lưu và tải số vàng mà người chơi đã thu thập.
- Cập nhật giao diện người dùng để hiển thị kho vàng của người chơi.
- Tự động lưu kho vàng của người chơi mỗi 30 giây.
- Lưu vị trí của người chơi khi họ rời trò chơi.
- Khôi phục vị trí của người chơi khi họ tham gia lại trò chơi.
Đến cuối hướng dẫn này, bạn sẽ có hai script với dữ liệu lưu trữ dưới ServerScriptService:
- Một script GoldManager được cập nhật theo dõi, tải và tự động lưu vàng của người chơi.
- Một script PositionManager được cập nhật lưu vị trí của người chơi khi họ rời trò chơi và khôi phục vị trí của họ khi họ quay lại trò chơi.

Kích hoạt quyền truy cập Studio vào dịch vụ API
Dữ liệu lưu trữ không được lưu trữ cục bộ trên thiết bị của bạn, vì vậy trò chơi của bạn phụ thuộc vào việc giao tiếp từ máy chủ đến máy chủ với hệ thống backend của Roblox để sử dụng chúng. Theo mặc định, Studio hạn chế giao tiếp này để ngăn chặn lạm dụng hoặc sử dụng chưa chính xác. Quyền truy cập vào dịch vụ API trong Studio bị tắt cho đến khi bạn rõ ràng cho phép nhằm đảm bảo rằng chỉ các trò chơi đáng tin cậy mới có thể đọc và ghi vào máy chủ backend của Roblox.
Để kích hoạt quyền truy cập Studio vào dịch vụ API để bạn có thể sử dụng dữ liệu lưu trữ:
- Mở tệp Gold Rush data store tutorial - Start .rbxl trong Studio và tạo một bản sao cục bộ.
- Quay lại Studio, đi tới File ⟩ Experience Settings ⟩ Security.
- Bật Enable Studio Access to API Services.
- Lưu thay đổi của bạn.
Tạo một dữ liệu lưu trữ chuẩn
Khi tạo một dữ liệu lưu trữ, bạn nên luôn gọi DataStoreService từ một Script bên máy chủ. Làm như vậy là quan trọng vì:
- Roblox chặn tất cả quyền truy cập dữ liệu lưu trữ từ phía khách hàng để chỉ máy chủ có quyền truy cập và sửa đổi dữ liệu người chơi bền vững.
- Các script bên máy chủ chạy trong một môi trường tập trung, đảm bảo rằng dữ liệu đang được đọc và viết đến dữ liệu lưu trữ của bạn là chính xác và hợp lệ.
- Vì các script bên khách hàng chạy trên thiết bị của người chơi, bất kỳ người chơi nào cũng có thể khai thác trò chơi và lấy hoặc ghi đè dữ liệu của những người chơi khác nếu phía khách có quyền truy cập vào dữ liệu lưu trữ của bạn.
Bạn cũng nên đặt cho dữ liệu lưu trữ của mình một cái tên duy nhất để giữ dữ liệu của bạn được tổ chức và ngăn chặn việc dữ liệu chồng lấp hoặc xung đột trong các dữ liệu lưu trữ khác nhau. Trong hướng dẫn này, dữ liệu lưu trữ lưu và lưu trữ kho vàng của người chơi được gọi là PlayerGold.
Để tạo dữ liệu lưu trữ PlayerGold:
Mở script GoldManager hiện có dưới ServerScriptService.

Ở trên các dịch vụ khác ở đầu script, khởi tạo DataStoreService và gọi GetDataStore với chuỗi "PlayerGold".
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")
Lưu và tải dữ liệu người chơi
Dữ liệu lưu trữ được tạo thành từ các khóa, xác định dữ liệu, và các giá trị, lưu trữ dữ liệu.
| Khóa | Giá trị | |
|---|---|---|
| Mô tả | Một khóa là một định danh duy nhất bạn có thể sử dụng để truy cập một phần dữ liệu cụ thể. Các khóa cho phép bạn tổ chức dữ liệu của mình để bạn có thể dễ dàng quản lý và gỡ lỗi nó. | Một giá trị là dữ liệu thực tế bạn muốn lưu hoặc tải, như kho đồ của người chơi hoặc cài đặt của họ. Các giá trị cho phép bạn lưu tiến trình giữa các phiên, cũng như truy xuất dữ liệu của người chơi mỗi lần họ tham gia trò chơi của bạn. |
| Các định dạng được phép | Chỉ có thể là chuỗi. | Có thể là số, chuỗi, boolean hoặc bảng. |
| Ví dụ | "Player_A", "TopScore", "GameSetting" | 100, "Level_5", true, {gold = 100, level = 5} |
Trong hướng dẫn này, khóa là userId của người chơi và giá trị là số vàng mà họ đã thu thập. Để sử dụng khóa và giá trị này để lưu và tải dữ liệu người chơi:
Trong script GoldManager, thêm một hàm trợ giúp có tên là saveGold để lưu vàng của người chơi vào dữ liệu lưu trữ PlayerGold.
local function saveGold(userId, value)local success, err = pcall(function()-- `userId` là ID duy nhất của người chơi-- `value` là số lượng vàng để lưu cho người chơi đógoldStore:SetAsync(userId, value)end)end- TÙY CHỌNThêm một cảnh báo vào saveGold để in ID của người chơi và một thông báo lỗi. Mặc dù không bắt buộc, bước này là thực hành tốt để dễ dàng gỡ lỗi khi chức năng của bạn gặp lỗi.local function saveGold(userId, value)local success, err = pcall(function()-- `userId` là ID duy nhất của người chơi-- `value` là số lượng vàng để lưu cho người chơi đógoldStore:SetAsync(userId, value)end)if not success thenwarn("[SAVE ERROR] Không thể lưu vàng cho", userId, ":", err)endend
Sửa đổi sự kiện onPlayerAdded để tải vàng của người chơi khi họ lần đầu tham gia trò chơi. Hàm onPlayerAdded được cập nhật:
- Cố gắng tải nội dung bên trong dữ liệu lưu trữ PlayerGold. Nó trả về số vàng đã lưu của người chơi hoặc một giá trị là 0 nếu người chơi không có vàng hoặc chưa từng chơi trò chơi trước đó.
- Cung cấp cho bạn một nhật ký gỡ lỗi để giúp bạn dễ dàng gỡ lỗi mã của mình. Nhật ký gỡ lỗi này bao gồm số vàng đã lưu của người chơi tham gia, hoặc một thông báo lỗi nếu onPlayerAdded không thể truy cập vào dữ liệu lưu trữ.
- Cập nhật giao diện người dùng để hiển thị số vàng đã lưu của người chơi trên màn hình của họ.
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("Không thể tải vàng cho", player.Name)endendSửa đổi sự kiện onPlayerRemoving để gọi hàm saveGold bạn đã tạo trước đó và lưu vàng của người chơi khi họ rời trò chơi.
local function onPlayerRemoving(player)local userId = player.UserIdif playerGold[userId] thensaveGold(userId, playerGold[userId])endend
Tự động lưu dữ liệu người chơi
Tự động lưu dữ liệu của một người chơi là một thực hành tốt vì nó bảo vệ người chơi khỏi việc mất dữ liệu của họ. Nếu bạn chỉ lưu dữ liệu của người chơi khi họ rời trò chơi với onPlayerRemoving, bạn có thể mất tiến trình mới nhất của họ nếu họ bị ngắt kết nối đáng tiếc khỏi máy chủ.
Để tự động lưu dữ liệu của người chơi:
Tạo một hằng số mới để xác định tần suất mà bạn muốn trò chơi tự động lưu dữ liệu của người chơi. Một hằng số là một biến mà giá trị của nó không thay đổi trong khi trò chơi đang chạy. Bạn có thể sử dụng hằng số này để tham chiếu đến khoảng thời gian tự động lưu trong toàn bộ script của bạn và dễ dàng điều chỉnh tần suất tự động lưu.
-- Số này là tính bằng giâylocal AUTOSAVE_INTERVAL = 30Thêm một coroutine tự động lưu vào hàm onPlayerAdded hiện có để tạo một vòng lặp nền chạy trong khi người chơi đang ở trong trò chơi. Một coroutine là một hàm chạy bất đồng bộ; nó có thể tạm dừng tại một số điểm nhất định, tiếp tục từ nơi nó đã dừng lại và chạy song song với các phần khác của script của bạn mà không làm chậm chúng.
Trong script này, vòng lặp nền của coroutine tự động lưu chờ một khoảng thời gian bằng số giây trong hằng số AUTOSAVE_INTERVAL của bạn, sau đó gọi hàm saveGold mà bạn đã tạo trước đó.
coroutine.wrap(function()while player.Parent dotask.wait(AUTOSAVE_INTERVAL)if playerGold[userId] thenprint("[AUTOSAVE] Đang lưu", playerGold[userId], "vàng cho", player.Name)saveGold(userId, playerGold[userId])endendend)()
Lưu và tải vị trí người chơi
Để lưu vị trí của một người chơi, làm việc với Character của họ thay vì đối tượng Player bản thân. Character của một người chơi đại diện cho mô hình vật lý của họ trong thế giới 3D và có tọa độ cho vị trí hiện tại và hướng của họ, trong khi đối tượng Player chỉ đại diện cho tài khoản người dùng.
Vì dữ liệu lưu trữ chỉ có thể lưu các kiểu dữ liệu cơ bản như số, chuỗi và bảng, bạn không thể lưu trữ trực tiếp các đối tượng phức tạp như giá trị Vector3 hoặc CFrame. Để lưu vị trí của một người chơi, bạn cần tách nó thành ba số riêng biệt (tọa độ X, Y và Z) và lưu chúng riêng lẻ. Khi tải vị trí sau đó, bạn có thể tái tạo lại Vector3 bằng cách sử dụng các tọa độ đã lưu.
Để lưu và tải vị trí của nhân vật:
Mở script PositionManager hiện có dưới ServerScriptService.
Ở đầu script, khởi tạo DataStoreService và gọi GetDataStore với chuỗi "PlayerPosition".
local DataStoreService = game:GetService("DataStoreService")local positionStore = DataStoreService:GetDataStore("PlayerPosition")Thêm một hàm trợ giúp có tên là savePosition mà nhận vào userId của người chơi và một vị trí Vector3. Vì bạn không thể lưu các giá trị Vector3 trực tiếp, hãy chuyển đổi vị trí thành một bảng chứa các số 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- TÙY CHỌNThêm một cảnh báo vào savePosition để in một thông báo lỗi và tên của người chơi mà bạn không thể lưu vị trí. Mặc dù không bắt buộc, bước này là thực hành tốt để dễ dàng gỡ lỗi khi chức năng của bạn gặp lỗi.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("Không thể lưu vị trí cho", player.Name, ":", err)endend
Thêm một hàm trợ giúp khác có tên là loadPosition để tải các tọa độ đã lưu của một người chơi trong dữ liệu lưu trữ PlayerPosition. Sử dụng PivotTo để khôi phục vị trí của nhân vật trong thế giới. Vì vị trí đã lưu của người chơi được trả về dưới dạng một bảng, bạn phải tái tạo một Vector3 và sau đó chuyển đổi nó thành một CFrame để di chuyển nhân vật.
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("Khôi phục vị trí cho", player.Name)character:PivotTo(CFrame.new(pos))elseif not success thenwarn("Không thể tải vị trí cho", player.Name)endendSửa đổi sự kiện onPlayerAdded để thiết lập logic vị trí cho mỗi người chơi tham gia trò chơi của bạn. Bên trong hàm onPlayerAdded được cập nhật:
- CharacterAdded gọi loadPosition để khôi phục vị trí cuối cùng được biết đến của nhân vật khi nhân vật của người chơi xuất hiện.
- CharacterRemoving gọi savePosition để lưu vị trí hiện tại của nhân vật người chơi nếu họ bị xóa khỏi trò chơi.
- GetPivot lấy vị trí chính xác của nhân vật trong thế giới vào lúc họ bị xóa.
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)
Mã cuối cùng
Xem các đoạn mã sau đây cho các script GoldManager và PositionManager hoàn chỉnh. Bạn có thể dán và chạy chúng trực tiếp trong tệp Gold Rush save data tutorial - Start .rbxl trong Studio.
GoldManager
-- Get services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local DataStoreService = game:GetService("DataStoreService")
-- Remote event to update the UI
local uiEvent = ReplicatedStorage:WaitForChild("UIEvent")
-- Data store for saving the player's gold chunks
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- Table to store the player's gold chunks for a single session
local playerGold = {}
-- Constants
local GOLD_VALUE = 10 -- How much each gold chunk is worth
local GOLD_REGEN_DELAY = 2 -- The delay before a chunk respawns (in seconds)
local AUTOSAVE_INTERVAL = 30 -- How often the player's chunks are saved (in seconds)
-- Function to handle the player collecting a gold chunk
local function processGoldTouch(chunk, player)
-- Hide the chunk when the player collects it
chunk.Parent = nil
-- Add the chunk to the player's session gold score
local userId = player.UserId
playerGold[userId] = (playerGold[userId] or 0) + GOLD_VALUE
print(player.Name, "now has", playerGold[userId], "gold")
-- Update the UI to reflect the new gold score for this session
uiEvent:FireClient(player, {
gold = playerGold[userId],
doTween = true,
showAlert = false
})
-- Wait a bit and then respawn the gold chunk that was just collected
task.delay(GOLD_REGEN_DELAY, function()
chunk.Parent = workspace.GoldChunks
end)
end
-- Loop through all parts tagged with "Gold" and connect them to touch detection
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
-- Function to save the player's gold to the data store
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
end)
if not success then
warn("Không thể lưu vàng cho", player.Name, ":", err)
end
end
-- Function to handle the player joining the game
local function onPlayerAdded(player)
local userId = player.UserId
print(player.Name, "has joined the game")
-- Try to load the player's gold from the data store
local success, storedGold = pcall(function()
return goldStore:GetAsync(userId)
end)
if success then
-- Set the current session gold score using the data store value for the player
local currentGold = storedGold or 0
playerGold[userId] = currentGold
-- Update the UI with the data store value for the player
uiEvent:FireClient(player, {
gold = currentGold,
doTween = false,
showAlert = false
})
print("Loaded", currentGold, "gold for", player.Name)
else
-- Notify the player their gold couldn't be loaded
uiEvent:FireClient(player, { showAlert = true })
warn("Không thể tải vàng cho", player.Name)
end
-- Start the autosave coroutine to save the player's gold every 30 seconds
coroutine.wrap(function()
while player.Parent do
task.wait(AUTOSAVE_INTERVAL)
if playerGold[userId] then
saveGold(player, playerGold[userId])
print("Đang tự động lưu", playerGold[userId], "vàng cho", player.Name)
end
end
end)()
end
-- Function to handle the player leaving the game
local function onPlayerRemoving(player)
local userId = player.UserId
print(player.Name, "has left the game")
-- Check if the player's gold was tracked
if playerGold[userId] then
-- Save the player's gold to the data store before they leave
saveGold(player, playerGold[userId])
end
end
-- Connect the joining and leaving player events
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
PositionManager
-- Get services
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- Data store for saving the player's position
local positionStore = DataStoreService:GetDataStore("PlayerPosition")
-- Function to save the player's position as a table of {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("Không thể lưu vị trí cho", player.Name, ":", err)
end
end
-- Function to load the player's last saved position and move their character
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("Khôi phục vị trí cho", player.Name)
character:PivotTo(CFrame.new(pos))
elseif not success then
warn("Không thể tải vị trí cho", player.Name)
end
end
-- Function to handle the player joining the game
local function onPlayerAdded(player)
local userId = player.UserId
-- Try to load the player's position when their character spawns
player.CharacterAdded:Connect(function(character)
loadPosition(player, character)
end)
-- Save the player's position when their character is removed
player.CharacterRemoving:Connect(function(character)
local pos = character:GetPivot().Position
savePosition(player, pos)
end)
end
Players.PlayerAdded:Connect(onPlayerAdded)