How to get all network owned parts and assemblies on the client

I needed a way to fetch all parts that are network-owned by the client, but Roblox doesn’t provide a built-in feature for this. To get around this, I created a script that sorts through the workspace to find and cache any owned parts dynamically. I’m sharing it here in case it helps others facing the same predicament.

Happy coding :partying_face:

--!strict

type TypeConnections = { [BasePart]: RBXScriptConnection? }
type TypeParts = { [BasePart]: boolean? }

local connections = {} :: TypeConnections
local parts = {} :: TypeParts

local UPDATE_RATE = 0.2

-- Determine which parts are owned by the client using ReceiveAge
-- https://create.roblox.com/docs/reference/engine/classes/BasePart#ReceiveAge
local function onUpdateLoop()
	for part in pairs(parts) do
		local value = part.ReceiveAge
		if value ~= 0 then parts[part] = nil continue end
		print("Owned by client", part.Name)
	end
end

-- Cache basepart and listen for physics changes
local function onDescendantAdded(descendant: Instance)
	local function onAnchoredChange(part: BasePart)
		if part.Anchored or part:IsGrounded() then
			parts[part] = nil
		else
			local add = part.AssemblyRootPart or part
			parts[add] = true
		end
	end
	
	if not descendant:IsA("BasePart") then return end
	connections[descendant] = descendant:GetPropertyChangedSignal("Anchored"):Connect(function()
		onAnchoredChange(descendant)
	end)
	onAnchoredChange(descendant)
end

-- Cleanup function that disconnects connections if any
local function onDescendantRemoving(descendant: Instance)
	if not descendant:IsA("BasePart") then return end
	parts[descendant] = nil
	
	local connection = connections[descendant]
	if connection then
		connection:Disconnect()
		connections[descendant] = nil
	end
end

-- Connections
workspace.DescendantAdded:Connect(onDescendantAdded)
workspace.DescendantRemoving:Connect(onDescendantRemoving)

-- Initialise
for _, descendant in ipairs(workspace:GetDescendants()) do
	onDescendantAdded(descendant)
end

task.spawn(function()
	while true do
		task.wait(UPDATE_RATE)
		onUpdateLoop()
	end
end)
9 Likes