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.

19 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.

I doubt ROBLOX is ever gonna fix this officially for R6, just like they made R15 heads/dynamics heads be a meshpart and kept R6 heads as a part with specialmesh

3 Likes

Someone should make a feature request so they change it

I won’t be keeping my hope high either but nonetheless this is a good means to fix that issue for R6 development so that we can keep up with Roblox development wise.

In fact I may even create an entire system for R6 that fixes and translates all issues and updates to ensure R6 development can keep up with R15 for those that do believe R6 is a good system for Roblox.

1 Like

That would be awesome, i also tried out some scripts that fixes the quality on R6 even allowing layered clothing (though ofc it won’t move along with the limbs) only using a few lines of code

If you want link to it lmk

This is actually helpful, I’m tired of having low quality texture in my game.

Thank you

2 Likes