I’m trying to make a twitter codes system in my game, and here’s the main script:
local DSS = game:GetService("DataStoreService")
local TCODESDS = DSS:GetDataStore("CodesDataStore")
local codes = {
["r3l3453"] = 1500
}
local asyncCodes = {
["r3l3453"] = false
}
game.ReplicatedStorage.RedeemCode.OnServerInvoke = function(player, codeValue)
codeValue = string.lower(tostring(codeValue))
local setAsyncCodes = {}
local playerUserId = player.UserId
local CodesData
local success, errormessage = pcall(function()
CodesData = TCODESDS:GetAsync(playerUserId)
end)
if CodesData ~= nil then
if table.find(CodesData, tostring(codeValue)) then
local codeValue2 = table.find(CodesData, tostring(codeValue))
if codeValue2 == false then
for _, v in pairs(CodesData) do
if v ~= playerUserId then
table.insert(setAsyncCodes, v)
end
end
if table.find(setAsyncCodes, tostring(codeValue)) then
setAsyncCodes[codeValue] = true
end
wait(0.5)
if table.find(setAsyncCodes, tostring(codeValue)) then
if setAsyncCodes[codeValue] == true then
CodesData:SetAsync(playerUserId, setAsyncCodes)
end
end
if table.find(codes, codeValue) then
player:WaitForChild("leaderstats")
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + tonumber(codes[codeValue])
return true
end
elseif codeValue2 == true then
return false
end
end
elseif CodesData == nil then
CodesData:SetAsync(playerUserId, asyncCodes)
if table.find(CodesData, tostring(codeValue)) then
local codeValue2 = table.find(CodesData, tostring(codeValue))
if codeValue2 == false then
for _, v in pairs(CodesData) do
if v ~= playerUserId then
table.insert(setAsyncCodes, v)
end
end
if table.find(setAsyncCodes, tostring(codeValue)) then
setAsyncCodes[codeValue] = true
end
wait(0.5)
if table.find(setAsyncCodes, tostring(codeValue)) then
if setAsyncCodes[codeValue] == true then
CodesData:SetAsync(playerUserId, setAsyncCodes)
end
end
if table.find(codes, codeValue) then
player:WaitForChild("leaderstats")
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + tonumber(codes[codeValue])
return true
end
elseif codeValue2 == true then
return false
end
end
end
end
For some reason, line 52 (the line under if codesdata == nil then) is giving me an error:
Why is this?
btw the redeem button script is:
local db = false
script.Parent.Activated:Connect(function()
if db == false then
local returnedValue = game.ReplicatedStorage.RedeemCode:InvokeServer(script.Parent.Text)
db = true
wait(0.05)
if returnedValue == true then
script.Parent.Text = "Success!"
elseif returnedValue == false then
script.Parent.Text = "Not valid"
end
wait(3)
db = false
script.Parent.Text = "REDEEM"
end
end)
You wouldn’t be calling :SetAsync() on CodesData in the first place. :SetAsync() should be used with the TCODESDS variable, since it’s the actual data store. CodesData is just the data that was saved, it doesn’t have any functions.
@BaldisFriend Change the bits where you put “CodesData:SetAsync” to “TCODESDS:SetAsync” instead.
elseif CodesData == nil then
TCODESDS:SetAsync(playerUserId, asyncCodes)
if table.find(CodesData, tostring(codeValue)) then
CodesData is nil, so you’re basically doing table.find(nil, value), which just won’t work. It looks like the whole block of code after that if statement is relying on CodesData existing, even though it wouldn’t be running unless CodesData was nil.
local DataStoreService = game:GetService("DataStoreService");
local CodeStore = DataStoreService:GetDataStore("CodesDataStore");
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local RedeemCode = ReplicatedStorage:WaitForChild("RedeemCode", 10);
local codes = {
r3l3453 = 1500;
};
local pendingChanges = {};
RedeemCode.OnServerInvoke = function(player, value)
if pendingChanges[player] then
return
end
local userId = player.UserId;
local success, result = pcall(function()
return CodeStore:GetAsync(userId);
end)
if success then
local existing = typeof(result)=="table" and result[value];
if existing then
warn(player, "already redeemed code:", value);
pendingChanges[player] = nil;
return false;
end
local codeValue = codes[value];
if codeValue then
local leaderstats = player:FindFirstChild("leaderstats");
local coins = leaderstats and leaderstats:FindFirstChild("Coins");
if coins then
coins.Value += codeValue;
end
CodeStore:UpdateAsync(userId, function(data)
data = data or {};
data[value] = true;
pendingChanges[player] = nil;
return data;
end)
return true;
else
warn(player, "attempted to redeem an invalid code:", value);
end
else
warn(result);
end
pendingChanges[player] = nil;
return false;
end
What does the output say? I’ve already tested it and it worked - you probably already have data stored for that code from your tests, so it gets rejected because it was already redeemed.
Edit: After looking at your first code attempt, I think you have a big of a misunderstanding about the logic here. You wouldn’t want to re-apply the code increment to their coins value every time they join the game, which is what it looks like you were attempting towards the bottom of your code - then they could just constantly leave and rejoin for free money (it’d add every time they rejoin), assuming that you’re saving their leaderstats elsewhere.
I accidentally put the redeem button’s text, instead of the code box’s text into the code.
However, it’s not creating any data so you can spam the codes, even if you rejoin.
I tried creating data, but I can’t.
This is what I have:
--[[
local DSS = game:GetService("DataStoreService")
local TCODESDS = DSS:GetDataStore("CodesDataStore")
local codes = {
["r3l3453"] = 1500
}
local asyncCodes = {
["r3l3453"] = false
}
game.ReplicatedStorage.RedeemCode.OnServerInvoke = function(player, codeValue)
codeValue = string.lower(tostring(codeValue))
local setAsyncCodes = {}
local playerUserId = player.UserId
local CodesData
local success, errormessage = pcall(function()
CodesData = TCODESDS:GetAsync(playerUserId)
end)
if CodesData ~= nil then
if table.find(CodesData, tostring(codeValue)) then
local codeValue2 = table.find(CodesData, tostring(codeValue))
if codeValue2 == false then
for _, v in pairs(CodesData) do
if v ~= playerUserId then
table.insert(setAsyncCodes, v)
end
end
if table.find(setAsyncCodes, tostring(codeValue)) then
setAsyncCodes[codeValue] = true
end
wait(0.5)
if table.find(setAsyncCodes, tostring(codeValue)) then
if setAsyncCodes[codeValue] == true then
CodesData:SetAsync(playerUserId, setAsyncCodes)
end
end
if table.find(codes, codeValue) then
player:WaitForChild("leaderstats")
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + tonumber(codes[codeValue])
return true
end
elseif codeValue2 == true then
return false
end
end
elseif CodesData == nil then
TCODESDS:SetAsync(playerUserId, asyncCodes)
local codeValue2 = table.find(CodesData, tostring(codeValue))
if codeValue2 == false then
for _, v in pairs(CodesData) do
if v ~= playerUserId then
table.insert(setAsyncCodes, v)
end
end
if table.find(setAsyncCodes, tostring(codeValue)) then
setAsyncCodes[codeValue] = true
end
wait(0.5)
if table.find(setAsyncCodes, tostring(codeValue)) then
if setAsyncCodes[codeValue] == true then
CodesData:SetAsync(playerUserId, setAsyncCodes)
end
end
if table.find(codes, codeValue) then
player:WaitForChild("leaderstats")
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + tonumber(codes[codeValue])
return true
end
elseif codeValue2 == true then
return false
end
end
end
--]]
-- Fixed Code:
local DataStoreService = game:GetService("DataStoreService");
local CodeStore = DataStoreService:GetDataStore("CodesDataStore");
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local RedeemCode = ReplicatedStorage:WaitForChild("RedeemCode", 10);
local codes = {
r3l3453 = 1500;
};
RedeemCode.OnServerInvoke = function(player, value)
local userId = player.UserId;
local success, result = pcall(function()
CodeStore:GetAsync(userId);
end)
if success then
local existing = typeof(result)=="table" and result[value];
if existing then
warn(player, "already redeemed code:", value);
return false;
end
local codeValue = codes[string.lower(value)];
if codeValue then
local leaderstats = player:FindFirstChild("leaderstats");
local coins = leaderstats and leaderstats:FindFirstChild("Coins");
if coins then
coins.Value += codeValue;
end
CodeStore:UpdateAsync(userId, function(data)
data = data or {};
data[value] = true;
end)
return true;
else
warn(player, "attempted to redeem an invalid code:", value);
return false;
end
else
warn(result);
end
return false;
end
It seems to be saving data fine for me, if you mean storing whether or not a code has been previously used. Leaderstats aren’t being saved in this code because I assume you’re doing that elsewhere, since there wasn’t an attempt to save the actual coins value in the first version of the code.
Here’s an example place that I set up with the same code:
Edit: Except for the local script, which I’m only invoking the server with and don’t have any text changes for whether it was a success or not.
Here’s the dev console showing my saved data from random codes that I tested:
You for some reason removed my “return” here when you were copying it.
My post:
The return is necessary, or else result is nil.
Edit: You also removed my return inside of the UpdateAsync function for some reason? Is there a reason why you think you need to remove these? UpdateAsync requires you to return the data that you want saved… or else there’s nothing to save.
No. They’re in a different scope. It won’t skip the rest of the script. If you have a pcall and don’t return anything, then there will be no result to read.
For example:
local function example()
local success, result = pcall(function()
return 4;
end)
print(result); -- prints 4
return 5;
end
print(example()); -- prints 5