DataStore not saving [SOLVED]

Hello everyone!

I want to do a code system for free UGCs but the data doesn’t save.

Please help me!

Video :
https://gemootest.s3.us-east-2.amazonaws.com/s/res/606690691329454080/610bf3744b46c67efcaca22abffef6c0.mp4?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIARLZICB6QQHKRCV7K%2F20240120%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20240120T091310Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7200&X-Amz-Signature=88cab821eacc05a6a1a11e25b01877a714a76a2449a052e1209470f83b2db613

Script :

local CodeManager = {}

local codes = {}
local DataStoreService = game:GetService("DataStoreService")
local codeDataStore = DataStoreService:GetDataStore("CodeDataStore")

function CodeManager.AddCode(code, itemID, quantity, creatorUserID)
	if code == "" then
		warn("Key name can't be empty.")
		return
	end

	codes[code] = {
		ItemID = itemID,
		Quantity = quantity,
		CreatorUserID = creatorUserID,
		RedeemerUserID = nil,
		RedeemedAt = nil,
	}

	local success, err = pcall(function()
		codeDataStore:SetAsync(code, codes[code])
	end)

	if not success then
		warn("Failed to save code to DataStore:", err)
	end
end

function CodeManager.GetCodeInfo(code)
	return codes[code]
end

function CodeManager.RedeemCode(code, redeemerUserID)
	local codeInfo = codes[code]

	if codeInfo and not codeInfo.RedeemerUserID then
		codeInfo.RedeemerUserID = redeemerUserID
		codeInfo.RedeemedAt = os.time()

		local success, err = pcall(function()
			codeDataStore:SetAsync(code, codes[code])
		end)

		if not success then
			warn("Failed to save updated code to DataStore:", err)
		end

		return true
	else
		return false
	end
end

function CodeManager.RemoveCode(code)
	codes[code] = nil

	local success, err = pcall(function()
		codeDataStore:RemoveAsync(code)
	end)

	if not success then
		warn("Failed to remove code from DataStore:", err)
	end
end

function CodeManager.LoadCodesFromDataStore()
	
	local success, result = pcall(function()
		local keys = codeDataStore:ListKeysAsync():GetCurrentPage()

		for _, key in ipairs(keys) do
			local success, value = pcall(function()
				return codeDataStore:GetAsync(key)
			end)

			if success then
				codes[key] = value
			else
				warn("Failed to load code from DataStore:", value)
			end
		end
	end)

	if not success then
		warn("Failed to load codes from DataStore:", result)
	end
end

return CodeManager
1 Like

Well I’m gonna adress some issues first:

I’ts not a good idea to load all keys from a datastore and then check whether the “code” exists. It would be better if you tried to :GetAsync(redeemCode) and check if that code is correct.

In your dataStructure for the code item

I see RedeemerUserID - That’s only gonna be working if every code can onlly ne used by one single person! I’d say you create that code item without Redeemer or RedeemedAt and then store the code in the codes datastore, whenever a user tries to redeem a code, check if the code they tried to redeem is in the codes datastore - if it is: check a redeemdatastore for the player and check if the code has already been redeemed by that player:

if table.find(redeemDataStore:GetAsync(player.UserId) , codeTheyRedeemedId) then
    print("code alr redeemed") 
    return 
end
2 Likes

I thought of something like this:

local DataStoreService	= game:GetService("DataStoreService")
local RedeemDataStore 	= DataStoreService:GetDataStore("RedeemDataStore")
local CodeDataStore		= DataStoreService:GetDataStore("CodeDataStore")

local maxTries 			= 5
local tryCooldown		= 2 --seconds

local CodeManager = {}

local function createCode(codeName,code,INDEX)
	if INDEX > maxTries then
		warn(tostring(codeName).." could not be saved!")
		return
	end
	local success = pcall(function()
		CodeDataStore:SetAsync(codeName,code)
	end)

	if success then
		print("success")
		return
	end
	
	task.wait(tryCooldown)
	createCode(codeName,code,INDEX+1) --recursion
end

local function checkCodeName(codeName)
	local success,code = pcall(function()
		CodeDataStore:GetAsync(codeName)
	end)
	
	if success and code and code["active"] > tick() or code["active"] < 0 then
		return true,code
	end
	
	return false
end

function CodeManager.newCode(codeName,itemId,count,creatorId,lifeTime) --lifetime in seconds or -1 for infinite
	local newCode = {
		itemId = itemId,
		itemC  = count,
		active = tick() + (lifeTime > 0 and lifeTime) or (-2*tick()),
		
		
		creatorId = creatorId;
	}
	
	createCode(string.lower(codeName),newCode,1)
end

local function giveItem(player,code)
	
end

local function playerRedeemCode(player,codeName,data,code)
	local newData = table.insert(data["codes"],codeName)
	local success = pcall(function()
		CodeDataStore:SetAsync(player.UserId,newData)
	end)
	
	giveItem(player,code)
end


function CodeManager.redeemCode(player,codeName)
	local codeName 	 = string.lower(codeName)
	local state,code = checkCodeName(codeName)
	
	if state == true then
		local success,data = pcall(function()
			CodeDataStore:GetAsync(player.UserId)
		end)
		
		if success then
			if data["codes"] and not table.find(data["codes"],codeName) then
				playerRedeemCode(player,codeName,data,code)
			end
		else
			RedeemDataStore:SetAsync(player.UserId,{})
			data = {codes = {}}
			playerRedeemCode(player,codeName,data,code)
		end
	end
end

return CodeManager

2 Likes

I need help with my main script, can you add me on Discord? (heyheyyt)

1 Like

I am having this error now :
DataStoreService: CantStoreValue: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. API: SetAsync, Data Store: CodeDataStore (x5)

1 Like

The error occurs because you’re possibly using a type of character encoding that is not UTF-8. It could possibly be a character issue. Could you please provide the data you’re trying to store? (Perhaps by printing it out?)

1 Like