Datastore not saving

Greetings, I was making a ban system for my game and it seems to appear not to work. Assistance would be very helpful.

local DatastoreService = game:GetService("DataStoreService")
local MessagingService = game:GetService("MessagingService")

local AdminStore = DatastoreService:GetDataStore("Administrator")
local BannedPlayers = DatastoreService:GetDataStore("BannedPlayers")

local AdminRemotes = game.ReplicatedStorage.AdminRemotes


local function disp_time(t, plr)
	local data = BannedPlayers:GetAsync(plr.UserId)
	local duration = data.Time
	
	local days = math.floor(t/86400)
	local hours = math.floor(math.modf(t, 86400)/3600)
	local minutes = math.floor(math.modf(t, 3600)/60)
end



AdminRemotes.Ban.OnServerEvent:Connect(function(sender, target, reason, duration)
	if AdminStore:GetAsync(sender.UserId) then
		local uid = game.Players:GetUserIdFromNameAsync(target)
		
		BannedPlayers:SetAsync(uid, {
			["Time"] = duration,
			["Moderator"] = sender.Name,
			["Reason"] = reason
		})
		
		local data = {
			["target"] = target,
		}
		
		MessagingService:PublishAsync("BAN_PLAYER", data)
	else
		BannedPlayers:SetAsync(sender.UserId, {
			["Time"] = -1,
			["Moderator"] = "Server: ",
			["Reason"] = "Exploiting is not allowed."
		})
		
		sender:Kick()
	end
end)

AdminRemotes.CheckAdministrator.OnServerInvoke = function(sender)
	local isAdmin = AdminStore:GetAsync(sender.UserId)
	
	if isAdmin then
		return true
	else
		return false
	end
end

AdminRemotes.Kick.OnServerEvent:Connect(function(sender, target, reason)
	if AdminStore:GetAsync(sender.UserId) then
		local player = game.Players:FindFirstChild(target)
		
		if player then
			player:Kick("reason")
		end
	else
		BannedPlayers:SetAsync(sender.UserId, {
			["Time"] = -1,
			["Moderator"] = "Server: ",
			["Reason"] = "Exploiting is not allowed."
		})

		sender:Kick()
	end
end)

AdminRemotes.Ban.OnServerEvent:Connect(function(sender, target, reason, duration)
	if AdminStore:GetAsync(sender.UserId) then
		local uid = game.Players:GetUserIdFromNameAsync(target)

		if BannedPlayers:GetAsync(uid) then
			BannedPlayers:RemoveAsync(uid)
		end
	else
		BannedPlayers:SetAsync(sender.UserId, {
			["Time"] = -1,
			["Moderator"] = "Server: ",
			["Reason"] = "Exploiting is not allowed."
		})

		sender:Kick()
	end
end)

game.Players.PlayerAdded:Connect(function(player)
	local bandata = BannedPlayers:GetAsync(player.UserId)
	local t = os.time()
	
	if bandata then
		if bandata.Time ~= -1 then
			if t >= bandata.Time then
				BannedPlayers:RemoveAsync(player.UserId)
			else
				player:kick(disp_time())
			end
		end
	end
end)

Edit: When I fire the ban event it kicks me and when I rejoin it fails to save that data, from the previous server.

Only thing that is provided via console is,

There is a whitelist system connected to this ban system, and will be adding that in too.

local UIS = game:GetService("UserInputService")

local checkadmin = game.ReplicatedStorage:WaitForChild("AdminRemotes").CheckAdministrator

local plr = game.Players.LocalPlayer

local function isAdministrator()
	local AdminStatus = checkadmin:InvokeServer()
	
	if not AdminStatus then
		script.Parent:Destroy()
	end
end


UIS.InputBegan:Connect(function(key, gameprocessed)
	if not gameprocessed then
		if key.KeyCode == Enum.KeyCode.C then
			script.Parent.Main.Visible = not script.Parent.Main.Visible
		end
	end
end)

isAdministrator()
2 Likes

That warning in the console basically means it should be added to the DataStore, maybe try it in public servers?

2 Likes

Testing that now! Will let you know if anythings happens.

1 Like

Seems like the issue is still appearing, thanks for the suggestion though.

1 Like

No problem, I’m not sure why it won’t work.

2 Likes

Same, I’m so confused on how it doesn’t work. API’s are enabled (via game settigns) and have tried different ways on it. :man_shrugging:

Still stuck, if anyone has found a solution, please let me know! :slight_smile:

1 Like

Resolved by @corlights.

Thank you to all the help for those who provided it,

Would help if you shared the solution so anyone who runs into a similar problem could also reference what you used to help you fix this problem. That being said, at least to me, seems obvious what happened here at least as far as the console message goes.

Be mindful of DataStore Errors and Limits when working with DataStores. Also watch out for the cache! GetAsync caches return values for 4 seconds. This is a good example of why it’s not a wise idea to interact with DataStores every time a remote is fired.

1 Like

It wasn’t that, the issue was that it was sending too many requsts because the script wasnt reading what to do if the duration was “-1” i simply set it as

if bandata then
if bandata.Time ~= -1 then

end

The script did not read what to do if the ban was set to that, hence why the datastore was reading the script and saving but wasn’t banning.

To resolve this issue you would need to specify 2 things via the script,

local function disp_time(t, plr)
    local data = BannedPlayers:GetAsync(plr.UserId)
    local duration = data.Time
    
    local days = math.floor(t/86400)
    local hours = math.floor(math.modf(t, 86400)/3600)
    local minutes = math.floor(math.modf(t, 3600)/60)

    return 'Your ban expires in ' .. days .. ' days, ' .. hours .. ' hours, ' .. minutes .. ' minutes.'
end

To return the ban reason if they are banned with a duration, you would the need to rescript the ending of the script and make sure that you are providing a action when the player has a -1 duration, (perm ban). To do this you would type the following at the end of the script,

ame.Players.PlayerAdded:Connect(function(player)
    local bandata = BannedPlayers:GetAsync(player.UserId)
    local t = os.time()
    
    if bandata then
        if bandata.Time ~= -1 then
            if t >= bandata.Time then
                BannedPlayers:RemoveAsync(player.UserId)
            else
                player:kick(disp_time())
            end
        else -- add else here
            player:Kick("Banned perm")
        end
    end
end

You could also manipulate the kick message in your own way or using the disp_time function that we used earlier.

player:Kick(disp_time(bandata.Time, player))

Thank you for the solution, but I do hope you intend to do something in the future about using a GetAsync call every time a remote is fired? That will eventually hit limits if you are frequently using admin actions. You should be caching a user’s admin or ban status for the current game session so you can reference the cache as opposed to using DataStore methods when remotes are fired.

1 Like