--Glenn's Anti-Exploit System (GAE for short). This code is very ugly, but does job done
local function SecureSettings(Player, Gun, Module)
	if Player then
		local PreNewModule = Gun:FindFirstChild("Setting")
		if Gun and PreNewModule then
			local NewModule = require(PreNewModule)
			if (CompareTables(Module, NewModule) == false) then
				if KickPlayer then
					Player:Kick("You have been kicked and blocked from rejoining this specific server for exploiting gun stats.")
					warn(Player.Name.." has been kicked for exploiting gun stats.")
					table.insert(_G.TempBannedPlayers, Player)
				else
					warn(Player.Name.." - Potential Exploiter Bypass! Case 2: Changed Gun Stats From Client")	
				end
				return
			end
		else
		--[[if KickPlayer then
			Player:Kick("Gun and Module are not found. Kicked!")
			warn("Gun and Module are missing from "..Player.Name.."'s inventory.")
		else
			warn(Player.Name.." - Potential Exploiter Bypass! Case 1: Missing Gun And Module")	
		end]]
			warn(Player.Name.." - Potential Exploiter Bypass! Case 1: Missing Gun And Module")
			return
		end
	else
		warn("Player does not exist.")
		return
	end
end

function _G.SecureSettings(Player, Gun, Module)
	SecureSettings(Player, Gun, Module)
end

VisualizeHitEffect.OnServerEvent:Connect(function(Player, Type, Replicate, Hit, Position, Normal, Material, ...)
	local Table = {...}
	if Type == "Normal" then
		for _, plr in next, Players:GetPlayers() do
			if plr ~= Player then
				VisualizeHitEffect:FireClient(plr, Type, Replicate, Hit, Position, Normal, Material, Table[1], Table[2], Table[3], nil)
			end
		end
	elseif Type == "Blood" then
		for _, plr in next, Players:GetPlayers() do
			if plr ~= Player then
				VisualizeHitEffect:FireClient(plr, Type, Replicate, Hit, Position, Normal, Material, Table[1], Table[2], nil)
			end
		end
	end
end)

VisualizeBullet.OnServerEvent:Connect(function(Player, Module, Tool, Handle, Directions, FirePointObject, HitEffectData, BloodEffectData, BulletHoleData, ExplosiveData, BulletData, WhizData, ClientData)
	for _, plr in next, Players:GetPlayers() do
		if plr ~= Player then
			VisualizeBullet:FireClient(plr, Module, Tool, Handle, Directions, FirePointObject, HitEffectData, BloodEffectData, BulletHoleData, ExplosiveData, BulletData, WhizData, ClientData)
		end
	end
end)

VisualizeMuzzle.OnServerEvent:Connect(function(Player, Handle, MuzzleFlashEnabled, MuzzleLightData, MuzzleEffect, Replicate)
	for _, plr in next, Players:GetPlayers() do
		if plr ~= Player then
			VisualizeMuzzle:FireClient(plr, Handle, MuzzleFlashEnabled, MuzzleLightData, MuzzleEffect, Replicate)
		end
	end
end)

PlayAudio.OnServerEvent:Connect(function(Player, Audio, LowAmmoAudio, Replicate)
	for _, plr in next, Players:GetPlayers() do
		if plr ~= Player then
			PlayAudio:FireClient(plr, Audio, LowAmmoAudio, Replicate)
		end
	end
end)

