Garry's Mod Wiki

Networking Options, Limits and Errors

This page lists which Networking Options there are and how they work, all Networking Limits and all found Networking Errors and how to solve them

The Navigator

This is a list containing all sections of this Page so you can navigate it easier.

Networking Options

umsg (DEPRECATED)

The umsg library is a deprecated serverside networking library that was previously the most common way of sending information from the server to the client. In order for clients to receive an umsg, it has to use the usermessage library, which is shared for the client and the server.

This library was used in some functions to send a message like text to the client and then to display it, and it is still used in some old functions like PrintMessage, Player:PrintMessage and Player:ChatPrint. It is also used by the NW System to network the NW Vars.

umsg sent by the engine to a client can be received by it even when his net buffer is overflown / he cannot receive & sent any net messages.

Hello World example with the umsg and usermessage library.

if SERVER then local filter = RecipientFilter() filter:AddAllPlayers() umsg.Start( "Example" ) umsg.String( "Hello World" ) umsg.End() else usermessage.Hook( "Example", function( msg ) print( msg:ReadString() ) end) end

net

The net library is one of the ways to send data between client and server. One of the major advantages of the net library is the ability to send data backwards - from the client to the server.

This library is commonly used in the network of values to a specific client only, or to network bigger values like Strings(net.WriteString) or Ints(net.WriteInt).
You can read more about this library here: Net_Library_Usage and Net_Library_Example

When the OnRequestFullUpdate Game_Events is called the first time, net messages will reliably be received
The AutoRefresh System uses the net library to network changes. Because of this, it is limited to 65536 bytes.
If you exceed the Limit, it will throw an error.

Hello World Example with the net library

if SERVER then util.AddNetworkString( "Example" ) net.Start( "Example" ) net.WriteString( "Hello World" ) net.Broadcast() else net.Receive( "Example", function() print( net.ReadString() ) end) end

NW

The NW system allows for a value to be networked on an entity to all clients with the SetNW functions like Entity:SetNWString and the value can be returned by using the GetNW functions like Entity:GetNWString.
It also allows to set global values with the SetGlobal* functions like SetGlobalString and the value can be retured by using the GetGlobal* functions like GetGlobalString

the value will be the same on all clients if they haven't been modified by the client.
All SetNW* and SetGlobal* functions will network the value every 10 seconds after it has been set.
(Because if this, It can cause massive amounts of networking if you use a bunch of NW vars.)
All NW values will be accessible clientside when the GM:InitPostEntity hook is called

SetGlobal* works internally like Entity(0):SetNW* and because of this, values set with the SetGlobal* functions can be accessed with Entity(0):GetNW*

Hello World Example with the NW system

if SERVER then Entity( 1 ):SetNWString( "Example", "Hello World" ) else Entity( 1 ):SetNWVarProxy( "Example", function(_, _, _, value ) print( value ) end) end

If you want to network a table with the NW system, you can use util.TableToJSON to make it into a string, and then you can send it with Entity:SetNWString or SetGlobalString and return it with Entity:GetNWString or GetGlobalString

The string returned by util.TableToJSON should not be bigger than 255 characters. You can use the NW2 system to use up to 511 characters.

Example

Networking a Table containing Hello World

if SERVER then local table = { "Hello World" } SetGlobalString( "Example", util.TableToJSON( table ) ) else PrintTable( util.JSONToTable( GetGlobalString( "Example" ) ) ) end
Output:
1 = Hello World

NW2

The NW2 system is the successor to the NW system, but it hasn't been officially finished. It allows for values to be networked on an entity to all clients in the entity's PVS(Potential Visibility Set) with the given value with the SetNW2* functions like Entity:SetNW2String and the value can be returned by using the GetNW2* functions like Entity:GetNW2String.

The value will only be updated clientside if the entity is or enters the client's PVS(Potential Visibility Set).
The value will only be networked if it isn't the same as the current value and unlike SetNW* the value will only be networked once and not every 10 seconds.
All NW2 values will be accessible clientside when the GM:InitPostEntity hook is called

