Datastore issues

I’m having issues with loading data from a datastore. When someone with data joins the game it works fine, but if someone without data (a new player) joins the game the script errors. How can I fix this?

Here is the script:

-- Configuration
local DataStoreService = game:GetService("DataStoreService")
local DATASTORE_NAME = "PlayerData"
local LoggingManager = require(script.Parent.LoggingManager)

-- Function to load player data
local function loadPlayerData(player:Player)
	local datastore = DataStoreService:GetDataStore(DATASTORE_NAME)
	
	local data
	local success, response = pcall(function()
		data = datastore:GetAsync(player.UserId)
	end)

	if success then
		warn("Successfully loaded player data for @" .. player.Name .. " (" .. player.UserId .. "):")
		warn(data)
		LoggingManager.PlayerAdded(player, data, "table")
		
		if data == nil then return nil else return data end
	else
		warn("Failed to load player data for @" .. player.Name .. " (" .. player.UserId .. "):")
		warn(response)
		LoggingManager.PlayerAdded(player, response, "error")
	end
end

-- Function to save player data
local function savePlayerData(player:Player)
	local datastore = DataStoreService:GetDataStore(DATASTORE_NAME)
	local leaderstats = player:FindFirstChild("leaderstats")
	local hiddenstats = leaderstats:FindFirstChild("hiddenstats")

	local data = {}
	
	if leaderstats then
		data.leaderstats = {}
		for _, stat in pairs(leaderstats:GetChildren()) do
			if not stat:IsA("Folder") and not stat:FindFirstChild("DoNotSave") then
				data.leaderstats[stat.Name] = stat.Value
			end
		end
	end

	local success, response = pcall(function()
		datastore:SetAsync(player.UserId, data)
	end)
	
	if success then
		warn("Successfully saved player data for @" .. player.Name .. " (" .. player.UserId .. "):")
		warn(data)
		LoggingManager.PlayerRemoving(player, data, "table")
	else
		warn("Failed to save player data for @" .. player.Name .. " (" .. player.UserId .. "):")
		warn(response)
		LoggingManager.PlayerRemoving(player, response, "error")
	end
end

-- Function to initialize stats for a new player
local function initializePlayerLeaderstats(player:Player, data)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local kills = Instance.new("IntValue")
	kills.Name = "Kills"
	kills.Parent = leaderstats

	local XP = Instance.new("IntValue")
	XP.Name = "XP"
	XP.Parent = leaderstats
	
	if data == nil or not data or not data.leaderstats or not data.hiddenstats then
		XP.Value = 0
		Kills.Value = 0
	elseif data and data.leaderstats and data.hiddenstats then
		XP.Value = (data and data.leaderstats and data.leaderstats.XP) or 0
		Kills.Value = (data and data.leaderstats and data.leaderstats.Kills) or 0
	end
end

game.Players.PlayerAdded:Connect(function(player) -- Player added event
	local data = loadPlayerData(player) -- Load player data
	if data == nil then
		if not player:FindFirstChild("leaderstats") then initializePlayerLeaderstats(player, nil) end
	else
		if not player:FindFirstChild("leaderstats") then initializePlayerLeaderstats(player, data) end
	end
end)

game.Players.PlayerRemoving:Connect(function(player) -- Player removing event
	savePlayerData(player) -- Save player data
end)

4 Likes

So… what’s the problem??? What do mean by “the script errors”? Is it not doing something it is supposed to do?

1 Like
ignore this, lol

You could assume a default value to give players if they don’t have data set already, if you’re not already doing that.

For example, I could have a coin data store that has a default of ‘0’. When the player data is loaded, if there is any, then that ‘0’ is changed accordingly. If there’s ‘technically’ no player data, then the players data is ‘0’.

That ‘nil’ being printed could instead be ‘false’ or something. Like, if data = nil, data = false. (the else statement for successfully getting the players data area of the code.)

This all is challenging for me to try to convey, I hope it makes sense. I’ve been working on my data system for my game and it’s over 1,000 lines of code at this point. It’s been a pain in my backside, so, I’d understand any frustration. :sweat_smile:

1 Like

Is that not what I currently do?

3 Likes

If there is no data for the player then the script breaks.

1 Like

What are you trying to achieve with this script?

1 Like

I’m trying to load player data from a datastore.

Well it’s gonna be nil if there is no data.

1 Like

But it doesn’t seem to know that. It doesn’t create the leaderstats folder if someone doesn’t have data.

3 Likes

You’re doing it right, I think. What I was initially recommending was wrong. It seems there’s a typo in the ‘initializePlayerLeaderstats’ function on lines 76 and 79.

The code I took from the OP. It might be more than just the spelling, but could you make sure it works when that issue is fixed?


I’d recommend changing it to this to better read what is the intValue and what is the name of said intValue:

I have a ton of stats so I edited the script quickly when posting the question. There aren’t any typos in the main script.

My issue:
The script works fine if the player has saved datastore stats, but it breaks (does not create a leaderstats folder) if they don’t have anything in the datastore.

2 Likes

