Property Data not loading in after saving, no errors showing up

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

  1. What do you want to achieve? Keep it simple and clear!
    I’m making a property system, where players can place items in the property that saves

  2. What is the issue? Include screenshots / videos if possible!
    When leaving the game and saving data, after renting the property again, the data doesnt seem to be loading back in, I’m not sure if it’s something do with how I’m not seralizing/deseralizng the data correctly.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried looking at other devforum posts and using ai.

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

There is different property types, for example SmallShop. Each property type has it own properties with the same exact model for each one, which each property inside of the property type has different locations and different orientations inside the map. For example, if the player adds in the chair in the corner of the property facing to the right in SmallShop2, if they join the game again and rent SmallShop3 this time, there will still be a chair in the same corner of the property facing to the right even if the property has a different location or is facing a different direction.

SavePropertyData script, under Server Script Service:

local players = game:GetService("Players")
local properties = game.Workspace.Properties
local dataStoreService = game:GetService("DataStoreService")
local httpService = game:GetService("HttpService")

players.PlayerRemoving:Connect(function(plr)
	for i, v in ipairs(properties:GetChildren()) do
		if v:IsA("Model") and v.PropertyInfo.PropertyOwner.Value == plr then
			-- Create a DataStore specific to this property
			local propertyDataStore = dataStoreService:GetDataStore(v.Parent.Name, plr.UserId)

			-- Loop through all placed items in the property
			local items = v.PlacedItems:GetChildren()
			local savedItems = {}

			for i, item in ipairs(items) do
				-- Save relative CFrame (includes both position and orientation)
				local relativeCFrame = v.CFrame:inverse() * item.MainPart.CFrame

				-- Collect the data of each item
				table.insert(savedItems, {
					Name = item.Name,
					CFrame = relativeCFrame, -- No need to extract orientation separately
					BrickColor = item.MainPart.BrickColor.Name,
					Material = tostring(item.MainPart.Material)
				})
			end

			-- Serialize and save the data
			local serializedData = httpService:JSONEncode(savedItems)
			propertyDataStore:SetAsync("PlacedItems", serializedData)
		end
	end
end)

PropertyHandler script also under ServerScriptService:

local rentProperty = game.ReplicatedStorage.RentProperty
local notify = game.ReplicatedStorage.Notify
local setPropertyInfo = game.ReplicatedStorage.SetPropertyInfo
local data = game:GetService("DataStoreService")
local httpService = game:GetService("HttpService")

rentProperty.OnServerEvent:Connect(function(plr, rentPrice, propertyToRent)
	if plr.leaderstats.Credits.Value >= rentPrice then
		plr.leaderstats.Credits.Value = plr.leaderstats.Credits.Value - rentPrice
		propertyToRent.PropertyInfo.PropertyOwner.Value = plr

		setPropertyInfo:FireClient(plr, propertyToRent)

		-- Load saved items
		local rentedProperty = propertyToRent
		local propertyType = rentedProperty.Parent.Name
		local propertyDataStore = data:GetDataStore(propertyType, plr.UserId)
		local savedItems = propertyDataStore:GetAsync("PlacedItems")

		if savedItems then
			local decodedData = httpService:JSONDecode(savedItems)
			print(decodedData)
			for _, savedItem in ipairs(decodedData) do
				-- Apply relative CFrame (includes both position and orientation)
				local newCFrame = rentedProperty.CFrame * savedItem.CFrame

				-- Create the item and set the CFrame
				local newItem = game.ReplicatedStorage.ObjectFolder[savedItem.Name]:Clone()
				newItem.Parent = rentedProperty.PlacedItems
				newItem.MainPart.CFrame = newCFrame -- Apply both position and orientation
				newItem.MainPart.BrickColor = BrickColor.new(savedItem.BrickColor)
				newItem.MainPart.Material = Enum.Material[savedItem.Material]
			end
		end
	else
		notify:FireClient(plr, "Not enough credits!", "You don't have enough credits!")
	end
end)

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

You can try to print data before it is actually saved and loaded to check if its values are correct. By the way, you shouldnt use SetAsync as it can lead to data loss, use UpdateAsync. You should also use protected calls (pcall) as saving and loading data can sometimes throw an error, and that also leads to data loss.

This is my SavePropertyData script now, it still doesnt seem to be printing anything at all and the data still isn’t being loaded back in:

local players = game:GetService("Players")
local properties = game.Workspace.Properties
local dataStoreService = game:GetService("DataStoreService")
local httpService = game:GetService("HttpService")

players.PlayerRemoving:Connect(function(plr)
	for i, v in ipairs(properties:GetChildren()) do
		if v:IsA("Model") and v.PropertyInfo.PropertyOwner.Value == plr then
			-- Create a DataStore specific to this property
			local propertyDataStore = dataStoreService:GetDataStore(v.Parent.Name, plr.UserId)

			-- Loop through all placed items in the property
			local items = v.PlacedItems:GetChildren()
			local savedItems = {}

			for i, item in ipairs(items) do
				-- Save relative CFrame (includes both position and orientation)
				local relativeCFrame = v.CFrame:inverse() * item.MainPart.CFrame

				-- Collect the data of each item
				table.insert(savedItems, {
					Name = item.Name,
					CFrame = relativeCFrame, -- No need to extract orientation separately
					BrickColor = item.MainPart.BrickColor.Name,
					Material = tostring(item.MainPart.Material)
				})
			end

			-- Serialize and save the data
			print(savedItems)  -- This should print a table of items
			local serializedData = httpService:JSONEncode(savedItems)
			print("Serialized Data: ", serializedData)
			
			-- Use pcall with UpdateAsync
			local success, errorMessage = pcall(function()
				propertyDataStore:UpdateAsync("PlacedItems", function(existingData)
					-- Return the new data to save
					return serializedData
				end)
			end)

			-- Check if there was an error
			if not success then
				warn("Failed to save data for player " .. plr.Name .. ": " .. errorMessage)
			else
				print("Data saved successfully for player " .. plr.Name)
			end
		end
	end
end)

If nothing is printing, then properties is empty, v is not a model, or v.PropertyInfo.PropertyOwner.Value is nil or not equal for this player. Can you tell me what class is PropertyOwner?

I think I figured something out why it isn’t printing, as a recent change I made but didn’t edit it into one of the scripts yet. Give me some time to figure it out and I will send another post.

1 Like

After some testing and a lot of script editing, when loading in I get an error saying on line 23 of PropertyHandler script, “attempt to concatenate string with table”

PropertyHandler script:

local rentProperty = game.ReplicatedStorage.RentProperty
local notify = game.ReplicatedStorage.Notify
local setPropertyInfo = game.ReplicatedStorage.SetPropertyInfo
local data = game:GetService("DataStoreService")
local httpService = game:GetService("HttpService")

rentProperty.OnServerEvent:Connect(function(plr, rentPrice, propertyToRent)
	if plr.leaderstats.Credits.Value >= rentPrice then
		plr.leaderstats.Credits.Value = plr.leaderstats.Credits.Value - rentPrice
		propertyToRent.PropertyInfo.PropertyOwner.Value = plr

		setPropertyInfo:FireClient(plr, propertyToRent)

		-- Load saved items
		local rentedProperty = propertyToRent
		local propertyType = rentedProperty.Parent.Name
		local propertyDataStore = data:GetDataStore(propertyType, plr.UserId)
		local savedItems = propertyDataStore:GetAsync("PlacedItems")

		if savedItems then
			local decodedData = httpService:JSONDecode(savedItems)
			print(decodedData)
			print("loaded items decode: "..decodedData)

			local bounds = rentedProperty:FindFirstChild("PropertyBounds")

			for _, savedItem in ipairs(decodedData) do
				-- Apply relative CFrame (includes both position and orientation)
				local newCFrame = bounds.CFrame * savedItem.CFrame

				-- Create the item and set the CFrame
				local newItem = game.ReplicatedStorage.ObjectFolder[savedItem.Name]:Clone()
				newItem.Parent = rentedProperty.PlacedItems
				newItem.MainPart.CFrame = newCFrame -- Apply both position and orientation
				newItem.MainPart.BrickColor = BrickColor.new(savedItem.BrickColor)
				newItem.MainPart.Material = Enum.Material[savedItem.Material]
			end
	
		end
	else
		notify:FireClient(plr, "Not enough credits!", "You don't have enough credits!")
	end
end)

Updated SavePropertyData script:

local players = game:GetService("Players")
local propertiesFolder = game.Workspace.Properties
local dataStoreService = game:GetService("DataStoreService")
local httpService = game:GetService("HttpService")

players.PlayerRemoving:Connect(function(plr)
	
	for i, v in ipairs(propertiesFolder:GetChildren()) do
		local properties = v:GetChildren()
		
		for _, property in ipairs(properties) do
			if property:IsA("Model") and property.PropertyInfo.PropertyOwner.Value == plr then
				-- Create a DataStore specific to this property
				local propertyDataStore = dataStoreService:GetDataStore(property.Parent.Name, plr.UserId)

				-- Loop through all placed items in the property
				local items = property.PlacedItems:GetChildren()
				local savedItems = {}
				
				local bounds = property:FindFirstChild("PropertyBounds")

				for i, item in ipairs(items) do
					-- Save relative CFrame (includes both position and orientation)
					local relativeCFrame = bounds.CFrame:inverse() * item.MainPart.CFrame

					-- Collect the data of each item
					table.insert(savedItems, {
						Name = item.Name,
						CFrame = relativeCFrame, -- No need to extract orientation separately
						BrickColor = item.MainPart.BrickColor.Name,
						Material = tostring(item.MainPart.Material)
					})
				end

				-- Serialize and save the data
				print(savedItems)  -- This should print a table of items
				local serializedData = httpService:JSONEncode(savedItems)
				print("Serialized Data: ", serializedData)

				-- Use pcall with UpdateAsync
				local success, errorMessage = pcall(function()
					propertyDataStore:UpdateAsync("PlacedItems", function(existingData)
						-- Return the new data to save
						return serializedData
					end)
				end)

				-- Check if there was an error
				if not success then
					warn("Failed to save data for player " .. plr.Name .. ": " .. errorMessage)
				else
					print("Data saved successfully for player " .. plr.Name)
				end
			end
		end
		end
		
end)

Serialized data does print, the savedItems table prints correctly as it should, and it said that the data was successfully saved.

So I think the issue is now that just loading the data in.

I made a new post as there is a different issue now.
Link: Placement system parts not showing in right location, saved data duplicates everytime when loading in