Is there a way to inrease the speed of this

so i’ve got this outfit randomizer, and i want to increase the speed of search
I did my research and here is the final code that i came up with but i still find a little slow

-- Services
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local MessagingService = game:GetService("MessagingService")

local ID_MIN = 10_000_000_000
local ID_MAX = 30_000_000_000
local MAX_POOL_SIZE = math.huge
local SEARCH_THREADS = 5
local FETCH_DELAY = 1 / SEARCH_THREADS
local MIN_OUTFIT_VALUE = 1
local MESSAGE_RATE = 5

-- State
local accessoriesToCheck = {
	"BackAccessory", "Face", "FaceAccessory", "GraphicTShirt",
	"HairAccessory", "HatAccessory", "Pants", "Shirt",
}

local triedOutfitIds = {}
local outfitPool = {}
local productInfoCache = {}
local outboundQueue = {}
local rng = Random.new()
local checksLastSecond = 0

-- Get random outfit ID
local function getRandomOutfitId()
	return math.floor(rng:NextNumber(ID_MIN, ID_MAX))
end

local function getProductInfo(id)
	if productInfoCache[id] then return productInfoCache[id] end
	local success, result = pcall(function()
		return MarketplaceService:GetProductInfo(id)
	end)
	if success then
		productInfoCache[id] = result
		return result
	else
		task.wait(1)
	end
	return nil
end

local function getOutfitValue(desc)
	if desc.Shirt == 0 or desc.Pants == 0 then return 0 end
	local total = 0
	for _, prop in ipairs(accessoriesToCheck) do
		if total >= MIN_OUTFIT_VALUE then break end
		local id = desc[prop]
		if id and id ~= 0 then
			local info = getProductInfo(id)
			if info and info.IsForSale then
				total += info.PriceInRobux or 0
			end
		end
	end
	return total
end

local function isValidOutfit(outfitId)
	if triedOutfitIds[outfitId] then return false end
	triedOutfitIds[outfitId] = true
	local success, desc = pcall(function()
		return Players:GetHumanoidDescriptionFromOutfitId(outfitId)
	end)

	if success and desc and getOutfitValue(desc) >= MIN_OUTFIT_VALUE then
		return true, desc
	else
		return false
	end
end

local function searchThread()
	while true do
		local id = getRandomOutfitId()
		local valid, desc = isValidOutfit(id)
		if valid then
			table.insert(outfitPool, { id = id, desc = desc })
			table.insert(outboundQueue, id)
		end
		checksLastSecond += 1
		task.wait(FETCH_DELAY)
	end
end

-- Share queued outfits every MESSAGE_RATE seconds
local function batchOutfitSharing()
	while true do
		task.wait(MESSAGE_RATE)
		if #outboundQueue > 0 then
			local batch = {}
			for i = 1, math.min(#outboundQueue, 10) do
				table.insert(batch, table.remove(outboundQueue, 1))
			end
			pcall(function()
				MessagingService:PublishAsync("NewValidOutfits", batch)
			end)
		end
	end
end

-- Receive from other servers
MessagingService:SubscribeAsync("NewValidOutfits", function(message)
	for _, id in ipairs(message.Data) do
		if not triedOutfitIds[id] and #outfitPool < MAX_POOL_SIZE then
			local success, desc = pcall(function()
				return Players:GetHumanoidDescriptionFromOutfitId(id)
			end)
			if success and desc then
				triedOutfitIds[id] = true
				table.insert(outfitPool, { id = id, desc = desc })
				print("Received outfit from another server:", id)
			end
		end
	end
end)

-- Start threads
for _ = 1, SEARCH_THREADS do
	task.spawn(searchThread)
end
task.spawn(batchOutfitSharing)

-- Count how many outfits were added each minute
task.spawn(function()
	local lastCount = 0
	while true do
		task.wait(60)
		local currentCount = #outfitPool
		local added = currentCount - lastCount
		print("Outfits found this minute:", added)
		lastCount = currentCount
	end
end)

Hi
They way i did it in my game is by getting a random id, then check if there is a Roblox player with that id. If so, i use GetHumanoidDescriptionFromUserId() to get that player outifit. From that description you will get an outfit and it will be random.

1 Like

Well the slowdown happens because every outfit triggers one description call plus up to eight individual price calls. You can collapse those eight into a single bulk request and use a small, fixed pool of workers with a simple queue so you don’t overwhelm Roblox’s APIs :face_with_monocle:

local Players = game:GetService("Players")
local Marketplace = game:GetService("MarketplaceService")
local ID_MIN = 10_000_000_000
local ID_MAX = 30_000_000_000
local MAX_POOL_SIZE = math.huge
local SEARCH_THREADS = 5
local FETCH_DELAY = 1 / SEARCH_THREADS
local MIN_OUTFIT_VALUE = 1

-- pieces to check
local ACCESSORIES = {
  "BackAccessory","Face","FaceAccessory","GraphicTShirt",
  "HairAccessory","HatAccessory","Pants","Shirt",
}

local idQueue   = {}
local priceCache= {}
local pool      = {}

-- fills queue to MAX_POOL_SIZE
task.spawn(function()
  while true do
    if #idQueue < MAX_POOL_SIZE then
      idQueue[#idQueue+1] = math.random(ID_MIN, ID_MAX)
    end
    task.wait(FETCH_DELAY)
  end
end)

-- grab prices for missing IDs 
local function fetchPrices(ids)
  local missing = {}
  for _, id in ipairs(ids) do
    if id ~= 0 and not priceCache[id] then
      missing[#missing+1] = id
    end
  end
  if #missing > 0 then
    local ok, infos = pcall(Marketplace.GetProductInfos, Marketplace, missing)
    if ok and infos then
      for _, info in ipairs(infos) do
        priceCache[info.ProductId] = info
      end
    end
  end
end

-- pulls ID, gets desc, batches price fetch, sums value
local function processLoop()
  while true do
    local outfitId = table.remove(idQueue, 1)
    if not outfitId then
      task.wait(0.1)
    else
      local ok, desc = pcall(
        Players.GetHumanoidDescriptionFromOutfitId,
        Players,
        outfitId
      )
      if ok and desc then
        local ids = {}
        for _, key in ipairs(ACCESSORIES) do
          local a = desc[key]
          if a and a ~= 0 then
            ids[#ids+1] = a
          end
        end

        fetchPrices(ids)

        local total = 0
        for _, a in ipairs(ids) do
          local info = priceCache[a]
          if info and info.IsForSale then
            total = total + (info.PriceInRobux or 0)
          end
        end

        if total >= MIN_OUTFIT_VALUE then
          pool[#pool+1] = { id = outfitId, desc = desc }
        end
      end
    end
  end
end

-- starts SEARCH_THREADS loops
for i = 1, SEARCH_THREADS do
  task.spawn(processLoop)
end

This is faster cause each outfit only costs one description call and one bulk price call, with a limited queue of loops and cached prices. :+1:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.