ShatterGlass.OnServerEvent:Connect(function(Player, Hit, Pos, Dir)
	if Hit then
		if Hit.Name == "_glass" then
			if Hit.Transparency ~= 1 then
				if PhysicEffect then
					local Sound = Instance.new("Sound")
					Sound.SoundId = "http://roblox.com/asset/?id=2978605361"
					Sound.TimePosition = .1
					Sound.Volume = 1
					Sound.Parent = Hit
					Sound:Play()
					Sound.Ended:Connect(function()
						Sound:Destroy()
			        end)
					GlassShattering:Shatter(Hit, Pos, Dir + Vector3.new(math.random(-25, 25), math.random(-25, 25), math.random(-25, 25)))
					--[[local LifeTime = 5
					local FadeTime = 1
					local SX, SY, SZ = Hit.Size.X, Hit.Size.Y, Hit.Size.Z
					for X = 1, 4 do
						for Y = 1, 4 do
							local Part = Hit:Clone()
							local position = Vector3.new(X - 2.1, Y - 2.1, 0) * Vector3.new(SX / 4, SY / 4, SZ)
							local currentTransparency = Part.Transparency
							Part.Name = "_shatter"
							Part.Size = Vector3.new(SX / 4, SY / 4, SZ)
							Part.CFrame = Hit.CFrame * (CFrame.new(Part.Size / 8) - Hit.Size / 8 + position)			
							Part.Velocity = Vector3.new(math.random(-10, 10), math.random(-10, 10), math.random(-10, 10))
							Part.Parent = workspace
							--Debris:AddItem(Part, 10)
							task.delay(LifeTime, function()
								if Part.Parent ~= nil then
									if LifeTime > 0 then
										local t0 = os.clock()
										while true do
											local Alpha = math.min((os.clock() - t0) / FadeTime, 1)
											Part.Transparency = Math.Lerp(currentTransparency, 1, Alpha)
							    			if Alpha == 1 then break end
						      				task.wait()
										end
										Part:Destroy()
									else
										Part:Destroy()
					    			end
								end
							end)
							Part.Anchored = false
						end
					end]]
				else
					local Sound = Instance.new("Sound")
					Sound.SoundId = "http://roblox.com/asset/?id=2978605361"
					Sound.TimePosition = .1
					Sound.Volume = 1
					Sound.Parent = Hit
					Sound:Play()
					Sound.Ended:Connect(function()
						Sound:Destroy()
			        end)
					local Particle = script.Shatter:Clone()
					Particle.Color = ColorSequence.new(Hit.Color)
					Particle.Transparency = NumberSequence.new{
						NumberSequenceKeypoint.new(0, Hit.Transparency), --(time, value)
						NumberSequenceKeypoint.new(1, 1)
					}
					Particle.Parent = Hit
					task.delay(0.01, function()
						Particle:Emit(10 * math.abs(Hit.Size.magnitude))
						Debris:AddItem(Particle, Particle.Lifetime.Max)
					end)
					Hit.CanCollide = false
					Hit.Transparency = 1
				end
			end
		else
			error("Hit part's name must be '_glass'.")
		end
	else
		error("Hit part doesn't exist.")
	end
end)

local function CalculateDamage(Damage, TravelDistance, ZeroDamageDistance, FullDamageDistance)
	local ZeroDamageDistance = ZeroDamageDistance or 10000
	local FullDamageDistance = FullDamageDistance or 1000
	local DistRange = ZeroDamageDistance - FullDamageDistance
	local FallOff = math.clamp(1 - (math.max(0, TravelDistance - FullDamageDistance) / math.max(1, DistRange)), 0, 1)
	return math.max(Damage * FallOff, 0)
end

