Hi there! Hope your having a great day! I’m currently making a simulator and would like some help. Currently the system I have makes it so you have to repeatedly click to gain “points”. How would I make it so that it would be like mining sim’s tools where you hold down the mouse? I’m just looking for ways I can do so.
My current client code which is in the tool itself
local equipped = false
local tool = script.Parent
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
tool.Equipped:Connect(function()
equipped = true
end)
tool.Unequipped:Connect(function()
equipped = false
end)
mouse.Button1Down:Connect(function()
if equipped then
game.ReplicatedStorage.Events.EatDonut:FireServer()
end
end)
Server Code
local LastEat = {}
function Eat(player)
local stat = 100
if LastEat[player.UserId] == nil then
LastEat[player.UserId] = os.time()
end
if (os.time() - LastEat[player.UserId] >= 1) then
if player.Stats.CurrentAmount.Value < player.Stats.MaxAmount.Value then
player.Stats.CurrentAmount.Value = player.Stats.CurrentAmount.Value + 1
LastEat[player.UserId] = os.time()
end
end
if (os.time() - LastEat[player.UserId] >= 1) then
if player.Stats.CurrentAmount.Value >= player.Stats.MaxAmount.Value then
player.Stats.CurrentAmount.Value = player.Stats.MaxAmount.Value
end
end
end
game.ReplicatedStorage.Events.EatDonut.OnServerEvent:Connect(function(player)
Eat(player)
end)
You’ll need a variable to store if the player is holding their click or not, similar to your equipped variable.
Then with the Tool, you can use the Activated and Deactivated events to toggle that variable. Activated is ran when the player clicks while the Tool is equipped, and Deactivated is ran when the player releases that click.
If you are constantly performing an action while the player is holding down their click, you’ll need a loop to help there. I don’t recommend spamming your RemoteEvent within a loop, so you can pass a variable to it and have that handle the check.
There is probably a better solution, but what typically works for me is a while loop that causes the tool’s action to happen when a certain value is true.
Here is what I would suggest:
local tool = script.Parent
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
mouseDown = false
mouse.Button1Down:connect(function()
mouseDown = true
end)
mouse.Button1Up:connect(function()
mouseDown = false
end)
while true do
wait()
if mouseDown then
game.ReplicatedStorage.Events.EatDonut:FireServer()
end
end
Edit: My bad, I completely forgot to put in a check to see if the player has the tool equipped or not (thank you, ChasingSpace). Make sure that’s added; the code you had to check that to begin with should work.
Close, but this would run regardless if the player has the tool equipped or not. Also, I don’t think it’s a great idea to spam fire a RemoteEvent like that. The server code should have it’s own loop, and the client code should only tell the server when the player clicks and when they release that click.
local lastsent = tick() --initialize to something between negative infinity and tick()
local increment = 0.1 --fire the remote event 10 times per second
while true do
wait()
if tick() >= lastsent + increment then
if mousedown then
lastsent = tick()
--fire server via remote event
end
end
end
To completely avoid having the remote events spammed, you could instead, send a signal to the server to communicate the mouse down and up event, and let the server run a loop to give the player points.
The client code can be changed to:
local equipped = false
local mouseDown = false
local lastClick = 0
local tool = script.Parent
local plr = game.Players.LocalPlayer
local inputServ = game:GetService("UserInputService")
tool.Equipped:Connect(function()
equipped = true
end)
tool.Unequipped:Connect(function()
equipped = false
end)
inputServ.InputBegan:Connect(function(input, processed)
if processed then
return
end
if equipped and input.UserInputType == Enum.UserInputType.MouseButton1 then
if tick()-lastClick >= 1 then
lastClick = tick()
mouseDown = true
game.ReplicatedStorage.Events.EatDonut:FireServer(true)
end
end
end)
inputServ.InputEnded:Connect(function(input, processed)
if mouseDown and input.UserInputType == Enum.UserInputType.MouseButton1 then
mouseDown = false
game.ReplicatedStorage.Events.EatDonut:FireServer(false)
end
end)
I’ve updated the mouse events to use UserInputService as is recommended on the developer hub.
And the server code:
local eating = {}
function Eat(player)
local stats = player.Stats
local current = stats.CurrentAmount
local maximum = stats.MaxAmount
-- While they're still eating, and not at maximum capacity
while eating[player.UserId] and current.Value < maximum.Value do
-- Add 1 point per second
current.Value = current.Value + 1
wait(1)
end
end
game.ReplicatedStorage.Events.EatDonut.OnServerEvent:Connect(function(player, mode)
if mode then -- Mouse down
eating[player.UserId] = true
Eat(player)
else -- Mouse up
eating[player.UserId] = false
end
end)
No matter what method you chose to use, be mindful of possible exploiters who may send invalid remote requests to the server. You could combat this by making sure they’re at least holding the tool on the server.
Hope this is what you needed, let me know if you face any problems as I haven’t tested the code!
Okay, you make a good point. I forgot about spam clicking, but my method will still make less remote event calls than yours while the mouse is being held down. If 10 players are holding the mouse for 10 seconds using your method, the remote event will recieve 1000 calls in those 10 seconds. Using my method, each player only sends an event at the start and end of their clicking, meaning the event will recieve just 20 calls in those 10 seconds.
I’ll update mine now to prevent spam clicking, that was an oversight when I coded it - more of a problem than something I intended to miss out.
local mouse = player:GetMouse()
local mousedown = false
local canshoot = true -- debounce
local cooldown = 0.5
local function shoot()
if canshoot == true then
canshoot = false
--do something
wait(cooldown)
canshoot = true
end
end
mouse.Button1Down:connect(function()
mousedown = true
if canshoot == true then
repeat
shoot()
until mousedown == false
end
end)
mouse.Button1Up:connect(function()
mousedown = false
end)
essentially its just debounce + repeated functions
But it would also be better to do on the server if spam clicking is a concern. Exploiters could completely overwrite the local script on the client and send that event as fast as they can.