SetGlobal2* works internally like Entity(0):SetNW2* and because of this, values set with the SetGlobal2* functions can be accessed with Entity(0):GetNW2*

All NW2Vars set on a Player are updated every 10 seconds because of sv_playerforcedupdate

It also allows to set global values with the SetGlobal2* functions like SetGlobal2String and the value can be returned by using the GetGlobal2* functions like GetGlobal2String. All SetGlobal2* functions will update the value clientside, and it will ignore the PVS.

Hello World Example with the NW2 system

if SERVER then Entity( 1 ):SetNW2String( "Example", "Hello World" ) else Entity( 1 ):SetNW2VarProxy( "Example", function( _, _, _, value ) print( value ) end) end

or

if SERVER then Entity( 1 ):SetNW2String( "Example", "Hello World" ) else hook.Add( "EntityNetworkedVarChanged", "Example", function( _, _, _, value ) print( value ) end) end

If you want to network a table with the NW2 system, you can use util.TableToJSON to make it into a string, and then you can send it with Entity:SetNW2String or SetGlobal2String and return it with Entity:GetNW2String or GetGlobal2String

The string returned by util.TableToJSON should not be bigger than 511 characters.

Example

Networking a Table containing Hello World

if SERVER then local table = { "Hello World" } SetGlobal2String( "Example", util.TableToJSON( table ) ) else PrintTable( util.JSONToTable( GetGlobal2String( "Example" ) ) ) end
Output:
1 = Hello World

Some additional information about the NW2 System

If Entity:SetPreventTransmit is set to true, it will leave the client's PVS and NW2Vars won't be networked.
The Entity won't enter the client's PVS again under any circumbstances until it has been set to false again.

A NW2Var is networked as a entmessage(Entity Message).

Entity:NetworkVar seems to use the NW2 System internally, because of that, they share the same limits.

Entity:UpdateTransmitState affects Entity:NetworkVar but not NW2Vars set with SetNW2*

You can use the EFL_IN_SKYBOX Engine Flag to force the Entity into the PVS of every client. (This won't work for the clients. If you want to add clients to the PVS, you'll need to use AddOriginToPVS)

Example

Forcing the Entity to Enter the PVS

local ent = Entity( 93 ) -- some Prop outside your PVS if SERVER then ent:SetNW2String( "Hello", "World" ) ent:AddEFlags( EFL_IN_SKYBOX ) else hook.Add( "EntityNetworkedVarChanged", "Example", print ) end
Output:
Entity [93][prop_physics] Hello nil World

There is no official function like BuildNetworkedVarsTable for the NW2 System, but you could use a function like this one.

Example

-- This is not the fastest way, and it can get slower when more entities exist, but you shouldn't call this function so often. function BuildNetworked2VarsTable() local vars = {} for _, ent in ipairs(ents.GetAll()) do for key, tbl in pairs(ent:GetNW2VarTable()) do if !tbl.value then continue end -- GetNW2VarTable can return keys with nil values. if !vars[ent] then -- we do this, because we only want to add entitys who have NW2 Vars. vars[ent] = {} end vars[ent][key] = tbl.value -- adds the NW2 Var. end end return vars end

Networking Limits

umsg limits

The umsg library has a 256 bytes limit per message.
The bytes are used as follows:

2 Bytes are used Internally
x Bytes are used for the umsg Name(1 Byte for each character.)
left Bytes are used by the actual umsg.

The umsg buffer for sending the data is not limited. Because of that, you can send as many umsg's until you run out of memory.
If you run out of memory, your game will simply crash.

By default, you can network 1024 bytes of umsgs to a client in a single tick.
If you need more than that to speed up something or just more capacity is needed,
you can increase the sv_usermessage_maxsize (default 1024bytes) ConVar to the needed amount of bytes.


net limits

