274 lines
9.7 KiB
Lua
274 lines
9.7 KiB
Lua
-- BodyPart v1.0.6
|
|
-- See http://wiki.roblox.com/index.php?title=R15_Compatibility_Guide#Package_Parts for details on how body parts work with R15
|
|
|
|
local assetUrl, baseUrl, fileExtension, x, y, R6RigUrl, customUrl = ...
|
|
|
|
local ThumbnailGenerator = game:GetService("ThumbnailGenerator")
|
|
ThumbnailGenerator:AddProfilingCheckpoint("ThumbnailScriptStarted")
|
|
|
|
local DFFlagBodyPartFocusInThreeDThumbnails = settings():GetFFlag("BodyPartFocusInThreeDThumbnails")
|
|
|
|
local CreateExtentsMinMax
|
|
local MannequinUtility
|
|
local ScaleUtility
|
|
|
|
if DFFlagBodyPartFocusInThreeDThumbnails then
|
|
CreateExtentsMinMax = require(ThumbnailGenerator:GetThumbnailModule("CreateExtentsMinMax"))
|
|
MannequinUtility = require(ThumbnailGenerator:GetThumbnailModule("MannequinUtility"))
|
|
ScaleUtility = require(ThumbnailGenerator:GetThumbnailModule("ScaleUtility"))
|
|
end
|
|
|
|
pcall(function() game:GetService('ContentProvider'):SetBaseUrl(baseUrl) end)
|
|
game:GetService('ScriptContext').ScriptsDisabled = true
|
|
game:GetService("UserInputService").MouseIconEnabled = false
|
|
|
|
local objects = game:GetObjects(assetUrl)
|
|
ThumbnailGenerator:AddProfilingCheckpoint("BodyPartLoaded")
|
|
|
|
local useR15 = false
|
|
local useR15NewNames = false
|
|
local bodyPartProportion = "Classic"
|
|
local floatMax = math.huge
|
|
|
|
if DFFlagBodyPartFocusInThreeDThumbnails then
|
|
for _, object in pairs(objects) do
|
|
if object:IsA("Folder") then
|
|
if object.Name == "R15" then
|
|
useR15 = true
|
|
elseif object.Name == "R15ArtistIntent" then
|
|
useR15 = true
|
|
useR15NewNames = true
|
|
end
|
|
end
|
|
end
|
|
|
|
bodyPartProportion = ScaleUtility.GetObjectsScaleType(objects)
|
|
else
|
|
for _, object in pairs(objects) do
|
|
if object:IsA("Folder") and (object.Name == "R15" or object.Name == "R15ArtistIntent") then
|
|
useR15 = true
|
|
|
|
-- Check to see if there are native scale parts in this object
|
|
local partScaleType = object:FindFirstChild("AvatarPartScaleType", true)
|
|
if partScaleType then
|
|
bodyPartProportion = partScaleType.Value
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local mannequin
|
|
if DFFlagBodyPartFocusInThreeDThumbnails then
|
|
if useR15 then
|
|
mannequin = MannequinUtility.LoadMannequinForScaleType(bodyPartProportion)
|
|
else
|
|
mannequin = MannequinUtility.LoadR6Mannequin()
|
|
end
|
|
else
|
|
local R15RigUrl = "http://www.roblox.com/asset/?id=516159357"
|
|
for _, object in pairs(objects) do
|
|
if object:IsA("Folder") and object.Name == "R15ArtistIntent" then
|
|
useR15NewNames = true
|
|
if bodyPartProportion == "Classic" then
|
|
R15RigUrl = "http://www.roblox.com/asset/?id=1664543044"
|
|
else
|
|
R15RigUrl = "http://www.roblox.com/asset/?id=2337256345"
|
|
end
|
|
break
|
|
end
|
|
end
|
|
|
|
if useR15 then
|
|
mannequin = game:GetObjects(R15RigUrl)[1]
|
|
else
|
|
mannequin = game:GetObjects(R6RigUrl)[1]
|
|
end
|
|
|
|
mannequin.Humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
|
|
mannequin.Parent = workspace
|
|
end
|
|
|
|
ThumbnailGenerator:AddProfilingCheckpoint("MannequinLoaded")
|
|
|
|
game:GetObjects(customUrl)[1].Parent = mannequin
|
|
|
|
ThumbnailGenerator:AddProfilingCheckpoint("CustomUrlLoaded")
|
|
|
|
local function addFolderChildren(folder, focusPartNamesOut, focusPartsOut)
|
|
for _, child in pairs(folder:GetChildren()) do
|
|
local existingBodyPart = mannequin:FindFirstChild(child.Name)
|
|
if existingBodyPart then
|
|
existingBodyPart:Destroy()
|
|
end
|
|
child.Parent = mannequin
|
|
table.insert(focusPartNamesOut, child.name)
|
|
table.insert(focusPartsOut, child)
|
|
end
|
|
end
|
|
|
|
local r15FolderName = "R15"
|
|
if (useR15 and useR15NewNames) then
|
|
r15FolderName = "R15ArtistIntent"
|
|
end
|
|
|
|
local focusParts = {}
|
|
local focusPartNames = {}
|
|
|
|
for _, object in pairs(objects) do
|
|
if useR15 and object:IsA("Folder") and object.Name == r15FolderName then
|
|
addFolderChildren(object, focusPartNames, focusParts)
|
|
elseif not useR15 and object:IsA("Folder") and object.Name == "R6" then
|
|
addFolderChildren(object, focusPartNames, focusParts)
|
|
elseif not (object:IsA("Folder") and string.find(object.Name, "R15")) then -- There will now be MULTIPLE R15 Folders. Ignore the ones we didn't search for.
|
|
object.Parent = mannequin
|
|
end
|
|
end
|
|
|
|
local function buildJoint(parentAttachment, partForJointAttachment)
|
|
local jointName = parentAttachment.Name:gsub("RigAttachment", "")
|
|
local motor = partForJointAttachment.Parent:FindFirstChild(jointName)
|
|
if not motor then
|
|
motor = Instance.new("Motor6D")
|
|
end
|
|
motor.Name = jointName
|
|
|
|
motor.Part0 = parentAttachment.Parent
|
|
motor.Part1 = partForJointAttachment.Parent
|
|
|
|
motor.C0 = parentAttachment.CFrame
|
|
motor.C1 = partForJointAttachment.CFrame
|
|
|
|
motor.Parent = partForJointAttachment.Parent
|
|
end
|
|
|
|
-- Builds an R15 rig from the attachments in the parts
|
|
local function buildRigFromAttachments(currentPart, lastPart)
|
|
local validSiblings = {}
|
|
for _, sibling in pairs(currentPart.Parent:GetChildren()) do
|
|
-- Don't find matching attachment in the current part being processed.
|
|
-- Don't visit the last part visited again, this would cause an infinite loop.
|
|
if sibling:IsA("BasePart") and sibling ~= currentPart and sibling ~= lastPart then
|
|
table.insert(validSiblings, sibling)
|
|
end
|
|
end
|
|
|
|
local function processRigAttachment(attachment)
|
|
for _, sibling in pairs(validSiblings) do
|
|
local matchingAttachment = sibling:FindFirstChild(attachment.Name)
|
|
if matchingAttachment then
|
|
buildJoint(attachment, matchingAttachment)
|
|
buildRigFromAttachments(matchingAttachment.Parent, currentPart)
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, object in pairs(currentPart:GetChildren()) do
|
|
if object:IsA("Attachment") and string.find(object.Name, "RigAttachment") then
|
|
processRigAttachment(object)
|
|
end
|
|
end
|
|
end
|
|
|
|
if useR15 then
|
|
if DFFlagBodyPartFocusInThreeDThumbnails then
|
|
local humanoid = mannequin:FindFirstChild("Humanoid")
|
|
if humanoid then
|
|
ScaleUtility.CreateProportionScaleValues(humanoid, bodyPartProportion)
|
|
humanoid:BuildRigFromAttachments()
|
|
end
|
|
else
|
|
-- Build R15 rig
|
|
local humanoidRootPart = mannequin:WaitForChild("HumanoidRootPart")
|
|
humanoidRootPart.CFrame = CFrame.new(Vector3.new(0, 5, 0)) * CFrame.Angles(0, math.pi, 0)
|
|
humanoidRootPart.Anchored = true
|
|
buildRigFromAttachments(humanoidRootPart)
|
|
local humanoid = mannequin:WaitForChild("Humanoid")
|
|
if humanoid then
|
|
local typeObject = humanoid:FindFirstChild("BodyTypeScale")
|
|
|
|
if typeObject == nil then
|
|
typeObject = Instance.new("NumberValue")
|
|
typeObject.Name = "BodyTypeScale"
|
|
typeObject.Value = 0
|
|
typeObject.Parent = humanoid
|
|
end
|
|
|
|
local proportionObject = humanoid:FindFirstChild("BodyProportionScale")
|
|
if proportionObject == nil then
|
|
proportionObject = Instance.new("NumberValue")
|
|
proportionObject.Name = "BodyProportionScale"
|
|
proportionObject.Value = 0
|
|
proportionObject.Parent = humanoid
|
|
end
|
|
|
|
if bodyPartProportion == "ProportionsNormal" then
|
|
typeObject.Value = 1
|
|
proportionObject.Value = 0
|
|
elseif bodyPartProportion == "ProportionsSlender" then
|
|
typeObject.Value = 1
|
|
proportionObject.Value = 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function addToBounds(cornerPosition, focusExtentsOut)
|
|
focusExtentsOut["minx"] = math.min(focusExtentsOut["minx"], cornerPosition.x)
|
|
focusExtentsOut["miny"] = math.min(focusExtentsOut["miny"], cornerPosition.y)
|
|
focusExtentsOut["minz"] = math.min(focusExtentsOut["minz"], cornerPosition.z)
|
|
focusExtentsOut["maxx"] = math.max(focusExtentsOut["maxx"], cornerPosition.x)
|
|
focusExtentsOut["maxy"] = math.max(focusExtentsOut["maxy"], cornerPosition.y)
|
|
focusExtentsOut["maxz"] = math.max(focusExtentsOut["maxz"], cornerPosition.z)
|
|
end
|
|
|
|
local function addCornerToBounds(partCFrame, cornerSelect, halfPartSize, focusExtentsOut)
|
|
local cornerPositionLocal = cornerSelect * halfPartSize
|
|
local cornerPositionWorld = partCFrame * cornerPositionLocal
|
|
addToBounds(cornerPositionWorld, focusExtentsOut)
|
|
end
|
|
|
|
local extentsMinMax
|
|
local shouldCrop = false
|
|
|
|
if DFFlagBodyPartFocusInThreeDThumbnails then
|
|
extentsMinMax = CreateExtentsMinMax(focusParts)
|
|
shouldCrop = #focusParts > 0
|
|
else
|
|
local focusOnExtents = { minx = floatMax, miny = floatMax, minz = floatMax, maxx = -floatMax, maxy = -floatMax, maxz = -floatMax }
|
|
|
|
local FFlagThumbnailSupportFocusOnPart = settings():GetFFlag("ThumbnailSupportFocusOnPart")
|
|
if FFlagThumbnailSupportFocusOnPart and string.lower(fileExtension) == "png" then
|
|
-- expand focusOnExtents to bound all the part(s) in the focusPartNames table
|
|
if #focusPartNames > 0 then
|
|
for _, focusPartName in pairs(focusPartNames) do
|
|
local focusPart = mannequin:FindFirstChild(focusPartName, --[[recursive = ]] true)
|
|
if focusPart then
|
|
local partPosition = focusPart.Position
|
|
local partRotation = focusPart.Rotation
|
|
local halfPartSize = focusPart.Size / 2.0
|
|
local partCFrame = CFrame.Angles(math.rad(partRotation.x), math.rad(partRotation.y), math.rad(partRotation.z)) + partPosition
|
|
addCornerToBounds(partCFrame, Vector3.new( 1, 1, 1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new( 1, 1,-1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new( 1,-1, 1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new( 1,-1,-1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new(-1, 1, 1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new(-1, 1,-1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new(-1,-1, 1), halfPartSize, focusOnExtents)
|
|
addCornerToBounds(partCFrame, Vector3.new(-1,-1,-1), halfPartSize, focusOnExtents)
|
|
shouldCrop = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
extentsMinMax = {
|
|
Vector3.new(focusOnExtents["minx"], focusOnExtents["miny"], focusOnExtents["minz"]),
|
|
Vector3.new(focusOnExtents["maxx"], focusOnExtents["maxy"], focusOnExtents["maxz"])
|
|
}
|
|
end
|
|
|
|
local result, requestedUrls = ThumbnailGenerator:Click(fileExtension, x, y, --[[hideSky = ]] true, --[[crop = ]] shouldCrop, extentsMinMax)
|
|
ThumbnailGenerator:AddProfilingCheckpoint("ThumbnailGenerated")
|
|
|
|
return result, requestedUrls |