Net Library Usage
Before reading this page, please ensure you understand the basics of Lua, or you will get stuck!
What is the net library?
The net library is one of a number of ways to send data between the client and server.
The major advantages of the net library is the large size limit compared to usermessage and console commands, 65533 bytes (64KiB with 3 bytes of unusable overhead) per message, and the ability to send data backwards - from the client to the server.
Using the net library
When you send a net message, you will most likely get an error which contains a shortened URL. This is because the message isn't precached. To precache a message, just call this once server-side:
Note: you will need to wait a couple of seconds after precaching before sending the message.
To be able to send data with the net library, there must be something to handle that data when it's received. We use the function net.Receive, which has two arguments: the name of the net message and the callback function to run when the message is received.
Below is an example of receiving a net message:
net.Receive( "MyMessage", function( len, ply ) print("I got it!") end)
Once our net message "MyMessage" is sent, the receiving function is called. The first argument of the receive function is the length of the message (which should mostly be ignored, unless you are debugging or something), the second is the player who sent it, this is only used when net.SendToServer is called (see below).
Now that we have a function to receive it, we need to send the message.
util.AddNetworkString( "myMessage" )
Then to start sending a net message, call net.Start with the name of the message. Then,
- Serverside: Use net.Send, which has one argument: a Player or a table of players. If you sending to all players, use net.Broadcast.
- Clientside: Use net.SendToServer.
For example, if you wanted to send the myMessage net message, you would do
net.Start("myMessage") net.Send( Entity( 1 ) )
The message sent would be empty, next we will look at sending data in net messages. Generally empty net messages are used as a simple way of alerting the player of something that has happened on the server which the client does not know about unless the server tells them about it, for example, after a certain time has passed on the server, an empty net message could be sent to the client to tell them that a menu should be opened.
For reading data, there are functions for each writable type of data above, generally being net.Read(Type).
You must read data in the same order that you sent it.
It is recommended you have a basic understanding of hooks before you attempt these.
util.AddNetworkString( "PlayerDied" ) hook.Add( "PlayerDeath", "NotifiyClient", function( ply, inf, att ) if IsValid( ply ) then -- Make sure the dead player exists net.Start( "PlayerDied" ) net.WriteEntity( ply ) net.Broadcast() end end )
net.Receive( "PlayerDied", function() local ply = net.ReadEntity() chat.AddText( ply, Color( 255, 0, 0 ), "has died!" ) end )
Explaination: Since chat.AddText is a function that we can only use on the client we need to find a way to tell the client that a player died. The solution is simple, in the GM:PlayerDeath hook, use net.WriteEntity to send the entity to the client, read the entity then run chat.AddText with the colors we want.
Challenges (Don't progress until you have done these!): Can you make it tell everyone who the player was killed by? Can you make it so that it only tells the attacker they killed a player?
Example 2: Giving the server information from the client. We want to know how old the player is, and we also want everyone on the server to know about it. The problem is, VGUI functions can only be called clientside, but don't worry, the net library is here!
local frame = vgui.Create( "DFrame" ) frame:SetSize( 400, 400 ) frame:SetTitle( "What is your age?" ) frame:Center() local age = vgui.Create( "DNumberWang", frame ) age:Dock( TOP ) age:SetDecimals( 0 ) age:SetMin( 0 ) age:SetMax( 100 ) local send = vgui.Create( "DButton", frame ) send:Dock( TOP ) send:SetText( "Send my age!" ) send.DoClick = function() net.Start( "SendAge" ) net.WriteUInt( age:GetValue(), 8 ) -- You can also use net.WriteInt here. The second argument is 8 since the age will never be above 255. Doing this saves bandwidth and can reduce lag. net.SendToServer() end
Notice how we don't actually tell the server who we are using net.WriteEntity. This is because serverside, net.Receive's second argument is the player who sent it. We'll go in to more depth about net message security after this example.
util.AddNetworkString( "SendAge" ) net.Receive( "SendAge", function( len, ply ) -- len is the net message length, which we don't care about, ply is the player who sent it. local age = net.ReadUInt( 8 ) -- Notice how ReadUInt requires an argument. This is the second argument of WriteUInt, which tells us how big the number is. PrintMessage( HUD_PRINTTALK, ply:Nick() .. " is " .. age .. " years old!" ) end )
Challenges (Don't continue until you have done these!): Can you make the age message show in color? Can you make the message also show the players favorite food?
When sending a net message from client to server, you pose a huge security risk. Let's pretend for a moment that someone has written this code serverside:
util.AddNetworkString( "BanPlayer" ) net.Receive( "BanPlayer", function( len, ply ) local toBan = net.ReadEntity() local time = net.ReadUInt( 32 ) toBan:Ban( time ) end )
Take a look at this code. Can you figure out what could happen if this code was actually used on a server?
Let's break it down. This net message bans a player when the BanPlayer net message is sent to the server. However, there are no checks to see if the player is actually an admin or not. This means people could send their own net messages, from outside the script that it was created in, gaining access to ban any player on your server. To prevent this, follow 1 simple rule:
NEVER TRUST THE CLIENT
Don't preform checks on user input clientside then assume that they are fine serverside. Don't be lazy and only check data in the realm where it can be easily manipulated. You should look out for negative numbers, people sending net messages very fast, people trying to write entities that should never be written, as long as many other things. Before you publish your code, try as hard as you can to break it.
An easy way to secure your Net functions: When using net.Receive (net.Receive( "my_message", function( len, ply ))) you can use the second argument (ply) (the sender) to perform checks. Never do net.WriteEntity(LocalPlayer()), that's unnecessary and easy to bypass. An easy check could look like this:
net.Receive("YourNetName", function( len, ply ) if( !ply:IsSuperAdmin() ) then return end --leaves the function if the sender isn't superadmin print( "This is a secured Net Message!" ) end)