The net library has a 64kb (65535 bytes - 3 bytes used internally) limit per message. The library has an internal buffer that has roughly a 256kb(2048kbit) limit before it overflows, and if it overflows, it will cause clients that receive the net message to disconnect. So do NOT fill the buffer.
It also has clienside a reliable stream which will overflow if too many net messages are queued and the total size of all net messages is over 256kb(2048bit).

Example

Creating a net message that uses the maximum size

local string = "" for k=1, 65532 do string = string .. "a" end net.Start( "test" ) net.WriteString( string ) net.Broadcast()
Output:
65536 524288

net bandwidth

reliable channel

the bandwidth for the reliable channel is roughly at 120kb/s but can vary for each client. The ping and the amount of time needed to process the net message plays a huge amount and can influence the bandwidth strongly because the net buffer could fill up because more net messages are received than processed, which can lead to the client being kicked because of a buffer overflow.

unreliable channel

the bandwidth seems to be unlimited for the unreliable channel and only seems to be influenced by the amount of time needed to send the net message. The net message won't actually be received most of the time because the buffer would be full, and it would just skip the net message.

clientside bugs (unreliable channel)

At somewhere around 12kb/s the net buffer seems to be overloaded, and you will be frozen in place because your client won't be able to receive any net message from the server while the buffer is overloaded, but you're still able to send net messages to the server. As soon as the buffer returns to a normal state, you will start to receive all reliable net messages that got delayed because the buffer overloaded.

serverside bugs (unreliable channel)

At somewhere around 12kb/s the net buffer seems to be overloaded, and the server will start to lag without any connection problems or packet loss. All inputs are getting delayed and some like jumping won't work right. The server will return to a normal state when the net buffer returns to a normal state.


NW limits

The NW system uses a stringtable that has 4095 slots and is used by all SetGlobal*, SetNW* functions and the util.AddNetworkString function.
By default, 95 slots are used. Each new key will use a slot, so if you use the same key on all entities, it will only use 1 slot.
The Maximum length for an NWVar Name is 49 characters.

The NW System uses user messages to network the Vars. Because of this, the maximum size of an NWVar can be 255 bytes.

Example

Returning the amount of used slots and the last key

for k = 1, 4096 do if !util.NetworkIDToString( k ) then print( k - 1, util.NetworkIDToString( k - 1 ) ) break end end
Output:
95 ServerName

NW2 limits

The NW2 system uses a separate stringtable that has 4095 slots, so it is not influenced by the NW stringtable.
The NW2 stringtable is used by all SetNW2* and SetGlobal2* functions. By default, the stringtable is completely empty.
Each new key will use a slot, so if you use the same key on all entities, it will only use 1 slot.
Currently, there is no way of checking the usage of the NW2 string table.
The maximum length for an NW2Var key is 1023 characters.
(why can you network more data for a key that a value? (SetNW2String can only network 511 characters.))
If you need to network a string smaller than 1023 characters but bigger than 511 characters, see the example for Entity:SetNW2String

Networking Optimization

sv_playerforcedupdate issue

If you run a larger server, you maybe noticed that players are force updated every 10 seconds.
This is because of sv_playerforcedupdate (default 10) which defines the amount of seconds to wait before updating a player again.
It updates the player by adding it to the PVS for one tick and then removing it in the next.
This is also the reason why NW2Vars are updated for players every 10 seconds (If they are out of sync).
This issue can cause massive amounts of networking for the client, and It can cause short frame drops.

If we were to set sv_playerforcedupdate to a number like 1000 and then change it back to 1,
this change would only apply after the next update. In this case after 1000 seconds
If you set it to 0 all players are updated every frame!

You can see an example of the networking spikes here.

Example

This is one of the ways to solve this Problem.
This solution is not perfect because we add the entire position to the PVS instead of just the Player.
We do it like this because currently there is no way to add a single entity to the PVS.