InflictTarget.OnServerInvoke = function(Player, Module, Tool, Tagger, TargetHumanoid, TargetTorso, Damage, Misc, Critical, Hit, GoreData, ExplosiveData)
	SecureSettings(Player, Tool, Module) --Second layer
	local TrueDamage
	if ExplosiveData and ExplosiveData[1] then
		local DamageMultiplier = (1 - math.clamp((ExplosiveData[3] / ExplosiveData[2]), 0, 1))		
		TrueDamage = ExplosiveData[4] and ((Hit and Hit.Name == "Head" and Damage[3]) and Damage[1] * Damage[2] or Damage[1]) * DamageMultiplier or (Hit and Hit.Name == "Head" and Damage[3]) and Damage[1] * Damage[2] or Damage[1]
	else
		TrueDamage = Damage[5] and CalculateDamage((Hit and Hit.Name == "Head" and Damage[3]) and Damage[1] * Damage[2] or Damage[1], Damage[4], Damage[6], Damage[7]) or (Hit and Hit.Name == "Head" and Damage[3]) and Damage[1] * Damage[2] or Damage[1]
	end
	--GORE
	if TargetHumanoid.Health - TrueDamage <= 0 and not TargetHumanoid.Parent:FindFirstChild("gibbed") then
		if Hit then
			if Hit.Name == "Head" or Hit.Name == "Torso" or Hit.Name == "Left Arm" or Hit.Name == "Right Arm" or Hit.Name == "Right Leg" or Hit.Name == "Left Leg" or Hit.Name == "UpperTorso" or Hit.Name == "LowerTorso" or Hit.Name == "LeftUpperArm" or Hit.Name == "LeftLowerArm" or Hit.Name == "LeftHand" or Hit.Name == "RightUpperArm" or Hit.Name == "RightLowerArm" or Hit.Name == "RightHand" or Hit.Name == "RightUpperLeg" or Hit.Name == "RightLowerLeg" or Hit.Name == "RightFoot" or Hit.Name == "LeftUpperLeg" or Hit.Name == "LeftLowerLeg" or Hit.Name == "LeftFoot" then
				VisualizeGore:FireAllClients(Hit, TargetHumanoid.Parent, GoreData)
			end
		end
	end
	if Tagger then
		local CanDamage = DamageModule.CanDamage(TargetHumanoid.Parent, Tool.Parent, Damage[8])
		if ExplosiveData and ExplosiveData[1] and ExplosiveData[5] then
			if TargetHumanoid.Parent.Name == Tagger.Name then
				CanDamage = (TargetHumanoid.Parent.Name == Tagger.Name)
				if ExplosiveData[7] then
					TrueDamage = TargetHumanoid:GetState() ~= Enum.HumanoidStateType.Freefall and TrueDamage or (TrueDamage * (1 - ExplosiveData[6]))
				else
					TrueDamage = TrueDamage * (1 - ExplosiveData[6])
				end
			end
		end
		if TargetHumanoid and TargetHumanoid.Health ~= 0 and TargetTorso and CanDamage then
			while TargetHumanoid:FindFirstChild("creator") do
				TargetHumanoid.creator:Destroy()
			end
			local creator = Instance.new("ObjectValue",TargetHumanoid)
			creator.Name = "creator"
			creator.Value = Tagger
			Debris:AddItem(creator, 5)
			if Critical[1] then
				local CriticalChanceRandom = Random.new():NextInteger(0, 100)
				if CriticalChanceRandom <= Critical[2] then
					TargetHumanoid:TakeDamage(math.abs(TrueDamage * Critical[3]))
				else
					TargetHumanoid:TakeDamage(math.abs(TrueDamage))
				end			
			else
				TargetHumanoid:TakeDamage(math.abs(TrueDamage))
			end
			if Misc[1] > 0 then --knockback
				if not (ExplosiveData and ExplosiveData[1] and ExplosiveData[5]) then
					local Shover = Tagger.Character.HumanoidRootPart or Tagger.Character.Head
					local Duration = 0.1
					local Speed = Misc[1] / Duration
					local Velocity = (TargetTorso.Position - Shover.Position).Unit * Speed
					local ShoveForce = Instance.new("BodyVelocity")
					ShoveForce.MaxForce = Vector3.new(1e9, 1e9, 1e9)
					ShoveForce.Velocity = Velocity
					ShoveForce.Parent = TargetTorso
					Debris:AddItem(ShoveForce, Duration)					
				end
			end
			if Misc[2] > 0 and Tagger.Character.Humanoid and Tagger.Character.Humanoid.Health ~= 0 then --lifesteal
				if ExplosiveData and ExplosiveData[1] and ExplosiveData[5] then
					if not TargetHumanoid.Parent.Name == Tagger.Name then
						Tagger.Character.Humanoid.Health = Tagger.Character.Humanoid.Health + (TrueDamage * Misc[2])
					end
				else
					Tagger.Character.Humanoid.Health = Tagger.Character.Humanoid.Health + (TrueDamage * Misc[2])
				end
			end
			if Misc[3] then	--affliction
				local roll = math.random(1, 100)
				if roll <= Misc[5] then
					if not TargetHumanoid.Parent:FindFirstChild(Misc[4]) then
						local Debuff = Tool:FindFirstChild("GunScript_Server"):FindFirstChild(Misc[4]):Clone()
						Debuff.creator.Value = creator.Value
						Debuff.Parent = TargetHumanoid.Parent
						Debuff.Disabled = false
					end
				end
			end		
		end
	else
		warn("Unable to register damage because player is no longer existing here")
	end
end

Players.PlayerAdded:Connect(function(player)
	for i, v in pairs(_G.TempBannedPlayers) do
		if v == player.Name then
			player:Kick("You cannot rejoin a server where you were kicked from.")
			warn(player.Name.." tried to rejoin a server where he/she was kicked from.")
			break
		end
	end
end)