ClientCast - A Client-based, Idiosyncratic Hitbox System!

I am making a fists tool with this that has a left and a right punch. I want to make this so there are two different hitboxes depending on which punch animation is being used, so I’ve created two casters and I start and stop an individual one when they’re needed. However, both casters seem to start when I intend to start only one. Is the module not supposed to be used like this, or is there a workaround?

This seems like an issue with your code. I’m not able to help you further without seeing a decently large snippet of code, but from the information at hand, it shouldn’t be an issue with the module.

What are the benefit’s for me switching to this module? Is it better for the user experience if its client side instead of server? For example, this is my current server side code for hitboxes. It might be bad but it does the job alright.

local ServerSideHandler = coroutine.wrap(function()
	
	while task.wait(0.009) do
		
		for i,v in pairs(AllRunningHitBoxes) do
			
			local player = v.player
			local playercharacter = v.player.Character
			
			for i,v in pairs(workspace:GetPartsInPart(v.hitboxpart)) do
				
				if not v:IsDescendantOf(playercharacter) then
					
					if (tick() - PlayerStates[player.Name].M1Frame) > 0.4 then
						
					print("hit")
						
					PlayerStates[player.Name].M1Frame = tick()
						
					end
					
				end
				
			end
			
		end
		
	end
	
end)

ServerSideHandler()

Your questions are already answered in the thread, please be more specific as to what issues you have with the module.

I found a workaround to my issue. However, an error pops up randomly and I’m wondering what it means.
https://i.imgur.com/2CMUcR4.png

Did you set AutoSetup to false in the Settings table by any chance? This error should only be happening if you set it to false.

Nope, I’ve never changed the AutoSetup value. Disregard the first edit I made.

That error shouldn’t be occurring if you haven’t changed the AutoSetup value. If possible, could you provide a minimal place file in which this error occurs? It would help greatly in fixing the issue.

Updates 1.0.8.3 - 1.0.8.5

  • Added checks for if a descendant connection exists before disconnecting it.

  • Added a one-second debounce for disconnecting a remote-event connection, in order to prevent potential remote packet exhaustion. Thank you @Bizarre_Amar for the help in recognizing the issue!

  • Added a check to make sure the Caster is still enabled at the time of receiving the remote packet data.

If the Caster Owner is set to the client, you’d use this for anti-cheat.

Caster.Collided:Connect(function(Data)
    if (Data.Position - Caster.Object.Position).Magnitude > 5 then
        return print("very likely an exploiter")
    end
end)

Is there a way to send the HitHumanoid directly to the Server since the server does the calculations to prevent exploiters? Because people can just call the remote function that sends the Hit Humanoid to the server.

1 Like

Yes, hence the need for a distance-check. An exploiter could send false hit data from the client to the server, which is unwanted behavior.
If you want to also have the humanoid which was hit sent to the server, see Caster.HumanoidCollided.

I’d like to clarify on a few matters:

  1. Minimizing exploitability is a pipe dream as it stands now anyway - even if you calculate hitboxes on the server, what prevents a client from simply teleporting their character around instead? If teleported at small distances around a target mob, the server won’t be able to detect it as a speed exploit.

  2. As mentioned in the original post, this trades security for client responsiveness & UX, creating for more visually-accurate hitboxes.

I have a question, I am unable to make my ClientCast work properly when the client cast starts everything but the damage portion works, it’s not detecting the humanoid of other players/dummies, therefore, it’s not doing any damage. Here’s my code please let me know what I’m doing wrong?

