SetNetworkOwner failing due to anchored parts, however none present

I’m trying to spawn an NPC right now. The workflow is fairly simple: one script copies an NPC into the Workspace and then that NPC starts its code. I’m having an absolutely mind-boggling issue right now though: SetNetworkOwner is failing.

The specific error tells me that SetNetworkOwner does not work with anchored parts. The thing is, I do not have any anchored parts whatsoever. I even printed the anchorship of every single BasePart descendant and each iteration returned false.

Save my soul, this small issue made my game stay down for 2 days.

The code involved in this is below, under a script called Mind. This runs almost instantaneously when placed in the Workspace, as is custom for any kind of script that’s transferred from ServerStorage. Everything else has been removed as it is not relevant to include.

local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local Head = Character:WaitForChild("Head")

function networkOwnership()
	for _, part in pairs(Character:GetDescendants()) do
		if part:IsA("BasePart") then
			print(part.Anchored) -- Debug condition
            -- Even using part.Anchored = false does not fix
			part:SetNetworkOwner(nil)
		end
	end
end

function init()
	networkOwnership()

    -- Truncated here
end

init()

To be clear: I’m not looking for anti-pattern alternatives, such as using waits before running anything.

6 Likes

This seems a lot like a bug. Can you make a repro place?

Just to make sure, no parts are welded to anything that is anchored? The same error will be thrown if this is the case.

@ElliottLMz I don’t know how accurate a repro would be but I could try. I’m still investigating the issue myself to see whether I’m just overlooking an implementation detail and Studio’s not cooperating (separate issue - the place is massive and it keeps freezing).

@General_Scripter It’s been made very explicitly clear that anchored parts do not exist in my assembly, both in the thread’s title and all over the OP. Code sample also had a test to force anchorship off and that did not fix the issue.

Honestly, what a strange problem.

I made use of BasePart.CanSetNetworkOwnership to help me isolate the problem and I got down to my accessories. The handles of my accessories aren’t anchored but they are welded. The weld shouldn’t make a difference: the parts themselves aren’t anchored.

Later I find out that for whatever blasted reason, the handles of accessories can’t have their network ownership set until later. Instantly printing the results of CanSetNetworkOwnership on accessory handles returns false but waiting a while and doing so gives me true.

Not sure why my character rig implicitly has network ownership setting enabled but my accessory handles don’t.

1 Like

I just tested this in my own place and I’m not having any issues. Mind attaching the place file?

It’s possible that when you’re attempting to set their network ownership the mechanism ‘network’ (as in graph) they’re part of hasn’t yet been resolved(?); either that or some part of the mechanism is anchored and is causing funky behavior.

Try calling GetRootPart on the accessory handles and see what it returns when CanSetNetworkOwnership is false.

Only other thing I can think of that’d cause this would be some incongruity between the server’s understanding of the mechanism’s structure and the client’s.

@thatsaniceROOT Like I’ve dropped everywhere, there are no anchored parts in the assembly. I’ve even attempted to force unanchor and that does not resolve the problem. I’ve included a disgusting workaround for now to mitigate the problem.

-- Tuple length forced to one
while not part:CanSetNetworkOwnership() do
    -- Hate this already
    wait()
end

That being said, I’ve attempted to apply your suggestion through a detailed print analysis during each iteration to attempt to diagnose the problem.

local function printEligiblity(part)
	local root = part:GetRootPart()
	
	print(
		"Instance:", part,
		"\nFullName:", part:GetFullName(),
		"\nAnchored:", part.Anchored,
		"\nRoot:", root, "anc", root and root.Anchored
	)
	
	-- separate lines due to supposed attempts to call boolean value
	-- when placed in the above analysis
	print("root canset:", root and root:CanSetNetworkOwnership() or "no root")
	print("part canset:", part:CanSetNetworkOwnership())
end

This is the resulting output:

So you can see how I think it makes absolutely no sense. There’s no root and there’s no indication of anchorship either. Despite that, it chooses to say no. I think this may be the issue, but I’m confused all the same. My accessory doesn’t have the HumanoidRootPart as a root.

The client shouldn’t bear any relevance here because the initial pipeline lives only on the server, from the NPC being spawned in to the NPC’s logic starting up. At this point early in, the server has no need to understand the client’s perspective and vice versa.


@Tom_atoes I do mind attaching the place file. I however have a repro that I’ve set up and some earlier investigations. There’s nothing different except the removal of meshes and code, so I don’t know what else to think about this situation.

SimilarlySetupRig.rbxl (34.1 KB)

Move the rig to ServerStorage, start a server and then move it to the workspace from the server-side.

So it appears this is indeed an issue of the joints not being ‘active’ by the time the script runs

local function printEligiblity(part)
	local root,can = part:GetRootPart()
	print(part.AccessoryWeld.Active) --> this prints true if the 'rig' is in the workspace before simulation; prints false if it's parented to the workspace from some other container.
	if root then
		can = pcall(root.CanSetNetworkOwnership, root)
	end
	print("root canset:", root and can or "no root")
end

I think the easiest fix would be to handle the setting of the accoutrement’s network ownership asynchronously: you set its handle’s net/ownership only after the joint has become active.

CC @ContextLost


Or perhaps you can set the ownership of just the humanoidrootpart since all other parts of the mechanism should inherit the ownership? Then, when the welds become part of the mechanism I presume they’ll also inherit the same networkownership; not entirely sure on this, though.

The weld shouldn’t have any bearing on the functionality of this code considering all parts are unanchored: the only thing that’s actually changing is how the part is involved with physics. That’s unless by right of the weld, the accessory handle becomes part of the character mechanism.

That being said, I wrote a small test on your theory regarding root parts. I definitely know that root parts make ownership behave differently but I wasn’t sure how.

local thing = workspace["???"]

print(thing.Head:GetNetworkOwner())
print(thing.Staff.Handle:GetNetworkOwner())
print(thing.HumanoidRootPart:GetNetworkOwner())

thing.HumanoidRootPart:SetNetworkOwner(nil)

print(thing.Head:GetNetworkOwner())
print(thing.Staff.Handle:GetNetworkOwner())
print(thing.HumanoidRootPart:GetNetworkOwner())

First it printed my name (automatic ownership), but then nil. That means that the root’s ownership is carried over to the other parts. This is done in an instantaneous test so I don’t know what weight it carries otherwise: I’m going to try this out.

If the test is successful, I’ll mark this post as the solution solely because of the bottom half.

1 Like

So I had a look into mechanism roots and network ownership, like my former reply suggested. It seems that did the trick: I now only set the ownership of my HumanoidRootPart and the engine takes care of the rest. Still puzzled by the problem but I assume the function was running a step ahead of physics simulation wherein the parts weren’t being acknowledged as parts of the mechanism.

I don’t really understand what you meant by setting asynchronously or how that would mitigate the issue in the past, but I don’t assume I was using network ownership properly in the first place. So really the first half doesn’t matter too much anymore.