Hi there!
I have made collectable coins (called “nuggets”) with a currency stats that have data store that I have found from some yt videos, and this is how it works:
The “nuggets” disappear when collected
After got collected, there is a waiting time to respawn the nuggets
The stats added some points on it, indicates how much “nuggets” does a player have right now
However, I wonder if we can make the “nuggets” disappear and respawn ONLY to the player who collected, but not the whole server!
Here is the “nuggets” script:
local DataStoreService = game:GetService("DataStoreService")
local CoinsDataStore = DataStoreService:GetDataStore("CoinsDataStore")
local RespawnTime = 10 -- I set the timer 10 seconds waiting
function savePlayerData(player)
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local coins = leaderstats:FindFirstChild("Nuggets")
if coins then
CoinsDataStore:SetAsync(player.UserId .. "_Nuggets", coins.Value)
end
end
end
function loadPlayerData(player)
local success, result = pcall(function()
return CoinsDataStore:GetAsync(player.UserId .. "_Nuggets")
end)
if success and result ~= nil then
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local coins = leaderstats:FindFirstChild("Nuggets")
if coins then
coins.Value = result
end
end
end
end
function onTouch(otherPart)
local player = game.Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
local leaderstats = player:FindFirstChild("leaderstats")
if not leaderstats then
return
end
local coins = leaderstats:FindFirstChild("Nuggets")
if coins then
coins.Value = coins.Value + 5 -- After collected, the nugget will give you +5 on the currency stats
end
script.Parent.CanTouch = false
script.Parent.Transparency = 1
wait(RespawnTime)
script.Parent.CanTouch = true
script.Parent.Transparency = 0
end
end
function onPlayerRemoving(player)
savePlayerData(player)
end
function onPlayerAdded(player)
loadPlayerData(player)
end
script.Parent.Touched:Connect(onTouch)
game.Players.PlayerRemoving:Connect(onPlayerRemoving)
game.Players.PlayerAdded:Connect(onPlayerAdded)
…and the “stats” script:
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Coin = Instance.new("IntValue")
Coin.Name = "Nuggets" -- The name of the currency!
Coin.Value = 0
Coin.Parent = leaderstats
end)
I hope guys can help me on this one, really appriciated if you also give me explanation of the solution, I want to know more about coding!
This would have to be on the client, of course, but I do not recommend doing this, as the client is able to be faked. The player could easily just teleport to all the coins.
oh… I have read some posts and its kinda related to local script (right?), idk how to use it while i have these mentioned scripts, or should i just paste it into the local script?
As I previously stated, I don’t recommend doing it, because the client could easily teleport to all the coins, although you may see less exploiting instances, because of byfron (correct me if wrong).
You should look into local scripts, anyways. And understand client-server boundaries. It’s not too hard.
I think others are not looking at the bigger picture;
you could make it so that every coin is being tracked on server script i.e. track who has collected the coin if you check if the player has obtained the coin then you can then prevent them from potentially cheating by “touching” it again some how (do sanity checks to ensure the player is close to a coin). Once the player touches the coin fire to the client (or also have a .touched event on client to handle deletion) in local script to delete the coin from their perspective (or in your case, set invisible for client, then after a certain amount of time remove player from tracking on server and set to visible for client).
the above should allow you to get you to the solution you are looking for.
This is true, but players can easily do this on a server side script too, and it would be more annoying if players lost all of their nuggets because a player was teleporting to all of the. Alongside this, hacked clients will try to give their clients an inconspicuous experience, and teleporting them everywhere in the players clear view is not the way to go. I’d suggest proceeding with the client script, that way the hacker can only damage their own experience.
You can make it so there’s a RemoteEvent that tells the client to make this nugget invisible, then after a certain time the RemoteEvent tells the client to make the nugget visible again.
To prevent the player from taking the same nugget twice you can add the player in a Dictionary Table like so:
local playerList = {}
local cooldownTimer = 5
nugget.Touched:Connect(function(part)
local player = game:GetService("Players"):GetPlayerFromCharacter(part.Parent)
if player then
if playerList[player.UserId] == nil or playerList[player.UserId] <= os.clock() then
playerList[player.UserId] = os.clock() + cooldownTimer
-- Give player + 1 nugget and tell the client to make this nugget invisible
yourRemoteEvent:FireClient(player, "hideNugget", nugget)
task.delay(cooldownTimer, function() -- Replace the cooldownTimer number with how many seconds it will take for it to reappear for this client.
yourRemoteEvent:FireClient(player, "showNugget", nugget)
end)
end
end
end)
-- On Client, you only gotta put this somewhere in a localscript or make a new one named "nuggetHandler" or something.
yourRemoteEvent.OnClientEvent:Connect(function(action, model)
if action == "hideNugget" then
-- Make the model transparent or move it elsewhere
elseif action == "showNugget" then
-- Make the model visible or move it where it belongs.
end
end)
Interesting… So simply i have to use local script (?) and RemoteEvent (?) to make the coin disappears (invisible) after a player touched > delete “tracking” during respawn time > set it visible again, right?
I have no idea abt delete player’s tracking, how to prevent?
This is mostly correct, local scripts run on the client’s device exclusively. However, exploiters can access aspects of server scripts if a remote event or other method of client server communication is created. If done properly, exploiters are restricted to only what they can do on the client.
Cool, but that’s kinda not what I meant
I want to make the nuggets visible again after players collected, after that players still can collect it again. Therefore, they are allowed to collect the nuggets at the same place, same nuggets!
And yes, I will try RemoteEvent, ty for your suggestion!
it will require serverscript, localscript & remote event
for tracking you can use a table
local playertable={}
--player .touched coin on server
--should also compare .magnitudes and make sure plr is actually at the coin
if not table.find(playertable, player) then
table.insert(playertable,player)
--awardcoin
--fireclient to invisible the coin
wait(15)
--fireclient visible coin
table.remove(playertable, table.find(playertable, player) )
else
--player already obtained this coin recently
end
As others have said, you’ll need to do this on the client. Here’s what I would do.
-- Client
nugget.Touched:Connect(function(part)
local player = CharacterUtils.getPlayerFromCharacter(part)
if player ~= Players.LocalPlayer then
return
end
if nuget:GetAttribute("IsPickedUp_" .. player.UserId) then
return
end
NuggetPickupRemoteEvent:FireServer(nugget)
nugget:SetAttribute("IsPickedUp_" .. player.UserId, true) -- Immediately render on client
end)
nugget:GetAttributeChangedSignal("IsPickedUp_" .. Players.LocalPlayer.UserId):Connect(function()
if nuget:GetAttribute("IsPickedUp_" .. Players.LocalPlayer.UserId) then
-- Hide nugget
nugget.Transparency = 1
else
nugget.Transparency = 0
end
end)
-- Server
nuggetRemoteEvent.OnServerEvent:Connect(function(player)
-- Validate character distance
nugget:SetAttribute("IsPickedUp_" .. player.UserId, true)
task.delay(3, function()
-- Reset nugget state (obviously do whatever you want here to refresh it)
nugget:SetAttribute("IsPickedUp_" .. player.UserId, nil)
end)
end)
Here’s the getPlayerFromCharacter helper method I used.