Data storage not saving

Another day, another topic… and this time it has to do with another more complicated problem: Datastoring.

I’m trying to make a simulator game that saves the data of the player, but for some reason, the data is returning nil no matter what. Whenever I print the table it just prints one specific part of the multi-table.

I’ve looked along the DevForum’s but haven’t seen anything helpful so far, and I’ve tried solving the issue myself.

Here is the dialogue module script:

local DataModule = {}

local DataStoreService = game:GetService("DataStoreService")
local PlayerStats = DataStoreService:GetDataStore("PlayerStats")
local PlayerInventoryData = DataStoreService:GetDataStore("PlayerInventory")
local PlayerSettingsData = DataStoreService:GetDataStore("PlayerSettingsData")
local PlayerMappingData = DataStoreService:GetDataStore("PlayerMapping")

local toolConfig = require(game.ReplicatedStorage.Modules:WaitForChild("Data"):WaitForChild("Tools"))
local attacktoolConfig = require(game.ReplicatedStorage.Modules:WaitForChild("Data"):WaitForChild("AttackTools"))

function DataModule.giveTool(player)
	local tool = player.inventory.EquippedTool.Value

	repeat task.wait() until player.Character

	local toolClone = game.ServerStorage:FindFirstChild("Tools"):FindFirstChild(tool):Clone()
	toolClone.Parent = player.Backpack
end

function DataModule.SaveData(player)
	local playerDataToSave = {}
	local playerToolsToSave = {}
	local playerSettingsToSave = {}
	local playerMappingToSave = {}
	
	local playerData = {
		Cheese = player.leaderstats.Cheese.Value,
		Money = player.leaderstats.Money.Value,
		Rebirths = player.leaderstats.Rebirths.Value,
	}
	playerDataToSave["PlayerData"] = playerData
	print(playerDataToSave["PlayerData"])
	
	local ownedToolsTable = {}
	for _, tool in ipairs(player.inventory.OwnedTools:GetChildren()) do
		ownedToolsTable[tool.Name] = tool.Value
	end

	local ownedAttackToolsTable = {}
	for _, tool in ipairs(player.inventory.OwnedAttackTools:GetChildren()) do
		ownedAttackToolsTable[tool.Name] = tool.Value
	end
	
	local inventory = {
		EquippedTool = player.inventory.EquippedTool.Value,
		OwnedTools = ownedToolsTable,
		EquippedAttackTool = player.inventory.EquippedAttackTool.Value,
		OwnedAttackTools = ownedAttackToolsTable,
	}
	
	playerToolsToSave["Inventory"] = inventory
	print(playerToolsToSave["Inventory"])
	
	local settingsData = {
		Shadows = player:WaitForChild("PlayerGui").MenuUI.Settings:WaitForChild("Settings").Shadows.Value,
		Music = player:WaitForChild("PlayerGui").MenuUI.Settings:WaitForChild("Settings").Music.Value,
		Sound = player:WaitForChild("PlayerGui").MenuUI.Settings:WaitForChild("Settings").Sound.Value,
	}
	
	playerSettingsToSave["Settings"] = settingsData
	
	local teleports = {}
	for _, teleport in ipairs(player.values:GetChildren()) do
		teleports[teleport.Name] = teleport.Value
	end
	playerMappingToSave["Teleports"] = teleports
	
	local success, errorMessage = pcall(function()
		PlayerStats:SetAsync(player.UserId, playerDataToSave)
		PlayerInventoryData:SetAsync(player.UserId, playerToolsToSave)
		PlayerSettingsData:SetAsync(player.UserId, playerSettingsToSave)
		PlayerMappingData:SetAsync(player.UserId, playerMappingToSave)
	end)
	
	if not success then
		warn("⚠️ "..errorMessage)
	else
		print("✅ Player's data has successfully saved.")
	end
end

