Way to send info from client remote function safely?

Hey! I made a post earlier today and got some good general advice about hitboxes and how they should be made. I’ve now moved to a client-sided hitbox system where the hit validation is done on the server and then the effects are shown on all clients.

Though this is all well, (at least I think it is if there’s any more ways to validate a hit on the hitbox let me know!) I want to be able to send information like the cooldown timer, magnitude range and angle it can hit at to the server so I can just keep using the same hit validation script.

The problem is that I know this is a BIG no no because the exploiter could simply just change those values in the local script, the same way with the vTable but that’s where my checks come in.

So I’m wondering if this is something I shouldn’t be worried about or if it is and there’s a way to validate those variables so I can continually use this script for all of my abilities.

local script:

local RS = game:GetService("ReplicatedStorage")
local PLRS = game:GetService("Players")
local UIS = game:GetService("UserInputService")

local abilityEvents = RS:WaitForChild("Ability")
local abilityRemote = abilityEvents:WaitForChild("AbilityRemote")

--Hitbox is created on the client for WYSIWYG flow. We will need checks on the server side for exploit purposes
UIS.InputBegan:Connect(function(input, gameProcessed)
	
	local character = script.Parent
	
	if gameProcessed then
		return
	end
	
	if input.KeyCode == Enum.KeyCode.Q then

		local hrp = character:FindFirstChild("HumanoidRootPart")
		local pos = hrp.Position
	
		local hitCharacters = {}
		local parameters = OverlapParams.new()
		local hitbox = Instance.new("Part")
		hitbox.Shape = Enum.PartType.Ball
		hitbox.Size = Vector3.new(10, 10, 10)
		hitbox.CanCollide = false
		hitbox.Anchored = true
		hitbox.Transparency = 0.5
		
		local cf = hrp.CFrame
		local size = hitbox.Size
		
		parameters.FilterDescendantsInstances = {character}
		hitbox.Position = pos
		hitbox.Parent = workspace
		
		local hitboxPart = workspace:GetPartBoundsInBox(cf, size, parameters)
		
		local vTable = {}
		
		for _, hitPart in pairs(hitboxPart) do
			local vHum = hitPart.Parent:FindFirstChild("Humanoid")
			if vHum and not table.find(vTable, hitPart.Parent) then
				table.insert(vTable, hitPart.Parent)
			end
		end
		
		abilityRemote:FireServer(vTable) --I would add a cooldown, magnitude and angle value in here
	
		game.Debris:AddItem(hitbox, 0.1)
	end
end)

Server Script:

local RS = game:GetService("ReplicatedStorage")

local abilityEvents = RS:WaitForChild("Ability")
local abilityRemote = abilityEvents:WaitForChild("AbilityRemote")
local abilityVFX = abilityEvents:WaitForChild("AbilityVFX")

local debounce = {}

abilityRemote.OnServerEvent:Connect(function(player, vTable) --and the cooldown, distance and degAngle values would change here
	
	local cooldown = 3
	
	local hitChars = {}
	
	local pChar = player.Character
	local hrp = pChar:FindFirstChild("HumanoidRootPart")
	local pos = hrp.Position
	local pDirection = hrp.CFrame.LookVector
	
	if table.find(debounce, player.Name) ~= nil then --Debounce cooldown so exploiters cannot spam the server with requests
		print("Under debounce!")
	else
		print("Ability casted!")
		table.insert(debounce, player.Name)
		
		for _, vChar in pairs (vTable) do --Checks if hit was actually valid
			
			local vrp = vChar:FindFirstChild("HumanoidRootPart")
			local vPos = vrp.Position
			
			local magCheck = (vPos - pos)
			local distance = magCheck.Magnitude --Gets distance between the players
			local normalizedDist = magCheck.Unit --Normalizes that distance number
			
			local dot = pDirection:Dot(normalizedDist)  --Normalizes look vector
			local radAngle = math.acos(dot) --Finds the angle between the vrp and player look direction
			local degAngle = math.deg(radAngle) --Converts above into an angle
			
			if distance <= 6 and degAngle <= 45 and vChar and not table.find(hitChars, vChar) then --Validation check
				print("Hit")
				table.insert(hitChars, vChar) --Adds player to table for VFX purposes
				vChar.Humanoid:TakeDamage(10)
			end	
		end
		
		abilityVFX:FireAllClients(hitChars) --VFX
		
		task.wait(cooldown)
		debounce[table.find(debounce, player.Name)] = nil
		
	end

end)

Sorry if this is considered a double post, but thanks regardless!

I think it would probably be smarter to store the magnitude range and angle it can hit at and cooldown in a module that both the server and client can access, that way you dont have to send it to the server, so exploiters cant mess with it. That and now the server doesnt have to validate it, and you can save some time!

1 Like

You pretty much can’t send information from the client safely.

The best method in your case here is to run the checks on the server and not on the client.

1 Like

So if I’m understanding this right, instead of having the validation checks run on a server script, they would be checked in a module script? So the purpose of firing a message from the client to the server would be only to require that module in which the SERVER sends the cooldown information and etc.?

close,

The information, such as the range, cooldown, etc, is all stored in a module script. The server then just uses that data to validate the data the client sent. I see now I phrased it wrong, so thats on me.

So you would do the same thing you’re doing now, but the information (that being any constant information that the client doesnt need to change) is stored in a module of which both client and server use.

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