My point was about the server side is:
-- these are not backed up at all, so once the function is called you will automatically get all your ammo back.
Ammo.Value = sWeaponStats[Tool.Name].Ammo.Value
Clip.Value = sWeaponStats[Tool.Name].Clip.Value
RefillS.Value = sWeaponStats[Tool.Name].RefillS.Value
If you want a truly sound and protected method then as @Autterfly said, fetch values off the server. From my experience making weaponry however, its not necessarily required that you need to protect your assets from exploits like these. It is all good having infinite ammo, but that still requires you to be able to aim - hence why most exploiters use aim bots and don’t exploit the munitions at all. As general practice you probably shouldn’t store values within NumberValue anyway, unless its being used as a start up value. This is mainly because it automatically raises the question of “what prevents me from just changing the values easily”, changing active threads is a lot more difficult especially when the memory location is being stored.
A small thing to note, if a client changes something on their side it doesn’t reflect onto the server i.e. you can always update the value based on what the server sees and not what the client sees.
If your interested:
Some highly complicated, most unnecessary and not probably fully accurate and very basic explanation about memory, this is probably wrong purely because I've oversimplified the process too much.
From what I know (this is mainly based on Python, but I’m guessing Roblox’s Lua Engine is probably similiar in handling - just with better memory deletion [because python doesn’t actually delete that memory address in the event you recall data, whereas java does]), essentially when you do:
local location = 0
“location” points to a memory address, its very difficult to then track that memory address so you can change it. Even if you did track it, the memory would then most likely be redundant as the player has died to another memory location was allocated as they’ve got a new weapon. When you use a NumberValue its very easy to change the value specifically because its a direct pointer, its relatively fixed and its very obvious.
If you want to keep your server storage clean..
Another method instead of having to fetch things from server storage could be to use a dictionary.
Example:
-- basics into how a dictionary works
local weapons = {
Gun = {
Ammo = 5
}
}
myAmmo = weapons["Gun"]["Ammo"]
You can then use this to individualize and assess weapons, whilst also maintaining all values into a single script and not having a huge amount of NumberValue in a single folder. You would also use up less memory as your no longer storing instances of a Number Value Class (which is what a NumberValue is).