I’m not sure what the specific issue might be. Maybe showing how I’ve gone about my system would help. :person_shrugging:

I use a folder with values that I clone and set under the player when they load/join into my game. This makes it easier to change data as I can access it easier across the entire game.

image

image

Whenever I call a function to save the game, the datastore script calls upon the values on the server and sets those values to a table of data. This all means that the player already has default data, technically, even though it’s not in Roblox’s DataStoreService at all yet. Only when that data is altered, which can happen by just leaving or playing the game, then the player then gets data stored using Roblox’s DataStoreService that passes the ‘success’ pcall.

Here's the current code of the main server script, if that helps.

local DataStoreService = game:GetService("DataStoreService")
---
local UpdateUIWithSaveFileInfo_RemoteEvent = game.Workspace.RemoteEventsFolder.UI.updateUIWithSaveFileInfo
---
local get_overallPlayTimeStat_FromDataStore = DataStoreService:GetDataStore("overallPlayTimeStat")
local get_playerOptionPreferenceDataTable_FromDataStore = DataStoreService:GetDataStore("playerOptionPreferenceDataTable")
local get_saveFile1_DataTable_FromDataStore = DataStoreService:GetDataStore("saveFile1")
local get_saveFile2_DataTable_FromDataStore = DataStoreService:GetDataStore("saveFile2")
local get_saveFile3_DataTable_FromDataStore = DataStoreService:GetDataStore("saveFile3")
---
local currentSaveFile


----- Data:
-- default value stuff, they get changed and saved and whatnot.
local data_overallPlayTimeStat = 0

local playerOptionPreferenceDataTable = {
	-- Audio:
	data_BackgroundMusicVolume = 0.5,
	data_SoundEffectsVolume = 0.5,
	
	-- General:
	data_ActiveCameraEnabled = true,
	data_AutoJumpEnabled = false,
	data_FOV = 70,
	data_HapticFeedbackEnabled = true,
	
	-- Graphics:
	data_BloomEnabled = true,
	data_CloudsEnabled = true,
	data_DynamicWaterEnabled = true,	
	data_DynamicWindEnabled = true,
	data_ColorCorrectionEnabled = true,
	data_EnvironmentalParticlesEnabled = true,
	data_GlobalShadowsEnabled = true,
	data_SunRaysEnabled = true,
}

local saveFile1_DataTable = {
	data_saveFileName = "Save File 1",
	
	data_totalCoinsCollected = 0,
	data_totalGoldenToastCollected = 0,

	data_fileSpecificPlayTimeStat = 0,
	data_hasGameBeenStarted = false,
	
	ObjectModelListOfGoldenToastCollected_DataTable = {
		-- Golden Toast 'object models' should be added to this list after being collected.
		-- Code for this is on 'GoldenToast - CollectionService Script'
	},
	
	WorldBasedGoldenToastCollected_DataTable = {
		HubWorld = 0,
		TestingWorld = 0,
		World1_Grasslands = 0,
	},
	
}

local saveFile2_DataTable = {
	data_saveFileName = "Save File 2",

	data_totalCoinsCollected = 0,
	data_totalGoldenToastCollected = 0,

	data_fileSpecificPlayTimeStat = 0,
	data_hasGameBeenStarted = false,
}

local saveFile3_DataTable = {
	data_saveFileName = "Save File 3",

	data_totalCoinsCollected = 0,
	data_totalGoldenToastCollected = 0,

	data_fileSpecificPlayTimeStat = 0,
	data_hasGameBeenStarted = false,
}
---


