Struggling to save current equipped character and load when respawning - inc into in game places

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    The code that i have used is a character shop which works. The characters can be purchased and equipped. I want to save the players current equipped character (whole rigged and animated body) in my lobby so that when they leave the game then come back to play they load in as their last equipped character - including spawning into my other in-game places to play the games after teleporting off my lobby. Can someone help me what to write and where please? I will really appreciate your help.
  2. What is the issue? Include screenshots / videos if possible!
    Im new to scripting and understand data stores at beginners level but cant seem to make/incorporate the equipped character (newCharacter)-data
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    Ive tried to make equipped character (newCharacter) into data to save but failed. Ive checked the Dev hub, google and my scripting book but cant find anything to help guide me.
    After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!
local replicatedStorage = game:GetService("ReplicatedStorage")
local DatastoreService = game:GetService("DataStoreService") ---data store
local Players = game:GetService("Players")

local datastore = DatastoreService:GetDataStore("MyDataStore") --data store


local characterShop = replicatedStorage.CharacterShop
local characters = characterShop.Characters
local remotes = characterShop.Remote
--i think this is the leaderstats
game.Players.PlayerAdded:Connect(function(player)
	local characterShop = Instance.new("Folder")
	characterShop.Name = "CharacterShop"
	characterShop.Parent = player
	
	local ownedCharacters = Instance.new("Folder")
	ownedCharacters.Name = "Characters"
	ownedCharacters.Parent = characterShop
	
	
	local equippedCharacter = Instance.new("StringValue")
	equippedCharacter.Name = "EquippedCharacter"
	equippedCharacter.Value = "nil"
	equippedCharacter.Parent = characterShop
	
	
	local _characters = nil
	
	local success, err = pcall(function()

		_characters = datastore:GetAsync(player.UserId.."Characters")
	end)
	if _characters == nil then return end
	

	
	if success and _characters ~= nil then
		for i, v in pairs(_characters) do
			local newVal = Instance.new("StringValue")
			newVal.Name = v
			newVal.Parent = ownedCharacters
		end
	else 
		warn(err)
	end 
end)
---up to here
local function playerRemoving(player)
	local _characters = {}
	
	local success, err = pcall(function()
		
		for i, v in pairs(player.CharacterShop.Characters:GetChildren()) do
			table.insert(_characters, v.Name)
		end
		
		datastore:SetAsync(player.UserId.."Characters", _characters)
	end)
	wait(6)
	if success then
		print("Success")
	else
		warn(err)
	end

end
---or ends here
remotes.Buy.OnServerInvoke = function(player, tempName)
	local character = characters:FindFirstChild(tempName)
	
	if character == nil then return end
	
	local price = character.Price.Value
	local currentChar = player.Character
	local pos = currentChar.PrimaryPart.CFrame
	
	if player.CharacterShop.Characters:FindFirstChild(character.Name) and player.CharacterShop.EquippedCharacter.Value == character.Name then
		return "Character Already Equipped"
	elseif player.CharacterShop.Characters:FindFirstChild(character.Name) and player.CharacterShop.EquippedCharacter.Value ~= character.Name then

		local newCharacter = character:Clone()
		newCharacter.Name = player.Name
		player.Character = newCharacter
		newCharacter.Parent = workspace
		newCharacter.PrimaryPart.CFrame = pos
		
		return "Equip"
	elseif not player.CharacterShop.Characters:FindFirstChild(character.Name) and player.CharacterShop.EquippedCharacter.Value ~= character.Name then
		
		if tonumber(player.leaderstats[character.Currency.Value].Value) >= tonumber(price) then
			player.leaderstats[character.Currency.Value].Value -= price
			
			local charcterVal = Instance.new("StringValue")
			charcterVal.Name = character.Name
			charcterVal.Parent = player.CharacterShop.Characters
			
			local newCharacter = character:Clone()
			newCharacter.Name = player.Name
			player.Character = newCharacter
			newCharacter.Parent = workspace
			newCharacter.PrimaryPart.CFrame = pos
			return "Buy"
		else
			return "Failed"
		end

	end
end

Players.PlayerRemoving:Connect(playerRemoving)

