My Data Saving Script Isn't Working

Ok, so my data store script isn’t functioning as I want it to. I can’t figure out why. Here’s my script:

-- Server Script

-- Get the DataStoreService and create a DataStore
local DataStoreService = game:GetService("DataStoreService")
local datastore = DataStoreService:GetDataStore("PlayerInvenDatastores")

-- Define default data for various inventories
local defaulttable = require(script:WaitForChild("DefaultData"))


game.Players.PlayerAdded:Connect(function(plr: Player)
	-- Get the local player

	local hasappliedstarterdata = false

	-- Create a folder to store player inventory data
	local plrInven = Instance.new("Folder")
	plrInven.Name = "PlayerInven"
	plrInven.Parent = plr
	local blockinvensaving = Instance.new("BoolValue")
	blockinvensaving.Value = true
	blockinvensaving.Name = "BlockInvenSaving"
	blockinvensaving.Parent = plrInven
	local SavePlrDataFromServerScripts = Instance.new("BindableEvent")
	SavePlrDataFromServerScripts.Name = "SaveDataEvent"
	SavePlrDataFromServerScripts.Parent = plrInven

	-- Material Slots
	local materialinven = Instance.new("Folder", plrInven)
	materialinven.Name = "Materials"
	local numberofMaterialSlots = 150
	local materialdataslots = {}

	for i = 1, numberofMaterialSlots do
		local currentSlot = Instance.new("StringValue", materialinven)
		currentSlot.Name = "Slot" .. tostring(i)
		materialdataslots["Slot" .. tostring(i)] = currentSlot

		local amount = Instance.new("IntValue", currentSlot)
		amount.Name = "Amount"
	end

	-- Melee Slots
	local meleeinven = Instance.new("Folder", plrInven)
	meleeinven.Name = "Melee"
	local numberofMeleeSlots = 10
	local meleedataslots = {}

	for i = 1, numberofMeleeSlots do
		local currentSlot = Instance.new("StringValue", meleeinven)
		currentSlot.Name = "Slot" .. tostring(i)
		meleedataslots["Slot" .. tostring(i)] = currentSlot
	end

	-- Head Armor Slots
	local hArmorInven = Instance.new("Folder", plrInven)
	hArmorInven.Name = "HeadArmor"
	local numberofHeadArmorSlots = 3
	local harmordataslots = {}

	for i = 1, numberofHeadArmorSlots do
		local currentSlot = Instance.new("StringValue", hArmorInven)
		currentSlot.Name = "Slot" .. tostring(i)
		harmordataslots["Slot" .. tostring(i)] = currentSlot
	end

	-- Middle Armor Slots
	local mArmorInven = Instance.new("Folder", plrInven)
	mArmorInven.Name = "MiddleArmor"
	local numberofMiddleArmorSlots = 3
	local marmordataslots = {}

	for i = 1, numberofMiddleArmorSlots do
		local currentSlot = Instance.new("StringValue", mArmorInven)
		currentSlot.Name = "Slot" .. tostring(i)
		marmordataslots["Slot" .. tostring(i)] = currentSlot
	end

	-- Leg Armor Slots
	local lArmorInven = Instance.new("Folder", plrInven)
	lArmorInven.Name = "LegArmor"
	local numberofLegArmorSlots = 3
	local larmordataslots = {}

	for i = 1, numberofLegArmorSlots do
		local currentSlot = Instance.new("StringValue", lArmorInven)
		currentSlot.Name = "Slot" .. tostring(i)
		larmordataslots["Slot" .. tostring(i)] = currentSlot
	end

	-- Ranged Slots
	local rangedinven = Instance.new("Folder", plrInven)
	rangedinven.Name = "Ranged"
	local numberofRangedSlots = 10
	local rangeddataslots = {}

	for i = 1, numberofRangedSlots do
		local currentSlot = Instance.new("StringValue", rangedinven)
		currentSlot.Name = "Slot" .. tostring(i)
		rangeddataslots["Slot" .. tostring(i)] = currentSlot
	end

	-- Arrows
	local arrows = Instance.new("StringValue", rangedinven)
	arrows.Name = "Arrows"
	local arrowAmount = Instance.new("IntValue", arrows)
	arrowAmount.Name = "Amount"
	rangeddataslots["Arrows"] = arrows

	-- Magic Slots
	local magicinven = Instance.new("Folder", plrInven)
	magicinven.Name = "Magic"
	local numberofMagicSlots = 10
	local magicdataslots = {}

	for i = 1, numberofMagicSlots do
		local currentSlot = Instance.new("StringValue", magicinven)
		currentSlot.Name = "Slot" .. tostring(i)
		magicdataslots["Slot" .. tostring(i)] = currentSlot
	end

	-- Mana
	local Mana = Instance.new("StringValue", magicinven)
	Mana.Name = "Mana"
	local manaAmount = Instance.new("IntValue", Mana)
	manaAmount.Name = "Amount"
	magicdataslots["Mana"] = Mana

	-- Quest Slots
	local completedquests = Instance.new("Folder", plrInven)
	completedquests.Name = "Quests"
	local questslots = {}
	local numberofQuestSlots = 150

	for i = 1, numberofQuestSlots do
		local currentSlot = Instance.new("StringValue", completedquests)
		currentSlot.Name = "Slot" .. tostring(i)
		questslots["Slot" .. tostring(i)] = currentSlot

		local rewards = Instance.new("StringValue", currentSlot)
		rewards.Name = "Rewards"

		local identifier = Instance.new("NumberValue", currentSlot)
		identifier.Name = "Identifier"
	end

	-- Player Stats
	local plrstats = Instance.new("Folder", plrInven)
	plrstats.Name = "Stats"

	local temperature = Instance.new("NumberValue", plrstats)
	temperature.Name = "Temperature"

	local stealth = Instance.new("NumberValue", plrstats)
	stealth.Name = "Stealth"

	local money = Instance.new("IntValue", plrstats)
	money.Name = "Money"

	-- Function to get data for all inventories
	function GetDataForAll()
		local materialdata = {}
		local meleedata = {}
		local rangeddata = {}
		local magicdata = {}
		local questdata = {}
		local headarmordata = {}
		local middlearmordata = {}
		local legarmordata = {}

		-- Get materials data
		for i = 1, numberofMaterialSlots do
			local currentSlot = materialdataslots["Slot" .. tostring(i)]
			materialdata["Slot" .. tostring(i) .. "Name"] = currentSlot.Value
			local amount = currentSlot:FindFirstChild("Amount")
			if amount then
				materialdata["Slot" .. tostring(i) .. "Amount"] = amount.Value
			else
				materialdata["Slot" .. tostring(i) .. "Amount"] = 0
			end
		end

		-- Get melee data
		for i = 1, numberofMeleeSlots do
			local data = meleedataslots["Slot" .. tostring(i)].Value
			meleedata["Slot" .. tostring(i)] = data
		end

		-- Get ranged data
		for i = 1, numberofRangedSlots do
			local data = rangeddataslots["Slot" .. tostring(i)].Value
			rangeddata["Slot" .. tostring(i)] = data
		end

		-- Get magic data
		for i = 1, numberofMagicSlots do
			local data = magicdataslots["Slot" .. tostring(i)].Value
			magicdata["Slot" .. tostring(i)] = data
		end
		magicdata["Mana"] = manaAmount.Value

		-- Get quest data
		for i = 1, numberofQuestSlots do
			local currentSlot = questslots["Slot" .. tostring(i)]
			questdata["Slot" .. tostring(i)] = currentSlot.Value

			local identifier = currentSlot:FindFirstChild("Identifier")
			if identifier then
				questdata["Slot" .. tostring(i) .. "Identifier"] = identifier.Value
			else
				questdata["Slot" .. tostring(i) .. "Identifier"] = 0
			end

			local rewards = currentSlot:FindFirstChild("Rewards")
			if rewards then
				questdata["Slot" .. tostring(i) .. "Rewards"] = rewards.Value
			else
				questdata["Slot" .. tostring(i) .. "Rewards"] = ""
			end
		end

		-- Get head armor data
		for i = 1, numberofHeadArmorSlots do
			local data = harmordataslots["Slot" .. tostring(i)].Value
			headarmordata["Slot" .. tostring(i)] = data
		end

		-- Get middle armor data
		for i = 1, numberofMiddleArmorSlots do
			local data = marmordataslots["Slot" .. tostring(i)].Value
			middlearmordata["Slot" .. tostring(i)] = data
		end

		-- Get leg armor data
		for i = 1, numberofLegArmorSlots do
			local data = larmordataslots["Slot" .. tostring(i)].Value
			legarmordata["Slot" .. tostring(i)] = data
		end

		return materialdata, meleedata, rangeddata, magicdata, questdata, headarmordata, middlearmordata, legarmordata, money.Value
	end
	local tabletoget
	-- Function to apply saved data from server
	function ApplySavedData()
		
		
		local id = game.PrivateServerId .. plr.UserId
		local success, data = pcall(function()
			return datastore:GetAsync(id)
		end)

		if success then
			if data then
				--print("Retrieved data for player " .. player.Name)
				tabletoget = data
			else
				--print("No data found for player " .. player.Name .. ", sending default data.")
				tabletoget = defaulttable
			end
		else
			warn("Failed to retrieve data for player " .. player.Name .. ": " .. data)
			-- Optionally, send default data in case of error
			tabletoget = defaulttable
		end
			print("Applying saved data to "..plr.Name..".")

			local materialsfrom = tabletoget["Materials"]
			local meleefrom = tabletoget["Melee"]
			local rangedfrom = tabletoget["Ranged"]
			local magicfrom = tabletoget["Magic"]
			local questsfrom = tabletoget["Quests"]
			local headfrom = tabletoget["Head"]
			local middlefrom = tabletoget["Middle"]
			local lowfrom = tabletoget["Low"]
			local moneyfrom = tabletoget["Money"]

			-- Apply money
			money.Value = moneyfrom

			-- Apply mana
			manaAmount.Value = magicfrom["Mana"]

			-- Apply materials data
			for i = 1, numberofMaterialSlots do
				local materialSlot = materialdataslots["Slot" .. tostring(i)]
				materialSlot.Value = materialsfrom["Slot" .. tostring(i) .. "Name"]
				local amount = materialSlot:FindFirstChild("Amount")
				if amount then
					amount.Value = materialsfrom["Slot" .. tostring(i) .. "Amount"]
				end
			end

			-- Apply melee data
			for i = 1, numberofMeleeSlots do
				local meleeSlot = meleedataslots["Slot" .. tostring(i)]
				meleeSlot.Value = meleefrom["Slot" .. tostring(i)]
			end

			-- Apply ranged data
			for i = 1, numberofRangedSlots do
				local rangedSlot = rangeddataslots["Slot" .. tostring(i)]
				rangedSlot.Value = rangedfrom["Slot" .. tostring(i)]
			end

			-- Apply magic data
			for i = 1, numberofMagicSlots do
				local magicSlot = magicdataslots["Slot" .. tostring(i)]
				magicSlot.Value = magicfrom["Slot" .. tostring(i)]
			end

			-- Apply quest data
			for i = 1, numberofQuestSlots do
				local questSlot = questslots["Slot" .. tostring(i)]
				questSlot.Value = questsfrom["Slot" .. tostring(i)]

				local identifier = questSlot:FindFirstChild("Identifier")
				if identifier then
					identifier.Value = questsfrom["Slot" .. tostring(i) .. "Identifier"]
				end

				local rewards = questSlot:FindFirstChild("Rewards")
				if rewards then
					rewards.Value = questsfrom["Slot" .. tostring(i) .. "Rewards"]
				end
			end

			-- Apply head armor data
			for i = 1, numberofHeadArmorSlots do
				local headArmorSlot = harmordataslots["Slot" .. tostring(i)]
				headArmorSlot.Value = headfrom["Slot" .. tostring(i)]
			end

			-- Apply middle armor data
			for i = 1, numberofMiddleArmorSlots do
				local middleArmorSlot = marmordataslots["Slot" .. tostring(i)]
				middleArmorSlot.Value = middlefrom["Slot" .. tostring(i)]
			end

			-- Apply leg armor data
			for i = 1, numberofLegArmorSlots do
				local legArmorSlot = larmordataslots["Slot" .. tostring(i)]
				legArmorSlot.Value = lowfrom["Slot" .. tostring(i)]
			end
			if not hasappliedstarterdata then
				blockinvensaving.Value = false
				hasappliedstarterdata = not hasappliedstarterdata
			end
	end

	-- Apply saved data on start
	ApplySavedData()
	print("Waiting for signal")
	game.ReplicatedStorage:WaitForChild("AllowToSaveData").OnServerEvent:Wait()
	blockinvensaving.Value = false
	print("Signal")
	
	local function SaveData(data)
		local id = game.PrivateServerId .. plr.UserId

		-- Save data with error handling
		local success, err = pcall(function()
			datastore:SetAsync(id, data)
		end)
		if not success then
			warn("Failed to save data for player " .. plr.Name .. ": " .. err)
		end
		print("Saving data to datastore for "..plr.Name..".")
	end

	-- Function to save data when properties change
	local function onValueChanged()
		if blockinvensaving.Value then
			return
		end
		print("getting data")
		local materialdata, meleedata, rangeddata, magicdata, questdata, headarmordata, middlearmordata, legarmordata, moneyValue = GetDataForAll()
		SaveData({materialdata, meleedata, rangeddata, magicdata, questdata, headarmordata, middlearmordata, legarmordata, moneyValue})
	end
	
	

	-- Connect value changed events to save data
	SavePlrDataFromServerScripts.Event:Connect(onValueChanged)
	money:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	manaAmount:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	arrowAmount:GetPropertyChangedSignal("Value"):Connect(onValueChanged)

	-- For materials
	for i = 1, numberofMaterialSlots do
		local currentMaterialSlot = materialdataslots["Slot" .. tostring(i)]
		print(currentMaterialSlot)
		local amount = currentMaterialSlot:FindFirstChild("Amount")
		if amount then
			amount:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
		end
		currentMaterialSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

	-- For quests
	for i = 1, numberofQuestSlots do
		local currentQuestSlot = questslots["Slot" .. tostring(i)]
		currentQuestSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)

		local identifier = currentQuestSlot:FindFirstChild("Identifier")
		if identifier then
			identifier:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
		end

		local rewards = currentQuestSlot:FindFirstChild("Rewards")
		if rewards then
			rewards:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
		end
	end

	-- For melee slots
	for i = 1, numberofMeleeSlots do
		local currentMeleeSlot = meleedataslots["Slot" .. tostring(i)]
		currentMeleeSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

	-- For ranged slots
	for i = 1, numberofRangedSlots do
		local currentRangedSlot = rangeddataslots["Slot" .. tostring(i)]
		currentRangedSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

	-- For magic slots
	for i = 1, numberofMagicSlots do
		local currentMagicSlot = magicdataslots["Slot" .. tostring(i)]
		currentMagicSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

	-- For head armor slots
	for i = 1, numberofHeadArmorSlots do
		local currentHeadArmorSlot = harmordataslots["Slot" .. tostring(i)]
		currentHeadArmorSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

	-- For middle armor slots
	for i = 1, numberofMiddleArmorSlots do
		local currentMiddleArmorSlot = marmordataslots["Slot" .. tostring(i)]
		currentMiddleArmorSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

	-- For leg armor slots
	for i = 1, numberofLegArmorSlots do
		local currentLegArmorSlot = larmordataslots["Slot" .. tostring(i)]
		currentLegArmorSlot:GetPropertyChangedSignal("Value"):Connect(onValueChanged)
	end

