How can I efficiently get a players game passes and inventory?

This time I would like to ask for help with a “Pls Donate Kit” that I am trying to install.

I am supposed to have done everything as shown in the KIT video, but when I test in my game the “Stand”, it does not load any passes, I have my public inventory and in other donation games my passes load fine, can you help me?

The videotutorial is this: https://youtu.be/2rpJsNF0p0A

Ensure you have enabled all security intents.

I have the security options shown in the video enabled

Any logs in the output?

When I click on “claim” I don’t get the passes, but in the log it shows a series of messages in “English and Spanish” almost all of them indicate that they are from “MainModule: 31”.

EDIT: I let the messages load for a while and after a while the passes appeared (although not all of them, I don’t know if there is a programmed limit).

I am going to upload the console logs so that you can see the messages, I will also upload the MainModule, could you help me to avoid loading all those unnecessary data and that the passes can appear faster?

At the end of the logs it is shown that after a few minutes the modules 75-76-77-78 are loaded, which are supposed to be the ones that check your account for passes.

MainModule

local module = {}
local dss = game:GetService("DataStoreService")
local http = game:GetService("HttpService")
local mps = game:GetService("MarketplaceService")
local mainStore = dss:GetDataStore("MainDataStore")

module.assetTypeIds = {
	["T-Shirt"]=2,
	["Shirt"]=11,
	["Pants"]=12,
	["Pass"]=34,
}

