Raycastparams hits object in its filterdescendants table bug

  1. What do you want to achieve?
    I wanted to change my bullet registration to the client side and validate the raycast. It would work buy sending a raycast result from the client to the server. Then a module script would verify the raycast.

  2. What is the issue?
    When I fire my bullet, it hits my character’s uppertorso, which is in the raycast’s ignorelist it hits it anyway.

  1. What solutions have you tried so far?
    I tried manually listing the uppertorso in the ignore list, but then it hit my humanoidrootpart. I tried making a function that would insert every part of the character in it and put it in the ignore list. I got uppertorso.

Edited Client Script:

local function getAllCharactersInTeam(team: Team): {Model}
	local characters = {}

	for _, plr: Player in pairs(team:GetPlayers()) do
		if plr.Character then
			table.insert(characters, plr.Character)
		end
	end

	return characters
end

local function getEverything(char: Model)
	local everything = {}
	
	for _, basepart: BasePart in pairs(char:GetDescendants()) do
		if basepart:IsA("BasePart") then
			table.insert(everything, basepart)
		end
	end
	
	return everything
end

local function intoTable(result: RaycastResult)
 --For some reason remote events dont allow raycast results to be sent
	local conversion = {}
	
	conversion.Position = result.Position
	conversion.Instance = result.Instance
	conversion.Material = result.Material
	conversion.Distance = result.Distance
	conversion.Normal = result.Normal
	
	return conversion
end

local function shoot()
	params.FilterDescendantsInstances = {Tool.Parent, getEverything(Tool.Parent), camera, getAllCharactersInTeam(player.Team)}

	local cast = Ray.new(camera.CFrame.Position, (mouse.Hit.Position - camera.CFrame.Position).Unit*5000)
	local secure = workspace:Raycast(cast.Origin, cast.Direction, params)
	print(mouse.Hit.Position)

	ShootEvent:FireServer(armsBarrelAttachment.WorldPosition, intoTable(secure), cast)
end

Tool.Activated:Connect(shoot)

Edited Server Script:

local ServerModules 							= ServerStorage:WaitForChild("ServerModules")
local KBConstructor								= require(ServerModules:WaitForChild("KBConstructor"))
local ClientRaySecure							= require(ServerModules:WaitForChild("SecureClientRays"))

local function shoot(plr: Player, clientPos: Vector3, result: RaycastResult, cast: Ray)
	local secure, direction = ClientRaySecure:CheckRay(plr, result, cast, getRandomBulletSpread(), {Tool.Parent})
	local hit = nil
	
	if secure then
		hit = secure.Instance
	else
		hit = result.Instance
	end
	
	print(hit)
	
	if hit then
		local model: Model = hit:FindFirstAncestorOfClass("Model")

		if model then
			local humanoid = model:FindFirstChildOfClass("Humanoid")

			if humanoid then
				local enemyPlr = game.Players:GetPlayerFromCharacter(model)
				local isAnEnemy = false

				if enemyPlr then
					if enemyPlr.Team ~= plr.Team then
						isAnEnemy = true

						local eProp: Model = model:WaitForChild("Properties")
						local playerDamagedMe: ObjectValue = eProp:WaitForChild("PlayerDamagedMe")
						playerDamagedMe.Value = plr
					end
				end

				if not enemyPlr then
					isAnEnemy = true
				end

				if isAnEnemy then
					local dmg = baseDmg
					local crit = false

					if hit.Name == "Head" then
						dmg *= 3
						crit = true
					end

					if (direction.Magnitude) > minimumDist then
						dmg -= 5
					end

					dmg = math.round(dmg)

					humanoid:TakeDamage(dmg)
					KBConstructor.new(model:WaitForChild("HumanoidRootPart"), myHRP.CFrame.LookVector.Unit, 25)
					DamageDisplay:FireClient(plr, secure ~= nil and secure.Position or result.Position, crit and true or false, dmg)
				end
			end
		end
	end
end

Client Ray Securer:

local Security 										  		 = {}
Security.MaxOriginDistance									 = 5

--direction = target - origin