end)

And then there is the module script for default data.

local materialsdef = {}
local meleedef = {}
local rangeddef = {}
local magicdef = {}
local questsdef = {}
local headdef = {}
local middledef = {}
local lowdef = {}
local moneydef = 0

-- Initialize default materials and quests data
for i = 1, 150 do
	materialsdef["Slot" .. tostring(i) .. "Name"] = ""
	materialsdef["Slot" .. tostring(i) .. "Amount"] = 0
	questsdef["Slot" .. tostring(i)] = ""
	questsdef["Slot" .. tostring(i) .. "Identifier"] = 0
	questsdef["Slot" .. tostring(i) .. "Rewards"] = ""
end

-- Initialize default melee, ranged, and magic data
for i = 1, 10 do
	meleedef["Slot" .. tostring(i)] = ""
	rangeddef["Slot" .. tostring(i)] = ""
	magicdef["Slot" .. tostring(i)] = ""
end
magicdef["Mana"] = 50

-- Initialize default armor data
for i = 1, 3 do
	headdef["Slot" .. tostring(i)] = ""
	middledef["Slot" .. tostring(i)] = ""
	lowdef["Slot" .. tostring(i)] = ""
end

-- Combine all default data into one table
local defaulttable = {}
defaulttable["Materials"] = materialsdef
defaulttable["Melee"] = meleedef
defaulttable["Ranged"] = rangeddef
defaulttable["Magic"] = magicdef
defaulttable["Quests"] = questsdef
defaulttable["Head"] = headdef
defaulttable["Middle"] = middledef
defaulttable["Low"] = lowdef
defaulttable["Money"] = moneydef

return defaulttable

You can set up exactly what I have here if you paste the first code into a script in ServerScriptService and the second chunk of code into a module script parented under the first one named “DefaultData”. :+1:

Thanks for your time!

You can’t save table in datastore. You should firstly convert to string and then save by datastore:SetAsync(id, HttpService:JSONEncode(data)). And when you get you should do return HttpService:JSONEncode(datastore:GetAsync(id)). That’s my first post on devforum :smile:

1 Like

Okay! I’ll try that. Thanks alot!

1 Like

np, ima always ready to help :slight_smile:

1 Like

I tried that but nothing is working :sob:

Actually nevermind! That was the issue its just that there were other issues as well. Thanks so much for helping!!!

I recommend you look at profile store/profile service will make it a lot easier with data saving and getting

Also good suggest, but i never tried that. I usually use datastore2

never heard of datastore2 and I am pretty sure profilestore/service is a lot more maintained an has better handling than other libraries out there.

Here’s ds2 How to use DataStore2 - Data Store caching and data loss prevention - Resources / Community Tutorials - Developer Forum | Roblox