Gun script lagging server

When I was working on my gun system, it worked just fine in studio. Upon testing it in a real server, however, it would create extreme server lag (the ping would go from 50 to 400). Could someone please tell me how I could optimize my code? (I would prefer if most of it could stay server-side as to prevent cheaters and to keep it simple, but if this isn’t an option, any advice is helpful.)

Server script:

local tool = script.Parent.Parent
local handle = tool.Handle
local equipped = false
local player
local character
local humanoid

--
local Range = script.Parent.Range.Value
local Damage = script.Parent.Damage.Value
local Pellets = script.Parent.PelletsPerShot.Value
local Spread = script.Parent.Spread.Value
local Type = script.Parent.Type
local cooldownTime = script.Parent.CooldownTime
local reloadTime = script.Parent.ReloadTime
local onCooldown = false
local origin = tool.Origin
local flash = origin.MuzzleFlash

local check = 0
local Reloading

local ClipAmmo = script.Parent.ClipAmmo --ammo thats in your clip currently
local MaxClip = script.Parent.MaxClip --the most amount of ammo you can have in your clip at one time
local Reserve = script.Parent.ReserveAmmo --the ammo in your pockets
local MaxReserve = script.Parent.MaxReserve ----the most amount of ammo you can have in your pockets at one time


local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.IgnoreWater = true

local CSI = game:GetService("ServerStorage"):FindFirstChild("CurrentSessionInformation")

tool.Equipped:Connect(function()
	equipped = true
	character = script.Parent.Parent.Parent
	humanoid = character:FindFirstChild("Humanoid")
	player = game.Players:GetPlayerFromCharacter(character)
	raycastParams.FilterDescendantsInstances = {character, tool, tool.Handle}
end)

tool.Unequipped:Connect(function()
	equipped = true
end)


function TagHumanoid(enemyHum, player)
	local creator_tag = Instance.new("ObjectValue")
	creator_tag.Value = player
	creator_tag.Name = "creator"
	creator_tag.Parent = enemyHum
	task.wait(0.25)
	UntagHumanoid(enemyHum)
end

function UntagHumanoid(humanoid)
	if humanoid ~= nil then
		local tag = humanoid:findFirstChild("creator")
		if tag ~= nil then
			tag.Parent = nil
		end
	end
end

function FX()
	flash.Enabled = true
	task.wait(0.1)
	flash.Enabled = false
end

local TipStep = false

function Reload(player)
	if Reserve.Value ~= 0 then
		Reloading = true
		print("Reloading... (" .. player.Name .. ")")
		handle.Reload:Play()
		wait(reloadTime.Value)
		print("Finished reloading! (" .. player.Name .. ")")
		local Difference = (ClipAmmo.Value - MaxClip.Value)
		ClipAmmo.Value = math.clamp(MaxClip.Value, 0, Reserve.Value)
		Reserve.Value += Difference
		if Reserve.Value < 0 then
			Reserve.Value = 0
		end
		Reloading = false
	else 
		if not TipStep then
			TipStep = true
			handle.DryFire:Play()
			task.wait(0.25)
			TipStep = false
		end
	end
end

function FireBullet(raycastResult)
	if raycastResult then
		local hitPart, hitPosition = unpack({raycastResult.Instance, raycastResult.Position})
		local hashum = hitPart.Parent:FindFirstChild("Humanoid")
		if hashum then
			local enemyHum = hitPart.Parent.Humanoid
			if hitPart.Name == ("Head") then
				enemyHum:TakeDamage(Damage * 4)
			else
				enemyHum:TakeDamage(Damage)
			end
			handle.HitPlayer:Play()
			local TagCoro = coroutine.create(TagHumanoid)
			coroutine.resume(TagCoro, enemyHum, player)
			----------------------------------------
		elseif hitPart.Parent:IsA("Accessory") or hitPart.Parent:IsA("Hat") then --if you hit a hat (used for helmets to make them only deal bodyshot damage)
			local enemyHum = hitPart.Parent.Parent:FindFirstChild("Humanoid")
			if hitPart.Parent.Name ~= ("Shield") then
				if hitPart.Parent.Name == ("Vest") or hitPart.Parent.Name == ("Armor") then
					enemyHum:TakeDamage(Damage)
					game.ServerStorage.ServerEventsGame.DestroyInfoPasser:Fire(hitPart) --send request to get % chance to destroy object
				else
					if CSI.IsLoud.Value == false then
						enemyHum:TakeDamage(Damage * 4)
					else
						enemyHum:TakeDamage(Damage * 2)
						game.ServerStorage.ServerEventsGame.DestroyInfoPasser:Fire(hitPart) --send request to get % chance to destroy object
					end
				
				end
				handle.HitPlayer:Play()
				local TagCoro = coroutine.create(TagHumanoid)
				coroutine.resume(TagCoro, enemyHum, player)
			end
			----------------------------------------
		elseif hitPart.Name == ("Glass") then
			game.ServerStorage.ServerEventsGame.DestroyInfoPasser:Fire(hitPart) --send request to break glass
			----------------------------------------
		else --if you missed
			handle.HitWorld:Play()
		end
	end
