Datastore not working

I’m making an automatic anti-exploit system, when someone fires a remote that they shouldn’t, they get banned. My datastore contains a table with all datastore information.
Datatable[1] is the reason why someone is banned, if it’s nil, then the player is not banned.
Here’s my script:

local dss = game:GetService("DataStoreService")
local tablestore = dss:GetDataStore("HML2_Table")
--    table_order = {BanReason,Value,Value,Value,Value,Value}
local default_table = {nil,0,0,0,0,0}

game.Players.PlayerAdded:Connect(function(plr)
	local plrInfoTable = tablestore:GetAsync(plr.UserId) or default_table
	print(plrInfoTable)
	
	if plrInfoTable[1] ~= nil then
		plr:Kick(plrInfoTable[1])
	end
end)

game.ReplicatedStorage.Project_Stainless.ReplicateGlobalBan.Event:Connect(function(target,reason)
	local plrInfoTable = tablestore:GetAsync(target.UserId)
	print(plrInfoTable)
	--plrInfoTable[1] = reason
	--tablestore:SetAsync(target.UserId,reason)
	game.ReplicatedStorage.BanClient:FireClient(target)
	wait(.1)
	target:Kick(reason)
end)

(BanClient remote plays evil morty for the client)

For some reason the first time (PlayerAdded) everything prints as it should [table complex_code].
But when I ban a player, or test the banning system, the same piece of code returns nil.
Why is this?

1 Like

You have the saving part commented out, but assuming it’d be uncommented in your normal game, there is one issue: you’re only saving the reason to the datastore, which I’m assuming is a string. You should save the plrInfoTable table instead.

Also, instead of using GetAsync and then SetAsync, you should use UpdateAsync which combines both and solves accidental data overrides issues:

game.ReplicatedStorage.Project_Stainless.ReplicateGlobalBan.Event:Connect(function(target,reason)
	tablestore:UpdateAsync(target.UserId, function(plrInfoTable)
		plrInfoTable = plrInfoTable or {nil,0,0,0,0,0}
		plrInfoTable[1] = reason
		return plrInfoTable
	end)
	game.ReplicatedStorage.BanClient:FireClient(target)
	wait(.1)
	target:Kick(reason)
end)

Also, while this doesn’t impact your code in its current state, you shouldn’t be using the same default_table variable in player-dependent functions. If you were to i.e. set a value to it on PlayerAdded, then every further event would see that value as well. What you should do instead is re-define the table every time in the function, like so:

game.Players.PlayerAdded:Connect(function(plr)
	local default_table = {nil,0,0,0,0,0}
	
	local plrInfoTable = tablestore:GetAsync(plr.UserId) or default_table
	print(plrInfoTable)
	
	if plrInfoTable[1] ~= nil then
		plr:Kick(plrInfoTable[1])
	end
end)

or eventually like this, which I think is the more clear and common way of doing it:

game.Players.PlayerAdded:Connect(function(plr)
	local plrInfoTable = tablestore:GetAsync(plr.UserId) or {nil,0,0,0,0,0}
	print(plrInfoTable)
	
	if plrInfoTable[1] ~= nil then
		plr:Kick(plrInfoTable[1])
	end
end)
2 Likes