add gs
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
local BundleLoader = {}
|
||||
|
||||
local AssetService = game:GetService("AssetService")
|
||||
local ThumbnailGenerator = game:GetService("ThumbnailGenerator")
|
||||
|
||||
local MannequinUtility = require(ThumbnailGenerator:GetThumbnailModule("MannequinUtility"))
|
||||
local ScaleUtility = require(ThumbnailGenerator:GetThumbnailModule("ScaleUtility"))
|
||||
|
||||
local ARTIST_INTENT_FOLDER = "R15ArtistIntent"
|
||||
local ASSET_URL = "asset/?id="
|
||||
|
||||
local function constructAssetUrl(baseUrl, assetId)
|
||||
return baseUrl ..ASSET_URL.. tostring(assetId)
|
||||
end
|
||||
|
||||
function BundleLoader.LoadBundleAssets(baseUrl, bundleId)
|
||||
local bundleInfo = AssetService:GetBundleDetailsSync(bundleId)
|
||||
|
||||
local contentIdsList = {}
|
||||
for _, itemInfo in pairs(bundleInfo.Items) do
|
||||
if itemInfo.Type == "Asset" then
|
||||
local assetId = itemInfo.Id
|
||||
local assetUrl = constructAssetUrl(baseUrl, assetId)
|
||||
|
||||
contentIdsList[#contentIdsList + 1] = assetUrl
|
||||
end
|
||||
end
|
||||
|
||||
local objectsList = game:GetObjectsList(contentIdsList)
|
||||
|
||||
local results = {}
|
||||
for _, objects in pairs(objectsList) do
|
||||
local assetFolder = Instance.new("Folder")
|
||||
|
||||
for _, object in pairs(objects) do
|
||||
object.Parent = assetFolder
|
||||
end
|
||||
|
||||
results[#results + 1] = assetFolder
|
||||
end
|
||||
|
||||
return results
|
||||
end
|
||||
|
||||
local function addPartsToCharacter(character, folder)
|
||||
for _, part in pairs(folder:GetChildren()) do
|
||||
local existingPart = character:FindFirstChild(part.Name)
|
||||
part.Parent = character
|
||||
|
||||
if existingPart then
|
||||
existingPart:Destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addMeshHeadToCharacter(character, mesh)
|
||||
local head = character:FindFirstChild("Head")
|
||||
if not head then
|
||||
return
|
||||
end
|
||||
|
||||
local existingMesh = head:FindFirstChild("Mesh")
|
||||
if existingMesh then
|
||||
existingMesh:Destroy()
|
||||
end
|
||||
|
||||
for _, child in pairs(mesh:GetChildren()) do
|
||||
if child:IsA("Vector3Value") and string.find(child.Name, "Attachment") then
|
||||
local attachment = head:FindFirstChild(child.Name)
|
||||
|
||||
if not attachment then
|
||||
attachment = Instance.new("Attachment")
|
||||
end
|
||||
attachment.Name = child.Name
|
||||
attachment.Position = child.Value
|
||||
attachment.Parent = head
|
||||
end
|
||||
end
|
||||
|
||||
mesh.Parent = head
|
||||
end
|
||||
|
||||
local function addFaceToCharacter(character, face)
|
||||
local head = character:FindFirstChild("Head")
|
||||
if not head then
|
||||
return
|
||||
end
|
||||
|
||||
local existingFace = head:FindFirstChild("face")
|
||||
if existingFace then
|
||||
existingFace:Destroy()
|
||||
end
|
||||
|
||||
face.Parent = head
|
||||
end
|
||||
|
||||
function BundleLoader.LoadBundleCharacter(baseUrl, bundleId)
|
||||
local bundleAssets = BundleLoader.LoadBundleAssets(baseUrl, bundleId)
|
||||
local character = MannequinUtility.LoadR15Mannequin()
|
||||
|
||||
local scaleType = ScaleUtility.GetObjectsScaleType(bundleAssets)
|
||||
|
||||
for _, loadedAsset in pairs(bundleAssets) do
|
||||
for _, item in pairs(loadedAsset:GetChildren()) do
|
||||
if item:IsA("Folder") and item.Name == ARTIST_INTENT_FOLDER then
|
||||
addPartsToCharacter(character, item)
|
||||
elseif not item:IsA("Folder") then
|
||||
if item:IsA("DataModelMesh") then
|
||||
addMeshHeadToCharacter(character, item)
|
||||
elseif item:IsA("Decal") then
|
||||
addFaceToCharacter(character, item)
|
||||
else
|
||||
item.Parent = character
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local humanoid = character:FindFirstChildOfClass("Humanoid")
|
||||
if humanoid then
|
||||
ScaleUtility.CreateProportionScaleValues(humanoid, scaleType)
|
||||
humanoid:BuildRigFromAttachments()
|
||||
end
|
||||
|
||||
return character
|
||||
end
|
||||
|
||||
return BundleLoader
|
||||
@@ -0,0 +1,75 @@
|
||||
-- Utility function for focusing on a selection of parts in a thumbnail
|
||||
|
||||
local FLOAT_MAX = math.huge
|
||||
|
||||
-- 10% tolerance for meshes that are bigger than the part which contains them
|
||||
local MESH_SIZE_TOLERANCE_MULTIPLIER = 1.1
|
||||
|
||||
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
|
||||
|
||||
-- Adds a tolerance for meshes in parts
|
||||
local function getPartSizeBounds(part)
|
||||
local mesh = part:FindFirstChildWhichIsA("DataModelMesh")
|
||||
if not mesh then
|
||||
return part.Size
|
||||
end
|
||||
|
||||
return part.Size * MESH_SIZE_TOLERANCE_MULTIPLIER
|
||||
end
|
||||
|
||||
local CORNERS = {
|
||||
Vector3.new( 1, 1, 1),
|
||||
Vector3.new( 1, 1, -1),
|
||||
Vector3.new( 1, -1, 1),
|
||||
Vector3.new( 1, -1, -1),
|
||||
Vector3.new(-1, 1, 1),
|
||||
Vector3.new(-1, 1, -1),
|
||||
Vector3.new(-1, -1, 1),
|
||||
Vector3.new(-1, -1, -1),
|
||||
}
|
||||
|
||||
local function CreateExtentsMinMax(focusParts)
|
||||
local focusOnExtents = {
|
||||
minx = FLOAT_MAX,
|
||||
miny = FLOAT_MAX,
|
||||
minz = FLOAT_MAX,
|
||||
maxx = -FLOAT_MAX,
|
||||
maxy = -FLOAT_MAX,
|
||||
maxz = -FLOAT_MAX
|
||||
}
|
||||
|
||||
-- Expand focusOnExtents to bound all the parts in the focusParts table
|
||||
for _, focusPart in ipairs(focusParts) do
|
||||
if focusPart:IsA("BasePart") then
|
||||
local partSize = getPartSizeBounds(focusPart)
|
||||
local halfPartSize = partSize * 0.5
|
||||
local partCFrame = focusPart.CFrame
|
||||
|
||||
for _, corner in ipairs(CORNERS) do
|
||||
addCornerToBounds(partCFrame, corner, halfPartSize, focusOnExtents)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local extentsMinMax = {
|
||||
Vector3.new(focusOnExtents["minx"], focusOnExtents["miny"], focusOnExtents["minz"]),
|
||||
Vector3.new(focusOnExtents["maxx"], focusOnExtents["maxy"], focusOnExtents["maxz"])
|
||||
}
|
||||
|
||||
return extentsMinMax
|
||||
end
|
||||
|
||||
return CreateExtentsMinMax
|
||||
@@ -0,0 +1,51 @@
|
||||
-- Utility module for functions related to loading mannequins for thumbnails
|
||||
|
||||
local MannequinUtility = {}
|
||||
|
||||
local InsertService = game:GetService("InsertService")
|
||||
|
||||
local R6_MANNEQUIN_CONTENT_ID = "rbxasset://models/Thumbnails/Mannequins/R6.rbxmx"
|
||||
local R15_MANNEQUIN_CONTENT_ID = "rbxasset://models/Thumbnails/Mannequins/R15.rbxm"
|
||||
local RTHRO_MANNEQUIN_CONTENT_ID = "rbxasset://models/Thumbnails/Mannequins/Rthro.rbxm"
|
||||
|
||||
local function loadMannequin(contentId)
|
||||
local mannequin = InsertService:LoadLocalAsset(contentId)
|
||||
mannequin.Humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
|
||||
mannequin.Parent = workspace
|
||||
|
||||
return mannequin
|
||||
end
|
||||
|
||||
function MannequinUtility.LoadR15Mannequin()
|
||||
return loadMannequin(R15_MANNEQUIN_CONTENT_ID)
|
||||
end
|
||||
|
||||
function MannequinUtility.LoadR6Mannequin()
|
||||
return loadMannequin(R6_MANNEQUIN_CONTENT_ID)
|
||||
end
|
||||
|
||||
function MannequinUtility.LoadRthroMannequin()
|
||||
return loadMannequin(RTHRO_MANNEQUIN_CONTENT_ID)
|
||||
end
|
||||
|
||||
function MannequinUtility.LoadMannequinForScaleType(scaleType)
|
||||
if scaleType == "Classic" then
|
||||
return MannequinUtility.LoadR15Mannequin()
|
||||
else
|
||||
return MannequinUtility.LoadRthroMannequin()
|
||||
end
|
||||
end
|
||||
|
||||
function MannequinUtility.RotateMannequin(mannequin, cframe)
|
||||
local humanoidRootPart = mannequin:FindFirstChild("HumanoidRootPart")
|
||||
if not humanoidRootPart then
|
||||
return
|
||||
end
|
||||
|
||||
local rootRigAttachment = humanoidRootPart:FindFirstChild("RootRigAttachment")
|
||||
if rootRigAttachment then
|
||||
rootRigAttachment.CFrame = rootRigAttachment.CFrame * cframe
|
||||
end
|
||||
end
|
||||
|
||||
return MannequinUtility
|
||||
@@ -0,0 +1,63 @@
|
||||
-- Utility module for managing the scale of mannequins and items in thumbnails
|
||||
|
||||
local ScaleUtility = {}
|
||||
|
||||
local CLASSIC_SCALE = "Classic"
|
||||
local RTHRO_NORMAL = "ProportionsNormal"
|
||||
local RTHRO_SLENDER = "ProportionsSlender"
|
||||
|
||||
local function getPartScaleType(part)
|
||||
local value = part:FindFirstChild("AvatarPartScaleType")
|
||||
if value then
|
||||
return value.Value
|
||||
end
|
||||
|
||||
return CLASSIC_SCALE
|
||||
end
|
||||
|
||||
function ScaleUtility.GetScaleTypeForAccessory(accessory)
|
||||
local handle = accessory:FindFirstChild("Handle")
|
||||
if not handle then
|
||||
return CLASSIC_SCALE
|
||||
end
|
||||
|
||||
return getPartScaleType(handle)
|
||||
end
|
||||
|
||||
function ScaleUtility.GetObjectsScaleType(objects)
|
||||
for _, object in pairs(objects) do
|
||||
local partScaleType = object:FindFirstChild("AvatarPartScaleType", --[[ recursive = ]] true)
|
||||
if partScaleType then
|
||||
return partScaleType.Value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getOrCreateScaleValue(humanoid, name, default)
|
||||
local scaleValue = humanoid:FindFirstChild(name)
|
||||
if scaleValue then
|
||||
return scaleValue
|
||||
end
|
||||
|
||||
scaleValue = Instance.new("NumberValue")
|
||||
scaleValue.Name = name
|
||||
scaleValue.Value = default
|
||||
scaleValue.Parent = humanoid
|
||||
|
||||
return scaleValue
|
||||
end
|
||||
|
||||
function ScaleUtility.CreateProportionScaleValues(humanoid, scaleType)
|
||||
local bodyTypeValue = getOrCreateScaleValue(humanoid, "BodyTypeScale", 0)
|
||||
local bodyProportionValue = getOrCreateScaleValue(humanoid, "BodyProportionScale", 0)
|
||||
|
||||
if scaleType == RTHRO_NORMAL then
|
||||
bodyTypeValue.Value = 1
|
||||
bodyProportionValue.Value = 0
|
||||
elseif scaleType == RTHRO_SLENDER then
|
||||
bodyTypeValue.Value = 1
|
||||
bodyProportionValue.Value = 1
|
||||
end
|
||||
end
|
||||
|
||||
return ScaleUtility
|
||||
Reference in New Issue
Block a user