game:BindToClose(function()
	wait(6)
	for i, v in pairs(Players:GetPlayers()) do
		playerRemoving(v)
	end
	

end)

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

2 Likes

hmmmm so i’ve changed a lot in your current data store script, and it should save the value of the “EquippedCharacter”, so tell me if it works or no, and tell me the error as well.

local replicatedStorage = game:GetService("ReplicatedStorage")
local dataStoreService = game:GetService("DataStoreService") 

local dataStore = dataStoreService:GetDataStore("MyDataStore") 

local characterShop = replicatedStorage:WaitForChild("CharacterShop")
local characters = characterShop:WaitForChild("Characters")
local remotes = characterShop:WaitForChild("Remote")

local loadedPlayers = {}

game.Players.PlayerAdded:Connect(function(player)
	local charShop = Instance.new("Folder")
	charShop.Name = "CharacterShop"
	charShop.Parent = player

	local ownedCharacters = Instance.new("Folder")
	ownedCharacters.Name = "Characters"
	ownedCharacters.Parent = characterShop

	local equippedCharacter = Instance.new("StringValue")
	equippedCharacter.Name = "EquippedCharacter"
	equippedCharacter.Value = ""
	equippedCharacter.Parent = characterShop
	
	local data
	local success, err = pcall(function()
		data = dataStore:GetAsync(player.UserId.. "Characters")
	end)
	
	if data then
		for i, v in pairs(data) do
			local newVal = Instance.new("StringValue")
			newVal.Name = v
			newVal.Parent = ownedCharacters
		end
		
		if data["EquippedCharacter"] then
			equippedCharacter.Value = data["EquippedCharacter"]
		end
	else 
		warn(err)
	end 
	
	-- Checks if the player is loaded, to avoid data lose; you'll see this again later in the saving data section --
	
	task.wait(2)
	
	loadedPlayers[player.Name] = true 
end)

function CreateDataTable(player)
	local dataTable = {}
	
	-- This is where Equipped Character saves 
	
	if player.CharacterShop:FindFirstChild("EquippedCharacter").Value ~= "" then
		dataTable["EquippedCharacter"] = player.CharacterShop:FindFirstChild("EquippedCharacter").Value
	end
	
	--

	for i, v in pairs(player.CharacterShop.Characters:GetChildren()) do
		table.insert(dataTable, v.Name)
	end

	return dataTable
end

function SaveData(player)
	local dataTable = CreateDataTable(player)

	local userId = player.UserId
	local key = userId .. "Characters"

	if loadedPlayers[player.Name] then -- Sup, checks if the player is loaded, then saves the data
		local success, err = pcall(function()
			dataStore:UpdateAsync(key, function(recentData)
				local newDataTable = recentData or {}

				for name, value in pairs(dataTable) do
					newDataTable[name] = value
				end

				return newDataTable
			end)
		end)
		
		if success then
			print("Data Saved!")
		else
			print("Data Failed To Save: " .. err)
		end
	end
end

remotes.Buy.OnServerInvoke = function(player, tempName)
	local character = characters:FindFirstChild(tempName)

	if character == nil then return end

	local price = character.Price.Value
	local currentChar = player.Character
	local pos = currentChar.PrimaryPart.CFrame

	if player.CharacterShop.Characters:FindFirstChild(character.Name) and player.CharacterShop.EquippedCharacter.Value == character.Name then
		return "Character Already Equipped"
	elseif player.CharacterShop.Characters:FindFirstChild(character.Name) and player.CharacterShop.EquippedCharacter.Value ~= character.Name then

		local newCharacter = character:Clone()
		newCharacter.Name = player.Name
		player.Character = newCharacter
		newCharacter.Parent = workspace
		newCharacter.PrimaryPart.CFrame = pos

		return "Equip"
	elseif not player.CharacterShop.Characters:FindFirstChild(character.Name) and player.CharacterShop.EquippedCharacter.Value ~= character.Name then

		if tonumber(player.leaderstats[character.Currency.Value].Value) >= tonumber(price) then
			player.leaderstats[character.Currency.Value].Value -= price

			local charcterVal = Instance.new("StringValue")
			charcterVal.Name = character.Name
			charcterVal.Parent = player.CharacterShop.Characters

			local newCharacter = character:Clone()
			newCharacter.Name = player.Name
			player.Character = newCharacter
			newCharacter.Parent = workspace
			newCharacter.PrimaryPart.CFrame = pos
			return "Buy"
		else
			return "Failed"
		end

	end
