Help; Values saved in DataStore keeps resetting!

Hey guys! :slight_smile:

So I’ve been working on this gamecode system for some time. The last problem I’m having is the fact that the values I save when the player leaves the game keep resetting for some reason. Because when I join back, the ‘Uses’ of said key are back to what it was. Despite the fact that whatever was saved did change. (Tested it by printing the values before stopping the test run, which gave the correct values. But when I pressed play solo again the values reset to the original values)

When I join

2018-05-28_02-06-33

When I leave

2018-05-28_02-08-41

When I join again

2018-05-28_02-09-42

ServerScript


local RS = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local MarketplaceService = game:GetService("MarketplaceService")

local Variables = require(RS:WaitForChild("Modules"):WaitForChild("KeyCodes"):WaitForChild("Variables")) 

local KeyCodeModule = require(ServerStorage:WaitForChild("Modules"):WaitForChild("Codes"):WaitForChild("KeyCodes")) 

local DS = game:GetService("DataStoreService")
local KeyDS = DS:GetDataStore("SomeOtherSortOfDataStore")
local BoughtKeyDS = DS:GetDataStore("SomeSortOfDataStore")

local PurchaseHistory = DS:GetDataStore("PurchaseHistory")
local CurrentValue

game.Players.PlayerAdded:connect(function(Player)	
	local UserTemplate = script.Data.UserTemplate:Clone()
	UserTemplate.Name = "Player_"..Player.userId
	UserTemplate.Parent = game:GetService("ServerStorage").GameCodes
	
	local Data = BoughtKeyDS:GetAsync(Player.userId.."_Keys");
	 
	if typeof(Data) == "table" then
		for i,key in pairs(Data) do
			for y,v in pairs(key) do
				print(i,key,y,v)
			end
			local KeyTemplate = script.Data.KeyTemplate:Clone()
			KeyTemplate.Name = i.."-GameCode"
			KeyTemplate.Duration.Value = key.Duration
			KeyTemplate.Owner.Value = key.Owner
			KeyTemplate.KeyName.Value = key.KeyName
			KeyTemplate.Uses.Value = key.Uses
			
			KeyTemplate.Parent = UserTemplate 
			
			if key.Uses > 0 and key.Duration > tick() then
				local LoggedKey = script.GUIs.KeyTemplate:Clone()
				LoggedKey.Key.Text = key.KeyName
				LoggedKey.Nr.Text = key.Uses.."U"
				LoggedKey.Name = key.Uses.."GameKey"
				LoggedKey.Parent = Player.PlayerGui:WaitForChild("KeyMenu"):FindFirstChild("KeyLog", true)
			end
		end
	else
		BoughtKeyDS:SetAsync(Player.userId.."_Keys", {}) 
	end
	
	local ActiveKey = UserTemplate.ActiveKey
	
	ActiveKey.CurrentTime.Value = tick()
	
	ActiveKey.Changed:connect(function()
		CurrentValue = ActiveKey.Value
		repeat
			ActiveKey.CurrentTime.Value = ActiveKey.CurrentTime.Value + 0.001
			wait(0.001)
		until ActiveKey.CurrentTime.Value > ActiveKey.Duration.Value or ActiveKey.Value ~= CurrentValue
		
		Player.PlayerGui.KeyMenu.Enabled = true
	end)
end)


game.Players.PlayerRemoving:connect(function(Player)
	local KeyData = game:GetService("ServerStorage").GameCodes["Player_"..Player.userId]
	local KeyTable = {}
	
	for i,key in pairs(KeyData:GetChildren()) do
		if key:IsA("Folder") then
			table.insert(KeyTable, {
				["Duration"] = key.Duration.Value;
				["KeyName"] = key.KeyName.Value;
				["Owner"] = key.Owner.Value;
				["Uses"] = key.Uses.Value;
			})
		end
	end
	
	for i,key in pairs(KeyTable) do
		for y,v in pairs(key) do
			print(i,key,y,v)
		end
	end
	
	BoughtKeyDS:SetAsync(Player.userId.."_Keys", KeyTable) 
	KeyData:Destroy()
end)

