Face not cloning onto head

I’ve got a script where if I press a button on a GUI, it clones a face onto the player’s head

Button Press Script: (this script is sending the data perfectly fine, i’ve tested it)

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local faceType = "SSHF"
script.Parent.MouseButton1Click:Connect(function()
	ReplicatedStorage.AddFace:FireServer(faceType) 
	script.Parent.Visible = false
	script.Parent.Parent.Unequip.Visible = true
end)

Face clone script: (Its printing 1, but not 2 and 3 so theres probably an issue that I can’t see)

local faces = game.ReplicatedStorage.Faces

game.ReplicatedStorage.AddFace.OnServerEvent:Connect(function(plr, faceType) 
	print("1")
	plr:WaitForChild("Character")
	local char = plr.Character
	local faceclone = faces:FindFirstChild():Clone()
	print("2")
	char:WaitForChild("Head")
	faceclone.Parent = char.Head
	print("3")
end)

If you have any extra info needed, please ask!

2 Likes

what is it?
image
And why are you using findfirstchild?

Also please cache services into variables and use :GetService()

???

Maybe its worth learning Luau and engine API first before rushing into production pal?

2 Likes

What would I use instead of findfirstchild?

as for the getservice thing, I always forget about that one

I’m just making a passion project and learning as I go, how would I learn to make a game without actually making a game?

I updated the cloning script a bit

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local faces = game.ReplicatedStorage.Faces

game.ReplicatedStorage.AddFace.OnServerEvent:Connect(function(plr, faceType) 
	print("1")
	plr:WaitForChild("Character")
	local char = plr.Character
	local faceclone = faces:FindFirstChild(faceType):Clone()
	print("2")
	char:WaitForChild("Head")
	faceclone.Parent = char.Head
	print("3")
end)
1 Like

With these updates, is it now printing 2 and 3? If not, are there any errors?

Bad news for you.
That not how you go into gamedev or anything related with programming/3D art.
You spend days and nights nerding documentation or syntax and only then you start to try.
Otherwise you just a become disapontment for yourself and community (if you are lucky enough to get one with such reckless approach to gamedev)

--!optimize 2
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local faces:Folder--[[I assume it is a folder]] = ReplicatedStorage.Faces

ReplicatedStorage.AddFace.OnServerEvent:Connect(function(plr:Player, faceType:string):() 
	local char:Model = plr.Character or plr.CharacterAdded:Wait()--returns player character so dw
	local faceclone:Decal = Instance.fromExisting(faces[faceType])::Decal--Faster alternative to :Clone 
	faceclone.Parent = char:WaitForChild("Head")::BasePart
end)

Also you really dont need faceclone variable at all and neither char variable.

Secure your code from exploiters firing signal aswell please

Code can be collapsed easily:

local WaitForChild = game.WaitForChild--Outside function scope

--Inside function
(Instance.fromExisting(faces[faceType])::Decal).Parent = WaitForChild((plr.Character or plr.CharacterAdded:Wait())::Model,"Head")::BasePart

Oh dw bro this rabbit hole of micro optimizations has not even started yet :smiling_imp:

doing things hands on is the best way to learn something, although it depends on someone’s learning style. Reading documentation for hours may work for some people, but without actual things to apply it to, it becomes difficult to get how it works

as for optimisation, this is just a small project im making. I’d rather the code work than have it not work but be optimised. Probably a reckless way to approach it, but i’ll be able to fix it

Here is some code to replace the server-side logic that includes comments detailing why the choices made have been made. If you’re still having issues, the warnings it emits should help provide some insight into where the problem lies. This script includes logic to validate the faceType argument to protect against remote triggers from bad actors.

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local faces = ReplicatedStorage.Faces

ReplicatedStorage.AddFace.OnServerEvent:Connect(function(plr: Player, faceType: string) 
	
	-- First, validate the client-supplied values.
	
	if type(faceType) ~= "string" then
		
		-- Abort equipping a face if the provided value is not the expected
		-- type for the request.
		
		warn(string.format("Invalid argument type '%s'", typeof(faceType)))
		
		return
	end
	
	-- Use "FindFirstChild" here to make sure the code will not crash if the
	-- provided "faceType" value is invalid.
	
	local face = faces:FindFirstChild(faceType)
	
	if not face then
		
		-- Abort equipping a face because the requested face could not be found.
		
		warn(string.format("Invalid faceType '%s'", faceType))
		
		return
	end
	
	-- Next, find the Character and its Head.
	
	-- "Character" is a property of "Player," so it needs to be accessed via the
	-- dot operator. "WaitForChild" cannot be used here because it attempts to
	-- find an Instance parented to the Player, and this will hang because no
	-- Instance of that name exists (probably, and if it did, it wouldn't be the
	-- Player's Character).
	
	-- I don't recommend yielding for either the character or head to exist
	-- because if multiple requests come in before these Instances become
	-- available, the requests will all process at the same time. Also, if the
	-- Instances never become available, the threads will stay stuck in memory.
	
	local character = plr.Character
	
	if not character then
		
		warn("Character not found")
		
		return
	end
	
	local head = character:FindFirstChild("Head")
	
	if not head then
		
		warn("Head not found")
		
		return
	end
	
	-- Optionally, before adding the new face, remove any existing ones.
	
	for _, object in head:GetChildren() do
		
		if object:IsA("Decal") then
			object:Destroy()
		end
	end
	
	-- Finally, add the new face to the head.
	
	Instance.fromExisting(face).Parent = head
end)

Also, as an aside, don’t do this:

It muddies the namespace with Instance methods and makes code unreadable, which hurts maintainability. Very rarely will code execution time be your bottleneck in general systems, so make your code readable first and fast second. When it seems like execution time due to Instance hierarchy navigation is a sore spot, check first if you can reduce the amount of navigation you do by caching results rather than method call micro-optimizations. If you want to make optimization changes that hurt readability, be sure to profile results before and after to see if your gains are really worth the cost.

Amazing explaination, thank you so much!
I was a bit confused about where to use the findfirstchild.

1 Like

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