end

game.Players.PlayerRemoving:Connect(function(player)
	SaveData(player)
end)

game:BindToClose(function()
	for i, v in pairs(game.Players:GetPlayers()) do
		v:Kick("Server Shutting Down!")
	end
	
	task.wait(5)
end)
2 Likes

Thankyou for your help.

In your script, i just had to change the charShop back to characterShop to stop getting an error for my client gui script. The changes you have made dont save or respawn the character to the last equipped. I think the equipped Character string is linked to my client gui script which i will paste below which makes the equip button work. The part of the main script which spawns the equipped character is this:

local newCharacter = character:Clone()
newCharacter.Name = player.Name
player.Character = newCharacter
newCharacter.Parent = workspace
newCharacter.PrimaryPart.CFrame = pos

The client-gui script is this:
local replicatedStorage = game:GetService(“ReplicatedStorage”)
local characterShop = replicatedStorage:WaitForChild(“CharacterShop”)
local characters = characterShop:WaitForChild(“Characters”)
local remotes = characterShop:WaitForChild(“Remote”)
local player = game.Players.LocalPlayer

local module3D = require(characterShop:WaitForChild(“Module3D”))

local characterShop = script.Parent
local Info = characterShop:WaitForChild(“Info”)
local scrollFrame = characterShop:WaitForChild(“ScrollingFrame”)
local viewport = Info:WaitForChild(“Viewport”)
local buyBTN = Info:WaitForChild(“BuyButton”)
local priceLabel = Info:WaitForChild(“Price”)
local nameLabel = Info:WaitForChild(“CharacterName”)
local template = scrollFrame:WaitForChild(“Template”)

local selectedTemplate = nil

local function selectTemplate(temp)
selectedTemplate = temp
nameLabel.Text = temp.Name
priceLabel.Text = characters:FindFirstChild(temp.Name).Price.Value

if player.CharacterShop.EquippedCharacter.Value == temp.Name then
	buyBTN.Text = "Equipped"
elseif player.CharacterShop.Characters:FindFirstChild(temp.Name) and player.CharacterShop.EquippedCharacter.Value ~= temp.Name then
	buyBTN.Text = "Equip"
elseif not player.CharacterShop.Characters:FindFirstChild(temp.Name) and player.CharacterShop.EquippedCharacter.Value ~= temp.Name then
	buyBTN.Text = "Buy"
end

for i, v in pairs(viewport:GetChildren()) do
	if v:IsA("ViewportFrame") then
		v:Destroy()
	end
end

local Model3D = module3D:Attach3D(viewport,characters:FindFirstChild(temp.Name):Clone())
Model3D:SetDepthMultiplier(1.2)
Model3D.Camera.FieldOfView = 5
Model3D.Visible = true

game:GetService("RunService").RenderStepped:Connect(function()
	Model3D:SetCFrame(CFrame.Angles(0,tick() % (math.pi * 2),0) * CFrame.Angles(math.rad(-10),0,0))
end)

end

local function buyCharacter()
if selectedTemplate ~= nil then
local result = remotes.Buy:InvokeServer(selectedTemplate.Name)

	if result == "Buy" then 
		buyBTN.Text = "Equipped"
		
	elseif result == "Equip" then
		buyBTN.Text = "Equipped"
	elseif result == "Character Already Equipped" then
		buyBTN.Text = "Equipped"
	end
end

end

for i, v in pairs(characters:GetChildren()) do
local newTemplate = template:Clone()
newTemplate.Name = v.Name
newTemplate.Parent = scrollFrame
newTemplate.Visible = true

local Model3D = module3D:Attach3D(newTemplate.Viewport,v:Clone())
Model3D:SetDepthMultiplier(1.2)
Model3D.Camera.FieldOfView = 5
Model3D.Visible = true

game:GetService("RunService").RenderStepped:Connect(function()
	Model3D:SetCFrame(CFrame.Angles(0,tick() % (math.pi * 2),0) * CFrame.Angles(math.rad(-10),0,0))
end)

