Saving onTouched events with datastores

the local script below makes it so when you touch a part it changes another parts proprieties. I want to use datastore to make it so when a player leaves those propriety changes remain when they rejoin.
its just very confusing to me because i dont really have any experience with scripting and especially with datastore.

local Part1 = PartA
local Part2 = PartB

Part1.Touched:Connect(function(hit)
     if hit.Parent == game.Players.LocalPlayer.Character then
          Part2.Color = Color3.new(1,1,1)
          Part2.Material = ("Neon")
     end
end)

So you want it so then when they leave the properties they’ve changed is serialized or the touch input?

i want it to be serialized, so that part remains white and neon when the player rejoins for example

Use DataStoreService | Roblox Creator Documentation. Its easy to learn, but ill give you some tips. Make a table with the properties of the part you want to save.
For example:

local Properties = {
	Color = Color3.fromRGB(Color),
	Material = Mat
}

And you can keep going on. Once done, save it to the datastore in the second arg. The first arg should be the player’s key. Then, when they join see if they have any saved data. If they do, check if they have Color and Material saved in the table. When that’s done, set the part to the properties in the table. It should look like this:

Part.Color = PlayerData["Color"]
Part.Material = PlayerData["Material"]

If you have any other questions just ask! :slight_smile:

i looked more into DataStoreServices, i still dont really get it im a little stupid, can you go in more into detail if you dont mind

local players = game:GetService("Players")
local dataStores = game:GetService("DataStoreService")
local partStore = dataStores:GetDataStore("PartStore")

local part = script.Parent

local function onPartTouched(hit)
	local hitModel = hit:FindFirstAncestorOfClass("Model")
	if hitModel then
		local hitPlayer = players:GetPlayerFromCharacter(hitModel)
		if hitPlayer then
			part.Color = Color3.new(1, 1, 1)
			part.Material = Enum.Material.Neon
		end
	end
end

local function deserializeData(data)
	local color = data["Color"]
	part.Color = Color3.new(color[1], color[2], color[3])
	local material = data["Material"]
	part.Material = Enum.Material[material]
end

local function serializeData()
	local data = {}
	data["Color"] = {part.Color.R, part.Color.G, part.Color.B}
	data["Material"] = part.Material.Name
	return data
end

local function onPlayerAdded(player)
	local success, result = pcall(function()
		return partStore:GetAsync(player.UserId)
	end)
	
	if success then
		if result then
			if type(result) == "table" then
				deserializeData(result)
			end
		end
	else
		warn(result)
	end
end

local function onPlayerRemoving(player)
	local data = serializeData()
	
	local success, result = pcall(function()
		return partStore:SetAsync(player.UserId, data)
	end)
	
	if success then
		if result then
			print(result)
		end
	else
		warn(result)
	end
end

local function onServerShutdown(player)
	for _, player in ipairs(players:GetPlayers()) do
		local data = serializeData()

		local success, result = pcall(function()
			return partStore:SetAsync(player.UserId, data)
		end)

		if success then
			if result then
				print(result)
			end
		else
			warn(result)
		end
	end
end

part.Touched:Connect(onPartTouched)
players.PlayerAdded:Connect(onPlayerAdded)
players.PlayerRemoving:Connect(onPlayerRemoving)
game:BindToClose(onServerShutdown)

Here you go, I tested this and it works.

Here’s the model file for reproduction purposes and if you’d like to see for yourself.

repro.rbxm (3.5 KB)

2 Likes

wait this worked like for the first time then it stopped working, and only for me for other people it didnt work at all

Now you’re asking for a completely different system (where each player has their own part), the script I provided works with a global part (shared by everyone), when that part is touched its properties change and those changes are saved each time a player leaves the server, fortunately for you, I decided to write an alternate system which creates, saves and loads a unique part for each player, you’ll need to randomize the location of the part by changing this line here.
part.CFrame = CFrame.new(0, 0, 0)

As an added bonus the part’s material is randomised and its color is randomised too, with a fading animation effect between color changes.

