Are my weapon stats safe from exploiters?

I’m scripting a weapon. Pretty straightforward, but I want to check if this code i’ve written is safe from exploiters. I don’t want the client to get infinite ammo or make the firerate really fast.

--Client
RemoteFolder.GetStats:FireServer(Tool)
Ammo = Tool:WaitForChild("Ammo").Value
Clip = Tool:WaitForChild("Clip").Value
RefillS = Tool:WaitForChild("RefillS").Value

--Server
local sWeaponStats = ServerStorage.sWeaponStats
RemoteFolder.GetStats.OnServerEvent:Connect(function(Player, Tool)
	local Ammo = Instance.new("NumberValue")
	Ammo.Parent = Tool
	local Clip = Instance.new("NumberValue")
	Clip.Parent = Tool
	local RefillS = Instance.new("NumberValue")
	RefillS.Parent = Tool
	Ammo.Name = "Ammo"
	Clip.Name = "Clip"
	RefillS.Name = "RefillS"
	Ammo.Value = sWeaponStats[Tool.Name].Ammo.Value
	Clip.Value = sWeaponStats[Tool.Name].Clip.Value
	RefillS.Value = sWeaponStats[Tool.Name].RefillS.Value
end)
1 Like

The simple answer is not really, exploiters can change anything on the client that they want to. They don’t tend to have much effect on currently running scripts as by simply saying:

local ammo = Tool:WaitForChild("Ammo").Value -- an integer now stored in memory.

while true do
   ammo = ammo + 1
   print(ammo)
end

The value of the NumberValue will not change but the ammo within the script will, this is obviously very hard for an exploiter to counteract without deleting / altering the client script (as a thread is already running).

What your method has done however is make ammo dependent on the server number value, meaning they can simply recall the GetStats event in order to refill their old ammo back. Also by doing sWeaponStats[Tool.Name] you could only ever have one tool which is that name.

1 Like

I did consider that an exploiter may fire the GetStats event, but GetStats only makes new values. To my understanding, the client should only recognize the variables that were made when it was first fired.

If you’re handling the values like ammo on the client, it doesn’t matter where the client gets them from, it’s exploitable.

If you’re handling the values in the server, but just telling the client what the values are so a counter or visual is updated and such, it’s fine.

2 Likes

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).

1 Like