local function Redeem(Player, SubmittedKeyCode)
	local Data = {
		["Generated"] = KeyDS:GetAsync(SubmittedKeyCode);
		["Purchased"] = game:GetService("ServerStorage").GameCodes["Player_"..Player.userId]; 
	}
	
	if not string.match(SubmittedKeyCode, "PAIDKEY") then
		if SubmittedKeyCode == Data["Generated"].KeyName then
			if Data["Generated"].Duration > tick() then
				if Data["Generated"].Uses > 0 then
					KeyCodeModule.EditCodeData(SubmittedKeyCode, false)
					print(Player.Name .. " has redeemed key '" .. Data["Generated"].KeyName  .. "', which expires after: " .. Data["Generated"].Duration)
					return "Redeemed"
				else
					return "Depleted"
				end
			else
				return "Expired"
			end
		else
			return false
		end
	elseif string.match(SubmittedKeyCode, "PAIDKEY") then
		for _,KeyData in pairs(Data["Purchased"]:GetChildren()) do
			if KeyData:IsA("Folder") then
				if SubmittedKeyCode == KeyData.KeyName.Value then
					if KeyData.Duration.Value > tick() then
						if KeyData.Uses.Value > 0 then
							KeyData.Uses.Value = KeyData.Uses.Value-1
							
							Data["Purchased"].ActiveKey.Value = SubmittedKeyCode
							Data["Purchased"].ActiveKey.Duration.Value = KeyData.Duration.Value  
							print(KeyData.Owner.Value .. " has redeemed key '" .. KeyData.KeyName.Value  .. "', which expires after: " .. KeyData.Duration.Value .. " and has " .. KeyData.Uses.Value .. " uses left.")
							return "Redeemed"
						else
							return "Depleted"
						end
					else
						return "Expired"
					end
				end
			end
		end
		return false
	end
end

Variables.Remotes["EnteredKey"].OnServerInvoke = Redeem

local Products = {
	["1 hour access"] = 165213438; 
	["8 hours access"] = 165213642; 
	["12 hours access"] = 165213776; 
	["168 hours access"] = 165214319; 
	["336 hours access"] = 165214425; 
}

MarketplaceService.ProcessReceipt = function(receiptInfo) 
	local info = game:GetService("MarketplaceService"):GetProductInfo(receiptInfo.ProductId, Enum.InfoType.Product)
	for i, Player in ipairs(game.Players:GetPlayers()) do
		if Player.userId == receiptInfo.PlayerId then
			if receiptInfo.ProductId == Products[info.Name] then
				local KeyNumber = math.random(1, 100000)
				local KeyData = game:GetService("ServerStorage").GameCodes["Player_"..Player.userId]
				
				local NewKey = script.Data.KeyTemplate:Clone()
				NewKey.Name = #KeyData:GetChildren().."-GameCode"
				NewKey.Duration.Value = tick() + (string.gsub(string.gsub(info.Name, "%D+", ""), "%D+", "") * 3600)
				NewKey.Owner.Value = Player.userId
				NewKey.KeyName.Value = "PAIDKEY-" .. KeyNumber
				NewKey.Uses.Value = 2
				NewKey.Parent = KeyData
				
				local KeyTable = {}
				
				for i,key in pairs(KeyData:GetChildren()) do
					if key:IsA("Folder") then
						table.insert(KeyTable, {
							["Duration"] = key.Duration.Value;
							["KeyName"] = key.KeyName.Value;
							["Owner"] = key.Owner.Value;
							["Uses"] = key.Uses.Value;
						})
					end
				end
	
				for i,v in ipairs(KeyTable) do
					print(i, v)
				end
				
				BoughtKeyDS:SetAsync(Player.userId.."_Keys", KeyTable) 
				
				Variables.Remotes["KeyPurchase"]:FireClient(Player, "PAIDKEY-" .. KeyNumber)
			end
		end
	end
	
	local PlayerProductKey = "Player_" .. receiptInfo.PlayerId .. "_purchase_" .. receiptInfo.ProductId
	PurchaseHistory:IncrementAsync(PlayerProductKey, 1)
	
	return Enum.ProductPurchaseDecision.PurchaseGranted		
end

LocalScript


