Help with a simple concommand

So I have an item. The item table has a function inside of it that will run when the entity is used.

That function sends a usermessage to the cl_init, which will draw a little menu asking what the player wants to do with it. The usermessage.Hook looks like this:


usermessage.Hook( "activateitem", function( data )
        local dat = data:ReadString()

	local frame = vgui.Create( "DFrame" )
	frame:SetPos( X/2-125, Y/2-75 )
	frame:SetSize( 250, 150 )
	frame:SetTitle( data:ReadString() )
	frame:MakePopup( true )

	local take = vgui.Create( "DButton", frame )
	take:SetPos( 10, 32 )
	take.DoClick = function()
		RunConsoleCommand( "u_use", data:ReadString() )
	end
end)

and it works beautifully. To a point… when I try to call the concommand “u_use” using the ‘RunConsoleCommand( “u_use”, data:ReadString() )’ it doesn’t do anything.

Now, the console command looks like this:


concommand.Add( "u_use", function( ply, cmd, args )
	print( args[1] )
end)

I removed the rest of the code which I had made into comments so that I could debug this issue. Right now it’s supposed to be printing the first argument sent (in this case it is the “data:ReadString()” that is being sent.)

Also, I am aware that these concommand arguments may only be strings. Not to mention that data:ReadString() is obviously going to be a string. To ensure that data:ReadString() has something in it, I have printed it as the frame title whenever I ran the usermessage hook. It works just fine.

If I remove the argument and modify the concommand to just be called and to then print a string, it works fine. The only part that wont work is when I try to send it the string as an argument from the usermessage. Can these things not be sent through a usermessage? I am doing it elsewhere in my code and it works just fine.

Even better would be if you could educate me on a better way to achieve this. I am aware of Net strings as well but IDK how to run a function using a net string… And even if you can a net string doesn’t carry from clientside into serverside…

Thanks for reading! Hope to get some help on this.

[editline]17th March 2014[/editline]

Alright, so I found the send to server command. When the string is sent to server, how would I be able to run a function with it?

Something like this:



net.Receive( "messagename",
    function( len, ply )
        yourFunction( ply, net.ReadString( ) ) -- for example
    end
)


Alright, that works for the function calling.
Yet again it’s not giving me the value though. I have narrowed it down to have something to do with either the data:ReadString() or the button.DoClick part. the data will read outside of the DoClick but not in the DoClick.

I believe that I read about something like “button:OnPressed()”

If I can find it, I’ll try that and get back to you. Thanks by the way.

[editline]18th March 2014[/editline]

Yeah. It was “OnMousePressed” although it seems to be doing the same thing.

[editline]18th March 2014[/editline]

Actually that one crashes my game with no errors in my server console.

[editline]18th March 2014[/editline]

Actually that one crashes my game with no errors in my server console.

[editline]18th March 2014[/editline]

Got it! Instead of using a usermessage, I used another net string to the client for the client file. God damn this was a pain. Thanks for teaching me how to receive a networked variable.

[editline]18th March 2014[/editline]

Got it! Instead of using a usermessage, I used another net string to the client for the client file. God damn this was a pain. Thanks for teaching me how to receive a networked variable.

Don’t use console commands to allow the client to communicate with the server; this opens up back-doors and may allow your code to be more easily exploited, especially if you need to call concommands in sequence for something to happen. If you were to use the concommand out of sequence it would call code out of order you were expecting… Use net-messages to allow the CLIENT to communicate with the SERVER.

Judging the many edits on your post, it looks like you’re definitely on the right track to doing all of that. Here’s some additionally help in networking:

Networking booleans; understanding the concept of sending multiple data with one message:
https://dl.dropboxusercontent.com/u/26074909/tutoring/networking/networking_booleans.lua

Honestly, concommands are still useful for things that don’t directly impact other players or saved data. Activate item is something (I’m guessing) gives you an item or toggles something which shouldn’t be bad as a concommand.

Concommands are useful for executing commands. For example, I use concommands as my chat command system:

In PlayerSay
[lua] //
// Do /commands privately, !commands publicly - Josh ‘Acecool’ Moser
//
local _bSlash = string.StartWith( text, “/” );
local _bExclaim = string.StartWith( text, “!” );
if ( _bSlash || _bExclaim ) then
Player:ConCommand( string.sub( text, 2 ) );
if ( !_bExclaim ) then
return “”;
end
end[/lua]

For things like:
[lua]//
// Cancel Timed Event
//
concommand.Add( “cancel”, function( ply, cmd, args )
if ( ply != NULL && !ply:IsSuperAdmin( ) ) then Log( ply, language.GetPhrase( “cancel_timedevent_log”, language.__default ) ); return; end
hook.Call( “CancelTimedEvent”, GAMEMODE, ply, args[ 1 ] );
end );

