GNet error

BlitzMax Forums/BlitzMax Programming/GNet error

Ghost Dancer(Posted 2007) [#1]
OK, I've rewritten my network code in GNet. Now I thought GNet seemed easy to use but I may have misunderstood some of the basic concepts as I am getting an error that I do not understand. I'll post the code, then explain the error.

Edit: code updated - see below

I get the following error (on the host) in the update() method (error line is marked):

Unhandled Exception: Assert failed

The error only shows in debug mode. If I comment out the error then I get the same error on the next GetGNetInt() command, so it looks like it will only let me do 1 GetGNetInt().

I'm guessing I've missed something obvious (I usually do). I have searched the forums but most examples seem to be out of date.


Ghost Dancer(Posted 2007) [#2]
OK, I think I've worked it out (finally). I was not taking into account that the object values were not changing (*hits himself on head*). So, for example, it was continually trying to connect once that value had been set.

I'm still have a few things to work out but if anyone is interested I'll post the code when it's done.


altitudems(Posted 2007) [#3]
Please do, as you mentioned most code related to Gnet is out of date.


Ghost Dancer(Posted 2007) [#4]
OK, np. I need to run some more tests on it, but once I'm happy with it I'll stick it in the code archives :)


altitudems(Posted 2007) [#5]
Thanks!


Ghost Dancer(Posted 2007) [#6]
Nuts, I thought I'd fixed it but hadn't used debug mode for a while and I'm getting exactly the same error as before ("Unhandled Exception: Assert failed" as noted in update method below) :-(

It all works when not using debug mode, except if you join a game, disconnect, then try to host, it crashes.

main code:
Framework BRL.GLMax2D
Import BRL.StandardIO
Import BRL.GNet

Strict

AppTitle = "Multiplayer test"

Include "multiplayer.bmx"

'custom indexes for net object
Const netind_startData = 10, netind_mouseData1 = 11, netind_mouseData2 = 12

Global multi:TMultiplayer = New TMultiplayer
Global notifyStart, gameStarted

Global mouse[2+1]
Local i, ipAddress$ = "127.0.0.1"

Graphics 640, 480


Repeat
	Cls
	
	DrawText "Ping: " + multi.getPing() + ", Connected: " + multi.isConnected(), 400, 10
	
	'escape resets everything
	If KeyHit(KEY_ESCAPE) Then
		multi.disconnect
		gameStarted = False
		notifyStart = False
	End If
	
	If gameStarted Then
		If multi.isConnected() Then
			DrawText "Game started", 10, 10
			
			DrawText "Press Esc to Disconnect", 10, 30
			
			For i = 1 To 2
				'show oponnent mouse status
				DrawText "Opponent mouse " + i + " = " + mouse[i], 10, 50 + (i*10)
				
				'set your mouse status in net object
				multi.setInt i + 10, MouseDown(i)
			Next
		Else
			notifyStart = False
			gameStarted = False
		End If
	Else
		Select multi.getConnectionType()
		Case netcon_none
			DrawText "Press H to Host, or J to Join", 10, 10
			
			If KeyHit(KEY_H) Then multi.startHost
			If KeyHit(KEY_J) Then multi.startClient
			
		Case netcon_client
			If multi.isConnected() = False ' Not connected
				DrawText "Press C to Connect to " + ipAddress$, 10, 10
				If KeyHit(KEY_C) Then multi.connectToHost(ipAddress$)
			Else
				DrawText "Waiting for host to start...", 10, 10
			End If
			
		Case netcon_host
			If multi.isConnected() = False ' Not connected
				DrawText "Waiting for opponent to join...", 10, 10
			ElseIf notifyStart Then
				DrawText "Client attempting to connect...", 10, 10
			Else
				DrawText "Press S to Start game", 10, 10
				If KeyHit(KEY_S) Then
					multi.setInt netind_startData, True		'send game info to client
					notifyStart = True
				End If
			End If
				
		End Select
	End If
	
	multi.update
	
	Delay 2	'free up some cpu time
	Flip
Until AppTerminate()

End


Function processObjects(remoteObj:TGNetObject)
	If GetGNetInt(remoteObj, netind_startData) And Not gameStarted Then
		gameStarted = True										'start game
		multi.setInt netind_startData, True					'notify other player
	Else
		'game data/events (we'll use mouse buttons to keep it simple)
		For Local i = 1 To 2
			mouse[i] = GetGNetInt(remoteObj, i + 10)			'get opponent mouse info
		Next
	End If
End Function


include file:
'connection types
Const netcon_none = 0, netcon_host = 1, netcon_client = -1

Type TMultiplayer
	Const netind_disconnect = 0, netind_connect = 1, netind_ping = 2	'other indexes should be set outside this module
	
	Field host:TGNetHost									'host type
	Field localObj:TGNetObject, remoteObj:TGNetObject		'net objects
	Field objList:TList 									'list of received, remote objects

	Field port = 8086, timeout = 2500
	Field conType, connected, ping, lastPing, currentMs, lastMs, pingTimer, displayPing
	
	
	'reset vars & objects for new connection
	Method resetConnection()
		'close old host if created
		If objList <> Null ClearList objList
		If localObj <> Null Then
			CloseGNetObject localObj
			localObj = Null
		End If
		If host <> Null Then
			CloseGNetHost host
			host = Null
		End If
		
		GCCollect
		
		'create new objects (thus clearing any old values)
		host = CreateGNetHost()
		localObj = CreateGNetObject:TGNetObject(host)
		objList = New TList
		
		'clear ping data
		ping = 0
		lastPing = 0
		displayPing = 0
	End Method
	
	
	Method startHost()
		conType = netcon_host
		resetConnection
		
		If Not GNetListen(host, port) Then
			conType = netcon_none
			RuntimeError "GNetListen failed"
		End If
	End Method
	
	
	Method startClient()
		conType = netcon_client
		resetConnection
	End Method
	
	
	'connect to host (used by client)
	Method connectToHost(ip$)
		If conType = netcon_client Then
			If GNetConnect(host, ip$, port, timeout) Then
				setInt netind_connect, True		'send connect notification to other player
			Else
				conType = netcon_none
				RuntimeError "GNetConnect failed"
			End If
		End If
	End Method
	
	
	Method setInt(index, data)
		SetGNetInt localObj, index, data
	End Method
	
	
	'listen for join request
	Method update()
		If conType <> netcon_none Then
			GNetSync host ' send to other instance & get updates
			
			'iterate through net objects & process
			objList = GNetObjects(host, GNET_MODIFIED)
			
			For remoteObj = EachIn objList
				'check for connection notification
				If GetGNetInt(remoteObj, netind_connect) And Not connected Then
					setInt netind_connect, True		'send notification back
					connected = True
				End If
				
				'check for disconnect
				If GetGNetInt(remoteObj, netind_disconnect) Then          '*** error here ***
					disconnect
				End If
				
				'custom processing (define function in external code)
				processObjects(remoteObj)
				
				'get ping data
				currentMs = GetGNetInt(remoteObj, netind_ping)
				
				If currentMs <> lastMs Then
					'remote ping has changed - update vars
					lastMs = currentMs
					
					lastPing = MilliSecs()
				End If
			Next
			
			If connected Then
				'send current ms to remote player
				setInt netind_ping, MilliSecs()
				
				'calc current ping
				If lastPing > 0 Then ping = MilliSecs() - lastPing
					
				'calc new ping every second
				If MilliSecs() - pingTimer >= 1000 Then
					displayPing = ping

					'update ping timer
					pingTimer = MilliSecs()
				End If
				
				'check for timeout
				If ping > timeout Then disconnect
			End If
		End If
	End Method
	
	
	Method getPing()
		Return displayPing
	End Method
	
	
	Method getConnectionType()
		Return conType
	End Method
	
	
	Method isConnected()
		Return connected
	End Method
	
	
	Method disconnect()
		'notify remote player
		setInt netind_disconnect, True
		GNetSync host
		
		'disconnect
		conType = netcon_none
		connected = False
		
		displayPing = 0
	End Method
End Type


My brain hurts now, so I'm going to come back to it tomorrow. If anyone can help it would be most appreciated.


Dreamora(Posted 2007) [#7]
Which assert is actually failing? Because this should give you the answer to your problem. (assert = Runtime assumption of variables and their state that must be met or will the app will fail. They are removed for release build and thus very powerfull and important when hunting bugs)


Ghost Dancer(Posted 2007) [#8]
The error occurs on the following line:

If GetGNetInt(remoteObj, netind_disconnect) Then


The remoteObj must exist since a different index of it is refernced a few lines above in the same loop on the following line:

If GetGNetInt(remoteObj, netind_connect) And Not connected Then


The way I understand GNet is that an object is created with 32 slots, so if one index is there, so should the other, right?


Ghost Dancer(Posted 2007) [#9]
Ah, after doing a little testing, I have discovered that the index must be created before accessing it. Running the following code at the start prevents this from happening:

For Local i = 0 To 31
	SetGNetInt localObj, i, 0
Next


Now that's sorted, I can get back to the problem I was trying to fix when all this cropped up...


Ghost Dancer(Posted 2007) [#10]
OK, I have finally got the beast working. Thanks for your help Dreamora - it was the first time I had come across that type of error.

I have put the final version in the code archives in case it is of use to anyone else.


Uncle Ho(Posted 2007) [#11]
Very nice.

But can anyone tell me if and how it is possible to connect multiple players (more than 2) to gNet?
i never managed to get this to work.