How to fix remote spamming?

So, I have a code that fires a remote to detect if a something is on the players screen. The problem is that it errors saying “Player appears to be spamming remote events”.

local function checkSight(part)
	local success, bool = pcall(function()
		return Remotes.CheckOnScreen:InvokeClient(player, part)
	end)
	return success, bool
end

RunService.Heartbeat:Connect(function()
    checkSight(part)
end)
5 Likes

Could you show me a screenshot, or copy-and paste what the error actually says? I’ve never seen this error before.

The reason why you have this error, is because in your script you are invoking the client right before every physics simulation, which occurs several times per second. I’m also not sure what you are trying to do, but it’s not recommended to use RemoteFunction:InvokeClient(player, ...) due to security reasons, and because the client is less guaranteed than the server is to return data from the invoking of the function.

Here is more info on this:

2 Likes

Something like this:
image

1 Like

This is a warning, and not an error, but what exactly are you trying to accomplish? Maybe I can help you do it differently so you don’t get this warning.

Edit: I am asking what are you trying to do that needs you to use InvokeClient() on the server? @GameMaster4268

1 Like

I want to prevent this warning from appearing.

1 Like

To check if a part is on the players screen

LocalScript:

Remotes.CheckOnScreen.OnClientInvoke = function(part)
	local Vector, OnScreen = currentCamera:WorldToViewportPoint(part.Position)
	return OnScreen
end

It’s my bedtime now. Going to check on this in the morning.

2 Likes

Could you connect the Heartbeat on the client and only fire an event when the client finds something?

--// LocalScript
local function CheckOnScreen()
	local Vector, OnScreen = currentCamera:WorldToViewportPoint(part.Position)
	return OnScreen
end

RS.Heartbeat:Connect(function()
    if CheckOnScreen() then
        event:FireServer() --// Regular RemoteEvent
    end
end)

