Multiplayer Games?

BlitzMax Forums/BlitzMax Beginners Area/Multiplayer Games?

I would like to play around with making a multiplayer game. I would be working with two computers on the same network. (No internet stuff) What is the best way to go about this?

Examples and Tutorials would be nice because I have no expierence in network games.

Does this help?

Why do you need an address for gnetconnect but not gnetlisten? And what is up with 127.0.0.1? And can the port be anything?

Because GnetListen listens on the port set during GnetConnect.
127.0.0.1 is the IP for LocalHost.
Some ports numbers are used by specific applications.

I want to make a game like the one below. The code is from an old BlitzPlus Program. I want to connect 2+ computers that are on a LAN. Any ideas?

;Very simple demo showing the basics of a network game
; Verified 1.48 compliant: 4/18/2001
AppTitle "Blitz Multiplayer demo"

Const width=640,height=480

Global send_freq=5	;send every fifth update
Global smoothing=5
Global Ping_time

Type Info
	Field txt$
End Type

Type Player
	Field x#,y#,r#		;where ship appears on screen
	Field dx#,dy#,dr#	;speeds - (recvd pos-current pos)/smoothing
	Field name$,net_id
	
End Type

If Not StartNetGame() Then End

Graphics width,height

send_cnt=1

;get player name
Repeat
	Cls
	Color 0,48,0
	For x=0 To width-1 Step 32
		Rect x,0,1,height
	Next
	For y=0 To height-1 Step 32
		Rect 0,y,width,1
	Next
	Color 255,255,255
	
	name$=Input$( "Player name? " )
Until name$<>""

;create a local player
Global player.Player=New Player
player\x=width/2
player\y=height/2
player\r=0
player\name=name$
player\net_id=CreateNetPlayer( name$ )

Global chat$

SetBuffer BackBuffer()

While Not KeyDown(1)

	UpdateNetwork()
	
	send_cnt=send_cnt-1
	If send_cnt=0
		send_cnt=send_freq
		send=True
	Else
		send=False
	EndIf
	
	UpdatePlayers( send )
	
	RenderAll()
	
	Flip
Wend

End

;update incoming network messages...
Function UpdateNetwork()
	While RecvNetMsg()
		Select NetMsgType()
		Case 1:
			p.Player=FindPlayer( NetMsgFrom() )
			If p<>Null Then UnpackPlayerMsg( NetMsgData$(),p )
		Case 2:
			info( NetPlayerName$( NetMsgFrom() )+":"+NetMsgData$() )
		Case 3:
			SendNetMsg 4,"Pong!",player\net_id,0,0
		Case 4:
			t=MilliSecs()-Ping_time
			info( "Ping: "+t+"ms" )
		Case 100:
			p.Player=New Player
			p\net_id=NetMsgFrom()
			p\name=NetPlayerName$( NetMsgFrom() )
			info( p\name+" has joined the game. " )
		Case 101:
			p.Player=FindPlayer( NetMsgFrom() )
			If p<>Null
				info( p\name+" has left the game. " )
				Delete p
			EndIf
		Case 102:
			info( "I'm the new host! " )
		Case 200:
			EndGraphics
			Print "The session has been lost!"
			WaitKey
			End
		End Select
	Wend
End Function

Function UpdatePlayers( send )

	If KeyHit(59)
		Ping_time=MilliSecs()				
		SendNetMsg 3,"Ping!",player\net_id,0,0
	EndIf
	If KeyHit(60) And send_freq>0 Then send_freq=send_freq-1
	If KeyHit(61) Then send_freq=send_freq+1
	If KeyHit(62) And smoothing>0 Then smoothing=smoothing-1
	If KeyHit(63) Then smoothing=smoothing+1
	
	For p.Player=Each Player
		If NetPlayerLocal( p\net_id )
		
			;L/R rotation
			If KeyDown( 203 )
				p\r=p\r-5
			Else If KeyDown( 205 )
				p\r=p\r+5
			EndIf
			
			;Thrust
			If KeyDown( 200 )
				p\x=p\x+Cos(p\r)*5
				p\y=p\y+Sin(p\r)*5
			EndIf
			
			;Chat stuff
			key=GetKey()
			If key
				If key=13
					If chat$<>"" SendNetMsg 2,chat$,p\net_id,0,0
					chat$=""
				Else If key=8
					If Len(chat$)>0 Then chat$=Left$(chat$,Len(chat$)-1)
				Else If key>=32 And key<127
					chat$=chat$+Chr$(key)
				EndIf
			EndIf
			
			;transmit player position and rot
			If send
				SendNetMsg 1,PackPlayerMsg$(p),p\net_id,0,0
			EndIf
		Else
			p\x=p\x+p\dx
			p\y=p\y+p\dy
			p\r=p\r+p\dr
		EndIf
	Next
End Function

Function RenderPlayers()
	For p.Player=Each Player
		x1=p\x+Cos(p\r)*8
		y1=p\y+Sin(p\r)*8
		x2=p\x+Cos(p\r+150)*8
		y2=p\y+Sin(p\r+150)*8
		x3=p\x+Cos(p\r-150)*8
		y3=p\y+Sin(p\r-150)*8
		
		Color 255,255,255
		Line x1,y1,x2,y2:Line x2,y2,x3,y3:Line x3,y3,x1,y1
		
		Color 0,0,255
		Text p\x+12,p\y,p\name,0,1
	Next
	
