Help with Saving Character Creation

Hi i would like to know the following things (some examples shown would be helpful if you can)

  • If a character chooses a hair during character creation and is done, how can i save the hair he chose?
  • How can I save skin colour?
  • How can i save the shirt they picked?

I have some idea in mind that for example, let’s say they pick a hair and the hair is “Hair1” would i save that to their datastore e.g. [“Hair”] = “Hair1”, then when i want to actually clone the hair to him, would i just search through serverstorage for someone of that name or is there a better method?

Do you just want it to save for their character while they’re in the game or do you want it to be persistent (save across unique server instances)?

You’ve got the basic idea of it, yes you would save each aspect of the character’s creation into a datastore, to do this you’d create a table like below with all the parts that can be customised by the player and then save this data, and upon joining the game the player’s character would load depending on what their creation is. An example of doing this would be the following, just a heads up I have not tested this in studio!

-- Data of player's character creation
local CharacterTable = {  
   ["Hair"] = "Hair1",
   ["SkinTone"] = "White",
   ["Shirt"] = "Shirt", -- all customisable parts of the character (list default values in here)
]

-- Getting the players data
game.Players.PlayerAdded:connect(function(Player)
    local playersData
	local success, errormessage = pcall(function()
		playersData = game:GetService("DataStoreService"):GetDataStore("DATA_STORE_NAME_HERE"):GetAsync(player.UserId.."_CharacterSelection")
	end)
	
	if success then -- grabbing the players data was successful
		if data then
--[[ this is where you'll put the loop to adjust the players character based on their data 
(Yes, searching through serverstorage and putting it in the character or I'd recommend a library in ReplicatedStorage of 
all the hairs/shirts/pants etc that you're storing in your game]]--
		end
	end
end)

-- Saving the players character
game:GetService("Players").PlayerRemoving:Connect(function(Player)
   local Success, Error = pcall(function()
      game:GetService("DataStoreService"):GetDataStore("DATA_STORE_NAME_HERE"):SetAsync(Player.UserId.."_CharacterSelection", CharacterTable)
      print("Data saved successfully"
   end)
   if Error then
      warn(Error) -- error saving players data
   end
end)
3 Likes

Apologies! This should be

if playersData then

To save in database, so if they design their character it saves forever till data wipe or something

Thank you, you know the charactertable is that the table i’d be using to insert what the player chooses during customisation stage?

It will save whatever they have selected as their character forever or until a data wipe, yeah.

The charactertable would be the default table of everything, then you’d just have to change the values of each aspect of it but playersData will be the players saved table that you grab from the datastore and will use that to load the character’s saved creation

Does it need a loop? I don’t think?
I think just clone the accessories from storage and put it on the player

1 Like

Yeah you’re right it doesn’t doing that should be fine

What you are referring to is called serialization. I would check out the tutorial I linked, as it explains it much better than I can.

In the words of @starmaq because apparently the quote block isn’t working:
“By definition, serialization is taking a piece of data that can’t be saved or transfered through the network, and turning it into a piece of data that can be saved or transfered through the network.”

What this means is that while you may not be able to save the actual character instances in-game, you can however save the information that you need to re-create that character.

For starters, there are two ways you can go about obtaining the information you need so you can save the character appearance. The first way is to create your own character customization system in-game. This would be easier to understand as all the data you use to customize the character is already accessible to you. However, because we cannot save roblox instances directly we must save the data that can be used to re-contruct the instance. While we may not be able to save the shirt instance we can save the Shirt | Roblox Creator Documentation property the shirt uses. This means that you could store the data in a table like in this example:

local characterAppearance = {
	Shirt = 1205935 -- a random number to indicate an asset id.
}

To get the shirt content id you could use a simple function like so:

local function FilterShirtContentId(shirt)
	return tonumber(string.match(shirt.ShirtTemplate, "%d+") or 0) -- use string patterns to automatically parse the string to get the number
end

Then you could use said function to create a table with the current shirt texture the player has equipped. We can rewrite our example from earlier to use this function:

local characterAppearance = {
	Shirt = FilterShirtContentId(shirt)
}

Great! Now we have a table that can be saved in a datastore and used to re-create texture a shirt instance to the saved texture. However, while the data we have is useable, we don’t have a method for creating a shirt from this data. Because we have the content id however, this is relatively easy. All we have to do is get or create a shirt object for a player and set it’s properties. So our function might look something like this:

local LoadShirt(player, contentId)
	local character = player.Character or player.CharacterAppearanceLoaded:Wait()
	local shirt = character:FindFirstChildWhichIsA("Shirt") or Instance.new("Shirt")

	shirt.ShirtTemplate = "rbxassetid://"..tostring(contentId)
	shirt.Parent = character
end

And there we have it.

The second method is easier to implement and more versatile but ultimately requires more setup and a greater understanding. It involves sorting through the contents of Players | Roblox Creator Documentation and using Player | Roblox Creator Documentation.

Lastly, if you do not understand how to save data then I reccomend checking out some tutorials roblox provides. They can be really helpful.

2 Likes

Also, just as a side note, if you are going to have the hair be numbered instead of named then it’d be easier to instead have a folder in ReplicatedStorage (Instead of ServerStorage because instances in ServerStorage aren’t accessible to the client) named “Hair” and then have the instances there named as numbers. You don’t have to do this, but it’s sort of redundant to have ["Hair"]="Hair#" and this would also allow you to arrange the instances in a defined order using:

table.sort(Hair:GetChildren(),function(child1 : Instance, child2 : Instance) : boolean
	return (tonumber(child1.Name) < tonumber(child2.Name))
end) 

Note: the Hair variable is the folder in ReplicatedStorage

thank you very much, by the second method are you referring to this

or

This: