Tool Saving Position not working

Im trying to make a script that will save the position of players tools in their hot bar for selecting tools. but i am encountering issues here are my scripts:

Localscript in StarterPlayerScripts:


local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players           = game:GetService("Players")
local mouse             = Players.LocalPlayer:GetMouse()

local player    = Players.LocalPlayer
local fetchFunc = ReplicatedStorage:WaitForChild("FetchPlayerData")
local placeEvent= ReplicatedStorage:WaitForChild("PlaceToolEvent")
local ServerStorage = game:GetService("ServerStorage")
local toolsFolder   = ServerStorage:WaitForChild("Tools")

-- Ghost‑placement setup
local function setupTool(tool)
	if not tool:IsA("Tool") or not tool:FindFirstChild("Handle") then return end

	local ghost, placing
	tool.Equipped:Connect(function()
		placing = true
		ghost = tool:Clone()
		for _, p in ipairs(ghost:GetDescendants()) do
			if p:IsA("BasePart") then
				p.Transparency = 0.5
				p.CanCollide = false
			end
		end
		ghost.Parent = workspace
		-- follow mouse:
		local conn
		conn = mouse.Move:Connect(function()
			if placing and ghost.PrimaryPart then
				ghost.PrimaryPart.CFrame = CFrame.new(mouse.Hit.p)
			else
				conn:Disconnect()
			end
		end)
	end)

	tool.Activated:Connect(function()
		if placing then
			placing = false
			if ghost then ghost:Destroy() end
			local cf = tool.Handle.CFrame
			local comps = { cf:GetComponents() } -- 12‑number array
			placeEvent:FireServer(tool.Name, comps)
			tool:Destroy()
		end
	end)

	tool.Unequipped:Connect(function()
		placing = false
		if ghost then ghost:Destroy() end
	end)
end

-- Watch for any new tools in Backpack or Character
player.Backpack.ChildAdded:Connect(setupTool)
player.CharacterAdded:Connect(function(char)
	char.ChildAdded:Connect(setupTool)
end)

-- On join, fetch saved counts & placements
local counts, placements = fetchFunc:InvokeServer()

-- 1) Clear existing “known” tools in Backpack+Character
for _, t in ipairs(player.Backpack:GetChildren()) do
	if t:IsA("Tool") and toolsFolder:FindFirstChild(t.Name) then
		t:Destroy()
	end
end
local char = player.Character or player.CharacterAdded:Wait()
for _, t in ipairs(char:GetChildren()) do
	if t:IsA("Tool") and toolsFolder:FindFirstChild(t.Name) then
		t:Destroy()
	end
end

-- 2) Spawn the autosaved counts into the Backpack
for toolName, count in pairs(counts) do
	local tpl = toolsFolder:FindFirstChild(toolName)
	if tpl then
		for i = 1, count do
			tpl:Clone().Parent = player.Backpack
		end
	end
end

-- 3) Spawn the world‑placed tools at their saved CFrames
for _, entry in ipairs(placements) do
	local tpl = toolsFolder:FindFirstChild(entry.toolName)
	if tpl and tpl.PrimaryPart then
		local m = tpl:Clone()
		m:SetPrimaryPartCFrame(CFrame.new(unpack(entry.cf)))
		m.Parent = workspace
	end
end
-- StarterPlayerScripts/ToolPersistenceClient.lua

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players           = game:GetService("Players")
local mouse             = Players.LocalPlayer:GetMouse()

local player    = Players.LocalPlayer
local fetchFunc = ReplicatedStorage:WaitForChild("FetchPlayerData")
local placeEvent= ReplicatedStorage:WaitForChild("PlaceToolEvent")
local ServerStorage = game:GetService("ServerStorage")
local toolsFolder   = ServerStorage:WaitForChild("Tools")

-- Ghost‑placement setup
local function setupTool(tool)
	if not tool:IsA("Tool") or not tool:FindFirstChild("Handle") then return end

	local ghost, placing
	tool.Equipped:Connect(function()
		placing = true
		ghost = tool:Clone()
		for _, p in ipairs(ghost:GetDescendants()) do
			if p:IsA("BasePart") then
				p.Transparency = 0.5
				p.CanCollide = false
			end
		end
		ghost.Parent = workspace
		-- follow mouse:
		local conn
		conn = mouse.Move:Connect(function()
			if placing and ghost.PrimaryPart then
				ghost.PrimaryPart.CFrame = CFrame.new(mouse.Hit.p)
			else
				conn:Disconnect()
			end
		end)
	end)

	tool.Activated:Connect(function()
		if placing then
			placing = false
			if ghost then ghost:Destroy() end
			local cf = tool.Handle.CFrame
			local comps = { cf:GetComponents() } -- 12‑number array
			placeEvent:FireServer(tool.Name, comps)
			tool:Destroy()
		end
	end)

	tool.Unequipped:Connect(function()
		placing = false
		if ghost then ghost:Destroy() end
	end)
end

-- Watch for any new tools in Backpack or Character
player.Backpack.ChildAdded:Connect(setupTool)
player.CharacterAdded:Connect(function(char)
	char.ChildAdded:Connect(setupTool)
end)

-- On join, fetch saved counts & placements
local counts, placements = fetchFunc:InvokeServer()

-- 1) Clear existing “known” tools in Backpack+Character
for _, t in ipairs(player.Backpack:GetChildren()) do
	if t:IsA("Tool") and toolsFolder:FindFirstChild(t.Name) then
		t:Destroy()
	end
end
local char = player.Character or player.CharacterAdded:Wait()
for _, t in ipairs(char:GetChildren()) do
	if t:IsA("Tool") and toolsFolder:FindFirstChild(t.Name) then
		t:Destroy()
	end
end

-- 2) Spawn the autosaved counts into the Backpack
for toolName, count in pairs(counts) do
	local tpl = toolsFolder:FindFirstChild(toolName)
	if tpl then
		for i = 1, count do
			tpl:Clone().Parent = player.Backpack
		end
	end
end

-- 3) Spawn the world‑placed tools at their saved CFrames
for _, entry in ipairs(placements) do
	local tpl = toolsFolder:FindFirstChild(entry.toolName)
	if tpl and tpl.PrimaryPart then
		local m = tpl:Clone()
		m:SetPrimaryPartCFrame(CFrame.new(unpack(entry.cf)))
		m.Parent = workspace
	end
end

ServerScriptService:

local Players          = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local RS               = game:GetService("ReplicatedStorage")

-- Remotes (all RemoteEvents)
local SaveHotbarEvent    = RS:WaitForChild("SaveHotbarEvent")    -- client→server
local RequestHotbarEvent = RS:WaitForChild("RequestHotbarEvent") -- client→server
local HotbarOrderEvent   = RS:WaitForChild("HotbarOrderEvent")   -- server→client

local store = DataStoreService:GetDataStore("PlayerHotbarOrder")
local cache = {}  -- [ userId ] = { [slot]=toolName, … }

-- Load cache on join
Players.PlayerAdded:Connect(function(plr)
	local ok, data = pcall(function()
		return store:GetAsync(tostring(plr.UserId))
	end)
	cache[plr.UserId] = (ok and type(data)=="table") and data or {}
end)

-- Save cache on leave
Players.PlayerRemoving:Connect(function(plr)
	pcall(function()
		store:SetAsync(tostring(plr.UserId), cache[plr.UserId])
	end)
	cache[plr.UserId] = nil
end)

-- Client tells us “slot X = toolName”
SaveHotbarEvent.OnServerEvent = function(plr, slotIndex, toolName)
	if type(slotIndex)=="number" and type(toolName)=="string" then
		cache[plr.UserId][slotIndex] = toolName
	end
end

-- Client requests their saved hotbar
RequestHotbarEvent.OnServerEvent = function(plr)
	-- send them their table (or {} if none)
	HotbarOrderEvent:FireClient(plr, cache[plr.UserId] or {})
end

can you show me what the output says

and also why did you do this :sob:

1 Like

image

This folder exists.
image

OnServerEvent is an event, not a callback

so to fix your script you need to do

RequestHotbarEvent.OnServerEvent:Connect(function(plr)
	-- send them their table (or {} if none)
	HotbarOrderEvent:FireClient(plr, cache[plr.UserId] or {})
end)
1 Like

I tried this it certainly got rid of the error but it still doesnt save

i didnt fully read the script earlier, sorry lol

LocalScripts cannot access ServerStorage, youll have to find a different way to add the tools to the player

1 Like

No worries, sorry for my late reply i will try this out soon if it works ill give you the solution

I tried this and it still didnt work, the output doesnt do much neither I even ultered the code more and still nothing.

well whats the new code, and what is the output saying now

1 Like

Sorry ive been busy, i changed the ServerScript to

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

-- Ensure RemoteEvents exist
local function getEvent(name)
    local ev = ReplicatedStorage:FindFirstChild(name)
    if not ev then
        ev = Instance.new("RemoteEvent")
        ev.Name = name
        ev.Parent = ReplicatedStorage
    end
    return ev
end

local SaveHotbarEvent    = getEvent("SaveHotbarEvent")
local RequestHotbarEvent = getEvent("RequestHotbarEvent")
local HotbarOrderEvent   = getEvent("HotbarOrderEvent")

-- Two template folders in ServerStorage
local tieredSwords = ServerStorage:WaitForChild("TieredSwords")
local toolsFolder  = ServerStorage:WaitForChild("Tools")

-- DataStore + cache
local store = DataStoreService:GetDataStore("PlayerHotbarOrder")
local cache = {}  -- [userId] = { [slot]=toolName }

-- Load on join
Players.PlayerAdded:Connect(function(p)
    local ok, data = pcall(store.GetAsync, store, tostring(p.UserId))
    cache[p.UserId] = (ok and type(data) == "table") and data or {}
end)

-- Save on change
SaveHotbarEvent.OnServerEvent:Connect(function(p, slot, name)
    if typeof(slot)=="number" and typeof(name)=="string" then
        cache[p.UserId][slot] = name
        pcall(store.SetAsync, store, tostring(p.UserId), cache[p.UserId])
    end
end)

-- On client request, clone missing tools and send layout
RequestHotbarEvent.OnServerEvent:Connect(function(p)
    local saved    = cache[p.UserId] or {}
    local backpack = p:WaitForChild("Backpack")
    local char     = p.Character or p.CharacterAdded:Wait()

    -- Clone only **missing** tools (never destroy)
    for slot = 1, 10 do
        local name = saved[slot]
        if typeof(name)=="string" and name ~= "" then
            local have = backpack:FindFirstChild(name) or char:FindFirstChild(name)
            if not have then
                local tpl = tieredSwords:FindFirstChild(name)
                         or toolsFolder:FindFirstChild(name)
                if tpl and tpl:IsA("Tool") then
                    tpl:Clone().Parent = backpack
                end
            end
        end
    end

    -- Send the saved order back
    HotbarOrderEvent:FireClient(p, saved)
end)

and the StarterPlayer code as

local RS  = game:GetService("ReplicatedStorage")
local PS  = game:GetService("Players")
local UIS = game:GetService("UserInputService")

local player             = PS.LocalPlayer
local SaveHotbarEvent    = RS:WaitForChild("SaveHotbarEvent")
local RequestHotbarEvent = RS:WaitForChild("RequestHotbarEvent")
local HotbarOrderEvent   = RS:WaitForChild("HotbarOrderEvent")

-- Map number‑keys 1–0 to slots 1–10
local keyToSlot = {
    [Enum.KeyCode.One ] = 1, [Enum.KeyCode.Two   ] = 2,
    [Enum.KeyCode.Three] = 3, [Enum.KeyCode.Four   ] = 4,
    [Enum.KeyCode.Five ] = 5, [Enum.KeyCode.Six    ] = 6,
    [Enum.KeyCode.Seven]= 7, [Enum.KeyCode.Eight  ] = 8,
    [Enum.KeyCode.Nine ] = 9, [Enum.KeyCode.Zero   ] = 10,
}

-- 1) Notify server on keypress
UIS.InputBegan:Connect(function(input, processed)
    if processed then return end
    local slot = keyToSlot[input.KeyCode]
    if slot then
        local tool = player.Character and player.Character:FindFirstChildWhichIsA("Tool")
        if tool then
            SaveHotbarEvent:FireServer(slot, tool.Name)
        end
    end
end)

-- 2) Reorder Backpack when server sends us the saved layout
HotbarOrderEvent.OnClientEvent:Connect(function(saved)
    local backpack = player:WaitForChild("Backpack")
    local char     = player.Character or player.CharacterAdded:Wait()
    local equipped = char:FindFirstChildWhichIsA("Tool")

    -- Temporarily unequip so it can be reordered
    if equipped then
        equipped.Parent = backpack
    end

    -- Reverse-order re-parenting (10→1)
    for slot = 10, 1, -1 do
        local name = saved[slot]
        if typeof(name)=="string" and name ~= "" then
            local t = backpack:FindFirstChild(name)
            if t then
                t.Parent = backpack
            end
        end
    end

    -- Put the previously equipped tool back on the character
    if equipped and backpack:FindFirstChild(equipped.Name) then
        equipped.Parent = char
    end
end)

-- 3) Ask server for layout on spawn
player.CharacterAdded:Connect(function()
    task.delay(0.1, function()
        RequestHotbarEvent:FireServer()
    end)
end)
if player.Character then
    RequestHotbarEvent:FireServer()
end

yeah me too lol

what is the output saying when the code runs?

1 Like

Its been quiet on this matter, nothing new has begun