Help with reload system

I have a reload system for a game, it works but is extremely buggy and prone to breaking, if you switch weapons while an old one is reloading and try to reload the new one everything breaks spectacularly, the reload text does not show up. Sometimes the game things the gun has no ammo at all for some reason, I tried to remake this system like 4 times now and every time it bugs so I don’t know what to do at all anymore. I know this script is trusting the client, its a single player game so It’s fine and there are an exact replica of the client script for each gun in the game with unique attributes

Server:

local event = game.ReplicatedStorage.ImportantRemotes.ReloadGun

local activeReloads = {}

function reloadEvent(player, Gun)
	if player.Character.Humanoid.Health <= 0 then return end
	if Gun:GetAttribute("CanShoot") == false then return end

	activeReloads[Gun] = true
	
	player.PlayerGui.Gun.Frame.Ammo.Text = "Reloading..."

	print("Reload started")
	Gun:SetAttribute("CanShoot", false)

	local bulletsLeft = Gun:GetAttribute("BulletsLeft")
	local inMag = Gun:GetAttribute("InMag")
	local maxMagSize = Gun:GetAttribute("MagSize")
	local ammoToFill = maxMagSize - inMag

	if bulletsLeft == 0 then
		Gun:SetAttribute("CanShoot", true)
		return
	end

	player.PlayerGui.Gun.Frame.Ammo.Text = "Reloading..."
	
	task.wait(Gun:GetAttribute("ReloadTime"))


	if bulletsLeft >= ammoToFill then
		Gun:SetAttribute("InMag", maxMagSize)
		Gun:SetAttribute("BulletsLeft", bulletsLeft - ammoToFill)
	else
		Gun:SetAttribute("InMag", bulletsLeft)
		Gun:SetAttribute("BulletsLeft", 0)
	end

	Gun:SetAttribute("CanShoot", true)
	--player.PlayerGui.Gun.Frame.Ammo.Text = Gun:GetAttribute("InMag") .. "/" .. Gun:GetAttribute("BulletsLeft")
	print("Reload ended")
	activeReloads[Gun] = false

end

event.OnServerEvent:Connect(function(player, Gun)
	
	if not activeReloads[Gun] then
		task.spawn(reloadEvent, player, Gun)
		
	end
end)

client:

local tool = script.Parent
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

local UIS = game:GetService("UserInputService")

local shootEvent = script.Parent:WaitForChild("DealDamage")
local decreaseAmmo = script.Parent:WaitForChild("DecreaseAmmo")
local setAmmo = game.ReplicatedStorage.ImportantRemotes.ReloadGun
local AmmoTextLabel = player.PlayerGui.Gun.Frame.Ammo
local GynTypeTextLabel = player.PlayerGui.Gun.Frame.GunType
--tool.Activated:Connect(function()
--	local MP = mouse.Hit.Position
--	shootEvent:FireServer(player)
--end)
local tool = script.Parent

local BulletsFolder = game.Workspace:WaitForChild("Bullets")

local FastCast = require(game.ReplicatedStorage.FastCastRedux)
-- FastCast.VisualizeCasts = true
local castBehavior = FastCast.newBehavior()

local castParams = RaycastParams.new()
castParams.FilterType = Enum.RaycastFilterType.Exclude
castParams.IgnoreWater = true

local HoldingTrigger = true
local Equipped = false

local bulletTemplate = Instance.new("Part")
bulletTemplate.Anchored = true
bulletTemplate.CanCollide = false
bulletTemplate.Size = Vector3.new(0.1, 0.1, 4) 
bulletTemplate.Material = Enum.Material.Neon
bulletTemplate.BrickColor = BrickColor.new("Yellow flip/flop")

castBehavior.RaycastParams = castParams
castBehavior.CosmeticBulletContainer = BulletsFolder
castBehavior.CosmeticBulletTemplate = bulletTemplate