End Function

Function info( t$ )
	i.Info=New Info
	i\txt$=t$
	Insert i Before First Info
End Function

Function RenderAll()
	;render everything!
	Cls
	Color 0,255,0
	Text 0,FontHeight()*0,"Multiplayer!"
	Text 0,FontHeight()*1,"F1:ping, type to chat"
	Text 0,FontHeight()*2,"Send freq:"+send_freq+" (F2-, F3+)"
	Text 0,FontHeight()*3,"Smoothing:"+smoothing+" (F4-, F5+)"
	Text 0,FontHeight()*4,">"+chat$
	y=FontHeight()*5
	r=255
	For i.Info=Each Info
		If r>0
			Color r,r/2,0
			Text 0,y,i\txt$
			y=y+FontHeight()
			r=r-12
		Else
			Delete i
		EndIf
	Next
	
	RenderPlayers()
	
End Function

;pack player details into a string.
;Not very elegant at present...more funcs coming!
Function PackPlayerMsg$( p.Player )
	Return LSet$( Int(p\x),6 )+LSet$( Int(p\y),6 )+LSet$( Int(p\r),6 )
End Function

;unpack player details from a string
Function UnpackPlayerMsg( msg$,p.Player )
	x=Mid$( msg$,1,6 )
	y=Mid$( msg$,7,6 )
	r=Mid$( msg$,13,6 )
	p\dx=(x-p\x)/smoothing
	p\dy=(y-p\y)/smoothing
	p\dr=(r-p\r)/smoothing
End Function

;find player with player id
Function FindPlayer.Player( id )
	For p.Player=Each Player
		If p\net_id=id Then Return p
	Next
End Function


The computer acting as a server always listens for connections. Even if you create a peer -> peer type, one of them must listen for incomming connections. Because of that, the listen command doesn not need an adress since it have no idea of what computer is going to connect.

127.0.0.1 is always pointing at your own computer. THink of it as a magic address. No matter what computer you use or if it has internet or not, 127.0.0.1 is always valid. To try the game on one computer, start the server and then launch the client and tell it to connect to 127.0.0.1. if it fails you did something wrong. :)

The port can be anything from 1 to 65535 if I remember correctly. But please use a port aboce 1024 because most ports below may be used by other programs.

Not to be whiney, but I WANT 2 DIFFERENT COMPUTERS TO COMMUNICATE, 127.0.0.1 may be magic but it doesn't do that. BlitzPlus pulled up a box that let me check for games in progress or start a new one. Does Blitzmax have a way to let me see what connections are available and which are used?

PS: Thank you so much for answering my questions.
---- And I am going to give BNet a shot.

The easy route:
1) Find out the IP on computer 1
2) Use it instead on 127.0.0.1
3) You teh win!

The not so easy route:
1) Server broadcasts that it is running and waiting for clients
2) The clients listens to broadcast packets
3) The client shows a list of running games
4) Connect
5) Yay!

The last method depends on what library you use. If I remember correctly you could send a message to another "magic" address and it would be automatically broadcasted over the LAN. But I have never done this before so I'm not sure.

Cool! I finally got all my numbers straight and it worked.

I have two computers chatting away and I am starting to get an idea of how it all works. I have hit a problem though. I don't know what the structure for a 3+ player game is. I would like to know what arrays, types, lists, etc. need to be setup for me to write a game that keeps track of individual players' info (name, x, y, etc.)

array or list of "objects" containing connected remote IPs, Ports, Names, PlayerIDs ... what you want to store to unify the remote-PCs.


Instead of only sending it to "remoteIP" you then have to make a "foreach"-loop with all remote IPs and send the same thing again and again.

Depending on how the information is spread...:
a.) Each client sends its changes to the server - and the server sends the changes to all clients

or

b.) Each client knows all other clients and sends itself the information to keep the dataamount for the server as small as possible


you need to program it differently.
I prefere a mixture of it a.) is used for the networklobby ...before game starts, server spreads around all needed infos ... game changes are then spread using b.). To keep everything in sync the a) method is used again all XXX millisec() to spread really the same info to all clients (I use UDP packets with Ack-responses but this take as much tries that the position differs to much to make some calculations correct - so the server sends its information about the players and overwrites all other commands).


bye
MB

I'm having trouble putting my concern into words. Here is another go...

What is the best way to figure out which remote-PC the info coming in came from.

Here is my concern stated in yet another way...

A is the server. B, C, and D are clients. When info comes in from a remote-PC, how do I know which (B-C-D) it came from. I would like to have 1 program that can be the server or client. (Also-How can you figure out how many/which people are involved at a given moment)

I'm sorry for all the questions.

you save the on that user on the first connection into an object for that user that you hold in a TUser list (or however you call the type) and when a message comes in you check for those information.

If you only have 1 datafield to identify, use TMap instead of TList