-- This is the Clientside part. if CLIENT then local cooldown = 0 -- This event is called twice. Because of this, we add a delay so that don't request it twice. hook.Add( "InitPostEntity", "RequestFullPlayerUpdate", function() gameevent.Listen( "OnRequestFullUpdate" ) -- We do this clientside because this event is called after the Update has been received. hook.Add( "OnRequestFullUpdate", "RequestFullPlayerUpdate", function( data ) if data.userid != LocalPlayer():UserID() then return end -- We can receive events about other players, so we need to filter them. if cooldown > CurTime() then return end net.Start( "RequestFullPlayerUpdate" ) net.SendToServer() cooldown = CurTime() + 5 end) net.Start( "RequestFullPlayerUpdate" ) -- Just to be sure the client has everything. net.SendToServer() end) return end -- The Clientside part is above. The rest is serverside only. -- This returns all players that are inside the PVS. local function player_FindInPVS( viewPoint ) local plys = {} for _, ent in ipairs( ents.FindInPVS( viewPoint ) ) do if ent:IsPlayer() then table.insert( plys, ent ) end end return plys end -- This returns all players that are outside the PVS. local function player_FindOutsidePVS( viewPoint ) local plys = {} local pvs_plys = player_FindInPVS( viewPoint ) for _, ply in ipairs( player.GetAll() ) do if !pvs_plys[ ply ] then -- We check if the player is inside the PVS. If he is not inside the PVS, we add him to the Table. table.insert( plys, ply ) end end return plys end local query = {} local query_size = 0 local function RemovePlayer( query, id, ply ) query[ id ] = nil if #query == 0 then query[ ply ] = nil query_size = query_size - 1 if query_size == 0 then hook.Remove( "SetupPlayerVisibility", "Player_Query" ) -- We remove the hook if hes not needed. end end end local function SetupPlayerVisibility( ply ) local left_plys = query[ ply ] if !left_plys then return end -- Skip if no players are left. local id local next_ply for k, v in pairs( left_plys ) do -- ipairs breaks so we need to use pairs. id = k next_ply = v break end if next_ply:TestPVS( ply ) then -- We check if the Player is inside the PVS. If he is, we remove him from the list. RemovePlayer( left_plys, id, ply ) return end AddOriginToPVS( next_ply:GetPos() ) RemovePlayer( left_plys, id, ply ) --[[ If we have a crowded server where most of the players are in the same place, we can check if other players are also in the query. You can disable the code below if you only have a few players, or they all distributed across the map, but I don't recommend it. The code below saves a bunch of networking because players that are in the PVS of another player that has been networked are removed. ]] local pvs_plys = {} for _, pvs_ply in ipairs( player_FindInPVS( next_ply ) ) do -- We flip the table because this saves performance. pvs_plys[ pvs_ply ] = true end for key, left_ply in pairs( left_plys ) do if pvs_plys[ left_ply ] then RemovePlayer( left_plys, key, ply ) end end end util.AddNetworkString( "RequestFullPlayerUpdate" ) net.Receive( "RequestFullPlayerUpdate", function( _, ply ) query[ ply ] = player_FindOutsidePVS( ply ) -- We add a table containing all players that we want to add to the PVS if query_size == 0 then hook.Add( "SetupPlayerVisibility", "Player_Query", SetupPlayerVisibility ) -- We add the hook when it's needed. end query_size = query_size + 1 end )

Networking Errors

umsg errors

realm

Error sending usermessage - too large ([name])

This error is created serverside when you exceed the umsg limit of 256 bytes. Reduce the size of your umsg to solve this error.


realm

Warning: Unhandled usermessage '[name]'

This error is created clientside when you forgot to use usermessage.Hook with the right key.

The umsg is deprecated, and you should use the net library instead.

Example

How to properly use the umsg library

if SERVER then local filter = RecipientFilter() filter:AddAllPlayers() umsg.Start( "Example" ) umsg.String( "Hello World" ) umsg.End() else usermessage.Hook( "Example", function( msg ) print( msg:ReadString() ) end) end

realm

Warning: [number] global queued usermessages!

This Warning occurs when sending more than 5000 umsg's in the same time. This warning can be completely ignored because it won't affect anything. This Warning can be fixed by sending less umsg's or disturbing them over a timespan.


net errors

realm

[addon] Trying to send an overflowed net message!

This error is created serverside when you exceed the net limit of 64kb (65536 bytes). Reduce the size of your net message to solve this error.


realm This error is created clientside when you overflowed the net reliable buffer, which has a 256kb(2048kbit) limit, and it will cause a client or all clients to be to disconnect.
To fix this error, you have to reduce the amount of net messages or the size of the net messages you send, so they won't overflow the net buffer.
You could distribute the net messages over a small period, so the net buffer has enough time to send all net messages.

You also can send unreliable net messages that won't kick a Client, but instead it will just ignore all unreliable net messages that couldn't fit in the buffer.

Example

Overflowing the reliable buffer while using unreliable net messages so the client won't be kicked.

local string = "" for k = 1, 65532 do string = string .. "a" end util.AddNetworkString( "Example" ) for k = 1, 4 do net.Start( "Example", true ) net.WriteString( string ) net.Broadcast() end
Output: Instead of kicking the client, all unreliable net messages just won't be received and the developer error:
Netchannel: failed reading message clc_GMod_ClientToServer from loopback.

will be created.


realm

loopback:send reliable stream overflow

This Error is shown when you overflow the clientside net reliable stream. When this error occurs the client won't be able to send any net messages to the server and after a while the client will be kicked because the server thinks the client timed out.
To fix this, reduce the amount of net messages you want to send to the server and distribute them over a small period, so the steam has enough time to sent everything.


realm

[Addon] Warning! A net message ([name]) is already started! Discarding in favor of the new message! (function origin of the net message)

This error is created by the net library when in a previous net message an error occurred. This can be fixed by fixing the error that has been created in the net message before it.


realm

Netchannel: failed reading message svc_GMod_ServerToClient from loopback.

This Warning is shown when you set the developer ConVar to 1 or higher and an unreliable net message is received, and it doesn't fit in the net buffer. This can be fixed by reducing the amount of net messages sent and to distribute them over a small period.


realm

Netchannel: failed reading message clc_GMod_ClientToServer from loopback.

This Warning is shown when you set the developer ConVar to 1 or higher and an unreliable net message is received, and it doesn't fit in the net buffer. This can be fixed by reducing the amount of net messages sent and to distribute them over a small period.


realm

Warning! Trying to net.Broadcast a message '[name]' with no players on server!

This Warning is shown when you set the developer ConVar to 1 or higher, and you try to broadcast a net message while the server is empty. This Warning can be completly Ignored because it won't affect anything.


realm

AUTOREFRESH: Not adding [file here] to datatable, its too large! ([file size] vs 65536) Refusing to send autorefreshed Lua file [file here], its too large! ([file size] vs 65536 max)

This Error is created, when you try to Autorefresh a file that contains more than 65536 chacters and even after some compression is still bigger than 65536 bytes. To solve this error, you need to reduce the size of your File.


NW errors

realm

DLL_MessageEnd: Refusing to send user message NetworkedVar of 256 bytes to client, user message size limit is 255 bytes

This Error is created, when you try to network a NWString in which the length of the key and value together is greater than 255 bytes.
This Error will occur every 10 seconds from that point on, because the NW System renetworks all NW Vars every 10 seconds.
To fix this error, you have to reduce the size of your NWVar name.


realm

Too many NWVar names, could not add name [key]

This error is created when you exceed the NW2Var limit, which is currently at 4095 slots. Reduce the amount of NW2Vars or consider using the net library to solve this error.


NW2 errors

realm

Host_Error: SV_PackEntity: SendTable_Encode returned false (ent 1).

This error is created when you try to network too many NW2Vars at the same time. When this error occurs, it will close the server and on your game will crash when you try to start a new game without restarting gmod first.
If you should ever get this error, you should reduce the amount of NW2Vars that you're trying to network at the same time


realm

Warning: Table networkstring is full, can't add [key]

This error is created when you exceed the NWVar limit, which is currently at 4095 slots. Reduce the amount of NWVars or consider using the net library or the SetNW* functions to solve this error.