Last active
November 14, 2018 01:44
-
-
Save ndbeals/5ad1d5082841aa74aab0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- Class Creator. | |
-- Creates a basic class template and returns it to be used for further editing and extending. | |
-- Supports infinite class inheritence. | |
--@function Class | |
--@param base The baseclass for the newly created class to inherit from. | |
--@return class Returns the new class template to be edited. | |
function Class( base ) | |
local class = { -- a new class metatable | |
base = base | |
} | |
class.__index = class | |
local classmt = { -- the new classes' meta table, this allows inheritence if the class has a base, and lets you create a new instance with <classname>() | |
__index = base | |
} | |
classmt.__call = function( class , ... ) -- expose a constructor which can be called by <classname>(<args>) | |
local obj = {} -- new instance of the class to be manipulated. | |
setmetatable( obj , class ) | |
if class.Initialize then | |
class.Initialize( obj , ... ) | |
end | |
return obj | |
end | |
setmetatable(class, classmt) | |
return class | |
end | |
--- Networker Class. | |
--@section Networker | |
Networker = Class() -- In charge of networking all of a players needs | |
--- Networker Class Constructor. | |
-- Creates a Networker class instance, Limits network usage so users don't flood the server. | |
--@param player Player to send it to (if used server side) | |
function Networker:Initialize( player ) | |
self.SendBuffer = {} | |
self.Receivers = {} | |
self.ReceiverTemplates = {} | |
self.PooledNames = {} | |
self.PooledNum = 0 | |
self:SetPlayer( player ) | |
end | |
--- Set Player. | |
-- Sets the player object the networker class will send data too (only useful serverside as clients always send to server) | |
-- Cannot change player while any buffers are open. | |
--@param player Player to send it to. | |
function Networker:SetPlayer( player ) | |
if not player or not IsValid( player ) then error("Invalid Player object",2) return end | |
if #self.SendBuffer > 0 then error("Cannot change player while any buffers are still open",2) return end | |
self.Player = player | |
end | |
--- Get Player. | |
-- Gets the player object the networker class will send data too (only useful serverside as clients always send to server) | |
--@return player Player to send it to. | |
function Networker:GetPlayer() | |
return self.Player | |
end | |
--- Add To Buffer. | |
-- adds a variable to the send buffer, basically a wrapper for table.insert. | |
--@param tab Table input to be added to the send buffer | |
function Networker:AddToBuffer( tab ) | |
if not self.CurrentBuffer then error("No Current buffer, no message started",2) end | |
self.CurrentBuffer.Size = self.CurrentBuffer.Size + tab.Size | |
table.insert( self.CurrentBuffer , tab ) | |
end | |
--- Write Integer. | |
-- Writes an Integer to the network buffer. | |
--@param int Integer to send. | |
function Networker:WriteInteger( int ) | |
self:AddToBuffer( { net.WriteInt , int , 32 , Size = 4 } ) | |
end | |
--- Write Unsigned Integer. | |
-- Writes an unsigned integer to the network buffer. | |
--@param int Integer to send. | |
function Networker:WriteUInteger( int ) | |
self:AddToBuffer( { net.WriteUInt , int , 32 , Size = 4 } ) | |
end | |
--- Write Number. | |
-- Writes a Number of a given size in bits to the network buffer. | |
--@param num Number to be written. | |
--@param size Size in bits of number. | |
function Networker:WriteNumber( num , size ) | |
size = size or 32 | |
self:AddToBuffer( { net.WriteInt , num , size , Size = size/8 } ) | |
end | |
--- Write Unsigned Number. | |
-- Writes an Unsigned Number of a given size in bits to the network buffer. | |
--@param num Number to be written. | |
--@param size Size in bits of number. | |
function Networker:WriteUNumber( num , size ) | |
size = size or 32 | |
self:AddToBuffer( { net.WriteUInt , num , size , Size = size/8 } ) | |
end | |
--- Write Angle. | |
-- Writes an angle to the network buffer. | |
--@param ang Angle to send. | |
function Networker:WriteAngle( ang ) | |
self:AddToBuffer( { net.WriteAngle , ang , Size = 8 } ) | |
end | |
--- Write Bit. | |
-- Writes a bit to the network buffer. | |
--@param bit Bit to send. | |
function Networker:WriteBit( bit ) | |
self:AddToBuffer( { net.WriteBit , bit , Size = 0.125 } ) | |
end | |
--- Write Bool. | |
-- Writes a boolean to the network buffer. | |
--@param bool Boolean to send. | |
function Networker:WriteBool( bool ) | |
self:AddToBuffer( { net.WriteBool, bool , Size = 0.125 } ) | |
end | |
--- Write Color. | |
-- Writes a color to the network buffer. | |
--@param col Color object to send. | |
function Networker:WriteColor( col ) | |
self:AddToBuffer( { net.WriteColor , col , Size = 4 } ) | |
end | |
--- Write Data. | |
-- Writes binary string data to the network buffer. | |
--@param data Data to send. | |
function Networker:WriteData( data ) | |
self:AddToBuffer( { net.WriteData , data , Size = #data } ) | |
end | |
--- Write Doube. | |
-- Writes a double to the network buffer. | |
--@param dbl Double to send. | |
function Networker:WriteDouble( dbl ) | |
self:AddToBuffer( { net.WriteDouble , dbl , Size = 8 } ) | |
end | |
--- Write Entity. | |
-- Writes an Entity to the network buffer. | |
--@param ent Entity to send. | |
function Networker:WriteEntity( ent ) | |
self:AddToBuffer( { net.WriteEntity , ent , Size = 2 } ) | |
end | |
--- Write Float. | |
-- Writes a float to the network buffer. | |
--@param float Float to send. | |
function Networker:WriteFloat( float ) | |
self:AddToBuffer( { net.WriteFloat , float , Size = 4 } ) | |
end | |
--- Write Normal. | |
-- Writes a vector normal to the network buffer. | |
--@param nrm Normal to send | |
function Networker:WriteNormal( nrm ) | |
self:AddToBuffer( { net.WriteNormal , nrm , Size = 4 } ) | |
end | |
--- Write Vector. | |
-- Writes a Vector to the network buffer. | |
--@param vec Vector to send. | |
function Networker:WriteVector( vec ) | |
self:AddToBuffer( { net.WriteVector , vec , Size = 9 } ) | |
end | |
--- Write Table. | |
-- Writes a table to the network buffer. Don't use this often. | |
--@param tab Table to send. | |
function Networker:WriteTable( tab ) | |
self:AddToBuffer( { net.WriteTable , tab , Size = 200 } ) | |
end | |
--- Write String. | |
-- Writes a String to the network buffer. | |
--@param str String to send. | |
function Networker:WriteString( str ) | |
if #str <= 250 then --base message is atleast 4 bytes long | |
self:AddToBuffer( { net.WriteUInt , 1 , 16 , Size = 2 } ) | |
self:AddToBuffer( { net.WriteString , str , Size = #str } ) | |
else | |
local chunks = math.ceil( #str / 250 ) | |
if chunks > 2^16 then error("Net message too large >15.625 Mega Bytes (why on earth do you need a single string this large?)",3) end | |
self:AddToBuffer( { net.WriteUInt , chunks , 16 , Size = 2 } ) | |
for index = 1 , #str , 250 do | |
self:AddToBuffer( { net.WriteString , str:sub(index,index + 249) , Size = #(str:sub(index,index + 249)) } ) | |
end | |
end | |
end | |
--- Read String. | |
-- Reads a String from the network buffer. | |
--@return String. | |
function Networker:ReadString() | |
coroutine.yield() | |
local ret , chunks = {} , net.ReadUInt( 16 ) | |
while chunks >= 1 do | |
coroutine.yield() | |
table.insert( ret , net.ReadString() ) | |
chunks = chunks - 1 | |
end | |
return table.concat( ret ) | |
end | |
--- Read Integer. | |
-- Reads a signed integer from the network buffer. | |
--@return Integer. | |
function Networker:ReadInteger() | |
coroutine.yield() | |
return net.ReadInt( 32 ) | |
end | |
--- Read Unsigned Integer. | |
-- Reads an unsigned integer from the network buffer. | |
--@return UInteger. | |
function Networker:ReadUInteger() | |
coroutine.yield() | |
return net.ReadUInt( 32 ) | |
end | |
--- Read Number. | |
-- Reads a Number of a given size in bits from the network buffer. | |
--@param size Size in bits of number. | |
--@return Number. | |
function Networker:ReadNumber( size ) | |
size = size or 32 | |
coroutine.yield() | |
return net.ReadInt( size ) | |
end | |
--- Read Unsigned Number. | |
-- Reads an Unsigned Number of a given size in bits from the network buffer. | |
--@param size Size in bits of number. | |
--@return UNumber. | |
function Networker:ReadUNumber( size ) | |
size = size or 32 | |
coroutine.yield() | |
return net.ReadUInt( size ) | |
end | |
--- Read Angle. | |
-- Reads an angle from the network buffer. | |
--@return Angle. | |
function Networker:ReadAngle() | |
coroutine.yield() | |
return net.ReadAngle() | |
end | |
--- Read Bit. | |
-- Reads a bit from the network buffer. | |
--@return Bit. | |
function Networker:ReadBit() | |
coroutine.yield() | |
return net.ReadBit() | |
end | |
--- Read Bool. | |
-- Reads a boolean from the network buffer. | |
--@return Boolean. | |
function Networker:ReadBool() | |
coroutine.yield() | |
return net.ReadBool() | |
end | |
--- Read Color. | |
-- Reads a color from the network buffer. | |
--@return Color. | |
function Networker:ReadColor() | |
coroutine.yield() | |
return net.ReadColor() | |
end | |
--- Read Data. | |
-- Reads binary string data from the network buffer. | |
--@return Data. | |
function Networker:ReadData() | |
coroutine.yield() | |
return net.ReadData() | |
end | |
--- Read Doube. | |
-- Reads a double from the network buffer. | |
--@return Double. | |
function Networker:ReadDouble() | |
coroutine.yield() | |
return net.ReadDouble() | |
end | |
--- Read Entity. | |
-- Reads an Entity from the network buffer. | |
--@return Entity. | |
function Networker:ReadEntity() | |
coroutine.yield() | |
return net.ReadEntity() | |
end | |
--- Read Float. | |
-- Reads a float from the network buffer. | |
--@return Float. | |
function Networker:ReadFloat() | |
coroutine.yield() | |
return net.ReadFloat() | |
end | |
--- Read Normal. | |
-- Reads a vector normal from the network buffer. | |
--@return Normal. | |
function Networker:ReadNormal() | |
coroutine.yield() | |
return net.ReadNormal() | |
end | |
--- Read Vector. | |
-- Reads a Vector from the network buffer. | |
--@return Vector. | |
function Networker:ReadVector() | |
coroutine.yield() | |
return net.ReadVector() | |
end | |
--- Read Table. | |
-- Reads a table from the network buffer, Don't use much. | |
--@param tab Table to send. | |
function Networker:ReadTable() | |
coroutine.yield() | |
return net.ReadTable() | |
end | |
--- Start Message. | |
-- Wrapping around net.Start to control resource usage | |
--@param name Name of the message to be sent | |
function Networker:Start( name ) | |
if not name then return end | |
identity = self:PoolMessage( name ) | |
self.CurrentBuffer = self.SendBuffer[ table.insert( self.SendBuffer , { Name = identity, Size = 0 } ) ] | |
self.CurrentBuffer.Position = 0 | |
end | |
--- End Message. | |
-- Simple wrapper to use the proper net.Send functions depending on server or client | |
function Networker:EndMessage() | |
if SERVER then | |
net.Send( self.Player ) | |
elseif CLIENT then | |
net.SendToServer() | |
end | |
end | |
--- Send Batch. | |
-- Sends a batch of info to the other realm (server to client or client to server). | |
--@param player optional, defaulted to container owner. | |
function Networker:SendBatch() | |
local curbuffer , size , messages = self.SendBuffer[ 1 ] , 4 , 0 | |
for msg = 1 , #curbuffer do | |
local message = curbuffer[msg + curbuffer.Position ] | |
if not message then | |
size = size - 256 -- make sure it returns true | |
break | |
end | |
if math.ceil( size + message.Size ) > 256 then | |
size = math.ceil( size + message.Size ) | |
break | |
end | |
messages = msg | |
size = size + message.Size | |
end | |
net.Start( "luabox_sendmessage" ) | |
net.WriteUInt( bit.lshift( curbuffer.Name - 1 , 9 ) + ( messages - 1 ) , 32 ) | |
for msg = 1 , messages do | |
local message = curbuffer[ msg + curbuffer.Position ] | |
message[ 1 ]( unpack( message , 2 ) ) | |
end | |
curbuffer.Position = curbuffer.Position + messages | |
self:EndMessage() | |
return size < 256 | |
end | |
---Finish Send. | |
-- Removes the net data from the send buffer. | |
function Networker:FinishSend() | |
table.remove( self.SendBuffer , 1 ) | |
end | |
function Networker:Send() | |
if not self:SendBatch() then | |
hook.Add( "Think" , "Luabox_NetworkThink:"..tostring( self ) , function() | |
if self.SendBuffer[1] then | |
if self:SendBatch() then | |
hook.Remove( "Think" , "Luabox_NetworkThink:"..tostring( self ) ) | |
self:FinishSend() | |
end | |
end | |
end) | |
else | |
self:FinishSend() | |
end | |
self.CurrentBuffer = nil | |
end | |
function Networker:Receive( name , func ) | |
if not func or not name then return end | |
--name = self:GetPooledIndex( name ) | |
self.Receivers[ name ] = coroutine.create( func ) | |
self.ReceiverTemplates[ name ] = func | |
self.FirstExecute = true -- Work around for coroutines needing to be resumed once to start their execution, Runs only when a new coroutine hasn't been ran at all. | |
end | |
function Networker:ProcessReceiver( name ) | |
if not name then return end | |
local coro = self.Receivers[ name ] | |
if self.FirstExecute then | |
coroutine.resume( coro ) | |
self.FirstExecute = false | |
end | |
coroutine.resume( coro ) | |
if coroutine.status( coro ) == "dead" then | |
self:Receive( name , self.ReceiverTemplates[ name ] ) | |
end | |
end | |
function Networker:PoolMessage( name , index ) | |
if self.PooledNames[ name ] then return self.PooledNames[ name ] end | |
if not index then | |
index = self.PooledNum + 1 | |
end | |
self.PooledNames[ index ] = name | |
self.PooledNames[ name ] = index | |
if SERVER then | |
net.Start( "luabox_poolmessagename" ) | |
net.WriteString( name ) | |
net.WriteUInt( index , 24 ) | |
net.Send( self.Player ) | |
end | |
self.PooledNum = index | |
return index | |
end | |
function Networker:GetPooledName( idx ) | |
return self.PooledNames [ idx ] | |
end | |
if SERVER then | |
util.AddNetworkString( "luabox_sendmessage" ) | |
util.AddNetworkString( "luabox_poolmessagename" ) | |
end | |
net.Receive( "luabox_sendmessage" , function( length , ply ) | |
local networker , info = PlayerContainer( ply ):GetNetworker() , net.ReadUInt(32) | |
local identity = bit.rshift( info , 9 ) + 1 | |
local messages = bit.rshift( bit.lshift( info , 23 ) , 23 ) + 1 | |
while messages > 0 do | |
networker:ProcessReceiver( networker.PooledNames[ identity ] ) | |
messages = messages - 1 | |
end | |
end) | |
net.Receive( "luabox_poolmessagename" , function( length , ply ) | |
local networker , name , poolnum = PlayerContainer( ply ):GetNetworker() , net.ReadString() , net.ReadUInt(24) | |
networker.PooledNames[ poolnum ] = name | |
networker.PooledNames[ name ] = poolnum | |
end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment