-
What do you want to achieve?
I want to make a combat/punch system along with a dash, you shouldn’t be able to dash and punch at the same time and vice versa. -
What is the issue?
Whenever a player spams the punch and dash in my game it can break the scripts, causing no dash cooldown, no punch cooldown, and other errors. -
What solutions have you tried so far?
I’ve searched the table errors and haven’t found anything too helpful. I also tried to add checks for the table being nil but I don’t really know what I’m doing with that so no help.
The entire systems are comprised of four scripts, two local scripts in StarterPlayerScripts and two scripts in ServerScriptService. Both systems use remote functions to handle debounce server-sided.
CombatScript located in ServerScriptService
--Services
local RS = game:GetService("ReplicatedStorage")
--Variables
local Damage = 5
local Cooldown0 = 0.375
local Cooldown1 = 2
local Debounce = {}
local Remotes = RS:WaitForChild("Remotes")
local Remote = Remotes.PunchFunction
local Remote1 = Remotes.HitEvent
--Functions
local function attackDebounce(Character)
Character:SetAttribute("IsAttacking", true)
task.wait(Cooldown0)
Character:SetAttribute("IsAttacking", false)
end
Remote.OnServerInvoke = function(Player, moveOrder)
local Character = Player.Character
if Character:GetAttribute("IsAttacking") == true or table.find(Debounce, Player.Name) ~= nil or Character:GetAttribute("IsDashing") == true then
print("Server Received!")
return true
else
print("Server Received!")
if moveOrder == 4 then
task.spawn(function()
table.insert(Debounce, Player.Name)
print("Inserted "..Player.Name.." Into Combat Debounce")
print(Debounce)
task.wait(Cooldown1)
Debounce[table.find(Debounce, Player.Name)] = nil
print("Made Combat Debounce Table Nil For "..Player.Name)
end)
else
task.spawn(attackDebounce, Character)
end
return false
end
end
local function damageDebounce(Character, Cooldown)
Character:SetAttribute("CanTakeDamage", false)
task.wait(Cooldown)
Character:SetAttribute("CanTakeDamage", true)
end
local function onServerEvent(Player, hitParts, moveOrder)
for i, v in pairs(hitParts) do
local Character = v.Parent
local Humanoid = Character:FindFirstChild("Humanoid")
if Humanoid ~= nil then
if v.Parent:GetAttribute("CanTakeDamage") == false then
--Already hit
else
--Hit
Humanoid:TakeDamage(Damage)
task.spawn(damageDebounce, Character, Cooldown0)
end
end
end
end
--Events
Remote1.OnServerEvent:Connect(onServerEvent)
DashScript located in ServerScriptService
--Services
local RS = game:GetService("ReplicatedStorage")
--Variables
local Cooldown0 = 0.3
local Cooldown1 = 2
local Debounce = {}
local Remotes = RS:WaitForChild("Remotes")
local Remote = Remotes.RollFunction
--Functions
local function dashDebounce(Player, Character)
table.insert(Debounce, Player.Name)
print("Inserted "..Player.Name.." Into Dash Debounce")
print(Debounce)
Character:SetAttribute("IsDashing", true)
task.wait(Cooldown0)
Character:SetAttribute("IsDashing", false)
task.wait(Cooldown1)
Debounce[table.find(Debounce, Player.Name)] = nil
print("Made Dash Debounce Table Nil For "..Player.Name)
end
Remote.OnServerInvoke = function(Player)
local Character = Player.Character
if Character:GetAttribute("IsDashing") == true or table.find(Debounce, Player.Name) ~= nil or Character:GetAttribute("IsAttacking") == true then
print("Server Received!")
return true
else
print("Server Received!")
task.spawn(dashDebounce, Player, Character)
return false
end
end
CombatSystem located in StarterPlayerScripts
--Services
local Players = game:GetService("Players")
local CAS = game:GetService("ContextActionService")
local RS = game:GetService("ReplicatedStorage")
local workSpace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
--Variables
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local keyBind = Enum.UserInputType.MouseButton1
local Remotes = RS:WaitForChild("Remotes")
local Remote = Remotes.PunchFunction
local Remote1 = Remotes.HitEvent
local Hitboxes = RS:WaitForChild("Hitboxes")
local Animations = {
script.PunchAnimation1,
script.PunchAnimation2,
script.PunchAnimation3,
script.PunchAnimation4
}
local moveOrder = 1
local ttl = 0.3
local timeElapsed = time()
local partsToIgnore = {Character}
local overlapParams = OverlapParams.new()
overlapParams.FilterType = Enum.RaycastFilterType.Exclude
--Functions
local function updatePartsToIgnore()
for i, v in pairs(workSpace:GetChildren()) do
if v:IsA("Model") and v:FindFirstChild("Humanoid") ~= nil then
--Can detect
elseif table.find(partsToIgnore, v) ~= nil then
--Don't add
else
table.insert(partsToIgnore, v)
end
end
print("updatePartsToIgnore Function")
print(partsToIgnore)
end
local function createHitbox(hitbox)
local hitboxClone = hitbox:Clone()
return hitboxClone
end
local function punchFunction(actionName)
local Hitbox = createHitbox(Hitboxes:FindFirstChild(actionName.."Hitbox"))
table.insert(partsToIgnore, Hitbox)
print("After adding hitbox")
print(partsToIgnore)
print(Hitbox)
Hitbox.Parent = workSpace
print(Hitbox.Name)
local Connection = RunService.Heartbeat:Connect(function()
Hitbox.CFrame = Character.HumanoidRootPart.CFrame * CFrame.new(0, 0, -2)
overlapParams.FilterDescendantsInstances = partsToIgnore
local hitParts = workSpace:GetPartBoundsInBox(Hitbox.CFrame, Hitbox.Size, overlapParams)
Remote1:FireServer(hitParts, moveOrder)
end)
local animationTrack = Character.Humanoid.Animator:LoadAnimation(Animations[moveOrder])
animationTrack:Play()
print(Animations[moveOrder])
moveOrder += 1
timeElapsed = time()
task.spawn(function()
task.wait(ttl)
Connection:Disconnect()
partsToIgnore[table.find(partsToIgnore, Hitbox)] = nil
Hitbox:Destroy()
end)
end
local function punchInput(actionName, inputState, inputObject)
if actionName == "Punch" and inputState == Enum.UserInputState.Begin then
local Debounce = Remote:InvokeServer(moveOrder)
if Debounce == true then
print("On Cooldown!")
else
print("Clicked!")
if moveOrder > 4 then
print("Reset To First Animation")
moveOrder = 1
punchFunction(actionName)
elseif (time() - timeElapsed) >= 1 then
print("Reset To First Animation")
moveOrder = 1
punchFunction(actionName)
else
print("Continue As Normal")
punchFunction(actionName)
end
end
end
end
--Events
CAS:BindAction("Punch", punchInput, false, keyBind)
workSpace.ChildAdded:Connect(updatePartsToIgnore)
DashSystem located in StarterPlayerScripts
--Services
local Players = game:GetService("Players")
local CAS = game:GetService("ContextActionService")
local RS = game:GetService("ReplicatedStorage")
--Variables
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local keyBind = Enum.KeyCode.Q
local Remotes = RS:WaitForChild("Remotes")
local Remote = Remotes.RollFunction
local Animation = script.DashAnimation
local animationTrack = Character.Humanoid.Animator:LoadAnimation(Animation)
local ttl = 0.2
--Functions
local function rollInput(actionName, inputState, inputObject)
if actionName == "Roll" and inputState == Enum.UserInputState.Begin then
local Debounce = Remote:InvokeServer()
if Debounce == true then
print("On Cooldown!")
else
print("Pressed Q!")
animationTrack:Play()
local Character = Player.Character
local HRP = Character.HumanoidRootPart
local lvel = Instance.new("LinearVelocity")
lvel.Parent = HRP
lvel.Attachment0 = HRP:FindFirstChild("RootAttachment")
lvel.ForceLimitMode = Enum.ForceLimitMode.PerAxis
lvel.MaxAxesForce = Vector3.new(math.huge, 0, math.huge)
lvel.VectorVelocity = HRP.CFrame.LookVector * 75
task.delay(ttl, function()
lvel:Destroy()
end)
end
end
end
--Events
CAS:BindAction("Roll", rollInput, false, keyBind)
I HAVE been able to replicate this in singleplayer, but it happens far more frequently in team test multiplayer.
Any additional info necessary just let me know.