In my game, Mini Cup, there are around 16 players in game. They are divided into 4 teams of 4 and play soccer against each other in turns. Anyone would assume, a major aspect of a soccer (football) game, would be kicking the ball into the oppositions net. And thats what they do in my game.
However it is hard to play with much precisions because the latency makes it so that the opposing players look far away from the ball when they kick it, when in reality, on their end of the game, on their screen, they are already touching the ball. If you play one match in this game you will see the issue yourself:
So now my issue is how do I fix this?
I’ve been trying for months but have come to no solution.
(I’ve changed velocity types, added a cooldown, set network owner to nil and everything I’ve heard of)
This is the current server script which is parented to the ball and is replicated from ServerStorage to the Workspace as needed.
local Players = game:GetService("Players") -- Get the Players service
local Debris = game:GetService("Debris") -- Get the Debris service
local Ball = script.Parent -- Get the ball object
local KickSound = Ball:WaitForChild("Kick") -- Get the kick sound
local bounce = false -- Set a flag to prevent multiple touches from being registered
local gameModule = require(game.ServerStorage.Modules.GameModule)
Ball.Touched:Connect(function(t) -- Connect to the Touched event on the ball
if t.Name == "PlayerHitBox" then
local character = t.Parent -- Get the character that touched the ball
if not character then return end -- If there is no character, return
local player = Players:GetPlayerFromCharacter(character) -- Get the player associated with the character
local humanoid = character:FindFirstChildOfClass("Humanoid") -- Get the humanoid of the character
local rootPart = character:FindFirstChild("HumanoidRootPart") -- Get the root part of the character
if not player or not humanoid or humanoid.Health <= 0 or not rootPart then return end -- If any of these are missing or the character is not alive, return
local ballVelocity = Ball.AssemblyLinearVelocity -- Check if the ball already has a velocity
if bounce == false and not player:GetAttribute("kicked") then -- If the flag is set and no other touches have been registered
player:SetAttribute("kicked", true)
print("Bounce is true")
bounce = true -- Set the bounce flag to prevent further touches from being registered
local direction = rootPart.CFrame.LookVector -- Get the direction the character is facing
if direction.Magnitude < 0.001 then return end -- If the direction is very small, return
Ball:SetNetworkOwner()
local kickForce = humanoid.WalkSpeed -- Get the character's walk speed
Ball.AssemblyLinearVelocity = (direction.Unit * kickForce * 1.95) + Vector3.new(0, kickForce * 1.15, 0) -- Set the velocity of the ball based on the direction and walk speed of the character
KickSound:Play() -- Play the kick sound
-- Set the attributes for the last and second-to-last player to touch the ball
if Ball:GetAttribute('LastTouch') ~= nil then
if Ball:GetAttribute('LastTouch') ~= player.Name then
local previousTouch = Ball:GetAttribute('LastTouch')
Ball:SetAttribute('LastTouch', player.Name)
Ball:SetAttribute('SecondTouch', previousTouch)
else
-- Do nothing if the current player is the same as the last player to touch the ball
end
else
Ball:SetAttribute('LastTouch', player.Name)
end
print("Sending For KickTimer")
gameModule.kickTimer(player)
print("Kicktimer Returned")
task.wait(0.6) -- Wait for 1/2 second
print("Debounce is false")
bounce = false -- Reset the bounce flag to allow for future touches to be registered
-- Increment the touch count for the player's team in the "Standings" folder
local teamName = player:GetAttribute('TeamName')
if game.ServerStorage.GameFolder.Standings:FindFirstChild(teamName) ~= nil and game.ServerStorage.GameFolder.Standings:FindFirstChild(teamName):GetAttribute("Touches") ~= nil then
game.ServerStorage.GameFolder.Standings:FindFirstChild(teamName):SetAttribute('Touches', game.ServerStorage.GameFolder.Standings:FindFirstChild(teamName):GetAttribute('Touches') + 1)
end
end
end
end)
At this point I think it requires an advance solution which I do not have the knowledge to implement. Any ideas or answers would help greatly!
I am also willing to hire an expert who can solve (or at least greatly remedy) the issue as a one time commission.
The issue is that you are using Touched and you are using it on the server.
The way I’d fix it is using raycasting or GetPartsInPart to look for the player character on the client and applying the velocity on the client after using SetNetworkOwner(localPlayer)
that way, there would be little to no latency.
To apply any special value changes, for example player:SetAttribute("kicked",true), that would be communicated to the server via remoteEvent/remoteFunction.
It would probably require you to rearrange your code, but it is not too hard to accomplish.
The issue you’re describing is a common one in multiplayer games where latency can cause discrepancies between what different players see on their screens. To address this, you can use techniques like client-side prediction and server reconciliation.
Client-side prediction involves predicting the movement of game objects on the client before receiving updates from the server. This can help reduce the perceived latency and make the game feel more responsive. Server reconciliation involves checking the state of game objects on the server and reconciling any discrepancies with the client’s predicted state. This helps ensure that all players are seeing the same game state and can help prevent cheating.
In your specific case, it looks like you are already setting the network owner to nil, which can help reduce perceived latency. However, you may want to consider implementing more advanced techniques like client-side prediction and server reconciliation to further reduce latency and ensure consistent game state across all clients.
If you’re not familiar with these techniques or don’t have the experience to implement them yourself, you may want to consider hiring an experienced game developer to help you. You can find game developers on freelance platforms like Upwork or Fiverr, or through game development communities like the Unity or Unreal Engine communities.
Sure lmao…
Client-side prediction is a technique used in games to reduce the effects of network latency and improve the responsiveness of player actions. In Roblox, client-side prediction can be implemented using RemoteFunctions and RemoteEvents.
Here’s a basic example of how you can implement client-side prediction for a player’s movement:
Create a RemoteFunction in a Script located in ServerScriptService. This RemoteFunction will be used to receive the player’s input data from the client and return the predicted result of the movement.
local function onPlayerInput(player, input)
-- calculate the predicted result of the movement based on the input
local predictedResult = calculatePredictedResult(input)
-- return the predicted result to the client
return predictedResult
end
game.ReplicatedStorage.RemoteFunction.OnServerInvoke = onPlayerInput
In a LocalScript located in StarterPlayerScripts, use UserInputService to capture the player’s input and send it to the server via the RemoteFunction created in step 1.
local function sendPlayerInput(input)
-- send the input data to the server and receive the predicted result
local predictedResult = game.ReplicatedStorage.RemoteFunction:InvokeServer(input)
-- apply the predicted result to the player's character
applyPredictedResult(predictedResult)
end
game:GetService("UserInputService").InputBegan:Connect(function(input)
-- capture the player's input and send it to the server
sendPlayerInput(input)
end)
On the server, calculate the predicted result of the player’s movement based on their input data. This could involve predicting the player’s position based on their velocity and acceleration, or predicting the result of a player’s attack animation based on their input and animation state.
On the client, apply the predicted result to the player’s character. This could involve updating the player’s position, orientation, or animation state.
It’s important to note that client-side prediction can introduce inaccuracies and inconsistencies in the game state. To minimize these issues, it’s recommended to use server-side validation to verify the results of the player’s actions and correct any discrepancies.
this issue will never really go away because of clients ping state and just server connections the best way i can think of is to kick the ball from local side to clear that off then fire remote event and kick the ball on the server side or you can refire the event to AllClients that way they kick the ball on their screen the best way to defeat lags is to not use server side since that would take more then just firing all clients that will also make more holes for cheaters but shoot your shot who knows you may get it
– edit
or you can keep the server side script and instead calculate the kick and send the informations to allclients so it moves on thier screen first in the end the cframe is always getting tracked from client or server side
I tried this but whenever I sent the remote event from the server script to the local script, it would FireAllClients but never be received by the client and the ball wouldn’t move.
can i see the script it very wierd for it to do so and unexpected if the connection to the remoteevent is done with local script then it should work or you can just loop through players and fire the remote event to each player