How do I wait for the datastore to load?

I am making my first game; a sword simulator, and am having a hard time waiting for everything to load in from the instances I make in the datastore script. Among others, I have a damage instance with the players base damage on it, and every weapon gets this instance every time it attacks. I also have a gamepass for double damage that also needs to be checked in the weapon’s scripts. This results in a lot of error codes when the data fails to load everything fast enough.

For now I have been using fx:

repeat task.wait()

until player. Damage.Value ~= nil

or just plain:

task.wait(5)

but I am worried that this slows the game significantly or just isn’t error proof.

Could it be an idea to create a damage value instance in each weapon and sync the value on that? That way the weapon wouldn’t have to get the damage from the player every time it reloads because the player dies.

– Update to show scripts:
Datastore

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local DatastoreService = game:GetService("DataStoreService")

local DataBase = DatastoreService:GetDataStore("data") -- all data that is saved (I changed the name because error in saved data)
local sessionData = {} -- data that is currently in the game (depending on the players present)



function playerAdded(player)
	-- finding humanoid from player
	while true do wait()
		if player.Character or player.CharacterAdded:Wait() then break end
	end
	local humanoid = player.Character:WaitForChild("Humanoid")
	
	-- creating empty instances under the added player
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	
	local Kills = Instance.new("IntValue", leaderstats) -- creating intvalue for amount of kills
	Kills.Name = "Kills"
	
	local Skulls = Instance.new("IntValue", player)
	Skulls.Name = "Skulls"
	
	
	-- Map wins
	local MountainWins = Instance.new("IntValue", player)
	MountainWins.Name = "MountainWins"
	
	local IslesWins = Instance.new("IntValue", player)
	IslesWins.Name = "IslesWins"
	
	local Wins = Instance.new("IntValue", leaderstats) -- doesn't need saving
	Wins.Name = "Wins"
	Wins.Value = MountainWins.Value + IslesWins.Value
	
	
	-- damage and health stats
	local Damage = Instance.new("NumberValue", player)
	Damage.Name = "Damage"
	
	local Health = Instance.new("IntValue", player)
	Health.Name = "Health"
	
	
	-- Weapons owned
	local LumberAxeOwned = Instance.new("BoolValue", player)
	LumberAxeOwned.Name = "LumberAxeOwned"
	
	local TheOarOwned = Instance.new("BoolValue", player)
	TheOarOwned.Name = "TheOarOwned"
	
	
	local success = nil
	local playerData = nil
	local attempt = 1
	
	repeat -- trying to get the data a couple of times
		success, playerData = pcall(function() -- making sure game gets the data
			return DataBase:GetAsync(player.UserId) -- getting any data with the right ID
		end)

		attempt += 1
		if not success then
			warn(playerData)
			task.wait(3)
		end
	until success or attempt == 5
	
	if success then
		if not playerData then -- checking if the playerdata is empty: this is a new player
			-- default playerdata
			playerData = {
				["kills"] = 0,
				["skulls"] = 0,
				
				["mountainwins"] = 0,
				["isleswins"] = 0,
				
				["damage"] = 5,
				["health"] = 100,
				
				["lumberaxeowned"] = false,
				["theoarowned"] = false,
			}
			
		end
		sessionData[player.UserId] = playerData -- if not new player, set saved data
	else
		warn("Unable to get data for", player.UserId)
		player:Kick("Unable to load data. Try again later") -- kick player if game doesn't find the players data
	end
	
	-- first connecting the empty instances with the data saved on datastoes
	-- afterwards, when the instances values changes midgame, the stores will save it
	Kills.Value = sessionData[player.UserId].kills
	Kills.Changed:Connect(function() -- if amount of kills change, sync values
		sessionData[player.UserId].kills = Kills.Value
	end)
	
	Skulls.Value = sessionData[player.UserId].skulls
	Skulls.Changed:Connect(function()
		sessionData[player.UserId].skulls = Skulls.Value
	end)
	
	MountainWins.Value = sessionData[player.UserId].mountainwins
	MountainWins.Changed:Connect(function()
		sessionData[player.UserId].mountainwins = MountainWins.Value
		Wins.Value = MountainWins.Value + IslesWins.Value
	end)
	
	IslesWins.Value = sessionData[player.UserId].isleswins
	IslesWins.Changed:Connect(function()
		sessionData[player.UserId].isleswins = IslesWins.Value
		Wins.Value = MountainWins.Value + IslesWins.Value
	end)
	
	Wins.Value = MountainWins.Value + IslesWins.Value -- update on change in above functions
	
	Damage.Value = sessionData[player.UserId].damage
	Damage.Changed:Connect(function()
		sessionData[player.UserId].damage = Damage.Value
	end)
	
	Health.Value = sessionData[player.UserId].health
	Health.Changed:Connect(function()
		sessionData[player.UserId].health = Health.Value
	end)
	
	LumberAxeOwned.Value = sessionData[player.UserId].lumberaxeowned
	LumberAxeOwned.Changed:Connect(function()
		sessionData[player.UserId].lumberaxeowned = LumberAxeOwned.Value
	end)
		
	TheOarOwned.Value = sessionData[player.UserId].theoarowned
	TheOarOwned.Changed:Connect(function()
		sessionData[player.UserId].theoarowned = TheOarOwned.Value
	end)
	
end

Players.PlayerAdded:Connect(playerAdded)



function playerLeaving(player)
	if sessionData[player.UserId] then -- checking if the player has any data saved, otherwise can lead to data loss
		local success = nil
		local errorMsg = nil
		local attempt = 1
		
		repeat -- trying to get the data a couple of times
		success, errorMsg = pcall(function() -- to make sure the game finds the data that is to be saved
				DataBase:SetAsync(player.UserId, sessionData[player.UserId]) -- if there is data to save, data will be saved to player
			end)
			
			attempt += 1
			if not success then
				warn(errorMsg)
				task.wait(3)
			end
		until success or attempt == 5
		
		if success then
			print("Data saved for", player.Name)
		else
			warn("Unable to save for", player.Name)
		end
	end
end
Players.PlayerRemoving:Connect(playerLeaving)



function serverShutDown() -- in case of a server shutdown
	if RunService:IsStudio() then
		return
	end
	print("server shutting down")
	for i, player in pairs(Players:GetPlayers()) do
		task.spawn(function()
			playerLeaving(player)
		end)
	end
end

game:BindToClose(serverShutDown)

Loading gear:


local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")


-- give items and remove skulls when buying in the gui
ReplicatedStorage.GiveWeapon.OnServerEvent:Connect(function(player, args)
	local Skulls = player:FindFirstChild("Skulls")
	local LumberAxeOwned = player:FindFirstChild("LumberAxeOwned")
	local TheOarOwned = player:FindFirstChild("TheOarOwned")
	
	if args == "BuyingAxe" then
		Skulls.Value -= 15
		LumberAxeOwned.Value = true
		
		local AxeCopy = ServerStorage.LumberAxe:Clone()
		AxeCopy.Parent = player.Backpack
	end
	
	if args == "BuyingOar" then
		Skulls.Value -= 15
		TheOarOwned.Value = true
		
		local OarCopy = ServerStorage.TheOAR:Clone()
		OarCopy.Parent = player.Backpack
	end
end)




