What do you want to achieve?
I’m trying to make client sided combat
What is the issue?
The player character has an attribute called state, the server script shouldnt run if the state isn’t Idle but it does. The server script works if the task.wait is 1 but it doesn’t if it’s .5
you can see here I press twice and attack works even thought it prints it can’t
local script
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local uips = game:GetService("UserInputService")
local remote = game.ReplicatedStorage.RemoteEvent
uips.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
local state = character:GetAttribute("State")
local torso = character.HumanoidRootPart
if state ~= "Idle" then print("Cant hit") return end
local overlap = OverlapParams.new()
overlap.FilterDescendantsInstances = {character}
overlap.FilterType = Enum.RaycastFilterType.Exclude
local attacklist = {}
local heart = game:GetService("RunService").Heartbeat:Connect(function()
local hitbox = workspace:GetPartBoundsInBox(torso.CFrame + torso.CFrame.LookVector*4, Vector3.new(5,4,5), overlap)
for i,v in hitbox do
local opponent = v.Parent:FindFirstChild("Humanoid")
if opponent then
attacklist[opponent.Parent.Name] = opponent.Parent
end
end
remote:FireServer(attacklist)
end)
task.wait(1)
heart:Disconnect()
end
end)
server script
local remote = game.ReplicatedStorage.RemoteEvent
local players = game:GetService("Players")
players.PlayerAdded:Connect(function(newplayer)
local character = newplayer.Character or newplayer.CharacterAdded:Wait()
character:SetAttribute("State", "Idle")
end)
remote.OnServerEvent:Connect(function(player, attacklist)
local character = player.Character
local state = character:GetAttribute("State")
if state ~= "Idle" then return end
print("attacking", state)
for i,v in attacklist do
local opponentstate = v:GetAttribute("State")
if opponentstate == "Evade" then return end
v.Humanoid:TakeDamage(10)
end
character:SetAttribute("State", "Attack")
task.wait(.5) -- doesn't work if it's .5 but works if it's 1
character:SetAttribute("State", "Idle")
end)
I don’t think its because of the heartbeat, if you look at the video at 2 seconds and pause the heartbeat is still running yet when I double click the heartbeat is still running, it prints it cant but it still does attack and the state attribute is still Attack. This is just debugging code, so I can make it work, I have a debounce on the more complicated one and same issue.
Also setting attributes on the client doesnt replicate which would cause issues if I want to check the states on the server and the client could exploit it.
I tried to print the state in the local script of the character and it seems it never updates on the client, I tried adding a while true do loop in the server and printing the characters state on the server, and in the local script I print the characters state too, in the local script it seems to always be Idle.
you can see in the video that the local script only prints Idle, and the serverscript prints it changed and it resets back to default, as it prints returned to idle.
local script
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character.Humanoid
local uips = game:GetService("UserInputService")
local remote = game.ReplicatedStorage.RemoteEvent
uips.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.F then
local torso = character.HumanoidRootPart
local state = character:GetAttribute("State")
local overlap = OverlapParams.new()
overlap.FilterDescendantsInstances = {character}
overlap.FilterType = Enum.RaycastFilterType.Exclude
local heart = game:GetService("RunService").Heartbeat:Connect(function()
print(state)
local hitbox = workspace:GetPartBoundsInBox(torso.CFrame + torso.CFrame.LookVector*4, Vector3.new(5,4,5), overlap)
for i,v in hitbox do
end
remote:FireServer()
end)
task.wait(1)
heart:Disconnect()
end
end)
server script
local remote = game.ReplicatedStorage.RemoteEvent
local player = game.Players
player.PlayerAdded:Connect(function(newplayer)
local character = newplayer.Character or newplayer.CharacterAdded:Wait()
character:SetAttribute("State", "Idle")
while true do
task.wait()
print("server state", character:GetAttribute("State"))
end
end)
remote.OnServerEvent:Connect(function(player)
local character = player.Character
local state = character:GetAttribute("State")
if state ~= "Idle" then return end
--print("Attack", state)
character:SetAttribute("State", "Attack")
wait(1)
character:SetAttribute("State", "Idle")
print("returned to idle")
end)
my mistake, the local state is changing if I print the updated character:GetAttribute() but what I’m still confused is even though the local and server is changing, if I double press attack it will work even though it should return because it’s already attacking.
I press twice here, and it prints Attack Idle twice even though it shouldnt
if I put a if state ~= Idle on the local script the extra Attack doesnt run, but I think the player would be able to hack and remove the if statement, I’m not sure why it doesnt return in the server script
Thanks for your effort debugging, shows some real sincerity to your problem.
I think its because in the same frame the server sets it to idle, the client can immediate sneak in a remote event in that exact same frame and trigger another attack.