local function updateAmmo()
	AmmoTextLabel.Text = script.Parent:GetAttribute("InMag").."/"..script.Parent:GetAttribute("BulletsLeft")
end

local function Hit(cast, result, velocity, bullet)

	game.Debris:AddItem(bullet, 0.1)

	if Equipped == false then return end
	local hit = result.Instance
	local character = hit:FindFirstAncestorWhichIsA("Model")
	if character and character:FindFirstChild("Humanoid") then
		shootEvent:FireServer(character.Humanoid, 20)
		--character.Humanoid:TakeDamage(20)
	end


end

local function onLengthChanged(cast, lastPoint, direction, length, velocity, bullet)
	if Equipped == false then return end
	if bullet then
		local bulletLength = bullet.Size.Z / 2
		local offset = CFrame.new(0, 0, -(length - bulletLength))
		bullet.CFrame = CFrame.lookAt(lastPoint, lastPoint + direction):ToWorldSpace(offset)
	end
end

local function equipped()
	Equipped = true
	player.PlayerGui.Gun.Frame.Ammo.Text = script.Parent:GetAttribute("InMag").."/"..script.Parent:GetAttribute("BulletsLeft")
	player.PlayerGui.Gun.Frame.GunType.Text = script.Parent.Name
	castParams.FilterDescendantsInstances = {tool.Parent, BulletsFolder}
end

local caster = FastCast.new()

local function shoot()
	if Equipped == false then return end
	if script.Parent:GetAttribute("InMag") > 0 and script.Parent:GetAttribute("CanShoot") == true and player.Character.Humanoid.Health > 0 then
		if script.Parent:GetAttribute('FireType') == "Semi" then
			decreaseAmmo:FireServer()
			local firePoint = script.Parent.Barrel.FirePoint
			local origin = firePoint.WorldPosition
			local direction = player.Character.HumanoidRootPart.CFrame.LookVector.Unit
			tool.ShootSound:Play()
			--updateAmmo()
			caster:Fire(origin, direction * 100, 100, castBehavior)
		elseif script.Parent:GetAttribute('FireType') == "Auto" then
			while task.wait(script.Parent:GetAttribute('TimeBetweenShotsAuto')) do
				if HoldingTrigger == false or Equipped == false or tool:GetAttribute("InMag") <= 0 or tool:GetAttribute("CanShoot") == false then break end
				decreaseAmmo:FireServer()
				local firePoint = script.Parent.Barrel.FirePoint
				local origin = firePoint.WorldPosition
				local direction = player.Character.HumanoidRootPart.CFrame.LookVector.Unit
				tool.ShootSound:Play()
				--updateAmmo()
				caster:Fire(origin, direction * 100, 100, castBehavior)
			end

		end

	else
		tool.GunEmpty:Play()
	end
end

UIS.InputBegan:Connect(function(input, gp)
	if gp then return end

	if input.KeyCode == Enum.KeyCode.R then
		if Equipped == false then return end
		setAmmo:FireServer(script.Parent)
	end

end)

mouse.Button1Down:Connect(function()
	if Equipped == false then return end
	HoldingTrigger = true
end)

mouse.Button1Up:Connect(function()
	if Equipped == false then return end
	HoldingTrigger = false
end)

tool.Unequipped:Connect(function()
	if Equipped == false then return end
	Equipped = false
end)

script.Parent:GetAttributeChangedSignal("InMag"):Connect(function()
	player.PlayerGui.Gun.Frame.Ammo.Text = script.Parent:GetAttribute("InMag").."/"..script.Parent:GetAttribute("BulletsLeft")
end)

script.Parent:GetAttributeChangedSignal("BulletsLeft"):Connect(function()
	player.PlayerGui.Gun.Frame.Ammo.Text = script.Parent:GetAttribute("InMag").."/"..script.Parent:GetAttribute("BulletsLeft")
end)

tool.Equipped:Connect(equipped)
tool.Activated:Connect(shoot)
caster.LengthChanged:Connect(onLengthChanged)
caster.RayHit:Connect(Hit)

