Syncing a moving ball on the client with the server?

Currently, the ball is owned always by the server, and velocity is used to move the ball.
This obviously creates a delay between the ball’s position, since it has to be sent to the client to update it. Basically the ball has latency depending on the player’s ping. This delay is even worse the faster the ball is.

The problem that this makes is for example, when a goal is being scored.
The ‘laggy’ client sees the ball way away from the goal, so while the player is trying to block it, the goal has already been scored.

I tried predicting the ball’s position on the client in multiple ways, but it’s not working how I want it to.

runService.Heartbeat:Connect(function()
	local ping = game.Players.LocalPlayer:GetNetworkPing()
    clientBall.Position = ball.Position + ball.AssemblyLinearVelocity * ping
end)

How could I solve this problem? Should the goal hit detection be client sided? Should it wait for a number of players to confirm a goal? Wouldn’t that create more problems?

Here’s another method I tried, the fake ball is still >delayed< ?

local ping = game.Players.LocalPlayer:GetNetworkPing() * 2
local velocity = ball.AssemblyLinearVelocity
	
if velocity == Vector3.zero then
	return
end
	
if (fakeBall.Position - ball.Position).Magnitude >= 4 then
	fakeBall.CFrame = ball.CFrame
end
	
fakeBall.AssemblyLinearVelocity = velocity * (1 + ping)

So a method for replicating ball movement I recently saw in a post and worked perfectly on an older project on mine, was calculating the CFrame on the client which activates the ball, pass it to the server which passes the CFrame to all clients and every client itsself creates its own ball and moving it with the CFrame from the Server
That was looking then sth like this:

LocalScript:
script.Parent.Activated:Connect(function()
	local fireballCFrame = cFrameCalculations
	event:FireServer(fireballCFrame)
end)

event.OnClientEvent:Connect(function(cFrame, otherPlr)
	local newBall = part:Clone()
	newBall.CFrame = cFrame
	newBall.Name....

	local Velocity = Instance.new("BodyVelocity")
	Velocity.maxForce.....

	local connection
	connection = newBall.Touched:Connect(function(hit)
		if hit.Parent:FindFirstChildWhichIsA("Humanoid") and hit.Parent.Name ~= otherPlr.Name then
			newBall:Destroy()
			connection:Disconnect()
		end
	end)
end)

ServerScript:
event.OnServerEvent:Connect(function(plr, cframe)
	event:FireAllClients(cframe, plr)
end)

still couldnt get it to work properly,