[HELP NEEDED] Why when i add rocket launcher logic to my game other guns don't work correctly?

I made a gun script 3 months ago it was working perfectly. When i decided to add rocket launcher logic to my game, the script stopped working no bulletholes were created, no damage only the explosion caused damage. Only the rocket launcher did damage and create bulletholes. here is the script 3 months ago working fine:

 --!nocheck
-- Services --
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")

-- Variables --
local gunEvent = ReplicatedStorage.Remotes.GunEvent

local timeSinceLastShot = {}
local whoIsReloading = {}

-- Constants --
local MAX_DISCREPANCY_DIST = 10

-- Functions --
local function createSound(parent, soundProperties)
	local sound = Instance.new("Sound")
	for property,value in pairs(soundProperties) do
		sound[property] = value
	end
	sound.Parent = parent
	return sound
end

local function createMuzzleFlash(parent, lightProperties)
	local light = Instance.new("PointLight")
	for property, value in pairs(lightProperties) do
		light[property] = value
	end
	light.Parent = parent
	light.Enabled = true
	return light
end

local function createBulletHole(properties, result)
	if not result then return end

	local bulletHole = ReplicatedStorage.Shared.Parts.BulletHole:Clone()
	bulletHole.Anchored = false -- make sure to unachor the bullet hole
	local weld = Instance.new("WeldConstraint")
	weld.Part0 =  bulletHole
	weld.Part1 = result.Instance
	weld.Parent = bulletHole

	local offset = (result.Position - result.InstanceOriginPosition)
	local serverCFrameOffset = CFrame.new(result.Instance.Position) * CFrame.new(offset)

	bulletHole.Size = properties.BulletHoleSize
	bulletHole.CFrame = CFrame.new(serverCFrameOffset.Position, serverCFrameOffset.Position+result.Normal) -- at the hit position, and facing the direction of the lookVector
	bulletHole.Parent = workspace.FilteringFolder.BulletHoles
	bulletHole:FindFirstChildWhichIsA("Decal").Color3 = result.Instance.Color

	bulletHole.ParticleEmitter.Color = ColorSequence.new(result.Instance.Color)
	bulletHole.ParticleEmitter:Emit(properties.BulletHoleParticleAmount)	

	Debris:AddItem(bulletHole, 0.5)
end

local function checkBulletRay(properties, result, player)
	if not result then return end

	local character = result.Instance.Parent
	if not character:FindFirstChildWhichIsA("Humanoid") or Players:GetPlayerFromCharacter(character) then return end

	local offset = (result.Position - result.InstanceOriginPosition)
	local serverCFrameOffset = CFrame.new(result.Instance.Position) * CFrame.new(offset)

	if (result.Position - serverCFrameOffset.Position).Magnitude > MAX_DISCREPANCY_DIST then return end
	--[[ by the time this information reaches the server, if the position where the client said they hit is within
	a reasonable distance of where the actual location of that hit is on the server, then probably no exploits
	
	
	10 studs is a GENEROUS estimate for lag, etc..
	A player COULD alter where the they say they hit the head, granting them double damage, even though they hit maybe like an arm.
	to avoid this, you could instead have the client pass their direciton where they shot and calculate the raycast on the server...
	BUT...
	that introduces lag and could make it where a player sees that they hit a zombie but the server didn't register the shot due to lag,
	which ruins the player experience
	
	you could also just reduce the discrepancy distance down to like 2 studs instead to try and combat that possible issue!
	]]
	character.Humanoid:TakeDamage(properties.Damage * properties.BodyPartMultipliers[result.Instance.Name])
	if character:FindFirstChild("WhoLastDamaged") then
		character.WhoLastDamaged.Value = player
	end
end

local function reload(player, gun, properties)
	local ammoInMag = gun:GetAttribute("AmmoInMag")
	local ammoReserve = gun:GetAttribute("AmmoReserve")
	if ammoInMag == properties.MaxMagAmmo then return end 
	if ammoReserve <= 0 then return end

	if timeSinceLastShot[player.Name][gun.Name] then
		if (DateTime.now().UnixTimestampMillis - timeSinceLastShot[player.Name][gun.Name]) < properties.ReloadDuration then return end
		-- the player somehow reloaded FASTER than the reload animation length (probably exploits)
	end

	if not whoIsReloading[player.Name] then
		-- create a new table for the player if they don't have one
		whoIsReloading[player.Name] = {[gun.Name] = true}
	elseif whoIsReloading[player.Name][gun.Name] then 
		return
	end
	whoIsReloading[player.Name][gun.Name] = true

	local ammoNeeded = math.min(properties.MaxMagAmmo - ammoInMag, ammoReserve)

	gun:SetAttribute("AmmoInMag", ammoInMag+ammoNeeded)
	gun:SetAttribute("AmmoReserve", ammoReserve-ammoNeeded)

	whoIsReloading[player.Name][gun.Name] = false