-----
local function loadSaveData(player)
	
	-- Main Folder:
	local playerDataFolder = script.Parent.playerDataFolder:Clone()
	playerDataFolder.Parent = player
	
		--- Game-wide Data:
		local gameWideDataFolder = playerDataFolder.gameWideDataFolder
	
			local overallPlayTimeStat_NumberValue = gameWideDataFolder.overallPlayTimeStat_NumberValue
	
		--- Player Options Preference Data Folder:
		local playerOptionPreferenceDataTable_TableFolder = playerDataFolder.playerOptionPreferenceDataTable_TableFolder
	
			--- Audio Folder:
			local Audio_TableFolder = playerOptionPreferenceDataTable_TableFolder.Audio_TableFolder
	
				local BackgroundMusicVolume_NumberValue = Audio_TableFolder.BackgroundMusicVolume_NumberValue
				local SoundEffectsVolume_NumberValue = Audio_TableFolder.SoundEffectsVolume_NumberValue
	
			--- General Folder:
			local General_TableFolder = playerOptionPreferenceDataTable_TableFolder.General_TableFolder
	
				local ActiveCameraEnabled_BoolValue = General_TableFolder.ActiveCameraEnabled_BoolValue
				local AutoJumpEnabled_BoolValue = General_TableFolder.AutoJumpEnabled_BoolValue
				local FOV_NumberValue = General_TableFolder.FOV_NumberValue
				local HapticFeedbackEnabled_BoolValue = General_TableFolder.HapticFeedbackEnabled_BoolValue
	
			--- Graphics Folder:
			local Graphics_TableFolder = playerOptionPreferenceDataTable_TableFolder.Graphics_TableFolder
				
				local BloomEnabled_BoolValue = Graphics_TableFolder.BloomEnabled_BoolValue
				local CloudsEnabled_BoolValue = Graphics_TableFolder.CloudsEnabled_BoolValue			
				local DynamicWaterEnabled_BoolValue = Graphics_TableFolder.DynamicWaterEnabled_BoolValue			
				local DynamicWindEnabled_BoolValue = Graphics_TableFolder.DynamicWindEnabled_BoolValue
				local ColorCorrectionEnabled_BoolValue = Graphics_TableFolder.ColorCorrectionEnabled_BoolValue
				local EnvironmentalParticlesEnabled_BoolValue = Graphics_TableFolder.EnvironmentalParticlesEnabled_BoolValue
				local GlobalShadowsEnabled_BoolValue = Graphics_TableFolder.GlobalShadowsEnabled_BoolValue
				local SunRaysEnabled_BoolValue = Graphics_TableFolder.SunRaysEnabled_BoolValue
	--- Safe File 1 Folder:
	local saveFile1_TableFolder = playerDataFolder.saveFile1_TableFolder
	local SaveFile1_collectiblesCollectedTableFolder = saveFile1_TableFolder.collectiblesCollectedTableFolder
	local SaveFile1_worldBasedGoldenToastCollectedFolder = SaveFile1_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local SaveFile1_totalCoinsCollected_NumberValue = SaveFile1_collectiblesCollectedTableFolder.totalCoinsCollected
	local SaveFile1_totalGoldenToastCollected_NumberValue = SaveFile1_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local SaveFile1_fileSpecificPlayTimeStat_NumberValue = saveFile1_TableFolder.fileSpecificPlayTimeStat
	local SaveFile1_hasGameBeenStarted_NumberValue = saveFile1_TableFolder.hasGameBeenStarted
	local SaveFile1_nameOfSaveFile = saveFile1_TableFolder.saveFileName_StringValue
	
	--- Safe File 2 Folder:
	local saveFile2_TableFolder = playerDataFolder.saveFile2_TableFolder
	local SaveFile2_collectiblesCollectedTableFolder = saveFile2_TableFolder.collectiblesCollectedTableFolder
	local SaveFile2_worldBasedGoldenToastCollectedFolder = SaveFile2_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local SaveFile2_totalCoinsCollected_NumberValue = SaveFile2_collectiblesCollectedTableFolder.totalCoinsCollected
	local SaveFile2_totalGoldenToastCollected_NumberValue = SaveFile2_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local SaveFile2_fileSpecificPlayTimeStat_NumberValue = saveFile2_TableFolder.fileSpecificPlayTimeStat
	local SaveFile2_hasGameBeenStarted_NumberValue = saveFile2_TableFolder.hasGameBeenStarted
	local SaveFile2_nameOfSaveFile = saveFile2_TableFolder.saveFileName_StringValue


	--- Safe File 3 Folder:
	local saveFile3_TableFolder = playerDataFolder.saveFile3_TableFolder
	local SaveFile3_collectiblesCollectedTableFolder = saveFile3_TableFolder.collectiblesCollectedTableFolder
	local SaveFile3_worldBasedGoldenToastCollectedFolder = SaveFile3_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local SaveFile3_totalCoinsCollected_NumberValue = SaveFile3_collectiblesCollectedTableFolder.totalCoinsCollected
	local SaveFile3_totalGoldenToastCollected_NumberValue = SaveFile3_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local SaveFile3_fileSpecificPlayTimeStat_NumberValue = saveFile3_TableFolder.fileSpecificPlayTimeStat
	local SaveFile3_hasGameBeenStarted_NumberValue = saveFile3_TableFolder.hasGameBeenStarted
	local SaveFile3_nameOfSaveFile = saveFile3_TableFolder.saveFileName_StringValue
	-----
	
	---------
	
	--

	local success, errormessage = pcall(function() 	-- Load Data
		data_overallPlayTimeStat = get_overallPlayTimeStat_FromDataStore:GetAsync(player.UserId) 
		
		playerOptionPreferenceDataTable = get_playerOptionPreferenceDataTable_FromDataStore:GetAsync(player.UserId)
		
		saveFile1_DataTable = get_saveFile1_DataTable_FromDataStore:GetAsync(player.UserId)
		saveFile2_DataTable = get_saveFile2_DataTable_FromDataStore:GetAsync(player.UserId)
		saveFile3_DataTable = get_saveFile3_DataTable_FromDataStore:GetAsync(player.UserId)

	end)

	if success == true then
		-- set data equal to what it needs to be
		
		--print("--- Print Test 1 ---")
		--print(data_overallPlayTimeStat)
		--print(playerOptionPreferenceDataTable)
		--print(saveFile1_DataTable)
		--print("--- End ---")

		if data_overallPlayTimeStat then
			overallPlayTimeStat_NumberValue.Value = data_overallPlayTimeStat
		end
			
		if playerOptionPreferenceDataTable then

			--- Audio:
			BackgroundMusicVolume_NumberValue.Value = playerOptionPreferenceDataTable.data_BackgroundMusicVolume
			SoundEffectsVolume_NumberValue.Value = playerOptionPreferenceDataTable.data_SoundEffectsVolume

			--- General:
			ActiveCameraEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_ActiveCameraEnabled
			AutoJumpEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_AutoJumpEnabled
			FOV_NumberValue.Value = playerOptionPreferenceDataTable.data_FOV
			HapticFeedbackEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_HapticFeedbackEnabled

			--- Graphics:
			BloomEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_BloomEnabled
			CloudsEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_CloudsEnabled
			DynamicWaterEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_DynamicWaterEnabled
			DynamicWindEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_DynamicWindEnabled
			ColorCorrectionEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_ColorCorrectionEnabled
			EnvironmentalParticlesEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_EnvironmentalParticlesEnabled
			GlobalShadowsEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_GlobalShadowsEnabled
			SunRaysEnabled_BoolValue.Value = playerOptionPreferenceDataTable.data_SunRaysEnabled

		end
		
		if saveFile1_DataTable then			
			SaveFile1_totalCoinsCollected_NumberValue.Value = saveFile1_DataTable.data_totalCoinsCollected
			SaveFile1_totalGoldenToastCollected_NumberValue.Value = saveFile1_DataTable.data_totalGoldenToastCollected

			SaveFile1_fileSpecificPlayTimeStat_NumberValue.Value = saveFile1_DataTable.data_fileSpecificPlayTimeStat 
			SaveFile1_hasGameBeenStarted_NumberValue.Value = saveFile1_DataTable.data_hasGameBeenStarted
			
			--print(saveFile1_DataTable.data_saveFileName)
			SaveFile1_nameOfSaveFile.Value = saveFile1_DataTable.data_saveFileName
			--a = saveFile1_DataTable.ObjectModelListOfGoldenToastCollected_DataTable.
			
			--print("Loaded Save File 1 data for "..player.Name)

		end

		if saveFile2_DataTable then						
			SaveFile2_totalCoinsCollected_NumberValue.Value = saveFile2_DataTable.data_totalCoinsCollected
			SaveFile2_totalGoldenToastCollected_NumberValue.Value = saveFile2_DataTable.data_totalGoldenToastCollected

			SaveFile2_fileSpecificPlayTimeStat_NumberValue.Value = saveFile2_DataTable.data_fileSpecificPlayTimeStat 
			SaveFile2_hasGameBeenStarted_NumberValue.Value = saveFile2_DataTable.data_hasGameBeenStarted
			
			SaveFile2_nameOfSaveFile.Value = saveFile2_DataTable.data_saveFileName
			--print("Loaded Save File 2 data for "..player.Name)

		end

		if saveFile3_DataTable then						
			SaveFile3_totalCoinsCollected_NumberValue.Value = saveFile3_DataTable.data_totalCoinsCollected
			SaveFile3_totalGoldenToastCollected_NumberValue.Value = saveFile3_DataTable.data_totalGoldenToastCollected

			SaveFile3_fileSpecificPlayTimeStat_NumberValue.Value = saveFile3_DataTable.data_fileSpecificPlayTimeStat 
			SaveFile3_hasGameBeenStarted_NumberValue.Value = saveFile3_DataTable.data_hasGameBeenStarted
			
			SaveFile3_nameOfSaveFile.Value = saveFile3_DataTable.data_saveFileName
			--print("Loaded Save File 3 data for "..player.Name)

		end
		
		print(player.Name.."'s data had been loaded.")
		UpdateUIWithSaveFileInfo_RemoteEvent:FireClient(player)
		--print("--- Print Test 2 ---")
		--print(data_overallPlayTimeStat)
		--print(playerOptionPreferenceDataTable)
		--print(saveFile1_DataTable)
		--print("--- End ---")
		
	end
	
	
