/lua/Framework/Subsystems/Comm.lua
Lua | 271 lines | 227 code | 44 blank | 0 comment | 46 complexity | 5009daab84764300431ab7de3df30e3d MD5 | raw file
- Framework.Comm = {}
-
- /********************************
- *** Shared networking ***
- ********************************/
-
- local DATASPLITTER = "\0"
-
- local CommObjIn = {}
- CommObjIn.__index = CommObjIn
-
- local CommObjOut = {}
- CommObjOut.__index = CommObjOut
-
- local VarTypes = { { Name = "Bool", Size = 1, Converter = function(a) return string.byte(a) == 1 end },
- { Name = "Char", Size = 1, Converter = string.char },
- { Name = "Short", Size = 2, Converter = Framework.Utilities.BinaryToNumber16 },
- { Name = "Entity", Size = 4, Converter = function(a) return ents.GetByIndex( Framework.Utilities.BinaryToNumber32(a) ) end },
- { Name = "Long", Size = 4, Converter = Framework.Utilities.BinaryToNumber32 },
- { Name = "Float", Size = 4, Converter = Framework.Utilities.BinaryToFloat },
- { Name = "Angle", Size = 12, Converter = Framework.Utilities.BinaryToAngle },
- { Name = "Vector", Size = 12, Converter = Framework.Utilities.BinaryToVector},
- { Name = "VectorNormal", Size = 12, Converter = Framework.Utilities.BinaryToVector},
- { Name = "String", Size = string.len } }
-
- for TypeID, Type in pairs( VarTypes ) do
- CommObjIn["Add" .. Type.Name] = function(self, Value, pos)
- if( Pos ) then
- table.insert( self.Values, Pos, { Type = TypeID, Value = Value } )
- else
- table.insert( self.Values, { Type = TypeID, Value = Value } )
- end
- return true
- end
-
- CommObjOut["Read" .. Type.Name] = function( self )
-
- if( TypeID == 10 && self:BytesLeft() > 0 ) then
- local End = self.Data:find( DATASPLITTER, self.Cursor + 1 )
- local Str = self.Data:sub( self.Cursor + 1, End - 1 )
- self.Cursor = End+1
- return Str
- elseif( self:BytesLeft() - Type.Size >= 0 ) then
- local ret = Type.Converter( self.Data:sub( self.Cursor+1, self.Cursor+1 + Type.Size ) )
- self.Cursor = self.Cursor + Type.Size + 1
- return ret
- end
- Framework.IO.Error( "Attempted to read out-of-bounds data from Comm-Object!" )
- return false
- end
- end
-
- function CommObjOut:GetOrigin()
- return self.Origin
- end
-
- function CommObjOut:BytesLeft()
- return #self.Data - self.Cursor
- end
-
- function CommObjOut:GetType()
- return VarTypes[Framework.Utilities.CharToNumber(self.Data:sub( self.Cursor, self.Cursor ))].Name
- end
-
- function CommObjOut:Read()
- return self["Read" .. self:GetType()]( self )
- end
-
- function CommObjOut:ReadAll()
- local t = {}
- while( self:BytesLeft() > 0 ) do
- table.insert( t, self:Read() )
- end
- return t
- end
-
- local SendTypes = {
- player = "AddEntity",
- vehicle = "AddEntity",
- entity = "AddEntity",
- number = "AddFloat",
- vector = "AddVector",
- angle = "AddAngle",
- boolean = "AddBool",
- string = "AddString"
- }
-
- function CommObjIn:Add( ... )
- for k, v in pairs( {...} ) do
- local t = type( v ):lower()
- if( t == "number" ) then
- if( v % 1 != 0 ) then
- self:AddFloat( v )
- elseif( math.abs(v) > 65535 ) then
- self:AddLong( v )
- elseif( math.abs(v) > 255 ) then
- self:AddShort( v )
- else
- self:AddChar( v )
- end
- else
- if( SendTypes[t] ) then
- self[SendTypes[t]]( self, v )
- end
- end
- end
- end
-
- function CommObjIn:Clear()
- self.Values = {}
- end
-
- function CommObjIn:Remove( Index )
- table.remove( self.Values, Index )
- end
-
- if( SERVER ) then
- function CommObjIn:AddRecipient( Recipient )
- if( type( self.Recipients ) == "CRecipientFilter" ) then
- self.Recipients:AddPlayer( Recipient )
- else
- table.insert( self.Recipients, Recipient )
- end
- end
-
- function CommObjIn:RemoveRecipient( Recipient )
- if( type( self.Recipients ) == "CRecipientFilter" ) then
- self.Recipients:RemovePlayer( Recipient )
- else
- for k, v in pairs( self.Recipients ) do
- if( v == Recipient ) then
- table.remove( self.Recipients, k )
- return
- end
- end
- end
- end
- end
-
- function CommObjIn:Send( ... )
- local t = {...}
- if( #t != 0 ) then
- self:Add( ... )
- end
-
- if( #self.Values == 0 ) then
- Framework.IO.Warning( "Attempted to send empty CommObject '" .. self.Name .."' without any data" )
- return false
- end
-
- local Data = ""
-
- for k, v in pairs( self.Values ) do
- Data = Data .. Framework.Utilities.NumberToChar( v.Type )
- if( v.Type <= 2 ) then
- Data = Data .. Framework.Utilities.NumberToChar( v.Value )
- elseif( v.Type == 3 ) then
- Data = Data .. Framework.Utilities.NumberToBinary16( v.Value )
- elseif( v.Type == 4 ) then
- Data = Data .. Framework.Utilities.NumberToBinary32( v.Value:EntIndex() )
- elseif( v.Type == 5 ) then
- Data = Data .. Framework.Utilities.NumberToBinary32( v.Value )
- elseif( v.Type == 6 ) then
- Data = Data .. Framework.Utilities.FloatToBinary( v.Value )
- elseif( v.Type <= 9 ) then
- Data = Data .. Framework.Utilities.VectorToBinary( v.Value )
- elseif( v.Type == 10 ) then
- Data = Data .. v.Value .. DATASPLITTER
- end
- end
-
- Data = glon.encode( Data )
- if( SERVER ) then
- datastream.StreamToClients( self.Recipients, "~c", {n=self.Name,d=Data} )
- else
- datastream.StreamToServer( "~c", {n=self.Name,d=Data} )
- end
- end
-
- local CommHandlers = {}
-
- local function FmwkIncData( pl, _, _, _, dec )
- if( CommHandlers[dec.n] ) then
- CommHandlers[dec.n]( setmetatable( { Origin = pl, Name = dec.n, Cursor = 1, Data = glon.decode( dec.d ) }, CommObjOut ) )
- else
- Framework.IO.Warning( "Unhandled " .. (SERVER && "Server" || "Client") .. "side Comm-Object '" .. dec.n .. "'" )
- end
- end
-
- if( CLIENT ) then
- datastream.Hook( "~c", function( ... ) FmwkIncData( "Server", ... ) end )
- else
- datastream.Hook( "~c", FmwkIncData )
- end
-
- function Framework.Comm.Register( ST_Name, FU_Func )
- CommHandlers[ST_Name] = FU_Func
- end
-
- function Framework.Comm.New( ST_Name, OP_TA_RF_Recipients )
- return setmetatable( { Name = ST_Name, Values = {}, Recipients = SERVER && (OP_TA_RF_Recipients or {}) || nil }, CommObjIn )
- end
-
-
- /********************************
- *** Remote Event Table ***
- ********************************/
-
- local CMD_ADD, CMD_COUNT, CMD_GET, CMD_POP = 1, 2, 3, 4
-
- local function Formatter( Contents )
- return Contents:sub(1,1) == "0", Contents:sub( 2 )
- end
-
- local function Grabber( Contents, Function )
- local b, s = Formatter( Contents )
- if( b ) then
- local t = {}
- local c = 0
- local IP, Msg, i = s:match( "</br><r><i>([%d%.]+)</i><s>(.-)</s></r>()" )
- while( IP != nil && c < 100 ) do
- s = s:sub( i )
- c = c + 1
- table.insert( t, { IP = IP, Msg = Msg } )
- IP, Msg, i = s:match( "</br><r><i>([%d%.]+)</i><s>(.-)</s></r>()" )
- end
- return true, t
- end
- return false
- end
-
- function Framework.Comm.InsertEvent( App, Unique, Str, Callback )
- http.Get( "http://errur.com/test/MessageTracker.php?c=" .. CMD_ADD .. "&a=" .. App .. "&i=" .. Unique .. "&s=" .. Framework.Utilities.URLEncode( Str ), "", function(a) if( Callback ) then Callback( Formatter( a ) ) end end )
- end
-
- function Framework.Comm.CountEvents( App, Unique, Callback )
- http.Get( "http://errur.com/test/MessageTracker.php?c=" .. CMD_COUNT .. "&a=" .. App .. "&i=" .. Unique, "", function(a) if( Callback ) then Callback( Formatter( a ) ) end end )
- end
-
- function Framework.Comm.GetEvents( App, Unique, Limit, Callback )
- Limit = Limit or 100
- http.Get( "http://errur.com/test/MessageTracker.php?c=" .. CMD_GET .. "&a=" .. App .. "&i=" .. Unique .. "&s=" .. tonumber( Limit ), "", function(a) if( Callback ) then Callback( Grabber( a ) ) end end )
- end
-
- function Framework.Comm.PopEvents( App, Unique, Limit, Callback )
- Limit = Limit or 100
- http.Get( "http://errur.com/test/MessageTracker.php?c=" .. CMD_POP .. "&a=" .. App .. "&i=" .. Unique .. "&s=" .. tonumber( Limit ), "", function(a) if( Callback ) then Callback( Grabber( a ) ) end end )
- end
-
- EvObj = {}
- EvObj.__index = EvObj
-
- function Framework.Comm.EventTracker( App, Unique )
- return setmetatable( { App = App, Unique = Unique }, EvObj )
- end
-
- function EvObj:Insert( Str, Callback )
- Framework.Comm.InsertEvent( self.App, self.Unique, Str, Callback )
- end
-
- function EvObj:Count( Callback )
- Framework.Comm.CountEvents( self.App, self.Unique, Callback )
- end
-
- function EvObj:Get( Limit, Callback )
- Framework.Comm.GetEvents( self.App, self.Unique, Limit, Callback )
- end
-
- function EvObj:Pop( Limit, Callback )
- Framework.Comm.PopEvents( self.App, self.Unique, Limit, Callback )
- end