Help with stats

Thank you I’ll take a look at it when I’m available. In the leaderstat script I had previously was there anything special that happened for the donations that I should be aware about? Like firing anything or stuff? Or is it just a leaderstat that displays how much I’ve raised / donated and saves it

It was the latter of the two. Only a leaderstat.

I have one question.


In this event, is the stat argument a string or object? I assume it’s a string, but I need to know to finish the script properly.

That event is indeed a string. Sorry for the late reply

Umm what is this suppos to be? BindToCloseonly runs for 60 seconds and you should use it to save players’ data when game shut downs.

It’s okay.

This should be a function and complete rewritten version. Please let me know if something doesn’t work, because everything does when I test it.


One thing that you are required to do when adding this script

In the code, the GetDataEvent is a RemoteEvent. I changed it to work with a RemoteFunction, so it can actually return the data to the client. In the events folder in ReplicatedStorage, delete the GetDataEvent, and then add a RemoteFunction to the folder. Name the RemoteFunction the exact same as the RemoteEvent was, so “GetDataEvent”.

Using a RemoteFunction is better than receiving something from the RemoteEvent, processing stuff, then firing it back to the client. It’s way more efficient to use RemoteFunctions because it returns it right back to the client, and I’m pretty sure using the RemoteEvent like that can cause some issues as well. I might be wrong on that though.

When using a RemoteFunction, you have to write it in a variable like a function in the script returning some data, like a number formatter or something.
Here is an example of what it would look like on the client:

local replicatedStorage = game:GetService("ReplicatedStorage")

local button = script.Parent

button.Activated:Connect(function()
	local availableMaps = replicatedStorage.GetMaps:InvokeServer()
	
	print(availableMaps) --// The server code for this example would find a folder in ServerStorage, get all of its children, and return that table. This would print a table with the names of all of the maps in that folder. This is really good to use so exploiters can't mess with maps in ReplicatedStorage. The client will be able to receive the maps from the server, because pretty much every exploiter can't really see anything that the server can, which includes ServerScriptService and ServerStorage
end)

Anyway, now that's out of the way, here is the script
-- >>: Variables
local Players = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local dataStoreService = game:GetService("DataStoreService")
local marketplaceService = game:GetService("MarketplaceService")
local httpService = game:GetService("HttpService")

local dataStore = dataStoreService:GetDataStore("DataStore")

local events = replicatedStorage:WaitForChild("Events")

local gamepassIDs = {
	DoubleIncrement = 154681682;
}

local defaultTable = {
	Donated = 0;
	Raised = 0;
	Minutes = 0;
}

-- >>: Functions
--// Set Data
local function AddDonated(userId: number, amount: number)
	local player = Players:GetPlayerByUserId(userId)

	if player and player:FindFirstChild("leaderstats") then
		player.leaderstats.Donated.Value += amount
	end
end

local function AddRaised(userId: number, amount: number)
	local player = Players:GetPlayerByUserId(userId)

	if player and player:FindFirstChild("leaderstats") then
		player.leaderstats.Raised.Value += amount
	end
end

local function AddMinutes(userId: number, amount: number)
	local player = Players:GetPlayerByUserId(userId)

	if player and player:FindFirstChild("leaderstats") then
		player.leaderstats.Minutes.Value += amount
	end
end

--// Remotes
local function GetData(player: Player, stat, value)
	for _, playerStat in pairs(player:GetDescendants()) do
		if playerStat.Name == stat then
			return playerStat, value
		end
	end
end

local function AddValue(userId: number, amount: number, stat: string)
	if stat == "Donated" then
		AddDonated(userId, amount)
	elseif stat == "Raised" then
		AddRaised(userId, amount)
	elseif stat == "Minutes" then
		AddMinutes(userId, amount)
	end
end

--// Player Data
local function PlayerAdded(player: Player)
	-- // Stats
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local donated = Instance.new("IntValue")
	donated.Name = "Donated"
	donated.Value = defaultTable.Donated
	donated.Parent = leaderstats

	local raised = Instance.new("IntValue")
	raised.Name = "Raised"
	raised.Value = defaultTable.Raised
	raised.Parent = leaderstats

	local minutes = Instance.new("IntValue")
	minutes.Name = "Minutes"
	minutes.Value = defaultTable.Minutes
	minutes.Parent = leaderstats

	--// Loading Data
	local encoded
	local dataTable

	local success, errorMessage = pcall(function()
		encoded = dataStore:GetAsync("dataTable-"..player.UserId)
	end)

	if success then
		if encoded ~= nil then
			dataTable = httpService:JSONDecode(encoded)

			if dataTable ~= nil then
				print("Successfully loaded data table for "..player.Name, dataTable)
			else
				warn("Data table for "..player.Name.." failed to be decoded")
				dataTable = defaultTable
			end
		else
			warn("There is no saved data table for "..player.Name)
			dataTable = defaultTable
		end
		
		donated.Value = dataTable.Donated
		raised.Value = dataTable.Raised
		minutes.Value = dataTable.Minutes
	else
		if errorMessage then
			warn(errorMessage, player.Name, player.UserId)
		elseif encoded == nil then
			warn("Data for "..player.Name.." is nil!", player.UserId)
		end
		
		dataTable = defaultTable
		
		donated.Value = dataTable.Donated
		raised.Value = dataTable.Raised
		minutes.Value = dataTable.Minutes
	end
	
	--// Other Stuff
	local minutesIncrement = 1
	
	if marketplaceService:UserOwnsGamePassAsync(player.UserId, gamepassIDs.DoubleIncrement) then
		minutesIncrement = 2
	end
	
	coroutine.wrap(function()
		while task.wait(60) do
			AddMinutes(player.UserId, minutesIncrement)
		end
	end)()
end

local function PlayerRemoving(player: Player)
	local success, errorMessage = pcall(function()
		local dataTable = {
			Donated = player.leaderstats.Donated.Value;
			Raised = player.leaderstats.Raised.Value;
			Minutes = player.leaderstats.Minutes.Value;
		}
		
		local encoded = httpService:JSONEncode(dataTable)
		
		dataStore:SetAsync("dataTable-"..player.UserId, encoded)
	end)
	
	if success then
		print("Successfully saved data for "..player.Name, player.UserId)
	else
		warn(errorMessage)
	end
end

-- >>: Events
--// Players Added/Removing
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving)

--// Remotes
events:WaitForChild("GetDataEvent").OnServerInvoke = GetData
events:WaitForChild("AddValue").Event:Connect(AddValue)

-- >>: Bind To Close
game:BindToClose(function()
	task.wait(75)
end)

Hey, I had some red code on these lines

Hover your mouse over it and tell me what it says

It’s just fine for me

It says this right here
image

Weird. I don’t know why that happens. I would switch it out with player:FindFirstChild("leaderstats") for those three lines

So do this to the 3 lines?

That should have fixed it, but I’m not sure why it didn’t. I know it is probably do do something with the player parameter being declared as the class “Player” given by the error. It should still run fine with that error, but if you want to try getting rid of it, remove the : Player after the “player” parameter in the function.

Got this error on like 169

Did you replace it with a RemoteFunction, or is it still a RemoteEvent?

It is still a remotevent, does it need to be a function?

Yes, it needs to be a RemoteFunction.

After the change it is still giving me the error

It should be working just fine. It works for me perfectly.

On your client, how are you running the code for it? It is requires to use it on the client, just like a RemoteEvent when firing the server, but it has to be setup slightly different.


Oh, and if you want to make your life easier, I really recommend this plugin. It’s super helpful

As in client do you mean change this?
image