end

local function attemptToSaveGame(player)
	
	-- Main Folder:
	local playerDataFolder = player.playerDataFolder
	
	--- Game-wide Data:
	local gameWideDataFolder = playerDataFolder.gameWideDataFolder
	local overallPlayTimeStat_NumberValue = gameWideDataFolder.overallPlayTimeStat_NumberValue
	
	--- Player Options Preference Data Folder:
	local playerOptionPreferenceDataTable_TableFolder = playerDataFolder.playerOptionPreferenceDataTable_TableFolder
	
	--- Audio Folder:
	local Audio_TableFolder = playerOptionPreferenceDataTable_TableFolder.Audio_TableFolder
	local BackgroundMusicVolume_NumberValue = Audio_TableFolder.BackgroundMusicVolume_NumberValue
	local SoundEffectsVolume_NumberValue = Audio_TableFolder.SoundEffectsVolume_NumberValue
	
	--- General Folder:
	local General_TableFolder = playerOptionPreferenceDataTable_TableFolder.General_TableFolder
	local ActiveCameraEnabled_BoolValue = General_TableFolder.ActiveCameraEnabled_BoolValue
	local AutoJumpEnabled_BoolValue = General_TableFolder.AutoJumpEnabled_BoolValue
	local FOV_NumberValue = General_TableFolder.FOV_NumberValue
	local HapticFeedbackEnabled_BoolValue = General_TableFolder.HapticFeedbackEnabled_BoolValue
	
	--- Graphics Folder:
	local Graphics_TableFolder = playerOptionPreferenceDataTable_TableFolder.Graphics_TableFolder
	local BloomEnabled_BoolValue = Graphics_TableFolder.BloomEnabled_BoolValue
	local CloudsEnabled_BoolValue = Graphics_TableFolder.CloudsEnabled_BoolValue			
	local DynamicWaterEnabled_BoolValue = Graphics_TableFolder.DynamicWaterEnabled_BoolValue			
	local DynamicWindEnabled_BoolValue = Graphics_TableFolder.DynamicWindEnabled_BoolValue
	local ColorCorrectionEnabled_BoolValue = Graphics_TableFolder.ColorCorrectionEnabled_BoolValue
	local EnvironmentalParticlesEnabled_BoolValue = Graphics_TableFolder.EnvironmentalParticlesEnabled_BoolValue
	local GlobalShadowsEnabled_BoolValue = Graphics_TableFolder.GlobalShadowsEnabled_BoolValue
	local SunRaysEnabled_BoolValue = Graphics_TableFolder.SunRaysEnabled_BoolValue
	
	
	--- Safe File 1 Folder:
	local saveFile1_TableFolder = playerDataFolder.saveFile1_TableFolder
	local saveFile1_collectiblesCollectedTableFolder = saveFile1_TableFolder.collectiblesCollectedTableFolder
	local saveFile1_worldBasedGoldenToastCollectedFolder = saveFile1_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local saveFile1_totalCoinsCollected_NumberValue = saveFile1_collectiblesCollectedTableFolder.totalCoinsCollected
	local saveFile1_totalGoldenToastCollected_NumberValue = saveFile1_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local saveFile1_fileSpecificPlayTimeStat_NumberValue = saveFile1_TableFolder.fileSpecificPlayTimeStat
	local saveFile1_hasGameBeenStarted_NumberValue = saveFile1_TableFolder.hasGameBeenStarted
	local SaveFile1_nameOfSaveFile = saveFile1_TableFolder.saveFileName_StringValue

	--- Safe File 2 Folder:
	local saveFile2_TableFolder = playerDataFolder.saveFile2_TableFolder
	local saveFile2_collectiblesCollectedTableFolder = saveFile2_TableFolder.collectiblesCollectedTableFolder
	local saveFile2_worldBasedGoldenToastCollectedFolder = saveFile2_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local saveFile2_totalCoinsCollected_NumberValue = saveFile2_collectiblesCollectedTableFolder.totalCoinsCollected
	local saveFile2_totalGoldenToastCollected_NumberValue = saveFile2_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local saveFile2_fileSpecificPlayTimeStat_NumberValue = saveFile2_TableFolder.fileSpecificPlayTimeStat
	local saveFile2_hasGameBeenStarted_NumberValue = saveFile2_TableFolder.hasGameBeenStarted
	local SaveFile2_nameOfSaveFile = saveFile2_TableFolder.saveFileName_StringValue

	--- Safe File 3 Folder:
	local saveFile3_TableFolder = playerDataFolder.saveFile3_TableFolder
	local saveFile3_collectiblesCollectedTableFolder = saveFile3_TableFolder.collectiblesCollectedTableFolder
	local saveFile3_worldBasedGoldenToastCollectedFolder = saveFile3_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local saveFile3_totalCoinsCollected_NumberValue = saveFile3_collectiblesCollectedTableFolder.totalCoinsCollected
	local saveFile3_totalGoldenToastCollected_NumberValue = saveFile3_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local saveFile3_fileSpecificPlayTimeStat_NumberValue = saveFile3_TableFolder.fileSpecificPlayTimeStat
	local saveFile3_hasGameBeenStarted_NumberValue = saveFile3_TableFolder.hasGameBeenStarted
	local SaveFile3_nameOfSaveFile = saveFile3_TableFolder.saveFileName_StringValue

	---------
	
	
	local sessionDataTable = {		
		----- Data:
		-- This is the data the game will safe. Simply change the values before the game saves for it to be saved. Or, they should.
		data_overallPlayTimeStat = overallPlayTimeStat_NumberValue.Value,

		playerOptionPreferenceDataTable = {
			-- Audio:
			data_BackgroundMusicVolume = BackgroundMusicVolume_NumberValue.Value,
			data_SoundEffectsVolume = SoundEffectsVolume_NumberValue.Value,

			-- General:
			data_ActiveCameraEnabled = ActiveCameraEnabled_BoolValue.Value,
			data_AutoJumpEnabled = AutoJumpEnabled_BoolValue.Value,
			data_FOV = FOV_NumberValue.Value,
			data_HapticFeedbackEnabled = HapticFeedbackEnabled_BoolValue.Value,

			-- Graphics:
			data_BloomEnabled = BloomEnabled_BoolValue.Value,
			data_CloudsEnabled = CloudsEnabled_BoolValue.Value,
			data_DynamicWaterEnabled = DynamicWaterEnabled_BoolValue.Value,	
			data_DynamicWindEnabled = DynamicWindEnabled_BoolValue.Value,
			data_ColorCorrectionEnabled = ColorCorrectionEnabled_BoolValue.Value,
			data_EnvironmentalParticlesEnabled = EnvironmentalParticlesEnabled_BoolValue.Value,
			data_GlobalShadowsEnabled = GlobalShadowsEnabled_BoolValue.Value,
			data_SunRaysEnabled = SunRaysEnabled_BoolValue.Value,
		},

		saveFile1_DataTable = {
			data_totalCoinsCollected =  saveFile1_totalCoinsCollected_NumberValue.Value,
			data_totalGoldenToastCollected = saveFile1_totalGoldenToastCollected_NumberValue.Value,

			data_fileSpecificPlayTimeStat = saveFile1_fileSpecificPlayTimeStat_NumberValue.Value ,
			data_hasGameBeenStarted = saveFile1_hasGameBeenStarted_NumberValue.Value,
			
			data_saveFileName = SaveFile1_nameOfSaveFile.Value,
		},
		
		saveFile2_DataTable = {
			data_totalCoinsCollected = saveFile2_totalCoinsCollected_NumberValue.Value,
			data_totalGoldenToastCollected = saveFile2_totalGoldenToastCollected_NumberValue.Value,

			data_fileSpecificPlayTimeStat = saveFile2_fileSpecificPlayTimeStat_NumberValue.Value ,
			data_hasGameBeenStarted = saveFile2_hasGameBeenStarted_NumberValue.Value,
			
			data_saveFileName = SaveFile2_nameOfSaveFile.Value,
		},
		
		saveFile3_DataTable = {
			data_totalCoinsCollected = saveFile3_totalCoinsCollected_NumberValue.Value,
			data_totalGoldenToastCollected = saveFile3_totalGoldenToastCollected_NumberValue.Value,

			data_fileSpecificPlayTimeStat = saveFile3_fileSpecificPlayTimeStat_NumberValue.Value ,
			data_hasGameBeenStarted = saveFile3_hasGameBeenStarted_NumberValue.Value,
			
			data_saveFileName = SaveFile3_nameOfSaveFile.Value,
		},
		
	}
	
	local success = nil
	local errorMessage = nil
	local attempt_count = 1
	
	repeat
		success, errorMessage = pcall(function()
			get_overallPlayTimeStat_FromDataStore:SetAsync(player.UserId,sessionDataTable.data_overallPlayTimeStat)
			get_playerOptionPreferenceDataTable_FromDataStore:SetAsync(player.UserId,sessionDataTable.playerOptionPreferenceDataTable)
			
			get_saveFile1_DataTable_FromDataStore:SetAsync(player.UserId,sessionDataTable.saveFile1_DataTable)
			get_saveFile2_DataTable_FromDataStore:SetAsync(player.UserId,sessionDataTable.saveFile2_DataTable)
			get_saveFile3_DataTable_FromDataStore:SetAsync(player.UserId,sessionDataTable.saveFile3_DataTable)

		end)
		if success then
			print("Data saved for "..player.Name)
			UpdateUIWithSaveFileInfo_RemoteEvent:FireClient(player,currentSaveFile)
		else
			warn("Unable to save for "..player.Name)
			warn(errorMessage)
			task.wait(3)
		end
		attempt_count = attempt_count + 1
	until success or attempt_count == 5
	
