I have a little throw animation before I shoot my projectile and initially the event that started the throw animation would give the server the mouse.Hit.Position so I could shoot the projectile to that point. The problem with that is you could not redirect your mouse during the animation and the projectile would go to the position the mouse was at when the animation started.
What I have done now is have a second event that is fired by the local script after a short period after the initial event that starts the animation. This event is now the one that gives the direction instead of the one that starts the animation. It makes the projectile easier to use now but I am worried that exploiters could use this to make an instantaneous and unreactable projectile by firing the 2 events with no delay between them.
The only other solution I can think of is that the server Fires an event to the client once the animation is done and the client then fires the event back to the server to give it the position. I feel this will cause issues with latency however since it has to bounce between the client and server so much. How do you all think I should go about making my projectile feel good to use while keeping it safe from exploiters?
Use Debounces to make sure only one thing runs at a time
local debounce = {}
local function function(player)
if not debounce[player] then
debounce[player] = true
-- code here --
task.wait(1)
---------------
debounce[player = false
end
end
If you need to cancel a function because you have a new function that will run instead you can use threads and cancel them.
-- Here we have a Railgun. When the player clicks it sends a signal to the server
-- and 3 seconds later it fires the railgun
-- If the player clicks twice in a row, we want to make sure the railgun only fires once
-- Use a thread with task.cancel to cancel functions
local thread = coroutine.create(function()end) --Dummy thread
local chargeTime = 2
local function onEvent(player)
task.cancel(thread)
thread = task.spawn(function()
task.wait(chargeTime)
fireRailgun()
end)
end
fireRailgun.OnServerEvent:Connect(onEvent)
I think you guys are misunderstanding me(or maybe I am misunderstanding you) but the problem is not that multiple things are running at the same time, my debouce is working perfectly fine, the problem is that if the player has there mouse at point A at the moment they hit the key to shoot the projectile and they move their mouse to point B during the windup animation, the projectile will still shoot to point A since the original event that fired sent over point As location. I currently have a what I think is a bandaid solution where the first event is fired to do the windup while the second event is what actually shoots the script. I need is to be this way because unless you can see 1 second into the future(the windup time), it is practically the same as having 1000ms of ping when trying to aim and instantaneous projectile.
My main concern with this solution is that an exploiter could create their own input where they fire the windup event then immediately fire the shoot event in quick succession and basically skip the entire windup animation. I have something similar to this in the local script :
Connections.UISConnection = UIS.InputBegan:Connect(function(key,chat)
if not chat and key.KeyCode.Name == script.AgingKnives.Value then
local ID = game:GetService("HttpService"):GenerateGUID()
game.ReplicatedStorage.RemoteEvents.AgingKnives:FireServer(ID)
task.wait(1)
game.ReplicatedStorage.RemoteEvents.DirectionEvent:FireServer(root.Position,mouse.Hit.Position,ID)
end
end)
What an exploiter could do is this :
Connections.UISConnection = UIS.InputBegan:Connect(function(key,chat)
if not chat and key.KeyCode.Name == script.AgingKnives.Value then
local ID = game:GetService("HttpService"):GenerateGUID()
game.ReplicatedStorage.RemoteEvents.AgingKnives:FireServer(ID)
task.wait()
game.ReplicatedStorage.RemoteEvents.DirectionEvent:FireServer(root.Position,mouse.Hit.Position,ID)
end
end)
local delayTime = 1
local currentTime = tick()
Connections.UISConnection = UIS.InputBegan:Connect(function(key,chat)
if not chat and key.KeyCode.Name == script.AgingKnives.Value then
local ID = game:GetService("HttpService"):GenerateGUID()
game.ReplicatedStorage.RemoteEvents.AgingKnives:FireServer(ID)
repeat RunService.Heartbeat:Wait() until tick() - currentTime >= delayTime
game.ReplicatedStorage.RemoteEvents.DirectionEvent:FireServer(root.Position,mouse.Hit.Position,ID)
end
end)