Issue with script to choose cosmetics

First and foremost, I would appreciate if anyone could assist me in figuring out a way to better do this, as I believe my approach is kind of nasty and would like to improve my code going forward.

The Purpose of the code: To reference a Dictionary with userdata and take the "Race Name " and find that specific folder in replicatedstorage which contains the cosmetic info, to do the same except for the RaceVariant which is in the same location under that race folder, once these two values are selected the body should be recoloured appropriately.

THE ERROR: Oftentimes the player will spawn without being recoloured, I imagine this is due to how I am trying to select the cosmetic info and the timing before applying it. I’m not a very experienced scripter so advice on how to improve this code massively would be appreciated as I am unsure how else to solve this issue.

This isn’t really a reason I cannot store the information for the cosmetic info in the datastore, I just imagine replicatedstorage would be better for reference from both the client and server.

My Code:

local CharacterHandler = {}

local RaceHandler = require(script.Parent.RaceHandler)

local ReplicatdStorage = game:GetService("ReplicatedStorage")

function CharacterHandler:LoadChar(Player, DataTable, Character)
	local UUID = Player.UserId
	DataTable[UUID]["CharacterData"]["Race"].RaceVar = 1
	local Race = DataTable[UUID]["CharacterData"]["Race"].RaceType
	local RaceVar = DataTable[UUID]["CharacterData"]["Race"].RaceVar
	local Humanoid = Character:WaitForChild("Humanoid")
	
	local SelectedSkinColour
	local SelectedEyeColour
	local SelectedHairColour
	
	for i, v in pairs(ReplicatdStorage.RaceAssets:GetChildren()) do
		if Race == v.Name then
			for j, k in pairs(v:GetChildren()) do
				if k:FindFirstChild("VariantNum") then
					if k:FindFirstChild("VariantNum").Value == RaceVar then
						SelectedSkinColour = k:FindFirstChild("SkinColour")
						SelectedEyeColour = k:FindFirstChild("EyeColour")
						SelectedHairColour = k:FindFirstChild("HairColour")
					end
				end
			end
		end
	end
	
	local connection = Player.CharacterAppearanceLoaded:Connect(function(character)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		humanoid:RemoveAccessories()
		local Head = character:WaitForChild("Head")
		local Left_Arm = character:WaitForChild("Left Arm")
		local Right_Arm = character:WaitForChild("Right Arm")
		local Torso = character:WaitForChild("Torso")
		local Left_Leg = character:WaitForChild("Left Leg")
		local Right_Leg = character:WaitForChild("Right Leg")
		
		Head.Color = SelectedSkinColour.Value
		Left_Arm.Color = SelectedSkinColour.Value
		Right_Arm.Color = SelectedSkinColour.Value
		Torso.Color = SelectedSkinColour.Value
		Left_Leg.Color = SelectedSkinColour.Value
		Right_Leg.Color = SelectedSkinColour.Value
	end)
end

return CharacterHandler

I would appreciate suggestions for improving this code a lot. Thank you :slight_smile:
Screenshot_29
Screenshot_30

1 Like

Hi! I suppose the main issue might simply be how exactly your trying to update the character. I cannot answer on the basis of efficiency or optimization, as I have not made a comparison, however I prefer to use models instead of values. This is simply because it is much easier for me to load everything all at once than each individual part at a time. The only time I would use values to change things would be skins, but even there I simply use models as it is much more comfortable for me.

So I will make this post try to do 2 things:

a. Give advice on your code and hopefully resolve the issue given the current method
b. Share with you my method for loading in custom characters

  1. Current Code

Ok so far, getting the CharacterData, specifically the “RaceType” value is a good start, as that is your identifier to call specific parts of your ReplicatedStorage. I will agree that perhaps the main issue might be the code.

local CharacterHandler = {}

local RaceHandler = require(script.Parent.RaceHandler)

local ReplicatdStorage = game:GetService("ReplicatedStorage")

function CharacterHandler:LoadChar(Player, DataTable, Character)
-- I assume you correctly got the data
--To get the character, I believe you can do local character = Player.Character, 
--but if you are getting the character, that is fine
	local UUID = Player.UserId
	DataTable[UUID]["CharacterData"]["Race"].RaceVar = 1
	local Race = DataTable[UUID]["CharacterData"]["Race"].RaceType
	local RaceVar = DataTable[UUID]["CharacterData"]["Race"].RaceVar
	local Humanoid = Character:WaitForChild("Humanoid")
	
	local SelectedSkinColour
	local SelectedEyeColour
	local SelectedHairColour
	
