New: Nitro Boost our Discord server and receive full donation perks here on the website! Join the Scripting Helpers Discord Server to learn more! You can also Support on Patreon as always.
Still have questions? Join our Discord server and get real time help.
0

# How can I modify DataStores with Workspace parts?

J_98482 18
1 year ago

I'm fairly new to the RBLX lua, so I'm looking for a bit of clarification regarding datastores. I'm trying to put together a script that keeps track of how many times a player has clicked on a specific part, and using this (https://www.robloxdev.com/articles/Saving-Player-Data) article from the roblox dev wiki to help me out.

I've got the proper pieces of the code I need that are featured in that article in a script in my game, but it didn't mention how to increase (IncrementAsync?) values using parts you might find in Workspace (like ClickDetectors), and so far I haven't found any other source that has the information I'm after. If someone could maybe point me in the right direction on where to head to next, it would be greatly appreciated.

0
Answered by 1 year ago
Edited 1 year ago

Just because your function is connected to an event (like a ClickDetector's MouseClick event) doesn't mean that the code will run any differently. This works the same as any other code that uses IncrementAsync, although you might want to use variables outside of the connected function to avoid sending a datastore request on every single click.

An example of using variables outside of the connected function so that you don't need to send constant requests would be:

local clickDetector = workspace.something.clicky
local dsService = game:GetService("DataStoreService")
local timesClickedDS = dsService:GetDataStore("TimesClicked") -- obviously "TimesClicked" doesn't matter one bit as long as its consistent
local playerService = game:GetService("Players")

local timesClickedTable = {}

clickDetector.MouseClick:Connect(function(player)
if timesClickedTable[player.UserId] then -- if there's a value  already saved
timesClickedTable[player.UserId] = timesClickedTable[player.UserId] + 1 -- increment counter
-- maybe something else
else
timesClickedTable[player.UserId] = 1 -- set to one since clicked once
end
end)

playerService.PlayerRemoving:Connect(function(player) -- when someone quits
local pUserId = player.UserId
if timesClickedTable[pUserId] then -- check how many times they clicked this session
timesClickedDS:IncrementAsync(pUserId, timesClickedTable[pUserId] -- increment it to their saved data
end
end)

playerService.PlayerAdded:Connect(function(player) -- for each player
while true do
wait(300) -- every 300 seconds
if timesClickedTable[player.UserId] then -- if there's any data
timesClickedDS:IncrementAsync(player.UserId, timesClickedTable[player.UserId]) -- save it to their datastore
end
end
end)


In this particular example, someone would be able to autoclick to increment the counter a lot more than (probably) intended, as there's no debounce or anything that will change once they've clicked it once.

As I'm pretty sure you've figured out (judging by your question), you can find a lot of information on the wiki page for datastores.

Edit: Since you wanted an answer where the value is available between scripts, you can adapt the original code to use IntValues instead of script-specific variables. This wouldn't require much change, but I'll repost the whole thing edited as the changes are spread throughout the script. Changed lines will be marked with "--***--" above them.

local clickDetector = workspace.something.clicky
local dsService = game:GetService("DataStoreService")
local timesClickedDS = dsService:GetDataStore("TimesClicked") -- obviously "TimesClicked" doesn't matter one bit as long as its consistent
local playerService = game:GetService("Players")

local timesClickedTable = {}

clickDetector.MouseClick:Connect(function(player)
if timesClickedTable[player.UserId] then -- if there's a value  already saved
--***-- added .Value twice so that it updates value of object rather than replacing the reference to the object in table with a number
timesClickedTable[player.UserId].Value = timesClickedTable[player.UserId].Value + 1 -- increment counter
-- maybe something else
else
--***-- next 4 lines are all new to set up IntValue
local intValueSetup = Instance.new("IntValue") -- make an IntValue to store data
intValueSetup.Name = "timesClicked" -- name it so it's easier to access from other scripts
intValueSetup.Value = 1 -- start at 1 because it was 0 and they just clicked
--***-- using intValueSetup instead of 1 since it's an object now
timesClickedTable[player.UserId] = intValueSetup -- put value in table for later
end
end)

playerService.PlayerRemoving:Connect(function(player) -- when someone quits
local pUserId = player.UserId
if timesClickedTable[pUserId] then -- check how many times they clicked this session
--***-- added .Value to check the IntValue's value rather than saving an object (doesn't work)
timesClickedDS:IncrementAsync(pUserId, timesClickedTable[pUserId].Value) -- increment it to their saved data
end
end)

-- in case of server crash or forced manual shutdown
playerService.PlayerAdded:Connect(function(player) -- for each player
while true do
wait(300) -- every 300 seconds
if timesClickedTable[player.UserId] then -- if there's any data
--***-- added .Value to check the IntValue's value rather than saving an object (doesn't work)
timesClickedDS:IncrementAsync(player.UserId, timesClickedTable[player.UserId].Value) -- save it to their datastore
end
end
end)


As you can see, it is largely the same aside from adding .Value to check the IntValue's value and extra setup for the IntValue since it's an object not just a number. If there's any confusion, I'll likely edit the post later.

0
Great stuff, this really helped me out. One more quick question though - if I wanted to request this data in another script, like a leaderboard, how would I get it? Would I make a reference to TimesClicked, or maybe the UserId? J_98482 18 — 1y
0
Instead of having a table of player userid to value, you could have a table of player userid to an IntValue object (parented to the player) so that you can access it from other scripts User#22604 1 — 1y
0
Sounds good, what line of code could I use that would instruct the table contents to be deposited into the IntValue? Thanks again. J_98482 18 — 1y
0
it'd be multiple lines so I'll edit original answer to have an IntValue solution User#22604 1 — 1y
View all comments (6 more)
0
After some testing, its seems that the ModuleScript isn't picking up on when clickDetector is clicked. I doubled checked, the adress of the detector and the adress in the script, and they match. Could it be because I put the ModScript in the wrong place (ServerStorage)? J_98482 18 — 1y
0
ModuleScripts don't run on their own, they're like shared code that can be accessed between scripts when required User#22604 1 — 1y
0
Does that mean the script needs to be active and running before it'll be able to register clicks from the clickDetector? J_98482 18 — 1y
0
this script would work fine as a script, try checking the values from another normal script rather than a module script User#22604 1 — 1y
0
Checked it out in a normal script, it doesn't seem to produce any errors. Still though, I'm not seeing an IntValue object being created no matter where the script is/what type of script it is. Any suggestions? J_98482 18 — 1y
0
It's created once they've clicked at least once under the player, are you checking before or after you've clicked? User#22604 1 — 1y