I need some help altering an avatar editor!

Hey! I’m a terrible scripter. The extent of my scripting knowledge is basically a GUI close button. ANYWAY, there’s this amazing open source resource by 0_1195

It’s an avatar editor, really well made. Basically a godsend for the unexperienced such as myself. I do have one thing I’m trying to fix up! I’m having trouble altering the scripts to accept decals as faces, as some of the faces in my game are just decals and not roblox faces themselves. I think that the scripts search for an item class based on the ID (i.e, this is a hat, weld to head, etc.) I’ve been looking through but its just a mess to me (probably much more legible to actual scripters) and I don’t know where to start.

If some of the more experienced scripters could help me out with this, it’d be much appreciated!

To be clear, I need to find a way to allow decals in the same class as faces, so they are put on the player’s face when equipped. I’ll post (what I think are) the relevant scripts below. If you’d like to look in the actual full resource, the link above has a downloadable baseplate game to see all the components.

ModuleScript in ServerScriptService

local Http = game:GetService("HttpService")

local subcategory = 9
local url = "https://search.roblox.com/catalog/json?Subcategory=" .. subcategory .. "&IncludeNotForSale=true&ResultsPerPage=60&PageNumber="

local pages = 25

local assets = {}

for i = 1, pages do
	local urlPage = url .. i
	local data = Http:JSONEncode(Http:GetAsync(urlPage))
	data = Http:JSONDecode(data)
	
	for ii = 1, #data do
		local asset = data[ii]
		
		local id = asset.AssetId
		local name = asset.Name
		
		assets[#assets + 1] = "{Id = " ..id .. ", Name = \"" .. name .. "\"}"
	end
	print(i)
end

local source = "return { \n\t" .. table.concat(assets, ",\n\t") .. "\n}"
local module = Instance.new("ModuleScript")
module.Source = source
module.Parent = workspace
Script in ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Marketplace = game:GetService("MarketplaceService")
local Insert = game:GetService("InsertService")
local Debris = game:GetService("Debris")
local Players = game:GetService("Players")

local remoteEvent = ReplicatedStorage.UpdateAvatar

local defaultBodyPartsR15 = script.HumanoidDefaultBodyPartsR15

local ACCESSORY_CAP = 10
local DEFAULT_SHIRT = "rbxassetid://855777285"
local DEFAULT_PANTS = "rbxassetid://867826313"
local DEFAULT_FACE = "rbxasset://textures/face.png"

local bannedAssets = {
--	["1527622"] = true,
--	["4640898"] = true,
--	["1055299"] = true,
}

local allowedAssets = {
	["8"] = true, -- Hat
	["11"] = true, -- Shirt
	["12"] = true, -- Pants
	["17"] = true, -- Head
	["18"] = true, -- Face
	["27"] = true, -- Torso
	["28"] = true, -- RightArm
	["29"] = true, -- LeftArm
	["30"] = true, -- LeftLeg
	["31"] = true, -- RightLeg
	["41"] = true, -- HairAccessory
	["42"] = true, -- FaceAccessory
	["43"] = true, -- NeckAccessory
	["44"] = true, -- ShoulderAccessory
	["45"] = true, -- FrontAccessory
	["46"] = true, -- BackAccessory
	["47"] = true, -- WaistAccessory
	["48"] = true, -- ClimbAnimation
	["50"] = true, -- FallAnimation
	["51"] = true, -- IdleAnimation
	["52"] = true, -- JumpAnimation
	["53"] = true, -- RunAnimation
	["54"] = true, -- SwimAnimation
	["55"] = true, -- WalkAnimation
}

local playerWearingAssets = {}
local AssetTypeEnumLookup = {}

local function insertToTable(assets, productInfo)
	table.insert(assets, {
		id = productInfo.AssetId,
		assetType = {
			name = AssetTypeEnumLookup[productInfo.AssetTypeId].Name,
			id = productInfo.AssetTypeId,
		},
		name = productInfo.Name
	})
end

local function getOriginalHeadMesh()
	local mesh = Instance.new("SpecialMesh")
	mesh.MeshType = Enum.MeshType.Head
	mesh.Scale = Vector3.new(1.25, 1.25, 1.25)
	local originalSize = Instance.new("Vector3Value")
	originalSize.Name = "OriginalSize"
	originalSize.Value = Vector3.new(1.25, 1.25, 1.25)
	originalSize.Parent = mesh
	return mesh
end

local function getOriginalFace()
	local decal = Instance.new("Decal")
	decal.Texture = DEFAULT_FACE
	return decal
end

local function getOriginalClothing(clothe)
	if clothe == "Shirt" then
		local shirt = Instance.new("Shirt")
		shirt.ShirtTemplate = DEFAULT_SHIRT
		return shirt
	elseif clothe == "Pants" then
		local pants = Instance.new("Pants")
		pants.PantsTemplate = DEFAULT_PANTS
		return pants
	end
end

local function wear(player, id)
	if id == nil or not (typeof(id) == "number") then
		return
	end
	if not playerWearingAssets[player] then
		return
	end
	if bannedAssets[tostring(id)] then
		return
	end
	
	local productInfo, items
	local success, err = pcall(function()
		productInfo = Marketplace:GetProductInfo(id)
	end)
	if not success then
		return warn(err)
	end
	local assetTypeId = tostring(productInfo.AssetTypeId)
	if not allowedAssets[assetTypeId] then
		return
	end
	
	local character = player.Character
	local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
	if humanoid == nil or humanoid.Health <= 0 then
		return
	end
	
	local success, err = pcall(function()
		items = Insert:LoadAsset(productInfo.AssetId)
	end)
	if not success then
		return warn(err)
	end
	for i, descendant in ipairs(items:GetDescendants()) do
		if descendant:IsA("LuaSourceContainer") or descendant:IsA("BackpackItem") then
			Debris:AddItem(descendant, 0)
		end
	end
	
	local characterAppearanceInfo = playerWearingAssets[player]
	local index = nil
	for i, asset in ipairs(characterAppearanceInfo.assets) do
		if asset.id == id then
			index = i
			break
		end
	end
	
	-- is there a better way to do this?
	if assetTypeId == "8" or assetTypeId == "41" or assetTypeId == "42" or assetTypeId == "43" or assetTypeId == "44" or assetTypeId == "45" or assetTypeId == "46" or assetTypeId == "47" then
		-- accessory
		local accessory = items:GetChildren()[1]
		if not accessory:IsA("Accoutrement") then
			return
		end
		if index then
			local wearing = character:FindFirstChild(accessory.Name)
			if wearing then
				Debris:AddItem(wearing, 0)
				table.remove(characterAppearanceInfo.assets, index)
			end
		elseif #humanoid:GetAccessories() < ACCESSORY_CAP then
			humanoid:AddAccessory(accessory)
			insertToTable(characterAppearanceInfo.assets, productInfo)
		end
	elseif assetTypeId == "11" or assetTypeId == "12" then
		-- clothing
		local clothing = items:GetChildren()[1]
		if not clothing:IsA("Clothing") then
			return
		end
		local wearing = character:FindFirstChildWhichIsA(clothing.ClassName)
		if wearing then
			Debris:AddItem(wearing, 0)
		end
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			getOriginalClothing(clothing.ClassName).Parent = character
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			clothing.Parent = character
		end
	elseif assetTypeId == "48" or assetTypeId == "50" or assetTypeId == "51" or assetTypeId == "52" or assetTypeId == "53" or assetTypeId == "54" or assetTypeId == "55" then
		-- animation
		local animationFolder = items:GetChildren()[1]
		local animateScript = character:FindFirstChild("Animate")
		
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			for i, value in ipairs(animationFolder:GetChildren()) do
				if animateScript:FindFirstChild(value.Name) then
					Debris:AddItem(animateScript[value.Name], 0)
				end
			end
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			if animateScript then
				for i, value in ipairs(animationFolder:GetChildren()) do
					if animateScript:FindFirstChild(value.Name) then
						Debris:AddItem(animateScript[value.Name], 0)
					end
					value.Parent = animateScript
				end
			end
		end
	elseif assetTypeId == "18" then
		-- face
		local decal = items:GetChildren()[1]
		if not decal:IsA("Decal") then
			return
		end
		local head = character:FindFirstChild("Head")
		local wearing = head and head:FindFirstChildWhichIsA("Decal")
		if wearing then
			Debris:AddItem(wearing, 0)
		end
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			player:LoadCharacterAppearance(getOriginalFace())
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			decal.Parent = head
		end
	elseif assetTypeId == "17" then
		-- head
		local mesh = items:GetChildren()[1]
		if not (mesh:IsA("SpecialMesh") or mesh:IsA("CylinderMesh")) then
			return
		end
		local head = character:FindFirstChild("Head")
		local wearing = head and head:FindFirstChildWhichIsA("SpecialMesh")
		if wearing then
			Debris:AddItem(wearing, 0)
		end
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			player:LoadCharacterAppearance(getOriginalHeadMesh())
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			player:LoadCharacterAppearance(mesh)
		end
	elseif assetTypeId == "27" or assetTypeId == "28" or assetTypeId == "29" or assetTypeId == "30" or assetTypeId == "31" then
		-- body parts
		local bodyPartFolder = items:FindFirstChild("R15ArtistIntent")
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			for i, part in ipairs(bodyPartFolder:GetChildren()) do
				local partInCharacter = character:FindFirstChild(part.Name)
				local bodyPartR15 = partInCharacter and humanoid:GetBodyPartR15(partInCharacter)
				local defaultBodyPart = bodyPartR15 and defaultBodyPartsR15:FindFirstChild(part.Name)
				if defaultBodyPart then
					defaultBodyPart = defaultBodyPart:Clone()
					humanoid:ReplaceBodyPartR15(bodyPartR15, defaultBodyPart)
				end
			end
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			for i, part in ipairs(bodyPartFolder:GetChildren()) do
				local partInCharacter = character:FindFirstChild(part.Name)
				local bodyPartR15 = partInCharacter and humanoid:GetBodyPartR15(partInCharacter)
				if bodyPartR15 then
					humanoid:ReplaceBodyPartR15(bodyPartR15, part)
				end
			end
		end
	end
	
	humanoid:BuildRigFromAttachments()
	Debris:AddItem(items, 0)
	remoteEvent:FireClient(player, characterAppearanceInfo)
end

local function skinTone(player, color)
	if color == nil or not (typeof(color) == "string") then
		return
	end
	if not playerWearingAssets[player] then
		return
	end
	
	local character = player.Character
	local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
	if humanoid == nil or humanoid.Health <= 0 then
		return
	end
	
	local characterAppearanceInfo = playerWearingAssets[player]
	local brickColor = BrickColor.new(color)
	characterAppearanceInfo.bodyColors.headColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.leftArmColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.leftLegColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.rightArmColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.rightLegColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.torsoColorId = brickColor.Number
	
	local bodyColors = character:FindFirstChildWhichIsA("BodyColors")
	bodyColors.HeadColor3 = brickColor.Color
	bodyColors.LeftArmColor3 = brickColor.Color
	bodyColors.LeftLegColor3 = brickColor.Color
	bodyColors.RightArmColor3 = brickColor.Color
	bodyColors.RightLegColor3 = brickColor.Color
	bodyColors.TorsoColor3 = brickColor.Color
end

local function scale(player, name, value)
	if name == nil or not (typeof(name) == "string") then
		return
	end
	if value == nil or not (typeof(value) == "number") then
		return
	end
	if not playerWearingAssets[player] then
		return
	end
	
	local character = player.Character
	local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
	if humanoid == nil or humanoid.Health <= 0 then
		return
	end
	
	if name == "BodyHeightScale" then
		math.clamp(value, 95, 105)
	elseif name == "BodyWidthScale" then
		math.clamp(value, 70, 100)
	elseif name == "HeadScale" then
		math.clamp(value, 95, 100)
	elseif name == "BodyProportionScale" then
		math.clamp(value, 0, 100)
	elseif name == "BodyTypeScale" then
		math.clamp(value, 0, 100)
	else
		return
	end
	
	local scaleValue = humanoid and humanoid:FindFirstChild(name)
	if not scaleValue then
		return
	end
	
	scaleValue.Value = value/100
end

-- limit how often the client can fire
local function onServerEvent(player, action, ...)
	if action == "wear" then
		wear(player, ...)
	elseif action == "skintone" then
		skinTone(player, ...)
	elseif action == "scale" then
		scale(player, ...)
	end
end

-- theres gotta be a better way
local function getHumanoidDescriptionFromCharacterAppearance(characterAppearanceInfo)
	local humanoidDescription = Instance.new("HumanoidDescription")
	humanoidDescription.BodyTypeScale = characterAppearanceInfo.scales.bodyType
	humanoidDescription.DepthScale = characterAppearanceInfo.scales.depth
	humanoidDescription.HeadScale = characterAppearanceInfo.scales.head
	humanoidDescription.HeightScale = characterAppearanceInfo.scales.height
	humanoidDescription.ProportionScale = characterAppearanceInfo.scales.proportion 
	humanoidDescription.WidthScale = characterAppearanceInfo.scales.width
	humanoidDescription.HeadColor = BrickColor.new(characterAppearanceInfo.bodyColors.headColorId).Color
	humanoidDescription.LeftArmColor = BrickColor.new(characterAppearanceInfo.bodyColors.leftArmColorId).Color
	humanoidDescription.LeftLegColor = BrickColor.new(characterAppearanceInfo.bodyColors.leftLegColorId).Color
	humanoidDescription.RightArmColor = BrickColor.new(characterAppearanceInfo.bodyColors.rightArmColorId).Color
	humanoidDescription.RightLegColor = BrickColor.new(characterAppearanceInfo.bodyColors.rightLegColorId).Color
	humanoidDescription.TorsoColor = BrickColor.new(characterAppearanceInfo.bodyColors.torsoColorId).Color
	for i, asset in ipairs(characterAppearanceInfo.assets) do
		if asset.assetType.name == "Hat" then
			humanoidDescription.HatAccessory = humanoidDescription.HatAccessory .. "," .. asset.id
		elseif asset.assetType.name == "BackAccessory" or asset.assetType.name == "Back Accessory" then
			humanoidDescription.BackAccessory = humanoidDescription.BackAccessory .. "," .. asset.id
		elseif asset.assetType.name == "FaceAccessory" or asset.assetType.name == "Face Accessory" then
			humanoidDescription.FaceAccessory = humanoidDescription.FaceAccessory .. "," .. asset.id
		elseif asset.assetType.name == "FrontAccessory" or asset.assetType.name == "Front Accessory" then
			humanoidDescription.FrontAccessory = humanoidDescription.FrontAccessory .. "," .. asset.id
		elseif asset.assetType.name == "HairAccessory" or asset.assetType.name == "Hair Accessory" then
			humanoidDescription.HairAccessory = humanoidDescription.HairAccessory .. "," .. asset.id
		elseif asset.assetType.name == "NeckAccessory" or asset.assetType.name == "Neck Accessory" then
			humanoidDescription.NeckAccessory = humanoidDescription.NeckAccessory .. "," .. asset.id
		elseif asset.assetType.name == "ShoulderAccessory" or asset.assetType.name == "Shoulder Accessory" then
			humanoidDescription.ShouldersAccessory = humanoidDescription.ShouldersAccessory .. "," .. asset.id
		elseif asset.assetType.name == "WaistAccessory" or asset.assetType.name == "Waist Accessory" then
			humanoidDescription.WaistAccessory = humanoidDescription.WaistAccessory .. "," .. asset.id
		elseif asset.assetType.name == "Face" then
			humanoidDescription.Face = asset.id
		elseif asset.assetType.name == "Shirt" then
			humanoidDescription.Shirt = asset.id
		elseif asset.assetType.name == "Pants" then
			humanoidDescription.Pants = asset.id
		elseif asset.assetType.name == "Head" then
			humanoidDescription.Head = asset.id
		elseif asset.assetType.name == "LeftArm" or asset.assetType.name == "Left Arm" then
			humanoidDescription.LeftArm = asset.id
		elseif asset.assetType.name == "LeftLeg" or asset.assetType.name == "Left Leg" then
			humanoidDescription.LeftLeg = asset.id
		elseif asset.assetType.name == "RightArm" or asset.assetType.name == "Right Arm" then
			humanoidDescription.RightArm = asset.id
		elseif asset.assetType.name == "RightLeg" or asset.assetType.name == "Right Leg" then
			humanoidDescription.RightLeg = asset.id
		elseif asset.assetType.name == "Torso" then
			humanoidDescription.Torso = asset.id
		elseif asset.assetType.name == "ClimbAnimation" or asset.assetType.name == "Climb Animation" then
			humanoidDescription.ClimbAnimation = asset.id
		elseif asset.assetType.name == "FallAnimation" or asset.assetType.name == "Fall Animation" then
			humanoidDescription.FallAnimation = asset.id
		elseif asset.assetType.name == "IdleAnimation" or asset.assetType.name == "Idle Animation" then
			humanoidDescription.IdleAnimation = asset.id
		elseif asset.assetType.name == "JumpAnimation" or asset.assetType.name == "Jump Animation" then
			humanoidDescription.JumpAnimation = asset.id
		elseif asset.assetType.name == "RunAnimation" or asset.assetType.name == "Run Animation" then
			humanoidDescription.RunAnimation = asset.id
		elseif asset.assetType.name == "SwimAnimation" or asset.assetType.name == "Swim Animation" then
			humanoidDescription.SwimAnimation = asset.id
		elseif asset.assetType.name == "WalkAnimation" or asset.assetType.name == "Walk Animation" then
			humanoidDescription.WalkAnimation = asset.id
		end
	end
	if humanoidDescription.Shirt == 0 then
		humanoidDescription.Shirt = 855777286
	end
	if humanoidDescription.Pants == 0 then
		humanoidDescription.Pants = 855782781
	end
	return humanoidDescription
end

local function playerAdded(player)
	local function characterAdded(character)
		local characterAppearanceInfo = playerWearingAssets[player]
		if characterAppearanceInfo then
			local humanoid = character:FindFirstChildWhichIsA("Humanoid") or character:WaitForChild("Humanoid")
			local humanoidDescription = getHumanoidDescriptionFromCharacterAppearance(characterAppearanceInfo)
			if not humanoid or not humanoid:IsDescendantOf(workspace) then
				humanoid.AncestryChanged:Wait()
			end
			if humanoid.Health > 0 and humanoidDescription then
				pcall(function()
					humanoid:ApplyDescription(humanoidDescription)
				end)
			end
		end
	end
	
	characterAdded(player.Character or player.CharacterAdded:Wait())
	
	local characterAppearanceInfo
	pcall(function()
		characterAppearanceInfo = Players:GetCharacterAppearanceInfoAsync(player.UserId)
	end)
	playerWearingAssets[player] = characterAppearanceInfo or {}
	
	player.CharacterAdded:Connect(characterAdded)
end

local function playerRemoved(player)
	if playerWearingAssets[player] then
		playerWearingAssets[player] = nil
	end
end

for i, enumItem in ipairs(Enum.AssetType:GetEnumItems()) do
	AssetTypeEnumLookup[enumItem.Value] = enumItem
end

for i, player in ipairs(Players:GetPlayers()) do
	coroutine.wrap(playerAdded)(player)
end

Players.PlayerAdded:Connect(playerAdded)
Players.PlayerRemoving:Connect(playerRemoved)
remoteEvent.OnServerEvent:Connect(onServerEvent)

He made a V2 wich is way easier to use and a bit more optimized: