[URGENT]Some of my players Don't get tools Equipped on spawn

Hey so i finally published my game after so long and im currency running ads on it

GAME LINK

But my problem is that some people dont get tools equipped when joining the game, some people dont have this problem even they log in 100 times. i dont know where is comes from either people coming from ads or idk. those players always have to reset to get the tool quipped back.

defiantly its not mobile players only thing because i have players who logged in on mobile and have 0 problems getting tools equipped. please help this is very urgent.

im attaching my script here, with rest of the stuff too.i have to change it multiple times but still no luck. please help

--Ref
local Player = game.Players:GetPlayerFromCharacter(script.Parent)
local Humanoid:Humanoid = script.Parent:WaitForChild("Humanoid")
local ToolPackage = game.ReplicatedStorage.GamePlaySystem.Scripts.DefaultToolPackage
local NameDisplay = game.ReplicatedStorage.GamePlaySystem.Prefabs.NameDisplay:Clone()

--Modules
local ToolModule = require(game.ReplicatedStorage.GamePlaySystem.Modules.ToolInfo)
local StatsModule = require(game.ReplicatedStorage.StatsSystem.Modules.StatInfo)
local LevelingModule = require(game.ReplicatedStorage.LevelingSystem.Modules.LevelingInfo)
local PhysicalPetsModule = require(script.PhysicalPets)
local NameplateModule = require(game.ReplicatedStorage.GamePlaySystem.Modules.NamePlateInfo)

--Functions
local AddBadgesFunction = require(game.ReplicatedStorage.BadgesSystem.Functions:WaitForChild("AddBadgeValues"))

while not Player:GetAttribute("DoneLoading") do task.wait(1) end

Humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None

function UpdateName()
	NameDisplay.Parent = script.Parent:WaitForChild("Head")
	NameDisplay.UI.Display.Text = Player.DisplayName
end

function Blockey()
	local FoundHumanoid = script.Parent:FindFirstChildOfClass("Humanoid")
	if not FoundHumanoid then return end

	local OriginalDescription = game.Players:GetHumanoidDescriptionFromUserIdAsync(Player.UserId)

	OriginalDescription.BodyTypeScale = 1
	OriginalDescription.HeadScale = 1
	OriginalDescription.DepthScale = 1
	OriginalDescription.WidthScale = 1
	OriginalDescription.HeightScale = 1
	OriginalDescription.ProportionScale = 0
	OriginalDescription.HeightScale = 1.05

	FoundHumanoid:ApplyDescription(OriginalDescription)
end

function UpdateStats()
	local MaxStamina = StatsModule:GetStatValue(Player, "Stamina")
	Humanoid:SetAttribute("Stamina", MaxStamina)
end

local ToolVersion = 0
function UpdateTool()
	ToolVersion += 1
	local MyVersion = ToolVersion

	task.spawn(function()
		local CurrentTool = Player:GetAttribute("CurrentTool")

		while not CurrentTool do
			if MyVersion ~= ToolVersion then return end
			task.wait(0.2)
			CurrentTool = Player:GetAttribute("CurrentTool")
		end

		local ToolFolder = game.ReplicatedStorage.GamePlaySystem.Tools
		local ToolTemplate = ToolFolder:FindFirstChild(CurrentTool)

		while not ToolTemplate do
			if MyVersion ~= ToolVersion then return end
			task.wait(0.2)
			ToolTemplate = ToolFolder:FindFirstChild(CurrentTool)
		end

		if MyVersion ~= ToolVersion then return end

		if not script.Parent:IsDescendantOf(workspace) then
			script.Parent.AncestryChanged:Wait()
		end

		script.Parent:WaitForChild("HumanoidRootPart", 5)
		task.wait(0.1)

		for _, ExistingTool in script.Parent:GetChildren() do
			if ExistingTool:IsA("Tool") then
				ExistingTool:Destroy()
			end
		end

		local Tool = ToolTemplate:Clone()

		for _, Child in ToolPackage:GetChildren() do
			local NewChild = Child:Clone()
			NewChild.Parent = Tool
			if Child:IsA("Script") or Child:IsA("LocalScript") then
				NewChild.Enabled = true
			end
		end

		local Damage = Instance.new("IntValue")
		Damage.Name = "BaseDamage"
		Damage.Value = ToolModule.Info[CurrentTool].Damage
		Damage.Parent = Tool

		local Backpack = Player:WaitForChild("Backpack", 5)
		if Backpack then
			Tool.Parent = Backpack
		else
			Tool.Parent = script.Parent
		end

		if MyVersion ~= ToolVersion then
			Tool:Destroy()
			return
		end

		for I = 1, 15 do
			if Humanoid.Health <= 0 then break end
			if MyVersion ~= ToolVersion then
				Tool:Destroy()
				return
			end

			pcall(function()
				Humanoid:EquipTool(Tool)
			end)

			if Tool.Parent == script.Parent then
				break
			end

			task.wait(0.2)
		end
	end)
end

local OldLevel = LevelingModule:GetLevelInfoFromExp(Player:GetAttribute("CurrentExp") or 0).Level
function UpdateLevel()
	local CurrentExp = Player:GetAttribute("CurrentExp") or 0
	local Info = LevelingModule:GetLevelInfoFromExp(CurrentExp)
	NameDisplay.UI.LevelHolder.Level.Text = `Lv.{Info.Level}`

	local PlateInfo = NameplateModule:GetLevelInfo(Info.Level)
	local PlateColor:ColorSequence = PlateInfo.Color

	NameDisplay.UI.UIGradient.Color = PlateColor
	NameDisplay.UI.RankName.Text = PlateInfo.Name
	NameDisplay.UI.RankName.UIGradient.Color = PlateColor

	if not OldLevel or OldLevel < Info.Level then
		AddBadgesFunction(Player, "PLAYER_LEVELUP", 1)
		OldLevel = Info.Level
		print("Player Level Up!")
	end
end

pcall(function()
	Blockey()
end)

UpdateTool()
UpdateStats()
UpdateName()
UpdateLevel()

Player:GetAttributeChangedSignal("CurrentTool"):Connect(UpdateTool)
Player:GetAttributeChangedSignal("CurrentExp"):Connect(UpdateLevel)
PhysicalPetsModule.Init(Player)

Is the issue that they’re not getting the tools in their inventory at all?

im not sure 100% its been hard to talk with people since most of them dont have chat, no errors its silent

1 Like

i cannot replicate this at all

Is the tool given by another script or is it in StarterPack?

tool is given by the script i attached

just confirmed that its not in the player character nor backpack as well. happened to me just now

im guessing one of your many yielding tasks is the cause of it, you should remove the .AncestryChanged if statement, since im guessing the script is in StarterCharacterScripts and i am pretty sure that waits for the character to be in the workspace, if that errors then at least you’ll know that may be the cause, and also the while not ToolTemplate do loop, since it’s not like the tool template is going to appear on the server side, unless the tools are being unpacked into that folder for whatever reason. that’ll leave just those two other while loops, and since im guessing your stats visibly load, have you made sure the CurrentTool attribute isn’t empty when the player joins?

hey thanks for the response
i had this simple one before

function UpdateTool()
	local CurrentTool = Player:GetAttribute("CurrentTool")
	
	local Tool = game.ReplicatedStorage.GamePlaySystem.Tools:FindFirstChild(CurrentTool):Clone()
	
	for _,Child in ToolPackage:GetChildren() do
		local NewChild = Child:Clone()
		NewChild.Parent = Tool
		if Child:IsA("Script") or Child:IsA("LocalScript") then
			NewChild.Enabled = true
		end
	end
	
	local Damage = Instance.new("IntValue")
	Damage.Name ="BaseDamage"
	Damage.Value = ToolModule.Info[CurrentTool].Damage
	Damage.Parent = Tool
	
	Tool.Parent = script.Parent
	Humanoid:EquipTool(Tool)
end

still it happand.

CurrentTool attribute is there when

while not Player:GetAttribute("DoneLoading") do task.wait(1) end

is done

if this function isn’t working, then i doubt it’s being called

how is the DoneLoading attribute given?

think is that all other functions after is being called, for level, name etc.

DoneLoading is given by the player data manager which works perfectly. after loading all the data it sets that attribute to true

hey so from my experience this looks like a roblox bug, if your game has ModelStreamingBehavior set to Improved, EquipTool just silently fails and keeps the tool stuck in the backpack. happened to me before and there were no errors nothing which made it super hard to debug. try switching it to Default in your game settings and see if that fixes it. if you really need Improved streaming the workaround i used was parenting the tool to workspace first before calling EquipTool instead of putting it in the backpack