function Security:CheckRay(owner: Player, result: RaycastResult, cast: Ray, bulletSpread: Vector3, filter: {Instance})	
	local origin = cast.Origin
	local direction = (cast.Direction.Unit)*bulletSpread
	
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Include
	params.FilterDescendantsInstances = {workspace.Map}
	params:AddToFilter(filter)
	
	local primaryPart = owner.Character.PrimaryPart
	
	if (primaryPart.Position - origin).Magnitude >= Security.MaxOriginDistance then
		origin = primaryPart.Position
	end
	
	local newResult = workspace:Raycast(origin, direction, params)
	
	return newResult, direction
	--[[
		if newresult then something is obstructing the ray
		if not newresult, then the clientRay is secure
	]]--
end
1 Like

It might have something to do with Edited Client Script, particularly this line:

params.FilterDescendantsInstances = {Tool.Parent, getEverything(Tool.Parent), camera, getAllCharactersInTeam(player.Team)}

getAllCharactersInTeam is returned as a table. It may need to be as a tuple instead though:

params.FilterDescendantsInstances = {Tool.Parent, getEverything(Tool.Parent), camera, table.unpack(getAllCharactersInTeam(player.Team))}
2 Likes

I don’t know if it’s already there, but make sure that params inside the “Edited client script” is set to Enum.RaycastParams.Exclude

1 Like

I changed

params.FilterDescendantsInstances = {Tool.Parent, getEverything(Tool.Parent), camera, getAllCharactersInTeam(player.Team)}

into

params.FilterDescendantsInstances = {Tool.Parent, table.unpack(getEverything(Tool.Parent)), camera, table.unpack(getAllCharactersInTeam(player.Team))}

It didn’t seem to work

params.FilterType								= Enum.RaycastFilterType.Exclude

Should I send the full local script?

1 Like

yeah, you should send the three scripts

1 Like

Local script:

local contextActionService						= game:GetService("ContextActionService")
local replicatedStorage							= game:GetService("ReplicatedStorage")
local runService								= game:GetService("RunService")

local armWeaponsFolder							= replicatedStorage:WaitForChild("FirstPersonWeapons")
local armTool									= armWeaponsFolder:WaitForChild("Pistol"):Clone()
local flashPart								    = armTool:WaitForChild("GunFlash")
local armsBarrelAttachment						= armTool:WaitForChild("Handle"):WaitForChild("BarrelAttachment")
local flashGui									= flashPart:WaitForChild("MuzzleFlash")
local armsEquipAnim								= armTool:WaitForChild("PistolEquip")
local armsHolsterAnim							= armTool:WaitForChild("PistolHolster")
local armsShootAnim								= armTool:WaitForChild("PistolShoot")
local armsReloadANim							= armTool:WaitForChild("PistolReload")
local armsReloadSound							= armTool:WaitForChild("ReloadSound")
local armsShootSound							= armTool:WaitForChild("ShootSound")

local Tool										= script.Parent
local ShootEvent								= Tool:WaitForChild("RemoteShoot")
local ReloadEvent								= Tool:WaitForChild("RemoteReload")
local Handle									= Tool:WaitForChild("Handle")
local GunFlash									= Tool:WaitForChild("GunFlash")
local MuzzleFlash								= GunFlash:WaitForChild("MuzzleFlash")

local EquipSound								= Handle:WaitForChild("EquipSound2")
local UnequipSound								= Handle:WaitForChild("UnequipSound")
local serverShootSound							= Handle:WaitForChild("ShootSound")
local serverReloadSound							= Handle:WaitForChild("ReloadSound")
serverShootSound.Volume							= 0
serverReloadSound.Volume 						= 0

local player									= game.Players.LocalPlayer
MuzzleFlash.PlayerToHideFrom					= player

local mouse										= player:GetMouse()
local camera									= workspace.CurrentCamera
local fpsArms: Model							= camera:WaitForChild("FirstPersonArms")
local fpsHum									= fpsArms:FindFirstChildOfClass("Humanoid")
local fpsRightArm: BasePart		     			= fpsArms:WaitForChild("Right Arm")
local ToolAttach: Motor6D						= fpsRightArm:WaitForChild("ToolAttach")

local armTracks 								= {
	equip			= fpsHum:LoadAnimation(armsEquipAnim),
	holster 		= fpsHum:LoadAnimation(armsHolsterAnim),
	shoot 			= fpsHum:LoadAnimation(armsShootAnim),
	reload 			= fpsHum:LoadAnimation(armsReloadANim)
}

