The New Net Library

I’ve been mucking around with the new net library in gmod beta, figured i’d share some findings with you all. There are some things i still haven’t quite figured out, such as sending tables that have strings as indices (sending tables with strings in them requires hacky workarounds right now, but it may just be a feature garry hasn’t coded yet). All in all this looks very promising though.

The cool thing about the net library is that the same code works both ways (client to server OR server to client) with very little modification. Here’s my test script:

[lua]local receiving_side = CLIENT // which side is receiving?

if receiving_side then

MsgN( "Loaded test script..." )

// TEST #1
// Reading tables.

net.Receive( "Test1", function( len )
 
    MsgN( "TEST 1: Received message of ", len, " bits..." )
	
	MsgN( "Printing the random arbitrary table..." )
	PrintTable( net.ReadTable() )
 
end )

// TEST #2
// Read specific values.

net.Receive( "Test2", function( len )
 
    MsgN( "TEST 2: Received message of ", len, " bits..." )
	
	MsgN( "ReadFloat:" )
	MsgN( net.ReadFloat() )
	
	MsgN( "ReadLong:" )
    MsgN( net.ReadLong() )
	
	MsgN( "ReadEntity:" )
	MsgN( net.ReadEntity() )
	
	MsgN( "ReadByte:" )
	MsgN( net.ReadByte() )
	
	MsgN( "ReadString:" )
	MsgN( net.ReadString() )
	
	MsgN( "ReadVector:" )
	MsgN( net.ReadVector() )
	
	MsgN( "ReadAngle:" )
	MsgN( net.ReadAngle() )
	
end )

else

MsgN( "Loaded test script..." )

// TEST #1
// Send tables.

local test_table = { "eggs", "cheese", "apple", 100200, 3.4567, Vector(1.2345,800,-900), Entity(1) } 

net.Start( "Test1" )

	net.WriteTable( test_table )
     
if receiving_side == SERVER then

	net.SendToServer()
	
else

	net.Broadcast() // Send it to all players.
	// net.Send( Entity(1) ) // alternatively you could send it to only yourself!

end

// TEST #2
// Send specific things.

local fl = 2.3456
local long = 100200
local ent = Entity(1) 
local byte = 10
local str = "John Lua"
local vec = Vector( 900, 3.4567, -500 )
local ang = Angle( 4.5678, -90, 45 )

net.Start( "Test2" )
 
	net.WriteFloat( fl )
    net.WriteLong( long )
	net.WriteEntity( ent )
	net.WriteByte( byte )
	net.WriteString( str )
	net.WriteVector( vec )
	net.WriteAngles( ang )
     
if receiving_side == SERVER then

	net.SendToServer()
	
else

	net.Broadcast() // Send it to all players.
	// net.Send( Entity(1) ) // alternatively you could send it to only yourself!

end

end[/lua]

Here’s the output if anyone is wondering:


TEST 1: Received message of 659 bits...
Printing the random arbitrary table...
1	=	eggs
2	=	cheese
3	=	apple
4	=	100200
5	=	3
6	=	1.2188 800.0000 -900.0000
7	=	Player [1][nüke]
TEST 2: Received message of 310 bits...
ReadFloat:
2.3455998897552
ReadLong:
100200
ReadEntity:
Player [1][nüke]
ReadByte:
10
ReadString:
John Lua
ReadVector:
900.0000 3.4375 -500.0000
ReadAngle:
4.563 -90.000 45.000

Some more useful links:

#1

#2

Share your findings here and also feel free to post code if you want it tested.

  • snip -

Last I checked the net library just crashed the entire game

Works fine for me…

You’re not calling net.Send(ply ). Don’t worry though, the crashing will be fixed next Beta update.

Look: http://www.facepunch.com/threads/1142025

Yes for the time being we can only use net.Broadcast(), which is fine since everything being written in the beta is for testing purposes only.

I hope that net.WriteTable supports more than just longs, entities and vectors next update.

In a twitter reply Garry implied that they will be supported.

As in strings, and other tables? I hope so.

Curious, but if you need to send a complex table to the client, why not just send the table encoded with glon to the client and have them reconstruct it?

Efficience, speed and data size.

You could use the AD2 like a module and use Donovan’s encoding/decoding once it’s shared on server and client I think. It’s fast and compresses data nicely into a string.

That’s what datastream did to my knowledge so i assume that method wouldn’t be any less optimal. I’ll see if it works.

Glon sends it as a string, which has more overhead than sending as bits and bytes… which is what we’re doing.

Plus my code is readable.

[lua]–
– Write a whole table to the stream
– This is less optimal than writing each
– item indivdually and in a specific order
– because it adds type information before each var

function net.WriteTable( tab )

for k, v in pairs( tab ) do

	net.WriteType( k )
	net.WriteType( v )

end

-- End of table
net.WriteByte( 0 )

end

function net.ReadTable()

local tab = {}

while true do

	local t = net.ReadByte()
	if ( t == 0 ) then return tab end
	local k = net.ReadType( t )

	local t = net.ReadByte()
	if ( t == 0 ) then return tab end
	local v = net.ReadType( t )
	
	tab[ k ] = v
	
end

end

net.WriteVars =
{
[TYPE_NUMBER] = function ( t, v ) net.WriteByte( t ) net.WriteLong( v ) end,
[TYPE_ENTITY] = function ( t, v ) net.WriteByte( t ) net.WriteEntity( v ) end,
[TYPE_VECTOR] = function ( t, v ) net.WriteByte( t ) net.WriteVector( v ) end,
}

function net.WriteType( v )

local typeid = TypeID( v )
local wv = net.WriteVars[ typeid ]
if ( wv ) then return wv( typeid, v ) end

Error( "Couldn't write type " .. typeid )

end

net.ReadVars =
{
[TYPE_NUMBER] = function () return net.ReadLong() end,
[TYPE_ENTITY] = function () return net.ReadEntity() end,
[TYPE_VECTOR] = function () return net.ReadVector() end,
}

function net.ReadType( typeid )

local rv = net.ReadVars[ typeid ]
if ( rv ) then return rv( v ) end

Error( "Couldn't read type " .. typeid )

end[/lua]

Yeah, and here’s hoping that net.WriteTable will support angles and more complex tables (ie. tables with strings, nested tables, etc).

Angles would be easy i think.

e: Boobs

You could just .WriteAngle

Oh, i missed that. Well then, all that we really need is support for tables containing strings and nested tables.

You also were using semi-expensive math functions (matrix multiplication/trig) to convert the angle into a normalized direction vector then back into an angle. It was not the best method to send the data packed in an angle object, three floats.

Agree.
It can be very useful to send over tables full of random stuff. Even though I expect garry to say something along the lines of: “If you would have coded it in a less inefficient and chaotic way then you wouldn’t be needing it.” I think it can still be useful.
Even if the direct need for it is not there as it can also be done manually, it would add so much ease of use. Sending over the table as is just makes the code faster to work with. Looping through it and reconstructing it on the client is simply annoying to do, and nested tables quickly become looping hell.

Do we get this package of awesomeness or are we expected to get our datastructures in line and do it manually? (or with GLON…)

I had fun turning {[1]={1,2},[2]={1,2}} into “1;1:2/2;1:2”. And then back.

Reminded me of code breaking.

Yeah, writing your own data structures is always fun and a good idea. If you do it specific to the data you are sending, its almost always far more efficient than glon and other “one size fits all” data structures.