ClientCast - A Client-based, Idiosyncratic Hitbox System!

Hello! I’m also using this module for my game, it’s awesome! But there’s a small issue. Sometimes appears a error: “Player appears to be spamming remote events.” And it’s causing lag i guess. How can i fix that error?
or am i doing something wrong.

Hello, this is due to remote connections disconnecting when you destroy clientcaster objects, and so the client ends up sending hitbox data to remotes that aren’t being listened to. It is recommended to instead destroy a clientcaster only a character despawns, and use :Stop() otherwise.

1 Like

This module is really useful, but I’ve been having issues with high ping players being unable to hit anything with it. Currently I’m using a tool that sends a remote event to the server, that then stops and starts the hitbox, however with high ping the hitbox does not appear when its supposed to, and due to this it can basically never register hits. Any possible solutions?

Im trying to use this as a reliable hitbox for my game’s melee weapons and it works perfectly in Roblox Studio, but I found some problems in game
If I make the server be the caster owner the hitbox sometimes wont detect hits on 150+ ping, but if I set the caster owner to the player it simply doesnt register any hits
I tried everything and managed to find that if I extend the duration of the hit(which is 0.225s normally) to atleast 0.7 seconds the hitbox works but delayed
imagen
imagen

Anyone knows what could be happening?
the combat test is here if you want to check, but it has other things like running and stamina so I will try to make another place only to replicate this “bug”

Awesome Resource!
I’ve been having issues with Raycasting Hitboxer v4.1, for some reason the rays would lag behind the player if they were moving and weren’t always consistent. I’m not sure if it’s cause the way I set them up was wrong, but either way ClientCast was a lot easier to set up and it 10x more consistent. I highly recommend if anyone is having issues with Raycast Hitboxes.

External Media
1 Like

What could be causing this error?

This is my script

----| Client Cast Init |----

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

local ClientCast = require(ServerStorage:WaitForChild("ClientCast"))

----|| Meta Table Set-Up ||----

local Players = game:GetService("Players")

local PlayerProfile = {}
PlayerProfile.__index = PlayerProfile

-- Function to create a new player profile
function PlayerProfile.new(player)
	local self = setmetatable({}, PlayerProfile)
	self.Player = player
	self.Character = player.Character or player.CharacterAdded:Wait()
	self.Weapons = {}
	self.LastAttackTime = {}
	self.ClientCastInfo = {}
	self.Class = "Worker"
	print("Profile created for player: " .. player.Name)
	return self
end

----| Client Cast Functions |----

function PlayerProfile:BeginClientCast(dmgPart, player)
	if not dmgPart then
		warn("dmgPart is nil for player " .. self.Player.Name)
		return
	end

	if not dmgPart:IsA("BasePart") then
		warn("dmgPart is not a valid BasePart for player " .. self.Player.Name)
		return
	end

	local character = self.Character
	local weapon = dmgPart
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {weapon, character}
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude

	local Caster = ClientCast.new(weapon, raycastParams, player)
	Caster:StartDebug()
	Caster:SetOwner(player)
	Caster:Start()
	
	

	-- Store the client cast info in the profile
	self.ClientCastInfo[weapon.Name] = {
		Caster = Caster,
		RaycastParams = raycastParams
	}

	print("SUCCESS! Client cast started for " .. weapon.Name)

	Caster.Collided:Connect(function()
		print("Collision detected for " .. weapon.Name)
		-- Implement hit logic here
	end)
end

----|| Profile Set-Up ||----

local playerProfiles = {}

-- Function to handle character spawning
local function onCharacterAdded(player, character)
	print("Character added for player: " .. player.Name)
	local profile = playerProfiles[player.UserId]
	if not profile then
		warn("Profile not found for player " .. player.Name)
		return
	end

	profile.Character = character

	-- Check player class and give appropriate weapon
	if profile.Class == "Worker" then
		local axe = ReplicatedStorage:FindFirstChild("Axe")
		if axe then
			print("Axe found in ReplicatedStorage for player " .. player.Name)
			local clonedAxe = axe:Clone()
			clonedAxe.Name = "PlayerAxe"  -- Rename the cloned axe to avoid confusion
			clonedAxe.Parent = character
			local damagePart = clonedAxe:WaitForChild("DamagePart")
			if damagePart then
				profile:BeginClientCast(damagePart, player)
				print("DamagePart found in cloned Axe for player " .. player.Name)
				print("Axe cloned and parented to character for player " .. player.Name)
			else
				warn("DamagePart not found in cloned Axe for player " .. player.Name)
			end
		else
			warn("Axe not found in ReplicatedStorage for player " .. player.Name)
		end
	end

	print(player.Name .. " is ready to play.")
