RakNet wrapper for Blitz (open source project)

Miscellaneous Forums/Blitz Showcase/RakNet wrapper for Blitz (open source project)

Hi,

The wrapper of RakNet version 3 is now out for BlitzMax!!
RakNet is a VERY powerful network library, with a lot of possibilities (see here).

This wrapper works for all versions of Blitz (BlitzMax, Blitz3D, BlitzPlus). Note that this is windows only unfortunately.

The wrapper is open source and any improvement is very welcome. If you modify the wrapper, please send me the updated file. Of course, the wrapper is free.

The wrapper could also be extended, since only a fraction of RakNet has been wrapped. I have almost no time to program now, so do not count on me!

You can download it here: http://repeatuntil.online.fr

Good job repeat :) clear code :)

Fantastic stuff !

great work... would be nice to see this for blitz3d ;)

Note that this is windows only.


Isn't it a cross-platform network library??

I guess the wrapping part of it is windows only?

It is cross platform. So in my initial try, my goal was to include directly the source in BlitzMax. But unfortunately, it was not possible because RakNet is threaded, and BlitzMax was crashing due to the threading in RakNet.
In the end, in front of this big difficulty, I had no choice but use a dll, hence windows only. I was the first disappointed!!

Please test this wrapper, as I am not sure everything works correctly...

It looks great but I have a question...
It should support a p2p network.
What I have to change in the example to make such a network?? All players have to connect to each other like the client to the server does or how I have to deal with that??

Yes, RakNet supports both client-server and peer to peer architecture.
I am not at all an expert of RakNet, but I think you should do basically like in the example I give, but set the maximum number of connection to 1 for everyone.
I am sure this question was asked on the RakNet forum, or is maybe in the manual: please have a look there: RakNet site.

Did some people here try to test the wrapper? Is this working as expected? Do you plan to include it in one of your project? Or even to improve the wrapper??

I tried the examples you provided which work beautifully.
No in-depth testing yet but this ranks high on my personal list of BMX network libraries taken into consideration :)

Same here - initial tests are working -I had to add the stream calls (as I extensively use those).

More to follow as Im planning another multiplayer game over the coming months.

Hi,

just to let you know that one user of the wrapper (Andy) did some change to the wrapper.


I have made a slight alteration to the Raknet.bmx file so it can compile in SuperStrict mode in BlitzMax. Nothing else has been altered.
Andy



Thanks very much to Andy! The updated files can be downloaded from my sig.

Blitz3D version: http://www.blitzbasic.com/Community/posts.php?topic=50546

Yes, but this is with an older version of RakNet (2.xx). That would be nice if someone (who needs it) could write the decls file to adapt the wrapper. This is an easy task (I won't do it since I have unfortunately no time for programming now).

Sorry to bring up a 2 month old topic; but has anyone managed to get raknet working with BM on other operating systems yet?

Not asking for a public release of it; just a response on whether it has been done.


Sorry to bring up a 2 month old topic; but has anyone managed to get raknet working with BM on other operating systems yet?



No, nobody is working on that. As I said in a previous message in this thread, I did an attempt, but failed miserably because BlitzMax doesn't work well with a threaded library...

By the way, RakNet is now available for Blitz3D/Plus. See another message in the same forum (sorry for the double post!).

How do i install RackNet for BlitzMax?

That's simple:
- put the RakNet dll file in a folder
- put the RakNet.bmx file in the same folder
- put the example file in the same folder (or your program)
- that's it!

Hope it helps...

Will this work for Truevision3D?

What I want to do is use BlitzMax with Gabriels TV3D wrapper and have network capabilities with Raknet?

Possible? I'm new to all this network stuff.

Ta for this by the way! :)

I doubt this is a bug, but it seems the packet delimiter for each udp packet is chr(0). Is this default in raknet? Is there any way to change that without altering the source?

It doesn't seem possible to use stream-styled packets with this in the way.

Amon: I haven't looked at RakNet, but I don't see any reason why not. TV doesn't have any Net stuff at the moment ( and when it does, it will be a separate dll ) so there should be nothing in place which would conflict.

Yes, RakNet would work with TrueVision3D, it will just be simply another call to the RakNet dll, no problem with that.

For the chr(0) in the udp packet, I don't know. What I know is that you can send message in 2 ways: either conventionnal one, either bitstreams. Maybe bitstreams is what you want?? Please refer to the RakNet web site for details (http://www.jenkinssoftware.com/) as unfortunately I am not at all an expert.

Thanks repeat. I wish I did that before playing around with the conventional method for several hours :'(.

Bitstreams are amazing! Thanks for this wrapper.

Bitstream functions for anyone who needs them:

