How to only create one int Value per player and have the value attached to them

You can write your topic however you want, but you need to answer these questions:
The game is here:

In early development as you can tell. (As of its unfinished state please do not dislike this is to help understand the problem not get people to play it)

Edit:The problem is every on touch creates A value and every player can use it
Edit: I rewrote the first bit…

  1. What do you want to achieve? I am making A datastore which saves cash but all the leaderstat values are not assaigned to A single player and newones are created evrytime the player joins.

You should only earn money on the grey block. However it is updating my cash value as well because you cannot distinguish them…
Datastore

local DSS = game:GetService("DataStoreService")
 
local cashData = DSS:GetDataStore("cashDataStore")
 
game.Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		
    	local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = Player
		
    	local Cash = Instance.new("IntValue")
		Cash.Name = "Cash"
    	Cash.Parent = leaderstats
    	Cash.Value = cashData:GetAsync(Player.userId) or 0
 
		game.Players.PlayerRemoving:connect(function(Player)
			cashData:SetAsync(Player.userId, Cash.Value)
		end)


		while true do
			wait(60)
			pcall(function()
			cashData:SetAsync(Player.userId, Cash.Value)	
			end)
		end
	end)
end)
game.Players.PlayerRemoving:Connect(function()
	
end)

and the block script is

local brick = script.Parent

function onTouched(hit)
    for i,player in ipairs(game.Players:GetPlayers()) do
        if player.Character then
            local stat = player:FindFirstChild("leaderstats")
			            if stat then
                player.leaderstats.Cash.Value = player.leaderstats.Cash.Value +1
            end
        end
    end
end


brick.Touched:connect(onTouched)

I have tried using remove functions and using A useerid as A “key” but I did not get it to work. As well as thish, I do not know how to only create one value per person.

1 Like

For not saving I believe it is reciving to many requests A minute but I dunno if I did pcall right

At first glance there are a few things you’ll want to consider, may or may not directly address the title:

You’re going to have a lot of these infinite loops per player, all executing in their own thread. Seeing what it does, you just need one per player. So it doesn’t need to be in the .CharacterAdded event (everytime an event is fired, a new thread is created to execute whatever code it has). This may also cause throttling since you’ll have a ton of requests going to datastores.

Your onTouched should also use a debounce: Debounce Patterns | Documentation - Roblox Creator Hub

You’re going to have a lot of these per player as a player’s character respawns. It should just be in player added.

Due to the above, you don’t know which cash object you’re getting when indexing into leaderstats. Ideally you just want one, the one created when the player joins.

Check out the output tab in studio, you’ll get warnings (yellow-ish) there if you’re going past the data store limit.

I have made a debounce using the guide but their are no errors but it appears it does not work I have tried searching for humaniod the Value does not increase at all.
local pressed = false
–Store whether the button is pressed in a local variable

workspace.Button.Touched:Connect(function(hit)
if not pressed then
pressed = true
if hit.parent then
game.player.leaderstats.Cash.Value = game.player.leaderstats.Cash.Value+5
wait(5)
game.player.leaderstats.Cash.Value = game.player.leaderstats.Cash.Value+5
wait(5)
end
pressed=false

end

end)

Is the wait on the pcall delaying it?

@Silentude I have updated the script but have player is not A valid member of DataModel
local pressed = false

game.Players.PlayerAdded:Connect(function()

workspace.Part.Touched:Connect(function(hit)

if not pressed then

pressed = true

if hit.parent then

game.player.leaderstats.Cash.Value = game.player.leaderstats.Cash.Value+5

wait(5)

end

pressed=false

end

end)

end)
The part is just A test I need to know why the data store does not work the part just gives the value.

Could you expand on the above
@Silentude

Everytime the character respawns/is added, you create a new IntValue which is parented to that character’s player’s leaderstats. So now you see as a player respawns they will have multiple IntValues named “Cash”. You can test this out yourself by looking into the explorer while testing.

So when you do player.leaderstats.Cash.Value... , out of the multiple Cash objects, one is chosen and you might not particularly know which one.