end

function setSaveFileData(player,SaveFileToLoad)
	
	if SaveFileToLoad then
		UpdateUIWithSaveFileInfo_RemoteEvent:FireClient(player,currentSaveFile)
	end
				
end

local function deleteSaveFileData(player,SaveFileToDelete)
	-- technically this just resets the players data for that file, but meh
	
	-----
	local playerDataFolder = player.playerDataFolder
	--- Safe File 1 Folder:
	local saveFile1_TableFolder = playerDataFolder.saveFile1_TableFolder

	local SaveFile1_collectiblesCollectedTableFolder = saveFile1_TableFolder.collectiblesCollectedTableFolder
	local SaveFile1_worldBasedGoldenToastCollectedFolder = SaveFile1_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local SaveFile1_totalCoinsCollected_NumberValue = SaveFile1_collectiblesCollectedTableFolder.totalCoinsCollected
	local SaveFile1_totalGoldenToastCollected_NumberValue = SaveFile1_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local SaveFile1_fileSpecificPlayTimeStat_NumberValue = saveFile1_TableFolder.fileSpecificPlayTimeStat
	local SaveFile1_hasGameBeenStarted_NumberValue = saveFile1_TableFolder.hasGameBeenStarted
	local SaveFile1_nameOfSaveFile = saveFile1_TableFolder.saveFileName_StringValue

	--- Safe File 2 Folder:
	local saveFile2_TableFolder = playerDataFolder.saveFile2_TableFolder
	local SaveFile2_collectiblesCollectedTableFolder = saveFile2_TableFolder.collectiblesCollectedTableFolder
	local SaveFile2_worldBasedGoldenToastCollectedFolder = SaveFile2_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local SaveFile2_totalCoinsCollected_NumberValue = SaveFile2_collectiblesCollectedTableFolder.totalCoinsCollected
	local SaveFile2_totalGoldenToastCollected_NumberValue = SaveFile2_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local SaveFile2_fileSpecificPlayTimeStat_NumberValue = saveFile2_TableFolder.fileSpecificPlayTimeStat
	local SaveFile2_hasGameBeenStarted_NumberValue = saveFile2_TableFolder.hasGameBeenStarted
	local SaveFile2_nameOfSaveFile = saveFile2_TableFolder.saveFileName_StringValue


	--- Safe File 3 Folder:
	local saveFile3_TableFolder = playerDataFolder.saveFile3_TableFolder
	local SaveFile3_collectiblesCollectedTableFolder = saveFile3_TableFolder.collectiblesCollectedTableFolder
	local SaveFile3_worldBasedGoldenToastCollectedFolder = SaveFile3_collectiblesCollectedTableFolder.worldBasedGoldenToastCollectedFolder
	local SaveFile3_totalCoinsCollected_NumberValue = SaveFile3_collectiblesCollectedTableFolder.totalCoinsCollected
	local SaveFile3_totalGoldenToastCollected_NumberValue = SaveFile3_collectiblesCollectedTableFolder.totalGoldenToastCollected
	local SaveFile3_fileSpecificPlayTimeStat_NumberValue = saveFile3_TableFolder.fileSpecificPlayTimeStat
	local SaveFile3_hasGameBeenStarted_NumberValue = saveFile3_TableFolder.hasGameBeenStarted
	local SaveFile3_nameOfSaveFile = saveFile3_TableFolder.saveFileName_StringValue

	-----
	local successForDeletingData, errormessage = pcall(function() 	-- Load Data
		saveFile1_DataTable = get_saveFile1_DataTable_FromDataStore:GetAsync(player.UserId)
		saveFile2_DataTable = get_saveFile2_DataTable_FromDataStore:GetAsync(player.UserId)
		saveFile3_DataTable = get_saveFile3_DataTable_FromDataStore:GetAsync(player.UserId)
	end)

	if successForDeletingData == true then

		-- set the UI for total coins collected & total golden toast collected 
		-- make the timer for the save-file-specific playtime count

		if saveFile1_DataTable and SaveFileToDelete == "SaveFile1" then			
			SaveFile1_totalCoinsCollected_NumberValue.Value = 0
			SaveFile1_totalGoldenToastCollected_NumberValue.Value = 0

			SaveFile1_fileSpecificPlayTimeStat_NumberValue.Value = 0 
			SaveFile1_hasGameBeenStarted_NumberValue.Value = false
			
			SaveFile1_nameOfSaveFile.Value = "Save File 1"
			
			--print("Save File 1 data for "..player.Name.." has been deleted.")

		end

		if saveFile2_DataTable and SaveFileToDelete == "SaveFile2" then						
			SaveFile2_totalCoinsCollected_NumberValue.Value = 0
			SaveFile2_totalGoldenToastCollected_NumberValue.Value = 0

			SaveFile2_fileSpecificPlayTimeStat_NumberValue.Value = 0 
			SaveFile2_hasGameBeenStarted_NumberValue.Value = false
			
			SaveFile2_nameOfSaveFile.Value = "Save File 2"

			--print("Save File 2 data for "..player.Name.." has been deleted.")

		end

		if saveFile3_DataTable and SaveFileToDelete == "SaveFile3" then						
			SaveFile3_totalCoinsCollected_NumberValue.Value = 0
			SaveFile3_totalGoldenToastCollected_NumberValue.Value = 0
			
			SaveFile3_fileSpecificPlayTimeStat_NumberValue.Value = 0
			SaveFile3_hasGameBeenStarted_NumberValue.Value = false
			
			SaveFile3_nameOfSaveFile.Value = "Save File 3"

			--print("Save File 3 data for "..player.Name.." has been deleted.")

		end
		
		-- save data to set changes in effect :)
		attemptToSaveGame(player)
		

	end
	
	
