gnet.bmx 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. SuperStrict
  2. Rem
  3. bbdoc: Networking/GameNet
  4. End Rem
  5. Module BRL.GNet
  6. ModuleInfo "Version: 1.08"
  7. ModuleInfo "Author: Mark Sibly"
  8. ModuleInfo "License: zlib/libpng"
  9. ModuleInfo "Copyright: Blitz Research Ltd"
  10. ModuleInfo "Modserver: BRL"
  11. ModuleInfo "History: 1.08"
  12. ModuleInfo "History: Fixed list issue."
  13. ModuleInfo "History: 1.07"
  14. ModuleInfo "History: Updated for NG."
  15. ModuleInfo "History: Made SuperStrict."
  16. ModuleInfo "History: 1.06 Release"
  17. ModuleInfo "History: Object id's now unmapped ASAP"
  18. ModuleInfo "History: 1.05 Release"
  19. ModuleInfo "History: Some doc fixes"
  20. ModuleInfo "History: 1.04 Release"
  21. ModuleInfo "Histort: Fixed low level send/recv leaks"
  22. ModuleInfo "History: 1.03 Release"
  23. ModuleInfo "History: Now uses Pub.ENet"
  24. ModuleInfo "History: 1.02 Release"
  25. ModuleInfo "History: Fixed Closing host not closing server socket"
  26. ModuleInfo "History: 1.01 Release"
  27. Import Pub.ENet
  28. Import BRL.Socket
  29. Import BRL.LinkedList
  30. Import BRL.System
  31. Import brl.standardio
  32. Private
  33. Const GNET_INT:Int = 1
  34. Const GNET_FLOAT16:Int = 2
  35. Const GNET_STRING:Int = 3
  36. Const GNET_UINT8:Int = 4
  37. Const GNET_UINT16:Int = 5
  38. Const GNET_FLOAT32:Int = 6
  39. Global GNET_DIAGNOSTICS:Int = False
  40. Const GNET_MAXIDS:Int = 4096
  41. ?Debug
  42. Function dprint( t:String )
  43. If GNET_DIAGNOSTICS WriteStdout t+"~n"
  44. End Function
  45. ?
  46. Function PackFloat16:Int( f:Float )
  47. Local i:Int = (Int Ptr Varptr f)[0]
  48. If i=$00000000 Return $0000 '+0
  49. If i=$80000000 Return $8000 '-0
  50. Local M:Int=i Shl 9
  51. Local S:Int=i Shr 31
  52. Local E:Int=(i Shr 23 & $ff)-127
  53. If E=128
  54. If M Return $ffff 'NaN
  55. Return S Shl 15 | $7c00 '+/-Infinity
  56. EndIf
  57. M:+$00200000
  58. If Not (M & $ffe00000) E:+1
  59. If E>15
  60. Return S Shl 15 | $7c00 '+/-Infinity
  61. Else If E<-15
  62. Return S Shl 15 '+/- 0
  63. EndIf
  64. Return S Shl 15 | (E+15) Shl 10 | M Shr 22
  65. End Function
  66. Function UnpackFloat16:Float( i:Int )
  67. i:&$ffff
  68. If i=$0000 Return +0.0
  69. If i=$8000 Return -0.0
  70. Local M:Int=i Shl 22
  71. Local S:Int=i Shr 15
  72. Local E:Int=(i Shr 10 & $1f)-15
  73. If E=16
  74. If M Return 0.0/0.0 'NaN
  75. If S Return -1.0/0.0 '-Infinity
  76. Return +1.0/0.0 '+Infinity
  77. Else If E = -15 'denormal as float16, but normal as float32.
  78. Local i:Int
  79. For i = 0 To 9 'find the leading 1-bit
  80. Local bit:Int = M & $80000000
  81. M:Shl 1
  82. If bit Exit
  83. Next
  84. E:-i
  85. End If
  86. Local n:Int=S Shl 31 | (E+127) Shl 23 | M Shr 9
  87. Return (Float Ptr Varptr n)[0]
  88. End Function
  89. Function PackFloat32:Int( f:Float )
  90. Return (Int Ptr Varptr f)[0]
  91. End Function
  92. Function UnpackFloat32:Float( i:Int )
  93. Return (Float Ptr Varptr i)[0]
  94. End Function
  95. Public
  96. Const GNET_ALL:Int = 0
  97. 'object states
  98. Const GNET_CREATED:Int = 1
  99. Const GNET_MODIFIED:Int = 2
  100. Const GNET_CLOSED:Int = 3
  101. Const GNET_SYNCED:Int = 4
  102. Const GNET_MESSAGE:Int = 5
  103. Const GNET_ZOMBIE:Int = -1
  104. Type TGNetMsg
  105. Field id:Int
  106. Field state:Int
  107. Field data:Byte[]
  108. End Type
  109. Type TGNetSlot
  110. Field _type:Int
  111. Field _int:Int
  112. Field _float:Float
  113. Field _string:String
  114. Method SetInt( data:Int )
  115. Assert _type=0 Or _type=GNET_INT Or _type=GNET_UINT8 Or _type=GNET_UINT16
  116. _int=data
  117. If data<0
  118. _type=GNET_INT
  119. Else If data<=255
  120. _type=GNET_UINT8
  121. Else If data<=65535
  122. _type=GNET_UINT16
  123. Else
  124. _type=GNET_INT
  125. EndIf
  126. End Method
  127. Method SetFloat( data:Float )
  128. Assert _type=0 Or _type=GNET_FLOAT32
  129. _float=data
  130. _type=GNET_FLOAT32
  131. End Method
  132. Method SetString( data:String )
  133. Assert _type=0 Or _type=GNET_STRING
  134. _string=data
  135. _type=GNET_STRING
  136. End Method
  137. Method GetInt:Int()
  138. Assert _type=GNET_INT Or _type=GNET_UINT8 Or _type=GNET_UINT16
  139. Return _int
  140. End Method
  141. Method GetFloat:Float()
  142. Assert _type=GNET_FLOAT32
  143. Return _float
  144. End Method
  145. Method GetString:String()
  146. Assert _type=GNET_STRING
  147. Return _string
  148. End Method
  149. End Type
  150. Type TGNetObject
  151. Method New()
  152. For Local i:Int=0 Until 32
  153. _slots[i]=New TGNetSlot
  154. Next
  155. End Method
  156. Method State:Int()
  157. Return _state
  158. End Method
  159. 'close object
  160. Method Close()
  161. Select _state
  162. Case GNET_CREATED
  163. _state=GNET_ZOMBIE
  164. Case GNET_MODIFIED,GNET_SYNCED
  165. _state=GNET_CLOSED
  166. Case GNET_CLOSED
  167. Default
  168. Throw "Illegal object state"
  169. End Select
  170. End Method
  171. Method SetInt( index:Int, data:Int )
  172. WriteSlot( index ).SetInt data
  173. End Method
  174. Method SetFloat( index:Int, data:Float )
  175. WriteSlot( index ).SetFloat data
  176. End Method
  177. Method SetString( index:Int, data:String )
  178. WriteSlot( index ).SetString data
  179. End Method
  180. Method GetInt:Int( index:Int )
  181. Return _slots[index].GetInt()
  182. End Method
  183. Method GetFloat:Float( index:Int )
  184. Return _slots[index].GetFloat()
  185. End Method
  186. Method GetString:String( index:Int )
  187. Return _slots[index].GetString()
  188. End Method
  189. Method WriteSlot:TGNetSlot( index:Int )
  190. Assert _state<>GNET_CLOSED And _state<>GNET_ZOMBIE Else "Object has been closed"
  191. _modified:|1 Shl index
  192. If _state=GNET_SYNCED _state=GNET_MODIFIED
  193. Return _slots[index]
  194. End Method
  195. Method Sync:TGNetMsg()
  196. Select _state
  197. Case GNET_SYNCED,GNET_ZOMBIE
  198. Return Null
  199. End Select
  200. Local msg:TGNetMsg
  201. If Not _peer
  202. msg:TGNetMsg=New TGNetmsg
  203. msg.id=_id
  204. msg.state=_state
  205. msg.data=PackSlots( _modified )
  206. EndIf
  207. _modified=0
  208. Select _state
  209. Case GNET_CREATED,GNET_MODIFIED
  210. _state=GNET_SYNCED
  211. Case GNET_CLOSED
  212. _target=Null
  213. _state=GNET_ZOMBIE
  214. End Select
  215. Return msg
  216. End Method
  217. Method Update( msg:TGNetMsg )
  218. Assert _id=msg.id
  219. UnpackSlots msg.data
  220. _state=msg.state
  221. End Method
  222. Method CreatedMsg:TGNetMsg()
  223. Local msg:TGNetMsg=New TGNetmsg
  224. msg.id=_id
  225. msg.state=GNET_CREATED
  226. msg.data=PackSlots( ~0 )
  227. Return msg
  228. End Method
  229. Method ClosedMsg:TGNetMsg()
  230. Local msg:TGNetMsg=New TGNetMsg
  231. msg.id=_id
  232. msg.state=GNET_CLOSED
  233. msg.data=PackSlots( 0 )
  234. Return msg
  235. End Method
  236. Method MessageMsg:TGNetMsg( id:Int )
  237. Local msg:TGNetMsg=New TGNetMsg
  238. msg.id=id
  239. msg.state=GNET_MESSAGE
  240. msg.data=PackSlots( ~0 )
  241. Return msg
  242. End Method
  243. Method PackSlots:Byte[]( mask:Int )
  244. Local sz:Int
  245. For Local index:Int=0 Until 32
  246. If Not (mask & 1 Shl index) Continue
  247. Local ty:Int=_slots[index]._type
  248. If Not ty Continue
  249. Select ty
  250. Case GNET_INT
  251. sz:+5
  252. Case GNET_UINT8
  253. sz:+2
  254. Case GNET_UINT16
  255. sz:+3
  256. Case GNET_FLOAT16
  257. sz:+3
  258. Case GNET_FLOAT32
  259. sz:+5
  260. Case GNET_STRING
  261. sz:+3+GetString(index).length
  262. End Select
  263. Next
  264. If sz>$fff0 Throw "GNet message data too large"
  265. Local data:Byte[sz]
  266. Local p:Byte Ptr=data
  267. For Local index:Int=0 Until 32
  268. If Not (mask & 1 Shl index) Continue
  269. Local ty:Int=_slots[index]._type
  270. If Not ty Continue
  271. Select ty
  272. Case GNET_INT
  273. Local n:Int=GetInt( index )
  274. p[0]=GNET_INT Shl 5 | index
  275. p[1]=n Shr 24
  276. p[2]=n Shr 16
  277. p[3]=n Shr 8
  278. p[4]=n Shr 0
  279. p:+5
  280. Case GNET_UINT8
  281. Local n:Int=GetInt( index )
  282. p[0]=GNET_UINT8 Shl 5 | index
  283. p[1]=n
  284. p:+2
  285. Case GNET_UINT16
  286. Local n:Int=GetInt( index )
  287. p[0]=GNET_UINT16 Shl 5 | index
  288. p[1]=n Shr 8
  289. p[2]=n Shr 0
  290. p:+3
  291. Case GNET_FLOAT16
  292. Local n:Int=PackFloat16( GetFloat(index) )
  293. p[0]=GNET_FLOAT16 Shl 5 | index
  294. p[1]=n Shr 8
  295. p[2]=n Shr 0
  296. p:+3
  297. Case GNET_FLOAT32
  298. Local n:Int=PackFloat32( GetFloat(index) )
  299. p[0]=GNET_FLOAT32 Shl 5 | index
  300. p[1]=n Shr 24
  301. p[2]=n Shr 16
  302. p[3]=n Shr 8
  303. p[4]=n Shr 0
  304. p:+5
  305. Case GNET_STRING
  306. Local data:String=GetString( index )
  307. Local n:Size_T=data.length
  308. p[0]=GNET_STRING Shl 5 | index
  309. p[1]=n Shr 8
  310. p[2]=n Shr 0
  311. Local t:Byte Ptr=data.ToCString()
  312. MemCopy p+3,t,n
  313. MemFree t
  314. p:+3+n
  315. Default
  316. Throw "Invalid GNet data type"
  317. End Select
  318. Next
  319. Return data
  320. End Method
  321. Method UnpackSlots( data:Byte[] )
  322. Local p:Byte Ptr=data
  323. Local e:Byte Ptr=p+data.length
  324. While p<e
  325. Local ty:Int=p[0] Shr 5
  326. Local index:Int=p[0] & 31
  327. p:+1
  328. Select ty
  329. Case GNET_INT
  330. SetInt index,p[0] Shl 24 | p[1] Shl 16 | p[2] Shl 8 | p[3]
  331. p:+4
  332. Case GNET_UINT8
  333. SetInt index,p[0]
  334. p:+1
  335. Case GNET_UINT16
  336. SetInt index,p[0] Shl 8 | p[1]
  337. p:+2
  338. Case GNET_FLOAT16
  339. Local t:Int=p[0] Shl 8 | p[1]
  340. SetFloat index,UnpackFloat16( t )
  341. p:+2
  342. Case GNET_FLOAT32
  343. Local t:Int=p[0] Shl 24 | p[1] Shl 16 | p[2] Shl 8 | p[3]
  344. SetFloat index,UnpackFloat32( t )
  345. p:+4
  346. Case GNET_STRING
  347. Local n:Int=p[0] Shl 8 | p[1]
  348. Local data:String=String.FromBytes( p+2,n )
  349. SetString index,data
  350. p:+2+n
  351. Default
  352. Throw "Invalid GNet data type"
  353. End Select
  354. Wend
  355. If p<>e Throw "Corrupt GNet message"
  356. End Method
  357. Function Create:TGNetObject( id:Int,state:Int,host:TGNetHost,peer:TGNetPeer )
  358. Local t:TGNetObject=New TGNetObject
  359. t._id=id
  360. t._state=state
  361. t._host=host
  362. t._peer=peer
  363. Return t
  364. End Function
  365. Field _id:Int
  366. Field _state:Int
  367. Field _host:TGNetHost
  368. Field _peer:TGNetPeer
  369. Field _target:Object
  370. Field _slots:TGNetSlot[32],_modified:Int
  371. End Type
  372. Type TGNetHost
  373. Method UpdateENetEvents()
  374. If Not _enetHost Return
  375. Repeat
  376. Local ev:ENetEvent=New ENetEvent
  377. If Not enet_host_service( _enetHost,ev.eventPtr,0 ) Return
  378. _enetEvents.AddLast(ev)
  379. Forever
  380. End Method
  381. Method Sync()
  382. _created.Clear
  383. _modified.Clear
  384. _closed.Clear
  385. _messages.Clear
  386. Local succ:TLink
  387. 'sync all objects
  388. succ=_objects.FirstLink()
  389. While succ
  390. Local link:TLink=succ
  391. succ=link.NextLink()
  392. Local obj:TGNetObject=TGNetObject(link.Value())
  393. Local msg:TGNetMsg=obj.Sync()
  394. If msg BroadCast msg,obj._peer
  395. If obj._state=GNET_ZOMBIE
  396. If Not obj._peer UnmapObject obj
  397. link.Remove
  398. EndIf
  399. Wend
  400. Repeat
  401. UpdateENetEvents
  402. If _enetEvents.IsEmpty() Return
  403. Local ev:ENetEvent=ENetEvent(_enetEvents.RemoveFirst())
  404. Local peer:TGNetPeer
  405. For Local t:TGNetPeer=EachIn _peers
  406. If t._enetPeer=ev.peer()
  407. peer=t
  408. Exit
  409. EndIf
  410. Next
  411. Select ev.event()
  412. Case ENET_EVENT_TYPE_CONNECT
  413. Assert Not peer Else "GNet error, ENET_EVENT_TYPE_CONNECT with invalid peer"
  414. peer=AddPeer( ev.peer() )
  415. Case ENET_EVENT_TYPE_DISCONNECT, ENET_EVENT_TYPE_DISCONNECT_TIMEOUT
  416. If peer
  417. For Local obj:TGNetObject=EachIn _objects
  418. If obj._peer<>peer Continue
  419. BroadCast obj.ClosedMsg(),peer
  420. peer.UnmapLocalId obj._id
  421. UnmapObject obj
  422. _closed.AddLast obj
  423. obj.Close
  424. Next
  425. _peers.Remove peer
  426. EndIf
  427. Case ENET_EVENT_TYPE_RECEIVE
  428. Assert Not peer Else "GNet error, ENET_EVENT_TYPE_RECEIVE with invalid peer"
  429. Local msg:TGNetMsg=peer.RecvMsg( ev.packet() )
  430. enet_packet_destroy ev.packet()
  431. Select msg.state
  432. Case GNET_MESSAGE
  433. Local obj:TGNetObject=_idMap[msg.id]
  434. If Not obj Continue
  435. If obj._peer
  436. obj._peer.SendMsg msg
  437. Else
  438. obj=TGNetObject.Create( msg.id,GNET_MESSAGE,Self,Null )
  439. _messages.AddLast obj
  440. obj.Update msg
  441. EndIf
  442. Default
  443. Local obj:TGNetObject
  444. Select msg.state
  445. Case GNET_CREATED
  446. obj=TGNetObject.Create( AllocId(),GNET_CREATED,Self,peer )
  447. MapObject obj
  448. peer.MapLocalId obj._id,msg.id
  449. msg.id=obj._id
  450. _objects.AddLast obj
  451. _created.AddLast obj
  452. Case GNET_MODIFIED
  453. obj=_idMap[msg.id]
  454. _modified.AddLast obj
  455. Case GNET_CLOSED
  456. obj=_idMap[msg.id]
  457. Assert peer=obj._peer
  458. peer.UnmapLocalId obj._id
  459. UnmapObject obj
  460. _closed.AddLast obj
  461. End Select
  462. BroadCast msg,peer
  463. obj.Update msg
  464. End Select
  465. Default
  466. Throw "GNet error with unhandled event: " + ev.event()
  467. End Select
  468. Forever
  469. End Method
  470. Method Close()
  471. If Not _peers Return
  472. For Local peer:TGNetPeer=EachIn _peers
  473. peer.Close
  474. Next
  475. _peers=Null
  476. If _enetHost
  477. enet_host_flush _enetHost
  478. enet_host_destroy _enetHost
  479. EndIf
  480. End Method
  481. Method BroadCast( msg:TGNetMsg,except:TGNetPeer )
  482. For Local peer:TGNetPeer=EachIn _peers
  483. If peer<>except peer.SendMsg msg
  484. Next
  485. End Method
  486. Method AddPeer:TGNetPeer( enetPeer:Byte Ptr )
  487. Local peer:TGNetPeer=TGNetPeer.Create( enetPeer )
  488. ?Debug
  489. dprint "Adding peer"
  490. ?
  491. _peers.AddLast peer
  492. For Local obj:TGNetObject=EachIn _objects
  493. Select obj._state
  494. Case GNET_SYNCED,GNET_MODIFIED
  495. peer.SendMsg obj.CreatedMsg()
  496. End Select
  497. Next
  498. Return peer
  499. End Method
  500. Method Objects:TList()
  501. Return _objects
  502. End Method
  503. Method Peers:TList()
  504. Return _peers
  505. End Method
  506. Method ObjectsCreated:TList()
  507. Return _created
  508. End Method
  509. Method ObjectsModified:TList()
  510. Return _modified
  511. End Method
  512. Method ObjectsClosed:TList()
  513. Return _closed
  514. End Method
  515. Method CreateObject:TGNetObject()
  516. Local obj:TGNetObject=TGNetObject.Create( AllocId(),GNET_CREATED,Self,Null )
  517. MapObject obj
  518. _objects.AddLast obj
  519. Return obj
  520. End Method
  521. Method CreateMessage:TGNetObject()
  522. Return TGNetObject.Create( 0,GNET_MESSAGE,Self,Null )
  523. End Method
  524. Method SendGNetMessage( msg:TGNetObject,toObject:TGNetObject )
  525. If toObject._peer
  526. toObject._peer.SendMsg msg.MessageMsg( toObject._id )
  527. EndIf
  528. End Method
  529. Method AllocId:Int()
  530. For Local id:Int=1 Until GNET_MAXIDS
  531. If Not _idMap[id] Return id
  532. Next
  533. Throw "Out of GNet object IDs"
  534. End Method
  535. Method MapObject( obj:TGNetObject )
  536. Assert Not _idMap[obj._id]
  537. _idMap[obj._id]=obj
  538. End Method
  539. Method UnmapObject( obj:TGNetObject )
  540. Assert _idMap[obj._id]=obj
  541. _idMap[obj._id]=Null
  542. End Method
  543. Method Listen:Int( port:Int )
  544. If _enetHost Return False
  545. Local addr:Byte Ptr=enet_address_create( ENET_HOST_ANY,port )
  546. _enetHost=enet_host_create( addr,32,0,0,0 )
  547. enet_address_destroy addr
  548. If Not _enetHost Return False
  549. Return True
  550. End Method
  551. Method Connect:Int( ip:Int,port:Int,timeout:Int )
  552. If _enetHost Return False
  553. _enetHost=enet_host_create( Null,32,0,0,0 )
  554. If Not _enetHost Return False
  555. Local addr:Byte Ptr=enet_address_create( ip,port )
  556. Local peer:Byte Ptr=enet_host_connect( _enetHost,addr,1,0 )
  557. enet_address_destroy addr
  558. If peer
  559. timeout:+MilliSecs()
  560. While timeout-MilliSecs()>0
  561. UpdateENetEvents
  562. For Local ev:ENetEvent=EachIn _enetEvents
  563. If ev.event()=ENET_EVENT_TYPE_CONNECT And ev.peer()=peer
  564. _enetEvents.Remove(ev)
  565. AddPeer peer
  566. Return True
  567. EndIf
  568. next
  569. Wend
  570. EndIf
  571. enet_host_destroy _enetHost
  572. _enetHost=Null
  573. End Method
  574. Method Connect:Int( ip:String,port:Int,timeout:Int )
  575. If _enetHost Return False
  576. _enetHost=enet_host_create( Null,32,0,0,0 )
  577. If Not _enetHost Return False
  578. Local addr:Byte Ptr=enet_address_create( ip,port )
  579. Local peer:Byte Ptr=enet_host_connect( _enetHost,addr,1,0 )
  580. enet_address_destroy addr
  581. If peer
  582. timeout:+MilliSecs()
  583. While timeout-MilliSecs()>0
  584. UpdateENetEvents
  585. For Local ev:ENetEvent=EachIn _enetEvents
  586. If ev.event()=ENET_EVENT_TYPE_CONNECT And ev.peer()=peer
  587. _enetEvents.Remove(ev)
  588. AddPeer peer
  589. Return True
  590. EndIf
  591. next
  592. Wend
  593. EndIf
  594. enet_host_destroy _enetHost
  595. _enetHost=Null
  596. End Method
  597. Function Create:TGNetHost()
  598. Local t:TGNetHost=New TGNetHost
  599. Return t
  600. End Function
  601. Field _enetHost:Byte Ptr
  602. Field _enetEvents:TList = New TList
  603. Field _peers:TList=New TList 'active peers
  604. Field _objects:TList=New TList 'all objects
  605. Field _created:TList=New TList 'created remote objects
  606. Field _modified:TList=New TList 'modified remote objects
  607. Field _closed:TList=New TList 'closed remote objects
  608. Field _messages:TList=New TList 'messages received
  609. Field _idMap:TGNetObject[GNET_MAXIDS]
  610. End Type
  611. Type TGNetPeer
  612. 'enet peer
  613. Field _enetPeer:Byte Ptr
  614. 'id mapping
  615. Field _localToRemote:Int[GNET_MAXIDS]
  616. Field _remoteToLocal:Int[GNET_MAXIDS]
  617. Method Close()
  618. If Not _enetPeer Return
  619. enet_peer_disconnect _enetPeer, 0
  620. _enetPeer=Null
  621. End Method
  622. Method MapLocalId( localId:Int,remoteId:Int )
  623. Assert Not _localToRemote[localId] And Not _remoteToLocal[remoteId]
  624. _localToRemote[localId]=remoteId
  625. _remoteToLocal[remoteId]=localId
  626. ?Debug
  627. dprint "Mapped localId:"+localId+"<->remoteId:"+remoteId
  628. ?
  629. End Method
  630. Method UnmapLocalId( localId:Int )
  631. Local remoteId:Int=_localToRemote[localId]
  632. Assert _localToRemote[localId]=remoteId And _remoteToLocal[remoteId]=localId
  633. _localToRemote[localId]=0
  634. _remoteToLocal[remoteId]=0
  635. ?Debug
  636. dprint "Unmapped localId:"+localId+"<->remoteId:"+remoteId
  637. ?
  638. End Method
  639. Method RecvMsg:TGNetMsg( packet:Byte Ptr )
  640. Local buf:Byte Ptr=bmx_enet_packet_data( packet )
  641. Local sz:Size_T=bmx_enet_packet_size( packet )-2
  642. Local id:Int=(buf[0] Shl 8 | buf[1]) & (GNET_MAXIDS-1)
  643. Local state:Int=(buf[0] Shl 8 | buf[1]) Shr 12
  644. If state<>GNET_MESSAGE
  645. id=_remoteToLocal[id]
  646. If id
  647. Assert state<>GNET_CREATED Else "Illegal remoteId"
  648. Else
  649. Assert state=GNET_CREATED Else "Unmapped remoteId: obj.state="+buf[1]
  650. id=(buf[0] Shl 8 | buf[1]) & (GNET_MAXIDS-1)
  651. EndIf
  652. EndIf
  653. Local msg:TGNetMsg=New TGNetmsg
  654. msg.id=id
  655. msg.state=state
  656. If sz
  657. msg.data=New Byte[sz]
  658. MemCopy msg.data,buf+2,Size_T(sz)
  659. EndIf
  660. ?Debug
  661. If msg.state<>2 dprint "RecvMsg id="+msg.id+", state="+msg.state+", size="+sz
  662. ?
  663. Return msg
  664. End Method
  665. Method SendMsg( msg:TGNetMsg )
  666. Local sz:Size_T=msg.data.length
  667. Local buf:Byte Ptr=MemAlloc( sz+2 )
  668. Local id:Int=msg.id
  669. If msg.state=GNET_MESSAGE
  670. id=_localToRemote[id]
  671. Assert id Else "SendMsg: Unmapped localId="+msg.id
  672. EndIf
  673. buf[0]=(msg.state Shl 12 | id) Shr 8
  674. buf[1]=(msg.state Shl 12 | id) Shr 0
  675. If sz MemCopy buf+2,msg.data,sz
  676. ?Debug
  677. dprint "SendMsg id="+id+", state="+msg.state+", size="+sz
  678. ?
  679. Local packet:Byte Ptr=enet_packet_create( buf,sz+2,ENET_PACKET_FLAG_RELIABLE )
  680. MemFree buf
  681. If enet_peer_send( _enetPeer,0,packet )<0 Throw "ENet errror"
  682. End Method
  683. Function Create:TGNetPeer( enetPeer:Byte Ptr )
  684. Local t:TGNetPeer=New TGNetPeer
  685. t._enetPeer=enetPeer
  686. Return t
  687. End Function
  688. End Type
  689. Rem
  690. bbdoc: Create GNet host
  691. returns: A new GNet host
  692. about:
  693. Once you have created a GNet host, you can use it to create objects with #CreateGNetObject,
  694. connect to other hosts with #GNetConnect and listen for connections from other hosts with
  695. #GNetListen.
  696. End Rem
  697. Function CreateGNetHost:TGNetHost()
  698. Return TGNetHost.Create()
  699. End Function
  700. Rem
  701. bbdoc: Close a GNet host
  702. about:
  703. Once closed, a GNet host cannot be reopened.
  704. End Rem
  705. Function CloseGNetHost( host:TGNetHost )
  706. host.Close
  707. End Function
  708. Rem
  709. bbdoc: Synchronize GNet host
  710. about:
  711. #GNetSync will update the state of all GNet objects. Once you have used this command,
  712. use the #GNetObjects function to determine which objects have been remotely created, modified
  713. or closed.
  714. End Rem
  715. Function GNetSync( host:TGNetHost )
  716. host.Sync()
  717. End Function
  718. Rem
  719. bbdoc: Listen for connections
  720. returns: True if successful, otherwise false
  721. about:
  722. Causes @host to start listening for connection attempts on the specified @port.
  723. Once a host is listening, hosts on other machines can connect using #GNetConnect.
  724. #GNetListen may fail if @port is already in use by another application, or if @host
  725. is already listening or has already connected to a remote host using #GNetConnect.
  726. End Rem
  727. Function GNetListen:Int( host:TGNetHost,port:Int )
  728. Return host.Listen( port )
  729. End Function
  730. Rem
  731. bbdoc: Connect to a remote GNet host
  732. returns: True if connection successful, otherwise false
  733. about:
  734. Attempts to connect @host to the specified remote address and port.
  735. A GNet host must be listening (see #GNetListen) at the specified address and port for the
  736. connection to succeed.
  737. End Rem
  738. Function GNetConnect:Int( host:TGNetHost,address:String,port:Int,timeout_ms:Int=10000 )
  739. Return host.Connect( HostIp(address),port,timeout_ms )
  740. End Function
  741. Rem
  742. bbdoc: Get a list of GNet objects
  743. returns: A linked list
  744. about:
  745. #GNetObjects returns a list of GNet objects in a certain state.
  746. The @state parameter controls which objects are listed, and can be one of &GNET_ALL,
  747. &GNET_CREATED, &GNET_MODIFIED or &GNET_CLOSED.
  748. Note that with the exception of &GNET_ALL, the returned lists will only ever contain remote objects.
  749. End Rem
  750. Function GNetObjects:TList( host:TGNetHost,state:Int=GNET_ALL )
  751. Select state
  752. Case GNET_ALL
  753. Return host.Objects()
  754. Case GNET_CREATED
  755. Return host.ObjectsCreated()
  756. Case GNET_MODIFIED
  757. Return host.ObjectsModified()
  758. Case GNET_CLOSED
  759. Return host.ObjectsClosed()
  760. End Select
  761. Throw "Unknown object state"
  762. End Function
  763. Rem
  764. bbdoc: Get a list of GNet messages sent to local objects
  765. returns: A linked list
  766. End Rem
  767. Function GNetMessages:TList( host:TGNetHost )
  768. Return host._messages
  769. End Function
  770. Rem
  771. bbdoc: Create a GNet object
  772. returns: A new GNet object
  773. End Rem
  774. Function CreateGNetObject:TGNetObject( host:TGNetHost )
  775. Return host.CreateObject()
  776. End Function
  777. Rem
  778. bbdoc: Create a GNet message object
  779. returns: A new GNet object
  780. End Rem
  781. Function CreateGNetMessage:TGNetObject( host:TGNetHost )
  782. Return host.CreateMessage()
  783. End Function
  784. Rem
  785. bbdoc: Send a GNet message to a remote object
  786. End Rem
  787. Function SendGNetMessage( msg:TGNetObject,toObject:TGNetObject )
  788. msg._host.SendGNetMessage( msg,toObject )
  789. End Function
  790. Rem
  791. bbdoc: Get message target object
  792. returns: The object that @msg was sent to
  793. End Rem
  794. Function GNetMessageObject:TGNetObject( msg:TGNetObject )
  795. Return msg._host._idMap[msg._id]
  796. End Function
  797. Rem
  798. bbdoc: Get state of a GNet object
  799. returns: An integer state
  800. about:The returned value can be one of the following:
  801. <table>
  802. <tr><th>Object State</th><th>Meaning</th></tr>
  803. <tr><td>GNET_CREATED</td><td>Object has been created</td></tr>
  804. <tr><td>GNET_SYNCED</td><td>Object is in sync</td></tr>
  805. <tr><td>GNET_MODIFIED</td><td>Object has been modified</td></tr>
  806. <tr><td>GNET_CLOSED</td><td>Object has been closed</td></tr>
  807. <tr><td>GNET_ZOMBIE</td><td>Object is a zombie</td></tr>
  808. <tr><td>GNET_MESSAGE</td><td>Object is a message object</td></tr>
  809. </table>
  810. Zombie objects are objects that have been successfully closed and will never again be used
  811. by GameNet. Therefore, such objects will never appear in any list returned by the
  812. #GNetObjects function.
  813. End Rem
  814. Function GNetObjectState:Int( obj:TGNetObject )
  815. Return obj.State()
  816. End Function
  817. Rem
  818. bbdoc: Determine whether a GNet object is local
  819. returns: True if object is a local object
  820. End Rem
  821. Function GNetObjectLocal:Int( obj:TGNetObject )
  822. Return obj._peer=Null
  823. End Function
  824. Rem
  825. bbdoc: Determine whether a GNet object is remote
  826. returns: True if object is a remote object
  827. End Rem
  828. Function GNetObjectRemote:Int( obj:TGNetObject )
  829. Return obj._peer<>Null
  830. End Function
  831. Rem
  832. bbdoc: Set GNet object int data
  833. End Rem
  834. Function SetGNetInt( obj:TGNetObject,index:Int,value:Int )
  835. obj.SetInt index,value
  836. End Function
  837. Rem
  838. bbdoc: Set GNet object float data
  839. End Rem
  840. Function SetGNetFloat( obj:TGNetObject,index:Int,value:Float )
  841. obj.SetFloat index,value
  842. End Function
  843. Rem
  844. bbdoc: Set GNet object string data
  845. End Rem
  846. Function SetGNetString( obj:TGNetObject,index:Int,value:String )
  847. obj.SetString index,value
  848. End Function
  849. Rem
  850. bbdoc: Get GNet object int data
  851. End Rem
  852. Function GetGNetInt:Int( obj:TGNetObject,index:Int )
  853. Return obj.GetInt( index )
  854. End Function
  855. Rem
  856. bbdoc: Get GNet object float data
  857. End Rem
  858. Function GetGNetFloat:Float( obj:TGNetObject,index:Int )
  859. Return obj.GetFloat( index )
  860. End Function
  861. Rem
  862. bbdoc: Get GNet object string data
  863. End Rem
  864. Function GetGNetString:String( obj:TGNetObject,index:Int )
  865. Return obj.GetString( index )
  866. End Function
  867. Rem
  868. bbdoc: Set a GNet object's target object
  869. about:
  870. This command allows you to bind an abitrary object to a GNet object.
  871. End Rem
  872. Function SetGNetTarget( obj:TGNetObject,target:Object )
  873. obj._target=target
  874. End Function
  875. Rem
  876. bbdoc: Get a GNet object's target object
  877. returns: The currently bound target object
  878. End Rem
  879. Function GetGNetTarget:Object( obj:TGNetObject )
  880. Return obj._target
  881. End Function
  882. Rem
  883. bbdoc: Close a GNet object
  884. End Rem
  885. Function CloseGNetObject( obj:TGNetObject )
  886. Assert Not obj._peer Else "CloseGNetObject can only be used with local objects"
  887. obj.Close
  888. End Function