Is there an alternative to Network Ownership?

The Issue

My game, Merge but betterer is based on the idea that players move unanchored balls into each other to merge them into a bigger ball. However, there is a big issue, exploiters can manipulate network ownership and basically move the balls anyway they want. (Ex; Make them fall through the map and cause them to be deleted.)

What I’ve Tried

My game has invisible safety nets to stop the balls from being able to be flung, these nets check when a ball touches them and recreates the ball in the middle of the map. However, this doesn’t work. Because exploiters can just delete the barriers locally and the balls wont be recreated as long as they have network ownership. Somone was kind enough to show me the exploit, before I had no idea Network Ownership had this vulnerability.

An Undesired Solution

Cleary the easiest solution would be to set the network owner to nil every time a ball is created.

Ball:SetNetworkOwner(nil)

However, this makes the balls not as easy to push, which is the whole point of the game to begin with. If anyone could give me any ideas, it would be very appreciated. (If this is in the wrong category, please tell me and I’ll fix it.)

I Found a Solution!

I decided to just check if the ball is to low, respawn the ball and kick the network owner. It should work and if any false positives occur at least, they will be able to rejoin.

local SystemMessages = require(script.Parent.Parent.Parent.Modules.SystemMessages)
while task.wait() do
local success, output = pcall(function()
  for index, Ball in ipairs(workspace.Balls:GetChildren()) do
    if Ball.Parent ~= nil then
      if Ball.Position.Y < -2 then
        local Player = Ball:GetNetworkOwner()
        if Player then
          Player:Kick("ANTI CHEAT!\nYou're not banned. If you did exploit, stop because it's not funny.")
          SystemMessages.Send("⚠️ "..Player.Name.." ("..Player.UserId..") was kicked by the anti cheat.")
        end
        Ball:Destroy()
        local HasFace = false
        if Ball:FindFirstChild("Face") then
          HasFace = true
        end
      script.Parent.CreateBall:Invoke(Ball.Level.Value, Vector3.new(math.random(-30, 30), 25, math.random(0, 60)), false, HasFace)
      end
    end
  end
  return
  end)
end