local ReloadActionName 							= "Pistol_Reload"
Handle.Transparency								= 1

local isEquipped 								= false
local mouseHeldDown								= false
local runDebounce								= false
local runCd										= 0.1
local params									= RaycastParams.new()
params.FilterType								= Enum.RaycastFilterType.Exclude

local function reload()
	ReloadEvent:FireServer()
end

local function getAllCharactersInTeam(team: Team): {Model}
	local characters = {}

	for _, plr: Player in pairs(team:GetPlayers()) do
		if plr.Character then
			table.insert(characters, plr.Character)
		end
	end

	return characters
end

local function getEverything(char: Model)
	local everything = {}
	
	for _, basepart: BasePart in pairs(char:GetDescendants()) do
		if basepart:IsA("BasePart") then
			table.insert(everything, basepart)
		end
	end
	
	return everything
end

local function intoTable(result: RaycastResult)
	local conversion = {}
	
	conversion.Position = result.Position
	conversion.Instance = result.Instance
	conversion.Material = result.Material
	conversion.Distance = result.Distance
	conversion.Normal = result.Normal
	
	return conversion
end

local function shoot()
	params.FilterDescendantsInstances = {Tool.Parent, table.unpack(getEverything(Tool.Parent)), camera, table.unpack(getAllCharactersInTeam(player.Team))}

	local cast = Ray.new(camera.CFrame.Position, (mouse.Hit.Position - camera.CFrame.Position).Unit*5000)
	local secure = workspace:Raycast(cast.Origin, cast.Direction, params)
	print(mouse.Hit.Position)

	ShootEvent:FireServer(armsBarrelAttachment.WorldPosition, intoTable(secure), cast)
end

mouse.Button1Down:Connect(function()
	mouseHeldDown = true
end)

mouse.Button1Up:Connect(function()
	mouseHeldDown = false
end)

Tool.Activated:Connect(shoot)

Tool.Equipped:Connect(function()
	contextActionService:BindAction(ReloadActionName, reload, true, Enum.KeyCode.R)
	EquipSound:Play()
	
	ToolAttach.Part1 = armTool:WaitForChild("Handle")
	
	armTracks.holster:Play()
	
	armTool.Parent = fpsArms
	armTracks.equip:Play()
	armTracks.equip:AdjustSpeed(0)
	
	isEquipped = true
end)

Tool.Unequipped:Connect(function()
	contextActionService:UnbindAction(ReloadActionName)
	UnequipSound:Play()
	
	ToolAttach.Part1 = nil
	
	armTool.Parent = nil
	armTracks.equip:Stop()
	
	isEquipped = false
end)

ShootEvent.OnClientEvent:Connect(function(endPos: Vector3)
	armTracks.shoot:Play()
	armTracks.shoot:AdjustSpeed(2)
	
	armsShootSound:Stop()
	armsShootSound:Play()
	
	flashGui.Enabled = true
	task.wait(.1)
	flashGui.Enabled = false
end)

ReloadEvent.OnClientEvent:Connect(function()
	armTracks.reload:Play()
	armTracks.reload:AdjustWeight(10)
	
	armsReloadSound:Stop()
	armsReloadSound:Play()
end)

runService.Heartbeat:Connect(function()
	if runDebounce or not isEquipped or not mouseHeldDown then
		return
	end
	
	runDebounce = true
	shoot()
	
	task.wait(runCd)
	
	runDebounce = false
end)

Server Script:

local ReplicatedStorage							= game:GetService("ReplicatedStorage")
local ServerStorage								= game:GetService("ServerStorage")

local ServerModules 							= ServerStorage:WaitForChild("ServerModules")
local KBConstructor								= require(ServerModules:WaitForChild("KBConstructor"))
local ClientRaySecure							= require(ServerModules:WaitForChild("SecureClientRays"))

local ServerEvents								= ServerStorage:WaitForChild("ServerEvents")
local ToolSwitchDelay							= ServerEvents:WaitForChild("ToolSwitch")