The problem is that a (random?) cash value is updated, and then saved by its thread running the while true save loop, but then another thread with that same code will run and overwrite the recently updated value.

1 Like

So what do I do? Is thir A solution
What about doing game.player:removed:connect

I have Still not got A solution and would appreciate any help. I am actively trying to find how to stop this.

I have put A thread on scripting helpers as well (I do not believe I a aloud to link it)

So I have an Idea but I am not sure how to do it:
How could I asaign each cash value to one player would using their UserId work.

Yes, this would work. UserId is the ideal way of handling/saving user data, in fact, since players can change their usernames.

1 Like

I understand that but am not ware of how to give A userid to A cash value. Script is above
Currently the data saves to the userId but uses any Cash value of any player on the server. I need to figure out how to make the Client only accsess their value and no one elses I thought I could give each value the UserId of the player and make it search for that one but do not know how.

Would this work?
local Cash = Instance.new(“IntValue”)
Cash.Name = “Cash”…“player.userid”
Cash.Parent = leaderstats
Cash.Value = cashData:GetAsync(Player.userId) or 0

For your top script, try:

local DSS = game:GetService("DataStoreService")
local cashData = DSS:GetDataStore("cashDataStore")

-- Manage data for individual players whenever one joins the server
game.Players.PlayerAdded:Connect(function(Player)
	-- Create leaderstats
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = Player
	
	-- Create cash
	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	Cash.Value = cashData:GetAsync(Player.UserId) or 0

	-- Save when a player leaves
	game.Players.PlayerRemoving:connect(function(Player)
		cashData:SetAsync(Player.UserId, Cash.Value)
	end)

	-- Autosave (?)
	while Player ~= nil do
		wait(60)
		pcall(function()
			cashData:SetAsync(Player.UserId, Cash.Value) --You had userId, the property is UserId :)
		end)
	end
end)

And for your bottom script, try this. I added a little cooldown mechanic, so that players can’t get tons of money super fast–they have to wait for cooldownTime seconds before getting money again. The .Touched event can fire dozens of times per second per player, so this is a way of managing how frequently they can get money. Your script was also giving money to all players when anything touched the part; I fixed that so it should only give money to the player that touches it now.

local Players = game:GetService("Players")
local brick = script.Parent
local cooldownTime = 1 -- Set this to the interval in seconds between when players get cash
local onCooldown = {}

function onTouched(hit)
	local Character = hit.Parent
	if Players:FindFirstChild(Character.Name) ~= nil then
		local Player = Players:FindFirstChild(Character.Name)
		local UID = Player.UserId
		local Stats = Player:WaitForChild("leaderstats")
		-- Verify that the user isn't on cash cooldown 
		if not onCooldown[UID] then
			-- Mark player for cooldown
			onCooldown[UID] = (Player)
			-- Add cash
			Player.leaderstats.Cash.Value = Player.leaderstats.Cash.Value +1
			-- Wait for cooldown to end, then remove player from cooldown
			wait(cooldownTime)
			onCooldown[UID] = nil
        end
    end
end
brick.Touched:connect(onTouched)

Let me know if these work!

EDIT: Also–unless I’m mistaken–Player.UserId is case-sensitive (just like all things), so using Player.userId won’t work.

1 Like

So does this save directly to the players cash value instead of A random one?
Also player is an unknown global so I put game.player instead. I s that ok @ChefJustice
Edit:
Error:player is not A valid member of Datamodel

That’s fine–my bad for not noticing that! Yes, it should save directly to the player’s UserId.
Edit: what line is that error on?
Edit [2]: nvm; DataModel is the fancy word for game. Where are you getting the datamodel error?

1 Like

This is great! One question:
What is A datamodel and why can I not but player in it

In the money brick script:
game.player.leaderstats.Cash.Value = game.player.leaderstats.Cash.Value + 1
I tried pluralizing players because I read an article on how that fixed the error but it still gave the same output.
Without game it was an unknown global. Should I try defining it.