Network library with guaranteed UDP?

BlitzMax Forums/BlitzMax Programming/Network library with guaranteed UDP?

Any good cross-platform bmx libraries out there?

gnet or BNetEx

I can't seem to find BNetEx. All links I can find are dead?

I don't think gnet has garanteed UDP, or ??? (as it is based on ENET, maybe it's implemented ?)

BNetEx

Bnet only supports unreliable udp. You would need to code an ack type system for safe udp.

Checked out enet. It has guaranteed UDP and looks pretty cool actually. With bandwidth control and stuff.
I'll look into it some more and get back to you :)

isnt the point of UDP is that its not guaranteed? just fire and forget and hope it gets there.

Yes and no.

The main reason to use UDP is that you can enable guaranteed only on important messages but not on unimportant stuff.
That way you can have high frequency where needed but as well guaranteed receive where needed (login message for example)

I wrapped ENet in a simple class in about 10 mins and it works like a charm :)

Enet is ALREADY wrapped with BlitzMax !!! This was done by Mark Sibly 6 months ago, and used in gnet. However, I am not sure if it was 100% wrapped??

GNet is not what I was looking for ;)

It's not a 100% wrapped, the ping functions among others are missing.
I might have a go at it later, but for now my own wrapper is just what I need :)

are you going to post it for us?

Never done anything multiplayer, but Wave's TNet:

http://www.truplo.com/TNet/

Dunno about guaranteed UDP, it says "reliable". :)

It's not reliable.

Here's my wrapper.
You'll still need the occasional ENet function tho.


SuperStrict

' ENet wrapper on top of ENet by Odin Jensen (Some borrowing from gnet ;)
' Inherit and override On* funcs to get it off the road :)
Type TENetModule

	' ENet host
	Field _enetHost:Byte Ptr
	
	' Events list
	Field _enetEvents:TList=New TList
	
	' Current unique ID
	Field _uniqueID:Long = 0
	
	' Start server at given port
	Method Host%(port%, maxClients% = 32, incomingLimit% = 0, outgoingLimit% = 0)
	
		' Create server 
		Local addr:Byte Ptr=enet_address_create(ENET_HOST_ANY, port)
		_enetHost=enet_host_create(addr, maxClients, incomingLimit, outgoingLimit)
		enet_address_destroy(addr)
		
		' Failed?
		If (Not _enetHost)
		
			Return False
		
		End If
	
		' All went well
		Return True
		
	End Method
	
	' Connect to server at given address/port
	Method Connect%(address:String, port%, timeout%=10000, incomingLimit% = 0, outgoingLimit% = 0)
	
		' Create client host
		_enetHost=enet_host_create(Null, 32, incomingLimit, outgoingLimit)
		
		' Failed?
		If (Not _enetHost)
		
			Return False
			
		End If
		
		' Attempt connection
		Local addr:Byte Ptr=enet_address_create(HostIp(address),port)
		Local peer:Byte Ptr=enet_host_connect(_enetHost,addr,1)
		enet_address_destroy(addr)
		If (Not peer)
		
			Return False
			
		End If
		
		timeout:+MilliSecs()
		
		While (timeout-MilliSecs() > 0)
		
			UpdateENetEvents(0)
			
			For Local ev:ENetEvent=EachIn _enetEvents
			
				If (ev.event=ENET_EVENT_TYPE_CONNECT And ev.peer=peer)
					
					OnConnect(ev)
					_enetEvents.Remove(ev)
					Return True
					
				EndIf
				
			Next
			
		Wend
	
		' No go bub
		Return False
		
	End Method
		
	' Disconnect
	Method Disconnect(peer:Byte Ptr)
	
		enet_peer_disconnect(peer)
		
	End Method
	
	' Get unique ID
	Method GetUniqueID%()
	
		_uniqueID:+1
		Return _uniqueID
	
	End Method
	
	' Send packet
	Method Send%(peer:Byte Ptr, data:Byte Ptr, dataLen%, reliable%=True)
		
		' Which flag?
		Local flag% = ENET_PACKET_FLAG_RELIABLE
		
		' Unrealiable packet requested?
		If (Not reliable)
		
			flag = 0 ' This correct? Need to check ENet source one day :)
		
		End If
	
		' Build packet
		'Local buf:Byte Ptr=MemAlloc(dataLen)
		'MemCopy(buf, data, dataLen)
		Local packet:Byte Ptr=enet_packet_create(data, dataLen, flag)
		
		'MemFree(buf)
		
		' Attempt send
		If (enet_peer_send(peer, 0, packet) < 0)
		
			Return False
			
		End If
		
		' All went well
		Return True 
		
	End Method

	' Shutdown
	Method Shutdown()
	
		' Destroy ENet stuff
		enet_host_flush(_enetHost)
		enet_host_destroy(_enetHost)
	
	End Method
	
	' Update ENet events
	Method UpdateENetEvents(timeout%=0)
	
		' Loop as long as there's messages waiting in line
		Repeat
		
			Local ev:ENetEvent=New ENetEvent
			If (Not enet_host_service(_enetHost,ev,timeout)) Return
			_enetEvents.AddLast(ev)
			
		Forever
		
	End Method
	
	' Update
	Method Update(timeout%=0)
	
		' Get messages
		UpdateENetEvents(timeout)

		' Loop until no more packets left		
		Repeat	
			
			' Time to leave eternal loop?	
			If (_enetEvents.IsEmpty()) Return
			
			' Get next event
			Local ev:ENetEvent=ENetEvent(_enetEvents.RemoveFirst())
		
			' Check out event type
			Select(ev.event)
				Case ENET_EVENT_TYPE_CONNECT	
					OnConnect(ev)		
				Case ENET_EVENT_TYPE_DISCONNECT
					OnDisconnect(ev)
				Case ENET_EVENT_TYPE_RECEIVE
					OnDataRecieved(ev)
			End Select
				
		Forever
	
	End Method
	
	' Called on new connection
	Method OnConnect(ev:ENetEvent) Abstract
	
			
	' Called on disconnect
	Method OnDisconnect(ev:ENetEvent) Abstract
	
	' Called when data recieved (Remember to enet_packet_destroy() packet, when you're done!)
	Method OnDataRecieved(ev:ENetEvent) Abstract

