Ball Network Ownership Bug

To put it bluntly,

In my football/soccer game, if Player A spawns a ball it sets the network ownership to their Player, but if they spawn it and Player B touches it before Player A does, the ball moves for Player B who kicked it but stays in the same place for Player A who spawned it - when Player A then tries to touch it, the ball bugs out and starts rolling/freezing without any of the properties updating.

The bug is rare but still happens.

The ball attributes DO update when the glitch happens.

Here’s an example of the ball once the Player B has kicked the ball Player A spawned without Player A touching it. (Player A’s perspective)

We’ve attempted to remove the setnetworkowner when the ball spawns but that didn’t fix it.

--// Only Fires once there's a new owner.
BallUpdate.OnServerInvoke = function(Player, Ball, GK, Info)
    if not (CS:HasTag(Ball, Tag)) then
        return false
    end

    local Character = Player.Character

    if Character ~= nil and Character:FindFirstChild("HumanoidRootPart") ~= nil then
        if (Character.HumanoidRootPart.Position - Ball.Position).Magnitude > 30 then 
            return false
        end
    else
        return false
    end

    if Ball:GetAttribute("Owner") == Player.UserId then --// Prevents exploits
        return false
    end

    if not GK then
        if Ball:GetAttribute("ReactSession") ~= Info[2] then
            General:FireAllClients("Debug", "Decline", {
                ["Player"] = Player,
                ["Ball"] = Ball,
                ["Reason"] = "DELAY",
                ["Position"] = Ball.Position
            })
            return false
        end

        local ReactSeconds = workspace:GetServerTimeNow() - Info[1]
        local Ping, MaxPing = SecondsToPing(ReactSeconds)

        if MaxPing then
            General:FireAllClients("Debug", "Decline", {
                ["Player"] = Player,
                ["Ball"] = Ball,
                ["Reason"] = "DELAY",
                ["Position"] = Ball.Position
            })
            return false
        end

        if Player.Ping.Value >= Storage.PingLimit then
            General:FireAllClients("Debug", "Decline", {
                ["Player"] = Player,
                ["Ball"] = Ball,
                ["Reason"] = "MAX PING",
                ["Position"] = Ball.Position
            })
            return false
        end

        if (Ball:GetAttribute("Decline") == true) then
            General:FireAllClients("Debug", "Decline", {
                ["Player"] = Player,
                ["Ball"] = Ball,
                ["Reason"] = "FIRST TOUCH",
                ["Position"] = Ball.Position
            })
            return false
        end

        Ball:SetNetworkOwner(Player)
        Ball:SetAttribute("Owner", Player.UserId)

        coroutine.wrap(function()
            local PlrsNearBall = GetPlayersNearBall(Ball)

            if PlrsNearBall > 4 then
                Cooldown = 1.35
            else
                Cooldown = 0.75
            end

            FirstTouch(false, Ball, Cooldown, Info[3])

            General:FireAllClients("Debug", "NewOwner", {
                ["NewOwner"] = Player,
                ["Ball"] = Ball,
                ["Position"] = Ball.Position
            })
        end)()

        return true
    end
end
--// Happens whenever the player touches the ball
function ToolManagement:ApplyVelocity(Ball, Forces, Extra, Curve)

    local OldPosition = Ball.Position

    local Velocity = Forces["Velocity"]

    if Ball:GetAttribute("Owner") ~= player.UserId then


        Ball.Anchored = true
        Ball.CanCollide = false

        coroutine.wrap(function()
            ReactUpdate:InvokeServer(
                Ball, 
                false, 
                {
                    workspace:GetServerTimeNow(), 
                    Ball:GetAttribute("ReactSession"), 
                    Velocity.Magnitude
                }
            )

            Ball.Anchored = false
            Ball.CanCollide = true
        end)()
        end
    end

    if Velocity.Magnitude > 0 then
        Velocity = (Velocity - (Ball.Position - OldPosition)).Unit * Velocity.Magnitude
    end

    React:ApplyBodyVelocity(Ball, Velocity, Forces["MForce"], Forces["Debris"], player.Name)
9 Likes

heyo!

this seems to be extremely odd behaviour.

try updating the ball’s network ownership to the closest player.

2 Likes

Hey, thank you for your response!

Unfortunately, the game mechanics aren’t built for changing the network owner to the closest player.

The owner of the ball will always be the network owner until they get tackled.

2 Likes

hi again!

unfortunately, there is not a good solution to this problem that i can think of, unless you can find a super hacky fix.

2 Likes

We encountered the same issue in our football game. Our fix was just to force the ball physics to always be ‘awake’, so that it does not sleep. Sleeping is an optimization for physics, which basically just means that whenever the ball has no forces acting upon on it, it will not run physics on it.

We force every ball to be awake by applying a small impulse to it, which works well for us since we have quite few balls at any time in the game. This may reduce performance if you have a lot of balls in the game at the same time though.

This seems like a bug on Roblox’s side, but I haven’t bothered to make a bug report for it.

4 Likes

This worked, thank you so much for your help! We really appreciate it.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.