--// Server Script
event.OnServerEvent:Connect(function(plr)
    print(plr.Name.." sees the thing!"
end)

Edit:
To reduce the number of times the event calls, add a debounce that only fires the event once on it entering the screen. If you want some sample code I can provide it.

1 Like

I have more than 1 part that I need to check. I have an NPC that attacks other NPC’s when the player camera can see the targets too.

Instead of the server invoking the client every frame to get the data, why not make the LocalScript fire an event every frame?

Heres the full code of what im trying to do:

local RunService = game:GetService("RunService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local Remotes = replicatedStorage:WaitForChild("Remotes")

local Modules = replicatedStorage:WaitForChild("Modules")

local ToolData = require(script.Parent:WaitForChild("ToolData"))

local character = script.Parent.Parent
local humanoid = character:WaitForChild("Hero")
local animator = humanoid:FindFirstChildOfClass("Animator")

local RemotesFolder = character:WaitForChild("RemotesFolder")

local npcs = workspace:WaitForChild("Npcs")

local animationTable = {
	[0] = script:WaitForChild("Attack1"),
}

local tool = character:WaitForChild("Bow")
local hitbox = tool:WaitForChild("Hitbox")
local firePoint = hitbox:WaitForChild("FirePoint")

local range = ToolData.MaxRange

local animationCombo = 0

local currentTime = tick()
local canShoot = true
local damageCooldown = 1.5

local currentTarget = nil

local canAttack = character:WaitForChild("CanAttack")
local track = nil

local function playAnimation()
	if animationTable[animationCombo] then
		local anim = animationTable[animationCombo]
		track = animator:LoadAnimation(anim)
		track:Play()
		track.Stopped:Wait()
		canShoot = true
	end
	animationCombo += 1

	if animationCombo > #animationTable then
		animationCombo = 0
	end
end

local function castRay(target)
	if target.PrimaryPart ~= nil then
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {npcs}
		raycastParams.FilterType = Enum.RaycastFilterType.Whitelist
		raycastParams.IgnoreWater = true
		
		local rayOrigin = character.PrimaryPart.Position
		local rayDestination = target.PrimaryPart.Position
		local rayDirection = (rayDestination - rayOrigin)
		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
		
		if raycastResult then
			local distance = math.floor(raycastResult.Distance)
			if distance <= range then
				currentTarget = target
				return true, raycastResult.Position, distance
			end
		end
	end
	currentTarget = nil
	return false, nil, nil
end

local function PredictNextPosition(targetPosition, targetVelocity)
	if targetPosition ~= nil and targetVelocity ~= nil then
		local t = ToolData.ProjectileTime
		local endPosition = targetPosition + targetVelocity * t
		return endPosition
	end
end

local function getPlayer()
	local player = Remotes.GetPlayerBindable:Invoke()
	if player then
		return player
	end
end

local player = getPlayer()

local function reset()
	if track ~= nil then
		track:Stop()
	end
	currentTarget = nil
	canShoot = true
end

local function findTarget()
	local checkRay, position, distance = nil, nil, nil

	for i,v in ipairs(npcs:GetChildren()) do
		checkRay, position, distance = castRay(currentTarget or v)

		if currentTarget ~= nil then
			local savedTarget = currentTarget

			local targetRoot = currentTarget.PrimaryPart
			local human = currentTarget:FindFirstChildWhichIsA("Humanoid")
			
			if human and human.Health > 0 then
				if human and human.Health <= 0 then
					currentTarget = nil
				end

				if distance > range then
					currentTarget = nil
				end

				if player and human and human.Health > 0 and currentTarget ~= nil and targetRoot ~= nil and checkRay == true then
					local success, bool = pcall(function()
						return Remotes.CheckOnScreen:InvokeClient(player, targetRoot, {npcs})
					end)
					
					if success and bool then
						local characterRoot = character.PrimaryPart
						characterRoot.CFrame = CFrame.lookAt(characterRoot.Position, Vector3.new(position.X, characterRoot.Position.Y, position.Z))

						if tick() - currentTime >= damageCooldown then
							currentTime = tick()
							playAnimation()
							checkRay, position, distance = castRay(savedTarget)
							local nextPosition = PredictNextPosition(position, targetRoot.AssemblyLinearVelocity)
							if checkRay ~= nil and checkRay == true and nextPosition ~= nil and canShoot == true and human and human.Health > 0 then
								RemotesFolder.FireProjectile:Fire(firePoint, nextPosition)
								canShoot = false
							else
								reset()
							end
						end
					end
				end
			else
				reset()
			end
		end
	end
end

RunService.Heartbeat:Connect(function()
	if character.PrimaryPart ~= nil and canAttack.Value == true then
		findTarget()
	end
end)

Camera Handler:

local player = game.Players.LocalPlayer

local camera = workspace.Camera
local CameraPart = workspace:WaitForChild("CameraPart")

local replicatedStorage = game:GetService("ReplicatedStorage")
local Remotes = replicatedStorage:WaitForChild("Remotes")

local currentCamera = workspace.CurrentCamera

local castParams = RaycastParams.new()
castParams.FilterType = Enum.RaycastFilterType.Whitelist
castParams.IgnoreWater = true

local function checkOnScreen(part, whitelist)
	castParams.FilterDescendantsInstances = whitelist
	local Vector, OnScreen = currentCamera:WorldToViewportPoint(part.Position, castParams)
	return OnScreen
end

Remotes.CheckOnScreen.OnClientInvoke = function(part, whitelist)
	return checkOnScreen(part, whitelist)
end

you really really do not want to invoke a remote every frame this causes tons of network lag (huge ping)

change it to only invoke a few times per second
example

local lastSendTick = tick()
local updatesPerSecond = 10

RunService.Heartbeat:Connect(function()
    if tick() - lastSendTick > 1 / updatesPerSecond then
        -- invoke to client
        lastSendTick = tick()
    end
end)

It would be more efficient to only send the data when it changes

For example, if you already sent that it was false then you do not need to send it again, you would only fire when it changes

this works too i just sent the first thing i thought of

This error occours when a player is spamming remote events so much that it may overload the server.

Consider changing the rate that you send remote events, such as a while true loop like blorbee said, or make it so the client does much of the work like rick said

I dont know what exactly what your trying to accolampish but it appears your trying to make it so whilst looking around any enemy you spot has fellow npc’s controlled by the player attack your target

Perhaps consider checking the parts on the client, and when the camera detects a target has entered the camera, fire a remote event to your npc’s the player in controlling which makes them follow the target.

Once your camera has looked away from the target, then fire a remote event to the server which stops the movemnt of your npc’s the player is controlling

This would mean it would only fire remote events around twice instead of a billion times

thats just an idea tho im not the best scripter

Just trying to make my NPC attack other NPC’s when the player’s currentcamera can see the target.

your camera never changes so just add an invisible part and when collided with the npc will start attacking the enemy who collided it

1 Like