Currently this is broken because half of my level is simulated locally and half is server-side. Impulses from collisions across boundaries do not reliably propagate (if they do at all - it’s like the parts on the other side of the boundary are anchored)
My work around is to set NetworkOwner(nil) (server) on every part in my level recursively.
On mobile this causes parts to get out of sync between gfx and physics. I have floating parts in space that are not where they think they are (you can walk through them).
I haven’t seen the same behavior on desktop but I also haven’t really stress tested it.
Shoot ball at some of the stacks of blocks (the different tools at the bottom shoot differented sized balls)
You will maybe see phantom blocks as pictured
I tried it on my phone while sitting next to my wifi router and I didn’t notice the issue. When I played downstairs on my tablet I noticed it. Maybe if the packets are lost we never resend? It’s fairly reproducible.
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.
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?
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.
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:
Load level using InsertService into ServerStorage
Clone level
Anchor every part in level (that isn’t already anchored, making a list of them)
Parent level to workspace
Set ownership to Client
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.
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.
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