gnet.bmx 22 KB

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