RakNet wrapper for Blitz (open source project)

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

RepeatUntil(Posted 2007) [#1]
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


Filax(Posted 2007) [#2]
Good job repeat :) clear code :)


Stu_ovine(Posted 2007) [#3]
Fantastic stuff !


chi(Posted 2007) [#4]
great work... would be nice to see this for blitz3d ;)


Brucey(Posted 2007) [#5]
Note that this is windows only.


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


ImaginaryHuman(Posted 2007) [#6]
I guess the wrapping part of it is windows only?


RepeatUntil(Posted 2007) [#7]
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...


Apprauuuu(Posted 2007) [#8]
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??


RepeatUntil(Posted 2007) [#9]
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.


RepeatUntil(Posted 2007) [#10]
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??


North(Posted 2007) [#11]
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 :)


Stu_ovine(Posted 2007) [#12]
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.


RepeatUntil(Posted 2007) [#13]
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.


_33(Posted 2007) [#14]
Blitz3D version: http://www.blitzbasic.com/Community/posts.php?topic=50546


RepeatUntil(Posted 2007) [#15]
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).


Retimer(Posted 2008) [#16]
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.


RepeatUntil(Posted 2008) [#17]

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!).


Trader3564(Posted 2008) [#18]
How do i install RackNet for BlitzMax?


RepeatUntil(Posted 2008) [#19]
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...


Amon(Posted 2008) [#20]
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! :)


Retimer(Posted 2008) [#21]
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.


Gabriel(Posted 2008) [#22]
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.


RepeatUntil(Posted 2008) [#23]
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.


Retimer(Posted 2008) [#24]
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
format_code('
' BitStreams are wrapped. If you need them, add the functions here!
')

With

format_codebox('
' 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")

')


Trader3564(Posted 2008) [#25]
Retimer, what are you working on? online game?


Retimer(Posted 2008) [#26]
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.


ImaginaryHuman(Posted 2008) [#27]
Sounds like what I'm working on too :-D


ImaginaryHuman(Posted 2008) [#28]
What is a bit stream, like a regular byte stream but you can access any number of bits?


Retimer(Posted 2008) [#29]
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.

format_codebox('
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- 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 hide_email('repeatuntil@free.fr') (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.


RepeatUntil(Posted 2008) [#30]
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:
format_codebox('
/*'----------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- 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 hide_email('repeatuntil@free.fr') (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(Posted 2008) [#31]

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.


RepeatUntil(Posted 2008) [#32]

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!


Retimer(Posted 2008) [#33]
-edited.

Will post a better version later.


smilertoo(Posted 2008) [#34]
I'm getting an error :(

Compile Error
Identifier 'CompressedPackets' not found


Retimer(Posted 2008) [#35]
. (removed)


Retimer(Posted 2008) [#36]
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)

format_codebox('
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.


RepeatUntil(Posted 2008) [#37]
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...


Retimer(Posted 2008) [#38]
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.


Retimer(Posted 2008) [#39]
format_code('
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.


Retimer(Posted 2008) [#40]
Example showing that packets recieved from different clients returns the same address:

format_codebox('
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- 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 hide_email('repeatuntil@free.fr') (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;
format_codebox('
RN_API SystemAddress * _stdcall RN_PacketGetSystemAddress(Packet *packet)
{
return &packet->systemAddress;
}
')


return &rakPeerInterface
format_codebox('
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.


RepeatUntil(Posted 2008) [#41]
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!


Retimer(Posted 2008) [#42]
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).


Retimer(Posted 2008) [#43]
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)
format_codebox('
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


RepeatUntil(Posted 2008) [#44]
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...


Loktar(Posted 2008) [#45]
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.


Retimer(Posted 2008) [#46]
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.


RepeatUntil(Posted 2008) [#47]
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...


Stu_ovine(Posted 2008) [#48]
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


squareiris(Posted 2008) [#49]
Windows only = game over :/


Kev(Posted 2008) [#50]
fixed version of the .dll can be downloaded here, the fix handel's SystemAddress correct.

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


Stu_ovine(Posted 2008) [#51]
Nice one Kev !!!

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


t3K|Mac(Posted 2008) [#52]
thats great. i am near the point where i add UDP-network stuff to my game using this lib.

thats a community!


Stu_ovine(Posted 2008) [#53]
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

format_code('
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- 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 hide_email('repeatuntil@free.fr') (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


')


RepeatUntil(Posted 2008) [#54]
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.


Kev(Posted 2008) [#55]
RepeatUntil, i will email you the fixed source for the posted .dll for inclusion sometime today


RepeatUntil(Posted 2008) [#56]
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.


Kev(Posted 2008) [#57]
I will take a look the RN_GetSystemAddressFromIndex() call in the next couple of days.

Kev


Stu_ovine(Posted 2008) [#58]
Any news on the fix yet ? Looking at the code it is evident why its now broken....


Kev(Posted 2008) [#59]
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'
format_code('
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...

format_code('
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.


RepeatUntil(Posted 2008) [#60]
Then I am really confused!!!
Because I have added one simple line in the code (the example):
format_code('
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?


*(Posted 2008) [#61]
Take into account that the licence fee for RackNet is $100 for a indy project that sells. Its free for non-commercial applications tho.


Kev(Posted 2008) [#62]
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


Stu_ovine(Posted 2008) [#63]
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.

format_code('
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 :)


Kev(Posted 2008) [#64]
ok seems like this now works, download below

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

please post your results.

kev


RepeatUntil(Posted 2008) [#65]
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...


t3K|Mac(Posted 2008) [#66]
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!


Retimer(Posted 2008) [#67]
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.


Kev(Posted 2008) [#68]
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


Stu_ovine(Posted 2008) [#69]
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)

format_code('
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.

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


Kev(Posted 2008) [#70]
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


Stu_ovine(Posted 2008) [#71]
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.


Stu_ovine(Posted 2008) [#72]
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"


Kev(Posted 2008) [#73]

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!

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

')


Stu_ovine(Posted 2008) [#74]
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"


Stu_ovine(Posted 2008) [#75]
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.


RepeatUntil(Posted 2008) [#76]
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...


Retimer(Posted 2008) [#77]
Holy crap. That's awsome news!


Amon(Posted 2008) [#78]
Great News on making it a module. :)


AlexO(Posted 2008) [#79]
sounds like an awesome library, wish I had this when I did my last multiplayer game. Great to see it available to Blitzmax.


Retimer(Posted 2008) [#80]
Out of curiosity what would it take to get the rakvoice api working in the module?


Stu_ovine(Posted 2008) [#81]
Excellent stuff ! - off to play with it now.

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


Stu_ovine(Posted 2008) [#82]
Seems that sending a Broadcast produces an error

format_code('
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.


Stu_ovine(Posted 2008) [#83]
Seems that UNASSIGNED_SYSTEM_ADDRESS is not returning a systemaddress.

A quick fix to send a broadcast message :-

add this to raknet.cpp
format_code('
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

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

Use RN_SendBitStreamBroadcast() instead of RN_SendBitStream()


RepeatUntil(Posted 2008) [#84]
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...


Stu_ovine(Posted 2008) [#85]
will test now.

BTW Could you ask him to look at returning the IPaddress

format_code('
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....


Stu_ovine(Posted 2008) [#86]
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 :-
format_code('
SendTest(ClientPeer,UNASSIGNED_SYSTEM_ADDRESS,1)
')

Server talking directly to a client

A server talking directly to a client would use :-
format_code('
SendTest(ServerPeer,RN_GetSystemAddressFromIndex(Serverpeer,<id>),0)
')
<ID> being the players ID to send to (ID being the index 0 - maxusers)

or

format_code('
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.


Stu_ovine(Posted 2008) [#87]
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.


RepeatUntil(Posted 2008) [#88]
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 :-(


Stu_ovine(Posted 2008) [#89]
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 ?


Stu_ovine(Posted 2008) [#90]
Another wrapped function that is useful :-

In Raknet.cpp
format_code('

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

')

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


Returns a string containing a summary of the stats.

usage :-

format_code('

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


Retimer(Posted 2008) [#91]
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 ;-)


Apollonius(Posted 2008) [#92]
Looking forward to anything RakNet related in BLITZ!!! Tutorials and documentation included ;D


Retimer(Posted 2008) [#93]
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?


Stu_ovine(Posted 2008) [#94]
ReTimer .... dont store the systemaddress !!!!

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

format_code('
RN_GetSystemAddressFromIndex(Serverpeer,<id>)
')

to grab the correct systemaddress.

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


Retimer(Posted 2008) [#95]
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:
format_code('
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.


Stu_ovine(Posted 2008) [#96]
I have it working no problems here .


Try grabbing from the index rather than the Packet

i.e. Replace

format_code('
Self.CurrentAddress = RN_PacketGetSystemAddress(Self.Packet)
')

with

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


Retimer(Posted 2008) [#97]
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.


MrTAToad(Posted 2008) [#98]
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).


Xaron(Posted 2008) [#99]
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...


Retimer(Posted 2008) [#100]
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:
format_codebox('
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:
format_code('
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:
format_code('
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:
format_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


RepeatUntil(Posted 2008) [#101]

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...


Stu_ovine(Posted 2008) [#102]
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 :-

format_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.


Retimer(Posted 2008) [#103]
Yes, I was just storing the systemaddress via packet everytime data was recieved before. Every time you send anything u must use

format_code('
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.


Xaron(Posted 2010) [#104]
Hi all,

I've updated the Blitzmax raknet module from jimon/repeatuntil

The wrapper from the page above is still using version 3.2 of RakNet.

I've updated it to the latest version 3.8.2. You can download it here:

http://www.xaron.net/dl/bb/RakNetModule_382.zip

A small example is included. I've informed the author of that wrapper to put it on his page as well.

Please let me know when you find any bugs.

Thanks!


Naughty Alien(Posted 2010) [#105]
..very nice indeed..thanks..


RepeatUntil(Posted 2010) [#106]
Thanks Xaron, this is very nice to see the wrapper updated with one of the latest stable RakNet version!
The web page is up to date, I have linked your version!!
Cheers!

Last edited show_time('2010-11-27 03:34:27')


Tab(Posted 2010) [#107]
And here the version 3.82 for Blitz3D.

http://www.badmouse.cl/dev/RaknetWrapper_3.82_B3D.zip


RepeatUntil(Posted 2010) [#108]
Great! I have updated the "official" web page and put there your version!


Naughty Alien(Posted 2010) [#109]
..by the way, RakNet is not a free library, so I guess, for commercial use, it has to be purchased, regardless of use as a wrapper(module) , right ?

http://www.jenkinssoftware.com/


xlsior(Posted 2010) [#110]
..by the way, RakNet is not a free library, so I guess, for commercial use, it has to be purchased, regardless of use as a wrapper(module) , right ?


Correct.

Typically, the license info of the module should mention this, but even if they don't you are still bound by the raknet terms and conditions.


Blitzplotter(Posted 2010) [#111]
This looks a very capable polished looking networking app. Makes me feel like I've been attempting to network (with some success wirelessly over a bespoke ISP router) in Blitz3D using a fat crayon (;-).


Richard Betson(Posted 2012) [#112]
Hi,

Does anyone have an example or a method for using RakVoice?

Thanks,
- Rich -

Last edited show_time('2012-05-18 15:21:58')


Guy Fawkes(Posted 2012) [#113]
I'm with Richard. Does anyone have an example for using RakVoice in BlitzBasic?

Last edited show_time('2012-05-19 08:12:29')