end

-- Function to handle player addition
local function onPlayerAdded(player)
	print("Player added: " .. player.Name)
	local profile = PlayerProfile.new(player)
	playerProfiles[player.UserId] = profile

	-- Ensure CharacterAdded event is handled for existing characters
	if player.Character then
		onCharacterAdded(player, player.Character)
	end

	-- Listen to CharacterAdded event
	player.CharacterAdded:Connect(function(character)
		onCharacterAdded(player, character)
	end)
end

-- Function to handle player removal
local function onPlayerRemoving(player)
	local profile = playerProfiles[player.UserId]
	playerProfiles[player.UserId] = nil
end

----|| Connections ||----

Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)

The object on the client has not yet loaded - likely because you are using streaming enabled. The client needs to wait for the hitbox part to be streamed in first.

2 Likes

Thanks. I was able to fix it by doing wait(2) like you’ve recommended to someone else. I wanted to ask you - is that okay, or would you recommend another fix? What if it takes longer than 2 seconds to load under high server or client stress?

if you want to be 100% sure, you can have the client fire a remote when its hitbox part has loaded - and only then should the server start the hitbox.

1 Like

How would I listen for the remote when the hitbox part has loaded? Kind of a noob at coding, but would appreciate your help a lot

What could be causing this issue? I’ve spent about 7-8 hours today trying to fix it, I basically studied your whole module back and forth. This happens only after player respawns, and then hits something (moment when humanoidcollided event is fired

This seems to happen at random times, so more often than not - on second respawn, this error throws after a hit, I think something related to collided event listener. Sometimes, it can go as far as 5th respawn. Raycast itself seems to work fine, and I can continue playing as normal.

In my game, I destroy ClientCaster, and then make a new ClientCaster object - as well as clone new tool from serverstorage, and parent it under player again.

1 Like

I’m having a small problem. The hitbox does not seem to… collide,. It starts and stops properly, the debug lines show, but it simply does not collide. This is my script:

local weapon = {}
weapon.__index = weapon
local client_cast_module = require(script.Parent.ClientCast)
function weapon.new(tool, player)
	local character = player.Character
	local raycast_params = RaycastParams.new()
	raycast_params.FilterDescendantsInstances = {character, tool}
	raycast_params.FilterType = Enum.RaycastFilterType.Exclude
	local client_caster = client_cast_module.new(tool, raycast_params)
	client_caster:SetOwner(player)
	return setmetatable({
		tool = tool,
		attack_duration = .5,
		client_caster = client_caster
	}, weapon)
end
function weapon:init()
	local debounce = {}
	self.client_caster.Collided:Connect(print) -- doesnt print
	self.client_caster.HumanoidCollided:Connect(function(raycast_result, humanoid)
		print("Hit") -- doesnt print
		if debounce[humanoid] then return end
		debounce[humanoid] = true
		task.delay(self.attack_duration, function()
			debounce[humanoid] = false	
		end)
		
		humanoid:TakeDamage(10) -- constant for debugging
	end)
	self.tool.Activated:Connect(function()
		self.client_caster:Start() -- does start
		task.delay(self.attack_duration, function()
			self.client_caster:Stop() -- does stop
		end)
	end)
end
return weapon

(I’m using the latest version of the module from github)

Update:
Apparently the module didn’t like that I gave it a tool. The collision detection part of it at least

@PysephDEV I think I found a bug. I’ve tested a lot to see if the problem was caused by me. I don’t think it is. I noticed that whenever I tested the game outside of studio, the hitbox acts strange. Hits down right don’t get registered for whatever reason. In studio it works fine. I can isolate the scripts and create a .rblx file if you want to take a look at it, but It’s a lot of code to isolate, so I want to make sure you’re willing to help me debug this in the first place.

Update:
Noticed something when I join the game. The client is getting this error: “multiple stylelinks under coregui may result in undefined behaviour”. I’m not sure if its relevant, but it’s an error I’m getting exclusively when I join the game. Thought its worth mentioning.

1 Like

What if the hitbox does not move, like player activate a skill, like the skill hitbox must move “slightly” in order to use this system?