Author Topic: Networking for Cowards - Part 1 - connection and messages  (Read 5358 times)

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10661
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
You're right for cowards. That's what you are :P. But this tutorial's gonna make you a cowboy, whee-haa!

So, in this tutorial I'll explain the NET.. commands of GLBasic, which are very easy to use.

The NET commands are designed for a client-server application, means one computer is the "main" computer, and all other computers connect as "clients" to this server. The server itself can have the same functionality as the clients, but internally it's doing things differently. All clients send messages to the server process. By process I mean the program on the server computer, which can be the same as the client computer. You can have 2 processes on one machine and they talk to each other.
The server collects all these messages and sends some of them back to the clients that should receive this message initially.
So, for a client-server application, the messages from client 1 to client 2 are always Client1->Server->Client2.
That's the internals, just to let you know.

First, make a server:
Code: GLBasic [Select]
SYSTEMPOINTER TRUE
AUTOPAUSE FALSE
 
You surely want to debug your program on _one_ computer, so use these 2 commands to have them both working in parallel.

Code: GLBasic [Select]
ok% = NETHOSTGAME(0)
IF ok% = FALSE THEN END
 
Start up the server. It will now idle and wait for clients to connect to it in the background. A separate thread is created to handle the message shuffling. Again, just in case you care.

On the client machine you want to connect to this server now:
Code: GLBasic [Select]
ok% = NETJOINGAME("127.0.0.1", 0)
IF ok%=FALSE THEN END
 
Now "127.0.0.1" is an IP address for "this computer". It's also called a "loopback device", which just means that you can connect to a process on the same machine with this virtual network adapter.
If you have a network game in the internet, insert the internet IP of the server program here. You can get you IP in internet from here: http://whatismyipaddress.com
If you're in a LAN, you can simply insert the network computer name here, too. So, my PC is called "PC-GF" and when I write this here it's working for my computer. If my mate starts the server, I put "PC-XY" here and I can connect to it.

If you have a problem here, print the result of
Code: GLBasic [Select]
err$ = NETGETLASTERR$()
 
somewhere. It tells you an error number and a long error string you might find useable for debugging the problem.
In both cases I specified a parameter "0" as the port, which means: Take the GLBAsic default port 27910 TCP. You have to open this port for TCP connections in:
  • Your Firewall  (ZoneAlarm?)
  • The Windows Firewall (if enabled)
  • Some Worm-Protection software (such as Norton AV)
  • Your gateway to the internet (if you're playing over the INET, and your box (FritzBox?) provides a port filter

Surely you can use another port above 1024 for your game to be unique.
Here's a list of ports and associated applications you might want to avoid:
http://www.iana.org/assignments/port-numbers

If both calls above succeeded, server and client will have a little chat about the weather, kids and if the server's still alive.
Next thing is to create "players". A player in the NET... world is simply a "mailslot" you can use to send data to or receive data from. Each program can create any number of players in one instance. Usually one player suffices for most applications. You can use different players to distinguish between certain actions, though.

Code: GLBasic [Select]
id% = NETCREATEPLAYER("John Doe")
IF id% = 0 THEN END
 
OK, if the return value is non-zero the server is now aware of this player and the process that called NETCREATEPLAYER is, too. This can be the same process, however. So the server can create a player "Sam" and the client can create a player "Ken" and both can have a chat now. The name can be anything you want in a string. I used it to send both player name and character sprite id, once.
The returned player ids will be unique on each machine.

If you want to know how many players the server is aware of, call
Code: GLBasic [Select]
num% = NETNUMPLAYERS()
 
This will send a query to the server and the server will send a response message. This call might take a little time, so be sure not to call it every frame update. If someone stepped over the server's power cord and closed the server, you will get a return value of "0" here (despite your knowledge you already created at least one player). You can quit now, too. There's no way to reach other clients any more. At least not using NET... commands, only.

Now you have the number of players totally, but you don't know their IDs.

Code: GLBasic [Select]
GLOBAL gIDs%[]
DIM gIDs%[num%]
FOR i% = 0 TO num%-1
   gIDs%[i] = NETGETPLAYERID(index%)
NEXT
 

So you can query the player ID from the player's index in the server's player list. New players will be put to the end of the list. A client should, however, only get the player IDs after the server has decided to
Code: GLBasic [Select]
NETALLOWJOINING FALSE
 
so no more players can connect. Send a message to the clients then. See later.

Maybe you want to display who you are fighting, so query the player's name by the id with
Code: GLBasic [Select]
name$ = NETGETPLAYERNAME$(id%)
 
Again, it's a query and as such takes some time. Don't do for every frame, but only once for each player.

If you want to quit, it's nice to call
Code: GLBasic [Select]
NETDESTROYPLAYER id%
NETSHUTDOWN
 

So the server knows it instead of "guessing" you've died.

Finally you can send messages across the game with
Code: GLBasic [Select]
ok% = NETSENDMSG(id_from%, id_to%, text$)
 
where id_from% must be a player that you created with this process, and id_to% can be any other valid player id. The server gets this message and forwards it to the players mailbox then. If you send to player id "0", the message gets sent to all except the sender (who should already know about it, doesn't he?)

If you have a stack of messages in your mailbox, you must call
Code: GLBasic [Select]
msg$ = NETGETMSG$(id%)
 
If msg$ is empty, there's no more messages for you, well done. If it's not, please call this message again until it is to free up the internal post office space.

With
Code: GLBasic [Select]
id% = NETGETSENDER()
 
you can find the id of the sender of the last message you recieved with NETGETMSG$(). In case you are nosy.

Be sure, that during a query, the player queues up incoming messages until the query result arrives. Thus, it's no good idea to send a few thousand messages per second to a player. It will simply choke and probably die.

So, what's the alternative to sending player messages rapidly?
- Send key changes and handle each player on each client. Send a sync-position update every 5 seconds.
- Only send when things changed
- Only send "informations" about events, not the event flow itself.

OK, that's pretty enough for today. I hope you will find some time to try the new network commands, since they really work good now. And I really want to encourage you to write a network game. It's no dark magic any more with GLBasic's NET commands.
« Last Edit: 2010-Dec-20 by Kitty Hello »

Offline FutureCow

  • HelpEditor
  • Prof. Inline
  • ******
  • Posts: 680
    • View Profile
Re: Networking for Cowards
« Reply #1 on: 2009-Feb-04 »
Is there any way to query a server as to whether it has any games open?

For example, if you were running a world of warcraft server (we all know WOW was written in GLbasic  :whistle:) and had multiple games running on it for people to join, how would the client query the server to say "do you have any free games available, and if so, which games are they?"

MrTAToad

  • Guest
Re: Networking for Cowards
« Reply #2 on: 2009-Feb-05 »
In my hosting system, the server retains the number of joined players, which in turn defines whether a player is allowed to join or not...

The above tutorial was very good, by the way.  What else would be good to see is some code for movement prediction.

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10661
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Re: Networking for Cowards
« Reply #3 on: 2009-Feb-05 »
There is 2 ways of doing this. For LAN sessions you can perform a broadcast message, for internet games you can query a session IP from a php script. I'll write a tutorial for both, soon.

Offline bigsofty

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 2537
    • View Profile
Re: Networking for Cowards
« Reply #4 on: 2009-Feb-05 »
A nice read Gernot, thank you.  :good:
Cheers,

Ian.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration.”
(E. W. Dijkstra)