Setting NetworkOwner(nil) on every part in my level causes sync issues on mobile

Sorry I had to upload over it because otherwise Studio won’t load the most recent assets for my game.

Protip: you can press home + lock button simultaneously to take a screenshot on any iOS device.

iOS devices suck.

Sure you can cap the image, but getting it to your main machine is a pain in the ass.

I don’t save my email credentials on my tablet.

imgur?

I turned on Diagnostics ShowOwners and SetNetworkOwner(player) is completely broken.

Even after calling it recursively on my level for a player that just joined, I am still seeing parts owned by the server.

I found a bug in my recursive call. It’s not recursive. :relaxed:

However, I fixed it and I am still seeing parts with no owner (how is this possible, they aren’t anchored?) when I set Owner to nil.

cc @zeuxcg

Ok. I figured it out. SetNetworkOwner is ignoring an edge case.

Here’es the deal:

If I set the network owner of a part that has no owner because it is currently welded (or snapped) to an anchored part (in this case the baseplate), and that part later becomes unwelded/unsnapped from that part, it does not remember that I have set the network owner. Instead it defaults to Auto. It is hard for me to trap this case in Lua land. Therefore I believe the engine needs to track this state for me.

Given this behavior I would further speculate that NetworkOwnership does not survive being welded/unwelded to a part with no owner.

2 Likes

http://wiki.roblox.com/index.php?title=Network_ownership#Anchored_Parts

NetworkOwnership is stable under the following conditions:

  • Welding two objects with the SAME Owner and MANUAL ownership.
  • Breaking up a single object that is set to a MANUAL network owner.
  • Anchoring a specific part on an assembly and then unanchoring it (making sure it’s not grounded)

NetworkOwnership reverts to Auto under the following conditions:

  • Welding two objects with different owners, or one is NOT set to Manual.
  • Anchoring the entire assembly.

Network Ownership does not survive being welded/unwelded to an anchored part, because it itself becomes “Grounded”.

Your post brought up a good point that these internal behaviors are not documented. I’m talking to Urist about getting that post fleshed out to include the internal behaviors for when you weld/anchor parts.

Quick off-topic to OP but related to network ownership question. If you create a part locally, does it automatically have its network ownership forced to the creating client? Or does it have some sort of other behavior?

Local Scripts create a part that is immediately assigned to the creator (but Automatic, meaning the server can override).

Server Scripts create a part that is Unassigned, and lets the server’s Automatic process assign an owner.

1 Like

In a FE game, does that ever happen though since as far as the server is aware, the part doesn’t exist (creation doesn’t replicate to server)?

FE Game the server doesn’t know about the part. So it should be owned by only the creator.

There was a weird clause that used to require a player character’s head to exist to assign the ownership to that player and start simulating. I saw that and went “Lolwut” and made it so that ALL parts created locally give ownership to the creator. Unfortunately I only enabled this like a month ago.

1 Like

So for my particular use case, I wanted to load a level server-side and then pass ownership of the entire level to the client.

Here is my algo:

  1. Load level using InsertService into ServerStorage
  2. Clone level
  3. Anchor every part in level (that isn’t already anchored, making a list of them)
  4. Parent level to workspace
  5. Set ownership to Client
  6. Unanchor parts in list

I have found that without steps 3 and 6 my level will replicate to the client before I have the opportunity to make sure that the entire thing is set to be owned by the client. This causes my level to fall apart at the boundaries of what the client is simulating and what the server is simulating.

What I needed was an “atomic” or “transactional” way to complete the entire operation of “clone this thing and set the owner to X”. I think this would probably be required for any large model/vehicle that you want to set the owner on. One possible nice way to do this would be to extend SetNetworkOwner to models so there is only one message that goes over the wire instead of the 100s I have to send.

In my case, I hacked around SetNetworkOwner by making my entire game local and turning on filtering to ensure that the server never simulates anything. The downside of this is that all my game code is in local scripts so it will be easy to steal. Still it might be the easier way to go - not having to wait for things to replicate has simplified my code in many places.

1 Like

Could you go into more detail as far as what you’re trying to do goes?
If the level isn’t going to fall apart immediately, shouldn’t you only change the network ownership to the player when you know that something is going to be physically simulated?

For instance, lets say you have an Explosion, and you know what player caused the explosion to happen. When Explosion.Hit is fired, you could check what part the explosion hit, and then set the network ownership to the player who is responsible for the explosion occurring.

I am trying to load a stack of blocks server-side and set the network owner to client without it falling over.

I am trying to do this in a reliable way for a large number of blocks.

Have you tried calling SetNetworkOwner after you Unanchor (Make sure there are no yields between the calls)? You cannot set ownership to Anchored parts.

Here is a script I have a BS model of parts.

local children = script.Parent:GetChildren()


while #game.Players:GetChildren()<1 do
	wait(.1)
end

local player = game.Players:GetChildren()[1]


for i,v in pairs(children) do
	if v:IsA("BasePart") then
		v.Anchored = false
		v:SetNetworkOwner(player)
	end
end

Yeah that is the first thing I tried.

I have to call SetNetworkOwner server-side (according to the docs).

So I either:

  1. Unachor locally
  2. Fire some remote function to set network owner to client

Or

  1. Unachor server side
  2. Set network owner to the client

In both cases, the change of network ownership happens after the parts have been unachored client-side. Typically this pile of unanchored parts has already started to be simulated before the networkowner change can replicate. If this simulation happens across dphysics regions my model falls apart because stacks of boxes don’t handle being simulated across regions well.

Maybe this is because physics hand-off wakes up the parts? I’m not sure.

I made a pyramid stack of boxes and I wasn’t able to reliably get it to be entirely client side simulated in a 1 player game.

What would work:

  1. Set networkowner to client
  2. Unanchor parts

But then anchored parts would have to remember that they have a network owner preferences. I assume we don’t do this now because anchored parts don’t have an instance of whatever the magic object is that makes them replicate physics updates over the network and network ownership is a property of that object?

If so we could use a hashset to keep track of these preferences similiar to what we do to hook up listeners for parts that haven’t sync across the network yet (i.e. keep a list of part references to look for and when we see them wire up the event later).

There is nothing preventing anchored objects from holding network ownership. NetworkOwnership is usually only stored on the Root of the replicated object (Assembly or Mechanism, depending on structure). When the root changes for some reason (breaking or adding joints) the new Root inherits the old system. There is no reason anchored parts can’t just keep their ownership setting internally, but the problem arises from there not being a clear mechanism to clean this up once it’s un-anchored in weird mechanisms/orders. Basically the reason NetworkOwnership resets to Auto when it does it to work as a sort of “garbage collection” mechanism. Otherwise you would have random parts in the world that have a hidden NetworkOwnership setting that becomes activated as soon as they become a root.

If you Unanchor on the server and then SetNetworkOwner, there shouldn’t be any simulation happening on the Server anymore. At this point it will be waiting for the client to take ownership, but it won’t run physics at it’s end, so there shouldn’t really be any cross-boundary behavior. Is your structure stable under any conditions outside of being asleep?

If you have such an unstable structure you can try welding all the parts to each other, setting the NetworkOwner to player and then breaking all the manual welds you created on the client.

Just out of curiosity… in a single player game, why are you mixing local and server-side parts?

1 Like

There are a bunch of API calls that only work server side

There are a bunch of API calls that only work client side

1 Like