How to create a one time use redeemable code using module scripts and DataStores

I want to create a system similar to those of Pet Sim X, and other games where you can receive a code from a Dev, and then enter that into a GUI

image_2024-01-28_124459228

My current code uses a RemoteEvent to send to the server where it uses a module script to check the available codes and then it removes it from the module script. The problem is I want it to be globally stored and whenever a user enters the code they receive the benefits and then the code is deleted on every server permanently

This is my code I have on the server script:

local CodesTable = require(script.ExclusiveCodesList)

game.ReplicatedStorage.CheckExclusiveCodes.OnServerEvent:Connect(function(Player,Text)
	local avalible = CheckCode(Text)
	game.ReplicatedStorage.ReturnCodeStatus:FireClient(Player, avalible)
	if avalible == true then
		print("CODE REEDEMED")
		local positionInTable = table.find(CodesTable, Text)
		table.remove(CodesTable, positionInTable)
		
		-- Redeem Stuff Here
		
	end
end)

function CheckCode(code)
	for i, v in pairs(CodesTable) do
		if v == code then
			return true
		end
	end
end
1 Like

You could store the code as a key in a DataStore, then when a player tries to redeem it, check if the key exists using GetAsync(), and if it does, redeem it and call RemoveAsync() on the key so it can’t be redeemed by anyone else.

I’ve got DataStores for all my other code (such as cash, xp and other stuff) but I’m not sure on how I would make it global or in which folder I should save the code or do I just keep it all on script without using physical string values?

2 Likes

DataStore’s are global and if you use the method I described, to save codes you could run this in the command bar

local Code = "CODEID"
local DataStore = game:GetService("DataStoreService"):GetDataStore("Codes")
DataStore:SetAsync(Code, true)
1 Like

When you get the DataStore Codes does that create a new DataStore or use the existing one?

1 Like

If a DataStore with the name hasn’t been accessed before it’ll created a new one, otherwise it’ll access the existing one.

1 Like

Okay, thanks I’ll try this out.

2 Likes

Does DataStore allow the use of saving string values with spaces in it? As since I’ve got all my codes on a table I’m converting the table into a long string so,

local Codes = {
	"code",
	"code2",

}

turns into

"code code2"
1 Like

I’ve just realized that I can just set the converted code into each individual code using a for i, v in pairs loop. Thanks again.

2 Likes

do you really have to turn it into a long string?

1 Like

No, I’m now just using for i, v in pairs loop to set the datastore:

local DataStore = game:GetService("DataStoreService"):GetDataStore("ExclusiveCodes")

for i, v in pairs(CodesTable) do
	if DataStore:GetAsync(v) then else
		print(v)
		DataStore:SetAsync(v, true)
	end
end

I havent tested this yet but It’s my current idea

1 Like

So my code works from server but whenever I leave it doesn’t save, I’m not sure if I need to use set Async when the player leaves or something else.

local DataStore = game:GetService("DataStoreService"):GetDataStore("ExclusiveCodes")

for i, v in pairs(CodesTable) do
	if DataStore:GetAsync(v) then else
		print(v)
		DataStore:SetAsync(v, true)
	end
end




game.ReplicatedStorage.CheckExclusiveCodes.OnServerEvent:Connect(function(Player,Text)
	local avalible = CheckCode(Text)
	game.ReplicatedStorage.ReturnCodeStatus:FireClient(Player, avalible)
	if avalible == true then
		print("CODE REEDEMED")
		
		DataStore:SetAsync(Text, false)
		
		-- Redeem Stuff Here
		
	end
end)
1 Like

So I’ve tried multiple solutions and this is where my code has gotten up to:

local CodesTable = require(script.ExclusiveCodesList)

local DataStore = game:GetService("DataStoreService"):GetDataStore("ExclusiveCodes")

local SaveData = {}
for i, v in pairs(CodesTable) do
	local data = DataStore:GetAsync("ExclusiveCodes")
	print(data[v])
	if not data[v] then
		SaveData[v] = true 
		else
		SaveData[v] = data[v]
	end
	print(data[v])
end
DataStore:SetAsync("ExclusiveCodes", SaveData)

game.ReplicatedStorage.CheckExclusiveCodes.OnServerEvent:Connect(function(Player,Text)
	local avalible = CheckCode(Text)
	game.ReplicatedStorage.ReturnCodeStatus:FireClient(Player, avalible)
	if avalible == true then
		print(SaveData)
		SaveData[Text] = false
		print(SaveData[Text])
		
		local success = nil
		local errorMsg = nil
		local attempt = 1
		
		repeat
			success, errorMsg = pcall(function()
				DataStore:SetAsync("ExclusiveCodes", SaveData)
			end)

			attempt += 1
			if not success then
				warn(errorMsg)
				task.wait(3)
			end
		until success or attempt == 5
		
		print(DataStore:GetAsync("ExclusiveCodes"))
		-- Redeem Stuff Here
		
	end
end)

function CheckCode(code)
	local data = DataStore:GetAsync("ExclusiveCodes")
	if data[code] then
		return true
	else
		return false
	end
end

It all works when in the same server but when I leave and rejoin the DataStore doesn’t work and you can keep redeeming the codes.

1 Like
for i, v in pairs(CodesTable) do
	if DataStore:GetAsync(v) == nil then
		DataStore:SetAsync(v, true)
	end
end

your old check would overwrite if the value is false, if its TRUE (boolean) then do nothing else, reset the code to true. the snippet i put above only calls setasync if the code is nil in the datastore

1 Like

Wouldn’t that only work If I was using one main code? I’m using a table from a module script:

local Codes = {
	"Code1",
	"Code2",
}

return Codes

Sorry If I didn’t make that part clear.

1 Like

no? it still loops though that table checking if it exists, if not, it creates a new key in the datastore

When I’m printing the value it returns with whether its redeemable (true or false) but then comes up with Instance

1 Like

Thanks, it seems to be working.

2 Likes

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