end

local function shoot(player, gun, properties, result)
	if gun:GetAttribute("AmmoInMag") == 0 then return end

	if not timeSinceLastShot[player.Name] then 
		-- create a new table for the player if they don't have one
		timeSinceLastShot[player.Name] = {[gun.Name] = 0}
	end
	if not timeSinceLastShot[player.Name][gun.Name] then
		-- create a new key-value pair for a new gun
		timeSinceLastShot[player.Name][gun.Name] = 0
	end

	if DateTime.now().UnixTimestampMillis - timeSinceLastShot[player.Name][gun.Name] < 60/properties.FireRate then return end
	-- the player somehow shot FASTER than the cooldown for shots (probably exploits)
	timeSinceLastShot[player.Name][gun.Name] = DateTime.now().UnixTimestampMillis

	gun:SetAttribute("AmmoInMag", gun:GetAttribute("AmmoInMag") - 1)
	-- make sure to remove ammo from gun

	if gun:GetAttribute("GunType") == "Spread" then
		if not result or #result == 0 then
			-- all the pellets went into the air, hit nothing, but we still want to play sound & effects
			local light = createMuzzleFlash(gun.Handle.Muzzle, properties.MuzzleFlashProperties)
			task.spawn(function()
				task.wait(0.15)
				light:Destroy()
			end)
			gun.Handle.Muzzle.Flash:Emit(1)

			local sound = createSound(gun.Handle.Muzzle, properties.ShootSoundProperties)
			sound:Play()
			sound.Ended:Connect(function() sound:Destroy() end)
			return
		end

		if #result > properties.TotalPellets then return end
		-- the client tried to fire more pellets than what is possible for their gun, which would indicate exploits

		for i,pelletResult in ipairs(result) do
			if i == 1 then
				-- play sound & effects for only 1 pellet
				local light = createMuzzleFlash(gun.Handle.Muzzle, properties.MuzzleFlashProperties)
				task.spawn(function()
					task.wait(0.15)
					light:Destroy()
				end)
				gun.Handle.Muzzle.Flash:Emit(1)

				local sound = createSound(gun.Handle.Muzzle, properties.ShootSoundProperties)
				sound:Play()
				sound.Ended:Connect(function() sound:Destroy() end)
			end
			checkBulletRay(properties, pelletResult, player)
			createBulletHole(properties, pelletResult, player)
		end
	elseif gun:GetAttribute("GunType") == "Standard" then
		local light = createMuzzleFlash(gun.Handle.Muzzle, properties.MuzzleFlashProperties)
		task.spawn(function()
			task.wait(0.15)
			light:Destroy()
		end)
		gun.Handle.Muzzle.Flash:Emit(5)

		local sound = createSound(gun.Handle.Muzzle, properties.ShootSoundProperties)
		sound:Play()
		sound.Ended:Connect(function() sound:Destroy() end)

		checkBulletRay(properties, result, player)
		createBulletHole(properties, result)
	end
end

-- Event handlers --
gunEvent.OnServerEvent:Connect(function(player, action, ...)
	if not player.Character then return end
	local gun = player.Character:FindFirstChildWhichIsA("Tool")
	if not gun:GetAttribute("GunType") then return end
	local properties = require(gun.Properties)

	if action == "ValidateShot" then
		local args = {...}
		if args[1] and args[2] and args[3] and args[4] then
			-- these args are passed when a 'standard' gun fires the event
			args = {["Instance"] = args[1], ["Position"] = args[2], ["Normal"] = args[3], ["InstanceOriginPosition"] = args[4]}
		elseif args[1] then
			-- this arg is passed when a shotgun fires the event
			args = args[1]
		else
			-- the bullet hit nothing
			args = nil
		end
		shoot(player, gun, properties, args)
	elseif action == "ValidateReload" then
		reload(player, gun, properties)
	end
end)

Players.PlayerRemoving:Connect(function(player)
	-- frees up memory
	if timeSinceLastShot[player.Name] then
		timeSinceLastShot[player.Name] = nil
	end
	if whoIsReloading[player.Name] then
		whoIsReloading[player.Name] = nil
	end
end)

the script with new added functionality:

--!nocheck
-- Services --
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")

-- Variables --
local gunEvent = ReplicatedStorage.Remotes.GunEvent

local timeSinceLastShot = {}
local whoIsReloading = {}

-- Constants --
local MAX_DISCREPANCY_DIST = 10

-- Functions --
local function createSound(parent, soundProperties)
	local sound = Instance.new("Sound")
	for property,value in pairs(soundProperties) do
		sound[property] = value
	end
	sound.Parent = parent
	return sound