1 Like

Fixed it

Server:

local event = game.ReplicatedStorage.ImportantRemotes.ReloadGun

local activeReloads = {}

function reloadEvent(player, Gun)
	if player.Character.Humanoid.Health <= 0 then return end
	if Gun:GetAttribute("CanShoot") == false then return end
	
	print('Reload event fired with ', Gun.Name)
	
	activeReloads[Gun] = true
	

	print("Reload started")
	Gun:SetAttribute("CanShoot", false)

	local bulletsLeft = Gun:GetAttribute("BulletsLeft")
	local inMag = Gun:GetAttribute("InMag")
	local maxMagSize = Gun:GetAttribute("MagSize")
	local ammoToFill = maxMagSize - inMag
	
	
	if bulletsLeft == 0 then
		Gun:SetAttribute("CanShoot", true)
		return
	end
	
	task.wait(Gun:GetAttribute("ReloadTime"))


	if bulletsLeft >= ammoToFill then
		Gun:SetAttribute("InMag", maxMagSize)
		Gun:SetAttribute("BulletsLeft", bulletsLeft - ammoToFill)
	else
		Gun:SetAttribute("InMag", bulletsLeft)
		Gun:SetAttribute("BulletsLeft", 0)
	end

	Gun:SetAttribute("CanShoot", true)
	print("Reload ended")
	activeReloads[Gun] = false

end


event.OnServerEvent:Connect(function(player, Gun)
	
	local bulletsLeft = Gun:GetAttribute("BulletsLeft")
	local inMag = Gun:GetAttribute("InMag")
	local maxMagSize = Gun:GetAttribute("MagSize")
	local ammoToFill = maxMagSize - inMag
	
	if ammoToFill == 0 then return end
	
	print(ammoToFill)
	
	if not activeReloads[Gun] then
		player.PlayerGui.Gun.Frame.Ammo.Text = "Reloading..."
		task.spawn(reloadEvent, player, Gun)
		
	end
end)

Client:

local tool = script.Parent
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

local UIS = game:GetService("UserInputService")

local shootEvent = script.Parent:WaitForChild("DealDamage")
local decreaseAmmo = script.Parent:WaitForChild("DecreaseAmmo")
local setAmmo = game.ReplicatedStorage.ImportantRemotes.ReloadGun
local AmmoTextLabel = player.PlayerGui.Gun.Frame.Ammo
local GynTypeTextLabel = player.PlayerGui.Gun.Frame.GunType
--tool.Activated:Connect(function()
--	local MP = mouse.Hit.Position
--	shootEvent:FireServer(player)
--end)
local tool = script.Parent

local BulletsFolder = game.Workspace:WaitForChild("Bullets")

local FastCast = require(game.ReplicatedStorage.FastCastRedux)
-- FastCast.VisualizeCasts = true
local castBehavior = FastCast.newBehavior()

local castParams = RaycastParams.new()
castParams.FilterType = Enum.RaycastFilterType.Exclude
castParams.IgnoreWater = true

local HoldingTrigger = true
local Equipped = false

local shotCooldown = false

local bulletTemplate = Instance.new("Part")
bulletTemplate.Anchored = true
bulletTemplate.CanCollide = false
bulletTemplate.Size = Vector3.new(0.1, 0.1, 4) 
bulletTemplate.Material = Enum.Material.Neon
bulletTemplate.BrickColor = BrickColor.new("Yellow flip/flop")

castBehavior.RaycastParams = castParams
castBehavior.CosmeticBulletContainer = BulletsFolder
castBehavior.CosmeticBulletTemplate = bulletTemplate

local function updateAmmo()
	AmmoTextLabel.Text = script.Parent:GetAttribute("InMag").."/"..script.Parent:GetAttribute("BulletsLeft")
end