Players.PlayerAdded:Connect(function(player) -- give players stuff they have already bought

		-- all about the gamepasses
		local DoubleDamageOwned = Instance.new("BoolValue", player)
	DoubleDamageOwned.Name = "DoubleDamageOwned"
	DoubleDamageOwned.Value = false
	
	local DoubleHealthOwned = Instance.new("BoolValue", player)
	DoubleHealthOwned.Name = "DoubleHealthOwned"
	DoubleHealthOwned.Value = false
	
	
		if MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690312761) then -- double damage
		DoubleDamageOwned.Value = true
	end
	
	if MarketplaceService:UserOwnsGamePassAsync(player.UserId, 694696047) then -- double health
		DoubleHealthOwned.Value = true
	end
	
	player.CharacterAdded:Connect(function()
		
	task.wait(3)
	-- all about the weapons
	-- connect to gui to fill inventory when the player already owns weapon
	-- copy to backpack for weapon now, copy to startergear for weapon after respawn or death
	
		if player:WaitForChild("LumberAxeOwned").Value == true then
			local LumberAxe = ServerStorage:FindFirstChild("LumberAxe"):Clone()
			LumberAxe.Parent = player.Backpack
		
			ReplicatedStorage.GiveWeapon:FireClient(player, "LumberAxe")
		end
	
		if player:WaitForChild("TheOarOwned").Value == true then
			local TheOar = ServerStorage:FindFirstChild("TheOAR"):Clone()
			TheOar.Parent = player.Backpack
		
			ReplicatedStorage.GiveWeapon:FireClient(player, "TheOar")
		end
		
	
		-- checks to see if new players own an object gamepass and gives them their item on entry
		task.wait(1)
		
		local OwnsSpeed = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690123446)
		if OwnsSpeed then -- returned true
			local SpeedCoil = game.ServerStorage:WaitForChild("SpeedCoil"):Clone()
			SpeedCoil.Parent = player.Backpack
		end -- no need for an else
		
		local OwnsGravity = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690360123)
		if OwnsGravity then
			local GravityCoil = game.ServerStorage:WaitForChild("GravityCoil"):Clone()
			GravityCoil.Parent = player.Backpack
		end

		local OwnsFusion = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690434007)
		if OwnsGravity then
			local FusionCoil = game.ServerStorage:WaitForChild("FusionCoil"):Clone()
			FusionCoil.Parent = player.Backpack
		end		
	end)
end)

SwordScript:

local tool = script.Parent

local Players = game:GetService("Players")
local player = tool.Parent.Parent -- owner of tool

local Debris = game:GetService("Debris")

local candmg = false

-- adding and removing creatortag
function TagHumanoid(humanoid, player)
	local Creator_Tag = Instance.new("ObjectValue")
	Creator_Tag.Name = "creator"
	Creator_Tag.Value = player
	Debris:AddItem(Creator_Tag, 2) -- removes tag after two seconds!
	Creator_Tag.Parent = humanoid
end

function UntagHumanoid(humanoid)
	for i, v in pairs(humanoid:GetChildren()) do
		if v:IsA("ObjectValue") and v.Name == "creator" then
			v:Destroy()
		end
	end
end

function determineDamage()
	repeat task.wait()
	until player.DoubleDamageOwned ~= nil
	local DoubleDamageOwned = player.DoubleDamageOwned

	if DoubleDamageOwned.Value == true then
		x = 2 else x = 1
	end

	return x
end

tool.Head.Touched:Connect(function(hit)
	
	if candmg then
		local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
		if humanoid then

			repeat task.wait()
			until player:FindFirstChild("Damage") ~= nil

			local Damage = player:FindFirstChild("Damage")

			determineDamage() -- returns with x and y
			humanoid:TakeDamage(Damage.Value * x)

			tool.Head.Hit:Play()
			candmg = false

			-- tagging hit player
			UntagHumanoid(humanoid)
			TagHumanoid(humanoid, player)
		end
	end
end)

tool.Client.Attack.OnServerEvent:Connect(function()
	if not candmg then
		candmg = true
		wait(.2)
		tool.Head.Woosh:Play()
		tool.Head.Woosh.Ended:Wait()
		candmg = false
	end
end)

I geniuenly don’t get the problem you’re having.
But as i understood you’re getting the damage from datastore and waiting until it loads into a value, and then putting that value in a weapon’s damage value, right?
Just to note - if you want to work with values faster store them in attributes instead of values

1 Like

what is the datastore loading?

if its an instance all you have to do is use :WaitForChild() to get it and it’ll wait until the datastore finishes.

1 Like

I start by putting instances onto the player, then I load values to put on the instances and sync the two every time the instance value changes. Whenever I need the instance values, I get them from the player. The issue that sometimes occur is that the script will error that :WaitForChild() is nil, as if the instance doesn’t even exist yet.

The issue is that I sometimes get error codes that say that my instances or values are nil; or that the values show the wrong things because the datastore hasn’t edited them before the game uses the instances.

I will look into attributes, I haven’t heard of them before :+1:

I went through the scripts and made sure to use WaitForChild() everywhere. I didn’t know that it works that way with instances: that seemed to fix my issue. Thanks for the replies!

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