//
// Test of the Timed Event system.
//
concommand.Add( “test”, function( ply, cmd, args )
if ( ply != NULL && !ply:IsSuperAdmin( ) ) then Log( ply, language.GetPhrase( “test_log”, language.__default ) ); return; end
hook.Call( “TimedEvent”, GAMEMODE, “test”, tonumber( args[1] or 10 ), NOTIFY_HINT, “#test_event”, function( ) end, ply, true, ( args[2] && tonumber( args[2] ) || true ) );
end );

concommand.Add( “shutdown”, function( ply, cmd, args )
if ( ply != NULL && !ply:IsSuperAdmin( ) ) then Log( ply, language.GetPhrase( “shutdown_log”, language.__default ) ); return; end
hook.Call( “TimedEvent”, GAMEMODE, “shutdown”, tonumber( args[1] or 20 ) * TIME_MINUTE, NOTIFY_HINT, “#shutdown_event”, function( ) RunConsoleCommand( “disconnect” ); end, ply, true );
end );

//
// Executes Changelevel after set time
//
concommand.Add( “relevel”, function( ply, cmd, args )
if ( ply != NULL && !ply:IsSuperAdmin( ) ) then Log( ply, language.GetPhrase( “relevel_log”, language.__default ) ); return; end
hook.Call( “TimedEvent”, GAMEMODE, “relevel”, tonumber( args[1] or 20 ) * TIME_MINUTE, NOTIFY_HINT, “#relevel_event”, function( ) hook.Call( “RestartLevel”, GAMEMODE ); end, ply, true );
end );

concommand.Add( “v2p”, function( ply, cmd, args )
if ( ply != NULL && !ply:IsSuperAdmin( ) ) then Log( ply, language.GetPhrase( “relevel_log”, language.__default ) ); return; end
hook.Call( “TimedEvent”, GAMEMODE, “v2p”, tonumber( args[1] or 20 ) * TIME_MINUTE, NOTIFY_HINT, “#changelevel_v2p_event”, function( ) hook.Call( “RestartLevel”, GAMEMODE, “rp_evocity2_v2p” ); end, ply, true );
end );
concommand.Add( “v33”, function( ply, cmd, args )
if ( ply != NULL && !ply:IsSuperAdmin( ) ) then Log( ply, language.GetPhrase( “relevel_log”, language.__default ) ); return; end
hook.Call( “TimedEvent”, GAMEMODE, “v33”, tonumber( args[1] or 20 ) * TIME_MINUTE, NOTIFY_HINT, “#changelevel_v33_event”, function( ) hook.Call( “RestartLevel”, GAMEMODE, “rp_evocity_v33x” ); end, ply, true );
end );
[/lua]

And it works out nicely. Console commands should be for specific applications. But using them for communication in sequences such as in a poker-table, slot machine, etc is just asking for trouble…

Use them for a one-time command as in you can use it and use it again without it messing something else up. The above examples lets me either use cancel, v2p, v33, etc in console or ! and / in chat to execute the commands.

Don’t rely on it for primary networking is what I’m getting at…

Thank you very much for that. I did actually find out that the code could be exploited if you ran them out of order. Don’t Networked variables become heavy on the server though? Or is this the best way?

I have been sending tables through networked strings with util.TablestoKeyValues() to send more than just one piece of ‘code’

GetNW* can cause issues if not cached, if I recall correctly. I’d have to double-check some old code I wrote, but I believe it used those and it caused quite a slow-down.

The new system I made, which uses net-messages to send a flag only when a variable is updated, effectively caches values and makes the script run much quicker.

It’s all based on how you do it. You can use GetNW* and retain most speed, but it’d be better to cache it and update it every second or so; but you may have issues with variables that change quicker at times.

But, if it can be limited to only be updated when the variable changes and remain in cache without causing net-strain; that’s best-case because it’s essentially a networked variable which can just be grabbed without forcing the server to update it.

Here’s a quick benchmark on the NW vs a variable.
https://dl.dropboxusercontent.com/u/26074909/tutoring/benchmarking_tips/benchmarking_nw_vars.lua

NW stuff ran 100000 times and causing high-load.

Test1: Get the NWString each time, and concatenate it to a string - both CLIENT/SERVER around 36 seconds

Test2: Save the NWString in a variable, then concat that. Server was < 0.002 seconds, CLIENT was ~28 seconds – Not entirely sure on this one…

With just setting a variable based on NW stuff:
All ran 10000000 times in order to capture times on saving…

Test3: Get NWString each time and set it to a variable - both CLIENT and SERVER were around 2.5 to 2.8 seconds.

Test4: Storing the NWString in a variable before the loop then creating a local variable in the loop while setting the value to it.
// Server output: 0.0080000000016298
// Client output: 0.0090000000054715

Test5: Storing the copy text in a variable outside the loop and creating a new local var in the loop and setting the text to that var
// Server output: 0.0080000000016298
// Client output: 0.0090000000054715

Test 1: For the first test, pretty standard poor performance which was expected.
Test 2: it did show the server somehow managing to be just as fast as test 3 ( if we were to run it that many more times ) suggesting caching or something.
Test 3: Raw time just grabbing the NWString, initializing new local var and setting the new var to the NWString
Test 4: A “caching” approach.
Test 5: a “caching” approach. Both 4 and 5 gave equal results suggesting that if done properly, caching a NW* can be as efficient as using a plain variable which is updated when it needs to be.

Please for the sake of everyone, do not use networked variables. Use either usermessages or the net library.