End Type




So you need to call update and you get callbacks when stuff happens.
This might come in handy too:

SuperStrict

' Network packet for easier handling of banks (C)2006 Odin Jensen
Type TNetPacket

	Field bank:TBank
	Field curOffset%=0

	' Init packet
	Method Init(size%=512)
	
		Self.bank = CreateBank(size)
	
	End Method
	
	' Rewind
	Method Rewind()
	
		curOffset = 0
	
	End Method
	
	' Bank to string
	Method BankToString:String(bank:TBank)
	
		Local ret:String = ""
		For Local i:Int = 0 To BankSize(bank)-1
		
			ret:+Chr(PeekByte(bank, i))
		
		Next
		
		Return ret
	
	End Method
	
	' Create from ENet packet
	Method FromENetPacket(packet:Byte Ptr)
	
		Local buf:Byte Ptr=enet_packet_data( packet )
		Local size%=enet_packet_size( packet )
		
		ResizeBank(Self.Bank, size)
		MemCopy(Lock(), buf, size)
		Unlock()
		
		Rewind()
	
	End Method
		
	' Get offset
	Method GetOffset%()
	
		Return curOffset		
	
	End Method
	
	' Get size
	Method GetSize%()
	
		Return BankSize(bank)
		
	End Method
	
	' Lock it
	Method Lock:Byte Ptr()
	
		Return LockBank(bank)
		
	End Method
	
	' Unlock
	Method Unlock()
	
		UnlockBank(bank)
	
	End Method
	
	' Write integer
	Method WriteInt(value%)
		
		If (curOffset+4 >= GetSize())
		
			ResizeBank(bank, GetSize()+8)
			DebugLog("Bank resize!")
		
		End If
	
		PokeInt(bank, curOffset, value)
		curOffset:+4
	
	End Method
	
	' Write string
	Method WriteString(value:String)
	
		Self.WriteInt(value.length)
		
		If (curOffset+value.length >= GetSize())
		
			ResizeBank(bank, GetSize()+(value.length*2))
			DebugLog("Bank resize!")
		
		End If
		
		For Local i:Int = 0 To value.length
			
			PokeByte(bank, curOffset+i, value[i])
		
		Next
		curOffset:+value.length
		
	End Method
	
	' Write float
	Method WriteFloat(value:Float)
	
		If (curOffset+4 >= GetSize())
		
			ResizeBank(bank, GetSize()+8)
			DebugLog("Bank resize!")
		
		End If
	
		PokeFloat(bank, curOffset, value)
		curOffset:+4
		
		'DebugLog("NetPacket: Wrote float (" + value + ")")
	
	End Method
	
	' Read integer
	Method ReadInt%()
	
		Local ret%=PeekInt(bank, curOffset)
		curOffset:+4
		Return ret
	
	End Method
	
	' Read string
	Method ReadString:String()
	
		Local size% = Self.ReadInt()
		Local ret:String = ""
		For Local i:Int = 0 To size-1
			
			ret:+Chr(PeekByte(bank, curOffset +i))
		
		Next
		curOffset:+size
		
		Return ret
	
	End Method
	
	' Read float
	Method ReadFloat#()
	
		Local ret:Float = PeekFloat(bank, curOffset)
		curOffset:+4
		'DebugLog("NetPacket: Read float (" + ret + ")")
		Return ret
	
	End Method

End Type


Send with


' Send it good
SendPacket.Rewind()
SendPacket.WriteInt(SOME_PACKET_ID)
SendPacket.WriteString("Hello!")
Send(player.peer, SendPacket.Lock(), SendPacket.GetOffset())
SendPacket.Unlock()



The peer is found in the event structure you get on the callbacks.
For futher questions, don't hesitate to ask :)

oops!

I'd wondered about the "reliable packet" option in GNet ever since it was mentioned that it uses ENet/UDP, so thanks for your ENet wrapper/GNet extender, ozak. I've been a fan of UDP's optional-reliability nature ever since using Surreal's BlitzPlay with Blitz3D.

Unless you're writting an application that really ought to use TCP, you don't really need reliable UDP. Sequential is usually good enough.