Here are the scripts.

--SERVER

local players = game:GetService("Players")
local dataStores = game:GetService("DataStoreService")
local partStore = dataStores:GetDataStore("PartStore")

local replicated = game:GetService("ReplicatedStorage")
local partRemote = replicated.PartRemote

local function loadData(player)
	local success, result = pcall(function()
		return partStore:GetAsync(player.UserId)
	end)

	if success then
		if result then
			if type(result) == "table" then
				return result
			end
		end
	else
		warn(result)
	end
end

local function saveData(player)
	local data = partRemote:InvokeClient(player)

	local success, result = pcall(function()
		return partStore:SetAsync(player.UserId, data)
	end)

	if success then
		if result then
			print(result)
			return result
		end
	else
		warn(result)
	end
end

local function onServerShutdown(player)
	for _, player in ipairs(players:GetPlayers()) do
		partRemote:InvokeClient(player)
	end
end

local function onRemoteInvoked(player, boolean)
	if boolean then
		return loadData(player)
	elseif not boolean then
		return saveData(player)
	end
end

partRemote.OnServerInvoke = onRemoteInvoked
game:BindToClose(onServerShutdown)
--CLIENT

local players = game:GetService("Players")
local localPlayer = players.LocalPlayer
local tweens = game:GetService("TweenService")
local replicated = game:GetService("ReplicatedStorage")
local partRemote = replicated:WaitForChild("PartRemote")

local materials = {256, 272, 288, 512, 528, 784, 788, 800, 804, 816, 820, 832, 836, 848, 864, 880, 896, 912, 1040, 1056, 1072, 1088, 1280, 1284, 1296, 1312, 1328, 1344, 1360, 1376, 1392, 1536, 1552, 1568, 1584, 1792, 2048}
local debounce = false

local part = Instance.new("Part")
part.Anchored = true
part.Size = Vector3.new(3, 3, 3)
part.CFrame = CFrame.new(0, 0, 0)
part.Parent = workspace

local randomObject = Random.new(tick())

local function onPlayerRemoving(player)
	if player == localPlayer then
		local partData = partRemote:InvokeServer(false)
	end
end

local function onPartTouched(hit)
	if debounce then
		return
	end
	
	local hitModel = hit:FindFirstAncestorOfClass("Model")
	if hitModel then
		local hitPlayer = players:GetPlayerFromCharacter(hitModel)
		if hitPlayer then
			if hitPlayer == localPlayer then
				debounce = true
				part.Material = materials[randomObject:NextInteger(1, #materials)]
				local tween = tweens:Create(part, TweenInfo.new(1), {Color = Color3.new(randomObject:NextNumber(), randomObject:NextNumber(), randomObject:NextNumber())})
				tween:Play()
				local partData = partRemote:InvokeServer(false)
				task.wait(10)
				debounce = false
			end
		end
	end
end

local function onRemoteInvoked()
	local data = {}
	data["Color"] = {part.Color.R, part.Color.G, part.Color.B}
	data["Material"] = part.Material.Name
	return data
end

players.PlayerRemoving:Connect(onPlayerRemoving)
partRemote.OnClientInvoke = onRemoteInvoked
part.Touched:Connect(onPartTouched)

local partData = partRemote:InvokeServer(true)

local color = partData["Color"]
local success, result = pcall(function()
	return Color3.new(color[1], color[2], color[3])
end)
if success then
	part.Color = result
end

local material = partData["Material"]
local success, result = pcall(function()
	return Enum.Material[material]
end)
if success then
	part.Material = result
end

This server script goes inside ServerScriptService and the local script goes inside StarterPlayerScripts. This implementation makes use of a a RemoteFunction in order to facilitate back and forth communication between both scripts (between the server and the client). This RemoteFunction instance is named “PartRemote” and should be placed inside the ReplicatedStorage folder.

Here’s a screenshot how everything should be organised.

image

Finally, here’s the model file for reproduction purposes.

repro.rbxm (3.5 KB)