module.getItems = function(assetId,plrId)
	local allItems = {}
	local success, errormsg = pcall(function()
		local done = false
		local nextPageCursor
		while done == false do
			local data
			if nextPageCursor then
				data = http:GetAsync("https://www.roproxy.com/users/inventory/list-json?assetTypeId="..tostring(assetId).."&cursor="..nextPageCursor.."&itemsPerPage=100&userId="..tostring(plrId))
			else
				data = http:GetAsync("https://www.roproxy.com/users/inventory/list-json?assetTypeId="..tostring(assetId).."&cursor=&itemsPerPage=100&userId="..tostring(plrId))
			end
			if data then
				data = http:JSONDecode(data)
				local items = data["Data"]["Items"]
				for _, item in pairs(items) do
					table.insert(allItems, item)
					print(item["Item"]["Name"])
				end
				if data["Data"]["nextPageCursor"] then
					nextPageCursor = data["Data"]["nextPageCursor"]
					--print(nextPageCursor)
				else
					done = true
				end
			else
				warn("No data.")
			end
		end
	end)
	if success then
		--print("Successfully retrieved data.")
	else
		warn(errormsg)
	end
	local createdByUser = {}
	for i, item in pairs(allItems) do
		pcall(function()
			if (item["Creator"]["Id"] == plrId) and (item["Product"]["IsForSale"] == true) then
				table.insert(createdByUser,item)
			end
		end)
	end
	--print(createdByUser)
	--print(tostring(#createdByUser).." items remain.")
	for _, item in pairs(createdByUser) do
		--print(item["Item"]["Name"],"-",item["Product"]["PriceInRobux"])
	end
	return createdByUser
end

module.loadItems = function(stand, plr)
	for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
		if frame:IsA("Frame") then
			frame:Destroy()
		end
	end
	local tshirts = module.getItems(module.assetTypeIds["T-Shirt"],plr.UserId)
	local passes = module.getItems(module.assetTypeIds["Pass"],plr.UserId)
	local shirts = module.getItems(module.assetTypeIds["Shirt"],plr.UserId)
	local pants = module.getItems(module.assetTypeIds["Pants"],plr.UserId)
	print(#tshirts,"T-Shirts found.")
	print(#shirts,"Shirts found.")
	print(#pants,"Pants found.")
	print(#passes,"Passes found.")
	local allItems = {}
	local tble = {tshirts,passes,shirts,pants}
	for _, itemType in pairs(tble) do
		for _, item in pairs(itemType) do
			table.insert(allItems,item)
		end
	end
	--print("Total items found:",#allItems)
	table.sort(allItems, function(a, b)
		return a["Product"]["PriceInRobux"] < b["Product"]["PriceInRobux"]
	end)
	for _, item in pairs(allItems) do
		if stand.ClaimedUserName.Value == plr.Name then
			local frame = script.Template:Clone()
			frame.ItemID.Value = item["Item"]["AssetId"]
			frame.Cost.Value = item["Product"]["PriceInRobux"]
			frame.ItemTypeId.Value = item["Item"]["AssetType"]
			frame.RobuxCost.Text = "$"..tostring(item["Product"]["PriceInRobux"])
			frame.Parent = stand.ItemsPart.Items.ScrollingFrame
		end
	end
end

module.clearStand = function(stand)
	--print("Clearing stand...")
	stand.SignPart.SurfaceGui.UserMessage.Text = "your text here"
	stand.Base.ClaimPrompt.Enabled = true
	stand.Base.ClaimedInfoDisplay.Enabled = false
	stand.Base.Unclaimed.Enabled = true
	stand.Claimed.Value = false
	stand.ClaimedUserName.Value = ""
	for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
		if frame:IsA("Frame") then
			frame:Destroy()
		end
	end
end

module.updateStandsEarned = function()
	for _, stand in pairs(game.Workspace.Stands:GetChildren()) do
		if stand.Claimed.Value == true then
			local plr = game.Players:FindFirstChild(stand.ClaimedUserName.Value)
			if plr then
				stand.Base.ClaimedInfoDisplay.UserRaised.Text = "R$"..tostring(plr.leaderstats.Raised.Value).." Raised"
			else
				--print("no player but claimed")
			end
		end
	end
end

module.findItem = function(itemID)
	for _, stand in pairs(game.Workspace.Stands:GetChildren()) do
		for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
			if frame:IsA("Frame") then
				if frame.ItemID.Value == itemID then
					return frame
				end
			end
		end
	end
end

return module

LOGS Screen

image

LOGS Raw
https://pastebin.com/raw/FFAn24yT

Update: I noticed that the names that appear in the logs, are passes that I have purchased, that is to say that module 31 is probably reading the passes that I have purchased, how can I do to skip this check?

Do you mean make it so it doesn’t print all the game passes you’ve purchased?

I mean I would like the code to skip the purchased passes, and focus on the created passes, to avoid the delay in loading the passes, since the passes are loaded once module 31 checks the purchased passes.

I still can’t solve it :,c

Okay, can you clearly re-state your issue? I’m struggling to exactly understand what is going wrong.

I’ll try to explain myself better…

I recently followed a tutorial of “coolcapidog” about a “Pls Donate Kit” that he had created, I did all the steps well, and the only problem I had, was that the passes took a long time to load (in the logs that I left, it took 3 minutes to load) after I put this post, I could notice that the delay of the passes was due to the fact that in the module 31 (as shown in the logs) this module was verifying the “purchased passes” which in this case being a donation booth, it should not verify the purchased passes but it should verify the “created passes”.

The help I am asking for is to help me to modify the “MainModule” to prevent it from verifying the purchased passes, and thus improve the loading of the passes, which should take seconds to appear not minutes.

This is the kit

And the videotutorial I left it in the message at the beginning of this post.

Okay, this is annoying. I do not have as many inventory items as you (You have 2780, I have 733.

Perhaps you are getting throttled by roproxy (Unlikely as their post says there is no rate limiting)? This would make sense as you would be sending 28 requests, you may also just be waiting for the pure compute time.

There might not be a super easy solution to reduce the waiting time

I’ve quickly whipped up this Python program to see how long everything takes:

timings.py

""""
A program designed to count the waiting time for roproxy.com

This program was not designed with efficiency in mind but rather replicating the MainModule used by the pls donate kit.

Get asset types: https://create.roblox.com/docs/reference/engine/enums/AssetType

"""
import time
import requests

startTime = time.time()
assetIds = [2, 11, 12, 34]
userId = 1012243713

def getItems(assetId):
    cursor = ""
    while True:
        request = requests.get(f"https://www.roproxy.com/users/inventory/list-json?assetTypeId={assetId}&cursor={cursor}&itemsPerPage=100&userId={userId}")
        requestJson = request.json()
        nextCusor = requestJson["Data"]["nextPageCursor"]
        if nextCusor == None:
            break
        else:
            cursor = nextCusor


for assetId in assetIds:
    getItems(assetId)
endTime = time.time()
finalTime = endTime - startTime
print(f"Time taken: {finalTime}")

After testing with your user ID (I think) time taken was 106 seconds, which is quite a long time to load in the assets for a single user, for me, it took 18 seconds, but of course, this is also too long.


The potential solution?

Perhaps, instead of waiting for all the data to be loaded before you add items, why not add items after each request?

Unfortunately due to the way that the main module is structured, this may quite a lot of code to be re-written.

I’ve attempted to re-write the module for you and it should work, heck, it’s not the best code for sure, but it should work. The data will add not sorted, but once all items are loaded, the items will be sorted but at least your stand has items.

MainModule.lua (Modified):

local module = {}
local dss = game:GetService("DataStoreService")
local http = game:GetService("HttpService")
local mps = game:GetService("MarketplaceService")
local mainStore = dss:GetDataStore("MainDataStore")

module.assetTypeIds = {
	["T-Shirt"]=2,
	["Shirt"]=11,
	["Pants"]=12,
	["Pass"]=34,
}

 module.getItems = function(assetId,plrId, stand, plr)
	local allItems = {}
	local createdByUser = {}
	local success, errormsg = pcall(function()
		local done = false
		local nextPageCursor
		while done == false do
			local data
			if nextPageCursor then
				data = http:GetAsync("https://www.roproxy.com/users/inventory/list-json?assetTypeId="..tostring(assetId).."&cursor="..nextPageCursor.."&itemsPerPage=100&userId="..tostring(plrId))
			else
				data = http:GetAsync("https://www.roproxy.com/users/inventory/list-json?assetTypeId="..tostring(assetId).."&cursor=&itemsPerPage=100&userId="..tostring(plrId))
			end
			if data then
				data = http:JSONDecode(data)
				local items = data["Data"]["Items"]
				for _, item in pairs(items) do
					table.insert(allItems, item)
					print(item["Item"]["Name"])
				end
				if data["Data"]["nextPageCursor"] then
					nextPageCursor = data["Data"]["nextPageCursor"]
					print(nextPageCursor)
				else
					done = true
				end
			else
				warn("No data.")
			end
			tempItems = {}
			for i, item in pairs(allItems) do
				pcall(function()
					if (item["Creator"]["Id"] == plrId) and (item["Product"]["IsForSale"] == true) then
						print("added item")
						table.insert(createdByUser,item)
						table.insert(tempItems, item)
					end
				end)
			end
			table.sort(tempItems, function(a, b)
				return a["Product"]["PriceInRobux"] < b["Product"]["PriceInRobux"]
			end)
			for _, item in pairs(tempItems) do
				if stand.ClaimedUserName.Value == plr.Name then
					local frame = script.Template:Clone()
					frame.ItemID.Value = item["Item"]["AssetId"]
					frame.Cost.Value = item["Product"]["PriceInRobux"]
					frame.ItemTypeId.Value = item["Item"]["AssetType"]
					frame.RobuxCost.Text = "$"..tostring(item["Product"]["PriceInRobux"])
					frame.Parent = stand.ItemsPart.Items.ScrollingFrame
				end
			end
		end
	end)
	return createdByUser
end

module.loadItems = function(stand, plr)
	for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
		if frame:IsA("Frame") then
			frame:Destroy()
		end
	end
	local tshirts = module.getItems(module.assetTypeIds["T-Shirt"],plr.UserId, stand, plr)
	local passes = module.getItems(module.assetTypeIds["Pass"],plr.UserId,stand, plr)
	local shirts = module.getItems(module.assetTypeIds["Shirt"],plr.UserId, stand, plr)
	local pants = module.getItems(module.assetTypeIds["Pants"],plr.UserId, stand, plr)
	print(#tshirts,"T-Shirts found.")
	print(#shirts,"Shirts found.")
	print(#pants,"Pants found.")
	print(#passes,"Passes found.")
	local allItems = {}
	local tble = {tshirts,passes,shirts,pants}
	for _, itemType in pairs(tble) do
		for _, item in pairs(itemType) do
			table.insert(allItems,item)
		end
	end
	--print("Total items found:",#allItems)
	table.sort(allItems, function(a, b)
		return a["Product"]["PriceInRobux"] < b["Product"]["PriceInRobux"]
	end)
	for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
		if frame:IsA("Frame") then
			frame:Destroy()
		end
	end
	for _, item in pairs(allItems) do
		if stand.ClaimedUserName.Value == plr.Name then
			local frame = script.Template:Clone()
			frame.ItemID.Value = item["Item"]["AssetId"]
			frame.Cost.Value = item["Product"]["PriceInRobux"]
			frame.ItemTypeId.Value = item["Item"]["AssetType"]
			frame.RobuxCost.Text = "$"..tostring(item["Product"]["PriceInRobux"])
			frame.Parent = stand.ItemsPart.Items.ScrollingFrame
		end
	end
end

module.clearStand = function(stand)
	--print("Clearing stand...")
	stand.SignPart.SurfaceGui.UserMessage.Text = "your text here"
	stand.Base.ClaimPrompt.Enabled = true
	stand.Base.ClaimedInfoDisplay.Enabled = false
	stand.Base.Unclaimed.Enabled = true
	stand.Claimed.Value = false
	stand.ClaimedUserName.Value = ""
	for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
		if frame:IsA("Frame") then
			frame:Destroy()
		end
	end
end

module.updateStandsEarned = function()
	for _, stand in pairs(game.Workspace.Stands:GetChildren()) do
		if stand.Claimed.Value == true then
			local plr = game.Players:FindFirstChild(stand.ClaimedUserName.Value)
			if plr then
				stand.Base.ClaimedInfoDisplay.UserRaised.Text = "R$"..tostring(plr.leaderstats.Raised.Value).." Raised"
			else
				--print("no player but claimed")
			end
		end
	end
end

module.findItem = function(itemID)
	for _, stand in pairs(game.Workspace.Stands:GetChildren()) do
		for _, frame in pairs(stand.ItemsPart.Items.ScrollingFrame:GetChildren()) do
			if frame:IsA("Frame") then
				if frame.ItemID.Value == itemID then
					return frame
				end
			end
		end
	end
end

return module

If this works, please mark as solution (this is deffo the longest scripting support response I’ve made ever (bleh) )

1 Like

I tried the code but many passes were repeated, I don’t know why, couldn’t you remove the check of purchased passes? to check only the created passes?

Extra information:
The stands of the next kit, if the passes load faster (but not all), maybe that’s why it loads faster, but I’ve seen this same model in other donation games and my passes load normal, could you help me to see how the code of this KIT is created and see if with that information we can improve the MainModule of the first kit?

Where is this being checked in the program?

Perhaps instead of loading all the assets they load just a couple, or perhaps they have API’s that cache?

I just noticed that it uses the same API, it just loads faster because it doesn’t load all the passes, only 4 passes, but it’s weird because I have visited other donation games (other than Pls Donate) and in those games my passes load fine.

Yes, we should exclude pls donate from the equation as it’s likely a very well devleoped system. Perhaps there’s a better API call you can do to fetch items that are created by you?

Let me take a look.

This looks good.

https://inventory.roblox.com/v2/users/{userid}/inventory/{assettype}?limit={limit}

The console displays this

10:05:20.401   ▼ HttpService is not allowed to access ROBLOX resources (x4)  -  Servidor - MainModule:47
     10:05:20.402     HttpService is not allowed to access ROBLOX resources
     10:05:20.402     HttpService is not allowed to access ROBLOX resources
     10:05:20.402     HttpService is not allowed to access ROBLOX resources
  10:05:20.402  0 T-Shirts found.  -  Servidor - MainModule:75
  10:05:20.402  0 Shirts found.  -  Servidor - MainModule:76
  10:05:20.402  0 Pants found.  -  Servidor - MainModule:77
  10:05:20.402  0 Passes found.  -  Servidor - MainModule:78

Because you haven’t implemented it properly using roproxy, you’ll have to re-write the program to get this to work properly.

import time
import requests

startTime = time.time()
assetIds = [2, 11, 12, 34]
userId = 1928307387

def getItems(assetId):
    cursor = ""
    while True:
        request = requests.get(f"https://inventory.roblox.com/v2/users/{userId}/inventory/{assetId}?limit=100&cursor={cursor}")
        requestJson = request.json()
        nextCursor = requestJson.get("nextPageCursor")
        if nextCursor is None:
            break
        else:
            cursor = nextCursor

for assetId in assetIds:
    getItems(assetId)

endTime = time.time()
finalTime = endTime - startTime
print(f"Time taken: {finalTime}")

With this new API I got:
“Time taken: 4.353755474090576”

Much better than the previous one.