end
-----

game.Players.PlayerAdded:Connect(function(player)
	loadSaveData(player)
end)

game.Players.PlayerRemoving:Connect(function(player)
	attemptToSaveGame(player)
end)

game.Workspace.RemoteEventsFolder["Data System"].SaveGameData.OnServerEvent:Connect(function(player)
	print("Manual Save All Game Data!")
	attemptToSaveGame(player)
end)

game:BindToClose(function()
	if game:GetService("RunService"):IsStudio() then
		return
	end
	
	for i, player in pairs(game.Players:GetPlayers()) do
		task.spawn(function()
			attemptToSaveGame(player)
		end)
	end
end)
-----

local LoadSaveFileData_RemoteEvent = game.Workspace.RemoteEventsFolder["Data System"].LoadSaveFileData
LoadSaveFileData_RemoteEvent.OnServerEvent:Connect(function(player,SaveFileToLoad)
	currentSaveFile = SaveFileToLoad
	setSaveFileData(player,SaveFileToLoad)
end)

local DeleteSaveFileDataRequest_RemoveEvent = game.Workspace.RemoteEventsFolder["Data System"].DeleteSaveFileDataRequest
DeleteSaveFileDataRequest_RemoveEvent.OnServerEvent:Connect(function(player,SaveFileToDelete)
	deleteSaveFileData(player,SaveFileToDelete)
end)

