PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lua/Framework/Subsystems/Comm.lua

http://gmod-developer-framework.googlecode.com/
Lua | 271 lines | 227 code | 44 blank | 0 comment | 46 complexity | 5009daab84764300431ab7de3df30e3d MD5 | raw file
  1. Framework.Comm = {}
  2. /********************************
  3. *** Shared networking ***
  4. ********************************/
  5. local DATASPLITTER = "\0"
  6. local CommObjIn = {}
  7. CommObjIn.__index = CommObjIn
  8. local CommObjOut = {}
  9. CommObjOut.__index = CommObjOut
  10. local VarTypes = { { Name = "Bool", Size = 1, Converter = function(a) return string.byte(a) == 1 end },
  11. { Name = "Char", Size = 1, Converter = string.char },
  12. { Name = "Short", Size = 2, Converter = Framework.Utilities.BinaryToNumber16 },
  13. { Name = "Entity", Size = 4, Converter = function(a) return ents.GetByIndex( Framework.Utilities.BinaryToNumber32(a) ) end },
  14. { Name = "Long", Size = 4, Converter = Framework.Utilities.BinaryToNumber32 },
  15. { Name = "Float", Size = 4, Converter = Framework.Utilities.BinaryToFloat },
  16. { Name = "Angle", Size = 12, Converter = Framework.Utilities.BinaryToAngle },
  17. { Name = "Vector", Size = 12, Converter = Framework.Utilities.BinaryToVector},
  18. { Name = "VectorNormal", Size = 12, Converter = Framework.Utilities.BinaryToVector},
  19. { Name = "String", Size = string.len } }
  20. for TypeID, Type in pairs( VarTypes ) do
  21. CommObjIn["Add" .. Type.Name] = function(self, Value, pos)
  22. if( Pos ) then
  23. table.insert( self.Values, Pos, { Type = TypeID, Value = Value } )
  24. else
  25. table.insert( self.Values, { Type = TypeID, Value = Value } )
  26. end
  27. return true
  28. end
  29. CommObjOut["Read" .. Type.Name] = function( self )
  30. if( TypeID == 10 && self:BytesLeft() > 0 ) then
  31. local End = self.Data:find( DATASPLITTER, self.Cursor + 1 )
  32. local Str = self.Data:sub( self.Cursor + 1, End - 1 )
  33. self.Cursor = End+1
  34. return Str
  35. elseif( self:BytesLeft() - Type.Size >= 0 ) then
  36. local ret = Type.Converter( self.Data:sub( self.Cursor+1, self.Cursor+1 + Type.Size ) )
  37. self.Cursor = self.Cursor + Type.Size + 1
  38. return ret
  39. end
  40. Framework.IO.Error( "Attempted to read out-of-bounds data from Comm-Object!" )
  41. return false
  42. end
  43. end
  44. function CommObjOut:GetOrigin()
  45. return self.Origin
  46. end
  47. function CommObjOut:BytesLeft()
  48. return #self.Data - self.Cursor
  49. end
  50. function CommObjOut:GetType()
  51. return VarTypes[Framework.Utilities.CharToNumber(self.Data:sub( self.Cursor, self.Cursor ))].Name
  52. end
  53. function CommObjOut:Read()
  54. return self["Read" .. self:GetType()]( self )
  55. end
  56. function CommObjOut:ReadAll()
  57. local t = {}
  58. while( self:BytesLeft() > 0 ) do
  59. table.insert( t, self:Read() )
  60. end
  61. return t
  62. end
  63. local SendTypes = {
  64. player = "AddEntity",
  65. vehicle = "AddEntity",
  66. entity = "AddEntity",
  67. number = "AddFloat",
  68. vector = "AddVector",
  69. angle = "AddAngle",
  70. boolean = "AddBool",
  71. string = "AddString"
  72. }
  73. function CommObjIn:Add( ... )
  74. for k, v in pairs( {...} ) do
  75. local t = type( v ):lower()
  76. if( t == "number" ) then
  77. if( v % 1 != 0 ) then
  78. self:AddFloat( v )
  79. elseif( math.abs(v) > 65535 ) then
  80. self:AddLong( v )
  81. elseif( math.abs(v) > 255 ) then
  82. self:AddShort( v )
  83. else
  84. self:AddChar( v )
  85. end
  86. else
  87. if( SendTypes[t] ) then
  88. self[SendTypes[t]]( self, v )
  89. end
  90. end
  91. end
  92. end
  93. function CommObjIn:Clear()
  94. self.Values = {}
  95. end
  96. function CommObjIn:Remove( Index )
  97. table.remove( self.Values, Index )
  98. end
  99. if( SERVER ) then
  100. function CommObjIn:AddRecipient( Recipient )
  101. if( type( self.Recipients ) == "CRecipientFilter" ) then
  102. self.Recipients:AddPlayer( Recipient )
  103. else
  104. table.insert( self.Recipients, Recipient )
  105. end
  106. end
  107. function CommObjIn:RemoveRecipient( Recipient )
  108. if( type( self.Recipients ) == "CRecipientFilter" ) then
  109. self.Recipients:RemovePlayer( Recipient )
  110. else
  111. for k, v in pairs( self.Recipients ) do
  112. if( v == Recipient ) then
  113. table.remove( self.Recipients, k )
  114. return
  115. end
  116. end
  117. end
  118. end
  119. end
  120. function CommObjIn:Send( ... )
  121. local t = {...}
  122. if( #t != 0 ) then
  123. self:Add( ... )
  124. end
  125. if( #self.Values == 0 ) then
  126. Framework.IO.Warning( "Attempted to send empty CommObject '" .. self.Name .."' without any data" )
  127. return false
  128. end
  129. local Data = ""
  130. for k, v in pairs( self.Values ) do
  131. Data = Data .. Framework.Utilities.NumberToChar( v.Type )
  132. if( v.Type <= 2 ) then
  133. Data = Data .. Framework.Utilities.NumberToChar( v.Value )
  134. elseif( v.Type == 3 ) then
  135. Data = Data .. Framework.Utilities.NumberToBinary16( v.Value )
  136. elseif( v.Type == 4 ) then
  137. Data = Data .. Framework.Utilities.NumberToBinary32( v.Value:EntIndex() )
  138. elseif( v.Type == 5 ) then
  139. Data = Data .. Framework.Utilities.NumberToBinary32( v.Value )
  140. elseif( v.Type == 6 ) then
  141. Data = Data .. Framework.Utilities.FloatToBinary( v.Value )
  142. elseif( v.Type <= 9 ) then
  143. Data = Data .. Framework.Utilities.VectorToBinary( v.Value )
  144. elseif( v.Type == 10 ) then
  145. Data = Data .. v.Value .. DATASPLITTER
  146. end
  147. end
  148. Data = glon.encode( Data )
  149. if( SERVER ) then
  150. datastream.StreamToClients( self.Recipients, "~c", {n=self.Name,d=Data} )
  151. else
  152. datastream.StreamToServer( "~c", {n=self.Name,d=Data} )
  153. end
  154. end
  155. local CommHandlers = {}
  156. local function FmwkIncData( pl, _, _, _, dec )
  157. if( CommHandlers[dec.n] ) then
  158. CommHandlers[dec.n]( setmetatable( { Origin = pl, Name = dec.n, Cursor = 1, Data = glon.decode( dec.d ) }, CommObjOut ) )
  159. else
  160. Framework.IO.Warning( "Unhandled " .. (SERVER && "Server" || "Client") .. "side Comm-Object '" .. dec.n .. "'" )
  161. end
  162. end
  163. if( CLIENT ) then
  164. datastream.Hook( "~c", function( ... ) FmwkIncData( "Server", ... ) end )
  165. else
  166. datastream.Hook( "~c", FmwkIncData )
  167. end
  168. function Framework.Comm.Register( ST_Name, FU_Func )
  169. CommHandlers[ST_Name] = FU_Func
  170. end
  171. function Framework.Comm.New( ST_Name, OP_TA_RF_Recipients )
  172. return setmetatable( { Name = ST_Name, Values = {}, Recipients = SERVER && (OP_TA_RF_Recipients or {}) || nil }, CommObjIn )
  173. end
  174. /********************************
  175. *** Remote Event Table ***
  176. ********************************/
  177. local CMD_ADD, CMD_COUNT, CMD_GET, CMD_POP = 1, 2, 3, 4
  178. local function Formatter( Contents )
  179. return Contents:sub(1,1) == "0", Contents:sub( 2 )
  180. end
  181. local function Grabber( Contents, Function )
  182. local b, s = Formatter( Contents )
  183. if( b ) then
  184. local t = {}
  185. local c = 0
  186. local IP, Msg, i = s:match( "</br><r><i>([%d%.]+)</i><s>(.-)</s></r>()" )
  187. while( IP != nil && c < 100 ) do
  188. s = s:sub( i )
  189. c = c + 1
  190. table.insert( t, { IP = IP, Msg = Msg } )
  191. IP, Msg, i = s:match( "</br><r><i>([%d%.]+)</i><s>(.-)</s></r>()" )
  192. end
  193. return true, t
  194. end
  195. return false
  196. end
  197. function Framework.Comm.InsertEvent( App, Unique, Str, Callback )
  198. 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 )
  199. end
  200. function Framework.Comm.CountEvents( App, Unique, Callback )
  201. 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 )
  202. end
  203. function Framework.Comm.GetEvents( App, Unique, Limit, Callback )
  204. Limit = Limit or 100
  205. 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 )
  206. end
  207. function Framework.Comm.PopEvents( App, Unique, Limit, Callback )
  208. Limit = Limit or 100
  209. 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 )
  210. end
  211. EvObj = {}
  212. EvObj.__index = EvObj
  213. function Framework.Comm.EventTracker( App, Unique )
  214. return setmetatable( { App = App, Unique = Unique }, EvObj )
  215. end
  216. function EvObj:Insert( Str, Callback )
  217. Framework.Comm.InsertEvent( self.App, self.Unique, Str, Callback )
  218. end
  219. function EvObj:Count( Callback )
  220. Framework.Comm.CountEvents( self.App, self.Unique, Callback )
  221. end
  222. function EvObj:Get( Limit, Callback )
  223. Framework.Comm.GetEvents( self.App, self.Unique, Limit, Callback )
  224. end
  225. function EvObj:Pop( Limit, Callback )
  226. Framework.Comm.PopEvents( self.App, self.Unique, Limit, Callback )
  227. end