I understand that there is upcoming API, but as i am a relatively new scripter. I still dont quite understand how to properly setup the hitbox even with the api listed above, if at some point you will have a noob friendly up to date api I would love to understand how it works!
Hi I’ve started implementing ShapecastHitbox into my game and I love the plugin too. Thank you for making something so amazing. I just have a bug that I can’t seem to get around with how OnHit() works with HitStop()
From one of my client scripts I’m passing in multiple parameters like combo, chargeLevel, etc which are used in calculating final damage in a server script. For some reason even when calling HitStop(), it seems like the OnHit() connection only uses the variables passed on the very first creation of the OnHit() listener. I’ve tried assigning it to a connection variable but it won’t allow me to disconnect it as it’s not a connection object being made in the first place.
The only way I’ve managed to get around this is destroying and recreating the hitbox on every call, but this feels like it would be very unoptimized especially when player counts get larger. Is this intended or is there something I’m missing? Below is the code.
Thank you so much for your hard work! I look forward to future updates.
type or paste code herefunction HitboxClient.CreateGearHitbox(hitboxPart, typeSort, dualWielding)
if not dualWielding then
if HitboxClient.weaponHitbox then HitboxClient.weaponHitbox:Destroy() end
local gearHitbox = shapeCastHitbox.new(hitboxPart)
HitboxClient.weaponHitbox = gearHitbox
else
if HitboxClient.weaponDualWieldHitbox then HitboxClient.weaponDualWieldHitbox:Destroy() end
local gearHitbox = shapeCastHitbox.new(hitboxPart)
HitboxClient.weaponDualWieldHitbox = hitboxPart
end
end
function HitboxClient.StartMeleeHit(lightOrHeavy : string, combo : number, invID : number, chargeLevel : number)
local hitbox : shapeCastHitbox.Hitbox = HitboxClient.weaponHitbox
local targetsHit = HitboxClient.targetsHit
hitbox:HitStart():OnHit(function(raycastResult, segmentHit : shapeCastHitbox.Segment)
local playerTargetHit = raycastResult.Instance.Parent:FindFirstChild("Humanoid")
local enemyNPCTargetHit = raycastResult.Instance.Parent:FindFirstChild("NPC")
if targetsHit[playerTargetHit] == true then return end
if targetsHit[enemyNPCTargetHit] == true then return end
if playerTargetHit then
-- TODO FIX CONNECETION ISSUE HITBOX KEEPS REUSING OLD HITSTART
targetsHit[playerTargetHit] = true
signal.FireServer("CharacterCombatServer:MeleeHitPlayer", playerTargetHit, lightOrHeavy, combo, raycastResult.Position, invID, chargeLevel)
end
if enemyNPCTargetHit then
targetsHit[playerTargetHit] = true
-- TODO
end
end)
end
function HitboxClient.StopMeleeHit()
local hitbox = HitboxClient.weaponHitbox
table.clear(HitboxClient.targetsHit)
hitbox:HitStop()
end
Hi there, have you tried using OnStopped callback? It has a parameter that will auto clean up every callbacks used so far, which should fix your issue. You can chain it anywhere as well.
hitbox:HitStart():OnHit():OnStopped(function(cleanCallbacks)
-- Will clean up the callbacks. Next iteration of hitbox called will only happen once.
cleanCallbacks()
end)
Thank you that fixed it! If I could just ask one more question about segment hit and raycast Result thats returned from OnHit(). In my server sanity checks, I’m checking both that the hitbox part the DmgPoints are parented to is near the character model hit and also that the blockcast that hit the character model is in range of the hitbox part to a reasonable degree. Is raycastResult position the parameter I should be sending over for that? I’m worried that exploiters will modify the size of the block cast coming from each DmgPoint attachment on the hitbox.
Thank you once again.
-- 3. Tight distance check from hitbox to target
local validHitbox
local validSegment
for _, hitbox in weaponHitboxPart do
if (weaponHitboxPart.Position - targetHRP.Position).Magnitude > MAX_TIGHT_HITBOX_DISTANCE then
warn(playerAttacker.Name .. hitbox .. " flagged: Weapon hitbox too far from target")
continue
else
-- One hitbox was valid
validHitbox = true
end
-- 4. Segment hit position must lie within hitbox bounds (w/ padding)
local hitboxCFrame = weaponHitboxPart.CFrame
local relativeHitPos = hitboxCFrame:PointToObjectSpace(raycastResult.Position)
local halfSize = weaponHitboxPart.Size / 2
-- Clamp the hit position to the hitbox's local bounds
local clamped = Vector3.new(
math.clamp(relativeHitPos.X, -halfSize.X, halfSize.X),
math.clamp(relativeHitPos.Y, -halfSize.Y, halfSize.Y),
math.clamp(relativeHitPos.Z, -halfSize.Z, halfSize.Z)
)
-- Compute how far outside the hit was
local outsideDistance = (relativeHitPos - clamped).Magnitude
-- If outside the shell padding, flag the player
if outsideDistance > HITBOX_PADDING then
warn(playerAttacker.Name .. hitbox .. " flagged: Segment hit position outside hitbox (softshell)")
continue
else
-- One segment was valid
validSegment = true
end
end
if not (validHitbox and validSegment) then
warn(playerAttacker.Name .. " flagged: Hitbox cheating")
CharacterCombatAntiCheat.addCheatFlag(playerAttacker)
end
So i have this bug where the hitbox cast continues from where i last activated it, in the picture you can see it cast for like 30 studs, the only way around it is to destroy and make the hitbox again and again… is there a way to clean this up?
hitbox:BeforeStart(function()
self.Duration = 0.5
hitbox.Active = true
end):HitStart(self.Duration):OnHit(function(raycastResult, segmentHit)
if hitbox.Active then
hitbox.Active = false
local hitCharacter = raycastResult.Instance.Parent
print(Player:DistanceFromCharacter(hitCharacter.HumanoidRootPart.Position))
--print("hit "..hitCharacter.Name)
hitbox:HitStop()
end
end):OnUpdate(function(deltaTime)
end):OnStopped(function(cleanCallbacks)
cleanCallbacks() --- This will clean up this chain
end)
Yes, you can send the position, but it’ll require a bit more effort to sanity check that.
You can also send the segment instance instead.
hitbox:OnHit(function(raycastResult, segment)
-- Of course edit this
signal:Fire(segment.Instance)
end)
The segment instance references the actual DmgPoint attachment, and you can take the position, size, and radius attributes directly from the instance for sanity checks rather than relying on client given values.
Of course, the client can still spoof which instance it can send over, so take note of that. Segment doesn’t really give you where the player has hit exactly, but I assume you’ll be checking the range anyway so it should still fit the bill.
sorry for the mega late reply, in general i am simply not understanding how the api works, maybe im looking at it wrong. Yes i also did check the playground, i hear that it might be outdated compared to newer updates but im not 100% sure.
anyways my general issue was that the api wasnt easy to follow and Im not an expert by any means, so if theres a way that could help me out regarding the api issue that would be awesome : D