Is my gamepass module efficient enough?

I’m considering my gamepass module finished but i’m still thinking there could be flaws that could potentially break it out. What can i do to improve it?

local Pass = {}

--// Services
local MarketPlaceService = game:GetService("MarketplaceService")

-- Variables
local Passes = {
	["UnlimitedBrainrots"] = 1729092154;
	["2xMultiplier"] = 1731132489;
}

local Perks = {
	["UnlimitedBrainrots"] = function(Player:Player)
		Player.Stats.MaxBrainrots.Value = math.huge
		game.ReplicatedStorage.Shared.Remotes.UpdateSpawned:FireClient(Player)
	end;
	
	["2xMultiplier"] = function(Player:Player)
		Player.Stats["2xMultiplier"].Value = true
	end,
}

--// Functions
function Pass:GetPlayerPerks(Player:Player)
	local Perks = {}

	for i,v in Passes do
		local success,has = pcall(function()
			return MarketPlaceService:UserOwnsGamePassAsync(Player.UserId,v)
		end)

		if success and has then
			table.insert(Perks,i)
		end
		
		if not success then
			warn("Gamepass check faillure: "..has)
		end
	end

	return Perks
end

function Pass:DeduceGamepassFromId(id:number): string?
	for i,v in Passes do
		if v == id then
			return i
		end
	end
end

function Pass:AwardPerks(Player:Player,Passid:number?)
	if Passid then
		local pass = self:DeduceGamepassFromId(Passid)

		print(pass)

		Perks[pass](Player)
	else
		local UserPerks = self:GetPlayerPerks(Player)

		for _,v in UserPerks do
			Perks[v](Player)
		end
	end
end

function Pass:HandleGamepassPurchases()
	MarketPlaceService.PromptGamePassPurchaseFinished:Connect(function(Player,Id,Purchased)
		if not Purchased then
			return
		end
		
		self:AwardPerks(Player,Id)
	end)
end

return Pass
3 Likes

After taking a look at your code, it looks perfectly fine. I can’t see any flaws that could make it break.

Is the script working as intended?

Your code is already pretty clean, but I can see a few areas that could use very minor tweaks.

This can error:
Perks[pass](player)\

If pass is nil, it’ll throw an error. Try this instead:

if pass and Perks[pass] then
    Perks[pass](Player)
end

Always guard table calls.


Inside GetPlayerPerks:
local Perks = {}
You now have:

  • Local Perks (list of strings)
  • Global Perks (perk functions)

This works but it’s confusing, rename it to:
local OwnedPerks = {}


Right now you’re using:

UserOwnsGamePassAsync

which is fine but you should also check ownership again when awarding perks after purchase.
Because PromptGamePassPurchaseFinished can fire improperly during failed transactions.

if Purchased then
	local owns = MarketPlaceService:UserOwnsGamePassAsync(Player.UserId, Id)
	if owns then
		self:AwardPerks(Player, Id)
	end
end

I wouldn’t recommend using math.huge:

Player.Stats.MaxBrainrots.Value = math.huge

This can cause leaderboards to glitch and other weird stuff. Instead, just use a very large cap like:
1e12 Or treat unlimited as a bolean flag instead.

And don’t worry, no one will EVER reach this number. If a player gained 1 brainrot per second nonstop, 60 per minute, 3,600 per hour, 86,400 per day, ~31.5 million per year. To reach 1e12 would take over 30,000 years.


Lastly I think you could improve your table structures. Right now you have:

Passes = { name = id }
Perks = { name = function }

Which is fine but a better way would be:

local Passes = {
	UnlimitedBrainrots = {
		Id = 1729092154,
		Apply = function(Player)
			Player.Stats.MaxBrainrots.Value = 1e12
		end
	},

	["2xMultiplier"] = {
		Id = 1731132489,
		Apply = function(Player)
			...
		end
	}
}

This way it is easier to expand and just better long-term.

cache player owned gamepasses so you dont have to make multiple calls to marketplace service.

There one issue. UserHasGamepassAsync have actualisation time. Doing this method would probably run into some problems such as a unpassed verification since it didn’t actualise.

1 Like