end

script.Parent.Shoot.OnServerEvent:Connect(function(Player, MousePos, OriginPos)
	if not onCooldown and character:FindFirstChild("Humanoid").Health ~= 0 then
		if ClipAmmo.Value ~= 0 and not Reloading then
			onCooldown = true
			ClipAmmo.Value = ClipAmmo.Value - 1
			if check == 0 then
				humanoid:LoadAnimation(script.Parent.Anim01):Play()
				check = 1
			elseif check == 1 then
				humanoid:LoadAnimation(script.Parent.Anim02):Play()
				check = 0
			end
			handle.Fire:Play()
			local FXCoro = coroutine.create(FX)
			coroutine.resume(FXCoro)
			local Direction = (MousePos - OriginPos).Unit * Range
			if Type.Value ~= ("Shotgun") then
				local raycastResult = workspace:Raycast(OriginPos, Direction, raycastParams)
				FireBullet(raycastResult)
			else
				for i = 1, Pellets do
					local random = Random.new()
					local NewDirection = ((MousePos + Vector3.new(random:NextNumber(-Spread, Spread), random:NextNumber(-Spread, Spread), random:NextNumber(-Spread, Spread))) - OriginPos).Unit * Range
					local raycastResult = workspace:Raycast(OriginPos, NewDirection, raycastParams)
					FireBullet(raycastResult)
				end
			end
			task.wait(cooldownTime.Value)
			onCooldown = false
		else
			if not Reloading then
				Reload(player)
			end
		end
	end
end)

script.Parent.Reload.OnServerEvent:Connect(function(Player)
	if not Reloading and ClipAmmo.Value ~= MaxClip.Value then
		Reload(player)
	end
end)

print("Gun system ready! (" .. tool.Name .. ")")

LocalScript:

local player = game.Players.LocalPlayer
repeat wait(1) until player.Character
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local Mouse = player:GetMouse()
local UIS = game:GetService("UserInputService")

local Anim = script.Parent.Idle
local IdleAnim = humanoid:LoadAnimation(Anim)

local Equipped = false
local tool = script.Parent.Parent
local origin = script.Parent.Parent:WaitForChild("Origin")

local range = script.Parent.Range.Value
local damage = script.Parent.Damage.Value
local cooldownTime = script.Parent.CooldownTime.Value
local check = 0
local serverReady = true

local Firing
local ReloadConnection

tool.Equipped:Connect(function()
	Equipped = true
	ReloadConnection = UIS.InputBegan:connect(function(input)
		if input.KeyCode == Enum.KeyCode.R then
			script.Parent.Reload:FireServer()
		end
	end)
	IdleAnim:Play()
end)

tool.Unequipped:Connect(function()
	Equipped = false
	Firing = false
	ReloadConnection:Disconnect()
	IdleAnim:Stop()
end)

local AllowedToStep = true

script.Parent.Parent.Activated:Connect(function()
	Firing = true
	while Firing do
		if AllowedToStep then
			AllowedToStep = false
			local MousePosition = Mouse.Hit.p
			local OriginPosition = origin.Position 
			script.Parent.Shoot:FireServer(MousePosition, OriginPosition)
			task.wait(cooldownTime)
			AllowedToStep = true
		end
		task.wait(0.02)
	end
end)

script.Parent.Parent.Deactivated:Connect(function()
	Firing = false
end)

Any help would be much appreciated!

2 Likes

try deleting all the useless prints

2 Likes

I tried and it doesn’t really affect anything, since there are only 3 and none of them occur when the gun is fired, only reloading and an extra one that only ever happens once.

1 Like

Do you know if there’s client lag, or server lag?

Second, instead of activated, use the LocalPlayer:GetMouse() function. (More info here but) Mouse

It seems you’re just doing a lot of operations on the server, and that might be the cause, But maybe the while loop on the client could be the culprit there. (Of course you do have a wait, so unless you have an exorbitantly crappy PC, studio hosts the server on your PC, i wouldnt know why).

Try testing it actually in game (not studio) and see what your frames are. You’ll also have access to Script Performance (F9 > Scripts) and you can see the stats for that.

1 Like

I’m not really sure why, but it’s suddenly working signifigantly better. I haven’t been able to get the system to lag at all today. I did also implement the change you recommended by replacing .Activated with Mouse.Button1Down, though the issue was server lag, not client lag. Not really sure why it’s better, but it is, so I’ll mark you as solution.