Code causes extreme lagspikes in certain circumstances

I am trying to make a pickaxe that can destroy blocks with a certain tag. This pickaxe sends a remote event every time the block should be damaged, with the player also being able to hold the mouse button to mine repeatedly.

I have recently been trying to fix an issue where if the player clicks or holds down the mouse button in the middle of mining, it would just stop mining alltogether. I want to make it so it will start mining once the debounce is over when this happens.

However, with my new code, when I try this, for some reason it will cause a giant lagspike (not network lag), the animation will not play, but the block can still get destroyed.

Client side code:

local CollectionService = game:GetService("CollectionService")

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local mouse = Player:GetMouse()

local Pickaxe = script.Parent
local Configs = Pickaxe:WaitForChild("Configurations")
local Speed = Configs.Speed.Value
local Power = Configs.Power.Value
local MineAnimation = Humanoid:LoadAnimation(Pickaxe.MineAnimation1)

local MineRE = game.ReplicatedStorage.RemoteEvents.Mine

local Mining = false
local tickNextPick = 0

local function Mine()
	MineAnimation:Play()
	if CollectionService:HasTag(mouse.Target, "Mineable") then
		local Range = (HumanoidRootPart.Position - mouse.Target.Position).magnitude
		if Range <= 20 then
			MineRE:FireServer(mouse.Target, Power)
			tickNextPick = os.clock() + Speed
		end 
	end
end

Pickaxe.Activated:Connect(function()
	Mining = true
	while Mining do
		if os.clock() >= tickNextPick then
			Mine()
			wait(Speed)
		end
	end
end)

Pickaxe.Deactivated:Connect(function()
	Mining = false
end)

Server Side code:

local MineRE = game.ReplicatedStorage.RemoteEvents.Mine

local Debris = game.ServerStorage.Debris
local DebrisService = game:GetService("Debris")

local StoneHitSound = game.Workspace.Sounds.StoneHit
local StoneBreakSound = game.Workspace.Sounds.StoneBreak

local TweenService = game:GetService("TweenService")
local Tween1Info = TweenInfo.new(0.15, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, true, 0)
local goal1 = {}
goal1.Size = Vector3.new(1, 1, 1)


MineRE.OnServerEvent:Connect(function(player, Block, Power, Time)
	print("Signal Received")
	local BlockPos = Block.Position
	local stone = player.leaderstats.Stone
	local Health = Block:FindFirstChild("Health")
		
	if Health == nil then print("ded") return end

	StoneHitSound:Play()
	Health.Value = Health.Value - Power
	
	local function ChangeTexture(TextureID, Part)
		local Dec = Instance.new("Decal")
		Dec.Texture = TextureID

		local Dec2 = Dec:Clone()
		local Dec3 = Dec:Clone()
		local Dec4 = Dec:Clone()
		local Dec5 = Dec:Clone()
		local Dec6 = Dec:Clone()
		
		Dec.Parent = Part
		Dec2.Parent = Part
		Dec3.Parent = Part
		Dec4.Parent = Part
		Dec5.Parent = Part
		Dec6.Parent = Part

		Dec.Face = Enum.NormalId.Back
		Dec2.Face = Enum.NormalId.Bottom
		Dec3.Face = Enum.NormalId.Front
		Dec4.Face = Enum.NormalId.Left
		Dec5.Face = Enum.NormalId.Right
		Dec6.Face = Enum.NormalId.Top
	end

	if Health.Value <= 0 then
		StoneBreakSound:Play()
		Block:Destroy()
		if Block.name == ("Stone") then
			for count = 1, math.random(2, 7) do
				local Particle = Debris.StoneDebris:Clone()
				Particle.Parent= workspace.Temp
				Particle.Name = "Particle"
				Particle.Position = BlockPos
				Particle.AssemblyLinearVelocity = Vector3.new(math.random(5, 20), math.random(5, 20), math.random(5, 20))
				DebrisService:AddItem(Particle, 10)
			end	
			stone.Value = stone.Value + 1
		end
	else
		local Tween1 = TweenService:Create(Block, Tween1Info, goal1)
		Tween1:Play()
		
		if Block.Name == ("Stone") then
			if Health.Value <= 1 then
				ChangeTexture("rbxassetid://8003108684", Block)
			elseif Health.Value <= 3 then
				ChangeTexture("rbxassetid://8003108052", Block)
			elseif Health.Value <= 5 then
				ChangeTexture("rbxassetid://8003107439", Block)
			elseif Health.Value <= 7 then
				ChangeTexture("rbxassetid://8003075298", Block)
			end
		end
	end
end)
1 Like

I didnt look through all of it because codeblocks are a pain on mobile, but this is one cause of lag
if the time is before the next pick, it will busywait and lag anything else that’s meant to run at the same time

you should also adjust the code so that only one of those loops can be active at a time
right now, if one of the loops is waiting and you spam the activate event before it finishes and checks if Mining is true, all of those will have separate loops that run at the same time
I’d implement it like this

local CurrentId = -1

on Tool.Activated
   local Id = os.clock()
   CurrentId = Id
   while CurrentId == Id do
      Mine()
      wait N seconds
   end
end

on Tool.Deactivated
   CurrentId = -1
end

and if you don’t like doing wait N seconds because of precision issues, you can calculate the time to wait to by adding to Id, set CurrentId to that new Id, then wait (NewId - OldId) seconds

This is the code that has worked the best so far, however, the debounce is ignored when you click while on debounce, so I am going to try implementing a server side debounce.

I forgot to add that you should check if CurrentId is -1 at the beginning of on Tool.Activated to continue

This started working when I played around with it a bit to make it compatible with the rest of the code. Here is the final code for anyone else who is looking at this:

local CollectionService = game:GetService("CollectionService")

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local mouse = Player:GetMouse()

local Pickaxe = script.Parent
local Configs = Pickaxe:WaitForChild("Configurations")
local Speed = Configs.Speed.Value
local Power = Configs.Power.Value
local MineAnimation = Humanoid:LoadAnimation(Pickaxe.MineAnimation1)

local MineRE = game.ReplicatedStorage.RemoteEvents.Mine

local OnDebounce = false
local tickNextPick = 0

local function Mine()
	if OnDebounce then
		print("Ondebounce")
	else
		MineAnimation:Play()
		if CollectionService:HasTag(mouse.Target, "Mineable") then
			local Range = (HumanoidRootPart.Position - mouse.Target.Position).magnitude
			if Range <= 20 then
				OnDebounce = true
				MineRE:FireServer(mouse.Target, Power)
				tickNextPick = os.clock() + Speed
				
				repeat wait() until os.clock() >= tickNextPick
				OnDebounce = false
			end 
		end	
	end
end

local CurrentId = -1

Pickaxe.Activated:Connect(function()
	if CurrentId == -1 then
		local Id = os.clock()
		CurrentId = Id

		while CurrentId == Id do
			Mine()
			repeat wait() until os.clock() >= tickNextPick
		end
	end
end)
	
Pickaxe.Deactivated:Connect(function()
	CurrentId = -1
end)
1 Like