Roblox R6 UGC Quality Fix

Roblox UGC developers want to go above and beyond with their designs for the catalog but they’re restricted to using low quality textures unless they decide that R6 textures will just have to take the L.

Noticing this issue I made a script for R6 developers to use so UGC developers can have the highest quality items in your games as well as R15, as opposed to the blurry mess you might be used to.

My brief explanation is that it’s a simply hacky method that just takes a hat and cframes it on the character rather than loading it normally through the character. High quality items just can’t be made on R6 characters because of the way those character models are rendered so until Roblox does something to fix that (if they do), the high quality UGC items will be restricted to R15 experiences (without this script).

local InsertService = game:GetService("InsertService")

local AccessoryCache = {}

function LoadAccessory(id, Humanoid, c, AccessoryType)
	local t = c:FindFirstChild("Torso")
	if t and id then
		if AccessoryCache[id] then
			local NewAccessory = AccessoryCache[id]:Clone()
			NewAccessory.Parent = c
			local AttachmentType = NewAccessory:FindFirstChildOfClass("Attachment").Name
			local AttachmentOnBody = c:FindFirstChild(AttachmentType, true)
			local AttachmentPart = AttachmentOnBody.Parent
			local Weld = Instance.new("WeldConstraint", NewAccessory)
			Weld.Part0 = NewAccessory
			NewAccessory.CFrame = AttachmentOnBody.WorldCFrame * NewAccessory[AttachmentType].CFrame:Inverse()
			Weld.Part1 = AttachmentPart
		else
			local NewAccessory = InsertService:LoadAsset(id):GetChildren()[1].Handle
			if NewAccessory then
				NewAccessory.CanCollide = false
				NewAccessory.CanQuery = false
				NewAccessory.CanTouch = false
				NewAccessory.Massless = true
				NewAccessory.Name = "Accessory"
				AccessoryCache[id] = NewAccessory:Clone()
				NewAccessory.Parent = c
				local AttachmentType = NewAccessory:FindFirstChildOfClass("Attachment").Name
				local AttachmentOnBody = c:FindFirstChild(AttachmentType, true)
				local AttachmentPart = AttachmentOnBody.Parent
				local Weld = Instance.new("WeldConstraint", NewAccessory)
				Weld.Part0 = NewAccessory
				NewAccessory.CFrame = AttachmentOnBody.WorldCFrame * NewAccessory[AttachmentType].CFrame:Inverse()
				Weld.Part1 = AttachmentPart
			end
		end
	end
end

function CharacterSetup(c)
	local Humanoid = c:WaitForChild("Humanoid")
	if Humanoid and Humanoid.RigType ~= Enum.HumanoidRigType.R15 then
		local GHD = Humanoid:GetAppliedDescription()
		Humanoid:RemoveAccessories()
		if GHD then
			if tostring(GHD.BackAccessory) ~= nil then for _,id in pairs(string.split(GHD.BackAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.FaceAccessory) ~= nil then for _,id in pairs(string.split(GHD.FaceAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.FrontAccessory) ~= nil then for _,id in pairs(string.split(GHD.FrontAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.HairAccessory) ~= nil then for _,id in pairs(string.split(GHD.HairAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.HatAccessory) ~= nil then for _,id in pairs(string.split(GHD.HatAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.NeckAccessory) ~= nil then for _,id in pairs(string.split(GHD.NeckAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.ShouldersAccessory) ~= nil then for _,id in pairs(string.split(GHD.ShouldersAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
			if tostring(GHD.WaistAccessory) ~= nil then for _,id in pairs(string.split(GHD.WaistAccessory, ",")) do LoadAccessory(tonumber(id), Humanoid, c) end end
		end
	end
end

function PlayerSetup(p)
	p.CharacterAppearanceLoaded:Connect(function(c)
		CharacterSetup(c)
	end)
end

for _,p in pairs(game.Players:GetPlayers()) do task.spawn(function() PlayerSetup(p) end) end
game.Players.PlayerAdded:Connect(function(p) task.spawn(function() PlayerSetup(p) end) end)

You can also grab it as a model here.

9 Likes

Beautiful! I’ve noticed this problem myself with some UGC I’ve uploaded, thank you for the fix!

3 Likes

I wonder if this resource could also act as a workaround for this issue where textures for accessories sometimes fail to load in R6 experiences. I’ve personally never made an R6 experience, but I’ll be sure to share this resource on that report and see if it resolves that issue for others. Thank you for taking time to create this resource!

2 Likes

I apologize if anyone was inconvenienced by the distributed weight of the character model as a result of the hats. I forgot to add “Massless = true” which is a small change that would only be an issue in niche cases but to replicate normal accessory behavior this is vital.

I apologize for forgetting the line and the script and code above has been updated with the correction.