function DataModule.LoadData(player)
	local playerData
	local playerInventory
	local playerSettings
	local playerMapping

	local success, errorMessage = pcall(function()
		playerData = PlayerStats:GetAsync(player.UserId)
		playerInventory = PlayerInventoryData:GetAsync(player.UserId)
		playerSettings = PlayerSettingsData:GetAsync(player.UserId)
		playerMapping = PlayerMappingData:GetAsync(player.UserId)
	end)
	
	if success then
		print(playerData)
		if playerData then
			print("✅ Data for player has successfully loaded.")
			
			-- Load cheese, money and rebirths
			player.leaderstats:WaitForChild("Cheese").Value = playerData.Cheese
			player.leaderstats.Money.Value = playerData.Money
			player.leaderstats.Rebirths.Value = playerData.Rebirths
		else
			print("⚠️ No data found for player "..player.Name..". Initializing data.")
			
			-- Initialize cheese, money, and rebirths
			local initialSuccess, initialError = pcall(function()
				player.leaderstats.Cheese.Value = 0
				player.leaderstats.Money.Value = 0
				player.leaderstats.Rebirths.Value = 0
			end)
			
			if not initialSuccess then
				warn("⚠️ Error initializing data: "..initialError)
				player:Kick("⚠️ An error occurred while initializing your data. Please rejoin the game later. ⚠️")
			end
		end
		
		if playerInventory then
			print(playerInventory)
			print("✅ Inventory data for player "..player.Name.." has successfully loaded.")
			print(playerInventory["Inventory"].EquippedTool)
			print(playerInventory["Inventory"])
			player.inventory.EquippedTool.Value = playerInventory.EquippedTool
			player.inventory.EquippedAttackTool.Value = playerInventory.EquippedAttackTools

			for toolName, toolValue in pairs(playerInventory.OwnedTools) do
				player.inventory.OwnedTools:FindFirstChild(toolName).Value = toolValue
			end
			
			for toolName, toolValue in pairs(playerInventory.OwnedAttackTools) do
				player.inventory.OwnedAttackTools:FindFirstChild(toolName).Value = toolValue
			end
		else
			-- Initialize owned tools.
			local initialSuccess, initialError = pcall(function()
				for _, tool in pairs(player.inventory.OwnedTools:GetChildren()) do
					if tool.Name == "BasicCheese" then
						tool.Value = true
					else
						tool.Value = false
					end
				end
				-- Attack tools.
				for _, tool in pairs(player.inventory.OwnedAttackTools:GetChildren()) do
					if tool.Name == "Nothing" then
						tool.Value = true
					else
						tool.Value = false
					end
				end

				player.inventory.EquippedTool.Value = "BasicCheese"
				player.inventory.EquippedAttackTool.Value = "Nothing"
			end)
			
			if not initialSuccess then
				warn("⚠️ Error initializing data: "..initialError)
				player:Kick("⚠️ An error occurred while initializing your data. Please rejoin the game later. ⚠️")
			end
		end
		
		if playerSettings then
			print("✅ Settings Data for player "..player.Name.." has successfully loaded.")
			print(playerSettings)
			player.PlayerGui.MenuUI.Settings.Settings.Shadows.Value = playerSettings.Shadows
			player.PlayerGui.MenuUI.Settings.Settings.Music.Value = playerSettings.Music
			player.PlayerGui.MenuUI.Settings.Settings.Sound.Value = playerSettings.Sound
		else
			print("⚠️ No settings data found for player "..player.Name..". Initializing data.")
			
			local initialSuccess, initialError = pcall(function()
				player.PlayerGui.MenuUI.Settings:WaitForChild("Settings").Shadows.Value = true
				player.PlayerGui.MenuUI.Settings:WaitForChild("Settings").Music.Value = true
				player.PlayerGui.MenuUI.Settings:WaitForChild("Settings").Sound.Value = true
			end)
			
			if not initialSuccess then
				warn("⚠️ Error initializing data: "..initialError)
				player:Kick("⚠️ An error occurred while initializing your data. Please rejoin the game later. ⚠️")
			end
		end
		
		if playerMapping then
			print("✅ Mapping Data for player "..player.Name.." has successfully loaded.")
			print(playerMapping["Teleports"])
			
			-- Load teleports
			for teleportName, teleportValue in pairs(playerMapping.Teleports) do
				player.values:FindFirstChild(teleportName).Value = teleportValue
				--if table.find(devTeam, player.Name) then
				--print(player.DisplayName.." is apart of the devteam! ⚠️")
				--player.values:FindFirstChild(teleportName).Value = true
				--end
			end
		else
			print("⚠️ No data found for player "..player.Name..". Initializing data.")

			-- Initialize teleports
			for _, teleport in ipairs(player.values:GetChildren()) do
				teleport.Value = false
			end
		end
	else
		warn("⚠️ Error loading data: "..errorMessage.." ⚠️")
		player:Kick("⚠️ "..player.Name.."'s data has failed to load. Please rejoin the game. ⚠️")
	end
end

return DataModule

I don’t need anyone to re-write this entire piece of code, I just need some pointers or some smaller code snippets on where the issue is. Thanks! :smile:

Here is error logs:
(yes ik there’s an error there but idk how to fix it) [and yes i already checked to absolutely make sure that the value is valid in explorer]

19:58:39.815 ▶ {...} - Server - DataModule:97 19:58:39.815 ✅ Data for player has successfully loaded. - Server - DataModule:99 19:58:39.815 ▶ {...} - Server - DataModule:122 19:58:39.816 ✅ Inventory data for player Capiso21 has successfully loaded. - Server - DataModule:123 19:58:39.816 ReplicatedStorage.Modules.DataModule:124: attempt to index nil with 'EquippedTool' - Server - DataModule:124

playerInventory["Inventory"]

[“Inventory”] is nil here. Did you mean [“inventory”]? Because that is what you wrote at the beginning. Capitalization matters.

No, just the folder’s actual name in the player is “inventory”. I know that Roblox is case-sensitive so I made sure that the names were spelled correctly. The main problem is that I don’t understand why it prints a table that (i doubt bc it’s weird what’s going on or smth) but only the “OwnedTools” folder’s children prints out in a table. It probably isn’t some weird error though.

Do all the tables print out something in the player’s inventory?

The way it works is that there is a folder named “inventory” inside of the player (in game.Players), and inside this folder are four things: EquippedTool, OwnedTools, EquippedAttackTool, and OwnedAttackTools.

Yes I’m asking you if OwnedTools and OwnedAttackTools print out something.

Yeah, if you’re talking about the folder, it prints out the list of children inside of it. However, if you’re talking about the data store itself, the player["Inventory"] prints all four with each having their values and children’s names with those children having their values. The issue here is that when loading, it isn’t working for some reason as only the OwnedTools folder children are printing (though i doubt it has something to do with something strange not working correctly…)

Man, I really need help on this one since data-saving is an important part of the game I’m trying to create. I can provide more details if possible, but as the game currently stands, it probably won’t be received well for lack of data-saving.

helppp :sob::sob::sob::sob::sob::sob::sob::sob::sob::sob::sob::sob::sob::sob::sob:

Seems like nobody has a solution :cry: