Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How can I modify DataStores with Workspace parts?

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.

1 answer

✓ Accepted answer

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.

10 comments

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?

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

0

Sounds good, what line of code could I use that would instruct the table contents to be deposited into the IntValue? Thanks again.

0

it'd be multiple lines so I'll edit original answer to have an IntValue solution

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)?

0

ModuleScripts don't run on their own, they're like shared code that can be accessed between scripts when required

0

Does that mean the script needs to be active and running before it'll be able to register clicks from the clickDetector?

0

this script would work fine as a script, try checking the values from another normal script rather than a module script

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?

0

It's created once they've clicked at least once under the player, are you checking before or after you've clicked?

This discussion is preserved as it was. New answers, comments, and votes are closed.