local PlayerEvents								= ReplicatedStorage:WaitForChild("PlayerEvents")
local DamageDisplay								= PlayerEvents:WaitForChild("DamageDisplay")
local HudEvents									= PlayerEvents:WaitForChild("HudEvents")
local gunAmmoClipEvent							= HudEvents:WaitForChild("AmmoClipEvent")
local switchDelayEvent							= PlayerEvents:WaitForChild("ToolSwitchDelay")
local effectsFolder								= PlayerEvents:WaitForChild("Effects")
local tracerEvent								= effectsFolder:WaitForChild("BulletTracer")

local Tool										= script.Parent
local ShootEvent								= Tool:WaitForChild("RemoteShoot")
local ReloadEvent								= Tool:WaitForChild("RemoteReload")
local BindableReload							= Tool:WaitForChild("BindableReload")
local Ammo										= Tool:WaitForChild("Ammo")
local ClipSize									= Tool:WaitForChild("ClipSize")
local GunFlash									= Tool:WaitForChild("GunFlash")
local MuzzleFlash								= GunFlash:WaitForChild("MuzzleFlash")
local Handle									= Tool:WaitForChild("Handle")
local ShootSound								= Handle:WaitForChild("ShootSound")
local ReloadSound								= Handle:WaitForChild("ReloadSound")

local Animations								= {
	Idle										= Tool:WaitForChild("Idle")
}

local params									= RaycastParams.new()
params.FilterType 								= Enum.RaycastFilterType.Exclude

local shootDebounce								= false
local shootcooldown								= .3

local maxAmmo 									= 12
local maxClip									= 150
local reloadCd									= 2.25

local currentPlr								= nil
local currentIdleTrack							= nil
local currentToolAttach: Motor6D  				= nil
local currentCharacter: Model					= nil

local minimumDist 								= 25
local baseDmg									= 17

local function getCharacter()
	return Tool.Parent
end

local function handleTracers(owner: Player, start: Vector3, clientStart: Vector3, point: Vector3, color: Color3)
	for _, plr: Player in pairs(game.Players:GetPlayers()) do
		if plr ~= owner then
			tracerEvent:FireClient(plr, start, point, color)
		else
			tracerEvent:FireClient(owner, clientStart, point, color)
		end
	end
end

local function getRandomBulletSpread()
	return Vector3.new(math.random(2975, 3100), math.random(2975, 3000), 1)/10
end

local function getAllCharactersInTeam(team: Team): {Model}
	local characters = {}

	for _, plr: Player in pairs(team:GetPlayers()) do
		if plr.Character then
			table.insert(characters, plr.Character)
		end
	end

	return characters
end

local function reload(plr)
	currentPlr = plr
	
	if shootDebounce or ClipSize.Value <= 0 or Ammo.Value == maxAmmo then
		return
	end

	local properties = currentCharacter:WaitForChild("Properties")
	local equipmentChange: BoolValue = properties:WaitForChild("CanChangeEquipment")
	
	equipmentChange.Value = false
	shootDebounce = true
	ClipSize.Value -= maxAmmo-Ammo.Value
	Ammo.Value = maxAmmo
	
	gunAmmoClipEvent:FireClient(plr, Ammo.Value, ClipSize.Value)
	ReloadEvent:FireClient(plr)
	
	ReloadSound:Stop()
	ReloadSound:Play()
	
	task.wait(reloadCd)
	
	equipmentChange.Value = true
	shootDebounce = false
end

