Trying to recreate the script of saving clothes in datastore that is posted on scriptinghelpers.org

hello there, I am an builder who want to make system that custom startercharacter saves the changed clothes that is worn inside the game and when startercharacter dies or rejoins, the clothing would save, I have searched for how to make that thing on roblox studio but had no luck other then this I found, there is some articles in scriptinghelpers site but I suck at scripts that I cannot understand it. anyway here is an link of that articles.

that one roblox scriptinghelpers article about how to save clothes in datastore

also in that article, there is two persons who have shown script or suggestion of script in that article, but I canā€™t understand those at this moment, anyway here is these scripts

(first page of script that Zoltra have posted first, it have errors of " error: ServerScriptService.clothesData:7: attempt to index nil with 'WaitForChild '"

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")


game.Players.PlayerAdded:Connect(function(player)
    local shirtId = player.Character:WaitForChild("Shirt").ShirtTemplate
    local pantsId = player.Character:WaitForChild("Pants").PantsTemplate

    local data
    local success, errormessage = pcall(function()
        data = myDataStore:GetAsync(player.UserId, {shirtId, pantsId})
    end)
    if success then
        shirtId = data[1]
        pantsId = data[2]
    else
        warn(errormessage)
    end

end)


game.Players.PlayerRemoving:Connect(function(player)
    local shirtId = player.Character:WaitForChild("Shirt").ShirtTemplate
    local pantsId = player.Character:WaitForChild("Pants").PantsTemplate

    local success, errormessage = pcall(function()
        myDataStore:SetAsync(player.UserId,{shirtId, pantsId})
    end)
    if success then
        print ("Player Data successfully saved")
    else
        print ("Error saving data")
        warn(errormessage)
    end
end)

also the other script suggestion that VerdommeMan have posted in that article.

thatā€™s all I could find of in that article, it was posted in 2 years ago and Iā€™m trying to recover that thing to work, thank you peoples.

-mari

2 Likes

I think that you are getting that error, cause the Shirt or Pants doesnt exist yet when you are trying to reach it. Or the name its different than Shirt or Pants, would be better to look for them by using its Class, and waiting for the Character Appearance fully loaded, like this:

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAppearanceLoaded:Wait()
	
	local shirtId = player.Character:FindFirstChildOfClass("Shirt").ShirtTemplate
	local pantsId = player.Character:FindFirstChildOfClass("Pants").PantsTemplate
	
	local data
	local success, errormessage = pcall(function()
		data = myDataStore:GetAsync(player.UserId, {shirtId, pantsId})
	end)
	if success then
		if data then
			warn(data)
			shirtId = data[1]
			pantsId = data[2]
		else
			warn("no data for player yet")
		end
	else
		warn(errormessage)
	end
end)

But, about the function for PlayerRemoving, that wont work as you need.
You cant get the Character of the Player when they are leaving the game, so this will never work, cause you are trying to access the character when theres no character, and then trying to get the Shirt or Pants of a Character that doesnt exist anymore:

