Raknet
BlitzMax Forums/BlitzMax Beginners Area/Raknet
| ||
The examples put together by Zeke initially work fine, but I have a couple of problems. I thought I'd try sending a constant stream of data to see how it handles it, so I simply removed the keyboard input from the Zeke_client program, so that it's sending the 6 bits of information continually. This immediately locks-up the server, which remains locked-up even after turning off the client. Bearing in mind that both client and server have a Delay 5 on each loop, it should only be sending 6 pieces of information, 200 times per second. That really doesn't sound like a huge amount of information and shouldn't be locking up the server, should it? I haven't altered the tutorials at all, only removed the If KeyHit(KEY_SPACE) Then / Endif lines. |
| ||
MaxGui is not so fast and thats why server "freeze".. but if you replace Addlog function in server code to this it works: Function Addlog(text:String) AddTextAreaText(txtlog , text + "~n") PollSystem() End Function |
| ||
Ah yes, it's just MaxGUI, that's a relief. I don't need to use MaxGUI for my server anyway so that's cool, and the fix works :) |
| ||
Still having a similar problem though. When sending the information both ways - i.e from server to client AND client to server (just a packet of 6 random numbers), it sends for about 2 seconds, then both sides just stop receiving. I think the problem is in the line .... interface.SendBitStream(bitstream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, True) I'm not sure what unassigned_system_address does here. From what I remember of using Raknet in B3D, that was the 'address' of the recipient. I'm using that line on both server and client and they do seem to receive the info, then they both just stop. In B3D, what I did was to store the 'ID' of each client after they connected, then use that when sending information to them. So unassigned_system_address was RN_PacketGetplayerID(packet) (to retreive the client's details directly from the packet and then use that to reply with some information). Hmmm, so anyway, how do I store each connections 'ID' so that I can send information specifically to each connection? And what do I use instead of 'unassigned_system_address' to send information BACK to the server? I've tried trawling through the Raknet documents but I find it very hard to understand. Once I know how to send/receive with both server and client I really don't intend to use anything more advanced in Raknet. |
| ||
when client connect to server, you can get client ID using:local clientID:TRKSystemAddress=packet.GetSystemAddress() and use that clientid instead UNASSIGNED_SYSTEM_ADDRESS. ( and change last True value to False, that value tells if we send stream to all connected clients (broadcast)) so quick help: Server: Send packet to ALL clients use: interface.SendBitStream(bitstream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, True) Send packet to only one client use: interface.SendBitStream(bitstream, HIGH_PRIORITY, RELIABLE, 0, clientID, False) Client: Send packet to server interface.SendBitStream(bitstream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, True) |
| ||
Excellent, thank you. Basically I just need to change my B3D syntax to the new Blitzmax syntax, but it does look very similar. Thanks for your help. |
| ||
Ok, that works too, but I still have the problem that communication seems to stop completely after about 2 seconds. I've altered your Zeke_Server and Zeke_Client slightly - mostly just moved stuff into functions. But also, both server and client send the packet to each other, 10 times per second. They then just print out the information on the screen. It seems to be working fine, but then it just stops receiving, although they don't lock up now (that random number at the top is just to show it's not locked up). Here's the programs...... Server..... SuperStrict Import bah.raknet AppTitle ="Server" 'GUI Graphics 300,200 'globals Global interface:TRKRakPeerInterface Global clientid:TRKSystemAddress StartServer() ' #################################### While Not (KeyHit(KEY_ESCAPE) Or AppTerminate()) Cls DrawText Rand(9),0,0 NetWork() SendToClient() Flip Delay 100 Wend ' #################################### If interface interface.Shutdown(300) TRKRakNetworkFactory.DestroyRakPeerInterface(interface) EndIf Function NetWork() If Not interface Then Return Local packet:TRKPacket packet = interface.Receive() If Not packet Then Return Local packetid:Int = packet.GetPacketIdentifier() Select packetid Case ID_NEW_INCOMING_CONNECTION 'Addlog "New Client connected to server, IP = " + packet.GetSystemAddress().ToString() clientID:TRKSystemAddress=packet.GetSystemAddress() Case ID_DISCONNECTION_NOTIFICATION 'Addlog "Client disconneced IP=" + packet.GetSystemAddress().ToString() Default Local bitstream:TRKBitStream = TRKBitStream.CreateFromData(packet.GetData(), packet.GetLength(), 0) Local _Byte:Byte Local _Short:Short Local _Int:Int Local _long:Long Local _float:Float Local _double:Double bitstream.ReadByte(_byte) bitstream.ReadShort(_short) bitstream.ReadInt(_int) bitstream.ReadLong(_long) bitstream.ReadFloat(_float) bitstream.ReadDouble(_double) DrawText _byte,10,50 DrawText _short,10,70 DrawText _Int,10,90 DrawText _long,10,110 DrawText _float,10,130 DrawText _double,10,150 End Select interface.DeallocatePacket(packet) End Function Function StartServer() 'init interface = TRKRakNetworkFactory.GetRakPeerInterface() clientid = UNASSIGNED_SYSTEM_ADDRESS 'start server Local sd:TRKSocketDescriptor = New TRKSocketDescriptor.Create(7777) Local result:Int = interface.Startup(5, 30, sd) interface.SetMaximumIncomingConnections(5) If result 'Addlog "Server started" Else 'Addlog "Server failed to start." End End If interface.SetOccasionalPing(True) End Function Function SendToClient() Local bitstream:TRKBitStream = New TRKBitStream.Create() Local_byte:Byte=rand(255) Local _short:Short = Rand(2000) Local _int:Int = Rand(20000) Local _long:Long = Rand(10000000) Local _float:Float = Rnd(100000) Local _double:Double = Rand(10) Local bit:Byte=1 bitstream.WriteByte(_byte) bitstream.WriteShort(_short) bitstream.WriteInt(_int) bitstream.WriteLong(_long) bitstream.WriteFloat(_float) bitstream.WriteDouble(_double) 'send packet interface.SendBitStream(bitstream, HIGH_PRIORITY, RELIABLE, 0, clientID, False) End Function Client SuperStrict Import bah.raknet AppTitle = "Client" Graphics 300, 200 Global interface:TRKRakPeerInterface Global clientid:TRKSystemAddress Global cstate:Int 'connectstate Global connectstate:String[] = ["Disconnected", "Connecting", "Connected", "Disconnecting", "Failed to connect server"] Connect() While Not (KeyHit(KEY_ESCAPE) Or AppTerminate()) Cls DrawText Rand(9),0,0 SendToServer() NetWork() Flip Delay 100 Wend 'Shutdown If interface interface.Shutdown(300) TRKRakNetworkFactory.DestroyRakPeerInterface(interface) EndIf Function Connect() interface = TRKRakNetworkFactory.GetRakPeerInterface() Local sd:TRKSocketDescriptor = New TRKSocketDescriptor.Create(0) interface.Startup(1, 30, sd) interface.SetOccasionalPing(True) Local result:Int = interface.Connect("localhost", 7777) If Not result Then Print "Unable to connect server" End If cstate = 1 'connecting End Function Function Network() If cstate = 4 Then Return If Not interface Then Return 'Handle packets Local packet:TRKPacket = interface.Receive() If Not packet Then Return Local packetid:Int = packet.GetPacketIdentifier() Select packetid Case ID_CONNECTION_ATTEMPT_FAILED 'Notify "Unable to connect server..." cstate = 4 'unable to connect Case ID_CONNECTION_REQUEST_ACCEPTED 'Notify "Connected to server " + packet.GetSystemAddress().ToString() cstate = 2 'connected Default DrawText "Received",50,50 Local bitstream:TRKBitStream = TRKBitStream.CreateFromData(packet.GetData(), packet.GetLength(), 0) Local _Byte:Byte Local _Short:Short Local _Int:Int Local _long:Long Local _float:Float Local _double:Double bitstream.ReadByte(_byte) bitstream.ReadShort(_short) bitstream.ReadInt(_int) bitstream.ReadLong(_long) bitstream.ReadFloat(_float) bitstream.ReadDouble(_double) DrawText _Byte,10,50 DrawText _Short,10,70 DrawText _Int,10,90 DrawText _Long,10,110 DrawText _Float,10,130 DrawText _Double,10,150 End Select interface.DeallocatePacket(packet) End Function Function SendToServer() If cstate = 2 'connected Local bitstream:TRKBitStream = New TRKBitStream.Create() Local _byte:Byte=Rand(255) Local _short:Short = Rand(200) Local _int:Int = Rand(200) Local _long:Long = Rand(100000) Local _float:Float = Rnd(100) Local _double:Double = Rand(1) bitstream.WriteByte(_byte) bitstream.WriteShort(_short) bitstream.WriteInt(_int) bitstream.WriteLong(_long) bitstream.WriteFloat(_float) bitstream.WriteDouble(_double) 'send packet interface.SendBitStream(bitstream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, True) End If End Function Is it perhaps something to do with not deallocating a packet somewhere? Or is Raknet just becoming overloaded? Or have I made a more basic error in the code somewhere? |
| ||
ah.. got it.. first BYTE what you write to bitstream is "packetID" right now raknet use first 109 packet id.. and first "free" packet id starts from 110.. BUT there is constant variable (declarend in common.bmx) ID_USER_PACKET_ENUM and i set that value to 150 (if in the future raknet want to use more packetid:s) this packetID is BYTE and readed FIRST.. and because this byte can only handle 0-255 bytes.. and first free packetid is 150, so you have available only 105 packetid for YOUR packets (move,shoot,chat,etc..) Server: Client: |
| ||
Ah, thank Goodness I asked because I would have never worked that out on my own! It works fine now...... seems to work perfectly even with Delay 1 instead of Delay 5 or 100. So, should I always add bitstream.WriteByte(ID_SendData) as the first byte when sending data? Is it only when sending bitstreams? |
| ||
yeah. first byte what to write bitstream is that "packet ID".. and that byte MUST be =>ID_USER_PACKET_ENUM and only when you send bitstreams. i dont know if there is better way to handle your own packet id:s what i use. but this is what i use and this works.. this also catch invalid packet ids... i use delay 5 when coding and debugging... or if i see that cpu usage is high... but its not needed.. also if you want more speed: change: Local result:Int = interface.Startup(5, 30, sd) '=> 30 to 0 (thats 30 is raknet internal delay. now its 30ms.. ) today i also made some tests, when reading bitstreams is similar like bmax streams.. like mybyte:byte=bitstream.readbyte() i made this earlier.. but changed back to original bruceys method bitstream.readbyte(mybyte).. but now this works well.. and i also wanted to use bitstream.writeint(200) <= its not possible right now.. because bah.raknet is coded that way.. but i made changes and it works also pretty well.. im still testing.. and trying to add writestring functions... but what do you like to use: original: local mybyte:int,myint:int bitstream.readbyte(mybyte) bitstream.readbyte(myint) local intseven:int=7777 bitstream.writeint(intseven) or like bmax: local mybyte:byte=bitstream.readbyte() local myint:byte=bitstream.readint() bitstream.writeint(7777) |
| ||
Are you saying there's no working Writestring yet? The Bmax version above looks better, just because it's shorter :) |
| ||
. |
| ||
no writestring right now.. this is right now quick solution: 'Sending: Rak_WriteString(bitstream,"Hello World!") Rem bbdoc: Write string (max 255 chars) End Rem Function Rak_WriteString(bitstream:TRKBitStream , text:String) bitstream.WriteByte(text.Length) 'or WriteShort/WriteInt For Local i:Int = 0 Until text.Length bitstream.WriteByte(text[i]) Next End Function 'Reading: Local mystring:String=Rak_ReadString(bitstream) Rem bbdoc: Read String (Max 255 chars) End Rem Function Rak_ReadString:String(bitstream:TRKBitStream) Local strlen:Int = bitstream.ReadByte() 'or WriteShort/WriteInt Local str:String For Local i:Int = 0 Until strlen str:+ Chr(bitstream.ReadByte() ) Next Return str End Function |
| ||
Sweet thanks. I was going to say it should be possible to do it character by character, but that saves me the need to do that :) I'll keep my eyes open for upgrades, but will use your functions in the meantime. |
| ||
Also, regarding disconnecting. If my client just disconnects, I assume the server has no idea that's happened, so I need to write my own disconnect routine? i.e If the client switches off, do I just send ID_DISCONNECTION_NOTIFICATION to the server? |
| ||
when client close(normal way) i use this:Method CloseConnection() If interface interface.Shutdown(300) TRKRakNetworkFactory.DestroyRakPeerInterface(interface) EndIf interface = Null End Method and that Shutdown send ID_DISCONNECTION_NOTIFICATION to server.. so you dont need to send that. also if client crashed. there is some seconds delay when server see that client is disconnected and server got that disconnection id. |
| ||
That's the code I'm currently using to shut down my client (my code is still mostly your server/client example but I'm expanding/changing it as I go along), but the server doesn't seem to receive anything. I've even put a simple 'End' after the server receives ID_DISCONNECTION_NOTIFICATION but it doesn't respond - meaning it isn't receiving it? |
| ||
Any idea what's wrong with the code below? When my client initially connects, I'm storing TRKSystemAddress=packet.GetSystemAddress() in a type, in a list. So then, when my client sends something to the server, I can identify which client sent it using the code below... Local ClientID:TRKSystemAddress = packet.GetSystemAddress() Local C:Client = GetClient(ClientID) Function GetClient:Client(ClientID:TRKSystemAddress) Local C:Client If Not ClientsList Then Return Null For C = EachIn ClientsList If C.id = ClientID Then Exit Next Return C End Function There are no errors, but the function always just returns the first client. When I run it through the debugger, the line 'If C.id = ClientID Then Exit' always seems to be true, even when the numbers don't match. Am I doing something wrong here. Or do you have a version of this function already written Zeke? |
| ||
I think the problem is probably that I shouldn't be storing TRKSystemAddress, but something else. Looking back at my old B3D code with Raknet, I was storing RN_PacketGetplayerIndex(packet). Is there an equivalent of RN_PacketGetPlayerIndex now? |
| ||
use:Local ClientGuid:TRKRakNetGUID = packet.GetGuid() and then it should work. and use it like this: Function GetClient:Client(GUID:TRKRakNetGUID) Local C:Client For C = EachIn clients If C.GUID.ToString() = GUID.ToString() Then Return C Next End Function |
| ||
Thank you, works perfectly now :) |
| ||
updated Raknet version http://www.blitzmax.com/Community/posts.php?topic=87434#1007510 |