model streaming is set to default but i will try to parent to workspace first
thanks

i dont really know much from reading your script but heres my answer based on past experiences:

if your game handles and manages alot of things constantly theres like this issue called client and server desynchronization and it happens to alot of roblox games and that issue can cause many certain problems related to the gameplay, it means problems that occur from client and server desynchronization may vary on many games because the problems are usually related to the gameplay

this only happens when players joins :smiling_face_with_tear:

Do you have any other scripts that might cause this?

Definitely a timing issue. Some players join instantly due to good connection or local cached data, but some load for a longer time, therefore the code runs, but the player wasn’t loaded correctly just yet.

Your current implementation of “DoneLoading” needs patching.

Also disable StreamingEnabled if you don’t need it. Workspace > StreamingEnabled

the problem still presists.
im attaching the function that does the done loading part

function Load(Player)
	local PlayerUserID = "Player_"..Player.UserId
	local Data = DataStore:GetAsync(PlayerUserID)

	PlayerCurrentSaveData[Player] = DeepCopyTable(DefaultData)

	if Data then
		print("DataFound")
		for  Key,Value in pairs(Data) do
			PlayerCurrentSaveData[Player][Key] = Value
		end
		print(Player.Name .. " - Loading Done")
	else
		print("DataNotFound")
		Player:SetAttribute("FirstTime",true)

		if DevMode then
			for ItemName,Info in Spawnables.Info do
				if not PlayerCurrentSaveData[Player]["Inventory"][ItemName] then
					PlayerCurrentSaveData[Player]["Inventory"][ItemName] = DevMode and 99999 or 0
				end
			end
		end
	end

	PlayerCurrentSaveData[Player] = CheckStats(PlayerCurrentSaveData[Player])


	local LeaderstatsFolder = Instance.new("Folder",Player)
	LeaderstatsFolder.Name = "leaderstats"

	for Key,Value in pairs(PlayerCurrentSaveData[Player]) do
		if type(Value) ~= "table" then
			--DataDisplayEvent:FireClient(Player,Key,Value)
		end
		UpdateValues(Player,Key,Value)
	end
	pcall(function()
		ProcessQuests(Player)
		UpdateLoggins(Player)
		CheckDailyRewards(Player)
	end)

	while Player.Character == nil do
		wait(1)
		if not Player then 
			return
		end
	end
	Player:SetAttribute("DoneLoading",true)
	LoadDataEvent:FireClient(Player,PlayerCurrentSaveData[Player])
end

this works perfectly tho

It works perfectly because client side and server side aren’t the same. You should be waiting for the game and the player’s character to perfectly load on the client then tell the server that the player finished loading in.

The workflow should be as following:
Server loads data → Waits for client
Client loads in → Requests data from server
Server → Client

Your current workflow is like this:
Server loads data → Sends “Finished” to the client

Now this can branch into two:
Client wasn’t ready → drops data
Client was ready → accepts data

You do NOT send data until the client has finished loading in COMPLETELY. Sending a remote event when the client hasn’t even loaded in can lead to a dropped request.

Problem is that both

  • print(Updating Tool {Player.Name} {CurrentTool or "NO TOOL"})
  • print(Tool Equipped)

prints without errors

function UpdateTool()
	local CurrentTool = Player:GetAttribute("CurrentTool")
	print(`Updating Tool {Player.Name} {CurrentTool or "NO TOOL"}`)
	if not CurrentTool then return end

	local Tool = game.ReplicatedStorage.GamePlaySystem.Tools:FindFirstChild(CurrentTool):Clone()

	for _,Child in ToolPackage:GetChildren() do
		local NewChild = Child:Clone()
		NewChild.Parent = Tool
		if Child:IsA("Script") or Child:IsA("LocalScript") then
			NewChild.Enabled = true
		end
	end

	local Damage = Instance.new("IntValue")
	Damage.Name ="BaseDamage"
	Damage.Value = ToolModule.Info[CurrentTool].Damage
	Damage.Parent = Tool

	Tool.Parent = script.Parent
	Humanoid:EquipTool(Tool)
	print(`Tool Equipped`)
end