Am I safely handling user input?

Hello, everyone. I have been making gun systems for around a year now, and I’ve never really given thought about the way I handle user input. Is this safe to use, or can it be easily exploited?

Local Code ( StarterCharacterScripts ):
Basically, we got a table for our binds:

local binds = {
	[1] = Enum.KeyCode.One,
	[2] = Enum.KeyCode.Two,
	[3] = Enum.KeyCode.Three
}

then, we loop through that table using ContextActionService:

for i in pairs(binds) do
	CAS:BindAction("equip"..i, equip, false, binds[i])
end

the equip() function:

local function equip(name, state, obj)
	if state ~= Enum.UserInputState.Begin then return end
	
	local index = tonumber(string.split(name, "equip")[2])
	
	if type(binds[index]) ~= type(obj) then return end
	
	h:equip(index)
end

now, you may have noticed h, its just a module for weapon framework lol, I changed it to weapon

Received by module:

function module:equip(index)
	_, _ = pcall(function()
		if index == table.find(self.loadout, self.curwep.Name) then return end
	end)	
	
	if self.equipped then 
		for i in self.loadedAnimations[self.curwep.Name] do
			self.loadedAnimations[self.curwep.Name][i]:Stop()
		end
		
		self.settings = nil
	end
	
	if index > #self.loadout then return end

	local wep = self.loadout[index]

	local response = repStorage.events.equip:InvokeServer(index)
	if not response then return end

	wep = self.character:FindFirstChild(wep)

	if not self.loadedAnimations[wep.Name] then
		self.loadedAnimations[wep.Name] = {}
	end

	if not self.loadedAnimations[wep.Name].idle then
		self.loadedAnimations[wep.Name].idle = self.humanoid:LoadAnimation(wep.animations.idle)
	end

	self.loadedAnimations[wep.Name].idle:Play()

	self.settings = require(wep.settings)
	
	self.curwep = wep
	self.equipped = true
	self.canFire = true
end

Server event equip:

events.equip.OnServerInvoke = function(plr, index)
	if players[plr.UserId].cooling then return false end
	
	if not players[plr.UserId].loadout[index] then return false end
	
	if players[plr.UserId].curwep then
		local wep = plr.Character:FindFirstChild(players[plr.UserId].curwep.name)
		if not wep then return end
		
		wep:Destroy()
	end
	
	local wep = game.ReplicatedStorage.weapons:FindFirstChild(players[plr.UserId].loadout[index])
	if not wep then return false end
	
	wep = wep:Clone()
	wep.Parent = plr.Character
	
	local weld = wep.root.torso
	weld.Part0 = plr.Character.Torso
	weld.Part1 = wep.root
	
	players[plr.UserId].equipped = true
	
	local sets = require(wep.serverSets)
	
	local ammoV
	
	if players[plr.UserId].savedAmmo[players[plr.UserId].loadout[index]] then
		ammoV = players[plr.UserId].savedAmmo
	else
		players[plr.UserId].savedAmmo[players[plr.UserId].loadout[index]] = sets.clip
		ammoV = sets.slip
	end
	
	players[plr.UserId].curwep = {name = players[plr.UserId].loadout[index], settings = sets, ammo = ammoV}
	
	coroutine.wrap(function()
		players[plr.UserId].cooling = true
		task.wait(COOLDOWN_TIME)
		players[plr.UserId].cooling = false
	end)()
	
	return true
end

btw, players[plr.UserId] is just a table with the given player’s info.

All the client should be doing is asking for certain inputs to be done, so yes you are safely handling user input.

1 Like

Thanks for letting me know! edwndjknas

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