├── LICENSE ├── sh_unittest.lua ├── README.md └── sh_gnetwork.lua /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 David 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sh_unittest.lua: -------------------------------------------------------------------------------- 1 | if SERVER then 2 | GNet.AddPacketID( 'a_packet_test' ) 3 | concommand.Add("net_test", function() 4 | local p = GNet.Packet( 'a_packet_test' ) 5 | p:WriteString('this is a string') 6 | p:WriteUChar( 254 ) 7 | p:WriteBit( true ) 8 | p:WriteBit( 1 ) 9 | p:WriteUShort( 271 ) 10 | p:WriteUInt( 12345, 32 ) 11 | p:WriteInt( 12345, 32 ) 12 | p:WriteChar( 254 ) 13 | p:WriteShort( 271 ) 14 | p:WriteFloat( 123.45 ) 15 | p:WriteDouble( 123.45 ) 16 | p:WriteVector( Vector( 123, 456, 789 ) ) 17 | p:WriteColor( Color( 213, 211, 91, 221 ) ) 18 | p:WriteEntity( player.GetAll()[1] ) 19 | p:WriteAngle( Angle( 123, 456, 789 ) ) 20 | p:WriteNormal( Vector( 1, 0, 1 ) ) 21 | p:WriteBool( false ) 22 | p:WritePlayer( player.GetAll()[1] ) 23 | for i = 1, math.random(5, 10) do 24 | local c = math.random(0, 255) 25 | p:WriteUChar( c ) 26 | print(c) 27 | end 28 | p:Send() 29 | end ) 30 | else 31 | GNet.OnPacketReceive( 'a_packet_test', function( packet ) 32 | 33 | print( packet:ReadString() ) 34 | print( packet:ReadUChar() ) 35 | print( packet:ReadBit() ) 36 | print( packet:ReadBit() ) 37 | print( packet:ReadUShort() ) 38 | print( packet:ReadUInt( 32 ) ) 39 | print( packet:ReadInt( 32 ) ) 40 | print( packet:ReadChar() ) 41 | print( packet:ReadShort() ) 42 | print( packet:ReadFloat() ) 43 | print( packet:ReadDouble() ) 44 | print( packet:ReadVector() ) 45 | print( packet:ReadColor() ) 46 | print( packet:ReadEntity() ) 47 | print( packet:ReadAngle() ) 48 | print( packet:ReadNormal() ) 49 | print( packet:ReadBool() ) 50 | print( packet:ReadPlayer() ) 51 | 52 | while packet:HasData() do 53 | Msg('%s '%packet:ReadUChar()) 54 | end 55 | MsgN() 56 | 57 | print( '%d bits still need to be read'%( packet:RemainingBits() ) ) // this returns 0 58 | end ) 59 | end 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## GNet Library 2 | The networking lib has lots of helper functions which are mainly rewrites of some of the original Garry's mods `net` library. It's mostly built up with dynamic bit counting and `net.WriteInt` and `net.WriteUInt`. This allows us to keep track of everything a lot easier and add logging of everything if needed in the future without overwriting the default functions. Many of the functions in our in house networking library also save bits on networking vs the default Garry's mod networking library. Please take care of networking, you should rarely need to send anything from the client to the server. *Never trust the client*. The networking lib is completely shared so each function can both be called on the server and the client EXCEPT adding messages to the network message pool. 3 | 4 | ### Functions ### 5 | #### GNet.AddPacketID( string packet_id ) *server* #### 6 | ```lua 7 | GNet.AddPacketID( 'UpdatePlayer' ) 8 | ``` 9 | This function should be called at init. This can be when a script file loads or in `GM:Initialize`. You **cannot** send a packet without pooling it first. This function is just an alias of `util.AddNetworkString`. 10 | 11 | #### `number` GNet.CalculateBits( number max_number, `optional` boolean signed ) *shared* #### 12 | ```lua 13 | GNet.CalculateBits( 255 ) 14 | GNet.CalculateBits( 255, true ) 15 | ``` 16 | This function returns the minimum required bits you'd need to use **IF** you know the maximum value you would ever need for a variable. The second argument decides if you're using a signed or an unsigned integer. What a signed int basically is that it means that your range can potentially go below 0. An unsigned 8 bit int range is from `0-255`. A signed 8 bit int range is `-128-127`. 17 | 18 | #### GNet.OnPacketReceive( string packet_id, function callback ) *shared* #### 19 | ```lua 20 | GNet.OnPacketReceive( 'ReadAString', function( packet ) 21 | print( packet:ReadString() ) 22 | end ) 23 | ``` 24 | This function adds a callback to the `packet_id` specified. It takes two argument, the `packet_id` and a callback function. The callback function has 1 argument which is a `PacketReader` metaclass. See below for reading packets. 25 | 26 | ### Packet Metatable ### 27 | 28 | #### `packet` GNet.Packet( string packet_id ) *shared* #### 29 | ```lua 30 | local packet = GNet.Packet( 'EmptyPacketLol' ) 31 | packet:Send() 32 | ``` 33 | Returns a packet object. This object is what's used to count the bits and use the internal optimized networking functions. 34 | 35 | #### packet:WriteString( string str ) *shared* #### 36 | ```lua 37 | local packet = GNet.Packet( 'WriteZehString' ) 38 | packet:WriteString( 'hard' ) 39 | packet:Send() 40 | ``` 41 | Saves a string to the packets networking table to be networked later on. Please note that your string should **not** contain any null bytes. If for any reason it contains null bytes then consider using `packet:WriteData`. The networking module writes `8 * number of chars + 8` bits. 42 | 43 | #### packet:WriteUChar( number char ) *shared* #### 44 | #### packet:WriteUChar( character char ) *shared* 45 | ```lua 46 | packet:WriteUChar( 'A' ) 47 | packet:WriteUChar( 48 ) 48 | ``` 49 | Saves an unsigned character to the networking table to be networked later on. This is an **UNSIGNED** data type which is **8 BITS**, meaning the range of the data which can be sent is `0-255`. 50 | 51 | #### packet:WriteChar( number char ) *shared* #### 52 | #### packet:WriteChar( character char ) *shared* #### 53 | ```lua 54 | packet:WriteChar( 'A' ) 55 | packet:WriteChar( 48 ) 56 | ``` 57 | Saves an unsigned character to the networking table to be networked later on. This is an **SIGNED** data type which is **8 BITS**, meaning the range of the data which can be sent is `-128-127`. 58 | 59 | #### packet:WriteBit( boolean state ) *shared* #### 60 | #### packet:WriteBit( number state ) *shared* #### 61 | ```lua 62 | packet:WriteBit( true ) 63 | packet:WriteBit( 1 ) 64 | ``` 65 | Saves a bit to the networking table to be sent to the client. This function can take either a number or a boolean as an argument. 66 | 67 | #### packet:WriteUShort( number short ) *shared* #### 68 | ```lua 69 | packet:WriteUShort( 511 ) 70 | ``` 71 | Saves an unsigned short to the networking table to be networked later on. This is a **UNSIGNED** data type which is **16 BITS**, meaning the range of the data which can be sent it `0-65535`. 72 | 73 | #### packet:WriteShort( number short ) *shared* #### 74 | ```lua 75 | packet:WriteShort( -511 ) 76 | ``` 77 | Saves an short to the networking table to be networked later on. This is a **SIGNED** data type which is **16 BITS**, meaning the range of the data which can be sent it `-32768-32767`. 78 | 79 | #### packet:WriteUInt( number int, number bits ) *shared* #### 80 | ```lua 81 | packet:WriteUInt( 8912374, GNet.CalculateBits( 9000000 ) ) 82 | packet:WruteUInt( 256, 9 ) 83 | ``` 84 | Saves an unsigned integer to the networking table to be networked later on. This is a **UNSIGNED** data type. You determine the bits needed, if you're unsure of this refer to the `GNet.CalculateBits` function. 85 | 86 | #### packet:WriteInt( number int, number bits ) *shared* #### 87 | ```lua 88 | packet:WriteInt( 8912374, GNet.CalculateBits( 9000000, true ) ) 89 | packet:WruteInt( -256, 9 ) 90 | ``` 91 | Saves an integer to the networking table to be networked later on. This is a **SIGNED** data type. You determine the bits needed, if you're unsure of this refer to the `GNet.CalculateBits` function. 92 | 93 | #### packet:WriteFloat( decimal num ) *shared* #### 94 | ```lua 95 | packet:WriteFloat( 123.4567 ) 96 | ``` 97 | Saves a single precision floating point number to be networked later on. This function uses 32 bits of data. 98 | 99 | #### packet:WriteDouble( decimal num ) *shared* #### 100 | ```lua 101 | packet:WriteDouble( 123.456789912 ) 102 | ``` 103 | Saves a double precision floating point number to be networked later on. This function uses 64 bits of data. 104 | 105 | #### packet:WriteVector( vector vec ) *shared* #### 106 | ```lua 107 | packet:WriteVector( 123, 45.67, 8723 ) 108 | ``` 109 | Saves a vector to be networked later on. This function sends the X,Y,Z competent of a vector as SINGLE PRECISION FLOATING POINTS. so be careful as some insignificant data will be lost. 110 | 111 | #### packet:WriteColor( Color col ) *shared* #### 112 | ```lua 113 | packet:WriteColor( Color( 255, 0, 213 ) ) 114 | packet:WriteColor( Color( 255, 0, 111, 231 ) ) 115 | ``` 116 | Saves a color table to be networked later on. The values passed into this function are rounded up MEANING. `Color( 231.2, 214.9, 201 )` will become `Color( 232, 215, 201 )`. If the alpha in this function is equal to 255*(the default value)*, then only 25 bits are networked. 24 bits for the r,g,b values which are sent as unsigned characters and 1 bit which determines if alpha is `255` or not. If the alpha is not `255` then 33 bits will be networked. 117 | 118 | #### packet:WriteEntity( Entity ent ) *shared* #### 119 | ```lua 120 | packet:WriteEntity( Entity( 1 ) ) 121 | ``` 122 | Saves a entity to be networked later on. This function is essentially `packet:WriteUShort( ent:EntIndex() )`. So it sends 16 bits of data. 123 | 124 | #### packet:WriteAngle( Angle ang ) *shared* #### 125 | ```lua 126 | packet:WriteAngle( 123, 45.67, 8723 ) 127 | ``` 128 | Saves a angle to be networked later on. This function sends the P,Y,R competent of a angle as SINGLE PRECISION FLOATING POINTS. so be careful as some insignificant data will be lost. 129 | 130 | #### packet:WriteData( string data, number len ) *shared* #### 131 | ```lua 132 | packet:WriteData( 'this is \x00 some sick \x21\x82\x82\x11\x01 data', 30 ) 133 | ``` 134 | Saves some raw data to be networked later on. This function can take all types of binary data INCLUDING null terminated strings. 135 | 136 | #### packet:WriteNormal( Vector normal ) *shared* #### 137 | ```lua 138 | packet:WriteNormal( Vector( 0, 1, 0 ) ) 139 | ``` 140 | This function is an alias of `packet:WriteVector` 141 | 142 | #### packet:WriteBool( boolean bool ) *shared* #### 143 | ```lua 144 | packet:WriteBool( true ) 145 | ``` 146 | This function is an alias of `packet:WriteBit` 147 | 148 | #### packet:WritePlayer( Player ply ) *shared* #### 149 | ```lua 150 | packet:WritePlayer( player.GetAll()[1] ) 151 | ``` 152 | This function is an alias of `packet:WriteEntity` 153 | 154 | #### packet:GetBits() *shared* #### 155 | ```lua 156 | print( 'This packet has %d bits'%packet:GetBits() ) 157 | ``` 158 | Returns the amount of bits which will be sent to the client/server. 159 | 160 | #### packet:GetBytes() *shared* #### 161 | ```lua 162 | print( 'This packet has %d bytes'%packet:GetBits() ) 163 | ``` 164 | Returns the amount of bytes which will be sent to the client/server. 165 | 166 | #### packet:GetKB() *shared* #### 167 | ```lua 168 | print( 'The packet is %dkb'%packet:GetKB() ) 169 | ``` 170 | Returns the size of the packet which will be sent to the client/server in kilobytes. 171 | 172 | #### `number` packet:Send( `optional` Player ply ) *shared* #### 173 | #### `number` packet:Send( `optional` table plyList ) *shared* #### 174 | ```lua 175 | packet:Send() 176 | packet:Send( ply ) 177 | packet:Send( { ply1, ply2 } ) 178 | ``` 179 | This is the main function in the networking library. It actually handles the sending of the data to the client/server. it can be called in various different ways to preform different functions. The **first argument is completely optional on the server** HOWEVER, on the **client, there is no first argument** as you can only send to the server. The first argument can send data to a specific player if only 1 `Player` entity is there, it can send to multiple players if there is a `table of players` such as `player.GetAll()`, OR if the **first argument is completely blank it networks to all clients**. Once the data is networked, the function returns how many bits were actually sent to the client. 180 | 181 | ### PacketReader Metatable ### 182 | #### `PacketReader` GNet.PacketReader( string packet_id, number len, Player ply ) *shared* #### 183 | ```lua 184 | GNet.PacketReader(packet_id, len, ply) 185 | ``` 186 | This is an internal function which shouldn't be called. It's automatically called with `GNet.OnPacketReceive` and passed into the callback. The function returns the `PacketReader` metatable. 187 | 188 | #### `Player` PacketReader:GetPlayer() *shared* #### 189 | ```lua 190 | print( 'Player %s sent the packet'%PacketReader:GetPlayer():Nick() ) 191 | ``` 192 | Returns the player which sent the packet on the server realm. However in the client realm `LocalPlayer()` is returned. 193 | 194 | #### `number` PacketReader:RemainingBits() *shared* #### 195 | ```lua 196 | print( 'There is still %d unread bits'%PacketReader:RemainingBits() ) 197 | ``` 198 | Returns how many bits are still remaining to be read in the packet. If this value is 0 then there is no more data to be read in the packet. 199 | 200 | #### `boolean` PacketReader:HasData() *shared* #### 201 | ```lua 202 | while PacketReader:HasData() do 203 | table.insert( itemIDList, PacketReader:ReadUInt( 32 ) ) 204 | end 205 | ``` 206 | This function uses `PacketReader:RemainingBits` to determine if there is still data in the packet to be read. This is extremely useful for reading large chunks of predictable data as we never have to send the length of how much we have to read. This saves us on networking extra bits. 207 | 208 | #### `string` PacketReader:ReadString() *shared* #### 209 | ```lua 210 | print( Packet:ReadString() ) 211 | ``` 212 | Reads a string from the packet. It reads `(StrLen * 8) + 8 bits` of data. 213 | 214 | #### `string` PacketReader:ReadData() *shared* #### 215 | ```lua 216 | print( Packet:ReadData() ) 217 | ``` 218 | Reads binary data from the packet. It reads `(DataLen * 8) + 16 bits` of data. 219 | 220 | #### `boolean` PacketReader:ReadBit() *shared* #### 221 | ```lua 222 | print( Packet:ReadBit() ) 223 | ``` 224 | Reads a single bit from the packet. 225 | 226 | #### `number` PacketReader:ReadUShort() *shared* #### 227 | ```lua 228 | print( Packet:ReadUShort() ) 229 | ``` 230 | Reads an unsigned short from the packet. It reads `16 bits` of data. 231 | 232 | #### `number` PacketReader:ReadShort() *shared* #### 233 | ```lua 234 | print( Packet:ReadShort() ) 235 | ``` 236 | Reads an short from the packet. It reads `16 bits` of data. 237 | 238 | #### `number` PacketReader:ReadUInt( number n ) *shared* #### 239 | ```lua 240 | print( Packet:ReadUInt(21) ) 241 | ``` 242 | Reads an unsigned int from the packet. It reads `n bits` of data. 243 | 244 | #### `number` PacketReader:ReadInt( number n ) *shared* #### 245 | ```lua 246 | print( Packet:ReadInt(21) ) 247 | ``` 248 | Reads an int from the packet. It reads `n bits` of data. 249 | 250 | #### `number` PacketReader:ReadUChar() *shared* #### 251 | ```lua 252 | print( Packet:ReadUChar() ) 253 | ``` 254 | Reads an unsigned character from the packet. It reads `8 bits` of data. 255 | 256 | #### `number` PacketReader:ReadChar() *shared* #### 257 | ```lua 258 | print( Packet:ReadChar() ) 259 | ``` 260 | Reads an character from the packet. It reads `8 bits` of data. 261 | 262 | #### `decimal` PacketReader:ReadFloat() *shared* #### 263 | ```lua 264 | print( Packet:ReadFloat() ) 265 | ``` 266 | Reads an single precision floating point number from the packet. It reads `32 bits` of data. 267 | 268 | #### `decimal` PacketReader:ReadDouble() *shared* #### 269 | ```lua 270 | print( Packet:ReadDouble() ) 271 | ``` 272 | Reads an double precision floating point number from the packet. It reads `64 bits` of data. 273 | 274 | #### `Vector` PacketReader:ReadVector() *shared* #### 275 | ```lua 276 | print( Packet:ReadVector() ) 277 | ``` 278 | Reads an vector from the packet. It reads `96 bits` of data. 279 | 280 | #### `Color` PacketReader:ReadColor() *shared* #### 281 | ```lua 282 | print( Packet:ReadColor() ) 283 | ``` 284 | Reads an color from the packet. It reads `25 bits` of data IF the alpha is `255`. If the alpha is not `255` then it reads `33 bits` of data. 285 | 286 | #### `Entity` PacketReader:ReadEntity() *shared* #### 287 | ```lua 288 | print( Packet:ReadEntity() ) 289 | ``` 290 | Reads an entity from the packet. It reads `8 bits` of data. 291 | 292 | #### `Angle` PacketReader:ReadAngle() *shared* #### 293 | ```lua 294 | print( Packet:ReadAngle() ) 295 | ``` 296 | Reads an angle from the packet. It reads `96 bits` of data. 297 | 298 | #### `Vector` PacketReader:ReadNormal() *shared* #### 299 | ```lua 300 | print( Packet:ReadNormal() ) 301 | ``` 302 | Reads an normal from the packet. This function is an alias of `PacketReader:ReadVector`. 303 | 304 | #### `boolean` PacketReader:ReadBool() *shared* #### 305 | ```lua 306 | print( Packet:ReadBool() ) 307 | ``` 308 | Reads an boolean from the packet. This function is an alias of `PacketReader:ReadBit`. 309 | 310 | #### `Player` PacketReader:ReadPlayer() *shared* #### 311 | ```lua 312 | print( Packet:ReadPlayer() ) 313 | ``` 314 | Reads an player from the packet. This function is an alias of `PacketReader:ReadEntity`. 315 | 316 | ### Network module example ### 317 | ```lua 318 | if SERVER then 319 | GNet.AddPacketID( 'a_packet_test' ) 320 | concommand.Add("net_test", function() 321 | local p = GNet.Packet( 'a_packet_test' ) 322 | p:WriteString('this is a string') 323 | p:WriteUChar( 254 ) 324 | p:WriteBit( true ) 325 | p:WriteBit( 1 ) 326 | p:WriteUShort( 271 ) 327 | p:WriteUInt( 12345, 32 ) 328 | p:WriteInt( 12345, 32 ) 329 | p:WriteChar( 254 ) 330 | p:WriteShort( 271 ) 331 | p:WriteFloat( 123.45 ) 332 | p:WriteDouble( 123.45 ) 333 | p:WriteVector( Vector( 123, 456, 789 ) ) 334 | p:WriteColor( Color( 213, 211, 91, 221 ) ) 335 | p:WriteEntity( player.GetAll()[1] ) 336 | p:WriteAngle( Angle( 123, 456, 789 ) ) 337 | p:WriteNormal( Vector( 1, 0, 1 ) ) 338 | p:WriteBool( false ) 339 | p:WritePlayer( player.GetAll()[1] ) 340 | for i = 1, math.random(5, 10) do 341 | local c = math.random(0, 255) 342 | p:WriteUChar( c ) 343 | print(c) 344 | end 345 | p:Send() 346 | end ) 347 | else 348 | GNet.OnPacketReceive( 'a_packet_test', function( packet ) 349 | 350 | print( packet:ReadString() ) 351 | print( packet:ReadUChar() ) 352 | print( packet:ReadBit() ) 353 | print( packet:ReadBit() ) 354 | print( packet:ReadUShort() ) 355 | print( packet:ReadUInt( 32 ) ) 356 | print( packet:ReadInt( 32 ) ) 357 | print( packet:ReadChar() ) 358 | print( packet:ReadShort() ) 359 | print( packet:ReadFloat() ) 360 | print( packet:ReadDouble() ) 361 | print( packet:ReadVector() ) 362 | print( packet:ReadColor() ) 363 | print( packet:ReadEntity() ) 364 | print( packet:ReadAngle() ) 365 | print( packet:ReadNormal() ) 366 | print( packet:ReadBool() ) 367 | print( packet:ReadPlayer() ) 368 | 369 | while packet:HasData() do 370 | Msg('%s '%packet:ReadUChar()) 371 | end 372 | MsgN() 373 | 374 | print( '%d bits still need to be read'%( packet:RemainingBits() ) ) // this returns 0 375 | end ) 376 | end 377 | ``` 378 | This is a working example of the network lib in action. 379 | -------------------------------------------------------------------------------- /sh_gnetwork.lua: -------------------------------------------------------------------------------- 1 | module( "GNet", package.seeall ) 2 | 3 | DEBUG_MESSAGES = false 4 | if SERVER then 5 | AddPacketID = util.AddNetworkString 6 | end 7 | 8 | --[[ @brief Calculate the maximum required bits needed to network a number. 9 | * @returns Amount of bits required 10 | * 11 | * This function calculates the amount of bits required to network a number, it takes 12 | * two arguments. The maximum number which will ever be networked and if the integer is 13 | * signed or not. 14 | ]] 15 | function CalculateRequiredBits( max_number, signed ) 16 | return math.max( math.ceil( math.log( max_number ) / math.log( 2 ) ) + Either( signed, 1, 0 ), 1 ) 17 | end 18 | 19 | local dataTypes = { 20 | BIT = 0, 21 | STRING = 1, 22 | UINT = 2, 23 | INT = 3, 24 | FLOAT = 4, 25 | DOUBLE = 5, 26 | } 27 | 28 | local objPacket = {} 29 | objPacket.__index = objPacket 30 | objPacket.__tostring = function(self) 31 | return string.format( 'Packet("%s") %d bits', self.packet_id, self.total_bits ) 32 | end 33 | 34 | --[[ @brief Networks a string 35 | * 36 | * The string which is network must NOT have a NUL character. This function writes 37 | * a string 1 char at a time and NUL terminates it automatically. 38 | ]] 39 | function objPacket.WriteString( self, str ) 40 | table.insert( self.network, { 41 | t = dataTypes.STRING, 42 | v = str, 43 | } ) 44 | self.total_bits = self.total_bits + ( str:len() + 1 ) * 8 45 | end 46 | 47 | --[[ @brief Networks a bit 48 | * 49 | * Networks 1 single bit which is either a 1 or a 0. 50 | ]] 51 | function objPacket.WriteBit(self, b) 52 | table.insert(self.network, {t = dataTypes.BIT, v = b}) 53 | self.total_bits = self.total_bits + 1 54 | end 55 | 56 | --[[ @brief Networks an unsigned character 57 | * 58 | * Networks 1 unsigned byte/8 bits/1 character which has a range from 0->255 59 | ]] 60 | function objPacket.WriteUChar( self, x ) 61 | table.insert( self.network, { 62 | t = dataTypes.UINT, 63 | v = x, 64 | bits = 8, 65 | } ) 66 | self.total_bits = self.total_bits + 8 67 | end 68 | 69 | --[[ @brief Networks an signed character 70 | * 71 | * Networks 1 signed byte/8 bits/1 character which has a range from -128 -> 127 72 | ]] 73 | function objPacket.WriteChar( self, x ) 74 | table.insert( self.network, { 75 | t = dataTypes.INT, 76 | v = x, 77 | bits = 8, 78 | } ) 79 | self.total_bits = self.total_bits + 8 80 | end 81 | 82 | --[[ @brief Networks an angle 83 | * 84 | * Networks 3 floats which has a range from -3.4E+38 -> +3.4E+38 for each component 85 | ]] 86 | function objPacket.WriteAngle(self, ang) 87 | table.insert(self.network, {t = dataTypes.FLOAT, v = ang.p}) 88 | table.insert(self.network, {t = dataTypes.FLOAT, v = ang.y}) 89 | table.insert(self.network, {t = dataTypes.FLOAT, v = ang.r}) 90 | self.total_bits = self.total_bits + 96 91 | end 92 | 93 | --[[ @brief Networks an unsigned short 94 | * 95 | * Networks 2 unsigned byte/16 bits which has a range from 0->65535 96 | ]] 97 | function objPacket.WriteUShort( self, x ) 98 | table.insert( self.network, { 99 | t = dataTypes.UINT, 100 | v = x, 101 | bits = 16, 102 | } ) 103 | self.total_bits = self.total_bits + 16 104 | end 105 | 106 | --[[ @brief Networks an signed short 107 | * 108 | * Networks 2 signed byte/16 bits which has a range from -32768 -> 32767 109 | ]] 110 | function objPacket.WriteShort( self, x ) 111 | table.insert( self.network, { 112 | t = dataTypes.INT, 113 | v = x, 114 | bits = 16, 115 | } ) 116 | self.total_bits = self.total_bits + 16 117 | end 118 | 119 | --[[ @brief Networks an unsigned long 120 | * 121 | * Networks 4 unsigned byte/32 bits which has a range from 0->4294967295 122 | ]] 123 | function objPacket.WriteULong( self, x ) 124 | table.insert( self.network, { 125 | t = dataTypes.UINT, 126 | v = x, 127 | bits = 32, 128 | } ) 129 | self.total_bits = self.total_bits + 32 130 | end 131 | 132 | --[[ @brief Networks an signed long 133 | * 134 | * Networks 4 signed byte/32 bits which has a range from -2147483648 -> 2147483647 135 | ]] 136 | function objPacket.WriteLong( self, x ) 137 | table.insert( self.network, { 138 | t = dataTypes.INT, 139 | v = x, 140 | bits = 32, 141 | } ) 142 | self.total_bits = self.total_bits + 32 143 | end 144 | 145 | --[[ @brief Networks an unsigned integer 146 | * 147 | * Networks ceil(n/4) unsigned bytes which has a range from 0 -> 2^n-1 148 | * where n = bits 149 | ]] 150 | function objPacket.WriteUInt( self, x, bits ) 151 | table.insert( self.network, { 152 | t = dataTypes.UINT, 153 | v = x, 154 | bits = bits, 155 | } ) 156 | self.total_bits = self.total_bits + bits 157 | end 158 | 159 | --[[ @brief Networks an signed integer 160 | * 161 | * Networks ceil(n/4) signed bytes which has a range from -2^(n-1) -> 2^(n-1)-1 162 | * where n = bits 163 | ]] 164 | function objPacket.WriteInt( self, x, bits ) 165 | table.insert( self.network, { 166 | t = dataTypes.INT, 167 | v = x, 168 | bits = bits, 169 | } ) 170 | self.total_bits = self.total_bits + bits 171 | end 172 | 173 | --[[ @brief Networks a float 174 | * 175 | * Networks 4 signed byte/32 bits which has a range from -3.4E+38 -> +3.4E+38 with 176 | * approxmently with 7 decimal places 177 | ]] 178 | function objPacket.WriteFloat( self, x ) 179 | table.insert( self.network, { 180 | t = dataTypes.FLOAT, 181 | v = x, 182 | } ) 183 | self.total_bits = self.total_bits + 32 184 | end 185 | 186 | --[[ @brief Networks a float 187 | * 188 | * Networks 4 signed byte/32 bits which has a range from -3.4E+38 -> 3.4E+38 with 189 | * approxmently with 7 decimal places 190 | ]] 191 | function objPacket.WriteFloat( self, x ) 192 | table.insert( self.network, { 193 | t = dataTypes.FLOAT, 194 | v = x, 195 | } ) 196 | self.total_bits = self.total_bits + 32 197 | end 198 | 199 | --[[ @brief Networks a double 200 | * 201 | * Networks 8 signed bytes/64 bits which has a range from -1.7E+308 -> 1.7E+308 with 202 | * approxmently with 16 decimal places 203 | ]] 204 | function objPacket.WriteDouble( self, x ) 205 | table.insert( self.network, { 206 | t = dataTypes.DOUBLE, 207 | v = x, 208 | } ) 209 | self.total_bits = self.total_bits + 64 210 | end 211 | 212 | --[[ @brief Networks a Vector 213 | * 214 | * Networks the x, y, z components as floats. Takes a total of 96 bits or 12 bytes of 215 | * data 216 | ]] 217 | function objPacket.WriteVector( self, x ) 218 | table.insert( self.network, {t = dataTypes.FLOAT, v = x.x} ) 219 | table.insert( self.network, {t = dataTypes.FLOAT, v = x.y} ) 220 | table.insert( self.network, {t = dataTypes.FLOAT, v = x.z} ) 221 | self.total_bits = self.total_bits + 96 222 | end 223 | 224 | --[[ @brief Networks a Color 225 | * 226 | * Worst case for this function is to network 33 bits and the best case is 25 bits. 227 | * The r, g, b components of the color table is networked as unsigned chars which 228 | * are ceiled to remove the decimal points. There's an extra bit added to determain 229 | * if an alpha of something besides 255 was networked or not. If the bit is set 230 | * to 0/false, the alpha isn't networked. However if the bit is true, 231 | * the alpha is networked. No extra input is needed as this all happens 232 | * behind the scenes if the alpha is set to anything which isn't 255. 233 | ]] 234 | function objPacket.WriteColor( self, color ) 235 | table.insert(self.network, {t = dataTypes.UINT, v = math.ceil(color.r), bits = 8}) 236 | table.insert(self.network, {t = dataTypes.UINT, v = math.ceil(color.g), bits = 8}) 237 | table.insert(self.network, {t = dataTypes.UINT, v = math.ceil(color.b), bits = 8}) 238 | self.total_bits = self.total_bits + 25 239 | if color.a ~= 255 then 240 | table.insert(self.network, {t = dataTypes.BIT, v = true}) 241 | table.insert(self.network, {t = dataTypes.UINT, v = math.ceil(color.a), bits = 8}) 242 | self.total_bits = self.total_bits + 8 243 | else 244 | table.insert(self.network, {t = dataTypes.BIT, v = false}) 245 | end 246 | end 247 | 248 | --[[ @brief Networks an Entity 249 | * 250 | * Networks 2 unsigned byte/16 bits which has a range from 0->65535. The item networked 251 | * is the entity index. On the client you simply can do Entity( ENT_INDEX ) 252 | ]] 253 | function objPacket.WriteEntity( self, x ) 254 | local ent_index = 0 255 | if IsValid( x ) then 256 | ent_index = x:EntIndex() 257 | end 258 | table.insert(self.network, { 259 | t = dataTypes.UINT, 260 | v = ent_index, 261 | bits = 16 262 | }) 263 | self.total_bits = self.total_bits + 16 264 | end 265 | 266 | --[[ @brief Networks raw data 267 | * 268 | * Raw data is passed as a string and the length of the data is provided. The packet 269 | * writes the total size of the data as an unsigned short. Next the data is written as 270 | * ( unsigned char * len ) of the data. 271 | ]] 272 | function objPacket.WriteData( self, data, len ) 273 | len = len or data:len() 274 | table.insert(self.network, { 275 | t = dataTypes.UINT, 276 | v = len, 277 | bits = 16 -- Max net message size is 64kb. 16 bits = ~65kb 278 | }) 279 | self.total_bits = self.total_bits + 16 280 | for i = 1, len do 281 | table.insert(self.network, {t = dataTypes.UINT, v = data:sub(i, i), bits = 8}) 282 | end 283 | self.total_bits = self.total_bits + ( 8 * len ) 284 | end 285 | 286 | -- Aliases 287 | objPacket.WriteNormal = objPacket.WriteVector 288 | objPacket.WriteBool = objPacket.WriteBit 289 | objPacket.WritePlayer = objPacket.WriteEntity 290 | 291 | --[[ @brief Get the total size of the network packet in bits. 292 | * @returns Amount of bits being sent 293 | ]] 294 | function objPacket.GetBits( self ) 295 | return self.total_bits 296 | end 297 | 298 | --[[ @brief Get the total size of the network packet in bytes. 299 | * @returns Amount of bytes being sent 300 | ]] 301 | function objPacket.GetBytes( self ) 302 | return math.ceil( self:GetBits() / 8 ) 303 | end 304 | 305 | --[[ @brief Get the total size of the network packet in KB. 306 | * @returns Amount of kilobytes being sent 307 | ]] 308 | function objPacket.GetKB( self ) 309 | return math.floor( self:GetBytes() / 1024 ) 310 | end 311 | 312 | --[[ @brief Networks packet 313 | * @returns Amount of bits being sent 314 | * 315 | * Iterates through the "network" table and constructs the net message to be sent. The 316 | * "clients" argument is optional, if it's not specified on the SERVER, the packet is 317 | * broadcasted to everyone. If it's specified it will network to specific clients. The 318 | * clients argument can be either a single player or a table of players. Lastly the clients 319 | * argument is completely ignored on the CLIENT and will just send to the server. The 320 | * packet will fail to send if the net message size is too big! The max net message size 321 | * is 64KB. 322 | ]] 323 | function objPacket.Send( self, clients ) 324 | if DEBUG_MESSAGES then 325 | print( '[gNetwork] Sending Packet ' .. self.packet_id .. " from " .. ( CLIENT and "CLIENT" or "SERVER" ) ) 326 | end 327 | 328 | if self:GetKB() > 64 then 329 | Error( tostring( self ) .. ' is greater than 64KB!\n' ) 330 | end 331 | 332 | net.Start( self.packet_id ) 333 | 334 | for _, v in pairs( self.network ) do 335 | if v.t == dataTypes.BIT then 336 | net.WriteBit( Either( type(v.v) ~= 'boolean', v.v == 1, v.v ) ) 337 | end 338 | if v.t == dataTypes.STRING then 339 | local len = v.v:len() 340 | for i = 1, len do net.WriteUInt(v.v:sub(i, i):byte(), 8) end 341 | net.WriteUInt(0, 8) 342 | end 343 | if v.t == dataTypes.UINT then 344 | if type( v.v ) == 'string' then v.v = v.v:byte() end 345 | net.WriteUInt(v.v, v.bits) 346 | end 347 | if v.t == dataTypes.INT then 348 | net.WriteInt(v.v, v.bits) 349 | end 350 | if v.t == dataTypes.FLOAT then 351 | net.WriteFloat(v.v) 352 | end 353 | if v.t == dataTypes.DOUBLE then 354 | net.WriteDouble(v.v) 355 | end 356 | end 357 | 358 | if SERVER then 359 | if clients then 360 | net.Send(clients) 361 | else 362 | net.Broadcast() 363 | end 364 | else 365 | net.SendToServer() 366 | end 367 | return self.total_bits 368 | end 369 | 370 | --[[ @brief Creates a packet 371 | * @returns objPacket 372 | ]] 373 | function Packet( packet_id ) 374 | return setmetatable({ 375 | packet_id = packet_id, 376 | total_bits = 0, 377 | network = {}, 378 | }, objPacket) 379 | end 380 | 381 | local objPacketReader = {} 382 | objPacketReader.__index = objPacketReader 383 | objPacketReader.__tostring = function( self ) 384 | return 'PacketReader("' .. self.packet_id .. '")' 385 | end 386 | 387 | --[[ @brief Returns the player entity 388 | * @returns Player 389 | * 390 | * If called on the CLIENT, LocalPlayer() is returned however if it's called on the server 391 | * then the player which sent the net message is returned. 392 | ]] 393 | function objPacketReader.GetPlayer( self ) 394 | return self.ply 395 | end 396 | 397 | --[[ @brief Returns the remaining bits in the net message 398 | * @returns Remaining Bits 399 | ]] 400 | function objPacketReader.RemainingBits(self) 401 | return self.bits - self.bits_read 402 | end 403 | 404 | --[[ @brief Returns a string from the net message 405 | * @returns String 406 | ]] 407 | function objPacketReader.ReadString(self) 408 | local str = '' 409 | while true do 410 | local c = net.ReadUInt(8) 411 | self.bits_read = self.bits_read + 8 412 | if c ~= 0 then 413 | str = str .. string.char( c ) 414 | else 415 | break 416 | end 417 | end 418 | return str 419 | end 420 | 421 | --[[ @brief Returns a unsigned char from the net message 422 | * @returns 8 bit number 423 | ]] 424 | function objPacketReader.ReadUChar(self) 425 | self.bits_read = self.bits_read + 8 426 | return net.ReadUInt( 8 ) 427 | end 428 | 429 | --[[ @brief Returns a signed char from the net message 430 | * @returns 8 bit number 431 | ]] 432 | function objPacketReader.ReadChar(self) 433 | self.bits_read = self.bits_read + 8 434 | return net.ReadInt( 8 ) 435 | end 436 | 437 | --[[ @brief Returns data from the net message 438 | * @returns Data 439 | ]] 440 | function objPacketReader.ReadData(self) 441 | local len = net.ReadUInt( 16 ) 442 | local data = '' 443 | for i = 1, len do 444 | data = data .. string.char( net.ReadUInt( 8 ) ) 445 | end 446 | self.bits_read = self.bits_read + 16 + ( 8 * len ) 447 | return data 448 | end 449 | 450 | --[[ @brief Returns a bit from the net message 451 | * @returns 1 bit 452 | ]] 453 | function objPacketReader.ReadBit(self) 454 | self.bits_read = self.bits_read + 1 455 | return net.ReadBit() 456 | end 457 | 458 | --[[ @brief Returns a unsigned short from the net message 459 | * @returns 16 bit number 460 | ]] 461 | function objPacketReader.ReadUShort(self) 462 | self.bits_read = self.bits_read + 16 463 | return net.ReadUInt( 16 ) 464 | end 465 | 466 | --[[ @brief Returns a unsigned int from the net message 467 | * @returns n bit number 468 | ]] 469 | function objPacketReader.ReadUInt( self, bits ) 470 | self.bits_read = self.bits_read + bits 471 | return net.ReadUInt( bits ) 472 | end 473 | 474 | --[[ @brief Returns a unsigned int from the net message 475 | * @returns n bit number 476 | ]] 477 | function objPacketReader.ReadInt( self, bits ) 478 | self.bits_read = self.bits_read + bits 479 | return net.ReadInt( bits ) 480 | end 481 | 482 | --[[ @brief Returns a unsigned long from the net message 483 | * @returns 32 bit number 484 | ]] 485 | function objPacketReader.ReadULong( self ) 486 | self.bits_read = self.bits_read + 32 487 | return net.ReadUInt( 32 ) 488 | end 489 | 490 | --[[ @brief Returns a signed long from the net message 491 | * @returns 32 bit number 492 | ]] 493 | function objPacketReader.ReadLong( self ) 494 | self.bits_read = self.bits_read + 32 495 | return net.ReadInt( 32 ) 496 | end 497 | 498 | --[[ @brief Returns a signed short from the net message 499 | * @returns 16 bit number 500 | ]] 501 | function objPacketReader.ReadShort(self) 502 | self.bits_read = self.bits_read + 16 503 | return net.ReadInt( 16 ) 504 | end 505 | 506 | --[[ @brief Returns a float from the net message 507 | * @returns 32 bit number 508 | ]] 509 | function objPacketReader.ReadFloat(self) 510 | self.bits_read = self.bits_read + 32 511 | return net.ReadFloat() 512 | end 513 | 514 | --[[ @brief Returns a double from the net message 515 | * @returns 64 bit number 516 | ]] 517 | function objPacketReader.ReadDouble(self) 518 | self.bits_read = self.bits_read + 64 519 | return net.ReadDouble() 520 | end 521 | 522 | --[[ @brief Returns a Vector from the net message 523 | * @returns Vector 524 | ]] 525 | function objPacketReader.ReadVector(self) 526 | self.bits_read = self.bits_read + 96 527 | return Vector( net.ReadFloat(), net.ReadFloat(), net.ReadFloat() ) 528 | end 529 | 530 | --[[ @brief Returns a Color from the net message 531 | * @returns Color 532 | ]] 533 | function objPacketReader.ReadColor(self) 534 | self.bits_read = self.bits_read + 25 535 | local c = Color(net.ReadUInt( 8 ), net.ReadUInt( 8 ), net.ReadUInt( 8 ), 255) 536 | if net.ReadBool() then 537 | self.bits_read = self.bits_read + 8 538 | c.a = net.ReadUInt( 8 ) 539 | end 540 | return c 541 | end 542 | 543 | --[[ @brief Returns a Entity from the net message 544 | * @returns Entity 545 | ]] 546 | function objPacketReader.ReadEntity(self) 547 | self.bits_read = self.bits_read + 16 548 | return Entity( net.ReadUInt( 16 ) ) 549 | end 550 | 551 | --[[ @brief Returns a Angle from the net message 552 | * @returns Angle 553 | ]] 554 | function objPacketReader.ReadAngle(self) 555 | self.bits_read = self.bits_read + (32 * 3) 556 | return Angle( net.ReadFloat(), net.ReadFloat(), net.ReadFloat() ) 557 | end 558 | 559 | --[[ @brief Returns a bool from the net message 560 | * @returns bool 561 | ]] 562 | function objPacketReader:ReadBool() 563 | self.bits_read = self.bits_read + 1 564 | return net.ReadBool() 565 | end 566 | 567 | objPacketReader.ReadNormal = objPacketReader.ReadVector 568 | objPacketReader.ReadPlayer = objPacketReader.ReadEntity 569 | 570 | --[[ @brief Returns if there's still data to be read in the net message 571 | * @returns Is Data Remaining 572 | ]] 573 | function objPacketReader.HasData(self) 574 | return self:RemainingBits() > 0 575 | end 576 | 577 | --[[ @brief Creates a packet reader 578 | * @returns objPacketReader 579 | ]] 580 | function PacketReader( packet_id, len, ply ) 581 | return setmetatable({ 582 | packet_id = packet_id, 583 | bits = len, 584 | bits_read = 0, 585 | ply = ply or LocalPlayer(), 586 | }, objPacketReader) 587 | end 588 | 589 | --[[ @brief Intercept the packet for reading. 590 | * 591 | * OnPacketReceive takes two arguments, the packet_id as a string and a callback function 592 | * with one argument which will contain the objPacketReader. 593 | ]] 594 | function OnPacketReceive(packet_id, callback) 595 | if packet_id and callback then 596 | net.Receive(packet_id, function(len, ply) 597 | if DEBUG_MESSAGES then 598 | print( '[gNetwork] Receiving packet ' .. packet_id .. " from " .. ( IsValid( ply ) and tostring( ply ) or "SERVER" ) ) 599 | end 600 | callback(PacketReader(packet_id, len, ply)) 601 | end ) 602 | end 603 | end 604 | --------------------------------------------------------------------------------