My hitbox system doesn’t work because it apparently has a cyclic table references and I can’t find out where
My code:
local Hitbox = {}
local Metatable = {__index = Hitbox}
local ClientCast = require(script:WaitForChild("ClientCast"))
local AttachmentFunctions = require(script:WaitForChild("AttachmentFunctions"))
local RunService = game:GetService("RunService")
type self = {
Size : Vector3,
CFrame : CFrame,
HitboxPart : Part,
Caster : any,
DebounceWaitTime : number,
SanityCheckRange : number,
onTouch : (Humanoid) -> nil?,
Debounces : {Humanoid}
}
export type HitboxType = typeof(setmetatable({} :: self, Metatable))
function Hitbox.new (cFrame : CFrame, size : Vector3, onTouch : (Humanoid) -> nil?, autoCalcDensity : boolean?, lifetime : number?): HitboxType
local self = setmetatable({} :: self, Metatable)
self.CFrame = cFrame
self.Size = size
local HitboxPart = Instance.new("Part")
HitboxPart.CFrame = self.CFrame
HitboxPart.Size = self.Size
HitboxPart.Parent = workspace
HitboxPart.Name = "HitboxPart"
HitboxPart.Color = Color3.new(1, 0.431373, 0.431373)
if RunService:IsStudio() then
HitboxPart.Transparency = 0.5
else
HitboxPart.Transparency = 1
end
HitboxPart.Anchored = true
HitboxPart.CanCollide = false
HitboxPart.Massless = true
self.HitboxPart = HitboxPart
local oldDensity
if autoCalcDensity then
oldDensity = AttachmentFunctions.CalculateSuitableDensity(HitboxPart)
end
AttachmentFunctions.GenerateAttachmentsVolume(HitboxPart)
if oldDensity then
AttachmentFunctions.Density = oldDensity
end
print(HitboxPart)
task.wait(0.005)
local Caster = ClientCast.new(HitboxPart, RaycastParams.new())
self.Caster = Caster
self.Debounces = {}
self.DebounceWaitTime = 0.5
self.SanityCheckRange = 5
self.onTouch = onTouch
self.Caster.HumanoidCollided:Connect (function(raycastResult : RaycastResult, humanoid : Humanoid)
if self:GetOwner() ~= nil then
warn("Hitbox has a player named ", self:GetOwner().Name)
local owner = self:GetOwner()
local character = owner.Character
local hrp = character:WaitForChild("HumanoidRootPart") :: BasePart
if (humanoid.RootPart.Position.Magnitude - hrp.Position.Magnitude) > self.SanityCheckRange then
warn("Most likely an exploiter")
return
end
else
warn("Hitbox doesn't have a player")
end
if not self.Debounces[humanoid] and onTouch ~= nil then
self.Debounces[humanoid] = true
self.onTouch(humanoid)
-- wait until stop touching
task.wait(1.25)
self.Debounces[humanoid] = false
end
end)
if lifetime then
self:Start()
task.delay(lifetime, function()
self:Destroy()
end)
end
return self
end
function Hitbox.SetOwner (self : HitboxType, player : Player?)
self.Caster:SetOwner (player)
if player then
local newRaycastParams = RaycastParams.new()
newRaycastParams.FilterDescendantsInstances = {player.Character}
newRaycastParams.FilterType = Enum.RaycastFilterType.Exclude
self.Caster:EditRaycastParams (newRaycastParams)
end
end
function Hitbox.EditRaycastParams (self : HitboxType, newRaycastParams : RaycastParams)
self.Caster:EditRaycastParams (newRaycastParams)
end
function Hitbox.SetSize (self : HitboxType, size : Vector3)
self.Size = size
self.HitboxPart.Size = size
end
function Hitbox.SetCFrame (self : HitboxType, cframe : CFrame)
self.CFrame = cframe
self.HitboxPart.CFrame = self.CFrame
end
function Hitbox.GetOwner (self : HitboxType) : Player?
return self.Caster:GetOwner ()
end
function Hitbox.Start (self : HitboxType)
self.Caster:Start()
end
function Hitbox.Stop (self : HitboxType)
self.Caster:Stop()
end
function Hitbox.WeldTo (self : HitboxType, part : BasePart)
self.HitboxPart.CFrame = part.CFrame
local weld = Instance.new("WeldConstraint")
weld.Parent = self.HitboxPart
weld.Name = "HitboxWeld"
weld.Part0 = part
weld.Part1 = self.HitboxPart
self.HitboxPart.Anchored = false
end
function Hitbox.Unweld (self : HitboxType)
if self.HitboxPart:FindFirstChild("HitboxWeld") then
self.HitboxPart:FindFirstChild("HitboxWeld"):Destroy()
self.HitboxPart.Anchored = true
end
end
function Hitbox.Destroy (self : HitboxType)
self.Caster:Destroy()
self.HitboxPart:Destroy()
setmetatable(self, nil)
end
return Hitbox
This is what client cast is: ClientCast - A Client-based, Idiosyncratic Hitbox System!
and this is the attachment functions module:
local AttachmentFunctions = {}
AttachmentFunctions.Density = 1.5
local RunService = game:GetService("RunService")
-- Higher values mean less attachments
-- Less attachments means more attachments
function AttachmentFunctions.GenerateAttachmentsDominantAxis (part : Part)
-- negative is start pos is end
local lAxis = math.max (part.Size.X, part.Size.Y, part.Size.Z) -- Find which axis is the largest
if lAxis == part.Size.X then
local sPos = (part.Position - Vector3.new(part.Size.X / 2)).X
local ePos = (part.Position + Vector3.new(part.Size.X / 2)).X
for x = sPos, ePos, AttachmentFunctions.Density do
local attachment = Instance.new("Attachment")
attachment.Parent = part
attachment.WorldPosition = Vector3.new(x, part.Position.Y, part.Position.Z)
attachment.Name = "DmgPoint"
if RunService:IsStudio() then
attachment.Visible = true
end
end
elseif lAxis == part.Size.Y then
local sPos = (part.Position - Vector3.new(0, part.Size.Y / 2, 0)).Y
local ePos = (part.Position + Vector3.new(0, part.Size.Y / 2, 0)).Y
for y = sPos, ePos, AttachmentFunctions.Density do
local attachment = Instance.new("Attachment")
attachment.Parent = part
attachment.WorldPosition = Vector3.new(part.Position.X, y, part.Position.Z)
attachment.Name = "DmgPoint"
if RunService:IsStudio() then
attachment.Visible = true
end
end
elseif lAxis == part.Size.Z then
local sPos = (part.Position - Vector3.new(0, part.Size.Z / 2, 0)).Z
local ePos = (part.Position + Vector3.new(0, part.Size.Z / 2, 0)).Z
for z = sPos, ePos, AttachmentFunctions.Density do
local attachment = Instance.new("Attachment")
attachment.Parent = part
attachment.WorldPosition = Vector3.new(part.Position.X, part.Position.Y, z)
attachment.Name = "DmgPoint"
if RunService:IsStudio() then
attachment.Visible = true
end
end
end
end
function AttachmentFunctions.CalculateSuitableDensity (part : Part)
local oldDensity = AttachmentFunctions.Density
local lAxis = math.max (part.Size.X, part.Size.Y, part.Size.Z) -- Find which axis is the largest
if lAxis == part.Size.X then
Density = part.Size.X / 20
elseif lAxis == part.Size.Y then
Density = part.Size.Y / 20
elseif lAxis == part.Size.Z then
Density = part.Size.Z / 20
end
return oldDensity
end
function AttachmentFunctions.GenerateCenterAttachment (part : Part)
local attachment = Instance.new("Attachment")
attachment.Parent = part
attachment.WorldPosition = Vector3.new(part.Position.X, part.Position.Y, part.Position.Z)
attachment.Name = "CenterPoint"
if RunService:IsStudio() then
attachment.Visible = true
end
end
function AttachmentFunctions.GenerateAttachmentsVolume (part : Part)
local count = 0
local hX, hY, hZ = part.Size.X / 2, part.Size.Y / 2, part.Size.Z / 2
local estimatedAttCount = hX * hY * hZ
for x = -hX, hX, AttachmentFunctions.Density do
for y = -hY, hY, AttachmentFunctions.Density do
for z = -hZ, hZ, AttachmentFunctions.Density do
local attachment = Instance.new("Attachment")
attachment.Parent = part
attachment.Position = Vector3.new(x, y, z)
attachment.Name = "DmgPoint"
if RunService:IsStudio() then
attachment.Visible = true
end
count += 1
end
end
end
print("estimation: ", estimatedAttCount)
print("actual count: ", count)
end
return AttachmentFunctions
And I’m sending these hitbox objects over bindable events.
Any help is appreciated