UpdateUIWithSaveFileInfo_RemoteEvent.OnServerEvent:Connect(function(player)
	UpdateUIWithSaveFileInfo_RemoteEvent:FireClient(player)
end)
-----

local getGameData_RemoteEvent = game.Workspace.RemoteEventsFolder["Data System"].GetGameData
getGameData_RemoteEvent.OnServerEvent:Connect(function(player,dataToGet)
	if dataToGet == "TotalCoinsCollectedData" then
		
		if currentSaveFile == "SaveFile1" then
			local dataToSend = player.playerDataFolder.saveFile1_TableFolder.collectiblesCollectedTableFolder.totalCoinsCollected.Value
			getGameData_RemoteEvent:FireAllClients(dataToGet,dataToSend)
		elseif currentSaveFile == "SaveFile2" then
			local dataToSend = player.playerDataFolder.saveFile2_TableFolder.collectiblesCollectedTableFolder.totalCoinsCollected.Value
			getGameData_RemoteEvent:FireAllClients(dataToGet,dataToSend)
		elseif currentSaveFile == "SaveFile3" then
			local dataToSend = player.playerDataFolder.saveFile3_TableFolder.collectiblesCollectedTableFolder.totalCoinsCollected.Value
			getGameData_RemoteEvent:FireAllClients(dataToGet,dataToSend)
			
		else
			--warn("Save file not selected yet.")
		end
		
	elseif dataToGet == "TotalGoldenToastCollectedData" then
		
		if currentSaveFile == "SaveFile1" then
			local dataToSend = player.playerDataFolder.saveFile1_TableFolder.collectiblesCollectedTableFolder.totalGoldenToastCollected.Value
			getGameData_RemoteEvent:FireAllClients(dataToGet,dataToSend)
		elseif currentSaveFile == "SaveFile2" then
			local dataToSend = player.playerDataFolder.saveFile2_TableFolder.collectiblesCollectedTableFolder.totalGoldenToastCollected.Value
			getGameData_RemoteEvent:FireAllClients(dataToGet,dataToSend)
		elseif currentSaveFile == "SaveFile3" then
			local dataToSend = player.playerDataFolder.saveFile3_TableFolder.collectiblesCollectedTableFolder.totalGoldenToastCollected.Value
			getGameData_RemoteEvent:FireAllClients(dataToGet,dataToSend)
		else
			--warn("Save file not selected yet.")	
		end
		
	end
	
		
	
end)
-----


