Roblox - 如何在 roblox 数据存储中存储大型数组

Roblox- how to store large arrays in roblox datastores

我正在尝试制作一款游戏,玩家可以在其中创建自己的建筑物,然后将它们保存起来供其他玩家查看和玩。但是,roblox 不允许我存储整个创建所需的所有数据(每个积木都有几个属性) 我得到的只是这个错误代码: 104: 无法在 DataStore 中存储数组

任何帮助将不胜感激!

我不确定这是否是最好的方法,但这是我的尝试。下面是一个 table 的例子,你可以使用 table 来存储多个值。我认为你可以使用HttpService的JSONEncode函数将tables转换成字符串(希望可以更有效地保存)

JSONEncode(把砖块的数据变成一个字符串,你可以把它保存到DataStore

local HttpService = game:GetService("HttpService")

-- this is an example of what we'll convert into a json string
local exampleBrick = {
    ["Size"] = Vector3.new(3,3,3),
    ["Position"] = Vector3.new(0,1.5,0),
    ["BrickColor"] = BrickColor.new("White")
    ["Material"] = "Concrete"
}

local brickJSON = HttpService:JSONEncode(exampleBrick)
print(brickJSON)

-- when printed, you'll get something like
-- { "Size": Vector3.new(3,3,3), "Position": Vector3.new(0,1.5,0), "BrickColor": BrickColor.new("White"), "Material": "Concrete"}
-- if you want to refer to this string in a script, surround it with two square brackets ([[) e.g. [[{"Size": Vector3.new(3,3,3)... }]]

JSONDecode(读取字符串并将其转换回砖块)

local HttpService = game:GetService("HttpService")
local brickJSON = [[ {"Size": Vector3.new(3,3,3), "Position": Vector3.new(0,1.5,0), "BrickColor": BrickColor.new("White"), "Material": "Concrete"} ]]

function createBrick(tab)
    local brick = Instance.new("Part")
    brick.Parent = <insert parent here>
    brick.Size = tab[1]
    brick.Position= tab[2]
    brick.BrickColor= tab[3]
    brick.Material= tab[4]
end

local brickData = HttpService:JSONDecode(brickJSON)
createBrick(brickData) --this line actually spawns the brick

如果您想解决任何可能的数据存储错误,也可以将函数包装在 pcall 中。

将整个模型编码成字符串

假设你的播放器'building'是一个模型,你可以使用上面的encode脚本将一个模型里面的所有零件都转换成json字符串保存。

local HttpService = game:GetService("HttpService")
local StuffWeWantToSave = {}

function getPartData(part)
    return( {part.Size,part.Position,part.BrickColor,part.Material} )
end

local model = workspace.Building --change this to what the model is
local modelTable = model:Descendants()
for i,v in pairs(modelTable) do
    if v:IsA("Part") or v:IsA("WedgePart") then
        table.insert(StuffWeWantToSave, HttpService:JSONEncode(getPartData(modelTable[v])))
    end
end

将一个字符串解码成一个完整的模型

这可能会在服务器加载玩家数据时发生。

local HttpService = game:GetService("HttpService")
local SavedStuff = game:GetService("DataStoreService"):GetDataStore("blabla") --I don't know how you save your data, so you'll need to adjust this and the rest of the scripts (as long as you've saved the string somewhere in the player's DataStore)

function createBrick(tab)
    local brick = Instance.new("Part")
    brick.Parent = <insert parent here>
    brick.Size = tab[1]
    brick.Position= tab[2]
    brick.BrickColor= tab[3]
    brick.Material= tab[4]
end

local model = Instance.new("Model") --if you already have 'bases' for the players to load their stuff in, remove this instance.new
model.Parent = workspace

for i,v in pairs(SavedStuff) do
    if v[1] ~= nil then
        CreateBrick(v)
    end
end

FilteringEnabled

如果您的游戏启用过滤功能,请确保只有服务器处理保存和加载数据!! (你可能已经知道了)如果你想让玩家通过点击一个 gui 按钮来保存,让 gui 按钮触发一个 RemoteFunction 将他们基地的数据发送到服务器以将其转换为字符串。

顺便说一句,我不太擅长编写脚本,所以我可能在某些地方犯了错误..祝你好运

Crabway 的回答是正确的,因为 HttpServiceJSONEncodeJSONDecode 方法是解决这个问题的方法。正如 DataStoreServiceData is ... saved as a string in data stores, regardless of its initial type. (https://developer.roblox.com/articles/Datastore-Errors.) 的开发人员参考页面上所说,这解释了您收到的错误,因为您不能简单地将 table 推送到数据店铺;相反,您必须首先使用 JSONEncode.

将 table 的数据编码为字符串

虽然我同意 Crabway 的大部分回答,但我相信函数 createBrick 不会按预期运行。考虑以下简单示例:

httpService = game:GetService("HttpService")
t = {
    hello = 1,
    goodbye = 2
}

s = httpService:JSONEncode(t)
print(s)
> {"goodbye":2,"hello":1}

u = httpService:JSONDecode(s)
for k, v in pairs(u) do print(k, v) end
> hello 1
> goodbye 2

如您所见,JSONDecode 返回的 table 和原来的一样,使用字符串作为键而不是数字索引。因此,createBrick应该这样写:

function createBrick(t)
    local brick = Instance.new("Part")
    brick.Size = t.Size
    brick.Position = t.Position
    brick.BrickColor = t.BrickColor
    brick.Material = t.Material
    -- FIXME: set any other necessary properties.
    -- NOTE: try to set parent last for optimization reasons.
    brick.Parent = t.Parent
    return brick
end

至于对模型进行编码,调用 GetChildren 会生成模型子项的 table,然后您可以循环遍历并对其中所有内容的属性进行编码。请注意,在 Crabway 的回答中,他只考虑了 Parts 和 WedgeParts。您应该使用 object:IsA("BasePart") 计算所有部分,并使用 object:IsA("UnionOperation") 检查并集。以下是一个非常基本的示例,其中我不存储编码数据;相反,我只是想展示如何检查必要的情况。

function encodeModel(model)
    local children = model:GetChildren()
    for _, child in ipairs(children) do
        if ((child:IsA("BasePart")) or (child:IsA("UnionOperation"))) then
            -- FIXME: encode child
        else if (child:IsA("Model")) then
            -- FIXME: using recursion, loop through the sub-model's children.
        end
    end
    return
end

对于 userdata,例如 Vector3s 或 BrickColors,当您使用 JSONEncode 对它们进行编码时,您可能希望将它们转换为字符串。

-- Example: part with "Brick red" BrickColor.
color = tostring(part.BrickColor)
print(string.format("%q", color))
> "Bright red"

我建议@Crabway 所说的,使用 HttpService。

local httpService = game:GetService("HttpService")
print(httpService:JSONEncode({a = "b", b = "c"}) -- {"a":"b","b":"c"}

但是如果您有任何 UserData 值,例如 Vector3s、CFramesColor3s、BrickColors 和 Enum 项,则使用这个library by Defaultio。其实挺好看的

local library = require(workspace:WaitForChild("JSONWithUserdata"))
library:Encode({Vector3.new(0, 0, 0)})

如果您需要一点文档,请查看脚本中的第一条评论:

-- Defaultio

--[[

    This module adds support for encoding userdata values to JSON strings.
    It also supports lists which skip indices, such as {[1] = "a", [2] = "b", [4] = "c"}

    Userdata support is implemented by replacing userdata types with a new table, with keys _T and _V:
        _T = userdata type enum (index in the supportedUserdataTypes list)
        _V = a value or table representing the value

    Follow the examples bellow to add suppport for additional userdata types.

    ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

    Usage example:

        local myTable = {CFrame.new(), BrickColor.Random(), 4, "String", Enum.Material.CorrodedMetal}

        local jsonModule = require(PATH_TO_MODULE)

        local jsonString = jsonModule:Encode(myTable)

        local decodedTable = jsonModule:Decode(jsonString)

--]]