Warn module somehow isn't saving warns properly

I attempted to make a module that allow to warn peoples and save they warn when they rejoin so every staff know if somewone abused on thems or they did something wrong and try to escape the game.

local ValidReasons = {
	"Inapropriate Audio",
	"Detain Abuse",
	"Admin Abuse",
	"Blocking",
	"Trolling",
	"Btools Abuse",
	"Fake Donation",
	"Exploiting",
	"Break Roblox TOS",
	"Moderation Bypass",
}

-- Services
local DatastoreService = game:GetService("DataStoreService")
local HttpService = game:GetService("HttpService")
local PlayersServ = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- Warning Datastore
local WarningDataStore = DatastoreService:GetDataStore("Warnings")

-- NumberOfWarningsRequiredForBan
local RequiredWarnings = 4

-- Store Warnings in a roblox table
local ActiveWarningListForPlayers = {}

local System = {}

local function WarnUser(UserId:number,Reason:string,sender:string)
	if not table.find(ValidReasons,Reason)  then
		return
	end
	
	local self = System

	local warningsamount = 0

	for i,v in ActiveWarningListForPlayers[UserId] do
		warningsamount +=1
	end

	warningsamount += 1

	ActiveWarningListForPlayers[UserId][warningsamount] = {
		Sender = sender,
		ReasonGiven  = Reason
	} 

	if warningsamount >= RequiredWarnings  then
		ActiveWarningListForPlayers[UserId] = {}

		-- Ban the player temporary with banasync
		PlayersServ:BanAsync({
			UserIds = {UserId},
			ApplyToUniverse = true,
			Duration = 250,
			DisplayReason =  "You have reachen the maximum amount of warnings allowed, Your last warning is "..Reason..".   If you think this is a mistake please contact our support team",
			PrivateReason = "Banned for max warning by admin for "..Reason,
			ExcludeAltAccounts = true
		})
		--warn("Player has been banned for "..reason.." by admin")


		self:SaveWarnings(UserId)
 
		if PlayersServ:GetPlayerByUserId(UserId) then
			PlayersServ:GetPlayerByUserId(UserId):Kick( "A moderation action had been taken, please rejoin to review it.")
		end
 
		task.wait(2)
		ActiveWarningListForPlayers[UserId] = nil

		return
	end


	if PlayersServ:GetPlayerByUserId(UserId) then
		ReplicatedStorage.RemoteEvents.Warnings:FireClient(PlayersServ:GetPlayerByUserId(UserId),sender,Reason)
	end
end

function System:Warn(UserId:number,Reason:string,sender:string)
	task.spawn(WarnUser,UserId,Reason,sender)   
end


function System:RemoveWarn(UserId:number,warnnumber:number)
	if not ActiveWarningListForPlayers[UserId][warnnumber] then
		return
	end
	
	local amountofwarns = 0
	
	for i,v in ActiveWarningListForPlayers[UserId] do
		amountofwarns += 1
	end
	
	if amountofwarns == 0 then
		return
	end
	
	local lastwarns = {}
	local afterwarns = {}
	
	for i,v in ActiveWarningListForPlayers[UserId] do
		if i < warnnumber  then
			lastwarns[i] = v
		end
		
		if i > warnnumber then
			afterwarns[i] = v
		end
	end
	
	-- Reclassify the warn by removing 1 from every i in afterwarns then put them back
	ActiveWarningListForPlayers[UserId] = {}
	
	for i,v in lastwarns do
		ActiveWarningListForPlayers[UserId][i] = v
	end
	
	for i,v in afterwarns do
		ActiveWarningListForPlayers[UserId][i-1] = v
	end

    -- Avoid memory leaks
	lastwarns = nil
	afterwarns = nil
end

function System:GetWarnings(UserId:number)
	-- Load from json to the table
	local Success, Data = pcall(function()
		return WarningDataStore:GetAsync(UserId)
	end)
	
	if Success and Data then
		ActiveWarningListForPlayers[UserId] = HttpService:JSONDecode(Data)
		print(Data)
	end
	
	if Success and not Data then
		ActiveWarningListForPlayers[UserId] = {}
	end
	
	return ActiveWarningListForPlayers[UserId]
end


function System:SaveWarnings(UserId:number)
	
	if not ActiveWarningListForPlayers[UserId] then
		warn("Save Operation failed. Warnings wasnt on the roblox table which might cause dataloss")
		return
	end 
	
	-- Use json to convert into string
	local Success, Error = pcall(function()
		WarningDataStore:SetAsync(UserId,HttpService:JSONEncode(ActiveWarningListForPlayers[UserId]))
	end)
	
    if not Success then
		warn("Failed to Save Warnings for "..UserId.." | Reason: "..Error)
	end
	
end

return System

Fire to warn script

-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- Modules
local ModerationModule = require(script.Parent.Parent.Modules.ModerationSystem)
local RankingSystem = require(script.Parent.Parent.Modules.RankingSystem)