In RakNet.bmx (RepeatUntil's)
Replace
' BitStreams are wrapped. If you need them, add the functions here!


With

' BitStreams are wrapped. If you need them, add the functions here!
Global RN_BitStreamCreate1:Int(initialBytesToAllocate:Int) "Win32" = GetProcAddress(lib, "RN_BitStreamCreate1@4") 
Global RN_BitStreamCreate2:Int(data:String,length:Int,copydata:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamCreate2@12")
Global RN_BitStreamReset(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReset@4")
Global RN_BitStreamDestroy(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamDestroy@4")
Global RN_BitStreamCreateFromPacket:Int(packet:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamCreateFromPacket@4")
Global RN_BitStreamWriteBool (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteBool@8")
Global RN_BitStreamWriteUnsignedChar (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedChar@8")
Global RN_BitStreamWriteChar (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteChar@8")
Global RN_BitStreamWriteUnsignedShort (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedShort@8")
Global RN_BitStreamWriteShort (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteShort@8")
Global RN_BitStreamWriteUnsignedInt (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedInt@8")
Global RN_BitStreamWriteInt (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteInt@8")
Global RN_BitStreamWriteUnsignedLong (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedLong@8")
Global RN_BitStreamWriteLong (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteLong@8")
Global RN_BitStreamWriteFloat (bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteFloat@8")
Global RN_BitStreamWriteDouble (bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteDouble@8")
Global RN_BitStreamWrite (bitstream:Int,Inpt:String,numberOfBytes:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWrite@12")
Global RN_BitStreamWriteCompressedUnsignedChar(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedChar@8")
Global RN_BitStreamWriteCompressedChar(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedChar@8")
Global RN_BitStreamWriteCompressedUnsignedShort(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedShort@8")
Global RN_BitStreamWriteCompressedShort(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedShort@8")
Global RN_BitStreamWriteCompressedUnsignedInt(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedInt@8")
Global RN_BitStreamWriteCompressedInt(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedInt@8")
Global RN_BitStreamWriteCompressedUnsignedLong (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedLong@8")
Global RN_BitStreamWriteCompressedLong(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedLong@8")
Global RN_BitStreamWriteCompressedFloat(bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedFloat@8")
Global RN_BitStreamWriteCompressedDouble(bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedDouble@8")
Global RN_BitStreamReadBool:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadBool@4")
Global RN_BitStreamReadUnsignedChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedChar@4")
Global RN_BitStreamReadChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadChar@4")
Global RN_BitStreamReadUnsignedShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedShort@4")
Global RN_BitStreamReadShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadShort@4")
Global RN_BitStreamReadUnsignedInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedInt@4")
Global RN_BitStreamReadInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadInt@4")
Global RN_BitStreamReadUnsignedLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedLong@4")
Global RN_BitStreamReadLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadLong@4")
Global RN_BitStreamReadFloat:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadFloat@4")
Global RN_BitStreamReadDouble:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadDouble@4")
Global RN_BitStreamRead:String(bitstream:Int,numberOfBytes:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamRead@8")
Global RN_BitStreamReadCompressedUnsignedChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedChar@4")
Global RN_BitStreamReadCompressedChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedChar@4")
Global RN_BitStreamReadCompressedUnsignedShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedShort@4")
Global RN_BitStreamReadCompressedShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedShort@4")
Global RN_BitStreamReadCompressedUnsignedInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedInt@4")
Global RN_BitStreamReadCompressedInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedInt@4")
Global RN_BitStreamReadCompressedUnsignedLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedLong@4")
Global RN_BitStreamReadCompressedLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedLong@4")
Global RN_BitStreamReadCompressedFloat:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedFloat@4")
Global RN_BitStreamReadCompressedDouble:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedDouble@4")
Global RN_BitStreamResetReadPointer(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamResetReadPointer@4")
Global RN_BitStreamAssertStreamEmpty(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAssertStreamEmpty@4")
Global RN_BitStreamPrintBits(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamPrintBits@4")
Global RN_BitStreamIgnoreBits(bitstream:Int,numberOfBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamIgnoreBits@8")
Global RN_BitStreamSetWriteOffset(bitstream:Int,offset:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamSetWriteOffset@8")
Global RN_BitStreamGetNumberOfBitsUsed:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetNumberOfBitsUsed@4")
Global RN_BitStreamGetNumberOfBytesUsed:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetNumberOfBytesUsed@4")
Global RN_BitStreamGetReadOffset:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetReadOffset@4")
Global RN_BitStreamGetNumberOfUnreadBits:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetNumberOfUnreadBits@4")
Global RN_BitStreamSetData(bitstream:Int,data:String,numberOfBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamSetData@12")
Global RN_BitStreamGetData:String(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetData@4")
Global RN_BitStreamGetDataPointer:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetDataPointer@4")
Global RN_BitStreamWriteBits(bitstream:Int,Inp:String,numberOfBitsToWrite:Int,rightAlignedBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteBits@16")
Global RN_BitStreamWriteAlignedBytes(bitstream:Int,Inpt:String,numberOfBytesToWrite:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteAlignedBytes@12")
Global RN_BitStreamReadAlignedBytes:String(bitstream:Int,numberOfBytesToRead:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadAlignedBytes@8")
Global RN_BitStreamAlignWriteToByteBoundary(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAlignWriteToByteBoundary@4")
Global RN_BitStreamAlignReadToByteBoundary(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAlignReadToByteBoundary@4")
Global RN_BitStreamReadBits:String(bitstream:Int,numberOfBitsToRead:Int,alignBitsToRight:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadBits@12")
Global RN_BitStreamWrite0(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWrite0@4")
Global RN_BitStreamWrite1(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWrite1@4")
Global RN_BitStreamReadBit:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadBit@4")
Global RN_BitStreamAssertCopyData(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAssertCopyData@4")
Global RN_BitStreamSetNumberOfBitsAllocated(bitstream:Int,lengthInBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamSetNumberOfBitsAllocated@8")



Retimer, what are you working on? online game?

A few seperate projects linking to the same thing. A developers network engine.

Basically an engine that will allow people to create games/applications for my company Lobby (sorta like Steam:halflife engine, but currently only supporting 2d sidescroll/isometric games & applications) with easy tools that will allow multiple people to work on projects at the same time;Multiplayer map editing, game data [database] creations, etc. The end goal is to create an engine that people can easily 'ship and go' applications&games within the lobby, update at anytime (or even real-time), and charge subscriptions+create revenue from it through the company.

It's completely experimental. Sorry for going off-topic repeat. I wish I could just use Private Messages.

Sounds like what I'm working on too :-D

What is a bit stream, like a regular byte stream but you can access any number of bits?

Yes. Booleans can actually be sent as a single bit, rather than 8 bits (1 byte).

I don't completely understand its architecture yet, but it also can uses some form of compression by including the number of 1's/0's in order. Lets you send chr(0)'s (as to optimize by using stream methods of writeByte,WriteShort,etc).

I've discovered though, that it's very important to create the streamsize to exactly what you are going to use. I also have had some trouble sending a single letter with bitstreamread/bitstreamwrite, but the work around is to tell it that the length is 2, or simply send a single char.

I have provided a bitstream example below (A redo of the conventional method provided by repeat, in bitstream). However since it was my first hour of playing with bitstreams (ever), i'm sure there are some things that can be fixed. It should at least give an idea though. I have commented my beliefs on how a lot of it works.
I also added a couple extra things to make it more like a real chat program. You can enter your screenname if you are a client. It also shows you bits and bytes sent.

Make sure you have added the bitstream commands to RakNet.bmx. I have showed how to add them in my above post.

'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- Raknet wrapper for BlitzMax. This wrapper was originally developped by Kurix for       -
'- Blitz3D, adapted to RakNet 3 and BlitzMax by RepeatUntil.                              -
'- This wrapper is open source, and could be modified by anyone who would like to         -
'- improve it. This is a project who should benefit the whole Blitz community, so please  -
'- send all improvements to repeatuntil@... (to upload on a web site).                -
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'Bitstream example unprofessionally redone by Retimer. Feb 5th,2008 - Rev 2

Strict

Include "RakNet.bmx"


Global txtList:TList = New TList


Global peer = 0
Global serverPort = 61019
Global packet = 0
Global isServer
Global stat = 0
Global BitReader:Int
Global BitWriter:Int

Global systemAddressServer = 0
Global systemAddressClient1 = 0
Global systemAddressClient2 = 0


' Should start after ID_USER_PACKET_ENUM (=71 in Raknet 3.0)
Const ID_KEY_F1 = 100
Const ID_CHAT = 101


Global nbPlayerMax = 32

Graphics 640, 480, 0

Global YourName:String

Local str:String = InputText("(S)erver or (C)lient?  ", 0, 0) 
If Upper(str:String) <> "S" 'Then player gets to choose screen name
	YourName = InputText("ScreenName: ", 0, 0) 
Else
	YourName = "Server"
End If
peer = RN_GetRakPeerInterface() 


If Upper(str$) = "S" Then
	isServer = True
	Local ok = RN_Startup(peer, nbPlayerMax, 0, serverPort)
	RN_SetMaximumIncomingConnections(peer,nbPlayerMax)
	
	If ok Then 
		AddTxt "Server correctly started"
	Else
		AddTxt "Problem when starting the server!"
	EndIf	
Else
	isServer = False
	str$ = "" 'InputText("Enter server IP Or hit enter For 127.0.0.1:  ", 0, 0);
	If Trim(str) = "" Then str = "127.0.0.1"
	RN_Startup(peer,1,0,0)   ' 1 player allowed to connect -> client
	Local ok = RN_Connect(peer, str, serverPort, "", 0) ;
	If ok Then 
		AddTxt "Client correctly started"
	Else
		AddTxt "Problem when starting the client!"
	EndIf
EndIf

While (Not KeyHit(KEY_ESCAPE))
	Local chatMsg$ = DynamicInput("Enter chat here : ", 20, GraphicsHeight()*0.9)
	If Trim(chatMsg) <> "" Then
		RN_BitStreamDestroy(BitWriter)  'Probobly not necessary, but I destroy it anyways.
		
		BitWriter = RN_BitStreamCreate1(0)      'Create an empty bitstream
		Local I:Int
		RN_BitStreamWriteChar(BitWriter, ID_CHAT)      'Packet Type
		RN_BitStreamWriteShort(BitWriter, Len(YourName))                'Length of the Chat Message
		For I = 1 To Len(YourName)    'Write Each Char out.
			RN_BitStreamWriteChar(BitWriter, Asc(Mid(YourName, I, 1))) 
		Next
		RN_BitStreamWriteShort(BitWriter, (Len(ChatMsg)))           'Length of the Chat Message
		For I = 1 To Len(ChatMsg)     'Write Each Char out
			RN_BitStreamWriteChar(BitWriter, Asc(Mid(ChatMsg, I, 1))) 
		Next
		RN_BitStreamSetNumberOfBitsAllocated(BitWriter, RN_BitStreamGetNumberOfBitsUsed(BitWriter))  'Fix Number of bytes allocated.
		RN_SendBitStream(peer, BitWriter, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, True) 

		'Small addition I added, so you can actually see what 'YOU' said.
		AddTxt "You Said: " + ChatMsg
	EndIf


	packet = RN_Receive(peer) 


	If (packet) Then
		If BitReader Then rn_bitstreamdestroy(BitReader)   'Destroy the old bitstream
		BitReader = RN_BitStreamCreateFromPacket(packet)  'Read the packet into a bitstream
		Local msgType:Int = (RN_BitStreamReadChar(BitReader))   'Get the packet type id.
		Local systemAddress:Int = RN_PacketGetSystemAddress(packet) 
		Local UserIndex:Int = RN_GetIndexFromSystemAddress(peer, systemAddress) 
		
		'Un-comment the line below if u truly need this for debugging.
		'AddTxt("Packet from = " + RN_PacketGetplayerIndex(packet) + "/" + RN_PacketGetBinaryAddress(packet) + "/" + RN_PacketGetPort(packet)) 
		
		Select msgType
			Case ID_REMOTE_DISCONNECTION_NOTIFICATION
				AddTxt("Another client has disconnected.")
			Case ID_REMOTE_CONNECTION_LOST
				AddTxt("Another client has lost the connection.")
			Case ID_REMOTE_NEW_INCOMING_CONNECTION
				AddTxt("Another client has connected.")
			Case ID_CONNECTION_REQUEST_ACCEPTED
				systemAddressServer = RN_PacketGetSystemAddress(packet)
				AddTxt("Our connection request has been accepted.")
			Case ID_NEW_INCOMING_CONNECTION
				If Not systemAddressClient1 Then
					systemAddressClient1 = RN_PacketGetSystemAddress(packet)
					stat = RN_ServerGetStatistics(peer,systemAddressClient1)
				Else
					systemAddressClient2 = RN_PacketGetSystemAddress(packet)
				EndIf
				AddTxt("A connection is incoming.")
			Case ID_NO_FREE_INCOMING_CONNECTIONS
				AddTxt("The server is full.")
			Case ID_DISCONNECTION_NOTIFICATION
				If (isServer)
					AddTxt("A client has disconnected.")
				Else
					AddTxt("We have been disconnected.")
				EndIf
			Case ID_CONNECTION_LOST
				If (isServer)
					AddTxt("A client lost the connection.")
				Else
					AddTxt("Connection lost.")
				EndIf
			Case ID_CHAT
				Local UserLen:Int = RN_BitStreamReadShort(BitReader)    'Get length of users ScreenName
				Local UserName:String
				Local I:Int
				For I = 1 To userlen
					UserName = UserName + Chr(RN_BitStreamReadChar(BitReader)) 
				Next
				Local ChatLen:Int = RN_BitStreamReadShort(BitReader)    'Get length of chat message
				Local ChatMessage:String
				For I = 1 To ChatLen
			    	ChatMessage = ChatMessage + Chr(RN_BitStreamReadChar(BitReader)) 
				Next
				AddTxt UserName + ": " + ChatMessage
				If (isServer) Then
					RN_BitStreamResetReadPointer(BitReader) 
					RN_SendBitStream(peer, BitReader, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RN_PacketGetSystemAddress(packet), True) ;
				EndIf
			Default
				AddTxt("Message with identifier " + msgType + " has arrived.") 

		End Select


		packet = RN_DeallocatePacket(peer, packet)

	EndIf

	DrawText(ServerConnectionCount() + " people connected", 20, GraphicsHeight()*0.55)
	If (isServer) Then
		If (systemAddressClient1)  DrawText("Ping: " + RN_GetAveragePing(peer, systemAddressClient1) + "/" + RN_GetLowestPing(peer,systemAddressClient1) + "/" + RN_GetLastPing(peer,systemAddressClient1), 20, GraphicsHeight()*0.6)
		If (stat) Then
			DrawText("stat = " + RN_StatisticsGetTotalBitsSent(stat) + " Bits (" + (RN_StatisticsGetTotalBitsSent(stat) / 8) + " Bytes) /" + RN_StatisticsGetPacketsReceived(stat), 20, GraphicsHeight() * 0.65) 
		EndIf
	EndIf

	DrawTxt()
	Flip
	
	Delay 1
	
	Cls
Wend

RN_CloseConnection(peer,RN_GetSystemAddressFromIndex(peer, 0), True)
RN_Shutdown(peer, 100)
peer = RN_DestroyRakPeerInterface(peer)




Function ServerConnectionCount%()
	Local count = 0
	For Local i = 0 To nbPlayerMax
		If RN_GetSystemAddressFromIndex(peer, i) <> -1  count = count + 1
	Next
	Return count
End Function





'-------------- NOT RELATED TO RAKNET - JUST USEFUL STUFF --------------------


Rem 
bbdoc: InputText works just as a normal input but in graphicsmode. It waits for you to press enter then returns a string.
EndRem 
Function InputText$(Text$,X,Y)
Local Inp$
	Repeat
		Inp = TInput.Text(Text$,X,Y)
		Flip;Cls
	Until Inp <> ""

Return Inp
EndFunction

Rem 
bbdoc: InputText works just as a normal Textinput but it does NOT stop the program! Returns "" until ENTER is pressed then the message you have written is returned as a string.
endrem 
Function DynamicInput$(Text$,X,Y)
	Return TInput.Text(Text$,X,Y)
EndFunction




Type TInput

	Global tempText$

	Function Text$(Text$,X,Y)
		
			Local aKeytoGet = GetChar()
			If aKeytoGet'Anykey was pressed
			
				If aKeytoGet = 13 'ENTER
					Text$ = tempText$
					If Text$ = "" Then Text = " "
					tempText$ = ""
					FlushKeys
					Return Text$
				Else If aKeytoGet = 8 Or aKeytoGet = 4 'AscII For Backspace And Delete
					If Len( tempText$ ) > 0 Then tempText$ = Left$( tempText$, Len(tempText$) -1 )	
				Else' If aKeytoGet>=32 And aKeytoGet<=122 And Len(Message)<52
					tempText$:+ Chr$(aKeytoGet)
				EndIf
	
			EndIf
			
			DrawText Text$ + tempText,X,Y
			Return ""

	EndFunction

EndType



'********************************************
' Object used to draw some text on the screen
'********************************************
Type Txt
	Field content$
	Field red%, green%, blue%
End Type



'**************************************************
' Function allowing to add some text to the txtList
'*************************************************
Function AddTxt(content$, red% = 255, green% = 255, blue% = 255, limit = 10)
	Local t:Txt = New Txt
	t.content = content
	t.red = red
	t.green = green
	t.blue = blue
	txtList.AddLast t
	If txtList.Count() > limit Then txtList.RemoveFirst()
End Function



'*******************************************
' Function to draw the txtList to the screen
'*******************************************
Function DrawTxt(x% = 20, y% = 20, yStep% = 20)
  SetScale 1,1
  SetRotation 0
	For Local t:Txt = EachIn txtList
		SetColor t.red, t.green, t.blue
		DrawText t.content, x, y
		y :+ yStep
	Next 
End Function



The raknet site claims bitstreams are much easier to cause issues, but I tested this example on a host 1000 miles away and tested sending probobly a hundred messages, all which arrived correctly. I believe they just meant that it's prone to make human error mistakes as it's more complicated to use, which can easily be worked around once you throw together a few functions to help yourself out.

Also, if anyone would like to improve or work on a new example using more of raknets features (There's so many!), i'de love to take part.

Cheers.

Retimer: Many thanks for your contribution! I will add the bitstreams to the wrapper, so that anybody can have it automatically. If you don't mind, I will also add your example in the package...

That's true that there is a lot of functions which were wrapped, but not put in the RakNet.bmx file or in the decls file, thanks for noticing this! You can find all the functions wrapped in the development version available on my website, in the file RakNet.cpp. For the curious people, here is this file:
/*'----------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- Raknet wrapper for BlitzMax. This wrapper was originally developped by Kurix for       -
'- Blitz3D, adapted to RakNet 3 and BlitzMax by RepeatUntil.                              -
'- This wrapper is open source, and could be modified by anyone who would like to         -
'- improve it. This is a project who should benefit the whole Blitz community, so please  -
'- send all improvements to repeatuntil@... (to upload on a web site).                -
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------*/


#include "Source/RakPeerInterface.h"
#include "Source/MessageIdentifiers.h"
#include "Source/RakNetworkFactory.h"
#include "Source/RakNetStatistics.h"
#include "Source/BitStream.h"
#include "Source/GetTime.h"
#include "Source/NatPunchthrough.h"

#define RN_API extern "C" __declspec(dllexport)

using namespace RakNet;



/*
RN_API void _stdcall RN_RakVoiceInit(RakVoice* rakVoice, bool sampleTypeIsShort, int speexSampleRate, int bufferSizeBytes)
{
	rakVoice->Init(sampleTypeIsShort, speexSampleRate, bufferSizeBytes);
}
*/


RN_API void _stdcall RN_RegisterAsRemoteProcedureCall(RakPeerInterface *rakPeerInterface, char* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) )
{
	rakPeerInterface->RegisterAsRemoteProcedureCall(uniqueID, functionPointer);
}

/*
RN_API bool _stdcall RN_RPC(RakPeerInterface *rakPeerInterface, char* uniqueID, char *data, int bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress playerId, bool broadcast, bool shiftTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget )
{
	rakPeerInterface->RPC(uniqueID, data, bitLength, PacketPriority(priority),PacketReliability(reliability),orderingChannel, playerId, broadcast, shiftTimestamp, networkID,replyFromTarget );
}
*/


/******************************************/
/* MISC FUNCTIONS */
/******************************************/
RN_API long _stdcall RN_GetUNASSIGNED_SYSTEM_ADDRESS()
{
	return long(&UNASSIGNED_SYSTEM_ADDRESS);
}

RN_API long _stdcall RN_GetUNASSIGNED_NETWORK_ID()
{
	return long(&UNASSIGNED_NETWORK_ID);
}

RN_API long _stdcall RN_GetTime()
{
	return GetTime();
}


/* INITIALIZE THE RAKNET PEER INTERFACE */
RN_API RakPeerInterface* _stdcall RN_GetRakPeerInterface()
{
	RakPeerInterface *rakPeerInterface;
	rakPeerInterface=RakNetworkFactory::GetRakPeerInterface();

	return rakPeerInterface;
}


/* DESTROY THE RAKNET PEER INTERFACE */
RN_API int _stdcall RN_DestroyRakPeerInterface(RakPeerInterface *rakPeerInterface)
{
if (rakPeerInterface)
	RakNetworkFactory::DestroyRakPeerInterface(rakPeerInterface);

return 0;
}


/******************/
/* PEER FUNCTIONS */
/******************/

// localPort = 0 -> client
// localPort > 0 -> server
RN_API bool _stdcall RN_Startup(RakPeerInterface *rakPeerInterface, int maxConnections, int _threadSleepTimer, int localPort)
{
	if (rakPeerInterface) {
       SocketDescriptor socketDescriptor(localPort,0); 
       return rakPeerInterface->Startup(maxConnections, _threadSleepTimer, &socketDescriptor, 1);
	} else
		return 0;
}


RN_API void _stdcall RN_InitializeSecurity(RakPeerInterface *rakPeerInterface, char *pubKeyE, char *pubKeyN, char *privKeyP, char *privKeyQ)
{
	rakPeerInterface->InitializeSecurity(pubKeyE, pubKeyN, privKeyP, privKeyQ);
}


RN_API void _stdcall RN_DisableSecurity(RakPeerInterface *rakPeerInterface)
{
	rakPeerInterface->DisableSecurity();
}


RN_API void _stdcall RN_SetMaximumIncomingConnections(RakPeerInterface *rakPeerInterface, int numberAllowed) 
{
	rakPeerInterface->SetMaximumIncomingConnections(numberAllowed);
}


RN_API int _stdcall RN_GetMaximumIncomingConnections(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->GetMaximumIncomingConnections();
}


RN_API void _stdcall RN_SetIncomingPassword(RakPeerInterface *rakPeerInterface, char* passwordData, int passwordDataLength)
{
	rakPeerInterface->SetIncomingPassword(passwordData, passwordDataLength);
}


RN_API void _stdcall RN_GetIncomingPassword(RakPeerInterface *rakPeerInterface, char* passwordData, int *passwordDataLength)
{
	rakPeerInterface->GetIncomingPassword(passwordData, passwordDataLength);
}


RN_API bool _stdcall RN_Connect(RakPeerInterface *rakPeerInterface, char* host, int remotePort, char* passwordData, int passwordDataLength)
{
	return rakPeerInterface->Connect(host, remotePort, passwordData, passwordDataLength);
}


RN_API void _stdcall RN_Shutdown(RakPeerInterface *rakPeerInterface, int blockDuration)
{
	rakPeerInterface->Shutdown(blockDuration);
}


RN_API void _stdcall RN_SetTimeoutTime(RakPeerInterface *rakPeerInterface, int timeMS, SystemAddress target)
{
	rakPeerInterface->SetTimeoutTime(timeMS, target);
}


RN_API bool _stdcall RN_IsActive(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->IsActive();
}


RN_API bool _stdcall RN_GetConnectionList(RakPeerInterface *rakPeerInterface, SystemAddress *remoteSystems, unsigned short *numberOfSystems) 
{
	return rakPeerInterface->GetConnectionList(remoteSystems, numberOfSystems);
}


RN_API bool _stdcall RN_Send(RakPeerInterface *rakPeerInterface,char *data,long length,int priority,int reliability,int orderingChannel,SystemAddress *playerID,bool broadcast)
{
return rakPeerInterface->Send(data,length,PacketPriority(priority),PacketReliability(reliability),orderingChannel,*playerID,broadcast);
}


RN_API bool _stdcall RN_SendBitStream(RakPeerInterface *rakPeerInterface,RakNet::BitStream *bitStream,int priority,int reliability,int orderingChannel,SystemAddress *playerID,bool broadcast)
{
	return rakPeerInterface->Send(bitStream,PacketPriority(priority),PacketReliability(reliability),orderingChannel,*playerID,broadcast);
}


RN_API Packet* _stdcall RN_Receive(RakPeerInterface *rakPeerInterface)
{
     return rakPeerInterface->Receive();
}


RN_API bool _stdcall RN_DeallocatePacket(RakPeerInterface *rakPeerInterface,Packet *packet)
{
	// FREE PACKET IF EXISTS
	if (packet) 
		rakPeerInterface->DeallocatePacket(packet);
	return 0;
}


RN_API int _stdcall RN_GetMaximumNumberOfPeers(RakPeerInterface *rakPeerInterface) 
{
	return rakPeerInterface->GetMaximumNumberOfPeers();
}


RN_API void _stdcall RN_CloseConnection(RakPeerInterface *rakPeerInterface, SystemAddress target, bool sendDisconnectionNotification)
{
	rakPeerInterface->CloseConnection(target, sendDisconnectionNotification);
}


RN_API SystemAddress * _stdcall RN_GetInternalID(RakPeerInterface *rakPeerInterface) 
{
	return &rakPeerInterface->GetInternalID();
}


RN_API SystemAddress * _stdcall RN_GetExternalID(RakPeerInterface *rakPeerInterface, SystemAddress target) 
{
	return &rakPeerInterface->GetExternalID(target);
}


RN_API void _stdcall RN_PushBackPacket(RakPeerInterface *rakPeerInterface,Packet *packet,bool pushAtHead)
{
	rakPeerInterface->PushBackPacket(packet,pushAtHead);
}


RN_API void _stdcall RN_ApplyNetworkSimulator(RakPeerInterface *rakPeerInterface,double maxSendBPS, int minExtraPing, int extraPingVariance) 
{
	rakPeerInterface->ApplyNetworkSimulator(maxSendBPS, minExtraPing, extraPingVariance);
}


RN_API bool _stdcall RN_IsNetworkSimulatorActive(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->IsNetworkSimulatorActive();
}


RN_API void _stdcall RN_PingPlayer(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	rakPeerInterface->Ping(*playerID);
}


RN_API void _stdcall RN_PingHost(RakPeerInterface *rakPeerInterface, char* host, int remotePort, bool onlyReplyOnAcceptingConnections)
{
	rakPeerInterface->Ping(host, remotePort, onlyReplyOnAcceptingConnections);
}


RN_API int _stdcall RN_GetAveragePing(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetAveragePing(*playerID);
}


RN_API int _stdcall RN_GetLastPing(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetLastPing(*playerID);
}


RN_API int _stdcall RN_GetLowestPing(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetLowestPing(*playerID);
}


RN_API void _stdcall RN_SetOccasionalPing(RakPeerInterface *rakPeerInterface, bool doPing)
{
	rakPeerInterface->SetOccasionalPing(doPing);
}


RN_API void _stdcall RN_SetOfflinePingResponse(RakPeerInterface *rakPeerInterface,char *data,int length)
{
	rakPeerInterface->SetOfflinePingResponse(data,length);
}


RN_API int _stdcall RN_GetNumberOfAddresses(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->GetNumberOfAddresses();
}


RN_API const char * _stdcall RN_GetLocalIP(RakPeerInterface *rakPeerInterface,int index)
{
	return rakPeerInterface->GetLocalIP(index);
}

RN_API int _stdcall RN_GetIndexFromSystemAddress(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetIndexFromSystemAddress(*playerID);
}


RN_API SystemAddress _stdcall RN_GetSystemAddressFromIndex(RakPeerInterface *rakPeerInterface,int index)
{
	return rakPeerInterface->GetSystemAddressFromIndex(index);
}


RN_API void _stdcall RN_AddToBanList(RakPeerInterface *rakPeerInterface,char *ip, int milliseconds)
{
	rakPeerInterface->AddToBanList(ip, milliseconds);
}


RN_API void _stdcall RN_RemoveFromBanList(RakPeerInterface *rakPeerInterface,char *ip)
{
	rakPeerInterface->RemoveFromBanList(ip);
}


RN_API void _stdcall RN_ClearBanList(RakPeerInterface *rakPeerInterface)
{
	rakPeerInterface->ClearBanList();
}


RN_API bool _stdcall RN_IsBanned(RakPeerInterface *rakPeerInterface,char *ip)
{
	return rakPeerInterface->IsBanned(ip);
}


RN_API int _stdcall RN_SetMTUSize(RakPeerInterface *rakPeerInterface,int size)
{
	return rakPeerInterface->SetMTUSize(size);
}


RN_API int _stdcall RN_GetMTUSize(RakPeerInterface *rakPeerInterface, SystemAddress target)
{
	return rakPeerInterface->GetMTUSize(target);
}


RN_API void _stdcall RN_AllowConnectionResponseIPMigration(RakPeerInterface *rakPeerInterface,bool allow)
{
	rakPeerInterface->AllowConnectionResponseIPMigration(allow);
}


RN_API void _stdcall RN_AdvertiseSystem(RakPeerInterface *rakPeerInterface,char *host,int remotePort, char *data, int dataLength)
{
	rakPeerInterface->AdvertiseSystem(host,remotePort,data,dataLength);
}


/*
RN_API PluginInterface* _stdcall RN_AttachPluginRakVoice(RakPeerInterface *rakPeerInterface)
{
	RakVoice rakVoice;
	rakPeerInterface->AttachPlugin(&rakVoice);
	return &rakVoice;
}
*/


RN_API void _stdcall RN_DetachPlugin(RakPeerInterface *rakPeerInterface, PluginInterface *messageHandler)
{
	rakPeerInterface->DetachPlugin(messageHandler);
}


RN_API RakNetStatistics * _stdcall RN_ServerGetStatistics(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetStatistics(*playerID);
}


/********************************************/
/* PACKET ACCESS */
/********************************************/
RN_API unsigned char * _stdcall RN_PacketGetData(Packet *packet)
{
	return (unsigned char *)packet->data;
}

RN_API int _stdcall RN_PacketGetBitSize(Packet *packet)
{
	return packet->bitSize;
}

RN_API SystemAddress * _stdcall RN_PacketGetSystemAddress(Packet *packet)
{
	return &packet->systemAddress;
}

RN_API int _stdcall RN_PacketGetplayerIndex(Packet *packet)
{
	return packet->systemIndex;
}

RN_API int _stdcall RN_PacketGetBinaryAddress(Packet *packet)
{
	return packet->systemAddress.binaryAddress;
}


RN_API int _stdcall RN_PacketGetPort(Packet *packet)
{
	return packet->systemAddress.port;
}

RN_API int _stdcall RN_SystemAddressGetBinaryAddress(SystemAddress *systemAddress)
{
	return systemAddress->binaryAddress;
}

RN_API int _stdcall RN_SystemAddressGetPort(SystemAddress *systemAddress)
{
	return systemAddress->port;
}
/********************************************/
/* BISTREAM FUNCTIONS
/********************************************/
RN_API BitStream * _stdcall RN_BitStreamCreate1(int initialBytesToAllocate)
{
	BitStream *b = new BitStream(initialBytesToAllocate);
	return b;
}

RN_API BitStream * _stdcall RN_BitStreamCreate2(unsigned char *data,int length,bool copydata)
{
	BitStream *b = new BitStream(data,length,copydata);
	return b;
}

RN_API void _stdcall RN_BitStreamReset(BitStream *bitstream)
{
	bitstream->Reset();
}

RN_API void _stdcall RN_BitStreamDestroy(BitStream *bitstream)
{
	delete bitstream;
}

RN_API BitStream * _stdcall RN_BitStreamCreateFromPacket(Packet *packet)
{	
	BitStream *b = new BitStream((unsigned char*)packet->data,packet->length,0);
	return b;
}

// WRITE
RN_API void _stdcall RN_BitStreamWriteBool(BitStream *bitstream,bool input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedChar(BitStream *bitstream,unsigned char input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteChar(BitStream *bitstream,char input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedShort(BitStream *bitstream,unsigned short input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteShort(BitStream *bitstream,short input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedInt(BitStream *bitstream,unsigned int input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteInt(BitStream *bitstream,int input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedLong(BitStream *bitstream,unsigned long input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteLong(BitStream *bitstream,long input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteFloat(BitStream *bitstream,float input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteDouble(BitStream *bitstream,double input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWrite(BitStream *bitstream,char *input,int numberOfBytes)
{
	bitstream->Write(input,numberOfBytes);
}

// WriteCompressedCOMPRESSED
RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedChar(BitStream *bitstream,unsigned char input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedChar(BitStream *bitstream,char input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedShort(BitStream *bitstream,unsigned short input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedShort(BitStream *bitstream,short input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedInt(BitStream *bitstream,unsigned int input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedInt(BitStream *bitstream,int input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedLong(BitStream *bitstream,unsigned long input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedLong(BitStream *bitstream,long input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedFloat(BitStream *bitstream,float input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedDouble(BitStream *bitstream,double input)
{
	bitstream->WriteCompressed(input);
}

// Read
RN_API bool _stdcall RN_BitStreamReadBool(BitStream *bitstream)
{
	bool input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadUnsignedChar(BitStream *bitstream)
{
	unsigned char input=0;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadChar(BitStream *bitstream)
{
	char input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadUnsignedShort(BitStream *bitstream)
{
	unsigned short input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadShort(BitStream *bitstream)
{
	short input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadUnsignedInt(BitStream *bitstream)
{
	unsigned int input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadInt(BitStream *bitstream)
{
	int input;
	bitstream->Read(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadUnsignedLong(BitStream *bitstream)
{
	unsigned long input;
	bitstream->Read(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadLong(BitStream *bitstream)
{
	long input;
	bitstream->Read(input);
	return input;
}

RN_API float _stdcall RN_BitStreamReadFloat(BitStream *bitstream)
{
	float input;
	bitstream->Read(input);
	return input;
}

RN_API double _stdcall RN_BitStreamReadDouble(BitStream *bitstream)
{
	double input;
	bitstream->Read(input);
	return input;
}

RN_API char * _stdcall RN_BitStreamRead(BitStream *bitstream,int numberOfBytes)
{
	char *input = new char[numberOfBytes];
	bitstream->Read(input,numberOfBytes);
	return input;		
}

// ReadCompressed COMPRESSED
RN_API int _stdcall RN_BitStreamReadCompressedUnsignedChar(BitStream *bitstream)
{
	unsigned char input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedChar(BitStream *bitstream)
{
	char input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedUnsignedShort(BitStream *bitstream)
{
	unsigned short input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedShort(BitStream *bitstream)
{
	short input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedUnsignedInt(BitStream *bitstream)
{
	unsigned int input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedInt(BitStream *bitstream)
{
	int input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadCompressedUnsignedLong(BitStream *bitstream)
{
	unsigned long input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadCompressedLong(BitStream *bitstream)
{
	long input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API float _stdcall RN_BitStreamReadCompressedFloat(BitStream *bitstream)
{
	float input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API double _stdcall RN_BitStreamReadCompressedDouble(BitStream *bitstream)
{
	double input;
	bitstream->ReadCompressed(input);
	return input;
}

// MISC
RN_API void _stdcall RN_BitStreamResetReadPointer(BitStream *bitstream)
{
	bitstream->ResetReadPointer();
}

RN_API void _stdcall RN_BitStreamAssertStreamEmpty(BitStream *bitstream)
{
	bitstream->AssertStreamEmpty();
}

RN_API void _stdcall RN_BitStreamPrintBits(BitStream *bitstream)
{
	bitstream->PrintBits();
}

RN_API void _stdcall RN_BitStreamIgnoreBits(BitStream *bitstream,int numberOfBits)
{
	bitstream->IgnoreBits(numberOfBits);
}

RN_API void _stdcall RN_BitStreamSetWriteOffset(BitStream *bitstream,int offset)
{
	bitstream->SetWriteOffset(offset);
}

RN_API int _stdcall RN_BitStreamGetNumberOfBitsUsed(BitStream *bitstream)
{
	return bitstream->GetNumberOfBitsUsed();
}

RN_API int _stdcall RN_BitStreamGetNumberOfBytesUsed(BitStream *bitstream)
{
	return bitstream->GetNumberOfBytesUsed();
}

RN_API int _stdcall RN_BitStreamGetReadOffset(BitStream *bitstream)
{
	return bitstream->GetReadOffset();
}

RN_API int _stdcall RN_BitStreamGetNumberOfUnreadBits(BitStream *bitstream)
{
	return bitstream->GetNumberOfUnreadBits();
}

//RN_API int _stdcall RN_BitStreamCopyData(BitStream *bitstream,char **data)
//{
//	return bitstream->CopyData(data);
//}

RN_API void _stdcall RN_BitStreamSetData(BitStream *bitstream,unsigned char *data)
{
	bitstream->SetData(data);
}

RN_API unsigned char * _stdcall RN_BitStreamGetData(BitStream *bitstream)
{
	return bitstream->GetData();
}

RN_API unsigned char * _stdcall RN_BitStreamGetDataPointer(BitStream *bitstream)
{
	return bitstream->GetData();
}

RN_API void _stdcall RN_BitStreamWriteBits(BitStream *bitstream,unsigned char *input, int numberOfBitsToWrite, bool rightAlignedBits)
{
	bitstream->WriteBits(input,numberOfBitsToWrite,rightAlignedBits);
}

RN_API void _stdcall RN_BitStreamWriteAlignedBytes(BitStream *bitstream,unsigned char *input, int numberOfBytesToWrite)
{
	bitstream->WriteAlignedBytes(input,numberOfBytesToWrite);
}

RN_API unsigned char * _stdcall RN_BitStreamReadAlignedBytes(BitStream *bitstream, int numberOfBytesToRead)
{
	unsigned char * input = new unsigned char[numberOfBytesToRead];
	bitstream->ReadAlignedBytes(input,numberOfBytesToRead);
	return input;
}

RN_API void _stdcall RN_BitStreamAlignWriteToByteBoundary(BitStream *bitstream)
{
	bitstream->AlignWriteToByteBoundary();
}

RN_API void _stdcall RN_BitStreamAlignReadToByteBoundary(BitStream *bitstream)
{
	bitstream->AlignReadToByteBoundary();
}

RN_API unsigned char * _stdcall RN_BitStreamReadBits(BitStream *bitstream,int numberOfBitsToRead, bool alignBitsToRight)
{
	unsigned char *output = new unsigned char[numberOfBitsToRead];
	bitstream->ReadBits(output,numberOfBitsToRead,alignBitsToRight);
	return output;
}

RN_API void _stdcall RN_BitStreamWrite0(BitStream *bitstream)
{
	bitstream->Write0();
}

RN_API void _stdcall RN_BitStreamWrite1(BitStream *bitstream)
{
	bitstream->Write1();
}

RN_API bool _stdcall RN_BitStreamReadBit(BitStream *bitstream)
{
	return bitstream->ReadBit();
}

RN_API void _stdcall RN_BitStreamAssertCopyData(BitStream *bitstream)
{
	bitstream->AssertCopyData();
}

RN_API void _stdcall RN_BitStreamSetNumberOfBitsAllocated(BitStream *bitstream,unsigned int lengthInBits)
{
	bitstream->SetNumberOfBitsAllocated(lengthInBits );
}

/* PRIVATE 
RN_API void _stdcall RN_BitStreamWriteCompressed(BitStream *bitstream,unsigned char *input,int size, bool unsignedData)
{
	bitstream->WriteCompressed(input,size,unsignedData);
}
RN_API unsigned char * void _stdcall RN_BitStreamReadCompressed(BitStream *bitstream,int size, bool unsignedData)
{
	unsigned char *input = new unsigned char[size];
	bitstream->ReadCompressed(input,size,unsignedData);
	return input;
}
*/

/**************************************/
/* STATISTICS STRUCT ACCESS */
/**************************************/
RN_API int _stdcall RN_StatisticsGetmessageSendBuffer(RakNetStatistics *stat,int queue)
{
	return stat->messageSendBuffer[queue];
}

RN_API int _stdcall RN_StatisticsGetmessagesSent(RakNetStatistics *stat,int queue)
{
	return stat->messagesSent[queue];
}

RN_API int _stdcall RN_StatisticsGetmessageDataBitsSent(RakNetStatistics *stat,int queue)
{
	return stat->messageDataBitsSent[queue];
}

RN_API int _stdcall RN_StatisticsGetmessageTotalBitsSent(RakNetStatistics *stat,int queue)
{
	return stat->messageTotalBitsSent[queue];
}

RN_API int _stdcall RN_StatisticsGetpacketsContainingOnlyAcknowlegements(RakNetStatistics *stat)
{
	return stat->packetsContainingOnlyAcknowlegements;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementsSent(RakNetStatistics *stat)
{
	return stat->acknowlegementsSent;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementsPending(RakNetStatistics *stat)
{
	return stat->acknowlegementsPending;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementBitsSent(RakNetStatistics *stat)
{
	return stat->acknowlegementBitsSent;
}

RN_API int _stdcall RN_StatisticsGetpacketsContainingOnlyAcknowlegementsAndResends(RakNetStatistics *stat)
{
	return stat->packetsContainingOnlyAcknowlegementsAndResends;
}

RN_API int _stdcall RN_StatisticsGetmessageResends(RakNetStatistics *stat)
{
	return stat->messageResends;
}

RN_API int _stdcall RN_StatisticsGetmessageDataBitsResent(RakNetStatistics *stat)
{
	return stat->messageDataBitsResent;
}

RN_API int _stdcall RN_StatisticsGetmessagesTotalBitsResent(RakNetStatistics *stat)
{
	return stat->messagesTotalBitsResent;
}

RN_API int _stdcall RN_StatisticsGetmessagesOnResendQueue(RakNetStatistics *stat)
{
	return stat->messagesOnResendQueue;
}

RN_API int _stdcall RN_StatisticsGetnumberOfUnsplitMessages(RakNetStatistics *stat)
{
	return stat->numberOfUnsplitMessages;
}

RN_API int _stdcall RN_StatisticsGetnumberOfSplitMessages(RakNetStatistics *stat)
{
	return stat->numberOfSplitMessages;
}

RN_API int _stdcall RN_StatisticsGettotalSplits(RakNetStatistics *stat)
{
	return stat->totalSplits;
}

RN_API int _stdcall RN_StatisticsGetPacketsSent(RakNetStatistics *stat)
{
	return stat->packetsSent;
}

RN_API int _stdcall RN_StatisticsGetencryptionBitsSent(RakNetStatistics *stat)
{
	return stat->encryptionBitsSent;
}

RN_API int _stdcall RN_StatisticsGetTotalBitsSent(RakNetStatistics *stat)
{
	return stat->totalBitsSent;
}

RN_API int _stdcall RN_StatisticsGetsequencedMessagesOutOfOrder(RakNetStatistics *stat)
{
	return stat->sequencedMessagesOutOfOrder;
}

RN_API int _stdcall RN_StatisticsGetsequencedMessagesInOrder(RakNetStatistics *stat)
{
	return stat->sequencedMessagesInOrder;
}

RN_API int _stdcall RN_StatisticsGetorderedMessagesOutOfOrder(RakNetStatistics *stat)
{
	return stat->orderedMessagesOutOfOrder;
}

RN_API int _stdcall RN_StatisticsGetorderedMessagesInOrder(RakNetStatistics *stat)
{
	return stat->orderedMessagesInOrder;
}

RN_API int _stdcall RN_StatisticsGetPacketsReceived(RakNetStatistics *stat)
{
	return stat->packetsReceived;
}

//RN_API int _stdcall RN_StatisticsGetpacketsWithBadCRCRecieved(RakNetStatistics *stat)
//{
//	return stat->packetsWithBadCRCRecieved;
//}

RN_API int _stdcall RN_StatisticsGetBitsReceived(RakNetStatistics *stat)
{
	return stat->bitsReceived;
}

RN_API int _stdcall RN_StatisticsGetbitsWithBadCRCReceived(RakNetStatistics *stat)
{
	return stat->bitsWithBadCRCReceived;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementsReceived(RakNetStatistics *stat)
{
	return stat->acknowlegementsReceived;
}

RN_API int _stdcall RN_StatisticsGetduplicateAcknowlegementsReceived(RakNetStatistics *stat)
{
	return stat->duplicateAcknowlegementsReceived;
}

RN_API int _stdcall RN_StatisticsGetmessagesReceived(RakNetStatistics *stat)
{
	return stat->messagesReceived;
}

RN_API int _stdcall RN_StatisticsGetinvalidMessagesReceived(RakNetStatistics *stat)
{
	return stat->invalidMessagesReceived;
}

RN_API int _stdcall RN_StatisticsGetduplicateMessagesReceived(RakNetStatistics *stat)
{
	return stat->duplicateMessagesReceived;
}

RN_API int _stdcall RN_StatisticsGetmessagesWaitingForReassembly(RakNetStatistics *stat)
{
	return stat->messagesWaitingForReassembly;
}

RN_API int _stdcall RN_StatisticsGetinternalOutputQueueSize(RakNetStatistics *stat)
{
	return stat->internalOutputQueueSize;
}

// Not any more present in RN 2.52
//RN_API int _stdcall RN_StatisticsGetwindowSize(RakNetStatistics *stat)
//{
//	return stat->windowSize;
//}

/*RN_API int _stdcall RN_StatisticsGetlossySize(RakNetStatistics *stat)
{
	return stat->lossySize;
}*/

RN_API int _stdcall RN_StatisticsGetconnectionStartTime(RakNetStatistics *stat)
{
	return stat->connectionStartTime;
}




Retimer: Many thanks for your contribution! I will add the bitstreams to the wrapper, so that anybody can have it automatically. If you don't mind, I will also add your example in the package...



Not a problem, and please do. I'll probobly be improving that example (I think there's better methods) or coming out with new ones as I progress with RakNet..it's a learning experience. I'm also working on a new type structure for making work with most RakNet functions easier than working with blitzmax' socket streams. I'll throw it in a codebox once i'm done.

I really do appreciate your contribution of this wrapper though. TCP has been boring me for a while now =P.


I really do appreciate your contribution of this wrapper though.


Happy to see it is useful! Note that 90% of the work was done by Kurix, who wrapped a previous version of RakNet. I just adapted his wrapper to the new version of RakNet (v3) (although that was not so easy due to a lot of changes).

This wrapper is in the community domain (I have no time now to program anymore - and I even don't use the wrapper myself!), and it's not at all my property. Any contribution is more than welcome. Even the wrapper could be extended if needed. For example, you have a voice communication plugin with RakNet, I don't know if this is possible to wrap, but that would be really cool!!
Anyway, I will try to maintain an up-to-date version of the wrapper on my web page. So thanks for these improvements!

-edited.

Will post a better version later.

I'm getting an error :(

Compile Error
Identifier 'CompressedPackets' not found

. (removed)

Repeat, can you please check something.

I don't believe RN_GetSystemAddressFromIndex is working properly. I have tried many routes trying to send data to specific players (non-broadcast) and have never got it to work properly. When broadcasting everything works flawlessly, but to specific players I either get nothing, or a message every once and a while (using different methods other than the one below)

Could you check it out?

Example: (uses maxgui)

Strict

Include "RakNet.bmx"

Global peer = 0
Global serverPort = 61019
Global packet = 0
Global isServer
Global stat = 0

Global systemAddressServer = 0
Global systemAddressClient1 = 0
Global systemAddressClient2 = 0

Const ID_KEY_F1 = 100
Const ID_CHAT = 101


Global nbPlayerMax = 320

Global MainWindow:TGadget = CreateWindow("Chat Test",100,100,700,500,,Window_Clientcoords|window_titlebar)
Global TextWindow:TGadget = CreateTextArea(0,0,500,480,MainWindow)
Global TextField:TGadget = CreateTextField(0,480,500,20,MainWindow)
Global LstPlayers:TGadget = CreateListBox(500,0,200,480,MainWindow)
Global CmdSend:tgadget = CreateButton("Send",500,480,200,20,MainWindow)

peer = RN_GetRakPeerInterface() 


Local Starter:Byte = Proceed("Act as server?")
If Starter = 1 Then
	isServer = True
	RN_Startup(peer, nbPlayerMax, 0, serverPort)
	RN_SetMaximumIncomingConnections(peer,nbPlayerMax)
	SetGadgetText(MainWindow,"ACTING AS SERVER")
ElseIf Starter = 0 Then
	AddGadgetItem(LstPlayers,"To All Players")
	isServer = False
	RN_Startup(peer,1,0,0)   ' 1 player allowed to connect -> client
	RN_Connect(peer, "127.0.0.1", serverPort, "", 0) ;
	SetGadgetText(MainWindow,"ACTING AS CLIENT")
Else
	End
EndIf

CreateTimer 60

While (Not KeyHit(KEY_ESCAPE))
	packet = RN_Receive(peer)


	If (packet) Then
		Local msg$ = RN_PacketGetData(packet)
		Local msgType = Asc(msg[0..1])

				
		Local systemAddress = RN_PacketGetSystemAddress(packet)

				
		Select msgType
			Case ID_CONNECTION_REQUEST_ACCEPTED
				systemAddressServer = RN_PacketGetSystemAddress(packet)
			Case ID_NEW_INCOMING_CONNECTION
				AddGadgetItem(LstPlayers,"To Client #" + ServerConnectionCount())
			Case ID_CHAT
				Local EditMsg:String
				 
				If isServer
					EditMsg = msg[0..1] + "Client #" + RN_PacketGetplayerIndex(Packet) + ":" + msg[1..]
				Else
					EditMsg = msg
				End If
				
 				SetGadgetText(TextWindow,EditMsg[1..]+"~n"+GadgetText(TextWindow))
				
				If (isServer) Then
					RN_Send(peer,EditMsg,Len(EditMsg)+1,HIGH_PRIORITY,RELIABLE_ORDERED,0,UNASSIGNED_SYSTEM_ADDRESS,True);
				EndIf
		End Select


		packet = RN_DeallocatePacket(peer, packet)

	EndIf

	WaitEvent()
	Select EventID()
		Case event_windowclose
			RN_CloseConnection(peer,RN_GetSystemAddressFromIndex(peer, 0), True)
			RN_Shutdown(peer, 100)
			peer = RN_DestroyRakPeerInterface(peer)
			End
		Case event_gadgetaction
			If EventSource() = cmdSend
				If isServer
					Local MyMsg:String = Chr(ID_Chat) + "From Server: " + GadgetText(TextField)
   					If SelectedGadgetItem(lstPlayers) >= 0
						RN_Send(peer, MyMsg,Len(MyMsg)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RN_GetSystemAddressFromIndex(peer,SelectedGadgetItem(lstPlayers)), False)
					Else
						Notify "Select a player to send a message to"
					End If

				Else
					Local MyMsg:String = Chr(ID_Chat) + GadgetText(TextField)
					RN_Send(peer, MyMsg,Len(MyMsg)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, True)
				End If
			End If
	End Select


Wend



Function ServerConnectionCount%()
	Local count = 0
	For Local i = 0 To nbPlayerMax
		If RN_GetSystemAddressFromIndex(peer, i) <> -1  count = count + 1
	Next
	Return count
End Function




Run 1 server, and 2-3 clients. As the server, select a client from the player list to send a message to. I'm getting nothing =(

ps. you need to click send to send the message, enter doesn't work.

OK, I have added the functions added by Retimer for the bitstreams. I have also added his example about bitstreams.
Also, Paco gave me an example for the Blitz3D version.
Thanks to these 2 contributors!

Download again (see my sig) to get the updated version.

Retimer: you deleted some nice package from your previous posts. When you feel they are good enough, don't hesitate to send it to me so that I can add it also in the package...

Retimer (bis): for your question -> I can not test your example because I have not maxGUI. Anyway, I tried to modify something in the wrapper (I am always confusing & and * in C++, what a shame!). I do not promise it will work, but please give it a try... The dll is updated with this "fix", please download it again...

Thanks!

I temporarily removed the framework because of this bug (If it is infact a bug).Unfortunately I don't think the issue was fixed in this update. I really wish I could help, but it's probobly beyond me.

RN_GetSystemAddressFromIndex still seems to be returning the same address, no matter which client I am trying to send data to. I'll try to come up with a simple non-maxgui example with comments to show you within the next day.

A bit of extra info:

RN_GetSystemAddressFromIndex(peer,RN_PacketGetplayerIndex(Packet))
RN_PacketGetSystemAddress(packet)

both seem to return different values, but those values never change no matter which client is sending data to the server, so it seems impossible to determine the address of specific clients.

Function ServerConnectionCount%()
	Local count = 0
	For Local i = 0 To nbPlayerMax
	If RN_GetSystemAddressFromIndex(peer, i) <> -1  count = count + 1
	Next
	Return count
End Function


in fact, that's always returning as positive in the new dll.

Example showing that packets recieved from different clients returns the same address:

'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- Raknet wrapper for BlitzMax. This wrapper was originally developped by Kurix for       -
'- Blitz3D, adapted to RakNet 3 and BlitzMax by RepeatUntil.                              -
'- This wrapper is open source, and could be modified by anyone who would like to         -
'- improve it. This is a project who should benefit the whole Blitz community, so please  -
'- send all improvements to repeatuntil@... (to upload on a web site).                -
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------


Strict

Include "RakNet.bmx"


Global txtList:TList = New TList


Global peer = 0
Global serverPort = 61019
Global packet = 0
Global isServer
Global stat = 0

Global systemAddressServer = 0
Global systemAddressClient1 = 0
Global systemAddressClient2 = 0

Const ID_CHAT = 101


Const nbPlayerMax:Int = 32

'SetGraphicsDriver GLMax2DDriver()
 
Graphics 800, 600, 0

Local str$ = InputText("(S)erver or (C)lient?  ", 0, 0);

peer = RN_GetRakPeerInterface()

If Upper(str$) = "S" Then
	isServer = True
	Local ok = RN_Startup(peer, nbPlayerMax, 0, serverPort)
	RN_SetMaximumIncomingConnections(peer,nbPlayerMax)
	
	If ok Then 
		AddTxt "Server correctly started"
	Else
		AddTxt "Problem when starting the server!"
	EndIf	
Else
	isServer = False
	str$ = "" 'InputText("Enter server IP Or hit enter For 127.0.0.1:  ", 0, 0);
	If Trim(str) = "" Then str = "127.0.0.1"
	RN_Startup(peer,1,0,0)   ' 1 player allowed to connect -> client
	Local ok = RN_Connect(peer,str, serverPort, "", 0);
	If ok Then 
		AddTxt "Client correctly started"
	Else
		AddTxt "Problem when starting the client!"
	EndIf
EndIf



While (Not KeyHit(KEY_ESCAPE))
	Local chatMsg$ = DynamicInput("Enter chat here : ", 20, GraphicsHeight()*0.9)
	If Trim(chatMsg) <> "" Then
		chatMsg = Chr(ID_CHAT) + chatMsg
		Local ok = RN_Send(peer, chatMsg$, Len(chatMsg$) + 1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, True)
	EndIf


	packet = RN_Receive(peer)


	If (packet) Then
		Local msg$ = RN_PacketGetData(packet)
		Local msgType = Asc(msg[0..1])

				
		Local systemAddress = RN_PacketGetSystemAddress(packet)
		If isServer Then addtxt("Packet Recv'd - Index:"+rn_packetgetplayerindex(packet) + ", Address:"+systemAddress )
				
		Select msgType
			Case ID_REMOTE_DISCONNECTION_NOTIFICATION
				AddTxt("Another client has disconnected.")
			Case ID_REMOTE_CONNECTION_LOST
				AddTxt("Another client has lost the connection.")
			Case ID_REMOTE_NEW_INCOMING_CONNECTION
				AddTxt("Another client has connected.")
			Case ID_CONNECTION_REQUEST_ACCEPTED
				systemAddressServer = RN_PacketGetSystemAddress(packet)
				AddTxt("Our connection request has been accepted.")
				'AddTxt("extern = " + RN_GetExternalID(peer,systemAddressServer))
			Case ID_NEW_INCOMING_CONNECTION
				If Not systemAddressClient1 Then
					systemAddressClient1 = RN_PacketGetSystemAddress(packet)
					stat = RN_ServerGetStatistics(peer,systemAddressClient1)
				Else
					systemAddressClient2 = RN_PacketGetSystemAddress(packet)
				EndIf
				addtxt("New Connection - Index:"+rn_packetgetplayerindex(packet) + ", Address:"+RN_PacketGetSystemAddress(packet))
			Case ID_NO_FREE_INCOMING_CONNECTIONS
				AddTxt("The server is full.")
			Case ID_DISCONNECTION_NOTIFICATION
				If (isServer)
					AddTxt("A client has disconnected.")
				Else
					AddTxt("We have been disconnected.")
				EndIf
			Case ID_CONNECTION_LOST
				If (isServer)
					AddTxt("A client lost the connection.")
				Else
					AddTxt("Connection lost.")
				EndIf
			Case ID_CHAT
				AddTxt "Chat Message: " + msg[1..]
				' The server relays this message to other clients
				' Ideally, we need to add RN_PacketGetSystemAddress(packet) to the message so that the client knows who is the original sender
				If (isServer) Then
					RN_Send(peer,msg$,Len(msg)+1,HIGH_PRIORITY,RELIABLE_ORDERED,0,RN_PacketGetSystemAddress(packet),True);
				EndIf
			Default
				AddTxt("Message with identifier " + msgType + " has arrived.")

		End Select


		packet = RN_DeallocatePacket(peer, packet)

	EndIf

	DrawText(ServerConnectionCount() + " people connected", 20, GraphicsHeight()*0.55)
	If (isServer) Then
		If (systemAddressClient1)  DrawText("Ping: " + RN_GetAveragePing(peer, systemAddressClient1) + "/" + RN_GetLowestPing(peer,systemAddressClient1) + "/" + RN_GetLastPing(peer,systemAddressClient1), 20, GraphicsHeight()*0.6)
		If (stat) Then
			DrawText("stat = " + RN_StatisticsGetTotalBitsSent(stat) + "/" + RN_StatisticsGetPacketsReceived(stat), 20, GraphicsHeight()*0.65)
		EndIf
	EndIf

	DrawTxt()
	Flip
	
	Delay 1
	
	Cls
Wend

RN_CloseConnection(peer,RN_GetSystemAddressFromIndex(peer, 0), True)
RN_Shutdown(peer, 100)
peer = RN_DestroyRakPeerInterface(peer)




Function ServerConnectionCount%()
	Local count = 0
	For Local i = 0 To nbPlayerMax-1
		If RN_GetSystemAddressFromIndex(peer, i) <> -1  count = count + 1
	Next
	Return count
End Function





'-------------- NOT RELATED TO RAKNET - JUST USEFUL STUFF --------------------


Rem 
bbdoc: InputText works just as a normal input but in graphicsmode. It waits for you to press enter then returns a string.
EndRem 
Function InputText$(Text$,X,Y)
Local Inp$
	Repeat
		Inp = TInput.Text(Text$,X,Y)
		Flip;Cls
	Until Inp <> ""
Return Inp
EndFunction

Rem 
bbdoc: InputText works just as a normal Textinput but it does NOT stop the program! Returns "" until ENTER is pressed then the message you have written is returned as a string.
endrem 
Function DynamicInput$(Text$,X,Y)
	Return TInput.Text(Text$,X,Y)
EndFunction




Type TInput

	Global tempText$

	Function Text$(Text$,X,Y)
		
			Local aKeytoGet = GetChar()
			If aKeytoGet'Anykey was pressed
			
				If aKeytoGet = 13 'ENTER
					Text$ = tempText$
					If Text$ = "" Then Text = " "
					tempText$ = ""
					FlushKeys
					Return Text$
				Else If aKeytoGet = 8 Or aKeytoGet = 4 'AscII For Backspace And Delete
					If Len( tempText$ ) > 0 Then tempText$ = Left$( tempText$, Len(tempText$) -1 )	
				Else' If aKeytoGet>=32 And aKeytoGet<=122 And Len(Message)<52
					tempText$:+ Chr$(aKeytoGet)
				EndIf
	
			EndIf
			
			DrawText Text$ + tempText,X,Y
			Return ""

	EndFunction

EndType



'********************************************
' Object used to draw some text on the screen
'********************************************
Type Txt
	Field content$
	Field red%, green%, blue%
End Type



'**************************************************
' Function allowing to add some text to the txtList
'*************************************************
Function AddTxt(content$, red% = 255, green% = 255, blue% = 255, limit = 10)
	Local t:Txt = New Txt
	t.content = content
	t.red = red
	t.green = green
	t.blue = blue
	txtList.AddLast t
	If txtList.Count() > limit Then txtList.RemoveFirst()
End Function



'*******************************************
' Function to draw the txtList to the screen
'*******************************************
Function DrawTxt(x% = 20, y% = 20, yStep% = 20)
  SetScale 1,1
  SetRotation 0
	For Local t:Txt = EachIn txtList
		SetColor t.red, t.green, t.blue
		DrawText t.content, x, y
		y :+ yStep
	Next 
End Function



I'm pretty certain that the only issue right now is with getting the proper address from clients. Everything else has worked out great when I applied raknet to my main project.

By the way, when sending data to a specific client using RN_GetSystemAddressFromIndex, it seems to always send only to the last player that connected. Hopefully that helps.

Time


Edit: noticed this as well in RakNet.cpp

return &packet->systemAddress;
RN_API SystemAddress * _stdcall RN_PacketGetSystemAddress(Packet *packet)
{
	return &packet->systemAddress;
}



return &rakPeerInterface
RN_API SystemAddress * _stdcall RN_GetSystemAddressFromIndex(RakPeerInterface *rakPeerInterface,int index)
{
	return &rakPeerInterface->GetSystemAddressFromIndex(index);
}


The '&' sign in those have any significance? Or is that what you had just changed in the last update?

Sorry if i'm pushing your patience with this.

OK, thank you for the example. I am not a C++ expert, and I am always confused about addressing (&, *, ...). Yes, I added a &rakPeerInterface in the wrapper, but apparently that didn't help. Any C++ expert out there to give me a clue? (the file RakNet.cpp is given in one of my post in the above).
Anyway, I will try to see what I can do for this bug. Unfortunately, that could be only in a few days that I could look at this problem, sorry about that.
Stay tune for news or pray that a C++ expert read this thread and be kind enough to look at the problem!

I've gone through the source code of almost all of raknet. I have manipulated the raknet.cpp source in several ways and still could not find the problem (hairloss).

I think I may have found a solution by having a rakpeerinterface for each client connecting to the server though, much like tcp arrayed socket streams. I'll test it further and get back to you when/if I have a working example. Should be soon as I really want to get this working. (Master Server Method).

Woohoo.

Works fine. I'm not sure if it's the best way for handling specific connections, but it works! Unfortunately, I dont have a non-maxgui example of this, since graphic ui takes up a hell of a lot more code and time.

It's not heavily commented but most of it is straight forward, and i'll be continuing my raknet framework to make things easier.

Hopefully Repeat will have more luck in finding the fix (if there is one..we don't know)

Example: (using maxgui)
SuperStrict

Include "RakNet.bmx"

Global PeerCount:Int = 0
Global serverPort:Int = 61019
Global packet:Int = 0
Global isServer:Byte
Global ConnectedNow:Int
Global MainPeer:Int

Global peer:Int[nbPlayerMax] 
Global MainWindow:TGadget = CreateWindow("Chat Test",100,100,700,500,,Window_Clientcoords|window_titlebar)
Global TextWindow:TGadget = CreateTextArea(0,0,500,480,MainWindow)
Global TextField:TGadget = CreateTextField(0,480,500,20,MainWindow)
Global LstPlayers:TGadget = CreateListBox(500,0,200,480,MainWindow)
Global CmdSend:tgadget = CreateButton("Send",500,480,200,20,MainWindow)


Const ID_CHAT:Byte = 101
Const nbPlayerMax:Int = 50



Local I:Int


Local Starter:Byte = Proceed("Act as server?") 
If Starter = 1 Then
	isServer = True
	For i = 0 To nbPlayerMax - 1
		peer[i] = RN_GetRakPeerInterface() 
		RN_Startup(peer[i] , 1, 0, (serverPort + 1 + i)) 
		RN_SetMaximumIncomingConnections(peer[i] , 1) 
	Next
	MainPeer = RN_GetRakPeerInterface() 
	RN_Startup(MainPeer, 2, 0, serverPort)       ' 1 player allowed to connect   
	RN_SetMaximumIncomingConnections(MainPeer, 2) 
	SetGadgetText(MainWindow, "ACTING AS SERVER") 
	SetGadgetText(TextWindow, "--Initialised Master Server--") 
ElseIf Starter = 0 Then
	AddGadgetItem(LstPlayers, "To All Players") 
	isServer = False
	MainPeer = RN_GetRakPeerInterface() 
	RN_Startup(MainPeer, 1, 0, 0)    ' 1 player allowed to connect -> client 
	RN_Connect(MainPeer, "127.0.0.1", serverPort, "", 0) ;
	SetGadgetText(MainWindow, "ACTING AS CLIENT") 
Else
	End
EndIf


CreateTimer 60
Local TO_Max:Int 'Default 0, what the client needs

If isserver Then 
	TO_Max = nbPlayerMax - 1
	ConnectedNow = 1
End If
Local MSG:String
Local msgType:Byte
While (Not KeyHit(KEY_ESCAPE))


'Master Server Method

	packet = RN_Receive(MainPeer) 
	If (packet) Then
		
		Msg = RN_PacketGetData(packet)
		msgType = Asc(msg[0..1])
		If isserver
			If msgType= ID_NEW_INCOMING_CONNECTION
				RN_Send(MainPeer, Chr(151) + (serverPort + PeerCount + 1), Len(Chr(151) + (serverPort + PeerCount + 1)) + 1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, True) ;
				peercount=peercount+1
				RN_Shutdown(MainPeer,1000) 'Completely Destroy main server interface. Ensures that connections to it are gone.
				MainPeer = RN_GetRakPeerInterface() 
				RN_Startup(MainPeer, 1, 0, serverPort) 
				RN_SetMaximumIncomingConnections(MainPeer, 1) 
				SetGadgetText(TextWindow, "--Client Connected at index:" + (PeerCount - 1) + "--~n" + GadgetText(TextWindow)) 
			End If
		Else 
			If msgType = 151
				If Not ConnectedNow
					Local NewPort:String = msg[1..]
					Peer[0] = RN_GetRakPeerInterface() 
					RN_Startup(peer[0],1,0,0)   ' 1 player allowed to connect -> client
					Local ok:Int = RN_Connect(peer[0], "127.0.0.1", Int(NewPort), "", 0) ;
					
					SetGadgetText(TextWindow, "Master Server said to connect to Port:" + NewPort + "~n" + GadgetText(TextWindow)) 
					If Not ok Then
						Notify "Couldnt connect? Shutting Down"
						End
					Else
						ConnectedNow = 1
					End If
				End If
			End If
		End If
		packet = RN_DeallocatePacket(MainPeer, packet) 
	End If


If connectedNow
	For i = 0 To TO_Max
		packet = RN_Receive(peer[i] ) 
		If (packet) Then
			Msg = RN_PacketGetData(packet)
			msgType = Asc(msg[0..1])
			Select msgType
				Case ID_CONNECTION_REQUEST_ACCEPTED
					SetGadgetText(TextWindow, "Connected To Server. Thanks master server.~n" + GadgetText(TextWindow)) 
				Case ID_NEW_INCOMING_CONNECTION
					AddGadgetItem(LstPlayers,"To Client #" + PeerCount)
				Case ID_CHAT
					
					Local EditMsg:String
					 
					If isServer
						EditMsg = MSG[0..1] + "Client #" + i + ":" + MSG[1..] 
					Else
						EditMsg = msg
					End If
					
		 				SetGadgetText(TextWindow,EditMsg[1..]+"~n"+GadgetText(TextWindow))
					
					If (isServer) Then
						For Local ii:Int = 0 To nbPlayerMax - 1
							RN_Send(peer[ii] , EditMsg, Len(EditMsg) + 1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, True) ;
						Next
					EndIf
			End Select
			packet = RN_DeallocatePacket(peer[i] , packet) 
		
		EndIf
	Next
End If

	WaitEvent()
	Select EventID()
		Case event_windowclose
			If isServer
				For i = 0 To nbPlayerMax - 1
					'RN_CloseConnection(peer[i] , RN_GetSystemAddressFromIndex(peer[i] , 0), True) 
					'RN_Shutdown(peer[i] , 0) 
					RN_DestroyRakPeerInterface(peer[i] ) 
				Next
			End If
			End
			
		Case event_gadgetaction
			If EventSource() = cmdSend
				If isServer
					Local MyMsg:String = Chr(ID_Chat) + "From Server: " + GadgetText(TextField)
   					If SelectedGadgetItem(lstPlayers) >= 0
						RN_Send(peer[SelectedGadgetItem(lstPlayers)], MyMsg,Len(MyMsg)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0,UNASSIGNED_SYSTEM_ADDRESS,True)					Else
						
					End If

				Else
					Local MyMsg:String = Chr(ID_Chat) + GadgetText(TextField)
					RN_Send(peer[0], MyMsg,Len(MyMsg)+1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS,True)
				End If
			End If
	End Select


Wend



Function ServerConnectionCount%()
	Local count:Int = 0
	For Local i:Int = 0 To nbPlayerMax - 1
		If RN_GetSystemAddressFromIndex(peer[i], 0) <> -1  count = count + 1
	Next
	Return count
End Function


A master server is created, which created on port <x> up to port <x+PlayerCount>. When you connect to the master server, it tells you an available port to connect to.

Advantages: It works.

Disadvantages:
-You may need to open a lot of ports manually if your configuration control panel sucks.
-High player count = longer initial loadtime.
-May not be as efficient, but this may actually be the only possible way, we don't know yet. I have not tried running it in a live environment yet, but there's no reason it can't.
-Some clients may need to allow a long list of ports to open, but that shouldn't be the case.

Also, the example does NOT handle disconnections / reconnections at all.

Cheers

OK, great you have a workaround. I will still try to debug the problem myself with the wrapper. The problem is that I am really busy with other non programmatic stuff, so go ahead with your method for now...

Can you use the voice streaming with this? I know Raknet supports it just wondering if all the stuff is defined in the decls and everything. Im a userlib n00b...

Actually this is a question meant for the Blitz3d one... got the threads mixed up.

Edit:
I believe the necessary files need to be added to the source, and probobly altered a bit. Until then, no rakvoice commands will work with the wrapper.

Repeat has included the source, so i'm sure if more people throw some time into this we could get a fully operational RakNet wrapper going.

Implementing the voice into the wrapper would be great!! I don't know if it is possible or not, one should try. I let this to other people as I don't program much now...

Hmmmm I remember a similar problem with playerIndex/IDs in Kurix incantation of the wrapper.

The workaround for that was to grab the clients ID when they first connected and just use that (rather than on each packet they send) This is not the case now.

Looking at the current wrapper, Im thinking its because SystemAddress is not being passed correctly (as it contains both the Address and the port ? )

I would have a play but when I compile using DEv C++ v4 theres all sorts of compiler errors .... :S

Windows only = game over :/

fixed version of the .dll can be downloaded here, the fix handel's SystemAddress correct.

http://www.whitegatesoftware.com/RakNet.zip

Nice one Kev !!!

Can you send the updated source to RepeatUntil - nice to keep it upto date.

thats great. i am near the point where i add UDP-network stuff to my game using this lib.

thats a community!

Another couple of little changes. Passing strings to and from the wrapper are currently 'borked' as the string passing has to be specified with $z not :string.

To send strings via the stream I always use
RN_BitStreamWriteUnsignedChar(), this elimiates the need to send individual chars from your string one at a time.

example:-
RN_BitStreamWriteUnsignedChar(OUTStream,Len(oString))
RN_BitStreamWrite(OUTStream, oString ,Len(YourName))


Heres an updated Raknet.bmx

'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- Raknet wrapper for BlitzMax. This wrapper was originally developped by Kurix for       -
'- Blitz3D, adapted to RakNet 3 and BlitzMax by RepeatUntil.                              -
'- This wrapper is open source, and could be modified by anyone who would like to         -
'- improve it. This is a project who should benefit the whole Blitz community, so please  -
'- send all improvements to repeatuntil@... (to upload on a web site).                -
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------


Global lib:Int = LoadLibraryA("RakNet.dll")

Global RN_GetRakPeerInterface%()"Win32" = GetProcAddress(lib, "RN_GetRakPeerInterface@0")
Global RN_DestroyRakPeerInterface%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_DestroyRakPeerInterface@4")

Global RN_Startup%(rakPeerInterface%,maxConnections%, _threadSleepTimer%, localPort%)"Win32" = GetProcAddress(lib, "RN_Startup@16")
Global RN_IsActive%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_IsActive@4")
Global RN_GetMaximumNumberOfPeers%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_GetMaximumNumberOfPeers@4")
Global RN_SetMaximumIncomingConnections(rakPeerInterface%,numberAllowed%)"Win32" = GetProcAddress(lib, "RN_SetMaximumIncomingConnections@8")
Global RN_GetMaximumIncomingConnections%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_GetMaximumIncomingConnections@4")
Global RN_Connect%(rakPeerInterface%,host$z,serverport%,passwordData$z,passwordDataLength%)"Win32" = GetProcAddress(lib, "RN_Connect@20")
Global RN_Shutdown(rakPeerInterface%,blockDuration%)"Win32" = GetProcAddress(lib, "RN_Shutdown@8")
Global RN_CloseConnection(rakPeerInterface%,target%,sendDisconnectionNotification%)"Win32" = GetProcAddress(lib, "RN_CloseConnection@16")
Global RN_GetConnectionList%(rakPeerInterface%,remoteSystems%,numberOfSystems%)"Win32" = GetProcAddress(lib, "RN_GetConnectionList@12") 
Global RN_Send%(rakPeerInterface%,data$z,length%,priority%,reliability%,orderingStream%,systemAddress%,broadcast%)"Win32" = GetProcAddress(lib, "RN_Send@32")
Global RN_SendBitStream%(rakPeerInterface%,bitStream%,priority%,reliability%,orderingChannel%,systemAddress%,broadcast%)"Win32" = GetProcAddress(lib, "RN_SendBitStream@28")
Global RN_Receive%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_Receive@4")
Global RN_DeallocatePacket%(rakPeerInterface%,packet%)"Win32" = GetProcAddress(lib, "RN_DeallocatePacket@8")

Global RN_GetInternalID%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_GetInternalID@4") 
Global RN_GetExternalID%(rakPeerInterface%,target%)"Win32" = GetProcAddress(lib, "RN_GetExternalID@12") 
Global RN_PingPlayer(rakPeerInterface:Int,systemAddress:Int)"Win32" = GetProcAddress(lib, "RN_PingPlayer@8")
Global RN_PingHost(rakPeerInterface:Int,host$z,remotePort:Int,onlyReplyOnAcceptingConnections:Int)"Win32" = GetProcAddress(lib, "RN_PingHost@16")
Global RN_GetAveragePing%(rakPeerInterface:Int,systemAddress:Int)"Win32" = GetProcAddress(lib, "RN_GetAveragePing@8")
Global RN_GetLastPing%(rakPeerInterface:Int,systemAddress:Int)"Win32" = GetProcAddress(lib, "RN_GetLastPing@8")
Global RN_GetLowestPing%(rakPeerInterface:Int,systemAddress:Int)"Win32" = GetProcAddress(lib, "RN_GetLowestPing@8")
Global RN_SetOccasionalPing(rakPeerInterface:Int,doPing:Int)"Win32" = GetProcAddress(lib, "RN_SetOccasionalPing@8")
Global RN_SetOfflinePingResponse(rakPeerInterface:Int,data$z,length:Int)"Win32" = GetProcAddress(lib, "RN_SetOfflinePingResponse@12")
Global RN_GetNumberOfAddresses%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_GetNumberOfAddresses@4")
Global RN_GetLocalIP$z(rakPeerInterface:Int,index:Int)"Win32" = GetProcAddress(lib, "RN_GetLocalIP@8")
Global RN_GetIndexFromSystemAddress%(rakPeerInterface:Int,systemAddress:Int)"Win32" = GetProcAddress(lib, "RN_GetIndexFromSystemAddress@8")
Global RN_GetSystemAddressFromIndex%(rakPeerInterface:Int,index:Int)"Win32" = GetProcAddress(lib, "RN_GetSystemAddressFromIndex@8")

Global RN_GetUNASSIGNED_SYSTEM_ADDRESS%()"Win32" = GetProcAddress(lib, "RN_GetUNASSIGNED_SYSTEM_ADDRESS@0")
Global RN_GetUNASSIGNED_NETWORK_ID%()"Win32" = GetProcAddress(lib, "RN_GetUNASSIGNED_NETWORK_ID@0")
Global RN_GetTime%()"Win32" = GetProcAddress(lib, "RN_GetTime@0")


Global RN_PacketGetData$z(packet%)"Win32" = GetProcAddress(lib, "RN_PacketGetData@4")
Global RN_PacketGetBitSize%(packet%)"Win32" = GetProcAddress(lib, "RN_PacketGetBitSize@4")
Global RN_PacketGetplayerIndex%(packet%)"Win32" = GetProcAddress(lib, "RN_PacketGetplayerIndex@4")  ' Server only according to RakNetTypes.h
Global RN_PacketGetSystemAddress%(packet%)"Win32" = GetProcAddress(lib, "RN_PacketGetSystemAddress@4")
Global RN_PacketGetBinaryAddress(packet%)"Win32" = GetProcAddress(lib, "RN_PacketGetBinaryAddress@4")
Global RN_PacketGetPort(packet%)"Win32" = GetProcAddress(lib, "RN_PacketGetPort@4")
Global RN_SystemAddressGetBinaryAddress%(systemAddress%)"Win32" = GetProcAddress(lib, "RN_SystemAddressGetBinaryAddress@4")
Global RN_SystemAddressGetPort%(systemAddress%)"Win32" = GetProcAddress(lib, "RN_SystemAddressGetPort@4")


Global RN_InitializeSecurity(rakPeerInterface%, pubKeyE$z, pubKeyN$z, privKeyP$z, privKeyQ$z)"Win32" =  GetProcAddress(lib, "RN_InitializeSecurity@20")
Global RN_DisableSecurity(rakPeerInterface%)"Win32" =  GetProcAddress(lib, "RN_DisableSecurity@4")
Global RN_SetIncomingPassword(rakPeerInterface%, passwordData$z, passwordDataLength%)"Win32" = GetProcAddress(lib, "RN_SetIncomingPassword@12")
Global RN_GetIncomingPassword(rakPeerInterface%, passwordData$z, passwordDataLength%)"Win32" = GetProcAddress(lib, "RN_GetIncomingPassword@12")

Global RN_ApplyNetworkSimulator(rakPeerInterface%,maxSendBPS%,minExtraPing%,extraPingVariance%)"Win32" = GetProcAddress(lib, "RN_ApplyNetworkSimulator@16")
Global RN_IsNetworkSimulatorActive%(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_IsNetworkSimulatorActive@4")


Global RN_AddToBanList(rakPeerInterface%,ip$z,milliseconds%)"Win32" = GetProcAddress(lib, "RN_AddToBanList@12")
Global RN_RemoveFromBanList(rakPeerInterface%,ip$z)"Win32" = GetProcAddress(lib, "RN_RemoveFromBanList@8")
Global RN_ClearBanList(rakPeerInterface%)"Win32" = GetProcAddress(lib, "RN_ClearBanList@4")
Global RN_IsBanned%(rakPeerInterface%,ip$z)"Win32" = GetProcAddress(lib, "RN_IsBanned@8")


Global RN_AdvertiseSystem(rakPeerInterface%,host$z,remotePort%, data$z,dataLength%)"Win32" = GetProcAddress(lib, "RN_AdvertiseSystem@20")

' Statistics. More functions are wrapped (you can add them here if needed!)
Global RN_ServerGetStatistics(rakPeerInterface%,systemAddress%)"Win32" = GetProcAddress(lib, "RN_ServerGetStatistics@8")
Global RN_StatisticsGetMessagesSent(stat%,queue%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetmessagesSent@8")
Global RN_StatisticsGetMessageDataBitsSent(stat%,queue%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetmessageDataBitsSent@8")
Global RN_StatisticsGetMessageTotalBitsSent(stat%,queue%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetmessageTotalBitsSent@8")
Global RN_StatisticsGetTotalBitsSent(stat%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetTotalBitsSent@4")
Global RN_StatisticsGetBitsReceived(stat%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetBitsReceived@4")
Global RN_StatisticsGetPacketsSent(stat%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetPacketsSent@4")
Global RN_StatisticsGetPacketsReceived(stat%)"Win32" = GetProcAddress(lib, "RN_StatisticsGetPacketsReceived@4")

' BitStreams
Global RN_BitStreamCreate1:Int(initialBytesToAllocate:Int) "Win32" = GetProcAddress(lib, "RN_BitStreamCreate1@4") 
Global RN_BitStreamCreate2:Int(data$z,length:Int,copydata:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamCreate2@12")
Global RN_BitStreamReset(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReset@4")
Global RN_BitStreamDestroy(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamDestroy@4")
Global RN_BitStreamCreateFromPacket:Int(packet:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamCreateFromPacket@4")
Global RN_BitStreamWriteBool (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteBool@8")
Global RN_BitStreamWriteUnsignedChar (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedChar@8")
Global RN_BitStreamWriteChar (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteChar@8")
Global RN_BitStreamWriteUnsignedShort (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedShort@8")
Global RN_BitStreamWriteShort (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteShort@8")
Global RN_BitStreamWriteUnsignedInt (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedInt@8")
Global RN_BitStreamWriteInt (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteInt@8")
Global RN_BitStreamWriteUnsignedLong (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteUnsignedLong@8")
Global RN_BitStreamWriteLong (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteLong@8")
Global RN_BitStreamWriteFloat (bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteFloat@8")
Global RN_BitStreamWriteDouble (bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteDouble@8")
Global RN_BitStreamWrite (bitstream:Int,Inp$z,numberOfBytes:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWrite@12")
Global RN_BitStreamWriteCompressedUnsignedChar(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedChar@8")
Global RN_BitStreamWriteCompressedChar(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedChar@8")
Global RN_BitStreamWriteCompressedUnsignedShort(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedShort@8")
Global RN_BitStreamWriteCompressedShort(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedShort@8")
Global RN_BitStreamWriteCompressedUnsignedInt(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedInt@8")
Global RN_BitStreamWriteCompressedInt(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedInt@8")
Global RN_BitStreamWriteCompressedUnsignedLong (bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedUnsignedLong@8")
Global RN_BitStreamWriteCompressedLong(bitstream:Int,Inp:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedLong@8")
Global RN_BitStreamWriteCompressedFloat(bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedFloat@8")
Global RN_BitStreamWriteCompressedDouble(bitstream:Int,Inp:Float)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteCompressedDouble@8")
Global RN_BitStreamReadBool:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadBool@4")
Global RN_BitStreamReadUnsignedChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedChar@4")
Global RN_BitStreamReadChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadChar@4")
Global RN_BitStreamReadUnsignedShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedShort@4")
Global RN_BitStreamReadShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadShort@4")
Global RN_BitStreamReadUnsignedInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedInt@4")
Global RN_BitStreamReadInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadInt@4")
Global RN_BitStreamReadUnsignedLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadUnsignedLong@4")
Global RN_BitStreamReadLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadLong@4")
Global RN_BitStreamReadFloat:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadFloat@4")
Global RN_BitStreamReadDouble:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadDouble@4")
Global RN_BitStreamRead$z(bitstream:Int,numberOfBytes:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamRead@8")
Global RN_BitStreamReadCompressedUnsignedChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedChar@4")
Global RN_BitStreamReadCompressedChar:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedChar@4")
Global RN_BitStreamReadCompressedUnsignedShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedShort@4")
Global RN_BitStreamReadCompressedShort:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedShort@4")
Global RN_BitStreamReadCompressedUnsignedInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedInt@4")
Global RN_BitStreamReadCompressedInt:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedInt@4")
Global RN_BitStreamReadCompressedUnsignedLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedUnsignedLong@4")
Global RN_BitStreamReadCompressedLong:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedLong@4")
Global RN_BitStreamReadCompressedFloat:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedFloat@4")
Global RN_BitStreamReadCompressedDouble:Float(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadCompressedDouble@4")
Global RN_BitStreamResetReadPointer(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamResetReadPointer@4")
Global RN_BitStreamAssertStreamEmpty(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAssertStreamEmpty@4")
Global RN_BitStreamPrintBits(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamPrintBits@4")
Global RN_BitStreamIgnoreBits(bitstream:Int,numberOfBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamIgnoreBits@8")
Global RN_BitStreamSetWriteOffset(bitstream:Int,offset:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamSetWriteOffset@8")
Global RN_BitStreamGetNumberOfBitsUsed:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetNumberOfBitsUsed@4")
Global RN_BitStreamGetNumberOfBytesUsed:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetNumberOfBytesUsed@4")
Global RN_BitStreamGetReadOffset:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetReadOffset@4")
Global RN_BitStreamGetNumberOfUnreadBits:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetNumberOfUnreadBits@4")
Global RN_BitStreamSetData(bitstream:Int,data$z,numberOfBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamSetData@12")
Global RN_BitStreamGetData$z(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetData@4")
Global RN_BitStreamGetDataPointer:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamGetDataPointer@4")
Global RN_BitStreamWriteBits(bitstream:Int,Inp$z,numberOfBitsToWrite:Int,rightAlignedBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteBits@16")
Global RN_BitStreamWriteAlignedBytes(bitstream:Int,Inpt$z,numberOfBytesToWrite:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWriteAlignedBytes@12")
Global RN_BitStreamReadAlignedBytes$z(bitstream:Int,numberOfBytesToRead:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadAlignedBytes@8")
Global RN_BitStreamAlignWriteToByteBoundary(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAlignWriteToByteBoundary@4")
Global RN_BitStreamAlignReadToByteBoundary(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAlignReadToByteBoundary@4")
Global RN_BitStreamReadBits$z(bitstream:Int,numberOfBitsToRead:Int,alignBitsToRight:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadBits@12")
Global RN_BitStreamWrite0(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWrite0@4")
Global RN_BitStreamWrite1(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamWrite1@4")
Global RN_BitStreamReadBit:Int(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamReadBit@4")
Global RN_BitStreamAssertCopyData(bitstream:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamAssertCopyData@4")
Global RN_BitStreamSetNumberOfBitsAllocated(bitstream:Int,lengthInBits:Int)"Win32"= GetProcAddress(lib,"RN_BitStreamSetNumberOfBitsAllocated@8")




'-------------------------'
'MESSAGE TYPES
'-------------------------'


	'//
	'// RESERVED TYPES - DO Not CHANGE THESE
	'// All types from RakPeer
	'//
	'/// These types are never returned To the user.
	'/// Ping from a connected system.  Update timestamps (internal use only)
	Const ID_INTERNAL_PING:Int = 0  
	'/// Ping from an unconnected system.  Reply but do Not update timestamps. (internal use only)
	Const ID_PING:Int = 1
	'/// Ping from an unconnected system.  Only reply If we have open connections. Do Not update timestamps. (internal use only)
	Const ID_PING_OPEN_CONNECTIONS:Int = 2
	'/// Pong from a connected system.  Update timestamps (internal use only)
	Const ID_CONNECTED_PONG:Int = 3
	'/// Asking For a New connection (internal use only)
	Const ID_CONNECTION_REQUEST:Int = 4
	'/// Connecting To a secured server/peer (internal use only)
	Const ID_SECURED_CONNECTION_RESPONSE:Int = 5
	'/// Connecting To a secured server/peer (internal use only)
	Const ID_SECURED_CONNECTION_CONFIRMATION:Int = 6
	'/// Packet that tells us the packet contains an integer ID To name mapping For the remote system (internal use only)
	Const ID_RPC_MAPPING:Int = 7
	'/// A reliable packet To detect lost connections (internal use only)
	Const ID_DETECT_LOST_CONNECTIONS:Int = 8
	'/// Offline message so we know when To reset And start a New connection (internal use only)
	Const ID_OPEN_CONNECTION_REQUEST:Int = 9
	'/// Offline message response so we know when To reset And start a New connection (internal use only)
	Const ID_OPEN_CONNECTION_REPLY:Int = 10
	'/// Remote procedure call (internal use only)
	Const ID_RPC:Int = 11
	'/// Remote procedure call reply =  For RPCs that Return data (internal use only)
	Const ID_RPC_REPLY:Int = 12

	'//
	'// USER TYPES - DO Not CHANGE THESE
	'//

	'/// RakPeer - In a client/server environment =  our connection request To the server has been accepted.
	Const ID_CONNECTION_REQUEST_ACCEPTED:Int = 13
	'/// RakPeer - Sent To the player when a connection request cannot be completed due To inability To connect.
	Const ID_CONNECTION_ATTEMPT_FAILED:Int = 14
	'/// RakPeer - Sent a connect request To a system we are currently connected to.
	Const ID_ALREADY_CONNECTED:Int = 15
	'/// RakPeer - A remote system has successfully connected.
	Const ID_NEW_INCOMING_CONNECTION:Int = 16
	'/// RakPeer - The system we attempted To connect To is Not accepting New connections.
	Const ID_NO_FREE_INCOMING_CONNECTIONS:Int = 17
	'/// RakPeer - The system specified in Packet::systemAddress has disconnected from us.  For the client =  this would mean the server has shutdown.
	Const ID_DISCONNECTION_NOTIFICATION:Int = 18
	'/// RakPeer - Reliable packets cannot be delivered To the system specified in Packet::systemAddress.  The connection To that system has been closed.
	Const ID_CONNECTION_LOST:Int = 19
	'/// RakPeer - We preset an RSA Public key which does Not match what the system we connected To is using.
	Const ID_RSA_PUBLIC_KEY_MISMATCH:Int = 20
	'/// RakPeer - We are banned from the system we attempted To connect to.
	Const ID_CONNECTION_BANNED:Int = 21
	'/// RakPeer - The remote system is using a password And has refused our connection because we did Not set the correct password.
	Const ID_INVALID_PASSWORD:Int = 22
	'/// RakPeer - A packet has been tampered with in transit.  The sender is contained in Packet::systemAddress.
	Const ID_MODIFIED_PACKET:Int = 23
	'/// RakPeer - The four bytes following this Byte represent an unsigned Int which is automatically modified by the difference in system times between the sender And the recipient. Requires that you call SetOccasionalPing.
	Const ID_TIMESTAMP:Int = 24
    '/// RakPeer - Pong from an unconnected system.  First Byte is const ID_PONG =  second SizeOf(RakNetTime) bytes is the ping =  following bytes is system specific enumeration data.
	Const ID_PONG:Int = 25
	'/// RakPeer - Inform a remote system of our IP/Port =  plus some offline data
	Const ID_ADVERTISE_SYSTEM:Int = 26
	'/// ConnectionGraph plugin - In a client/server environment =  a client other than ourselves has disconnected gracefully.  Packet::systemAddress is modified To reflect the systemAddress of this client.
	Const ID_REMOTE_DISCONNECTION_NOTIFICATION:Int = 27
	'/// ConnectionGraph plugin - In a client/server environment =  a client other than ourselves has been forcefully dropped. Packet::systemAddress is modified To reflect the systemAddress of this client.
	Const ID_REMOTE_CONNECTION_LOST:Int = 28
	'/// ConnectionGraph plugin - In a client/server environment =  a client other than ourselves has connected.  Packet::systemAddress is modified To reflect the systemAddress of this client.
	Const ID_REMOTE_NEW_INCOMING_CONNECTION:Int = 29
	'// RakPeer - Downloading a large message. Format is Const ID_DOWNLOAD_PROGRESS (MessageID) =  partCount (unsigned Int) =  partTotal (unsigned Int) =  partLength (unsigned Int) =  first part data (length <= MAX_MTU_SIZE)
	Const ID_DOWNLOAD_PROGRESS:Int = 30

	'/// FileListTransfer plugin - Setup data
	Const ID_FILE_LIST_TRANSFER_HEADER:Int = 31
	'/// FileListTransfer plugin - A file
	Const ID_FILE_LIST_TRANSFER_FILE:Int = 32

	'/// DirectoryDeltaTransfer plugin - Request from a remote system For a download of a directory
	Const ID_DDT_DOWNLOAD_REQUEST:Int = 33
	
	'/// RakNetTransport plugin - Transport provider message =  used For remote console
	Const ID_TRANSPORT_STRING:Int = 34

	'/// ReplicaManager plugin - Create an Object
	Const ID_REPLICA_MANAGER_CONSTRUCTION:Int = 35
	'/// ReplicaManager plugin - Destroy an Object
	Const ID_REPLICA_MANAGER_DESTRUCTION:Int = 36
	'/// ReplicaManager plugin - Changed scope of an Object
	Const ID_REPLICA_MANAGER_SCOPE_CHANGE:Int = 37
	'/// ReplicaManager plugin - Serialized data of an Object
	Const ID_REPLICA_MANAGER_SERIALIZE:Int = 38
	'/// ReplicaManager plugin - Finished downloading all serialized objects
	Const ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE:Int = 39

	'/// ConnectionGraph plugin - Request the connection graph from another system
	Const ID_CONNECTION_GRAPH_REQUEST:Int = 40
	'/// ConnectionGraph plugin - Reply To a connection graph download request
	Const ID_CONNECTION_GRAPH_REPLY:Int = 41
	'/// ConnectionGraph plugin - Update edges / nodes For a system with a connection graph
	Const ID_CONNECTION_GRAPH_UPDATE:Int = 42
	'/// ConnectionGraph plugin - Add a New connection To a connection graph
	Const ID_CONNECTION_GRAPH_NEW_CONNECTION:Int = 43
	'/// ConnectionGraph plugin - Remove a connection from a connection graph - connection was abruptly lost
	Const ID_CONNECTION_GRAPH_CONNECTION_LOST:Int = 44
	'/// ConnectionGraph plugin - Remove a connection from a connection graph - connection was gracefully lost
	Const ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION:Int = 45

	'/// Router plugin - route a message through another system
	Const ID_ROUTE_AND_MULTICAST:Int = 46

	'/// RakVoice plugin - Open a communication channel
	Const ID_RAKVOICE_OPEN_CHANNEL_REQUEST:Int = 47
	'/// RakVoice plugin - Communication channel accepted
	Const ID_RAKVOICE_OPEN_CHANNEL_REPLY:Int = 48
	'/// RakVoice plugin - Close a communication channel
	Const ID_RAKVOICE_CLOSE_CHANNEL:Int = 49
	'/// RakVoice plugin - Voice data
	Const ID_RAKVOICE_DATA:Int = 50

	'/// Autopatcher plugin - Get a list of files that have changed since a certain date
	Const ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE:Int = 51
	'/// Autopatcher plugin - A list of files To create
	Const ID_AUTOPATCHER_CREATION_LIST:Int = 52
	'/// Autopatcher plugin - A list of files To Delete
	Const ID_AUTOPATCHER_DELETION_LIST:Int = 53
	'/// Autopatcher plugin - A list of files To get patches For
	Const ID_AUTOPATCHER_GET_PATCH:Int = 54
	'/// Autopatcher plugin - A list of patches For a list of files
	Const ID_AUTOPATCHER_PATCH_LIST:Int = 55
	'/// Autopatcher plugin - Returned To the user: An error from the database repository For the autopatcher.
	Const ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR:Int = 56
	'/// Autopatcher plugin - Finished getting all files from the autopatcher
	Const ID_AUTOPATCHER_FINISHED_INTERNAL:Int = 57
	Const ID_AUTOPATCHER_FINISHED:Int = 58
	'/// Autopatcher plugin - Returned To the user: You must restart the application To finish patching.
	Const ID_AUTOPATCHER_RESTART_APPLICATION:Int = 59

	'/// NATPunchthrough plugin - Intermediary got a request To help punch through a nat
	Const ID_NAT_PUNCHTHROUGH_REQUEST:Int = 60
	'/// NATPunchthrough plugin - Intermediary cannot complete the request because the target system is Not connected
	Const ID_NAT_TARGET_NOT_CONNECTED:Int = 61
	'/// NATPunchthrough plugin - While attempting To connect =  we lost the connection To the target system
	Const ID_NAT_TARGET_CONNECTION_LOST:Int = 62
	'/// NATPunchthrough plugin - Internal message To connect at a certain time
	Const ID_NAT_CONNECT_AT_TIME:Int = 63
	'/// NATPunchthrough plugin - Internal message To send a message (To punch through the nat) at a certain time
	Const ID_NAT_SEND_OFFLINE_MESSAGE_AT_TIME:Int = 64

	'/// LightweightDatabase plugin - Query
	Const ID_DATABASE_QUERY_REQUEST:Int = 65
	'/// LightweightDatabase plugin - Update
	Const ID_DATABASE_UPDATE_ROW:Int = 66
	'/// LightweightDatabase plugin - Remove
	Const ID_DATABASE_REMOVE_ROW:Int = 67
	'/// LightweightDatabase plugin - A serialized table.  Bytes 1+ contain the table.  Pass To TableSerializer::DeserializeTable
	Const ID_DATABASE_QUERY_REPLY:Int = 68
	'/// LightweightDatabase plugin - Specified table Not found
	Const ID_DATABASE_UNKNOWN_TABLE:Int = 69
	'/// LightweightDatabase plugin - Incorrect password
	Const ID_DATABASE_INCORRECT_PASSWORD:Int = 70
	
	'// For the user To use.  Start your first enumeration at this value.
	Const ID_USER_PACKET_ENUM:Int = 71



'-------------------------'
'MESSAGE PRIORITIES
'-------------------------'
Const	HIGH_PRIORITY:Int = 1
Const	MEDIUM_PRIORITY:Int = 2
Const	LOW_PRIORITY:Int = 3

'-------------------------'
'MESSAGE RELIABILITY
'-------------------------'
Const UNRELIABLE:Int = 0
Const UNRELIABLE_SEQUENCED:Int = 1
Const RELIABLE:Int = 2
Const RELIABLE_ORDERED:Int = 3
Const RELIABLE_SEQUENCED:Int = 4

'-------------------------'
'UNASSIGNED PLAYER ID
'-------------------------'
Global UNASSIGNED_SYSTEM_ADDRESS:Int = RN_GetUNASSIGNED_SYSTEM_ADDRESS()
Global UNASSIGNED_NETWORK_ID:Int = RN_GetUNASSIGNED_NETWORK_ID()

Function RN_GetPacketIdentifier%(packet%)
	Local msg$ = RN_PacketGetData(packet)
	Return Asc(msg[0..1])
End Function




Great, great, great!! Effectively, that's really a nice community! I will add all these improvements in the RakNet wrapper to have one single improved version. I will post here when done (could take several days...).

Ovine, I will check with which version I am compiling (I am at work now...)

My programming time is reaching 0 now, so this wrapper should be considered developped by the community. I will still centralize the RakNet code, and reply to threads or emails.

RepeatUntil, i will email you the fixed source for the posted .dll for inclusion sometime today

I just uploaded new version of the RakNet wrapper (Blitz3D/Max)!! The new stuff:
- fixes by Ovine in RakNet.bmx
- fixes by Kev in the wrapper itself. Should fix a very important bug, ie the code to identify clients!
- And, as everyone was courageous but me, I decided to update the wrapper to the very latest version of RakNet (v3.2)! RakNet.bb/.bmx and the dll were modified.

You can download all this fun from my signature.
By the way, I have added the wrapper in the toolbox for posterity: http://www.blitzmax.com/toolbox/toolbox.php?tool=215

However, it seems that the function RN_GetSystemAddressFromIndex() is not working properly. I commented out the use of this function in the examples. Kev (or others), could you check that it is working or not?


I would have a play but when I compile using DEv C++ v4 theres all sorts of compiler errors .... :S


I use dev-C++ v4.9.9.2. I have now put a file HELPRakNetWrapper.txt in the dev version. Follow it step by step, and you should be able to first compile RakNet alone (if it is not working at this point, this is because your settings are incorrect), and then the wrapper itself.

I will take a look the RN_GetSystemAddressFromIndex() call in the next couple of days.

Kev

Any news on the fix yet ? Looking at the code it is evident why its now broken....

ok having taken a look over the source and testing using the provided example. IT DOES SEEM TO WORK!

take the following...

i replace the original example code server keyhit 'enter' section with the code below. then i create a server(key s) then i create 3 clients(key c)

here we send the message only to client who's index is '1'
		If KeyHit(28)
			Print "sending message from server"
			chatMsg$=" Hello world!!! server here"
			chatMsg$ = Chr(ID_CHAT) + chatMsg
			; and now broadcast it
			ok = RN_Send(peer, chatMsg$, Len(chatMsg$) + 1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RN_GetSystemAddressFromIndex(peer, 1), False)
		EndIf



now say we want to send the message to all clients BUT NOT client 1 we change the broadcast flag to 'true' so...

		If KeyHit(28)
			Print "sending message from server"
			chatMsg$=" Hello world!!! server here"
			chatMsg$ = Chr(ID_CHAT) + chatMsg
			; and now broadcast it
			ok = RN_Send(peer, chatMsg$, Len(chatMsg$) + 1, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RN_GetSystemAddressFromIndex(peer, 1), True)
		EndIf



ive not tested using RN_SendBitStream() but it should work.

Then I am really confused!!!
Because I have added one simple line in the code (the example):
DrawText(RN_GetSystemAddressFromIndex(peer, 0) 
+ " / " + RN_GetSystemAddressFromIndex(peer, 1) 
+ " / " + RN_GetSystemAddressFromIndex(peer, 2), 20, GraphicsHeight()*0.7)


I have connected the server with 2 clients on one machine. Then you see that the 3 RN_GetSystemAddressFromIndex printed on screen are completely identical, whereas I expect them to be different for the server and the 2 clients, no?
By the way, it is different from the system address returned in the string "Packet from" in the wrapper example. So, I am really confused!!!!

Could you try to add this debugging line and tell me what you have and if you understand it?

Take into account that the licence fee for RackNet is $100 for a indy project that sells. Its free for non-commercial applications tho.

hold on i think i understand, in the raknet.cpp heres what we have for RN_GetSystemAddressFromIndex() to function correct.

we first make 'SystemAddress addr;' have global scope. devc++ did not like returning the address of a temporary variable. now each time RN_GetSystemAddressFromIndex() is called the addr struct is populated and its address returned.

so were returning the same address thats populated with new SystemAddress details each call.

i could be wrong though, i will look into it.

kev

Thanks for your work on this so far Kev.

As soon as I plugged in the new DLL my working program stopped.

It does seem to be RN_GetSystemAddressFromIndex thats at fault.

RN_SendBitStream(Server, BitStreamOUT, HIGH_PRIORITY, RELIABLE_ORDERED, 2, RN_GetSystemAddressFromIndex(Server, playerindex), False) 


Also where has the extra 200k come from in the new build of the wrapper- not that lightweight anymore is it :)

ok seems like this now works, download below

http://www.whitegatesoftware.com/RakNet_update.rar

please post your results.

kev

Yes, the additional 200K comes from v3.2 wrt v3.0 beta. I don't know what he added though...

OK, Kev, please let us know if you think you have found a fix...

An yes, RakNet is not free if you sell something with it...

100$ is nothing in Euros ;)

If you plan to sell something, i think you can afford the 100 bucks.

keep on developing this nice wrapper!

I made a framework for this wrapper a while back, and from what I saw it looked like a heaploads of work to impliment other feature or fix current ones.

You would think "RN_GetSystemAddressFromIndex" would be a simple return value fix but it doesn't seem that easy.

ive emailed the fixed function call to RepeatUntil, for now the link above has been updated with the new working .dll. this has been tested in blitzmax and blitz3d both seem to work as expected.

kev

Still same problem here


The sticking point for me now is sending a packet back to a client thats just logging on (grabbing the systemaddress from the packet)

RN_PacketGetSystemAddress(Packet)



More investigation, im wrong. The client isnt connecting to the server. Its returning an error "ID_NO_FREE_INCOMING_CONNECTIONS".

Works in previous version not in this one.

	Local ret = RN_Startup(Server, 15, 0, Int(portnumber:String)) 
	RN_SetMaximumIncomingConnections(Server, 15) 


OvineByDesign, can you confirm that RN_GetSystemAddressFromIndex() is working for you and that theres also a problem with RN_PacketGetSystemAddress() or that BOTH are still broke.

kev

Right I got the client to connect (my bad)

All code is now working for me both RN_GetSystemAddressFromIndex() and RN_PacketGetSystemAddress().

Good fix. Ive not tested what RepeatUntil has reported tho. I'll fire up an example and see.

The RN_GetSystemAddressFromIndex(peer, 0) as repeatuntil is reporting is correct, its returning the same address no matter what player index you give it :S

Which is bizare as its working for me in game - just not with the "simpleExample.bmx"


The RN_GetSystemAddressFromIndex(peer, 0) as repeatuntil is reporting is correct, its returning the same address no matter what player index you give it :S



yes it will as its returning the same struct's address thats been populated using the SystemAddress obtained from the passed index. not great i know, im still unable to find a working fix for this.


Which is bizare as its working for me in game - just not with the "simpleExample.bmx"



in the example it broadcasts to all clients, to change this use the following

under 'Case ID_CHAT' change to!

If (isServer) Then
	RN_Send(peer,msg$,Len(msg)+1,HIGH_PRIORITY,RELIABLE_ORDERED,0,RN_GetSystemAddressFromIndex(peer, 1),True);
EndIf



Whilst your looking in the source Kev, can you look at converting the systemaddress into a readable IP addy ?

Reading the forums :-

"Use ToString() to output a statically allocated string for SystemAddress"

As I needed an immediate fix, Ive added GetIPAddressFromIndex(index) to the RakPeer source code.

Probably not the best way todo it (as its effecting the core product) but I couldnt get toString() to work in just RakNet.cpp :S

I now can grab the external IP addys of the clients connected.

Very good news for them who were expecting that: this RakNet wrapper is now available as a module for BlitzMax, which means that it is now cross-platform!!

This work was done by Jimon. I didn't test it, but Jimon told me that it was working perfectly on Windows and Linux. A big thanks to him!

You can download this new version from my sig (RakNet web page), or directly from this link.

It uses the latest version of the wrapper and of RakNet.

Please test it and report any problem...

Holy crap. That's awsome news!

Great News on making it a module. :)

sounds like an awesome library, wish I had this when I did my last multiplayer game. Great to see it available to Blitzmax.

Out of curiosity what would it take to get the rakvoice api working in the module?

Excellent stuff ! - off to play with it now.

Out of interest, has anyone tried it out on a Mac yet ?

Seems that sending a Broadcast produces an error

RN_SendBitStream(peer, BitWriter, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, True)



Seems to be "UNASSIGNED_SYSTEM_ADDRESS" related as the example app that was supplied test app sends without problem using "RN_PacketGetSystemAddress(Packet)
" as the address....

Just to clarify I'm trying to send a broadcast message to all clients.

Seems that UNASSIGNED_SYSTEM_ADDRESS is not returning a systemaddress.

A quick fix to send a broadcast message :-

add this to raknet.cpp
RN_API bool RN2_API RN_SendBitStreamBroadcast(RakPeerInterface *rakPeerInterface,RakNet::BitStream *bitStream,int priority,int reliability,int orderingChannel)
{
	return rakPeerInterface->Send(bitStream,PacketPriority(priority),PacketReliability(reliability),orderingChannel,UNASSIGNED_SYSTEM_ADDRESS,1);
}




and this to raknet.bmx - then recompile the mod

Function RN_SendBitStreamBroadcast%(rakPeerInterface%,bitStream%,priority%,reliability%,orderingChannel%) = "RN_SendBitStreamBroadcast"


Use RN_SendBitStreamBroadcast() instead of RN_SendBitStream()

Hello,

Unfortunately, the author of the module (jimon) has no access to this forum (don't ask me why). But he read this thread and send me an email which reads:

i don't know now why it d'ont work :(

this UNASSIGNED_* values are const in raknet library, but i dont know how to get it if library linked as static :(
damn, blitzmax can't send agruments to gcc compiler ...
i think, i should try to compile raknet to .a file, and make some voodoo :)



and


here we go - beta 2 :)
i tested this version with ExampleBitstreams.bmx and NetTest.bmx (with some changes in NetTest.bmx)
also this version use last raknet code - v3.24



You can find the updated file he gave me here for now:
http://repeatuntil.free.fr/raknet/beta2.rar
If you find it fixes the errors, then I will put it at the official place...

will test now.

BTW Could you ask him to look at returning the IPaddress

RN_API int RN2_API RN_SystemAddressGetBinaryAddress(SystemAddress *systemAddress)
{
	return systemAddress->binaryAddress;
}


as this is supposed to return the IP address of a systemaddress, as you can see it returns an INT, according to the docs it needs conveting using "toString()" in C++.

Ive hacked the wrapper for my own use but would be nice to get it in the wrapper....

With the new updated NetTest.bmx got a bug.

Although I think its a bug - its not the correct way todo things (as far as I know).

When the client sends to the server it should always use a broadcast as the client can only see the server in any case.

In the example, ServerSystemAdress = RN_PacketGetSystemAddress(Packet) upon the client connecting to the server. You would assume that this serveraddress will never change, but it seems it does. (see reference to this earlier in the discussion). In the example the client constantly times out as its not talking to the server.

Clients send to server
I would suggest that clients always broadcast to the server

In the example do this :-
SendTest(ClientPeer,UNASSIGNED_SYSTEM_ADDRESS,1)


Server talking directly to a client

A server talking directly to a client would use :-
SendTest(ServerPeer,RN_GetSystemAddressFromIndex(Serverpeer,<id>),0)

<ID> being the players ID to send to (ID being the index 0 - maxusers)

or

SendTest(ServerPeer,RN_PacketGetSystemAddress(Packet),0))

If replying to a packet that has just been received.

I have used it this way since the original wrapper...

Hope this helps.

I can now confirm that the wrapper compiles and works on MacOsX (leopard) on an IMac.

A few compiler errors (well more like warnings) about symbols not loaded but works a treat.

Pass on my regards to "jimon" (just get him to get RN_SystemAddressGetBinaryAddress to return a string and I'll be happy) - although my insertion of a new function is working Id still prefer it to be part of the wrapper instead of a fix I have to keep remembering to insert.

Jimon is watching this thread so I hope he will work on your request (I will notify you if he sends me an email)! Otherwise, if someone knows a bit of C++, he might be able to fix the wrapper.
I must shamely admit that my programming time is now stricly 0, and so can't help :-(

Another one for Jimon.

Im trying to catch the debug info, but the assert() from within the C++ code is not producing any output.

Ive put a #define _DEBUG in the reliablilityLayer.h thinking thats the place to put it ?

Im using printf() instead of the assert() but again its messing with the core code so not the best idea.....


Is there anything Im doing wrong or missing ?

Another wrapped function that is useful :-

In Raknet.cpp

RN_API const char * RN2_API RN_StatisticsToString(RakNetStatistics *stat, int verbosityLevel)
{
	char c[ 4096 ];
	StatisticsToString(stat, c, verbosityLevel);
	return c;
}



In Raknet.bmx
Function RN_StatisticsToString$z(stat%, Level%) =  "RN_StatisticsToString"



Returns a string containing a summary of the stats.

usage :-


local stat:int 
stat = RN_ServerGetStatistics(Server, RN_PacketGetSystemAddress(Packet))

'Stat now points to the players stats that were last received
DebugLog(RN_StatisticsToString(stat,  0))  ' print brief detail
DebugLog(RN_StatisticsToString(stat,  1))  ' med detail
DebugLog(RN_StatisticsToString(stat,  2))  ' full detail




Produces (full detial)

Messages in send buffer: SP:1 HP:0 MP:0 LP:0
Messages sent: SP:5 HP:1 MP:0 LP:0
Message data bytes sent: SP:43 HP:129 MP:0 LP:0
Message header bytes sent: SP:30 HP:12 MP:0 LP:0
Message total bytes sent: SP:73 HP:141 MP:0 LP:0
Bytes received: Ttl:225 Good:225 Bad:0
Packets received: Ttl:5 Good:5 Bad:0
Acks received: Ttl:0 Good:0 Dup:0
Messages received: Total:5 Valid:5 Invalid:0 Dup:0
Packetloss: 0.0%
Packets sent: 5
Acks sent: 5
Acks in send buffer: 0
Messages waiting for ack: 0
Ack bytes sent: 19
Sent packets containing only acks: 0
Sent packets w/only acks and resends: 0
Reliable messages resent: 0
Reliable message data bytes resent: 0
Reliable message header bytes resent: 0
Reliable message total bytes resent: 0
Number of messages split: 0
Number of messages unsplit: 6
Message splits performed: 0
Additional encryption bytes: 0
Sequenced messages out of order: 0
Sequenced messages in order: 0
Ordered messages out of order: 0
Ordered messages in of order: 1
Split messages waiting for reassembly: 0
Messages in internal output queue: 1
Inst KBits per second: 67.6
Elapsed time (sec): 0.0
KBits per second sent: 156.3
KBits per second received: 138.5
Bandwith exceeded: 1

Since the wrapper seems more stable now i'll continue my EasyRak module and release it within the next week with some examples.

This wrapper is too great to go limp ;-)

Looking forward to anything RakNet related in BLITZ!!! Tutorials and documentation included ;D

Ah nevermind =(

The exact same issues still seem to be there. It seems you can still only send to one client. The issue is still there with getting the incorrect SystemAddress. It continues to return the same system address no matter what index you are recieving data from.

The only difference I see is that the issues are now wrapped for cross-platform.

Has anyone been able to actually send data properly to multiple clients, and specific clients?

ReTimer .... dont store the systemaddress !!!!

if you store the players index instead and when you want to talk to them use :-

RN_GetSystemAddressFromIndex(Serverpeer,<id>)


to grab the correct systemaddress.

I tried to explain this a few posts back. It does work.

That is actually what i'm doing, and it's still a no go. The server only seems to send to the user that last contacted it. Something is wrong =/

Have you actually been able to come up with a simple app to contact specific clients?


Part of my mod code below:
Method IsDataAvailable:Byte() 
			If Self.packet
				RN_DeallocatePacket(Interface, Self.packet)      'Must get rid of old packet. Otherwise it may be possible to cause memory leaks.
			End If
			Self.packet = RN_Receive(Interface) 
			If (Self.packet) Then
				Self.Create_BitStream_From_Packet(Self.packet) 
				Self.MsgType = RN_BitStreamReadUnsignedChar(Self.Reader) 
				Self.CurrentIndex = RN_PacketGetplayerIndex(Self.packet) 
				Self.CurrentAddress = RN_PacketGetSystemAddress(Self.Packet)     
				Print Self.currentaddress
				If Not IsServer
					ServerSystemAdress = Self.CurrentAddress
				Else
					RakPlayers[Self.CurrentIndex].Address = Self.CurrentAddress 
				End If
				If Self.MsgType < ID_USER_PACKET_ENUM 'Message was created by Raknet itself. 
					ProcessMsgID(Self.MsgType, Self.CurrentIndex, Self.CurrentAddress) 
					Return 0
				Else
					UseCompression = Self.ReadBool() 
					Return 1
				End If
				
			Else
				Return 0
			End If
	End Method


The adress prints out, on connection:


-A new client is connecting (0) - Address: 3352636
-A new client is connecting (1) - Address: 3352636



The same goes for when they send messages.....the address is the same. I have tried every method of getting the address (not just via packet) and it does the same thing.

I have it working no problems here .


Try grabbing from the index rather than the Packet

i.e. Replace

Self.CurrentAddress = RN_PacketGetSystemAddress(Self.Packet)


with

Self.CurrentAddress = RN_GetSystemAddressFromIndex(interface,Self.CurrentIndex)


Same thing. Can you provide an example where it works? I have tried every angle I can think of and it is not working properly.

If you can provide an example where you can send to specific clients and/or multiple clients. If i'm wrong, it'll at least provide some insight for others having a hard time with the RN wrapper.

Or even an example showing that the addresses incoming are different with each client?

I have tried with every systemaddress command, in multiple examples, different servers, clients, etc and all the addresses of the clients return the same thing, and trying to send to that address only sends to the last client to send a packet to the server.

Nice to see you've got a multi-OS version availiable - and it does seem (according to the included test program) to work on a Mac.

One thing - how would a client connect to a server that is effectively not known (ie it sends broadcast messages to all machines on a network, from which the client would respond).

Thanks for this great stuff! But what kind of download "server" do you use? I've got about 800 byte(!) per second...

Have mirrored it to my server - at least the release version, the others are still pending. *gg*

http://www.xaron.net/dl/bb/RakNetWrapper_release.rar
http://www.xaron.net/dl/bb/RakNetWrapper_dev.rar
http://www.xaron.net/dl/bb/RakNetModule.rar

Regards - Xaron

edit: Added the other two archives...

Alright I managed to figure out my issue, thanks Ovine.

I have an old wrapper of a wrapper here that I threw together back when the raknet wrapper was first setup, and I just managed to fix it up a little. The idea was to make it a lot less mind boggling to use the RakNet wrapper with bitstreams, and simplify it.


Here is the simplified Wrapper of jimon.raknet mod:

EasyRak:
Import jimon.raknet


Type TEasyRak
	Field UseCompression:Byte
	Field IsServer:Byte
	Field Interface:Int
	Field Connected:Byte
	Field PlayerCount:Byte
	Field MaxPlayers:Int
	Field Users:TList = CreateList() 

	Method Destroy() 
		If Interface
			RN_CloseConnection(Interface, RN_GetSystemAddressFromIndex(Interface, 0), True) 
			RN_Shutdown(Interface, 100) 
			RN_DestroyRakPeerInterface(Interface) 
		Else 'Error handler. Interface isn't even Defined Yet!
			RuntimeError("Something was coded wrong in your application, as the raknet interface has not yet been initiated much less destroyed") 
		End If
	End Method

	Method Active:Byte() 
		If Interface
			Return RN_IsActive(Interface) 
		Else
			Return 0 'Interface isn't even Defined yet!
		End If
	End Method

	Method CreateServer:Byte(Port:Int = 20202, MaxPlayers:Int = 10, UseSecurity:Byte = 0, UsePassword:String = "") 
		If Interface
			Self.Destroy()  'Interface already exists. Destroy it before creating new server
		End If
		
		Interface = RN_GetRakPeerInterface() 
		If UseSecurity = 1
			RN_InitializeSecurity(Interface, "0", "0", "0", "0") 
		End If
		
		If UsePassword <> ""
			RN_SetIncomingPassword(Interface, UsePassword, Len(UsePassword)) 
		End If
		
		Local StartResult:Byte = RN_Startup(Interface, MaxPlayers, 1, Port) 
		RN_SetMaximumIncomingConnections(Interface, MaxPlayers) 
		IsServer = 1
		Return StartResult
	End Method
	
	Method Connect_To_Server:Byte(IP:String = "127.0.0.1", Port:Int = 20202, UsePassword:String = "") 
		If Interface
			Self.Destroy()  'Interface already exists. Destroy it before creating new server
		End If
	
		Interface = RN_GetRakPeerInterface() 
		RN_Startup(Interface, 1, 1, 0)      'The 0 at the end allows raknet to choose the best port to use, rather than running into already used ports.
		Local ConnectResult:Byte = RN_Connect(Interface, IP, Port, UsePassword, Len(UsePassword)) 

		Return ConnectResult
	End Method
	
	Method GetConnectionCount:Int() 
		Return Self.Users.Count() 
		'The below Removal would work as well.
		rem
			Local count:Int = 0
			For Local i:Int = 0 To Self.MaxPlayers - 1
				If RN_GetSystemAddressFromIndex(Interface, i) <> - 1 count = count + 1
			Next
			Return count
		end rem
	End Method
	
	Method GetMaxPlayers:Int() 
		Return Self.MaxPlayers ' RN_GetMaximumNumberOfPeers(Interface) '< This works too
	End Method
	
	Method Time:Int() 
		Return RN_GetTime() 
	End Method
	
	Method HostingAsServer:Byte()  'Returns 1 for true, 0 for false.
		Return Self.IsServer
	End Method
End Type


Type TBitStream Extends TEasyRak
	Field packet:Int
	Field MsgType:Int
	Field CurrentAddress:Int		'Player Address
	Field CurrentIndex:Int			'Player Index
	Field Reader:Int				'Bitstream reader
	Field Writer:Int				'bitstream writer
	Field Length:Int
	
	Method SendDataTo(Index:Int, Priority:Int = HIGH_PRIORITY, Reliability:Int = RELIABLE_ORDERED)       'Index = -1, Broadcast = 1 to broadcast to 'EVERYONE'
		RN_BitStreamSetNumberOfBitsAllocated(Self.Writer, RN_BitStreamGetNumberOfBitsUsed(Self.Writer)) 
		RN_SendBitStream(Interface, Self.Writer, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, Index) , 0) 
	End Method

	Method SendDataToAll(Priority:Int = HIGH_PRIORITY, Reliability:Int = RELIABLE_ORDERED) 
		RN_BitStreamSetNumberOfBitsAllocated(Self.Writer, RN_BitStreamGetNumberOfBitsUsed(Self.Writer)) 
		RN_SendBitStream(Interface, Self.Writer, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, - 1), 1) 
	End Method
	
	Method SendDataToAll_Except(Index:Int, Priority:Int = HIGH_PRIORITY, Reliability:Int = RELIABLE_ORDERED) 
		RN_BitStreamSetNumberOfBitsAllocated(Self.Writer, RN_BitStreamGetNumberOfBitsUsed(Self.Writer)) 
		RN_SendBitStream(Interface, Self.Writer, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, Index), 1) 
	End Method
	
	Method SendReaderTo(Index:Int, Priority:Int = HIGH_PRIORITY, Reliability:Int = RELIABLE_ORDERED) 
		RN_BitStreamSetNumberOfBitsAllocated(Self.Reader, RN_BitStreamGetNumberOfBitsUsed(Self.Reader)) 
		RN_SendBitStream(Interface, Self.Reader, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, Index), 0) 
		Rem
			Sends the data that was 'read'. Basically copying the read data to write data and resending it.
		end Rem
	End Method
	
	Method SendReaderToAll(Priority:Int = HIGH_PRIORITY, Reliability:Int = RELIABLE_ORDERED) 
		RN_BitStreamSetNumberOfBitsAllocated(Self.Reader, RN_BitStreamGetNumberOfBitsUsed(Self.Reader)) 
		RN_SendBitStream(Interface, Self.Reader, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, - 1), 1) 
		Rem
			Sends the data that was just recieved. Basically copying the read data and resending it.
		end Rem
	End Method
	
	Method SendReaderToAll_Except(Index:Int, Priority:Int = HIGH_PRIORITY, Reliability:Int = RELIABLE_ORDERED) 
		RN_BitStreamSetNumberOfBitsAllocated(Self.Reader, RN_BitStreamGetNumberOfBitsUsed(Self.Reader)) 
		RN_SendBitStream(Interface, Self.Reader, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, Index), 1) 
		Rem
			Sends the data that was just recieved. Basically copying the read data and resending it.
		end Rem
	End Method
	
	Method IsDataAvailable:Byte() 
			If Self.packet
				RN_DeallocatePacket(Interface, Self.packet)      'Must get rid of old packet. Otherwise it may be possible to cause memory leaks.
			End If
			Self.packet = RN_Receive(Interface) 
			If (Self.packet) Then
				Self.Create_BitStream_From_Packet(Self.packet) 
				Self.MsgType = RN_BitStreamReadUnsignedChar(Self.Reader) 
				Self.CurrentIndex = RN_PacketGetplayerIndex(Self.packet) 
				Self.CurrentAddress = RN_GetSystemAddressFromIndex(Interface, Self.CurrentIndex) 

				If Self.MsgType < ID_USER_PACKET_ENUM 'Message was created by Raknet itself. 
					ProcessMsgID(Self.MsgType, Self.CurrentIndex) 
					Return 0
				Else
					UseCompression = Self.ReadBool() 
					Return 1
				End If
			Else
				Return 0
			End If
	End Method
	
	Method Create_BitStream(MessageID:Int, Compressed:Byte) 
		If Self.Writer Then RN_BitStreamDestroy(Self.Writer) 
		Self.Writer = RN_BitStreamCreate1(0) 
		RN_BitStreamWriteUnsignedChar(Self.Writer, MessageID) 
		Self.WriteBool(Compressed) 
	End Method
	
	Method Reset_BitStream() 
		RN_BitStreamReset(Self.Reader) 
		Self.Length = 0
	End Method
	
	Method Destroy_Reader_BitStream(Written:Byte) 
		RN_BitStreamDestroy(Self.Reader) 
	End Method
	
	Method Destroy_Writer_BitStream(Written:Byte) 
		RN_BitStreamDestroy(Self.Writer) 
	End Method
	
	Method Create_BitStream_From_Packet(Packet:Int) 
		If Self.Reader Then rn_bitstreamdestroy(Self.Reader) 
		Self.Reader = RN_BitStreamCreateFromPacket(Self.packet) 
		Self.Length = RN_BitStreamGetNumberOfUnreadBits(Self.Reader) 
	End Method
	
'''Writing Commands
	Method WriteBool(Value:Byte) 
		RN_BitStreamWriteBool(Self.Writer, Value) 
	End Method
	
	Method WriteByte(Value:Int) 
		If UseCompression
			RN_BitStreamWriteCompressedUnsignedChar(Self.Writer, Value) 
		Else
			RN_BitStreamWriteUnsignedChar(Self.Writer, Value) 
		End If
	End Method
	
	Method WriteShort(Value:Int) 
		If UseCompression
			RN_BitStreamWriteCompressedShort(Self.Writer, Value) 
		Else
			RN_BitStreamWriteShort(Self.Writer, Value) 
		End If
	End Method
	
	Method WriteInt(Value:Int) 
		If UseCompression
			RN_BitStreamWriteCompressedInt(Self.Writer, Value) 
		Else
			RN_BitStreamWriteInt(Self.Writer, Value) 
		End If
	End Method
	
	Method WriteLong(Value:Int) 
		If UseCompression
			RN_BitStreamWriteCompressedLong(Self.Writer, Value) 
		Else
			RN_BitStreamWriteLong(Self.Writer, Value) 
		End If
	End Method
	
	Method WriteFloat(Value:Float) 
		If UseCompression
			RN_BitStreamWriteCompressedFloat(Self.Writer, Value) 
		Else
			RN_BitStreamWriteFloat(Self.Writer, Value) 
		End If
	End Method
	
	Method WriteDouble(Value:Double) 
		If UseCompression
			RN_BitStreamWriteCompressedDouble(Self.Writer, Value) 
		Else
			RN_BitStreamWriteDouble(Self.Writer, Value) 
		End If
	End Method
	
	Method WriteString(Value:String)  'A string with a length UNDER the size of a short.
		If Len(Value) <= 255
			RN_BitStreamWriteBool(Self.Writer, 0)      'The length will be written as a byte
			If UseCompression
				RN_BitStreamWriteCompressedUnsignedChar(Self.Writer, Len(value)) 
			Else
				RN_BitStreamWriteUnsignedChar(Self.Writer, Len(value)) 
			End If
		ElseIf Len(value) > 255
			RN_BitStreamWriteBool(Self.Writer, 1)       'The length will be written as a short
			If UseCompression
				RN_BitStreamWriteCompressedShort(Self.Writer, Len(value)) 
			Else
				RN_BitStreamWriteShort(Self.Writer, Len(value)) 
			End If
		End If
		Local I:Int
		If UseCompression
			For I = 0 To Len(value) - 1
				RN_BitStreamWriteCompressedUnsignedChar(Self.Writer, Asc(Value[I..I + 1] )) 
			Next
		Else
			For I = 0 To Len(value) - 1
				RN_BitStreamWriteUnsignedChar(Self.Writer, Asc(Value[I..I + 1] )) 
			Next
		End If
	End Method
	
'''Reading Commands
	Method ReadBool:Byte() 
		Return RN_BitStreamReadBit(Self.Reader) 
	End Method
	
	Method ReadByte:Byte() 
		If UseCompression
			Return RN_BitStreamReadCompressedUnsignedChar(Self.Reader) 
		Else
			Return RN_BitStreamReadUnsignedChar(Self.Reader) 
		End If
	End Method
	
	Method ReadShort:Short() 
		If UseCompression
			Return RN_BitStreamReadCompressedShort(Self.Reader) 
		Else
			Return RN_BitStreamReadShort(Self.Reader) 
		End If
	End Method
	
	Method ReadInt:Int() 
		If UseCompression
			Return RN_BitStreamReadCompressedInt(Self.Reader) 
		Else
			Return RN_BitStreamReadInt(Self.Reader) 
		End If
	End Method
	
	Method ReadLong:Long() 
		If UseCompression
			Return RN_BitStreamReadLong(Self.Reader) 
		Else
			Return RN_BitStreamReadCompressedLong(Self.Reader) 
		End If
	End Method
	
	Method ReadFloat:Float() 
		If UseCompression
			Return RN_BitStreamReadFloat(Self.Reader) 
		Else
			Return RN_BitStreamReadCompressedFloat(Self.Reader) 
		End If
	End Method
	
	Method ReadDouble:Double() 
		If UseCompression
			Return RN_BitStreamReadDouble(Self.Reader) 
		Else
			Return RN_BitStreamReadCompressedDouble(Self.Reader) 
		End If
	End Method

	Method ReadString:String() 
		Local S:Byte = Self.ReadBool() 
		Local S2:Int
		Local NewString:String
		Local I:Int
		If UseCompression = 0
			If S = 0
				s2 = (RN_BitStreamReadUnsignedChar(Self.Reader)) 
			Else
				s2 = (RN_BitStreamReadShort(Self.Reader)) 
			End If
			
			For I = 1 To s2
				NewString:+Chr(RN_BitStreamReadUnsignedChar(Self.Reader)) 
			Next
			Return NewString
		Else 'Compressed
			If S = 0
				s2 = (RN_BitStreamReadCompressedUnsignedChar(Self.Reader)) 
			Else
				s2 = (RN_BitStreamReadCompressedShort(Self.Reader)) 
			End If
			
			For I = 1 To s2
				NewString:+Chr(RN_BitStreamReadCompressedUnsignedChar(Self.Reader)) 
			Next
			Return NewString
		End If
	End Method

''''Misc Commands
	Method IgnoreBits(Length:Int) 
		RN_BitStreamIgnoreBits(Self.Reader, Length) 
	End Method
''''Info Commands
	Method Size_Bits:Int(Written:Byte = 1) 
		If Written
			Return RN_BitStreamGetNumberOfBitsUsed(Self.Writer) 
		Else
			Return RN_BitStreamGetNumberOfBitsUsed(Self.Reader) 
		End If
		Rem
			Returns the current length of the bitstream in Bits.
		end rem
	End Method
	
	Method Size_Bytes:Int(Written:Byte = 1) 
		If Written
			Return RN_BitStreamGetNumberOfBytesUsed(Self.Writer) 
		Else
			Return RN_BitStreamGetNumberOfBytesUsed(Self.Reader) 
		End If
		Rem
			Returns the current length of the bitstream in Bytes.
		end rem
	End Method
	
	Method Size_KiloBytes:Float(Written:Byte = 1) 
		If Written
			Return (RN_BitStreamGetNumberOfBytesUsed(Self.Writer) * 0.0009765625)     'bytes / 1024 basically.
		Else
			Return (RN_BitStreamGetNumberOfBytesUsed(Self.Reader) * 0.0009765625)    'bytes / 1024 basically.
		End If
		'Not sure about Blitzmax, but usually multiplication is faster than division
		Rem
			Returns the current length of the bitstream in Kb.
		end rem
	End Method
	
	Method UnreadBits:Int() 
		Return RN_BitStreamGetNumberOfUnreadBits(Self.Reader) 
		Rem
			Returns the remaining bits not yet read from the bitstream.
		end rem
	End Method
	
	Method Reset_Read_Cursor() 
		RN_BitStreamResetReadPointer(Self.Reader) 
	End Method
	
	Method Reset_Write_Cursor() 
		RN_BitStreamResetReadPointer(Self.Writer) 
	End Method
	
	Method Get_Reader_Pos:Int() 
		Return RN_BitStreamGetReadOffset(Self.Reader) 
		Rem
			Returns the current position. It's where the cursor is from your last read.
		end rem
	End Method
	
	Method ProcessMsgID(MsgId:Byte, Index:Int) 
		Select MsgID
			Case ID_CONNECTION_REQUEST_ACCEPTED 		'msgid = 13
				ConnectionAccepted(Index) 
			Case ID_REMOTE_CONNECTION_LOST 				'msgid = 14
				ConnectionLost(Index) 
				EasyRak_ConnectionLost(Index) 
			Case ID_ALREADY_CONNECTED 					'msgid = 15
				AlreadyConnected() 
			Case ID_NEW_INCOMING_CONNECTION				'msgid = 16
				NewConnectionAttempt(Index) 
				EasyRak_NewConnection(Index) 
			Case ID_NO_FREE_INCOMING_CONNECTIONS		'msgid = 17
				NoFreeIncomingConnections(Index) 
			Case ID_DISCONNECTION_NOTIFICATION			'msgid = 18
				DisconnectionNotice(Index) 
				EasyRak_Disconnected(Index) 
			Case ID_CONNECTION_LOST						'msgid = 19
				LostConnectionNotice(Index) 
			Case ID_RSA_PUBLIC_KEY_MISMATCH				'msgid = 20
				RSA_Key_MisMatch(Index) 
			Case ID_CONNECTION_BANNED					'msgid = 21
				Connection_Banned(Index) 
			Case ID_INVALID_PASSWORD					'msgid = 22
				Invalid_Password(Index) 
			Case ID_MODIFIED_PACKET						'msgid = 23
				Modified_Packet(Index) 
			
			'The rest is only used under different environments.
		End Select
	End Method
	
	
	
	
	
	'''''''''''''''''''''''Dealing with Internal raknet messages''''''''''''''''''''''''''''''
		
	Method ConnectionAccepted(Index:Int) 
		?Debug
			Print "-Connection Accepted"
		?
		Self.Connected = 1
	End Method
	
	Method ConnectionLost(Index:Int) 
		?Debug
			Print "-Connection Lost under index: " + Index
		?
		Self.Connected = 0
	End Method
	
	Method AlreadyConnected() 
		?Debug
			Print "-Already Connected! Application made an attempt to connect after already being connected."
		?
	End Method
	
	Method NewConnectionAttempt(Index:Int) 
		?Debug
			Print "-A new client is connecting (" + index + ") - "
		?
		Users.AddLast(String(index)) 
	End Method
	
	Method NoFreeIncomingConnections(Index:Int) 
		?Debug
			Print "-The server is not accepting new connections"
		?
	End Method
	
	Method DisconnectionNotice(Index:Int) 
		?Debug
			Print "-The connection from index:" + Index + " has been closed"
		?
		Self.Users.Remove(String(index)) 
	End Method
	
	Method LostConnectionNotice(Index:Int) 
		?Debug
			Print "-The connection from index:" + Index + " has been lost"
		?
		Self.Users.Remove(String(index)) 
	End Method
	
	Method RSA_Key_MisMatch(Index:Int) 
		?debug
			Print "-Preset an RSA Public key which doesn't match the server"
		?
	End Method
	
	Method Connection_Banned(Index:Int) 
		?debug
			Print "-Banned from server"
		?
	End Method
	
	Method Invalid_Password(Index:Int) 
		?debug
			Print "-Password has been refused from server"
		?
	End Method
	 
	Method Modified_Packet(Index:Int)    'Ban em!
		?debug
			Print "-Packet was modified by Id: " + Index
		?
	End Method
	
End Type


''For your use with disconnections
Function EasyRak_Disconnected(Index:Int) 
		
End Function

'For Your use with lost connections
Function EasyRak_ConnectionLost(Index:Int) 
	EasyRak_Disconnected(Index) 
End Function

'For your use with new connections
Function EasyRak_NewConnection(Index:Int) 
	
End Function



Creating a Simple Server:
Global MyRak:TBitstream = New TBitstream

MyRak.CreateServer() 


While Not KeyHit(KEY_ESCAPE) 
	If MyRak.IsDataAvailable()  'This actually does all the processing, along with checking if data is available.
		Select MyRak.MsgType 'MsgType is the id of the bitstream packet.
		
		End Select
	End If
Wend

MyRak.Destroy


A client is done the exact same way, but instead of createserver(), you'll use MyRak.Connect_To_Server().

Sending/Recieving Data has been made quite a bit simpler..

Sending:
Const MsgID_CharacterInfo:Byte = 120

Function SendCharacterInfo()
	'Create bit stream, and create it with a packet id.
	MyRak.Create_BitStream(MsgID_CharacterInfo) 
	MyRak.WriteByte(4)   'Character ID?
	MyRak.WriteString("John Doe")  'Character Name?
	MyRak.WriteBool(1)   '1 = Male, 0 = Female. This is a bit.
	MyRak.SendDataTo(Index)    'Sending data...
End Function



Recieving that sent code:
If MyRak.IsDataAvailable() 
	Select MyRak.MsgType
		Case MsgID_CharacterInfo
			Local id:Byte
			id = MyRak.ReadByte() 
			Character(id).Name = MyRak.ReadString() 
			Character(id).Sex = MyRak.ReadBool() 
	End Select
End If



You can either use EasyRak as a mod (you'll have to set that up, easily), or just an include. I was going to fix it up more, and include some examples/docs but i'm falling so far behind on things lately.

The methods within it should at least give some assistance to how things work, or can work.

Time


Alright I managed to figure out my issue, thanks Ovine.


Retimer, could you tell us what you did to fix this issue??

And great job for the wrapper's wrapper!! As soon you think you are close to a final version (maybe now?), I will include it in the official release...

Glad its working for you.

>Retimer, could you tell us what you did to fix this issue??

Correct me if im wrong but if you look thru his code :-

RN_SendBitStream(Interface, Self.Reader, Priority, Reliability, 0, RN_GetSystemAddressFromIndex(Interface, Index), 0) 


He is now sending to the client by using "RN_GetSystemAddressFromIndex" rather than directly from a stored systemaddress. (as this does change per packet received)

i.e. just store the clients connected index rather than an address.

Yes, I was just storing the systemaddress via packet everytime data was recieved before. Every time you send anything u must use

RN_GetSystemAddressFromIndex(Interface, Index)


for the address to deliver it correctly. Ovine was correct from the start, I just misunderstood him initially about addresses changing after packets are recieved; so I figured ide grab the address every time a packet was recieved for that index. It was an issue on my part. Sorry for that.

In the next couple weeks i'll try to find the time to setup some examples and throw together the updates i've made recently for it. The EasyRak now has an event handler, for dealing with events within RN, and a couple other fairly needed features.
This will make it so the EasyRak can be made into a module, to reduce compile time for projects that use it and so I can organize a system of examples/templates better.

I'm now using RN on my focused project, so like Ovine, I can vouch that it works, and extremely well. I previously wrote a simplified Enet wrapper and the comparisons in features and stability all head for raknet.

As for the stability...for anything less important, don't use HIGH_PRIORITY and RELIABLE_ORDERED. For unimportant packets, constant movement updates (in 3d, or non-tilebased 2d), medium/low priority and Unreliable settings should help improve network performance by a longshot.