--I will assume that there are no issues when you call
	for i, v in pairs(ReplicatdStorage.RaceAssets:GetChildren()) do
		if tostring(Race) == tostring(v.Name) then
			for j, k in pairs(v:GetChildren()) do
				if k:FindFirstChild("VariantNum") then
					if k:FindFirstChild("VariantNum").Value == RaceVar then
						SelectedSkinColour = k:FindFirstChild("SkinColour")
						SelectedEyeColour = k:FindFirstChild("EyeColour")
						SelectedHairColour = k:FindFirstChild("HairColour")
                   else
                      print("The values do not match")
					end
               else
                   print("Could not find the VariantNum child")
				end
			end
        else
            print("The values do not match")
		end
	end
	
--This is the confusing part for me to understand, why exactly have local connection here inside your module?
--Remember you need to actually call this function as it is right now idle in your module script, you need to separately call it
--This is because you do define it, but there seems to be no place you actually use it, so its just better to do Player.CharacterAppearanceLoaded:Connect()
--
	local connection = Player.CharacterAppearanceLoaded:Connect(function(character)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		humanoid:RemoveAccessories()
		local Head = character:WaitForChild("Head")
		local Left_Arm = character:WaitForChild("Left Arm")
		local Right_Arm = character:WaitForChild("Right Arm")
		local Torso = character:WaitForChild("Torso")
		local Left_Leg = character:WaitForChild("Left Leg")
		local Right_Leg = character:WaitForChild("Right Leg")
		
		Head.Color = SelectedSkinColour.Value
		Left_Arm.Color = SelectedSkinColour.Value
		Right_Arm.Color = SelectedSkinColour.Value
		Torso.Color = SelectedSkinColour.Value
		Left_Leg.Color = SelectedSkinColour.Value
		Right_Leg.Color = SelectedSkinColour.Value
	end)
end

return CharacterHandler
  1. Method I use

The method I use generally revolves around 2 things, we get the Player.Character and each “skin” (basically model) has the exact same type of children (like humanoid, parts, welds, etc.). Here is how it goes:

  1. Get the Player Data - I won’t go into this as you seem to have a good grasp on calling the player data, we just need the name of the skin
  2. Clone the model from replicated storage - this I would say is the most important part as when you clone, you can change the clone.Parent to the Player.Character, allowing you to have an actual model as the character. So now when you load in, your character will load (I have yet to experience issues with this method).

I hope this helps!

1 Like

Hello I appreciate the response, and yes that connection part is not needed ( I was using code from another forum post and didn’t remove it.

I will attempt to implement your #2 method and will update you on how it goes, I appreciate the response.

1 Like

U need a server script,becuase i think u did not acttivate it

Game.Player.PlayerAdded:Connect(function()
– module function

End

This is incorrect, the function is being activated correctly and I can provide a server script example if needed, but it would just show passing the datatable in the screenshot and the player / character object.

Could you provide a code example of #2 and how you would achieve that?

Sure! I will provide you a general step by step framework that you should be able to easily customize:

Step 1: Create your models/characters that you want the player to “dress up” as and put them in Replicated Storage (additionally, if you like you can put them under a folder, if you would like to stay organized. It should look something like this:

image

Step 2: Create a Script in ServerScriptService, you can call this CharacterLoader.
IMPORTANT: You will need a remote or bindable event to indicate the Server of when you want to load the character or when the character. For me, when the player loads, I fire a bindable event to the CharacterLoader script so it can get ready. I’m not the biggest fan when it comes down to client firing remotes, so I just load it beforehand, unless the player is changing their skin (like Arsenal). Basically you need a remote event, to fire to CharacterLoader

Assume that the Data for the player is structured like this (I believe you already have a structure):

Data = {

PlayerName = "RealCalculus"
Character = "Alpha"

}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LoadingCharacter = ReplicatedStorage["Events"]:WaitForChild("LoadingCharacter")

--Now we need to handle the event logic (I used a bindable, my DataStorage will send 
--the player data to this script
LoadingCharacter.Event:Connect(function(player, Data)

local skin = Data.Character
local characterObject = ReplicatedStorage["Skins"]:WaitForChild(skin):Clone()

characterObject.Parent = workspace
player.Character = characterObject
player:LoadCharacter()

end)

This is about the general idea of creating your skin system, I might have a couple errors in terms of defining terms but this is the general gist. I hope this helps!

1 Like

Oh,that is good…Btw,u got learn claculus???

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.