In-Game Subscription System

Recently I have been working on some rather unusual things that are of zero relevance to me, quite frankly, just for fun. One of these projects is an in-game subscription system, now it isn’t the best but it works, you may want to slightly revamp this. But it simply is just a draft, I wrote it all in one session, anyway, here it is, thanks!

--Created by YellowTripleG, https://www.roblox.com/users/119187141
local dataService = game:GetService("DataStoreService")
local subDat = dataService:GetDataStore("isSubscribed")
local purchaseHistoryStore = dataService:GetDataStore("purchaseHistory")
local marketServ = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local thirtyDays = 2592000
local subscriptionId = 0

function createInst(Parent,Name,Type)
	local c = Instance.new(Type)
	c.Name =  Name
	c.Parent = Parent
	return c
end

game.Players.PlayerAdded:Connect(function(Player)
	local data
	local currentDate = os.time()
	local success, err = pcall(function()
		data = subDat:GetAsync(Player.UserId) or nil
	end)
	if success then
		if data ~= nil then
			if currentDate >= data + thirtyDays then
				print('Subscription Ended!')
				local success1, err1 = pcall(function()
					subDat:RemoveAsync(Player.UserId)
				end)
				if err1 then
					error(err1)
				end
				marketServ:PromptProductPurchase(Player,subscriptionId)
			else
				local daysLeft = math. floor(((data + thirtyDays) - currentDate)/86400 + 0.5)
				print(daysLeft..' days left!')
				local subInfo = createInst(Player,"subInfo","Folder")
				local isSubbed = createInst(Player.subInfo,"isSubscribed","StringValue")
				local subDays = createInst(Player.subInfo,"subDays","StringValue")
				while wait(1) do
					local newD
					currentDate = os.time()
						local success2, err2 = pcall(function()
						newD = subDat:GetAsync(Player.UserId)
					end)
					if success2 then
						isSubbed.Value = (newD + thirtyDays) - currentDate
						subDays.Value = math. floor(((newD + thirtyDays) - currentDate)/86400 + 0.5)
					else
						error(err2)
					end
				end
			end
		end
	else
		error(err)
	end
end)

local productFunctions = {}

productFunctions[subscriptionId] = function(receipt, Player)
	if Player then
		if not Player:FindFirstChild("subInfo") then
			local subInfo = createInst(Player,"subInfo","Folder")
			local isSubbed = createInst(Player.subInfo,"isSubscribed","StringValue")
			local subDays = createInst(Player.subInfo,"subDays","StringValue")
		end
		local success, err = pcall(function()
			subDat:SetAsync(Player.UserId,os.time())
		end)
		while wait(1) do
			local newD
			local currentDate = os.time()
			local success2, err2 = pcall(function()
				newD = subDat:GetAsync(Player.UserId)
			end)
			if success2 then
				Player:WaitForChild("subInfo").isSubscribed.Value = (newD + thirtyDays) - currentDate
				Player:WaitForChild("subInfo").subDays.Value = math. floor(((newD + thirtyDays) - currentDate)/86400 + 0.5)
			else
				error(err2)
			end
		end
		if err then
			error(err)
		else
			return true
		end
	end
end

local function processReceipt(receiptInfo)

	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
	print(playerProductKey)
	local purchased = false
	local success, errorMessage = pcall(function()
		purchased = purchaseHistoryStore:GetAsync(playerProductKey)
	end)

	if success and purchased then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	elseif not success then
		error("Data store error:" .. errorMessage)
	end

	local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not player then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	local handler = productFunctions[receiptInfo.ProductId]
	local success, result = pcall(handler, receiptInfo, player)
	if not success or not result then
		warn("Error occurred while processing a product purchase")
		print("ProductId:", receiptInfo.ProductId)
		print("Player:", player)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	local success, errorMessage = pcall(function()
		purchaseHistoryStore:SetAsync(playerProductKey, true)
	end)
	if not success then
		error("Cannot save purchase data: " .. errorMessage)
	end

	return Enum.ProductPurchaseDecision.PurchaseGranted
end

marketServ.ProcessReceipt = processReceipt
11 Likes