local RS = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local StarterGui = game:GetService("StarterGui")

local Variables = require(RS:WaitForChild("Modules"):WaitForChild("KeyCodes"):WaitForChild("Variables")) 

local Player = script.Parent.Parent.Parent.Parent.Parent
local MainGUI = Player:WaitForChild("PlayerGui"):WaitForChild("KeyMenu"); 

local Input = MainGUI:FindFirstChild("KeyBox", true)
local Purchase = MainGUI:FindFirstChild("Purchase", true) 

local Debounce = false

if game.Players.LocalPlayer.UserId ~= 416387433 then
	StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.All, false)
	Player:WaitForChild("PlayerGui"):SetTopbarTransparency(0)
	MainGUI.Enabled = true 
end 	

Purchase.MouseButton1Click:Connect(function()
	MainGUI.Main.Body.Visible = false
	MainGUI.Main.Shop.Visible = true
end)

for _,button in pairs(MainGUI.Main.Shop.Main:GetDescendants()) do
	if button:IsA("GuiButton") then
		button.MouseButton1Click:connect(function()
			if Debounce == false then
				Debounce = true
				if string.gsub(button.Parent.Name, "%D+", "") == "1" then
					MarketplaceService:PromptProductPurchase(game.Players.LocalPlayer, 165213438)
				elseif string.gsub(button.Parent.Name, "%D+", "") == "8" then
					MarketplaceService:PromptProductPurchase(game.Players.LocalPlayer, 165213642)
				elseif string.gsub(button.Parent.Name, "%D+", "") == "12" then
					MarketplaceService:PromptProductPurchase(game.Players.LocalPlayer, 165213776)
				elseif string.gsub(button.Parent.Name, "%D+", "") == "168" then
					MarketplaceService:PromptProductPurchase(game.Players.LocalPlayer, 165214319)
				elseif string.gsub(button.Parent.Name, "%D+", "") == "336" then
					MarketplaceService:PromptProductPurchase(game.Players.LocalPlayer, 165214425)
				end
				Debounce = false
			end
		end)
	end
end 

Input.FocusLost:Connect(function(enterPressed)
	if enterPressed == true then
		if Debounce == false then
			if Input.Text ~= "" then
				Debounce = true
				local KeyCheck = Variables.Remotes["EnteredKey"]:InvokeServer(string.gsub(Input.Text, "%s+", "N/A"):sub(1,40))
				if KeyCheck == "Redeemed" then
					Input.Text = ""
					Input.PlaceholderText = "Redeemed!"
					wait(1)
					MainGUI.Enabled = false
					
					Player.PlayerGui:SetTopbarTransparency(0.4)
					StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.All, true)
				elseif KeyCheck == "Expired" then
					Input.Text = ""
					Input.PlaceholderText = "This key has expired; sorry!"
				elseif KeyCheck == "Depleted" then
					Input.Text = ""
					Input.PlaceholderText = "This code has been depleted! Please, try another."
				elseif KeyCheck == "Not Owner" then
					Input.Text = ""
					Input.PlaceholderText = "This is not your code!"
				elseif KeyCheck == false then
					Input.Text = ""
					Input.PlaceholderText = "This key is invalid! Please check your spelling and try again."
				end
				Debounce = false
			end
		end
	end
end)

Variables.Remotes["KeyPurchase"].OnClientEvent:Connect(function(Key)
	MainGUI.Main.Shop.Visible = false
	MainGUI.Main.Body.Visible = true
	
	local LoggedKey = script.KeyTemplate:Clone()
	LoggedKey.Key.Text = Key
	LoggedKey.Nr.Text = "2U"
	LoggedKey.Parent = MainGUI:FindFirstChild("KeyLog", true)
	LoggedKey.Name = "2GameKey"
end) 

What am I doing wrong? :worried:

Oddly enough it somewhat resolved itself. :slight_smile:

:ok_hand:

I would recommend using UpdateAsync instead of set so you can be sure you are not overwriting existing data. I would also recommend you use Pcall to wrap your data store calls to catch any errors (there will be errors on Roblox’s end).

2 Likes

Awesome, thanks for the suggestions! Will definitely do that :smiley:

1 Like