game.Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		
		print('CharacterAdded')
		
		
		local PropWep = WepFolder.PropWep:Clone()
		PropWep:SetPrimaryPartCFrame(Character.UpperTorso.CFrame * CFrame.new(0,0,-0.60))
		PropWep.Parent = Character

		local Motor6D = Instance.new('Motor6D')

		Motor6D.Name = "HandWeld"
		Motor6D.Part0 = Character.PrimaryPart
		Motor6D.Part1 = PropWep.PrimaryPart
		Motor6D.C0 = CFrame.new(Vector3.new(0,0,0.60)) * CFrame.Angles(0,0,math.rad(45))
		Motor6D.Parent = PropWep

		
		
		
		
		local raycastparams = RaycastParams.new()
		local Debounce = {}
		
		
		raycastparams.FilterDescendantsInstances = {Character}
		raycastparams.FilterType = Enum.RaycastFilterType.Blacklist
		ClientCaster = ClientCast.new(PropWep, raycastparams)
		local Character = Player.Character or Player.CharacterAdded:Wait()

		
		
		ClientCaster.Collided:Connect(function(RaycastResult, HitHumanoid)
			print('before')
			if IsEquipped and debounce[HitHumanoid] then
				return
			end
			print('After')

			debounce[HitHumanoid] = true
			IsEquipped = true
			HitHumanoid:TakeDamage(10)

			wait(0.5)

			debounce[HitHumanoid] = false
			IsEquipped = false
			
			
			print('Swing')


		end)
		
		ClientCaster:Start()
		ClientCaster:StartDebug()
		
	end)

end)

Hello, you should be using HumanoidCollided and not Collided.

I’ve tried both ways neither work

I recommend you isolate as much of your code as possible and make a script which reproduces the issue in as little lines as possible. From there, it will be easier to see what the bug is.

I appreciate you so much for this! This is absolutely awesome. Can i ask a question? Where does this script go?

-- Call module
local ClientCast = require(PATH.ClientCast)
-- Create ClientCaster object
local Caster = ClientCast.new(workspace.Part, RaycastParams.new())

-- Connect callback to 'Collided' event
Caster.Collided:Connect(print)
-- Set owner of ClientCaster, who will be the one to calculate collisions.
-- You can skip this if you want the server to be the owner.
Caster:SetOwner(Player)
-- Start detecting collisions
Caster:Start()

i was reading your post on github and i dont really understand where to put this script at. Any help is greatly appreciated.

You can place it either in ReplicatedStorage or ServerStorage.

Forgive me if im not the smartest but if im doing it correctly:

The clientcast module script goes in “ServerStorage”

-- Call module
local ClientCast = require(PATH.ClientCast)
-- Create ClientCaster object
local Caster = ClientCast.new(workspace.Part, RaycastParams.new())

-- Connect callback to 'Collided' event
Caster.Collided:Connect(print)
-- Set owner of ClientCaster, who will be the one to calculate collisions.
-- You can skip this if you want the server to be the owner.
Caster:SetOwner(Player)
-- Start detecting collisions
Caster:Start()

this script goes in “serverstorage”

local ClientCast = require(game.ServerStorage.ClientCast)

local KillPart = Instance.new('Part')
KillPart.Anchored = true
KillPart.CanCollide = false
KillPart.CFrame = CFrame.new(0, 1, 0)
KillPart.Parent = workspace

function GenerateAttachment(Position)
	local Attachment = Instance.new('Attachment')
	Attachment.Name = 'DmgPoint'
	Attachment.Position = Position
	Attachment.Parent = KillPart
end

for X = -2, 2 do
	GenerateAttachment(Vector3.new(X, Y, Z))
end

local ClientCaster = ClientCast.new(KillPart, RaycastParams.new())
local Debounce = {}
ClientCaster.HumanoidCollided:Connect(function(RaycastResult, HitHumanoid)
	if Debounce[HitHumanoid] then
		return
	end
	Debounce[HitHumanoid] = true
	print('Ow!')
	HitHumanoid:TakeDamage(10)
	
	wait(0.5)
	Debounce[HitHumanoid] = false
end)
ClientCaster:Start()

and this script goes in serverscriptservice i believe?
Then i just add DmgPoints as attachments.

How could i make it so that the ClientCaster can only hit 1 person instead of multiple?