A custom model with a few different parts welded/hinged together, and every part has the following physical properties
Density: 100
Friction: 0.2
Elasticity: 0
FrictionWeight: 1
ElasticityWeight: 1
The ball is given a velocity manually, and due to its high elasticity and elasticity weight, it bounces around without losing much velocity
The custom model is moved with a vector force.
If both the ball and the model have network ownership on the server, their collision behaves as you’d expect and the ball bounces off the model, having essentially zero effect on the model, while the ball increases in speed due to being hit by a very dense moving object. See this video for an example.
However, this model essentially replaces the player’s character in my game, and they control this model instead, so it’s better to have all of its parts owned by the player for quicker control feedback and more rigid-looking joints. (Some of the parts that are joined by a constraint other than a weld stutter and don’t travel smoothly with the rest of the model if the model’s parts are owned by the server)
But for some reason, I get some very odd collision behaviour when I set the network owner of the model’s parts to a player, shown in this video. Note: this only happens if the model is moving. If the model has no velocity, and only the ball is moving, the collision still behaves as expected.
I’m not sure scripting support is the right spot for this, but I wasn’t sure where else it should go, as I’m not even sure if this a bug or something I’m overlooking.
This seems to be expected, looks like the client has it’s pad pushed because the ball has multiple collisions with the pad while the server didn’t detect a collision (the pad is a bit behind on the server), the physics interaction between different owners doesn’t account for latency. I believe you could do a much more efficient replication if you extrapolate the ball’s trajectory on every client.
Could you explain a bit? Do you mean to have an instance of the ball created locally on every client? And if so, how would you keep them in sync with each other? With different latency on each client, couldn’t you end up with varying collisions?
I also tried making it so that the network owner of the ball changes to the player of the closest paddle within 20 studs, or to the server if its not within 20 studs of a paddle (and this does fix the collision behaviour), but there’s a noticeable hiccup/stutter in the ball when it changes network owner while moving.
Can you set the network ownership of the ball to the nearest player?
It may look odd to other players but may fix the collision issue whilst maintaining responsiveness.
As I said in my reply, I kind of tried that already and it doesn’t look super pretty.
Sidenote: when the ball is owned by a player, physics stuff like velocity can be manipulated with a localscript on the client side. Could that make things more vulnerable to exploiters/hackers?
This seems wrong. If the ball is a lower density part, you shouldn’t be displaced so far by it unless there is other logic that is adding velocity to it. Is there a repro level you can link that I can take a look at?
Latency will always be involved because objects across simulation boundaries will see the world at different timelines, so what I would expect is the ball to sometimes pass through the paddle. But the paddle shouldn’t be getting displaced.
The optimal solution for server-client model, would be for the server to calculate (own) the physics of the ball and so for client it should be considered just an effect, they should in no way interfere with the pad, for that you could:
Synchronizing client clocks (using clock sync modules or ntp) to after, move the ball according to a custom replication and physics, such as collisions based on raycasting, on every collision detected by the server (frame).
Prevent client from doing the collision with an outdated object, such as the ball, because it’s essentially just a snapshot of the server’s physics and so won’t respect the current position of the pad. Basically: ball.CanCollide = false on every client.
Make a local ball and replicate it on every frame (using hacks such as using ReceiveAge to detect frame updates), making it so that the local ball may collide, on the client, with the pad many times, but doesn’t push the pad.
To help remove any unnecessary variables, I stripped this demonstration of basically everything except the fundamentals needed easily reproduce this issue, and the same behaviour still occurs, so it definitely isn’t any additional scripts causing the issue, nor does it have anything to do with the particular setup of the paddle model.
It’s now just a ball with a BodyPosition allowing it to float, with its velocity set once by a script to start its motion, and a single block with a BodyPosition allowing it to float, a BodyGyro to keep it from rotating, and a VectorForce to apply velocity (the same result also happens if you set velocity manually for the paddle too). By default, both the ball and block are server-owned.
Here is a repro level.
Workspace contains the ball and block as described above, and a simple union to contain the ball and block.
ServerScriptService has 5 scripts:
MoveBall (Enabled) - sets a velocity for ball and automatically deletes itself
MoveBlock (Disabled) - enable this to begin moving the block without changing the network owner to the player
SetNetOwnerPlayer (Disabled) - enable this to set the network owner of the block to the player
SetNetOwnerPlayerAndMoveBlock (Disabled) - Enable this to simultaneously set the network owner of the block to the player and start moving the block.
ResetSimulation (Enabled) - contains a bool value inside of script named “Reset” - when checked, the simulation will reset to its original state.
To test/reproduce, start a server with 1 player in studio, then just enable the script from the server for the simulation you want to test. And it can be quickly reset with the BoolValue in ResetSimulation. Script #4 in the list above is where the strange collision comes into play.
Huh? why do you even have a player character? I set character auto loads to false. With no player characters then everything is defaulted to server ownership.
Okay. I figured out some of the problem. So what you are trying to do is supposed to be fairly reasonable. Basically you have a player-owned Block that is trying to push a bouncing Server-Owned ball. The ball has a tiny amount of density so it should not be affecting the block.
Problem is that when 2 objects cross-simulation boundaries interact, the object you don’t simulate is essentially infinitely massive. So in your repro case the ball is “infinitely massive” with respect to the Block on the player’s screen.
We actually have code in place to prevent this, so when the Block gets close to the ball it is supposed to locally start simulating the ball to prevent this infinitely massive issue. This should have solved your problem except that there is extra logic that makes it so that “property driven motion” isn’t allowed to be locally simulated because the timelines involved between property replication and physics replication will fight each other.
So, by applying a Body Position object you marked the ball as “cannot locally simulate”. If you try to keep the ball floating using a different object you will see much better results. Don’t use BodyPosition.
Here is a better version that has the Ball use BodyVelocity to float. There is apparently a bug with sleeping when using BodyVelocity somehow… Which is why one of my scripts Anchors and UnAnchors. Will investigate.
Yeah that’s my bad. When I originally ran into this issue within the context of my actual game that I’m developing, I saw more or less the same collision result from both the client and the server. So for my repro, I didn’t really care about watching both the client and the server, so I just set the player character auto spawn to false, which just has you stare at the origin (0, 0, 0) point if you don’t do anything else. But it may have been useful to see both the server and client’s perspective, even if I didn’t think the results looked much different.
Sounds like I managed to get really unlucky and hit an unfortunate combination to set myself up for a frustrating situation.
The ball needs to 100% stay at a certain height on the Y-Axis for my game. With enough force, could the ball not still move vertically even with a BodyVelocity with a very high MaxForce on the Y-Axis and velocity set to zero? I wouldn’t be surprised if some obscure situation such as two player paddles crashing into each other and sandwiching the ball in the middle could apply such a force. With a BodyPosition, if such an event were to occur, the ball would quickly travel back up/down to the proper height. It would be cool if roblox had something like Unity’s RigidBody constraints, which allows you to freeze movement or rotation on a particular axis.
If you set Max Force on Body Velocity to an insane amount I think it SHOULD work fine. Otherwise, you can tune the velocity in a script from time to time if it finds error to reach the goal.
I’ve request a documentation update to list BodyPosition and BodyGyro as objects that disqualify things from local-simulation.
Additionally I think I found a fix for the sleep bug I discovered with your repro level as well. The final thing I see is that velocities between the server-owned ball and remote block aren’t properly transferring during collision time.
So, I just discovered something very peculiar. Apparently not having a character somehow impacts this collision behaviour too, more than the BodyPosition does.
I tried changing the BodyPosition to a BodyVelocity in my game, but the results didn’t change at all. The paddle was still being displaced like crazy. Then I went back to my original version of my repro level, and swapped out the BodyPosition for a BodyVelocity, and yet again, still a crazy amount of displacement. I figured out that the main difference between your edited version of my repro level and the original version is that game.Players.CharacterAutoLoads = true on yours, and is false on mine (and my actual game).
If you use your version of my repro level and simply change CharacterAutoLoads to false, and the paddle is massively displaced even with the BodyVelocity instead of BodyPosition (The result is the same on both the server view and the client view, though to see the client view you’ll have to add a simple local script into StarterPlayerScripts to adjust the camera to a more useful view).
So out of curiosity, since it seemed to be the absence of a character causing this, I decided to see what would happen using a BodyPosition while still having a character. The paddle only gets displaced a little bit with a BodyPosition, but it doesn’t go flying across the screen like it does with the absence of a character.
My game doesn’t need the player to have a character as the paddle is what the user controls instead.
So… after some testing I’m having doubt about whether or not I even still want the player to have network ownership over their paddle.
My original thought was that it “feels good” to have that instant feedback when you control the paddle, rather than a slight delay before it responds. It also makes the paddle appear smoother as an entire object. When the server has network ownership, the parts that I have constrained by hinges to the main part of the paddle have a bit of stutter and don’t move very smoothly.
But as good as it feels to have that instant feed back, and as nice as it looks to have the whole paddle travel smoothly, the delay between the paddle moving on the client to the paddle moving on the server is a problem. If I’m moving my paddle and get to the ball just in time (from my own client perspective), the ball goes right through my paddle because the server version of my paddle lags behind slightly and didn’t actually collide with the ball. Similarly, if I’m moving towards the ball and accidentally go a tad too far (from my own client perspective), even though it looks like I should have missed the ball, the delayed version of my paddle on the server didn’t go too far yet and hits the ball.
While slightly delayed control input doesn’t feel the best, it’s probably a lot better than missing the ball when it looked like you hit it or hitting the ball when it looked like you missed it. And as for the hinge constrained parts on my paddle, the purpose I’m using those for could probably be replicated my a traditional weld with CFrame rotation, so the hinge constraint stutters could potentially be avoided, which leaves delayed control input as pretty much the only issue with having everything owned by the server. (And with no major lag, its only about .1 or .2 seconds delay)