So basically I have a script on the client side which if supposed to detect if I have hit a crystal. The issue is that it doesn’t always detect the hitbox of the crystal, therefore a message isn’t sent to the server to inflict damage. Are there any other methods to reliably detect something compared to .Touched?
local plr = game.Players.LocalPlayer
local weapon
local blade
local detected = false
local combatremote = game.ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("Combat")
local debounce = false
local connection
local function animate()
local animations = {"rbxassetid://03514781007","rbxassetid://03526565168"}
local random = math.random(1,#animations)
local charatcer = plr.Character
if charatcer then
local animation = Instance.new("Animation",charatcer)
animation.AnimationId = animations[random]
local humanoid = charatcer:WaitForChild("Humanoid")
humanoid:LoadAnimation(animation):Play()
animation:Destroy()
end
end
plr.CharacterAdded:Connect(function()
local character = plr.Character
weapon = character:WaitForChild("Weapon")
blade = weapon:WaitForChild("Blade")
weapon.Activated:Connect(function()
if not debounce then
debounce = true
animate()
connection = blade.Touched:Connect(function(thing)
connection:Disconnect()
print("Detected Object")
if thing.Parent.Name == "Crystal" then
thing = thing.Parent
combatremote:FireServer(thing)
elseif thing.Parent.Parent.Name == "Crystal" then
thing = thing.Parent.Parent
combatremote:FireServer(thing)
end
end)
wait(0.4)
connection:Disconnect()
debounce = false
end
end)
end)
The touched event should be handled on the server. Letting the client handle dealing damage can be dangerous. But do handle the activated event listeners and animation playing on the client. Also is it really necessary to connect an activated listener each time the character is (re)spawned?
The way I have it set up, I see no problems using .Touched on the client. I use it to detect whatever the client has hit, then it is sent to the server for sanity checks such as a distance check to make sure the player is actually near the crystal.
But you don’t need to handle it on the client. The client shouldn’t be able to decide what it hit in the first place. Even with sanity checks. It’s the server that should be doing it. Just as you don’t see an issue handling it locally, I don’t see why the client should have any say on what it hit.
Even if an exploiter were to try to spoof what the client hit the server would just ignore it with the sanity checks. Anyways I would’ve thought it would have been more efficient to have the listener on the client versus the server having to listen to all the clients to be more efficient on the server.
I have a big reason not to however. Right now, after an animation plays on the client, a .Touched listener is connected straight after. It may detect something when the player’s character moves. However, if I was to do this on the server, there would be a few milliseconds latency from the client requesting a swing of a tool to the server. This would make the weapon seem unresponsive.
Well, what if the animation was done on the client side and the listener on the server? That would an issue because by the time the server sees that the player has done an animation, the listener would have already ended from the latency. The lack of movement would cause the server to detect no crystals.
I disagree with this. I handle the majority of the touched events on the client as it’s faster, more reliable, and doesn’t add unnecessary listeners on the server.
I’ve experienced that with more touched events on the server comes slower server performance in terms of detection. I’ve once had a game take 10 seconds to fire a touched event despite all other features performing normally.
Actually, even if you use .Touched on the server, you can’t avoid checks entirely. Resizing a part on the client to something extremely big or extremely small would result in the .Touched event firing on the server too - even if it doesn’t replicate. It’s really weird behavior.
I’ve experienced this with linked swords/swords that use .Touched for a hitbox. An exploiter can increase their hitbox size – therefore increasing their reach.
as a newbie scripter that just started a few months ago this seems insanely hard (raycasting + magnitude + regions) , could you explain it more? (i’ve had insanely bad lag problems with region3 and i never learned how to use them, and raycasts got annoying for large projectiles so i can’t imagine using them for hitboxing a sword).
Even having said what you have, if the client handles touched I could just keep firing the event which would lag the server with all the ‘sanity’ checks it would have to do. Just do it server side, so much simpler.
Well, maybe not using regions – just Touched and Magnitude.
Since I mentioned earlier that the hitbox for any object can be changed if you used .Touched, you would have to do some server-sided distance checks to ensure that they aren’t too far away to do something. Of course, this sort of works the other way: if the exploiter reduces the size of the hitbox to absolutely nothing, then they can avoid firing the .Touched event all together. This is why I suggested that you should also try to incorporate regions, but now that I think about it, it would be extremely hard to make use regions here without sacrificing either reliability (not use regions consistently to improve efficiency so it might miss some players) or efficiency (spamming regions for maximum reliability resulting in some stress on the server).
I also mentioned that you could use raycasting, but there is no reliable way of using raycasting for a .Touched method because of the same reasons as a Region – sacrifice either reliability or efficiency. Not to mention, the only feedback you would get with a raycast is how far away the character is from the crystal – in which case you can simply use magnitude (the distance between a player’s character and the crystal).
Knowing all of this, there is no real definitive way to avoid players from removing the crystal’s hitbox, so I typically ignore that. I’d rather an exploiter only be able to remove the hitbox for himself rather than being able to lag the server at his command by spamming remotes.
All that being said, the code would look something like this:
local crystalHitbox = workspace.Crystal.Hitbox -- or something like that
local alreadyTouchedHumanoids = {} -- used for debounces
crystalHitbox.Touched:Connect(function(hit)
if hit.Parent and hit.Parent:FindFirstChild"Humanoid" and not alreadyTouchedHumanoids[hit.Parent.Humanoid] and (hit.Position - crystalHitbox.Position).magnitude < 5 then -- maximum of 5 studs of leeway so they don't get damaged far away
alreadyTouchedHumanoids[hit.Parent.Humanoid] = true -- debounce
hit.Parent.Humanoid:TakeDamage(damageYouWant)
wait(1)
alreadyTouchedHumanoids[hit.Parent.Humanoid] = nil
end
end)
Let me know if you have any questions regarding anything I said.
I would disagree, the server has a debounce, the debounce simply checks if the player’s weapons debounce is false, if it is false, then the server will do the sanity checks, if it is true, it just ignores the request and does nothing. Simple. No lag whatsoever.
If your crystal is a mesh, then setting the Collision Fidelity to box causes the collision to be inaccurate. Meaning the Touched event will fire and when a player touches the outer bounds of the MeshPart, not the actual mesh. So, if you want more accurate collision that detect Touched events based on the geometry of the mesh, then you should set the Mesh’s Collision Fidelity to Default.
You can useBasePart:GetTouchingPartsorRegion3 for most effective detection. Along with that, follow other advice about keeping your script on client. You hear the reasons already, so I won’t repeat them.