Please read this quoted post. That’s why I’m saying this, correct me if I’m wrong.
You can save tables in a datastore but to you can also specifically convert something that can’t be saved in a datastore into JSONEncode().
To save:
local success, err
repeat
success, err = pcall(function()
autoSavingStore:SetAsync(key, function()
return game:GetService("HttpService"):JSONEncode(data)
end)
end)
task.wait()
until success
To load:
local function load(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local success, err
local data
repeat
success,err = pcall(function()
data = autoSavingStore:GetAsync(key)
end)
until success or not players:FindFirstChild(player.Name)
if not data then return end
if success then
data = game:GetService("HttpService"):JSONDecode(data)
Hmm. I didn’t know that. Thanks
is that correct?
local players = game:GetService("Players")
local dataStoreService = game:GetService("DataStoreService")
local autoSavingStore = dataStoreService:GetDataStore("F3XAutoSave")
local keyPrefix = "Player: "
local function save(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local data = {}
for i, obj: BasePart in ipairs(workspace:FindFirstChild("Builds"):WaitForChild(player.Name):GetDescendants()) do
if obj:IsA("BasePart") then
table.insert(data, {
-- PART PROPERTIES
obj.Name,
obj.CanCollide,
obj.Position.X,
obj.Position.Y,
obj.Position.Z,
obj.Orientation.X,
obj.Orientation.Y,
obj.Orientation.Z,
obj.Anchored,
obj.Size.X,
obj.Size.Y,
obj.Size.Z,
obj.Color.R,
obj.Color.G,
obj.Color.B,
(string.match(tostring(workspace.Baseplate.TopSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.BottomSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.LeftSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.RightSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.BackSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.FrontSurface), "%.(%w+)$")),
obj.Transparency,
obj.Reflectance,
string.match(tostring(obj.Material), "%.(%w+)$")
})
local success, err
repeat
success, err = pcall(function()
autoSavingStore:SetAsync(key, function()
return game:GetService("HttpService"):JSONEncode(data)
end)
end)
task.wait()
until success
end
end
end
local function load(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local success, err
local data
repeat
success,err = pcall(function()
data = autoSavingStore:GetAsync(key)
end)
until success or not players:FindFirstChild(player.Name)
if not data then return end
if success then
data = game:GetService("HttpService"):JSONDecode(data)
for i, obj in ipairs(data) do
local partInstance = Instance.new("Part")
partInstance.Name=obj[1]
partInstance.CanCollide=obj[2]
partInstance.Position = Vector3.new(obj[3], obj[4], obj[5])
partInstance.CFrame *= CFrame.Angles(math.rad(obj[6]),math.rad(obj[7]),math.rad(obj[8]))
partInstance.Anchored=obj[9]
partInstance.Size = Vector3.new(obj[10], obj[11], obj[12])
partInstance.Color = Color3.new(obj[13],obj[14],obj[15])
partInstance.TopSurface = Enum.SurfaceType[obj[16]]
partInstance.BottomSurface = Enum.SurfaceType[obj[17]]
partInstance.LeftSurface = Enum.SurfaceType[obj[18]]
partInstance.RightSurface = Enum.SurfaceType[obj[19]]
partInstance.BackSurface = Enum.SurfaceType[obj[20]]
partInstance.FrontSurface = Enum.SurfaceType[obj[21]]
partInstance.Transparency = obj[22]
partInstance.Reflectance = obj[23]
partInstance.Material = Enum.Material[obj[24]]
end
else
warn(tostring(err))
end
end
players.PlayerAdded:Connect(load)
players.PlayerRemoving:Connect(save)
game:BindToClose(function()
for i, plr: Player in ipairs(players:GetPlayers()) do
save(plr)
end
end)
Yes, but this is probably not the cause for the error you’re facing.
i still get the error , it is not working
hold on a minute, i forgot to add the httpservice, i will add that rn mb
i added the httpservice variable and applied it but it still doesn’t work…
try changing the colon to an underscore in the keyPrefix
the key is customizable, also when i tried to change it , didnt work.
Hello,
I checked your script and the issue seems to occur because you’re using a function in SetAsync()
(which is what you should use for UpdateAsync
Here is the updated script:
local players = game:GetService("Players")
local dataStoreService = game:GetService("DataStoreService")
local autoSavingStore = dataStoreService:GetDataStore("FX3AutoSave")
local keyPrefix = "Player_"
local function save(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local data = {}
for i, obj: BasePart in ipairs(workspace:FindFirstChild("Builds"):WaitForChild(player.Name):GetDescendants()) do
if obj:IsA("BasePart") then
table.insert(data, {
-- PART PROPERTIES
obj.Name,
obj.CanCollide,
obj.CFrame.X,
obj.CFrame.Y,
obj.CFrame.Z,
obj.Orientation.X,
obj.Orientation.Y,
obj.Orientation.Z,
obj.Anchored,
obj.Size.X,
obj.Size.Y,
obj.Size.Z,
obj.Color.R,
obj.Color.G,
obj.Color.B,
(string.match(tostring(workspace.Baseplate.TopSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.BottomSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.LeftSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.RightSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.BackSurface), "%.(%w+)$")),
(string.match(tostring(workspace.Baseplate.FrontSurface), "%.(%w+)$")),
obj.Transparency,
obj.Reflectance,
string.match(tostring(obj.Material), "%.(%w+)$")
})
local success, err
repeat
success, err = pcall(function()
autoSavingStore:SetAsync(key, data)
end)
task.wait()
until success
if not success then
warn(tostring(err))
end
end
end
end
local function load(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local success, err
local data
repeat
success,err = pcall(function()
data = autoSavingStore:GetAsync(key)
end)
until success or not players:FindFirstChild(player.Name)
if not data then return end
if success then
for i, obj in ipairs(data) do
local partInstance = Instance.new("Part")
partInstance.Name=obj[1]
partInstance.CanCollide=obj[2]
partInstance.CFrame = CFrame.new(obj[3], obj[4], obj[5])
partInstance.CFrame *= CFrame.Angles(math.rad(obj[6]),math.rad(obj[7]),math.rad(obj[8]))
partInstance.Anchored=obj[9]
partInstance.Size = Vector3.new(obj[10], obj[11], obj[12])
partInstance.Color = Color3.new(obj[13],obj[14],obj[15])
partInstance.TopSurface = Enum.SurfaceType[obj[16]]
partInstance.BottomSurface = Enum.SurfaceType[obj[17]]
partInstance.LeftSurface = Enum.SurfaceType[obj[18]]
partInstance.RightSurface = Enum.SurfaceType[obj[19]]
partInstance.BackSurface = Enum.SurfaceType[obj[20]]
partInstance.FrontSurface = Enum.SurfaceType[obj[21]]
partInstance.Transparency = obj[22]
partInstance.Reflectance = obj[23]
partInstance.Material = Enum.Material[obj[24]]
end
else
warn(tostring(err))
end
end
players.PlayerAdded:Connect(load)
players.PlayerRemoving:Connect(save)
game:BindToClose(function()
for i, plr: Player in ipairs(players:GetPlayers()) do
save(plr)
end
end)
Some people mentioned data serialization with JSONEncode & JSONDecode which might be a good practise but imo it makes data harder to manipulate and may fail.
Hope that helps!
thank you so muchhhh, this is worked just like what i wanted!
one question tho, how do i detect if the part have a decal so i add its options too
You could do:
if part:FindFirstChildWhichIsA("Decal") then
local decal = part:FindFirstChildWhichIsA("Decal")
-- save decal --
end
I’d advice you to create a recursive function that serializes the properties into a table outside of the SaveData func, so basically, you’re executing that serialize func on an instance which runs itself on all of the instance’s children and so on until you reach the end.
alright thank you so much for your help!
i dont know where to put it, can you tell me where to put it and if it detected a decal it will make the decal with the options that are saved?
I’ve made several changes in your script, here’s the updated version that should support both BasePart & Decals tho you can add more later!
please note there are already some serialization tools out there (RBLXSerialize - a easy to use and really cool all-in-one Roblox Serializer) for example; tho it was pretty fun working on this one.
local players = game:GetService("Players")
local dataStoreService = game:GetService("DataStoreService")
local autoSavingStore = dataStoreService:GetDataStore("FX3AutoSave")
local keyPrefix = "Player_"
local function serialize(obj: Instance | any)
local _, properties = pcall(function()
local r = {}
r.Name = obj.Name
r.ClassName = obj.ClassName
r.Children = {}
if obj:IsA("BasePart") then
r.CanCollide = obj.CanCollide
r.CFrameX = obj.CFrame.X
r.CFrameY = obj.CFrame.Y
r.CFrameZ = obj.CFrame.Z
r.OrientationX = obj.Orientation.X
r.OrientationY = obj.Orientation.Y
r.OrientationZ = obj.Orientation.Z
r.Anchored = obj.Anchored
r.SizeX = obj.Size.X
r.SizeY = obj.Size.Y
r.SizeZ = obj.Size.Z
r.ColorR = obj.Color.R
r.ColorG = obj.Color.G
r.ColorB = obj.Color.B
r.TopSurface = (string.match(tostring(obj.TopSurface), "%.(%w+)$"))
r.BottomSurface = (string.match(tostring(obj.BottomSurface), "%.(%w+)$"))
r.LeftSurface = (string.match(tostring(obj.LeftSurface), "%.(%w+)$"))
r.RightSurface = (string.match(tostring(obj.RightSurface), "%.(%w+)$"))
r.BackSurface = (string.match(tostring(obj.BackSurface), "%.(%w+)$"))
r.FrontSurface = (string.match(tostring(obj.FrontSurface), "%.(%w+)$"))
r.Transparency = obj.Transparency
r.Reflectance = obj.Reflectance
r.Material = string.match(tostring(obj.Material), "%.(%w+)$")
elseif obj:IsA("Decal") then
-- Handle Decal properties
r.Texture = obj.Texture
r.Face = tostring(obj.Face)
r.Transparency = obj.Transparency
-- Add other Decal properties as needed
else
-- Handle other types of objects if needed
end
return r
end)
for i, v in pairs(obj:GetChildren()) do
table.insert(properties.Children, serialize(v))
end
return properties
end
local function save(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local data = {}
for i, obj: BasePart in ipairs(workspace:FindFirstChild("Builds"):WaitForChild(player.Name):GetChildren()) do
if obj:IsA("BasePart") then
local s, serializedTable = pcall(function()
return serialize(obj)
end)
if typeof(serializedTable) == "string" then
warn(serializedTable)
continue
end
table.insert(data, serializedTable)
end
end
local success, err = pcall(function()
print(data)
autoSavingStore:SetAsync(key, data)
end)
if not success then
warn(tostring(err))
end
end
local function load(player: Player)
local key = keyPrefix .. tostring(player.UserId)
local success, err
local data
repeat
success, err = pcall(function()
data = autoSavingStore:GetAsync(key)
end)
until success or not players:FindFirstChild(player.Name)
if not data then return end
if success then
for i, objData in pairs(data) do
local function createInstance(objData)
local instance
if objData.Name and objData.ClassName then
instance = Instance.new(objData.ClassName)
instance.Name = objData.Name
for property, value in pairs(objData) do
if property ~= "Name" and property ~= "ClassName" and property ~= "Children" then
if property == "CFrameX" or property == "CFrameY" or property == "CFrameZ" then
instance.CFrame = CFrame.new(objData.CFrameX, objData.CFrameY, objData.CFrameZ)
elseif property == "OrientationX" or property == "OrientationY" or property == "OrientationZ" then
instance.Orientation = Vector3.new(objData.OrientationX, objData.OrientationY, objData.OrientationZ)
elseif property == "ColorR" or property == "ColorG" or property == "ColorB" then
instance.Color = Color3.new(objData.ColorR, objData.ColorG, objData.ColorB)
elseif property == "SizeX" or property == "SizeY" or property == "SizeZ" then
instance.Size = Vector3.new(objData.SizeX, objData.SizeY, objData.SizeZ)
else
instance[property] = value
end
end
end
if objData.Children then
for _, childData in ipairs(objData.Children) do
local childInstance = createInstance(childData)
childInstance.Parent = instance
end
end
end
return instance
end
local partInstance = createInstance(objData)
if partInstance then
partInstance.Parent = workspace.Builds:WaitForChild(player.Name) -- Adjust the hierarchy based on your structure
end
end
else
warn(tostring(err))
end
end
players.PlayerAdded:Connect(load)
players.PlayerRemoving:Connect(save)
game:BindToClose(function()
for i, plr: Player in ipairs(players:GetPlayers()) do
save(plr)
end
end)
It might not be very optimized to save everything when a player leaves, i’d say you better to save when there’s a change in the game instead, imagine what may happen if the player tries to save a really big structure and the server closes before? That’d be an issue. But anyway, have fun!
works just like i expected,
about what you said about when a player leaves:
i made it saves every 3 minutes you build something
thank you so much
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.