Skip to content

Lưu dữ liệu ​

data giữ giá trị giữa các lần chơi: xu của người chơi, túi đồ, thời gian tốt nhất trên một đường đua. Chỉ dành cho Script trên server.

Một kho (store) ​

lua
local store = data.store("PlayerData")   -- một kho có tên, riêng cho mỗi game
Phương thứcLàm gì
store:get(key)Giá trị đã lưu dưới key, hoặc nil
store:set(key, value)Lưu value dưới key (nil thì xoá)
store:update(key, fn)Đọc giá trị, đưa cho fn, lưu thứ fn trả về
store:increment(key, delta)Cộng delta (1 nếu bỏ trống) vào một số và trả về tổng mới
store:remove(key)Xoá key

Giá trị có thể là nil, boolean, số, chuỗi, kiểu giá trị (vec3, màu...) và bảng chứa những thứ đó - không có part hay đối tượng - tối đa 16 KB mỗi key.

Mỗi lần gọi đều chờ câu trả lời mà không làm đứng game, và báo lỗi khi thất bại (mạng, cơ sở dữ liệu). Luôn bọc trong pcall.

Lưu xu của người chơi ​

lua
local store = data.store("PlayerData")

players.joined:connect(function(player)
    player.stats.Coins = 0                       -- trước khi có gì được lưu
    if player.userId <= 0 then return end        -- khách (userId -1) không bao giờ được lưu

    local ok, saved = pcall(function()
        return store:get("user_" .. player.userId)
    end)
    if ok and saved then
        player.stats.Coins = saved
    end
end)

players.left:connect(function(player)
    if player.userId <= 0 then return end
    pcall(function()
        store:set("user_" .. player.userId, player.stats.Coins)
    end)
end)

Gõ savedata ở đầu dòng trong trình soạn để có snippet này.

Dùng userId làm key, đừng dùng tên

Người chơi có thể đổi tên. userId của họ không bao giờ đổi. Khách có userId -1, nên kiểm tra userId > 0 trước khi lưu.

Lưu một bảng ​

lua
local profile = {
    coins = 120,
    level = 4,
    inventory = {"Sword", "Shield"},
}
pcall(function() store:set("user_" .. player.userId, profile) end)

Mỗi người chơi lưu một bảng thay vì nhiều key: một yêu cầu thay vì nhiều, và không bao giờ bị lưu dở dang.

Thay đổi an toàn: update và increment ​

update và increment an toàn khi nhiều server cùng đụng vào một key (hai server của cùng game, một bộ đếm chung). update chỉ ghi đè lên đúng giá trị nó đã đọc; nếu trong lúc đó giá trị thay đổi, nó đọc lại và chạy lại fn - nên đừng để fn có tác dụng phụ:

lua
local stats = data.store("Global")
pcall(function() stats:increment("totalWins") end)

pcall(function()
    stats:update("bestTime", function(old)
        if old == nil or myTime < old then return myTime end
        return old
    end)
end)

Khi server tắt ​

Khi một server đóng - cập nhật, khởi động lại, người chơi cuối cùng rời đi - game.closing chạy trước, lúc mọi người chơi vẫn còn trong game, rồi từng người rời đi, nên các hàm players.left của bạn chạy và lưu. Server chờ chúng tối đa 20 giây.

lua
game.closing:connect(function()
    -- lưu những gì game giữ chung cho mọi người (kỷ lục thế giới, ngân hàng chung)
end)

Đọc trước khi chờ

Sau một task.wait trong players.left, người chơi đã đi: hãy đọc những gì cần (player.userId, player.stats.Coins) trước khi chờ.

Lưu ở đâu ​

Game chạy từ KHIM lưu lên KHIM, riêng từng game: game khác không đọc được.

Giới hạn ​

  • 16 KB mỗi giá trị.
  • 64 yêu cầu đang chờ cùng lúc trên một server.
  • update bỏ cuộc và báo lỗi nếu key cứ thay đổi mười hai lần liên tiếp.

JSON ​

json.encode(value, pretty?) đổi một bảng thành chuỗi JSON, json.decode(text) đổi ngược lại - cho cài đặt viết bằng JSON, hoặc một bảng lưu thành một chuỗi:

lua
local text = json.encode({coins = 5, items = {"Sword"}})   -- '{"coins":5,"items":["Sword"]}'
local back = json.decode(text)
print(back.items[1])                                       -- Sword