local function Hit(cast, result, velocity, bullet)

	game.Debris:AddItem(bullet, 0.1)

	if Equipped == false then return end
	local hit = result.Instance
	local character = hit:FindFirstAncestorWhichIsA("Model")
	if character and character:FindFirstChild("Humanoid") then
		shootEvent:FireServer(character.Humanoid, 20)
		--character.Humanoid:TakeDamage(20)
	end


end

local function onLengthChanged(cast, lastPoint, direction, length, velocity, bullet)
	if Equipped == false then return end
	if bullet then
		local bulletLength = bullet.Size.Z / 2
		local offset = CFrame.new(0, 0, -(length - bulletLength))
		bullet.CFrame = CFrame.lookAt(lastPoint, lastPoint + direction):ToWorldSpace(offset)
	end
end

local function equipped()
	Equipped = true
	updateAmmo()
	player.PlayerGui.Gun.Frame.GunType.Text = script.Parent.Name
	castParams.FilterDescendantsInstances = {tool.Parent, BulletsFolder}
end

local caster = FastCast.new()

local function shoot()
	if Equipped == false then return end
	if script.Parent:GetAttribute("InMag") > 0 and script.Parent:GetAttribute("CanShoot") == true and player.Character.Humanoid.Health > 0 then
		if script.Parent:GetAttribute('FireType') == "Semi" then
			if shotCooldown then return end
			shotCooldown = true
			decreaseAmmo:FireServer()
			local firePoint = script.Parent.Barrel.FirePoint
			local origin = firePoint.WorldPosition
			local direction = player.Character.HumanoidRootPart.CFrame.LookVector.Unit
			tool.ShootSound:Play()
			caster:Fire(origin, direction * 100, 100, castBehavior)
			task.wait(tool:GetAttribute("FireRate"))
			shotCooldown = false
		elseif script.Parent:GetAttribute('FireType') == "Auto" then
			while task.wait(script.Parent:GetAttribute('FireRate')) do
				if HoldingTrigger == false or Equipped == false or tool:GetAttribute("InMag") <= 0 or tool:GetAttribute("CanShoot") == false then break end
				decreaseAmmo:FireServer()
				local firePoint = script.Parent.Barrel.FirePoint
				local origin = firePoint.WorldPosition
				local direction = player.Character.HumanoidRootPart.CFrame.LookVector.Unit
				tool.ShootSound:Play()

				caster:Fire(origin, direction * 100, 100, castBehavior)
				
			end
			if  tool:GetAttribute("InMag") == 0 then
				tool.GunEmpty:Play()
			end
		end

	else
		tool.GunEmpty:Play()
	end
end

UIS.InputBegan:Connect(function(input, gp)
	if gp then return end

	if input.KeyCode == Enum.KeyCode.R then
		if Equipped == false then return end
		if tool:GetAttribute("InMag") ~= tool:GetAttribute("MagSize") then
			tool.Reload:Play()
			player.PlayerGui.Gun.Frame.Ammo.Text = "Reloading..."
			setAmmo:FireServer(script.Parent)
		end

	end

end)

mouse.Button1Down:Connect(function()
	if Equipped == false then return end
	HoldingTrigger = true
end)

mouse.Button1Up:Connect(function()
	if Equipped == false then return end
	HoldingTrigger = false
end)

tool.Unequipped:Connect(function()
	if Equipped == false then return end
	Equipped = false
end)

script.Parent:GetAttributeChangedSignal("InMag"):Connect(function()
	if not Equipped then return end
	updateAmmo()
end)

script.Parent:GetAttributeChangedSignal("BulletsLeft"):Connect(function()
	if not Equipped then return end
	updateAmmo()
end)

tool.Equipped:Connect(equipped)
tool.Activated:Connect(shoot)
caster.LengthChanged:Connect(onLengthChanged)
caster.RayHit:Connect(Hit)

For some reason setting the reload text on the server did not work after the first call of the remote so I put more work on the client and not it works, its insecure but not an issue for my game specifically

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.