Issue with ammo on my gun

So I was working on revamping my old gun system, and I wanted to add ammo, but I came across an issue pretty soon. If you have 1 magazine left, but you have 0 bullets in your current magazine, it wouldn’t reload. Here is the script:

Server script inside of tool

local db = false
local configs = script.Parent.Configs
script.Parent.Fire.OnServerEvent:Connect(function(player, mousePos)
	
	local storedammo = configs.StoredAmmo
	local ammo = configs.Ammo
	local mags = configs.Mags
	local tool = script.Parent
	--local fireAniM = tool.FireAnim
	local char = tool.Parent
	local hmoid = char.Humanoid

	--local animT = hmoid:LoadAnimation(fireAniM)
	
	if mags.Value ~= 0 and ammo.Value ~= 0 then
		if ammo.Value ~= 0 then

			ammo.Value -= 1

			--animT:Play()
			script.Parent.Handle.Shot:Play()


			local raycastParams = RaycastParams.new()
			raycastParams.FilterDescendantsInstances = {player.Character}
			raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

			local raycastResult = workspace:Raycast(script.Parent.Handle.Position, (mousePos - script.Parent.Handle.Position)*configs.BulletRange.Value,raycastParams)

			if raycastResult then

				local hitPart = raycastResult.Instance
				local model = hitPart:FindFirstAncestorOfClass("Model")

				if model then
					if model:FindFirstChild("Humanoid") then
						model.Humanoid:TakeDamage(script.Parent.Configs.Damage.Value)
						game:GetService("ReplicatedStorage"):WaitForChild("HitMark"):FireClient(player)
					end
				end
			end
		elseif ammo.Value == 0 then
			if not db then
				db = true
				script.Parent.Handle.Reload:Play()
				wait(script.Parent.Handle.Reload.TimeLength)
				mags.Value -= 1
				ammo.Value = storedammo.Value
				db = false
			end
		end
	end	
end)

Any help is appreciated!

In your first “if”, you look whether the gun has a mag and ammo left. You then do a check for when the ammo is not zero or when it’s zero. Because of this, the first if needs to be removed. Additionally, the mag check (whether you have a mag left) needs to be placed inside the elseif, because that’s where you reload the gun.

...
elsif ammo.Value == 0 and mags.Value ~= 0 then
...
1 Like

For some reason, it’s not working. No errors, just nothing is happening, updated script:

local db = false
local configs = script.Parent.Configs
script.Parent.Fire.OnServerEvent:Connect(function(player, mousePos)
	
	local storedammo = configs.StoredAmmo
	local ammo = configs.Ammo
	local mags = configs.Mags
	local tool = script.Parent
	--local fireAniM = tool.FireAnim
	local char = tool.Parent
	local hmoid = char.Humanoid

	--local animT = hmoid:LoadAnimation(fireAniM)
	
	if ammo.Value ~= 0 then

		ammo.Value -= 1

		--animT:Play()
		script.Parent.Handle.Shot:Play()


		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {player.Character}
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

		local raycastResult = workspace:Raycast(script.Parent.Handle.Position, (mousePos - script.Parent.Handle.Position)*configs.BulletRange.Value,raycastParams)

		if raycastResult then

			local hitPart = raycastResult.Instance
			local model = hitPart:FindFirstAncestorOfClass("Model")

			if model then
				if model:FindFirstChild("Humanoid") then
					model.Humanoid:TakeDamage(script.Parent.Configs.Damage.Value)
					game:GetService("ReplicatedStorage"):WaitForChild("HitMark"):FireClient(player)
				end
			end
		end
	elseif ammo.Value == 0 and ammo.Value ~= 0 then
		if not db then
			db = true
			script.Parent.Handle.Reload:Play()
			wait(script.Parent.Handle.Reload.TimeLength)
			mags.Value -= 1
			ammo.Value = storedammo.Value
			db = false
		end
	end
end)

Also, should I keep the reloads, and ammo on the server or the client?

omg I am dumb

You have a typo in your script, typed “ammo.Value ~= 0” instead of “mags.Value ~= 0”.

1 Like

I just realized that, thank you, it works like a charm!

Depends on the design, but if you don’t want your players to be able to exploit, then you should store the important information on the server. Even hitting a player could be checked by the server, so that an exploiter can’t shoot a player across the map.

1 Like

Everything but the detection of the player clicking and the ammo gui is on the client. I have another question, I made the walk speed of a player change when you equip the gun on the client, should it be on the server?

Sadly speedhacking is very easy due to the fact that the client can change everything on its own machine. Even when only setting the speed change (from the gun) server-side, the player can still speedhack. What you could do is timed checks on the server, setting the speed of the player accordingly, so when the player changes its speed on his client, it gets reset. But this can be heavy on performance so might not be the perfect solution.

EDIT: In general, it’s very difficult to make a game 100% exploit proof. So I would keep exploit defence in mind, but would compare it with the potential performance decrease. In the end, exploiters are not present in very big numbers, so the experience of normal players has a big factor.

1 Like

I was mostly thinking about if the change in the walk speed on the client was displayed on the server so other players could see it. I am pretty sure you can get the player in the equipped function like this:

tool.Equipped:Connect(function(plr)

end)

Is something like this possible? Also thank you for the information on exploiters.

EDIT: I did a test about printing the plr on the server, and it just prints “Instance”.

Yes, you can see server side whether a player has a weapon equipped, but it’s more difficult then just doing it client side tbh. Client side, it’s like you showed with the function (without the player), but server side, you would need to check whether the tool is in the backpack of the player (How do I check if a tool is equipped? - #2 by BasedKnowledge).

So personally, I would do it client side. If you need information from the server when you equip the weapon, you can get that by making a remote function.

1 Like

If I do this:

script.Parent.Equipped:Connect(function()
	game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = script.Parent.Configs.WalkSpeed.Value
end)
script.Parent.Unequipped:Connect(function()
	game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = 16
end)

In a local script, can other players see the change of speed? If you answered this question in your reply, sorry I either didn’t see it, or understood it.

Yes, but the server itself will not know how fast the player is walking.
Let’s say that there are two players, A and B. They both have speed 10. Player A changes its speed locally with your code, so its speed becomes 16. When player A walks around, the server and player B can see that player A is moving faster, but the speed value for the server will still be 10. This is not really a problem when the server doesn’t need that information though.

EDIT: If you’re not sure on some things regarding server replication, you can always create two game instances with the “start server” button on the test tab in Roblox Studio, after selecting two players. You basically start a game with that button where each window that opens is another player.

1 Like