game.Players.PlayerRemoving:Connect(function(player)
	local shirtId = player.Character:FindFirstChildOfClass("Shirt").ShirtTemplate

Probably you want to use CharacterRemoving instead of PlayerRemoving. But that will trigger everytime the player dies too. And you dont want to save the datastore everytime a player diesā€¦

I would try a different approach, in which, everytime a player changes their cloths, you store that data into a server table, and when the player leaves, you take that table and save it into the datastore and after the successful saving you clean up the playerā€™s table.

1 Like

I think the problem may be that when you are loading the data you shouldnā€™t set the data, you should also return the myDataStore:GetAsync(player.UserId, {shirtId, pantsId}). Another factor is changing the errormessage to the returned data. Maybe try this? I have to get off for now but if you have questions Iā€™ll be back on later.

(first page of script that Zoltra have posted first, it have errors of " error: ServerScriptService.clothesData:7: attempt to index nil with 'WaitForChild '"

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")


game.Players.PlayerAdded:Connect(function(player)
    local shirtId = player.Character:WaitForChild("Shirt").ShirtTemplate
    local pantsId = player.Character:WaitForChild("Pants").PantsTemplate

    local data
    local success, Gotdata = pcall(function()
        return myDataStore:GetAsync(player.UserId, {shirtId, pantsId})
    end)
    if success and Gotdata then
        data = Gotdata
        shirtId = data[1]
        pantsId = data[2]
    else
        warn(errormessage)
    end

end)


game.Players.PlayerRemoving:Connect(function(player)
    local shirtId = player.Character:WaitForChild("Shirt").ShirtTemplate
    local pantsId = player.Character:WaitForChild("Pants").PantsTemplate

    local success, errormessage = pcall(function()
        myDataStore:SetAsync(player.UserId,{shirtId, pantsId})
    end)
    if success then
        print ("Player Data successfully saved")
    else
        print ("Error saving data")
        warn(errormessage)
    end
end)
1 Like

hello there, thanks for trying to help me with that, but for some reasons it still does not work in way,
also for that startercharacter in my game, itā€™s Shirt and Pants it have is named ā€œShirtā€ and ā€œPantsā€,
and also there is some mannequins that changes the startercharacterā€™s Shirt and Pant when clicked, and the main problem is, those changed clothings does not save even with that script, and I donā€™t know where I should put that script you posted in here,
also I want to use CharacterRemoving so it might trigger everytime player dies or something. I donā€™t know much but your help will make it improve it so much.
also you said about saving clothe data into server table and save it into the datastore and after successful saving it cleans up the playerā€™s table, I donā€™t know how itā€™s supposed to be work or made, thought it would be awesome if you could help me out, thanks!

also I share you this screenshot of in-developing game Iā€™m trying to implementing the cloth saving script into that game, hope it can help fixing the script.

(also the ā€œdatastore cannot be access from clientā€ message is from that script you suggested but I put that script in StarterCharacterScripts as localscript, let me know if there is something wrong in there.)
-mari

2 Likes

Sure Iā€™ll be glad to help.
Well, now I see you are sure that the instances are called exactly Shirt and Pants and you are using a Model called StarterCharacter inside StarterPlayer folder, good.

Yup, you cant save onto the DataStore from a client script (Local Script) You should handle the system on server side by using a normal script in ServerScriptService.

The script I sent is intended to be used in the server script in ServerScriptService. Its only handling when the player joins, reading the data from DataStore and IF there is previous data it will be loaded, otherwise it only prints a text saying ā€œno data for player yetā€.

Now, paste in here the script that handles the changing clothing. That script will be responsible for creating a table for the player and storing the values of the clothing during the game session.

1 Like

hey there, I have pasted that script on the ServerScriptService as normal script, however it still doesnā€™t seems to work still, and the warning message doesnā€™t seems to appear in the OutPut, and we are making that script in ServerScriptService for make table and storing the value of the shirt/pants template right? but I couldnā€™t understand that due to my low scripting skill, help is still gladly needed thank you, also there is screenshot of pasted script and proof that no warning have been logged in the output, it would be awesome if you could help me with, thank you.

1 Like

That error is from a different script, in which you are trying to load an asset.

I understand you are starting in scripting and dont worry thats pretty cool and Iā€™d love to help.

Lets start from zero, I tested this script and does exactly what you want, when player change Pants or Shirt its gets saved for the player, when leaves its saved on DataStore, and when joins agains their character will spawn with the right clothes they saved previously.

Create a new blank file and paste this script in ServerScriptService, make sure it has DataStore saving feature enabled for the place and publish it to Roblox:

local DataStoreService = game:GetService("DataStoreService")
local PlayerCloths_DSS = DataStoreService:GetDataStore("PlayerCloths")

-- WHEN PLAYER JOINS - READ DATASTORE
game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Wait()
	
	warn("Creating Folder and Values for player:", player)
	local newFolder = Instance.new("Folder")
	newFolder.Name = "MyCloths"
	newFolder.Parent = player

	local shirtVal = Instance.new("StringValue")
	shirtVal.Name = "ShirtVal"
	shirtVal.Parent = newFolder
	
	local pantsVal = Instance.new("StringValue")
	pantsVal.Name = "PantsVal"
	pantsVal.Parent = newFolder
	
	warn("Waiting for Shirt and Pants to exist in player")
	local shirtInstance = player.Character:WaitForChild("Shirt")
	local pantsInstance = player.Character:WaitForChild("Pants")
	
	local data
	local success, errormessage = pcall(function()
		data = PlayerCloths_DSS:GetAsync(player.UserId, {shirtInstance, pantsInstance})
	end)
	if success then
		if data then
			warn("DSS data exist for player, updating")
			shirtInstance.ShirtTemplate = data[1]
			pantsInstance.PantsTemplate = data[2]
			shirtVal.Value = data[1]
			pantsVal.Value = data[2]
		else
			warn("New player, no data in DSS yet")
			-- Setting the default StarterCharacter data
			shirtVal.Value = shirtInstance.ShirtTemplate
			pantsVal.Value = pantsInstance.PantsTemplate
		end
	else
		warn(errormessage)
	end
	
	-- Listening when Shirt or Pants get changed by server side
	shirtInstance.Changed:Connect(function(prop)
		if prop == "ShirtTemplate" then
			shirtVal.Value = shirtInstance.ShirtTemplate
		end
	end)
	pantsInstance.Changed:Connect(function(prop)
		if prop == "PantsTemplate" then
			pantsVal.Value = pantsInstance.PantsTemplate
		end
	end)
end)


-- WHEN PLAYER LEAVES - SAVES DATASTORE
game.Players.PlayerRemoving:Connect(function(player)
	local success, errormessage = pcall(function()
		PlayerCloths_DSS:SetAsync(player.UserId, {player.MyCloths.ShirtVal.Value, player.MyCloths.PantsVal.Value} )
	end)
	if success then
		print ("Player Data successfully saved")
	else
		print ("Error saving data")
		warn(errormessage)
	end

end)

And create 2 parts in workspace called, ShirtBTN and PantsBTN. Place a ClickDetector inside them. Its just for quick testing, the buttons will change the cloths of the player randomly on click. And for the buttons system just paste this script in ServerScriptService too as a different script than the previous one:

local InsertService = game:GetService("InsertService")

local ShirtsIDs = {6680877688, 7713626261, 11612658975, 6780970545}
local PantsIDs = {6314613214, 6752704115, 5053949817, 11679597207}

game.Workspace:WaitForChild("ShirtBTN").ClickDetector.MouseClick:Connect(function(player)
	local chooseRandom = ShirtsIDs[math.random(1, #ShirtsIDs)]
	player.Character.Shirt.ShirtTemplate = InsertService:LoadAsset(chooseRandom).Shirt.ShirtTemplate
end)

game.Workspace:WaitForChild("PantsBTN").ClickDetector.MouseClick:Connect(function(player)
	local chooseRandom = PantsIDs[math.random(1, #PantsIDs)]
	player.Character.Pants.PantsTemplate = InsertService:LoadAsset(chooseRandom).Pants.PantsTemplate
end)

I just copied some IDs from Roblox Catalog randomly for the Pants and Shirts, you can replace the ids, but thats not important, cause we need to connect YOUR changing clothing script weā€™ll not use this random one, this is only for testing

Im sending you the file so would be easier to test, a lil video. Im using a blank model as the StarterCharacter womanRig for the test:

The place file:
SaveChar.rbxl (61.6 KB)

1 Like

thank you for your help, I have pasted these scripts as you said, however things doesnā€™t still come in the way, the BTN parts doesnā€™t change the StarterCharacterā€™s clothing at all, (but I want player to wear clothes that isnā€™t worn randomly so it could be more awesome if you could edit the random pick system on BTN part, and also there will be four mannequins that gives player the clothings, so we can make four BTN parts with different numbers like ShirtBTN1 and ShirtBTN2 parts and make it work.) and also there is ā€œHTTP 403 Forbiddenā€ error from 2nd script and ā€œUnable to assign property Value. string expected, got Instanceā€ error from 1st script.
and thanks for showing me file of that while I was writing this, I appreciate that.
also I will show you one screenshot of that in-dev clothing part you suggested to me and output messages. thank you so much.

-mari

1 Like

Nonono, I dont mean you should change the shirts/pants randomly. I stated that the buttons I added are for testing. So you can see the Saving system script works, and you can use it with your own changing clothing system.

What I want is to help you step by step, if you download the file I sent, and enable Datastore saving, and you make it to work is the first step, cause the script works.

Then, try to understand whats happening in the script. Then in your game, make sure you are changing the Shirt/Pants on server side, and my script will save that into datastore. If you use the script found in the file I sent. Or copy the script again from my message (I edited an error of the previous one)


this is an footage of me bringing that StarterCharacter I use in wanted game but it does not work for odd reasons, probably because character is an r6 or somethingā€¦ who knows
(I have re-tested it with r15 StarterCharacter that you used and it works fine, also when I was testing with both StarterCharacter, I uploaded the game and allowed https request while testing with both, through.
-mari again

You replaced my blank StarterCharacter with yours? The Shirt instance in yours is named ā€œPantsā€, and the Pants is named ā€œShirtā€. Thats why the error says trying to find PantsTemplate in Shirtā€¦ xD
Shift the names of your Pants and Shirt first

fixed that name issues through, but now when I join the game my character is wearing default clothes for brief second and gets n@aked, and buttons still not work and shows ā€œHTTP 403 Forbiddenā€ error even through I have HTTP allowed in my game,
also here is model of that StarterCharacter Iā€™m using mainly, itā€™s R6 and have worn Shirt named Shirt and Pants named Pants. here is the model, and thank you very much for helping me out by ton.
AshiStarterCharacterModel.rbxm (10.6 KB)

The player character being naked means that the String placed in the ShirtTemplate is not a valid URL. You should provide a string like this: "http://www.roblox.com/asset/?id=6680877684" so the Shirt or Pants be loaded correctly.

Probably the data in the datastore has been saved as a number and not as a string URL.
Add prints to show what DataStore has when player joins to debug, or check the Shirt/Pants properties in explorer too.

A string will be stored in a StringValue inside the Player, the script I already gave you called ā€œSavingScriptā€ its already handling that:

  • When player joins creates a Folder called MyCloths and placed in Player along with StringValues called ShirtVal and PantsVal to store the cloths the player is using.
  • Read the DSS and perform different tasks depending on new player or rejoined
  • And listening when the Shirt or Pants has been changed by Server to rewrite the String values inside MyCloths folder.
  • When player leaves, takes the values inside MyCloths folder and save them into DSS

You gotta make sure that you are changing the Shirt and Pants template with a button or something on ServerSide so my savingScript read that and when player leaves save it.
And make sure you are providing a correct URL string to be placed in the Shirt and Pants template.

If you have the Roblox Catalog IDs of the Shirts and Pants you wanna use, you can get the right URL string with this, just replace the IDs:

local ShirtURL = game:GetService("InsertService"):LoadAsset(6680877688).Shirt.ShirtTemplate
local PantsURL = game:GetService("InsertService"):LoadAsset(6314613214).Pants.PantsTemplate

To make things easier, just place this folder in Workspace. Play test, click some buttons those will change your shirt and pants, then leave test to save the DataStore, join again to verify it was saved.
Then look for the script inside the folder and replace the IDs with the ones you collected from Roblox Catalog:
ClothBTNs.rbxm (4.3 KB)

hello there, your script kinda helped me with that but when I changed the IDs in the script, now whole thing broken, and I even used an datastore editor but I suck at using that, also I want to use these codes listed below in that clotheBTNs folder script, here I list them below.

Shirts= 7843411811, 9056088978, 8224770109, 7307508033
pants= 6594989145, 10023059908, 5814743514, 6594989145

sorry for this much of inconvinces, you are great, anyway. I will also show you the footage of me click the BTN parts but it does not work and nor doesnā€™t print anythings in output, it would be very awesome if you could help me with it, thank you so much.

(I was taking two hours to respond due to eating dinner in outside.)
-Mari

Its broken cause those are not Catalog IDs, those are Library IDs, the direct texture ID.

In the example I gave you I was directly copying the ID from Catalog, then by script collecting the texture ID. In your case you dont need to collect the texture ID from the Catalog ID, cause you already have the texture ID, replace ClothBTNScript with this:

local InsertService = game:GetService("InsertService")

--local ShirtsIDs = {6680877688, 7713626261, 11612658975, 6780970545}
--local PantsIDs = {6314613214, 6752704115, 5053949817, 11679597207}

local URLstart = "http://www.roblox.com/asset/?id="

local ShirtsIDs = {7843411811, 9056088978, 8224770109, 7307508033}
local PantsIDs = {6594989145, 10023059908, 5814743514, 6594989145}

for i, btn in pairs(game.Workspace:WaitForChild("ClothsBTNs"):WaitForChild("Shirts"):GetChildren()) do
	--local ShirtURL = InsertService:LoadAsset(ShirtsIDs[i]).Shirt.ShirtTemplate
	btn:WaitForChild("ClickDetector").MouseClick:Connect(function(player)
		--player.Character.Shirt.ShirtTemplate = ShirtURL
		player.Character.Shirt.ShirtTemplate = URLstart..tostring(ShirtsIDs[i])
	end)
end

for i, btn in pairs(game.Workspace:WaitForChild("ClothsBTNs"):WaitForChild("Pants"):GetChildren()) do
	--local PantsURL = InsertService:LoadAsset(PantsIDs[i]).Pants.PantsTemplate
	btn:WaitForChild("ClickDetector").MouseClick:Connect(function(player)
		--player.Character.Pants.PantsTemplate = PantsURL
		player.Character.Pants.PantsTemplate = URLstart..tostring(PantsIDs[i])
	end)
end

I disabled all lines in the script that search the Library ID by using the Catalog ID. And now its directly using the Library IDs that you have.

Testing your IDs video:

hey thank you so much for you help in total! the things finally come into my hand and there is four pairs of buttons that can change the clothings in my game and saves it! let me show you the footage of that.

however, could you please tell me how to make more pairs of buttons like that? then I may gladly gift you with Solutions, and you can finally move on for others help, if I stumble upon problem with this thing, I may call you for need. thank you.

-very happy mari

1 Like

Its looking good! Good job at ordering them, cause the example I provided its kinda hardcoded and unordered, and Im wodering how you did ordered each button to be in front of the Item/Cloths that belongs.
Did you edited the order of these arrays?:

local ShirtsIDs = {7843411811, 9056088978, 8224770109, 7307508033}
local PantsIDs = {6594989145, 10023059908, 5814743514, 6594989145}

Or are you using a different script to give functions to the ClickDectectors on those parts?

Im asking that, because the way to add more buttons depends on how you are giving the functions to the buttons.

The example I gave its hardcoded, and its only iterating the parts in a folder in workspace. And using the number of the iteration to take a value from a table.

You would need to add a new texture ID into this table: local ShirtsIDs and
add a new part with a ClickDetector in the Workspace folder ClothsBTNs > Shirts or Pants.


The entire approach was only for testing, it can be improved a lot, its just about step by step

2 Likes