local function shoot(plr: Player, clientPos: Vector3, result: RaycastResult, cast: Ray)
	currentPlr = plr
	
	if shootDebounce then
		return
	end
	
	if Ammo.Value <= 0 then
		reload(plr)
		
		return
	end
	
	local character = getCharacter()
	local head: BasePart = character:WaitForChild("Head")
	local myHRP: Part	= character:WaitForChild("HumanoidRootPart")
	
	local properties = character:WaitForChild("Properties")
	
	shootDebounce = true
	Ammo.Value -= 1
	MuzzleFlash.Enabled = true
	ShootSound:Stop()
	ShootSound:Play()
	currentCharacter = character
	
	print(result)
	local secure, direction = ClientRaySecure:CheckRay(plr, result, cast, getRandomBulletSpread(), {Tool.Parent})
	local hit = nil
	
	if secure then
		hit = secure.Instance
	else
		hit = result.Instance
	end
	
	print(hit)
	
	if hit then
		local model: Model = hit:FindFirstAncestorOfClass("Model")

		if model then
			local humanoid = model:FindFirstChildOfClass("Humanoid")

			if humanoid then
				local enemyPlr = game.Players:GetPlayerFromCharacter(model)
				local isAnEnemy = false

				if enemyPlr then
					if enemyPlr.Team ~= plr.Team then
						isAnEnemy = true

						local eProp: Model = model:WaitForChild("Properties")
						local playerDamagedMe: ObjectValue = eProp:WaitForChild("PlayerDamagedMe")
						playerDamagedMe.Value = plr
					end
				end

				if not enemyPlr then
					isAnEnemy = true
				end

				if isAnEnemy then
					local dmg = baseDmg
					local crit = false

					if hit.Name == "Head" then
						dmg *= 3
						crit = true
					end

					if (direction.Magnitude) > minimumDist then
						dmg -= 5
					end

					dmg = math.round(dmg)

					humanoid:TakeDamage(dmg)
					KBConstructor.new(model:WaitForChild("HumanoidRootPart"), myHRP.CFrame.LookVector.Unit, 25)
					DamageDisplay:FireClient(plr, secure ~= nil and secure.Position or result.Position, crit and true or false, dmg)
				end
			end
		end
	end
	
	handleTracers(plr, GunFlash.Position, clientPos, secure ~= nil and secure.Position or result.Position or GunFlash.Position+direction, plr.TeamColor.Color)
	
	ShootEvent:FireClient(plr)
	gunAmmoClipEvent:FireClient(plr, Ammo.Value, ClipSize.Value)
	
	task.wait(3/60)
	MuzzleFlash.Enabled = false
	
	task.wait(shootcooldown)
	shootDebounce = false
end

Tool.Equipped:Connect(function()
	local character = getCharacter()
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	local rightHand	= character:WaitForChild("RightHand")
	currentToolAttach = rightHand:WaitForChild("ToolAttach")
	currentToolAttach.Part1 = Handle
		
	currentPlr = game.Players:GetPlayerFromCharacter(Tool.Parent)
	params.FilterDescendantsInstances = {character, table.unpack(currentPlr.Team:GetPlayers())}
	
	currentIdleTrack = humanoid:LoadAnimation(Animations.Idle)
	currentIdleTrack:AdjustSpeed(0)
	currentIdleTrack:Play()
	
	gunAmmoClipEvent:FireClient(currentPlr, Ammo.Value, ClipSize.Value)
	
	shootDebounce = true
	task.wait(.15)
	shootDebounce = false
end)

Tool.Unequipped:Connect(function()
	currentToolAttach.Part1 = nil
	
	gunAmmoClipEvent:FireClient(currentPlr, "", "")
	currentIdleTrack:Stop()
	
	ToolSwitchDelay:Fire(currentPlr, Tool)
end)

BindableReload.Event:Connect(reload)
ReloadEvent.OnServerEvent:Connect(reload)
ShootEvent.OnServerEvent:Connect(shoot)

I’m pretty sure the module script isn’t edit but here it is anyway:

local Security 										  		 = {}
Security.MaxOriginDistance									 = 5

--direction = target - origin

function Security:CheckRay(owner: Player, result: RaycastResult, cast: Ray, bulletSpread: Vector3, filter: {Instance})	
	local origin = cast.Origin
	local direction = (cast.Direction.Unit)*bulletSpread
	
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Include
	params.FilterDescendantsInstances = {workspace.Map}
	params:AddToFilter(filter)
	
	local primaryPart = owner.Character.PrimaryPart
	
	if (primaryPart.Position - origin).Magnitude >= Security.MaxOriginDistance then
		origin = primaryPart.Position
	end
	
	local newResult = workspace:Raycast(origin, direction, params)
	
	return newResult, direction
	--[[
		if newresult then something is obstructing the ray
		if not newresult, then the clientRay is secure
	]]--
end

return Security

i think the problem here is that in your security module, in the line that says “params:AddToFilter(filter)” you are adding the tool.Parent to the params’ filterDescendantsInstances, which is set to “Include”, that way making it being detected by the cast.

1 Like

I tested it out and your solution worked! I hate making such simple and silly mistakes…

I’m glad to know it worked! Don’t worry about the silly mistakes. Believe me, they are REALLY common in scripting

1 Like

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