How to save progress (workspace items)

  1. What do you want to achieve? Keep it simple and clear!
    I want to know how I could make it so that when a player presses a save gui button all the things they have done gets saved, for example, like if they built a base in the game i want to be able to load that progress in when the player joins the game again.

  2. What is the issue? Include screenshots / videos if possible!
    I am not good with tables or datastore.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I have tried Devforum.

can you atleast show any script or what

can you be specific

Let’s assume that there’s a Base folder in the workspace and there are all the parts you want to save. You can store some properties of these parts in the datastore by using a dictionary that stores inherited dictionaries each for one part. These inherited dictionaries will store the properties of these parts. Here’s an example script:

local playerDataStore = game:GetService("DataStoreService"):GetDataStore("PlayerData")

local function savePlayerData(player)
    local playerKey = "player_"..player.UserId
    local playerData = {}
    for _, part in ipairs(game.Workspace.Base:GetChildren()) do
        -- Save any properties you want
        playerData[part.Name] = {
            Position = part.Position,
            Rotation = part.Rotation,
            Color = part.Color,
            Size = part.Size,
            Material = part.Material
            -- etc
        }
    end
    local success, err = pcall(function()
        playerDataStore:SetAsync(playerKey, playerData)
    end)
end

local function loadPlayerData(player)
    local playerKey = "player_"..player.UserId
    local playerData
    
    local success, err = pcall(function()
        playerData = playerDataStore:GetAsync(playerKey)
    end)
    if playerData then
        for partName, partData in ipairs(playerData)
            local newPart = Instance.new("Part")
            newPart.Position = partData.Position
            newPart.Rotation = partData.Rotation
            newPart.Color = partData.Color
            newPart.Material = partData.Material
            newPart.Size = playerData.Size
            -- etc
        end
    end
end

game.Players.PlayerAdded:Connect(function(player)
    loadPlayerData(player)
     -- locate your save button, turn the ResetOnSpawn property of your ScreenGui containing that button to false
    player.PlayerGui:WaitForChild("ScreenGui").SaveButton.MouseButton1Click:Connect(function()
        savePlayerData(game.Players.LocalPlayer)
    end)
end)

You can store whatever properties you want. Sorry if the script contains bugs, I wrote it on phone, just reply if you found one and I’ll fix it.

1 Like

Anyway to have a button that can wipe the data?

Yeah just add a new button to your game then I believe its RemoveAsync or DeleteAsync, i haven’t used datastore in a while. Also the player.PlayerGui:WaitForChild(“ScreenGui”) e.t.c inside that function savePlayerData(game.Players.LocalPlayer) should be savePlayerData(player) since you cannot access LocalPlayer from server scripts.

Hey, my game uses model instead of parts, do you have any ideas how to save that?

I suggest creating a Model folder in replicatedstorage which saves all your assets example Tree, Couch, Lamp. Then You save the model.Name, and Position and Rotation. If you want to be precise you could do CFrame its up to you. Then when the player presses the load button just load the datastore and look through the Assets folder and load that model with the index of the DataStore.

What would that look like in code?

Using @SuchTheLegendary code it would look something like this

local playerDataStore = game:GetService("DataStoreService"):GetDataStore("PlayerData")

local function savePlayerData(player)
	local playerKey = "player_"..player.UserId
	local playerData = {}
	for _, instance in ipairs(game.Workspace.Base:GetChildren()) do\
		playerData[instance.Name] = {
			Position = instance.Position,
			Rotation = instance.Rotation,
			-- CFrame = instance.CFrame -- ["I am not sure if this will work especially saving since it could take up API Requests!"]
			-- etc Data Being Saved
		}
	end
	local success, err = pcall(function()
		playerDataStore:SetAsync(playerKey, playerData)
	end)
end

local function loadPlayerData(player)
	local playerKey = "player_"..player.UserId
	local playerData

	local success, err = pcall(function()
		playerData = playerDataStore:GetAsync(playerKey)
	end)
	if playerData then
		for modelName, modelData in ipairs(playerData) do
			local ModelClone = game:GetService("ReplicatedStorage").Assets[modelName]:Clone()
			ModelClone.Position = modelData.Position
			ModelClone.Rotation = modelData.Rotation
			ModelClone.Parent = workspace.Base
			-- etc
	end
end
game.Players.PlayerAdded:Connect(function(player)
	loadPlayerData(player)
	-- locate your save button, turn the ResetOnSpawn property of your ScreenGui containing that button to false
	player.PlayerGui:WaitForChild("ScreenGui").SaveButton.MouseButton1Click:Connect(function()
		savePlayerData(player)
	end)
end)

Let me know if you run into any issues using this.