end

local function createMuzzleFlash(parent, lightProperties)
	local light = Instance.new("PointLight")
	for property, value in pairs(lightProperties) do
		light[property] = value
	end
	light.Parent = parent
	light.Enabled = true
	return light
end

local function createExplosion(explosionProperties)
	local explosion = Instance.new("Explosion")
	for property,value in pairs(explosionProperties) do
		explosion[property] = value
	end
	-- don't parent explosion to workspace yet
	return explosion
end

local function createBulletHole(properties, result, rocket)
	if not result then return end

	local bulletHole = ReplicatedStorage.Shared.Parts.BulletHole:Clone()
	bulletHole.Anchored = false -- make sure to unachor the bullet hole
	local weld = Instance.new("WeldConstraint")
	weld.Part0 =  bulletHole
	weld.Part1 = result.Instance
	weld.Parent = bulletHole

	local offset = (result.Position - result.InstanceOriginPosition)
	local serverCFrameOffset = CFrame.new(result.Instance.Position) * CFrame.new(offset)

	bulletHole.Size = properties.BulletHoleSize
	bulletHole.CFrame = CFrame.new(serverCFrameOffset.Position, serverCFrameOffset.Position+result.Normal) -- at the hit position, and facing the direction of the lookVector
	bulletHole.Parent = workspace.FilteringFolder.BulletHoles
	bulletHole:FindFirstChildWhichIsA("Decal").Color3 = result.Instance.Color

	bulletHole.ParticleEmitter.Color = ColorSequence.new(result.Instance.Color)
	bulletHole.ParticleEmitter:Emit(properties.BulletHoleParticleAmount)	

	if rocket ~= nil then
		local explosion = createExplosion({["BlastPressure"] = 0, ["BlastRadius"] = 20, ["DestroyJointRadiusPercent"] = 0, ["ExplosionType"] = Enum.ExplosionType.NoCraters})
		explosion.Position = bulletHole.Position
		explosion.Parent = workspace:WaitForChild("FilteringFolder"):WaitForChild("BulletHoles")

		explosion.Hit:Connect(function(hitPart, distance)
			if hitPart.Name ~= "HumanoidRootPart" then return end
			local humanoid = hitPart.Parent:FindFirstChildWhichIsA("Humanoid")
			if not humanoid then return end
			if Players:GetPlayerFromCharacter(hitPart.Parent) then return end -- for when update of players can not kill eachother

			local damage = 12000
			humanoid:TakeDamage(damage)
		end)
	end

	Debris:AddItem(bulletHole, 0.5)
end

local function checkBulletRay(properties, result, player)
	if not result then return end

	local character = result.Instance.Parent
	if not character:FindFirstChildWhichIsA("Humanoid") or Players:GetPlayerFromCharacter(character) then return end

	local offset = (result.Position - result.InstanceOriginPosition)
	local serverCFrameOffset = CFrame.new(result.Instance.Position) * CFrame.new(offset)

	if (result.Position - serverCFrameOffset.Position).Magnitude > MAX_DISCREPANCY_DIST then return end
	--[[ by the time this information reaches the server, if the position where the client said they hit is within
	a reasonable distance of where the actual location of that hit is on the server, then probably no exploits
	
	
	10 studs is a GENEROUS estimate for lag, etc..
	A player COULD alter where the they say they hit the head, granting them double damage, even though they hit maybe like an arm.
	to avoid this, you could instead have the client pass their direciton where they shot and calculate the raycast on the server...
	BUT...
	that introduces lag and could make it where a player sees that they hit a zombie but the server didn't register the shot due to lag,
	which ruins the player experience
	
	you could also just reduce the discrepancy distance down to like 2 studs instead to try and combat that possible issue!
	]]
	character.Humanoid:TakeDamage(properties.Damage * properties.BodyPartMultipliers[result.Instance.Name])
	if character:FindFirstChild("WhoLastDamaged") then
		character.WhoLastDamaged.Value = player
	end
end

local function reload(player, gun, properties)
	local ammoInMag = gun:GetAttribute("AmmoInMag")
	local ammoReserve = gun:GetAttribute("AmmoReserve")
	if ammoInMag == properties.MaxMagAmmo then return end 
	if ammoReserve <= 0 then return end

	if timeSinceLastShot[player.Name][gun.Name] then
		if (DateTime.now().UnixTimestampMillis - timeSinceLastShot[player.Name][gun.Name]) < properties.ReloadDuration then return end
		-- the player somehow reloaded FASTER than the reload animation length (probably exploits)
	end

	if not whoIsReloading[player.Name] then
		-- create a new table for the player if they don't have one
		whoIsReloading[player.Name] = {[gun.Name] = true}
	elseif whoIsReloading[player.Name][gun.Name] then 
		return
	end
	whoIsReloading[player.Name][gun.Name] = true

	local ammoNeeded = math.min(properties.MaxMagAmmo - ammoInMag, ammoReserve)

	gun:SetAttribute("AmmoInMag", ammoInMag+ammoNeeded)
	gun:SetAttribute("AmmoReserve", ammoReserve-ammoNeeded)

	whoIsReloading[player.Name][gun.Name] = false