Players.PlayerAdded:Connect(function(player)
	ModerationModule:GetWarnings(player.UserId)
	RankingSystem:RankUser(player.UserId)
	
end)

Players.PlayerRemoving:Connect(function(player)
	ModerationModule:SaveWarnings(player.UserId)
end)

ReplicatedStorage.BindableEvents.FireForWarning.Event:Connect(function(userid, reason, sender)
	ModerationModule:Warn(userid, reason, sender)
end)

However the 141 lines print [] each time i rejoin

1 Like

Have you checked to see what is being saved to the datastore when you leave?

What does your script show for ActiveWarningListForPlayers[UserId] and the resulting JSON encoded string right before you save it to the datastore?

I would start there and confirm that the expected values are being sent to the datastore.


image

There is the whole saving proccess of the table system. and warning system

Saving

function System:SaveWarnings(UserId:number)
	
	if not ActiveWarningListForPlayers[UserId] then
		warn("Save Operation failed. Warnings wasnt on the roblox table which might cause dataloss")
		return
	end 
	
	for i,v in ActiveWarningListForPlayers[UserId] do
		print(i,v)
	end
	
	local ratio,encoding = pcall(function()
		return HttpService:JSONEncode(ActiveWarningListForPlayers[UserId])
	end)
	
	print(encoding)
	
	if not ratio then
		warn(encoding)
	end
	
	-- Use json to convert into string
	local Success, Error = pcall(function()
		WarningDataStore:SetAsync(UserId,encoding)
	end)
	
    if not Success then
		warn("Failed to Save Warnings for "..UserId.." | Reason: "..Error)
	end
	
end

Give a warning

local function WarnUser(UserId:number,Reason:string,sender:string)
	if not table.find(ValidReasons,Reason)  then
		return
	end
	
	local self = System

	local warningsamount = 0

	for i,v in ActiveWarningListForPlayers[UserId] do
		warningsamount +=1
	end

	warningsamount += 1

	ActiveWarningListForPlayers[UserId][warningsamount] = {
		Sender = sender,
		ReasonGiven  = Reason
	} 

	if warningsamount > RequiredWarnings  then
		ActiveWarningListForPlayers[UserId] = {}

		-- Ban the player temporary with banasync
		PlayersServ:BanAsync({
			UserIds = {UserId},
			ApplyToUniverse = true,
			Duration = BanDurationInSeconds,
			DisplayReason =  "You have reachen the maximum amount of warnings allowed, Your last warning is "..Reason..".   If you think this is a mistake please contact our support team",
			PrivateReason = "Banned for max warning by admin for "..Reason,
			ExcludeAltAccounts = false
		})
		--warn("Player has been banned for "..reason.." by admin")


		self:SaveWarnings(UserId)
 
		if PlayersServ:GetPlayerByUserId(UserId) then
			PlayersServ:GetPlayerByUserId(UserId):Kick( "A moderation action had been taken, please rejoin to review it.")
		end
 
		task.wait(2)
		ActiveWarningListForPlayers[UserId] = nil

		return
	end


	if PlayersServ:GetPlayerByUserId(UserId) then
		ReplicatedStorage.RemoteEvents.Warnings:FireClient(PlayersServ:GetPlayerByUserId(UserId),sender,Reason)
	end
end

function System:Warn(UserId:number,Reason:string,sender:string)
	task.spawn(WarnUser,UserId,Reason,sender)   
end

Have you tried saving to the datastore without JSON encoding?

local warningsamount = 0

for i,v in ActiveWarningListForPlayers[UserId] do
	warningsamount +=1
end

warningsamount += 1

ActiveWarningListForPlayers[UserId][warningsamount] = {
	Sender = sender,
	ReasonGiven  = Reason
} 

Also unrelated question: why not just use table.insert(ActiveWarningListForPlayers[UserId], ...) instead of manually keeping track of the the warning amount like that.

Also you should be able to change the settings of your output window so printing tables actually prints the content and not just the table address

Well, how can i do that with that. 1 year i have been told too and still didn’t make it work

table.insert don’t support [ ] which is needed for my system to count who own the following warnings.

Uncheck “Log Mode”

table.insert just pushes whatever you pass to the end of the array. You can use #ActiveWarningListForPlayers[UserId] to get the number of active warnings a player has

im using a format such as [UserId][number] = {Reason = “”, Sender = “”}

number allow to use tier tool to calculate the warn number to remove it if needed.

Ah I see. Fair enough.

But yea, I’d try saving to the datastore without encoding to see if that makes a difference

image

gettings an empty table for some reasons.
Added a print to know if not data and keeps printing like it didnt save.

Are those print statements from SaveWarnings or GetWarnings?

those prints are for GetWarnings currently

can you show what print(ActiveWarningListForPlayers[UserId]) logs in SaveWarnings?


image

You cut off what the print says for line 150 in the picture. But it looks like it’s an empty table?

image