-----
local playerPickedUpACollectableRemoteEvent = game.Workspace.RemoteEventsFolder.PlayerPickedUpCollectable
playerPickedUpACollectableRemoteEvent.OnServerEvent:Connect(function(player,typeOfCollectable)

	if typeOfCollectable == "coin" then
		if currentSaveFile == "SaveFile1" then
			game.Players:WaitForChild(player.Name).playerDataFolder.saveFile1_TableFolder.collectiblesCollectedTableFolder.totalCoinsCollected.Value += 1
		elseif currentSaveFile == "SaveFile2" then
			game.Players:WaitForChild(player.Name).playerDataFolder.saveFile2_TableFolder.collectiblesCollectedTableFolder.totalCoinsCollected.Value += 1
		elseif currentSaveFile == "SaveFile3" then
			game.Players:WaitForChild(player.Name).playerDataFolder.saveFile3_TableFolder.collectiblesCollectedTableFolder.totalCoinsCollected.Value += 1
		end

	elseif typeOfCollectable == "GoldenToast" then
		if currentSaveFile == "SaveFile1" then
			game.Players:WaitForChild(player.Name).playerDataFolder.saveFile1_TableFolder.collectiblesCollectedTableFolder.totalGoldenToastCollected.Value += 1
		elseif currentSaveFile == "SaveFile2" then
			game.Players:WaitForChild(player.Name).playerDataFolder.saveFile2_TableFolder.collectiblesCollectedTableFolder.totalGoldenToastCollected.Value += 1
		elseif currentSaveFile == "SaveFile3" then
			game.Players:WaitForChild(player.Name).playerDataFolder.saveFile3_TableFolder.collectiblesCollectedTableFolder.totalGoldenToastCollected.Value += 1
		end
	end

end)

---



The game is single-player, so if anyone uses the code to hack my game they’d only be ruining their own play experience. I’d recommend copying the code and putting it into Roblox Studio or an IDE rather than reading it here. Reading it with just the markdown features isn’t the best experience.

If the player has no data, it will return you a nil. You can basically check if it is nil or not. Also another note: it is a warning not an error.

1 Like

After looking through the logs again, I found that the issue was caused by my LoggingManager for some reason. I did script the datastore correctly!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.