How to make time based developer products?

In the game Power Simulator (game link: https://www.roblox.com/games/3255597014/SHIELDS-Power-Simulator?refPageId=e5bfbc41-9712-4b6c-81ea-9755f6539f7b) you are able to buy a VIP pass that grants a series of advantages in the game. Usually in most games, a pricey gamepass would be used and once purchased will forever grant that player that VIP pass. But in Power Simulator, this is time based (VIP lasting for 3 hours for example). Seeing as this is bought numerous times, it is a developer product.

I plan on using a similar system but I have no idea where to start and which coding methods I should use to achieve this. May I have some guidance on this?

2 Likes

Well, as you said, you’d approach this by making use of devproducts; as far as making it last a certain amount of time goes, I’d personally go about this by setting up a function you can invoke which checks the amount of time that’s elapsed (using either a cached os.time, current ostime, & os.difftime or by making use of a cached os.date & uncached os.date).

Upon the purchase of the devproduct, I’d

  1. cache the time of purchase.
  2. enable whatever ‘VIP’ features the player should then have access to.
  3. check the time difference between when they bought it & the current time
    • When the player joins the server
    • In set intervals, for all online players, across the lifetime of each game server
    • When the player leaves the server (somewhat redundant)
3 Likes

I see, so let’s say, every 1 minute, check to see if a dev product is active, I would save this in a datastore, with the key being the vip and the value being the amount of time elapsed? I’m pretty sure there would he problems when players begin to stack them.

I was operating under the assumption that you’d only be able to purchase vip while not a vip.

Finally got around to writing some mock code to show the gist of it. I’m not sure if this shows the best approach to take nor if there is a library that may make achieving the intended behavior easier (I’ll have to look, if there isn’t one I’ll consider making one similar to LuaDate but for roblox).


I used LuaDoc-esque comments to explain function behavior & --> to signify what the output would look like as a result of that function’s execution



local vip = {
	data = {}
}

local secondsPer = {
	sec = 1,
	min = 60,
	hour = 3600,
	day = 86400,
	week = 604800,
	month = 2629800,
	year = 31557600,
}


--- dummyPurchase ( playerName, _debugCurrentTimeOverride )
--- An dummy example of what the purchasing function should look like
--@param	playerName	name of the purchaser
--@param	_debugCurrentTimeOverride	debug override that lets you set the time of the mock purchase
--
--@return	nil

function vip:dummyPurchase(playerName, _debugCurrentTimeOverride)

	local hoursToGrant = 3 -- Number of hours to add per purchase

	local currentTime = _debugCurrentTimeOverride or os.time()
	local pdata = (
		self.data[playerName]
	or
		{ -- Default data
			tOfInitialPurchase = nil,
			hoursRemaining = 0,
		}
	)

	if (not pdata.tOfInitialPurchase) or self:hasExpired(pdata, currentTime) then
		-- Purchased for the first time or after expiration of last purchase
		pdata.tOfInitialPurchase = os.time()
		pdata.hoursRemaining = hoursToGrant
		print('new purchase/expired')
	else
		-- Purchased while a VIP
		pdata.hoursRemaining = pdata.hoursRemaining + hoursToGrant
		print('purchased while vip')
	end

	self.data[playerName] = pdata

end

--- hasExpired ( pdata, currentTime )
--@param	pdata	A table describing a player's vip
--@param	time	Any number; intepreted as seconds since Epoch
--
--@return	bool, number	Whether the player's vip has expired, hours until it expires

function vip:hasExpired(pdata, time)

	local difference = (pdata.tOfInitialPurchase+(pdata.hoursRemaining*secondsPer.hour) - time)

	return difference < 0, difference/secondsPer.hour

end
-- Mock purchase
vip:dummyPurchase('test') --> new purchase

print(
	-- Check if the player's VIP has expired
	vip:hasExpired(vip.data.test, os.time())
) --> false	3

vip:dummyPurchase('test') --> purchased while vip

print(
	-- Check if the player's VIP has expired
	vip:hasExpired(vip.data.test, os.time())
) --> false	6

 -- Emulate a purchase a day after their last
vip:dummyPurchase('test', os.time()+secondsPer.day) --> new purchase/expired
4 Likes

This is great, never thought about using a dictionary to store the seconds, I shall elaborate on this, thank you man!

3 Likes