This script checks for the AssetID and finds the Bundle and prompts the purchase of the bundle.
However, free bundles tend to say that the item is currently not for sale, instead of prompting the purchase properly.
Code (ServerScriptService):
-- SERVICES --
local AvatarEditorService = game:GetService('AvatarEditorService')
local MarketplaceService = game:GetService('MarketplaceService')
local Players = game:GetService('Players')
local HttpService = game:GetService('HttpService')
local ReplicatedStorage = game:GetService('ReplicatedStorage')
-- VARIABLES --
local BundleCaches = {}
local BundleParts = {17, 27, 28, 29, 30, 31, 48, 49, 50, 51, 52, 53, 54, 55, 79}
local PurchaseDebounce = {}
local CheckOwnershipDebounce = {}
local BundleLink = 'https://catalog.roproxy.com/v1/assets/%d/bundles'
local SaveOutfitsEvent = ReplicatedStorage.Signals.Events.SaveOutfits
local SaveOutfitsFunction = ReplicatedStorage.Signals.Functions.SaveOutfits
-- FUNCTIONS --
local function CacheBundle(ItemId)
local BundleInfo
local Success, Error = pcall(function()
BundleInfo = HttpService:JSONDecode(HttpService:GetAsync(string.format(BundleLink, ItemId)))
end)
if BundleInfo and BundleInfo.data and #BundleInfo.data >= 1 then
BundleCaches[tostring(ItemId)] = BundleInfo.data[1].id
return BundleInfo.data[1].id, 'Bundle'
end
end
-- Get details of an item
local function GetPurchasableId(ItemId)
-- If cache already exists, return cached id
if BundleCaches[tostring(ItemId)] then
return BundleCaches[tostring(ItemId)], 'Bundle'
end
-- Get the product info
local ProductInfo
pcall(function()
ProductInfo = MarketplaceService:GetProductInfo(ItemId, Enum.InfoType.Asset)
end)
-- Check if item is a body part or an animation
if ProductInfo then
if table.find(BundleParts, ProductInfo.AssetTypeId) then
return CacheBundle(ItemId)
end
end
return ItemId
end
-- Check the ownership of an item
local function CheckOwnership(Player, ItemId)
local IsOwned
-- Check if cache exists
if BundleCaches[tostring(ItemId)] then
pcall(function()
IsOwned = MarketplaceService:PlayerOwnsBundle(Player, BundleCaches[tostring(ItemId)])
end)
end
-- Get the product info
local ProductInfo
pcall(function()
ProductInfo = MarketplaceService:GetProductInfo(ItemId, Enum.InfoType.Asset)
end)
-- Check if body part or animation is owned
if ProductInfo then
if table.find(BundleParts, ProductInfo.AssetTypeId) then
local ToCheckId = CacheBundle(ItemId)
if ToCheckId then
pcall(function()
IsOwned = MarketplaceService:PlayerOwnsBundle(Player, ToCheckId)
end)
end
end
end
-- Check if accessory or clothing is owned
pcall(function()
IsOwned = MarketplaceService:PlayerOwnsAsset(Player, ItemId)
end)
return IsOwned
end
-- EVENTS --
SaveOutfitsEvent.OnServerEvent:Connect(function(Player, Request, ...)
if Request == 'PurchaseItem' then
if PurchaseDebounce[Player] then
return
end
PurchaseDebounce[Player] = true
-- Set the variables
local ItemId = ...
-- Verify the variables
if typeof(ItemId) ~= 'number' then
return
end
-- Purchase the item
local PurchasableId, Type = GetPurchasableId(ItemId)
if PurchasableId then
if Type == 'Bundle' then
MarketplaceService:PromptBundlePurchase(Player, PurchasableId)
PurchaseDebounce[Player] = nil
return
end
MarketplaceService:PromptPurchase(Player, PurchasableId)
end
task.wait(1)
PurchaseDebounce[Player] = nil
elseif Request == 'SetupAvatarModel' then
local AvatarModel = ...
if AvatarModel and AvatarModel:IsA('Model') and AvatarModel.Name == 'Model' then
local HumanoidDescription = Players:GetHumanoidDescriptionFromUserId(Player.UserId)
AvatarModel:WaitForChild('Humanoid'):ApplyDescriptionReset(HumanoidDescription)
end
end
end)
SaveOutfitsFunction.OnServerInvoke = function(Player, Request, Variable1)
if Request == 'CheckOwnership' then
if CheckOwnershipDebounce[Player] then
repeat
task.wait()
until not CheckOwnershipDebounce[Player]
end
CheckOwnershipDebounce[Player] = true
-- Set variables
local Items = Variable1
-- Verify variables
if typeof(Items) ~= 'table' then
return
end
local ToReturn = {
Owned = {};
Unowned = {};
}
-- Check the ownership of each variable
for _, ItemId in pairs(Items) do
if typeof(ItemId) == 'number' then
local IsOwned = CheckOwnership(Player, ItemId)
if IsOwned then
table.insert(ToReturn.Owned, ItemId)
else
table.insert(ToReturn.Unowned, ItemId)
end
end
end
task.spawn(function()
task.wait(1)
CheckOwnershipDebounce[Player] = nil
end)
return ToReturn
end
end