Custom concommand for server-side call

I am using the Pointshop addon. I’ve looked through Facepunch to see if anyone else has had the same issue, and I’ve found a few but no solution.
I’ve attempted to compile the ideas together for a custom concommand that will allow me to type a console command in the box, and it give points to a player.

On the pointshop side it uses:


ply:PS_GivePoints(amount)

I found this solution, but it doesn’t appear to work:



concommand.Add("ps_givepoints", function(ply, cmd, args)
	-- Give Points
	if ply:IsPlayer() then return false end
	
	local to_give = args[1]
	local num = tonumber(args[2])
	
	if not to_give or not num then
		ply:PS_Notify("Please give a name and number!")
		return
	end
	
	if not type(to_give) == "player" then
		if to_give then
			ply:PS_Notify("You weren't specific enough with the name you typed!")
		else
			ply:PS_Notify("No player found by that name!")
		end
	else
		to_give:PS_GivePoints(num, "given by " .. ply:Nick() .. "!")
	end
end)


I only want to do it from the actual console in the box (not in garry’s mod in-game console).
Basically I just need this because I’ve linked up points to a mysql database, and I made an rcon connection via PHP and I want to execute the rcon command to give points so I don’t have to go in-game and do it.

I tried injecting the points into the mysql database for the user, which updates fine, but when the server dishes out points every 10 minutes, it overrides that amount.

Any help appreciated.

Well, here’s a list:

  1. You want to do IsValid(ply) instead of ply:IsPlayer().
  2. All of the arguments for the concommand are strings. Therefore, to_give will always be a string, not a player. To get the player object, you will need to iterate through player.GetAll() and find the player (or players, depending on your preference) and check if the name has the first argument inside.
  3. Instead of using type, just check if no players were found after checking if any players match the name.

Try this for getting the players:



local players = {}
for _, p in pairs(player.GetAll()) do
	if p:Name():find(args[1], 1, true) then
		players[#players + 1] = p
	end
end

if #players > 1 then
	-- Do what happens when more than one player was found
elseif #players == 0 then
	-- Do what happens when no players were found.
else
	-- Do what happens when one player is found.
end


Probably not completely correct, but am I heading in the correct direction:


concommand.Add("ps_givepoints", function(ply, cmd, args)
	-- Give Points
	if IsValid(ply) then return false end
	
	local to_give = args[1]
	local num = tonumber(args[2])
	local players = {}

	for _, p in pairs(player.GetAll()) do
		if p:Name():find(args[1], 1, true) then
			players[#players + 1] = p
		end
	end

	if #players > 1 then
		print("More than one result found, please narrow your search")
	elseif #players == 0 then
		print("No players match that query")
	else
		to_give:PS_GivePoints(num)
	end
end)

You mention to_give as a string, so just loop through the players. Instead of to_give how would I capture the one player being found.

You are heading there. Use the first player value in the player table (players[1]) as the object to execute the PS_GivePoints method on. Since there can only be one player in the table due to the “ifs,” it will always be the only player found.



concommand.Add("ps_givepoints", function(ply, cmd, args)
	-- Give Points
	if IsValid(ply) then return end
	
	local name = args[1]
	local num = tonumber(args[2])
	local players = {}

	for _, p in pairs(player.GetAll()) do
		if p:Name():find(name, 1, true) then
			players[#players + 1] = p
		end
	end

	if #players > 1 then
		print("More than one result found, please narrow your search")
	elseif #players == 0 then
		print("No players match that query")
	else
		players[1]:PS_GivePoints(num)
	end
end)


Why are you returning if the player is valid, shouldn’t you be doing that if they aren’t valid?

Tried it out by joining the server, and it returns “No player matches that query” even with my name in console being added. Unless I’m missing another step.

[editline]19th May 2015[/editline]

[Edit] Is working, had to fix something in the code. Explain the player is valid comment, because I’d like to fix this up and post the solution if you don’t mind, on here so others can use it. It seems to be something others have asked about with no real solution (if AK doesn’t mind)

I assume he wants an RCon only command.

An rcon only command would be appreciated. I’m going to accomplish where I can execute the rcon comment via our php script (that part is done) and functions. But my fear is I don’t want someone on staff “guessing” the command and issuing points. Since the original pointshop only allows admins and up to issue points. So the only thing I think I’m missing are conditional values to block such actions.

[editline]19th May 2015[/editline]


concommand.Add("ps_givepoints", function(ply, cmd, args)
	if IsValid(ply) then return end
	
	local name = args[1]
	local num = tonumber(args[2])
	local players = {}

	for _, p in pairs(player.GetAll()) do
		if p:Name():find(name, 1, true) then
			players[#players + 1] = p
		end
	end

	if #players > 1 then
		print("More than one result found, please narrow your search")
	elseif #players == 0 then
		print("No players match that query")
	else
		players[1]:PS_GivePoints(num)
		print(num .. " points given to " .. players[1]:Nick())
	end
end)

[lua]concommand.Add( “ps_givepoints”, function( ply, cmd, args )
if IsValid( ply ) then return end

for k, v in pairs( player.GetAll() ) do
	if v:Nick() == args[1] then
		v:PS_GivePoints( args[2] )
	else
		print( "That name couldn't be found!" )
	end
end

end )[/lua]

As simple as it gets, no fancy auto complete, you would need the full name.

It would be better to do it with SteamIDs anyway by changing v:Nick() to v:SteamID() and the print to say SteamID instead of name.

Edit: Derp, this will only work if the players are online :stuck_out_tongue:
You would probably need to use MySQL to set it by ID or name if the players are offline. Or PData is you aren’t using MySQL.

Since our online system in PHP uses steamid, I may want to just go with SteamID anyway. Because I don’t want them to have to be on the server to issue points.

Your code will only work for players who are online.

Unfortunately pointshop uses UniqueID by default (it would probably have been better to use SteamID64 for this exact reason), so you’d have to use util.CRC to make an equivalent hash from the Steam ID. From there, you’d have to either modify the pointshop’s mysql data provider to add offline compatibility or, alternatively, make another connection and query the database adding/setting points based on the Steam ID.



-- To go from steam id to unique id, do:
util.CRC('gm_'..steamidhere..'_gm')


Edit:

Forgot about this: instead of having a IsValid(ply) check, change the flag of the console command to FCVAR_SERVER_CAN_EXECUTE.



concommand.Add("ps_givepoints", function(ply, cmd, args)
    local name = args[1]
    local num = tonumber(args[2])
    local players = {}

    for _, p in pairs(player.GetAll()) do
        if p:Name():find(name, 1, true) then
            players[#players + 1] = p
        end
    end

    if #players > 1 then
        print("More than one result found, please narrow your search")
    elseif #players == 0 then
        print("No players match that query")
    else
        players[1]:PS_GivePoints(num)
        print(num .. " points given to " .. players[1]:Nick())
    end
end,
nil,
FCVAR_SERVER_CAN_EXECUTE)