newTemplate.MouseButton1Click:Connect(function()
	selectTemplate(newTemplate)
end)

end

buyBTN.MouseButton1Click:Connect(buyCharacter)

1 Like

thats odd… i changed it since you already defined

"local characterShop = “replicatedStorage:WaitForChild(“CharacterShop”)” in line 6.

so i made this to charShop.

also can you check for me if the “EquippedCharacter” value saves? before i try to figure out the problem?

1 Like

Hi Dreivion,

When i use charShop i get the following error:
Characters is not a valid member of Folder “Players.FoxLaBoom.CharacterShop” - Client - CharacterShop_ClientTest:52

However there is an equipped string value that shows up in my replicated storage folder whose parent is CHaracterShop

1 Like

oh i see i made a mistake in the script i gave you (also sorry for late response- i didnt receive any notification)

game.Players.PlayerAdded:Connect(function(player)
	local charShop = Instance.new("Folder")
	charShop.Name = "CharacterShop"
	charShop.Parent = player

	local ownedCharacters = Instance.new("Folder")
	ownedCharacters.Name = "Characters"
	ownedCharacters.Parent = charShop -- This line 

	local equippedCharacter = Instance.new("StringValue")
	equippedCharacter.Name = "EquippedCharacter"
	equippedCharacter.Value = ""
	equippedCharacter.Parent = charShop -- and this line 

that should fix the error now

1 Like

Im really sorry for my late reply. I was working so havnt been able to get on. Ive put your amended script in and it isnt loading the last equipped character skin in.

Another thing ive changed is loading the name of the new skin into the EquippedCharacter Value by adding the following (last line):

local newCharacter = character:Clone()
newCharacter.Name = player.Name
player.Character = newCharacter
newCharacter.Parent = workspace
newCharacter.PrimaryPart.CFrame = pos
player.CharacterShop.EquippedCharacter.Value = character.Name

This now added the equipped character name in the value of the EquippedCharacter string value. I really now dont know how to load this up when i spawn into the game :s
The value remains when i reset my player - but it disappears when i come out of the game and go back in.

BTW there are now no errors when i run your code :slight_smile:

Ok so, does the equipped value saves now? its the most important in this one

Yes it does - the name of the character that i change into when i equip it on the shopGUI shows up in the EquippedCharacter.Value. Its just a matter of saving this when the player leaves the game and loads back in then using this value to look for the model to load the character when spawning into the game.

I really do appreciate your help. :slight_smile:

Alright alright, so to have it saved

  1. When the player chooses a character and equip it, we’re gonna change the EquippedCharacter Value to that Equipped Character’s name (So we can get the character later on)

ex.

equipRemote.OnServerEvent:Connect(function(player, charName)

     local equippedCharacter  = player:WaitForChild("something something, just locate the equippedCharacter Value Instance")

     equippedCharacter.Value = charName -- Ofc you still need to define the EquippedCharacter first
end

The Data Store Script will handle the data (Save it) when the player leaves.

And for the character to load, Its either you have it loaded in when the player joins or load it when the player presses something like “Equip”?

You just need to first

  1. Set the player.Character to the Model of the cloned character
local characterToLoad = characters:FindFirstChild(the Value of the EquippedCharacter):Clone()

player.Character = characterToLoad

-- After you load the character fire a remote to that player 

remote:FireClient(player, -- add a condition like "RefreshCamera")

-- And from a local script, lets get that event

remote.OnClientEvent:Connect(function(state)
    if state == "RefreshCamera" then
         workspace.CurrentCamera.CameraSubject = player.Character.Humanoid
    end
end


-- This isn't a proper script, just a barebone, do the rest.

With much effort, time and manipulation of my script ive managed to make it all work and i want you to know that i am grateful for your help which helped guide me to make this progress.
You are welcome to add me on roblox to try my game out - which wont be completed for a few months so isnt published yet as i am a one man band and new to development - but i just have a good feeling about it.

good to know lol, i dont think i helped a lot tho, its just basics.

You’ll encounter more complex and harder problems in the future so goodluck as well

i would like to try it out when its available

1 Like