end

local function shoot(player, gun, properties, result, rocket)
	if gun:GetAttribute("AmmoInMag") == 0 then return end

	if not timeSinceLastShot[player.Name] then 
		-- create a new table for the player if they don't have one
		timeSinceLastShot[player.Name] = {[gun.Name] = 0}
	end
	if not timeSinceLastShot[player.Name][gun.Name] then
		-- create a new key-value pair for a new gun
		timeSinceLastShot[player.Name][gun.Name] = 0
	end

	if DateTime.now().UnixTimestampMillis - timeSinceLastShot[player.Name][gun.Name] < 60/properties.FireRate then return end
	-- the player somehow shot FASTER than the cooldown for shots (probably exploits)
	timeSinceLastShot[player.Name][gun.Name] = DateTime.now().UnixTimestampMillis

	gun:SetAttribute("AmmoInMag", gun:GetAttribute("AmmoInMag") - 1)
	-- make sure to remove ammo from gun

	if gun:GetAttribute("GunType") == "Spread" then
		if not result or #result == 0 then
			-- all the pellets went into the air, hit nothing, but we still want to play sound & effects
			local light = createMuzzleFlash(gun.Handle.Muzzle, properties.MuzzleFlashProperties)
			task.spawn(function()
				task.wait(0.15)
				light:Destroy()
			end)
			gun.Handle.Muzzle.Flash:Emit(1)

			local sound = createSound(gun.Handle.Muzzle, properties.ShootSoundProperties)
			sound:Play()
			sound.Ended:Connect(function() sound:Destroy() end)
			return
		end

		if #result > properties.TotalPellets then return end
		-- the client tried to fire more pellets than what is possible for their gun, which would indicate exploits

		for i,pelletResult in ipairs(result) do
			if i == 1 then
				-- play sound & effects for only 1 pellet
				local light = createMuzzleFlash(gun.Handle.Muzzle, properties.MuzzleFlashProperties)
				task.spawn(function()
					task.wait(0.15)
					light:Destroy()
				end)
				gun.Handle.Muzzle.Flash:Emit(1)

				local sound = createSound(gun.Handle.Muzzle, properties.ShootSoundProperties)
				sound:Play()
				sound.Ended:Connect(function() sound:Destroy() end)
			end
			checkBulletRay(properties, pelletResult, player)
			createBulletHole(properties, pelletResult, player)
		end
	elseif gun:GetAttribute("GunType") == "Standard" then
		local light = createMuzzleFlash(gun.Handle.Muzzle, properties.MuzzleFlashProperties)
		task.spawn(function()
			task.wait(0.15)
			light:Destroy()
		end)
		gun.Handle.Muzzle.Flash:Emit(5)

		local sound = createSound(gun.Handle.Muzzle, properties.ShootSoundProperties)
		sound:Play()
		sound.Ended:Connect(function() sound:Destroy() end)

		checkBulletRay(properties, result, player)
		if rocket == nil then
			createBulletHole(properties, result)
		else
			createBulletHole(properties, result, rocket)
		end
	end
end

-- Event handlers --
gunEvent.OnServerEvent:Connect(function(player, action, rocket, ...)
	if not player.Character then return end
	local gun = player.Character:FindFirstChildWhichIsA("Tool")
	if not gun:GetAttribute("GunType") then return end
	local properties = require(gun.Properties)

	if action == "ValidateShot" then
		local args = {...}
		if args[1] and args[2] and args[3] and args[4] then
			-- these args are passed when a 'standard' gun fires the event
			args = {["Instance"] = args[1], ["Position"] = args[2], ["Normal"] = args[3], ["InstanceOriginPosition"] = args[4]}
		elseif args[1] then
			-- this arg is passed when a shotgun fires the event
			args = args[1]
		else
			-- the bullet hit nothing
			args = nil
		end
		if rocket == nil then
			shoot(player, gun, properties, args)
		else
			shoot(player, gun, properties, args, rocket)
		end
	elseif action == "ValidateReload" then
		reload(player, gun, properties)
	end
end)

Players.PlayerRemoving:Connect(function(player)
	-- frees up memory
	if timeSinceLastShot[player.Name] then
		timeSinceLastShot[player.Name] = nil
	end
	if whoIsReloading[player.Name] then
		whoIsReloading[player.Name] = nil
	end
end)