Jump to content


Photo
* * * * * 2 votes

Last Stop For Multiplayer Learning


  • Please log in to reply
149 replies to this topic

#1 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 30 August 2009 - 10:53 AM

  • Title: Last Stop for Multiplayer Learning
  • Description: All the details you will ever need for multiplayer game creation using 39dll.
  • GM Version: GM7
  • Registered: yes
  • File Type: .zip
  • File Size: 464.01 kb
  • File Link: download
Additional Info

All credit to True Valhalla for compiling this list of other resources:
True Valhalla{2}
BlaXun's Online Engine and guides{2}{3}
Onlin3's Engine, plus refination by Koron XYZ{2}{4}{5}
39dll thread{2}{1}

Although most code and ideas expressed herein is my own, it may seem similar to others. I can assure you that anything I do not reference directly is my own work. References will be noted with a number in braces after using public works. If anyone specifically wants their things removed, PM me and I will snip it and find other public works to pull from.

Foreward

The material given is expressed as if the reader ("you") is fairly new in the world of networked computers and the internet. It assumes many areas of technology are already known by you. Steps are taken slowly to build up new knowledges in this area along with some analogies, and your learning speed may differ that from this document. Apologies to you if this document fails you in your learning.

Requirements

Making an online game in GM7 will require the following for this document:

  • Pro version of Game Maker 7
  • 39dll.dll here {1}
  • Dllscripts.gm6 {1}
  • Fairly decent computer
  • Patience
For the 39dll.dll, the link provided is to the topic itself on GMC. It contains the file suite (which contains a small tutorial, gm files, like the Dllscripts.gm6, and the 39dll.dll). If you would like to dive right in and read the tutorial provided, by all means, you can come back here if you get stumped. The file I have provided in this tutorial contains the 39dll.dll file, if 39ster has a problem, I will have to remove it.

Chapter 1: The OSI

OSI stands for "Open System Interconnection", although this is not going to be tested on at any point, it does serve a purpose for us. This purpose is it contains the model in which data flows through the internet from program to program, particular the TCP/IP and UDP models are our current interest in it.

For an example, we have a chat program and "Joe" is on the other side. You want to say "hello" to him, so you type "hello" in your chat box and click the send key. Now let's follow the path of the data through your computer:

  • Data is given a port header: (port:3499) + (to:Joe) + "hello"
  • Data is given an IP header: (ip:43.39.9.132/192.168.0.10) + (port:3499) + (to:Joe) + "hello"
  • Data is given a frame header and footer: (frameh:1/1/0/192.168.1.1) + (ip:43.39.9.132/192.168.0.10) + (port:3499) + (to:Joe) + "hello" + (framef: cs)
  • Data is put on the wire outside the network card
A bit intimidating at first, but it was just to break the ice, let's take apart the data on the wire and see what each part does:

(frameh:1/1/0/192.168.1.1)

This is the frame header, it contains much more data than is shown here, but I have knocked it down to the very basics. The first "1" denotes that this is the first packet of data being sent (since packets have a limited size on the network, huge packets are automatically split up and given a number and reorganized on the other end). The second "1" denotes that there is only 1 packet to deal with, so (1/1) means first packet of 1 packets, which means we have it all right here.

The third value "0" is our hop count, every time this data moves from one object (router or network card) to another object, this value goes up. After this number reaches a certain value, the data is automatically dropped from the internet (effectively deleting it). This is because data will always try the fastest route to its destination (sometimes that route may lead too far away and get lost), so instead of the data constantly jumping around forever, there is a time limit.

The last set of digits is the IP address of the gateway the data must travel. Because the IP address of where the data needs to be sent is not on this network (this side of the router), we must send this data out into the world, and our router is what is connected to that outside world. 192.168.1.1 happens to be the IP address of our router, which is our gateway.

(ip:43.39.9.132/192.168.0.10)

This is the IP address of where we want to send our data and what our address is. The first numbers are the chat server's address and is arbitrary in this example, and the second set is our IP.

(port:3499)

A port number is similar to an extension on a company phone. In order for the data to reach the proper network card and program, it requires this number, just as you cannot speak to a specific representative without knowing their phone extension. This is different than the IP itself in that the IP is like the phone number to the business, which tells it which network the data should go to, but not the computer nor the program.

(to:Joe) + "hello"

These should be evident as the code for the chat program, if not, maybe a quick tutorial on making an interpretive language should help you.

(framef: cs)

At this moment it only contains the checksum of the entire message. A checksum is just a way to quickly check if the message has been corrupted or not. As the message moves through the network, IP addresses of gateways are added to the footer to let it know where it has been, so that it doesn't go "backwards" when it hops.

UDP works the same way except it does not get acknowledged by any device upon receiving. Which means it hops fast from point to point hoping to reach its destination before it dies or becomes corrupted, whether it makes it or not is less important for UDP.

Chapter 2: The Router

When your data reaches the router, the router will break down the message to find out where it is going, replace IPs as well as store the header into a lookup table with a timer. When the timer runs out, that entry is deleted. This is so that the router can listen for a reply from the computer your data was sent to, but after awhile, the connection is closed. Let's follow the data from our last example through the router:

  • Data is stripped to the IP header and saved to table: (ip:43.39.9.132/192.168.0.10)
  • IP header is altered to reflect outter address: (ip:43.39.9.132/71.1.45.193)
  • Data is recombined with frame pointing to next jump: (frameh:1/1/1/71.1.45.192) + (ip:43.39.9.132/71.1.45.193) + (port:3499) + (to:Joe) + "hello" + (framef: cs)
  • Data is put on the wire outside the router
Let's break it down again:

(frameh:1/1/1/71.1.45.192)

Notice we increased the hopcount and our gateway address has now changed. Because your routers address on the outside is on the 71.1.45.192-199 network arbitrarily, and 192 happens to be the next router/gateway location. This is so the data can keep moving toward the 43.39.9.132 network.

(ip:43.39.9.132/71.1.45.193)

Same as before, except the address of the data "from" is now the router's outside address

Everything else is the same as before, the data continues to hop from point to point until it ends up where it needs to be.

Chapter 3: Portfowarding

Because you can have many computers connected to the same router, data coming into the router from the outside does not know where to go. In our example, your computer's address is at 192.168.0.10, let's say we had 10 computers on this side of the router....192.168.0.1-10. If data were to be coming down the line pointing to 71.1.45.193 (which is the outside of our router), the router will look at it and say "where does this go?" The router knows it is its network, but which one of the 10 computers should receive the data? If a connection was already made by one of the computers, the router can look in its table of saved addresses and see if it is listed, but what if there were none?

This is where portforwarding comes into play. When you tell the router "forward port 10 to my computer", when it receives a message, it can check if the port matches and send the data your way. Because of the need for a router to know where to send data, 2 situations require it:

  • servers behind a router
  • servers and clients using UDP
Client computers are usually the ones to start a connection, so they send out data to the server first. Since this data is just like a normal TCP/IP packet, the router on the server's end requires a port foward in order for the server to get the connection details. UDP is connectionless, so it is in constant need of port fowarding in order to route the data properly.

*Note: We will not be discussing UDP holepunching, this is a security threat and is a redundantly slow system, so not worth our time.

Chapter 3.5: Usable Ports

People have asked me about which ports should be used in their games, and it's not always clear what the best approach is. You can google for "internet ports" or look at the IANA documentation for port numbers here {6}. A "port" is a 2 byte value that allows your computer to communicate with specific programs on the internet, some of which are static (which means they never change their port value). The document gives a bunch of dribble about "registering with the IANA" in order to assign your port, this does not apply to you, so don't worry about that. What you do want to worry about is conflicting with current devices already installed in your computer or customers might already be accessing, like:

  • port 7 - echo (ping and such)
  • port 20 and 21 - ftp server
  • port 23 - telnet
  • port 80 - web browsing
I could go on, but the document has all that information. It is lengthy, it will take you time, or you can just read the next few sentences. What you have to understand is that ports are assigned in order of registration with the IANA, and although you can pick some of the ports like 1200 (scol - rarely used) or 10006 (unassigned) by reading the list...you can just as easily skim to the end and see that it maxes out at 49151 (as of 9/10/2009). Since a 2 byte value maximum is 65535, that leaves you all numbers between 49152 and 65535 completely open (for now). However, before you start plugging away, try not to go above 65000 (I think one of them is a multicaster port -- not entirely sure, just don't do it). A more advanced person would be able to switch ports on-the-fly if a port was already being used, we may discuss this in a later tutorial.

Chapter 4: Hosting

No matter what multiplayer game you are creating (RTS, RPG, FPS, etc.), in order for it to work online, someone will need to be a server. This can be as simple as a 2 player game with 1 of those people being a server, or an actual 24/7 server hosting thousands of players. Don't think of a server as this untouchable object that holds great power, it isn't, so don't be afraid. The servers' job is to let people connect to them and be the hub where data is moved around.

Imagine your local bar, does the waitress go door to door giving you liquor? No, this is similar to what a server does (weird how the names are the same), YOU as the CLIENT must walk in to the bar (connect). The server can then give you liquor while you are there. If you leave (disconnect), she no longer can give you liquor.

Chapter 5: Initialization

Let's go ahead and start making some code. We will begin with initialization, like most things, variables need to be set properly before they are used, 39dll is no different. Start by loading the Dllscripts.gm6 file, create a persistent object called "obj_dll", and in the create event put:

dllinit(0, true, false);

The first argument "0" means use "39dll.dll" file, if you rename the dll file, you would put the string here. The second argument loads our network functions, the third loads utility functions (which we won't use in this tutorial). You only need to place 1 of these objects in the first room and you're done. Save this file as base.gmk because we will be modifying it further as we go through the other chapters.

Chapter 6: Server

base.gmk object obj_dll create event

listen = tcplisten(12000, 4, 1);
if (listen < 0) game_end();
This makes the program begin listening to port 12000. When the server is busy, it can not always connect people right away, this is called a queue, and the "4" is how many in that queue are allowed. If the queue is full, any new clients will be ignored, 4 is sufficient for now. The "1" means "non-blocking", it deals with parallelism, which is what we want, so just set it. The function returns a "socket" required by other functions or "-1" if it failed (a socket is the connection between your program and the network card containing information about the virtual connection between the two computers, the complex actions are seemlessly done by the simple functions supplied by 39dll). We need an object to hold client connections, so create persistent object "obj_client".

obj_client create event
client = -1;
obj_dll step event
client = tcpaccept(listen, 1);
if (client >= 0)
{
	o = instance_create(0, 0, obj_client);
	o.client = client;
}
When clients try to connect, the server must accept their connection (which means the underlying socket will store their IP and port information for you). It will grab the first in the queue and create a connection and return the socket (or "-1" if none were in the queue). After a connection has been made, we create the client object and give it the socket. Save this file as server.gmk.

Chapter 7: Client

base.gmk object obj_dll create event

server = tcpconnect("43.39.9.132", 12000, 2);
if (server < 0) game_end();
This makes the program send out a connection request to the computer at IP 43.39.9.132, you will need to change this to the server's IP address (if you are on the same network, the network card will contain the IP address, otherwise use "whatsmyip.org" to get it). The next number is the port, notice it is the same as the server's "tcplisten" command in the previous chapter, these must be equal in order to make a connection. The last number means we don't want the connection to freeze our program, so just set it to "2" (some computers may require it to be "1" which is also a nonblocking connection, but only after the primary data send -- this isn't anything to worry about, if "2" doesn't work, use "1" that simple). It will return the socket for the connection or "-1" if it fails. Save this as client.gmk. You can effectively run both the server.gmk and the client.gmk (in that order) and create a connection between the two (use "127.0.0.1" for IP to connect to yourself). Right now there is nothing fancy, it just creates the connection.

Chapter 8: Basic Movement

client.gmk object obj_player step event

if keyboard_check(vk_up) y -= 1;
if keyboard_check(vk_down) y += 1;
if keyboard_check(vk_left) x -= 1;
if keyboard_check(vk_right) x += 1;
This is a basic moving object, you can use any image you want and put 1 in the first room of the file.

Chapter 9: Client to Server Communication

client.gmk object obj_dll create event

dx = -1;
dy = -1;
This will save our x/y locations, so we don't keep sending the same coordinates.

obj_dll step event
if !instance_exists(obj_player) exit;
sx = obj_player.x;
sy = obj_player.y;
if (server >= 0) && ((dx != sx) || (dy != sy))
{
	dx = sx;
	dy = sy;
	clearbuffer();
	writeint(1);
	writeint(dx);
	writeint(dy);
	sendmessage(server);
}
This will check if we are connected and if our x/y coordinates have changed, if so it will send a specific sequence of numbers to the server. "clearbuffer()" is called first to empty out any data that was in the socket buffer, "writeint()" is a function that will add a number to the next position in the socket buffer, and "sendmessage()" will transmit whatever you put in the socket buffer to the socket. In order of numbers we have "1" which tells the server "we are sending you an x/y coordinate", you can use whatever code you like, but good practice to have a scheme. The next is the "x" coordinate, then the "y" coordinate. Don't forget to save it (client.gmk).

Chapter 10: Server from Clients Communication

At this moment, the client would be sending a barrage of data to the server, but the server is currently ignoring it because we haven't read the data.

server.gmk object obj_client step event

if (client != -1)
{
	clearbuffer();
	size = receivemessage(client);
	if (size == 0) instance_destroy();
	if (size > 0)
	{
		code = readint();
		switch (code)
		{
				case 1:
						x = readint();
						y = readint();
						break;
		}
	}
}
A lot to handle, but let's break it down one line at a time. First we make sure that we have a socket (client is -1 when created but set from the other object afterward, this is to ensure the other object had enough time to set it). We then have "clearbuffer()" which I like to do before any reading and writing to a socket, it just clears an area of memory for us. Next we have "size = receivemessage(client)", which looks at the client socket for any messages that may have arrived, it returns (-1) if none have yet, (0) if there is no connection (which means the other player disconnected), or (X) which is the size of the data part of the packet. We can use this information to determine "if (size == 0)" we destroy the object because it is no longer connected, or "if (size > 0)" we have a message, so we need to decypher it. In the same order the client sent the data "1/x/y", we read it back with "readint()". The first is the code, we only have one, but we might have more later, so we use the "switch" statement to figure out which code has been sent. Code "1" is x/y so we read those in the same way we sent them from the client, and we're done. Well, not quite, we have to close the socket when the connection is lost, so:

obj_client destroy event
if (client != -1) closesocket(client);
Go ahead and make the object's image same as the client's obj_player sprite, don't forget to save it (server.gmk). You can now connect multiple clients to this server and each client will send its x/y coordinate to the server, the server can see ALL of the players locations at the same time on its screen. When a client disconnects, it will automatically delete that player from the screen.

Chapter 11: Relay That

You will notice that the clients cannot see the other clients, that is because the server never relayed that information to anyone. If we make the players send to everyone, that would be exponentially lagging your network, so we have to centalize our data and send out the same packet to everyone from the server. This way the clients send out 1 packet and receive 1 packet, far less stress on the clients network, and the server will lag linearly instead of exponentially with the connections. Ok, so we need to gather up all the coordinates of all the players and put it in a socket buffer:

server.gmk obj_dll end step event

ic = instance_number(obj_client);
if (ic == 0) exit;
clearbuffer();
writeint(1);
writeint(ic);
for (i = 0; i < ic; i += 1)
{
	oi = instance_find(obj_client, i);
	writeint(oi.id);
	writeint(oi.x);
	writeint(oi.y);
}
Breaking down the lines, you will find the similar aspects of the previous sending code the client did in an earlier chapter. We have "clearbuffer" to make a clean slate to write our data and "writeint(1)" which is the server's code for "update" (you can pick whatever you'd like for codes, as long as they match for reading them for the client). After the codeword we have a count of how many players there are connected to the server, followed by each player's id, x, and y. Now that we've gathered the data into a buffer, we need to send that buffer multiple times:

same event
for (i = 0; i < ic; i += 1)
{
	oi = instance_find(obj_client, i);
	sendmessage(oi.client);
}
This is the reason why you need to use "clearbuffer" prior to writing onto it, because sending data doesn't automatically delete it, which is a good thing because we are sending the same block of data to multiple people. That is what this code does. Don't forget to save it (server.gmk).

Chapter 12: Relay What?

Just like when the clients barraged the server until we read it, now we have the server barraging the clients until we read it. But we now need objects to represent other players, we cannot use the same object. Make an object called "obj_others", same image as the player for now. This object needs no code because the server sends the data in a single big package for us, we need to read it, but you will notice that there is no way the client knows which object the server is talking about. The server sends us the id of the object, but that's only the server's interpretation of that object's id, not the client's. So we will begin by creating a script:

client.gmk script 'scr_translate_client'

//scr_translate_client(id)
//  looks for id in our list
//  if it finds it, it returns the true id
//  if none found, it creates a new obj_others and adds it to the list

if ds_map_exists(dspid, argument0)
	return ds_map_find_value(dspid, argument0);
io = instance_create(0, 0, obj_others);
ds_map_add(dspid, argument0, io);
return io;
We will need to initialize some variables before we can use it:

client.gmk object obj_dll create event
dspid = ds_map_create();
Now we can understand the server's block of data when we receive it:

client.gmk object obj_dll begin step event
if (server >= 0)
{
	size = receivemessage(server);
	if (size == 0) game_end();
	if (size > 0)
	{
		code = readint();
		switch (code)
		{
			case 1:
				ic = readint();
				for (i = 0; i < ic; i += 1)
				{
					iod = scr_translate_client(readint());
					(iod).x = readint();
					(iod).y = readint();
				}
				break;
		}
	}
}
This should look familiar, it is almost exactly like how the server is reading information from clients, and is set up in the same order the server wrote those values into the buffer. You have successfully created a server that can host multiple clients and relayed information from point to point, give yourself a small clap, you deserve it. Don't forget to save it (client.gmk) and maybe even try it out.

Chapter 13: Coding Connections

You will notice that there is an object that seems to mimic your movements, this is caused by the server ghosting you (the server told the client something moved in that location, but because the client doesn't know the difference between player and other players, that's what you get). We now have to communicate connection codes to allow clients to know their own IDs. Let's start with the server giving the clients their object ID on sign on:

server.gmk obj_dll step event

if (client >= 0)
{
	clearbuffer();
	writeint(4);
	writeint(o);
	sendmessage(client);
}
You should already have the previous code in front of it with "o" equal to the player's object on the server's side, we just sent "4" (our "Your ID" code to client) followed by the ID itself. Now to read it on the client's side:

client.gmk obj_dll begin step event modify switch
switch (code)
		{
			case 1:
				ic = readint();
				for (i = 0; i < ic; i += 1)
				{
					iod = scr_translate_client(readint());
					tx = readint();
					ty = readint();
					if (iod != -1)
					{
						(iod).x = tx;
						(iod).y = ty;
					}
				}
				break;
			case 4:
				ic = readint();
				if ds_map_exists(dspid, ic)
				{
					with ds_map_find_value(dspid, ic) instance_destroy();
					ds_map_delete(dspid, ic);
				}
				ds_map_add(dspid, ic, -1);
				break;
		}
Notice this is only the "switch" statement inside obj_dll. Starting with "case 4" you can see that we read in what our client ID is from the server, it will then look inside the 'dspid' map to see if it already exists (if it does, it removes it from the list and destroys the object), afterward it will add the client ID key with a value of '-1' to the map. This will let our reading code know that it is OUR object and why we needed to adjust the "case 1" code above. You will see it now checks if 'scr_translate_client' returns a '-1', if it does, it doesn't modify anything (because it is us).

We have now gotten rid of our ghost image, you deserve another clap maybe even a little louder this time. Don't forget to save your files and try them out.

Chapter 14: Coding Disconnections

It is good practice to have both the server and clients tell each other when they are about to disconnect, rather then have a forced disconnect. Although the code handles it fine, we should still do it for practice. We will use "9" for our disconnection code for client, which will react by telling everyone the same "9" code, and "11" for a forced "get off my server" code for the server to a specific client. First, let's have the client disconnect:

client.gmk obj_dll destroy event

if (server >= 0)
{
	clearbuffer();
	writeint(9);
	sendmessage(server);
}
This tells the server we have disconnected, now the server needs to read the code and respond:

server.gmk obj_client step event modify switch
case 9:
				instance_destroy();
				break;
Not sure if you need the "break;" after a destroy function, but it's good practice anyway, this destroys the client. We now have to tell everyone that someone has disconnected:

server.gmk obj_client destroy event modify all
if (client != -1)
{
	clearbuffer();
	writeint(9);
	writeint(self.id);
	ic = instance_number(obj_client);
	for (i = 0; i < ic; i += 1)
	{
		oi = instance_find(obj_client, i);
		if (oi != self.id)
			sendmessage(oi.client);
	}
	closesocket(client);
}
This should start to look familiar, it clears the buffer, then writes the "9" relay code along with the ID of the object that has disconnected (which is itself). It then runs through every client socket and sends the message to them, unless it is this client because he disconnected of course. Now we need to read this code from all the other clients:

client.gmk obj_dll begin step event modify switch
case 9:
				ic = readint();
				with scr_translate_client(ic) instance_destroy();
				ds_map_delete(dspid, ic);
				break;
See how we are going back and forth to write the code, read the code and relay information, then read the relay information to react to it.

Let's see how to write a forced disconnection code "11" from the server. To show how it works, we will use the right-click of the mouse on an object in the server window to disconnect that object:

server.gmk obj_client mouse right-button event
if (client != -1)
{
	clearbuffer();
	writeint(11);
	sendmessage(client);
	instance_destroy();
}
See what we did there? Sent that client a code "11" and destroyed the object on the server's end, and in the obj_client destroy code it already contains the disconnection code for everyone else. Now we go to the client to read that we were forced off:

client.gmk obj_dll begin step event modify switch
case 11:
				server = -1;
				instance_destroy();
				game_end();
				break;
The "server = -1" is so that we don't end up sending code to a nonexistent server, the server just force killed us so it isn't listening anymore. A lot has changed, don't forget to save both files and test it out!


Appendix A: 39dll scripts

dllinit("39dll.dll", true, true);
This function must be called one time during the loading of your game, you should not call it more times then that. The first argument is the name of the dll file, you can put the number '0' instead if it is the same name as "39dll.dll". The second argument will initialize all socket functions (which is all your internet stuff), and the third argument will initialize all file functions (GM comes with file capabilities, but 39dll comes with some better file tools). You are not required to load either of them (although not loading both will make having this useless).

dllfree();
This function should be called when the game ends, although you do not need to because windows will unload it for you after the game unloads, it is good practice to free the memory yourself instead of making windows do it.

A buffer is like a string. It has a length which you can add onto it, change bytes inside it, and even read from it. The difference is that a buffer is required in order to send or receive information on the internet. Although you can put a string inside a buffer, you cannot send any variable directly.

createbuffer()
This function will return an ID, you will need this ID to perform any other functions on the buffer. This is similar to "ds_list_create()".

bufferexists(ID);
freebuffer(ID);
These should be obvious, the first returns true/false depending on if the ID you provide is a created buffer, and the second will free it from memory. Although there is no exact function similarity for the first function for "ds_list", the second is similar to "ds_list_destroy(ID)".

Buffers have 2 internal variables that cannot directly be seen. The first one will point to the beginning of the buffer and is used for reading, anytime you read from the buffer, this pointer advances forward. The second variable points to the end of the buffer and is use for writing, anytime you write to the buffer, this pointer advances forward also. You can get the position of either pointer and set the positions of both pointers simultaneously using the following functions:

getpos(ID, wr);
setpos(ID, pos);
The first one "wr" means "write/read", if it is 0, it will return the "write pointer", if it is 1, it will return the "read pointer". This is a little backwards than normal electronics (0 is usually read and 1 is write), but since it is reverse, I reversed the wording to compensate. The second function sets the position to both pointers, you cannot however set the position to a specific pointer (it is not an included functionality, sorry).

buffsize(ID);
bytesleft(ID);
clearbuffer(ID);
The first will return how many bytes the buffer currently has, the second will subtract the buffer size by the read position pointer (which will give the number of "bytes left" to read). The last function should be evident, it clears the buffer (does not free it) and set both read and write pointers to 0.

There are several data types that are allowed to be written and read to/from a buffer, each of which contains its own set of functions: byte (0 to 255), short (-32768 to 32767), ushort (0 to 65535), int (-2147483648 to 2147483647), uint (0 to 4294967296), float (4 bytes), double (8 bytes), chars (a string), and string (a string with a chr(0) at the end). You can write any of these values with these functions:

writebyte(val, ID);
writeshort(val, ID);		writeushort(val, ID);
writeint(val, ID);		  writeuint(val, ID);
writefloat(val, ID);		writedouble(val, ID);
writechars(str, ID);		writestring(str, ID);
And its read functions are just the same:

readbyte(ID);
readshort(ID);			 readushort(ID);
readint(ID);			   readuint(ID);
readfloat(ID);			 readdouble(ID);
						   readstring(ID);
You will notice that the "readchars" is not listed. The reason is because the program doesn't know where the end of the character stream to stop, since you wrote it as a string with no end pointer. However, if you know the amount of characters you wrote in, you can read back that many using:

readchars(size, ID);
Hopefully you will have also noticed how "writestring" and "readstring" work by using the chr(0) to denote the end-of-string, this means you CANNOT use a chr(0) in your string. You can bypass this by doing this:

writeushort(string_length(yourstring));
writechars(yourstring, ID);
And to read it back:

size = readushort(ID);
mystring = readchars(size, ID);
Only a few more to go, for even more string fun there's:

readsep(char, ID);
This is very similar to the "string_pos" function by finding "char" inside the buffer but it returns everything up to that point (not just the position of it), setting the "read pointer" after it. For example, if you had "John:412", then using 'readsep(":", ID)' will return "John" and puts the readpointer at the "4" for the next reading.

By the way, there is a default buffer already created for you, so if you do not wish to use "ID" in the read/write functions, you do not have to supply it, it will automatically use the default. You have to take care in using a default buffer though, you constantly have to clear it before every data transaction.

Finally:
copybuffer(dest, src);
copybuffer2(dest, pos, size, src);
The first will copy all of the buffer "src" into buffer "dest" starting at the 'write pointer'. The second function is more precise in that you choose what part of "src" you want to copy into the destination buffer. There are 2 other functions supplied with the buffers of dllscripts, but they are pure GML and doesn't really deal directly with the 39dll.dll file.

tcplisten(port, queue, nb);
This should look familiar, it creates a socket that tells your network card to relay any information that is received on "port" to your program (not really, but easier to understand). The number of connection requests allowed at any given time are given by the "queue". Two of the functions that will be defined (tcpaccept and receivemessage) have 2 ways of handling the program flow, if you set "nb" to 0, those functions will freeze until it gets a response, but if you set "nb" to 1, they will simply return an error (-1) if they didn't get a response. In almost all cases you will be using 'nb' (nonblocking) as 1.

tcpaccept(lsock, nb);
After you have a socket open and listening, you will need to connect incoming requests to your computer's program, this is the function for that. "lsock" is your listening socket (set with the tcplisten function), and "nb" just like before sets up nonblocking for this specific connection. It automatically creates another socket for you and returns the socket ID, which you will need in order to talk with the computer you are connected to.

udpconnect(port, nb);
This is new to most of you, but it is a very simple packet type. Since it is a connectionless protocol, in order to "connect" you are actually telling it what "port" you are listening. This is very misleading to a new person, think of it like "udplisten" instead of connect. The only difference is that this socket will also be the one you send out of (unlike the listening socket of TCP), so it's like a 2-way street. I shouldn't have to explain "nb" anymore do I?

sendmessage(sockID, IP, port, bufferID);
Woah Woah, this isn't what you learned from the first tutorial is it? Nope, the first one used only the first argument, that's ok because the other 3 are optional arguments. When sending a message over a TCP connection, the "sockID" already connects the connection information (which is IP and port), and "bufferID" is optional because if you don't supply it, it will use the default buffer anyway. If you need to use a buffer other than the default for TCP connections, you would use:

sendmessage(sockID, "", 0, bufferID);
The reason for the IP and Port arguments is because with UDP connections (which are connectionless), you must provide the IP and port you are sending to. Realize something cool yet? You guessed it, a "udpconnect" can have a different port assignment than a "sendmessage" over the udp connection, but they must match each others opposite. Huh? Ok, if you have a server that says "udpconnect(14000, 1)" and sends a message to a client on port 15000, then the client has to have a "udpconnect(15000, 1)" and send messages to the server on port 14000. Notice the send/receive ports match, but on each machine they are swapped. This is where you are able to portswap (as long as you let the other computer know you are doing it -- in code).

Note: UDP messages are very fast, but they are unreliable. Some messages may be distorted (out of order) from when you sent them, or never arrive at all. If the message is important (like chat), use TCP. UDP is mostly used for unimportant things (like x/y updates, since location is constantly changing, the next update will correct the last).

receivemessage(sockID, size, bufferID)
Again, this is more arguments then you are used to, but it should start to sink in. The first argument is the socket ID of the 'accepted' socket (for TCP) or the 'udpconnect'ed socket. The second argument will read only the amount specified, and you will probably never use it, setting it to 0 will default it to read all of the data on the socket. I hope you can figure out what bufferID does, and yes, it's optional as well.

tcpip(sockID);
Pretty straight forward function, it returns the IP address of the computer this socket is connected to. This is good for when you have TCP and UDP connections and you need to know where to send your UDP data (hint: you would connect using TCP, grab the IP address, then open up UDP connections).

closesocket(sockID);
Oh whew! At least that didn't change right? Yeah, it basically frees the memory of that specific socket. Make sure you close ALL of your sockets before your game ends.

Most of the other socket functions you will hardly use, if anyone wants an explanation, I can add it in, but I feel they are almost worthless (almost).

fileopen(filename, rw);
fileclose(fileID);
filesize(fileID);
filepos(fileID);
filesetpos(fileID, pos);
As far as I know, you cannot use the same file identifiers that this DLL uses with the file identifiers that GM uses, so I would suggest not trying. The dll comes with basic file usage tools. The first opens a file, obviously, "rw" means "read/write" (0 for read, 1 for write, 2 for both), it returns a fileID (or error -1). The second closes the file, third returns the size fo the file. The last two are similar to how the buffer works, but using only 1 pointer in the file, these get and set the position of that pointer.

fileread(fileID, size, bufferID);
filewrite(fileID, bufferID);
You guessed it, more buffers, where else did you think we were going to store the information? Just like before, bufferID is optional, it will use the default if you do not supply one. The first one will read "size" bytes from the file and write it to the buffer, and the second function will write ALL of the buffer to the file at the position of the file pointer. Think of a use for these yet? Yep, file transfer (upload/download).

bufferencrypt(pass, bufferID);
bufferdecrypt(pass, bufferID);
Do not ask me why these were put in the file section of the initialization process, but they're there, let's move on. These functions are actually the same function, encrypting a buffer using the RC4 scheme twice will result in the original, so making "bufferdecrypt" useless. "pass" can be just about any string (without chr(0), and it gets chopped off at 256 string length). Although these are good enough encryption schemes, sending password information would make using these schemes useless, and without knowing the passwords, you cannot decrypt the information...hmm, hard choice, we'll have to cover that in a more advanced topic.

md5string(string);
md5buffer(bufferID);
Again 'bufferID' is optional. These functions create a hash, the first is a hash of a string, the second is a hash of the buffer. A hash is similar to a checksum but with more calculations that cause breaking it almost impossible. The hash returned is a 32 length string of hex digits, you can smash this down into 16 bytes for better storage (if you needed to store it), but unfortunately you would have to write the code yourself (this function is not supplied).

adler32(bufferID);
This function actually DOES return the checksum of the buffer, using the adler function. It returns a 4 byte positive value that is less secure than the md5* functions, but runs much faster.

Appendix B: Answered posts for Part 2

CubinJ: sorry if this is a stupid or obvious question, but how many people do you think this style of multiplayer can support?

Spoiler


Schyler: You would run out of ports...
Spoiler


canscaw28: I started useing my external Ip but it did not work for both LAN and online. so then I found my normal IP and it worked for only LAN. I don't know which IP i need to use.
Spoiler


ifisch: I am a little bit confused about sending and receiving.
Spoiler


2DLuis: I found a small typo in your first part, decypher should be decipher.
Spoiler


shadowman465: If you use closesocket on the client side will it close the socket on the server side?
Spoiler


icuurd12b42: Could it be possible for you to merge your tutorial parts in a single topic (the first one)
Spoiler

Appendix C: References and Credits

This concludes the first two parts in a series of multiplayer learning tutorials. I will be working on more advanced topics and link them in when I have time. For now, I'd like to thank:

  • 39ster {1} for the 39dll so I didn't have to write it myself
  • True Valhalla {2}
  • BlaXun {3}
  • ONL1N3 {4}
  • Koron XYZ {5}
  • iana.org {6}
  • xshortguy for approving this tutorial before I was done
  • the_recruiting for giving me a reason to make this tutorial
If you feel that you deserve credit, let me know. I would also appreciate anyone to let me know if there is any proofreading/coding errors. Thank you all!


Edited by sabriath, 07 November 2011 - 04:40 AM.

  • 11

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#2 xshortguy

xshortguy

    GMC Member

  • Global Moderators
  • 4355 posts
  • Version:GM:Studio

Posted 30 August 2009 - 07:00 PM

I'll approve this for the time being, seeing as the information here may be very useful, even though there is no editable example. However, this needs to be finished in a timely fashion and should provide some basic implementation into Game Maker using the 39dll.
  • 1
Check out my Profile's About Me Page for some useful links.

#3 Desert Dog

Desert Dog

    GMC Member

  • GMC Elder
  • 6409 posts
  • Version:Unknown

Posted 30 August 2009 - 10:43 PM

Cheers, xshortguy. :GM060:

I know nothing about multiplayer gamemaking, so this is(will be) really useful for me, just in explaining how things work. I have a Q, though.

(frameh:1/1/0/192.168.1.1)

This is the frame header, it contains much more data than is shown here, but I have knocked it down to the very basics. The first "1" denotes that this is the first packet of data being sent (since packets have a limited size on the network, huge packets are automatically split up and given a number and reorganized on the other end). The second "1" denotes that there is only 1 packet to deal with, so (1/1) means first packet of 1 packets, which means we have it all right here.


How large is a single packet? Like, is it a single byte, or what?
Edit: Heh, well, I guess that's what wikipedia's for :( It's still pretty confusing, though.

Edited by Desert Dog, 30 August 2009 - 10:52 PM.

  • 0
HTML5 games for mobile:
HexDogs Bugz Burn! Captain George Golfing Block Memory

Games for Androids
*NEW* Word Dog - Published by Dangerous_Dave


Code: General Array Functions - GM-S friendly. sorting, shuffling. Includes a quicksort.
Use the quicksort to sort ds_lists 10-18 times faster than ds_list_sort()!

#4 Kamokow

Kamokow

    GMC Member

  • New Member
  • 39 posts

Posted 30 August 2009 - 11:59 PM

How large is a single packet? Like, is it a single byte, or what?

A single packet ranges from between 7 to 65542 bytes. AFAIK that does include the packet header.
  • 0

#5 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 31 August 2009 - 09:57 AM

How large is a single packet? Like, is it a single byte, or what?

A single packet ranges from between 7 to 65542 bytes. AFAIK that does include the packet header.

The smallest packet size that can actually traverse the internet is an ICMP packet (which Ping uses) which contains minimum:
  • 4 bytes destination IP
  • 2 bytes destination port
  • 4 bytes source IP
  • 2 bytes source port
  • 2 bytes command type (0000 for echo reply, aka ping)
  • 2 bytes error ID stamp
  • 2 bytes overall package length
  • 1 byte ttl (time to live)
  • 1 byte checksum
Which comes to a total of 20 bytes for an empty data frame. A game will normally try to burst 512 data packets, depending on network lag, since length is 2 bytes, the theoretical maximum is 65535 (including header), but usually packets are split up around 2k-4k so that it doesn't hog the network (since you cannot have more than 1 piece of data on the line at the same time).
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#6 the_recruiting

the_recruiting

    GMC Member

  • New Member
  • 800 posts

Posted 31 August 2009 - 10:21 AM

wow thanx mate :GM060: i will study your tut over the next few weeks.
  • 0

#7 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 01 September 2009 - 09:35 PM

Hate to bump this, but I have added chapters 5 - 10, and hardly any replies. I would love for any feedback or questions. I am trying to add 2 or so chapters a night while I have time until I reach the board limit (which I'm not sure when I'll hit it, but it's probably soon).
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#8 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 01 September 2009 - 10:09 PM

This is nice. I havent read the whole thing yet but I will be needing this soon(I might use and engine I found, but for this game I just want simple multiplayer). :)
  • 0

InvaderX.gif


#9 Mordi

Mordi

    Maker of Menus

  • New Member
  • 3635 posts

Posted 01 September 2009 - 10:37 PM

Just remember to touch on optimizing the code for smoother games, and movement prediction.
  • 0

#10 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 01 September 2009 - 10:41 PM

Maybe include image_angle in the tutorial? Just so if you are making a topdown game then you dont have to figure out how to put it in. I suppose it would just be like making the other player see it...

P.S. Mordi, I like your avatar. :)

Edited by commander of games, 01 September 2009 - 10:42 PM.

  • 0

InvaderX.gif


#11 xshortguy

xshortguy

    GMC Member

  • Global Moderators
  • 4355 posts
  • Version:GM:Studio

Posted 01 September 2009 - 11:14 PM

Maybe include image_angle in the tutorial? Just so if you are making a topdown game then you dont have to figure out how to put it in. I suppose it would just be like making the other player see it...

P.S. Mordi, I like your avatar. happy.gif


If you aren't abstracting the information needed to send arbitrary data using the tcp protocol, then you aren't getting what you should be getting when reading this tutorial.
  • 0
Check out my Profile's About Me Page for some useful links.

#12 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 01 September 2009 - 11:16 PM

Maybe include image_angle in the tutorial? Just so if you are making a topdown game then you dont have to figure out how to put it in. I suppose it would just be like making the other player see it...

P.S. Mordi, I like your avatar. happy.gif


If you aren't abstracting the information needed to send arbitrary data using the tcp protocol, then you aren't getting what you should be getting when reading this tutorial.

It's ok xshortguy...I will be doing some optimizations and advanced material in a "part 2" tutorial when I'm done with this one, including not sending x/y coordinates all the time etc. And I want to thank you for approving this tutorial.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#13 Guest_yoyofromhotmail_*

Guest_yoyofromhotmail_*
  • Guests

Posted 02 September 2009 - 01:00 AM

This is Awesome I never fully understood how to do it until now thank you for posting you've really helped me.
If you can put the rest up soon. Thanks! :)

#14 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 02 September 2009 - 01:54 AM

Finished reading the guide. I cant wait until tommorow when more steps are added!
  • 0

InvaderX.gif


#15 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 02 September 2009 - 06:16 AM

Finished reading the guide. I cant wait until tommorow when more steps are added!

I present Chapter 11 and 12. :medieval:

I would appreciate if anyone can let me know if I have proofreading errors or code errors, I am not testing the code as I write this document lol, in fact I don't even have an outline of where I'm going with it :) . Let me know what you think.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#16 xshortguy

xshortguy

    GMC Member

  • Global Moderators
  • 4355 posts
  • Version:GM:Studio

Posted 02 September 2009 - 06:49 AM

If you're looking for a direction, then perhaps create a well-documented tutorial on how to create a chat room program with the following features:

1. A server program that stores information and transmits data, a client program that connects to the server for chatting.
2. Users should be able to create a unique user name and password to be displayed in the chat room program.
3. Users should be able to create and join both public and private chat rooms.
4. The server lists all available public chat rooms to join and shows the number of people connected vs the total number of people who can join.
5. Users should be able to send private messages to each other.
6. Users should be able to maintain friends lists that display whose connected.
7. Users should be able to view all players online.
8. The server should be able to store up to an arbitrary amount of users.
9. Each player can have a profile that lists various information.
  • 0
Check out my Profile's About Me Page for some useful links.

#17 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 02 September 2009 - 06:54 AM

If you're looking for a direction, then perhaps create a well-documented tutorial on how to create a chat room program with the following features:

1. A server program that stores information and transmits data, a client program that connects to the server for chatting.
2. Users should be able to create a unique user name and password to be displayed in the chat room program.
3. Users should be able to create and join both public and private chat rooms.
4. The server lists all available public chat rooms to join and shows the number of people connected vs the total number of people who can join.
5. Users should be able to send private messages to each other.
6. Users should be able to maintain friends lists that display whose connected.
7. Users should be able to view all players online.
8. The server should be able to store up to an arbitrary amount of users.

I appreciate the help xshortguy, but I was thinking this would be more advanced and a great idea for my second parter. I think getting this to just have a bunch of people moving around is good enough for beginner. As soon as I describe the ghost images and defining your character along with new connects/disconnects code, this tutorial will be finished.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#18 xshortguy

xshortguy

    GMC Member

  • Global Moderators
  • 4355 posts
  • Version:GM:Studio

Posted 02 September 2009 - 06:56 AM

Then perhaps you can give some tips on organization techniques.
  • 0
Check out my Profile's About Me Page for some useful links.

#19 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 02 September 2009 - 02:08 PM

One thing I can never(and probobly other people too)is shooting. For some reason the bullet doesnt show up on the other players screen. Perhaps you could make a tutorial for shooting bullets with 39dll?
  • 0

InvaderX.gif


#20 Guest_yoyofromhotmail_*

Guest_yoyofromhotmail_*
  • Guests

Posted 02 September 2009 - 05:36 PM

Hi I think you made a mistake. In the end step event of the obj_dll on te server you used instance_count which is a variable that equals the total amount of instances in the room. You can't put (obj_player) infront of it it will cause an error and it would count obj_dll as 1 so I think you may want to use ic = instance_number(obj_player); instead.

#21 Ichiroku

Ichiroku

    GMC Member

  • GMC Member
  • 237 posts
  • Version:GM:Studio

Posted 02 September 2009 - 08:09 PM

Really a good tutorial, it goes deep into how a package works, what a connection is etc.

Also, gotta say it, love your programming style. Alot of people tend to abuse the game maker fix thingy, where you don't have to use brackets and double = etc.

Hope to see anything more from this tutorial :3. I give it a 10/10

P.S.: Please people, this is so you can learn how to create online games, Don't ask for a whole engine, with this you can easily see how to create like a bullet shooting engine. (just send the x and y of the bullet, then send it to everyone, and let them create a bullet -.-).
  • 0

#22 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 02 September 2009 - 08:27 PM

None is asking for a whole engine, it would just be nice to have a tutorial for a 39dll shooter game.
  • 0

InvaderX.gif


#23 walkingbush

walkingbush

    GMC Member

  • New Member
  • 447 posts

Posted 03 September 2009 - 05:13 AM

Hey, not sure if this is a dumb question or not, but I got an error, something about
FATAL ERROR in
action number 1
of Begin Step Event
for object obj_dll:

COMPILATION ERROR in code action
Error in code at line 14:
iod = scr_translate_client(readint());

at position 28: Unknown function or script: scr_translate_client
  • 0
I don't always use signatures, but when I do, they are useful.

#24 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 03 September 2009 - 05:36 AM

Ok, before I finish this tutorial, I read some of your comments, time for me to recap:

Then perhaps you can give some tips on organization techniques.

Maybe after my Part 2 and Part 3 of multiplayer learning I'll get into organization techniques for project creation. I'm bad when it comes to organization though, so I'll have to really think about how to write it.

One thing I can never(and probobly other people too)is shooting. For some reason the bullet doesnt show up on the other players screen. Perhaps you could make a tutorial for shooting bullets with 39dll?

This will be covered in either Part 2 or Part 3 of this series, it is more an optimization technique rather then sending destructive objects through the net. I'm only one man, got lots to do, including job and wife lol.

Hi I think you made a mistake. In the end step event of the obj_dll on te server you used instance_count which is a variable that equals the total amount of instances in the room. You can't put (obj_player) infront of it it will cause an error and it would count obj_dll as 1 so I think you may want to use ic = instance_number(obj_player); instead.

You are absolutely right, and I thank you for finding this error, it is "instance_number" that I wanted. I will fix it in my next update.

Really a good tutorial, it goes deep into how a package works, what a connection is etc.

Also, gotta say it, love your programming style. Alot of people tend to abuse the game maker fix thingy, where you don't have to use brackets and double = etc.

Hope to see anything more from this tutorial :3. I give it a 10/10

P.S.: Please people, this is so you can learn how to create online games, Don't ask for a whole engine, with this you can easily see how to create like a bullet shooting engine. (just send the x and y of the bullet, then send it to everyone, and let them create a bullet -.-).

In order: Thanks, Definate Thanks, More coming soon/Thank you, (p.s.) I might create an engine, but bullets are destructive objects and a waste of bandwidth, they will be covered in optimization techniques.

None is asking for a whole engine, it would just be nice to have a tutorial for a 39dll shooter game.

Patience young grasshoppa, patience. It's one of the requirements.

{} FATAL ERROR in {} at position 28: Unknown function or script: scr_translate_client

You need to reread the tutorial where I said "client.gmk script 'scr_translate_client'". The script needs to be created, the code is in the tutorial.

To everyone: As I said, I'm only one man, I appreciate any errors you bring forth so I can bring a flawless piece of code to you, and I will try and be as quick as possible getting these chapters out for you.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#25 walkingbush

walkingbush

    GMC Member

  • New Member
  • 447 posts

Posted 03 September 2009 - 05:57 AM

Oh, man, I knew it was a dumb thing to post. Anyway, a really great tutorial, I have to say. Coding is one thing, explaining it is another whole (was about to type whole nother) thing, and you, my friend, have it down. For one man that is :) Good luck with it, my friend was right to suggest your tutorial. Really helpful.
  • 0
I don't always use signatures, but when I do, they are useful.

#26 general sirhc

general sirhc

    Dream Big, Act Small

  • GMC Member
  • 1667 posts
  • Version:GM:Studio

Posted 03 September 2009 - 07:18 AM

I must ask why you would use an int for a message id....Unless I miss read

Writes a 4 byte integer to the internal buffer. The value can be between
-2147483648 and +2147483647


Normally for message ID's a single byte will be fine since its not like your gunna be sending 255 different types of messages

Write 1 byte. The value can be between 0 and 255


PS:
When/If this tutorial include how to do non jump/laggy movement I will be downloading and using :)

Edited by general sirhc, 03 September 2009 - 07:22 AM.

  • 0

qs8ZFMQ.png?1


#27 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 03 September 2009 - 10:43 AM

Oh, man, I knew it was a dumb thing to post. Anyway, a really great tutorial, I have to say. Coding is one thing, explaining it is another whole (was about to type whole nother) thing, and you, my friend, have it down. For one man that is Good luck with it, my friend was right to suggest your tutorial. Really helpful

It wasn't dumb, any replies helps keep this post up top and more viewed. I'd like to know my nights of staying up weren't in vain. And thank you for the compliment.

Thought I'd give this a read through to see how it compares to my tutorial (which I should really redo considering how old it is now).

I must admit, this is very well written. I believe you should incorporate constants as a substitute for writebyte(1), etc., and that the first section of the tutorial (with the IP and port parts of the packet) was a bit unnecessary and more suited towards advanced users who are interested in the details (I actually did find this section useful, but a new user would not).

Depending on how far you intend to take this, the addition of an efficient movement system would be useful (I take it this will come with your optimisation section).

Overall, good tut, very well written, and another great starting point for new users.

-Tv

I do prefer constants as well, but digits in GM are actually stores in a less planar system making it faster than defining a constant (blah). I haven't looked into making it a resource constant yet though, I'll think about it in the next set of tutorials. The reason for all the babble in the beginning is to let people know how complicated a connection is, and that the code presented in 39dll is nowhere near as complicated, it also gives them a basic foundation for internet workings and will help them move into more advanced topics later (which I can refer back to). If a new user cannot get through a few chapters of pseudonetworking, then I don't think they'd be able to make it through actual multiplayer creation...right? Plus I stated "this isn't going to be a test" and people can skip chapters :whistle: .

Yes, right now the code is not optimized for network transmissions other than no transmission is sent if the player doesn't move, and I will be touching on this in a later tut....thank you for the compliment!

Normally for message ID's a single byte will be fine since its not like your gunna be sending 255 different types of messages

This is true, except when you are dealing with encrypting code markers and in a game as massive as world of warcraft, you will need at least 30,000 codes. I could've used "writeshort" as a 2 byte code, but I'm use to "int" from my days in C++ so I used it.

Everyone: This tutorial is finished for the scope of knowledge I created it for. When I get some time to get my webpage working, I'll link in the gmk files that are in this tutorial for you.

Edited by sabriath, 03 September 2009 - 10:45 AM.

  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#28 Ichiroku

Ichiroku

    GMC Member

  • GMC Member
  • 237 posts
  • Version:GM:Studio

Posted 03 September 2009 - 12:39 PM

I can really see that there is alot of time put into this. and that time is well used, really great to see the rest of the chapters, hope to see those gmk files :3

maybe if there is more to come I will surely check it out :whistle:
  • 0

#29 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 03 September 2009 - 02:00 PM

The finished product is very good and helpfull, whats the next tutorial going to be about?

Edited by commander of games, 03 September 2009 - 02:02 PM.

  • 0

InvaderX.gif


#30 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 04 September 2009 - 01:42 AM

I can really see that there is alot of time put into this. and that time is well used, really great to see the rest of the chapters, hope to see those gmk files :3

The files have been put up in the header, they follow along with the chapters laid out in this tutorial. I have tested the code and fixed all the errors I could find. The files automatically contain the "127.0.0.1" IP pointer, so it works right out of the box for testing purposes (the IP is pointing to yourself).

Instructions in order:
run chapter14_server.gmk
run chapter14_client.gmk
use up/down/left/right to move around a bit
run another chapter14_client.gmk
move the windows so you can see all 3
move around on either client and watch the other client move you
right click any of the player's images in the server screen and it will disconnect that player

maybe if there is more to come I will surely check it out

The finished product is very good and helpfull, whats the next tutorial going to be about?

There will be more, and the next product will be dealing somewhat with a chat program (xshortguy is currently running a project on it, but I will be running one separate for tutorial purposes). I plan to impliment not only a lobby to chat in, but private messages and file transferring (to show how to set up double connections). This will be more intricate so I'm having to write the working product first, then I'll write the tutorial on it.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#31 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 04 September 2009 - 02:13 AM

A chat program is something I would like to see. Hey, maybe the chat example could enclude sending URL links to everyone else?

Edited by commander of games, 04 September 2009 - 02:13 AM.

  • 0

InvaderX.gif


#32 the_recruiting

the_recruiting

    GMC Member

  • New Member
  • 800 posts

Posted 04 September 2009 - 09:32 AM

  • 39ster {1} for the 39dll so I didn't have to write it myself
  • xshortguy for approving this tutorial before I was done
  • the_recruiting for giving me a reason to make this tutorial

I am honored to inspire a human being like yourself :whistle: By the way awesome tut.
  • 0

#33 randomazin

randomazin

    GMC Member

  • New Member
  • 84 posts

Posted 09 September 2009 - 12:22 AM

wow this is a good basic tutorial, really helped alot. thanks for making it
  • 0

#34 Zeddy

Zeddy

    Totally Radical Dude

  • GMC Member
  • 1891 posts
  • Version:GM:Studio

Posted 09 September 2009 - 08:17 AM

So, in summary:

- Start with dllinit(0, true, false);
- servers listen with tcplisten()
- clients connect with tcpconnect(ip, port, 2 or 1)
- send stuff with clearbuffer(), writeint(x), sendmessage(recipent)
- receive stuff with clearbuffer(), recievemessage(), readint()
- Keep ids for freaking everything.

This guide was helpful, thanks for writing it!
  • 0

#gmc - The totally awesome GMC IRC
Radical — NeaPunch.gif - PsychoPow.gif - DuoShip.png - stefanWalkAndTalk.gif - katiecat.png — Creations
Radical — The Consuming Shadow - Sienna - Turnabout Substitution - Ben There, Dan That — Recommendations


#35 lefty97

lefty97

    GMC Member

  • New Member
  • 49 posts

Posted 09 September 2009 - 11:12 PM

I was starting a game a while ago with another tutorial, and it didnt tell me which port to open. This covers all of that right?
  • 0

#36 shadowman465

shadowman465

    GMC Member

  • New Member
  • 244 posts

Posted 16 September 2009 - 01:05 AM

I really liked this tutorial it gives the basics really well but i was wondering if you could show how to like speed it up cause the movement is like delayed a couple seconds

-Thank you
  • 0
Best Game Ever Made: |||||||||||||||||||||||||||||| -10% Complete

#37 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 16 September 2009 - 01:36 AM

A chat program is something I would like to see. Hey, maybe the chat example could enclude sending URL links to everyone else?

There is a chat program in my projects list, I'll get to it eventually, thanks for the suggestion.

the_recruiting: I am honored to inspire a human being like yourself By the way awesome tut.

randomazin: wow this is a good basic tutorial, really helped alot. thanks for making it

zeddidragon:
So, in summary:

- Start with dllinit(0, true, false);
- servers listen with tcplisten()
- clients connect with tcpconnect(ip, port, 2 or 1)
- send stuff with clearbuffer(), writeint(x), sendmessage(recipent)
- receive stuff with clearbuffer(), recievemessage(), readint()
- Keep ids for freaking everything.

This guide was helpful, thanks for writing it!

Thanks and no problem

I was starting a game a while ago with another tutorial, and it didnt tell me which port to open. This covers all of that right?

No, but my second part tutorial contains documentation on port usage, I will put the link to it in the original post.

I really liked this tutorial it gives the basics really well but i was wondering if you could show how to like speed it up cause the movement is like delayed a couple seconds

-Thank you

No, thank you for reading it. There is no way to "speed it up" because the lag you see is network lag, there is absolutely no way to speed this up aside from making the customer purchase a faster internet connection. It can however be compressed and the movement not sent in every step...but this was just a beginning tutorial, it will be covered in another part later. For now I'm working on a compiler and other projects.

Edited by sabriath, 16 September 2009 - 01:37 AM.

  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#38 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 23 November 2009 - 10:52 AM

[BUMP] I have updated my link for the example files. I hope there are still people out there interested in my work. ;)
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#39 itatind09

itatind09

    GMC Member

  • New Member
  • 5 posts

Posted 23 November 2009 - 04:52 PM

I enjoyed that video. How many light balls do you have and where do you use yours?
  • 0

#40 commander of games

commander of games

    Kaos Kreator

  • GMC Member
  • 2883 posts
  • Version:GM:Studio

Posted 23 November 2009 - 04:58 PM

I enjoyed that video. How many light balls do you have and where do you use yours?

;) What video? And what 'light balls'? I think you might have posted in the wrong topic...
  • 0

InvaderX.gif


#41 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 23 November 2009 - 08:20 PM

I enjoyed that video. How many light balls do you have and where do you use yours?

:D What video? And what 'light balls'? I think you might have posted in the wrong topic...

I am also at a loss to understand that post ;)
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#42 Rassym

Rassym

    GMC Member

  • New Member
  • 286 posts
  • Version:Unknown

Posted 23 November 2009 - 08:39 PM

WOW! THIS TUTORIAL IS FANTASTIC!!
Im beginning to understand how online works in game maker!
Thanks! I just need to read this a few more times, and maybe read some other tutorials later!

But there is one thing about the example you teach us to make in this tutorial.
When i move left, right or down, or maybe up, it takes around 2 or 3 secs on the other client before it shows that client one moved!

So i will give this tutorial a 4/5! Good work!
Im beginning to learn this now! And it all thanks to you!
  • 0

#43 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 23 November 2009 - 09:03 PM

WOW! THIS TUTORIAL IS FANTASTIC!!
Im beginning to understand how online works in game maker!
Thanks! I just need to read this a few more times, and maybe read some other tutorials later!

But there is one thing about the example you teach us to make in this tutorial.
When i move left, right or down, or maybe up, it takes around 2 or 3 secs on the other client before it shows that client one moved!

So i will give this tutorial a 4/5! Good work!
Im beginning to learn this now! And it all thanks to you!

A 4/5 just because there is a delay on the network card? sheesh. I can't control network lag, that's not _my_ problem to solve. It is the sole purpose of dead-reckoning, and there is a topic in the advanced section here:

http://gmc.yoyogames...howtopic=415538

When I'm finished helping a friend with his game, I will get back to writing another tutorial which will handle dead-reckoning....but since this was a _beginner_ tutorial, I don't think I deserved a 4...that's not fair *pouts* ;)

Thanks for the post though and good luck.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#44 Rassym

Rassym

    GMC Member

  • New Member
  • 286 posts
  • Version:Unknown

Posted 23 November 2009 - 09:10 PM

WOW! THIS TUTORIAL IS FANTASTIC!!
Im beginning to understand how online works in game maker!
Thanks! I just need to read this a few more times, and maybe read some other tutorials later!

But there is one thing about the example you teach us to make in this tutorial.
When i move left, right or down, or maybe up, it takes around 2 or 3 secs on the other client before it shows that client one moved!

So i will give this tutorial a 4/5! Good work!
Im beginning to learn this now! And it all thanks to you!

A 4/5 just because there is a delay on the network card? sheesh. I can't control network lag, that's not _my_ problem to solve. It is the sole purpose of dead-reckoning, and there is a topic in the advanced section here:

http://gmc.yoyogames...howtopic=415538

When I'm finished helping a friend with his game, I will get back to writing another tutorial which will handle dead-reckoning....but since this was a _beginner_ tutorial, I don't think I deserved a 4...that's not fair *pouts* ;)

Thanks for the post though and good luck.


Oh sorry for that!
You're right it must be network lag.
*Changed ratings* 5/5
  • 0

#45 drame log

drame log

    GMC Member

  • New Member
  • 2 posts

Posted 03 January 2010 - 06:22 AM

when i run the client.exe i get this error

___________________________________________
ERROR in
action number 1
of Begin Step Event
for object obj_dll:

Error in code at line 22:
switch (code)
^
at position 10: Unknown variable code

i have double checked the code, it looks just like yours, i have know idea what it is
please help
  • 0

#46 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 03 January 2010 - 07:11 AM

when i run the client.exe i get this error

___________________________________________
ERROR in
action number 1
of Begin Step Event
for object obj_dll:

Error in code at line 22:
switch (code)
^
at position 10: Unknown variable code

i have double checked the code, it looks just like yours, i have know idea what it is
please help


I do not know what file you are talking about, considering the switch is on line 8, not 22. I do not know what you did with my files to come up with that error. I suggest re-downloading the file and try it again. The code in the block is:

if (server >= 0)
{
	size = receivemessage(server);
	if (size == 0) game_end();
	if (size > 0)
	{
		code = readint();
		switch (code)
		{
And as you can see...."code" is defined directly before the switch statement.
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#47 beatson

beatson

    GMC Member

  • GMC Member
  • 319 posts
  • Version:GM8

Posted 06 January 2010 - 04:42 PM

Im having a problem with port forwarding. Is it possible to host an online game with wireless internet? Iv given myself a static IP address on my network and iv port forwarded correctly. Followed tutorials online for my router several times. I know its correct. So this is the problem:

(all on port 80 - any other port doesnt connect to the server)
I run the server - everything works.
I run the client - It connects to the server.
I then click register an account and nothing happens. Im guessing it timesout or something? Anyone know whats wrong? (this happens with servers+clients I have coded with 39dll and also with all examples I can find..)

I did try using no-ip, but that does the same and times out. I also tried using a program called Hamachi to see if it was a problem with the coding etc. Everything works fine with Hamachi, but the other players must also have hamachi to successfuly connect.

Could this be with something to do with router firmware?
  • 0

VIS Design - Quality Web Design & Development


#48 BlaXun

BlaXun

    Slime Online Creator

  • GMC Member
  • 2750 posts
  • Version:GM:Studio

Posted 06 January 2010 - 07:03 PM

Not sure if somebody allready mentioned it, but you always use writeint in your scripts.
Maybe you could explain the difference between all the write...() functions and explain when to use which function to get the best results =)

Nice tutorial!
  • 0

iBNKRoX.png


#49 sabriath

sabriath

    12013

  • GMC Member
  • 3197 posts

Posted 07 January 2010 - 05:56 AM

Im having a problem with port forwarding. Is it possible to host an online game with wireless internet? Iv given myself a static IP address on my network and iv port forwarded correctly. Followed tutorials online for my router several times. I know its correct. So this is the problem:

(all on port 80 - any other port doesnt connect to the server)
I run the server - everything works.
I run the client - It connects to the server.
I then click register an account and nothing happens. Im guessing it timesout or something? Anyone know whats wrong? (this happens with servers+clients I have coded with 39dll and also with all examples I can find..)

I did try using no-ip, but that does the same and times out. I also tried using a program called Hamachi to see if it was a problem with the coding etc. Everything works fine with Hamachi, but the other players must also have hamachi to successfuly connect.

Could this be with something to do with router firmware?

My scripts do not currently have a "register" feature, so I'm not sure how I can help you if you are using yours or someone elses code. If you run the server and client and they connect, I don't see how this is a port-forwarding problem.

Not sure if somebody allready mentioned it, but you always use writeint in your scripts.
Maybe you could explain the difference between all the write...() functions and explain when to use which function to get the best results =)

Nice tutorial!

As you have already commented on the Part 2 tutorial, you see that I explain all of them. Thanks for the comments though, much appreciated! ;)
  • 0

Tutorials of Interest:
* Multiplayer: mine or True Valhalla's

Projects:
* Net39
* My 39dll scripts
* My 39dll lib
* Multiplayer Engine
* Artificial Chemistry

Posted Image

#50 beatson

beatson

    GMC Member

  • GMC Member
  • 319 posts
  • Version:GM8

Posted 08 January 2010 - 05:33 PM

Im having a problem with port forwarding. Is it possible to host an online game with wireless internet? Iv given myself a static IP address on my network and iv port forwarded correctly. Followed tutorials online for my router several times. I know its correct. So this is the problem:

(all on port 80 - any other port doesnt connect to the server)
I run the server - everything works.
I run the client - It connects to the server.
I then click register an account and nothing happens. Im guessing it timesout or something? Anyone know whats wrong? (this happens with servers+clients I have coded with 39dll and also with all examples I can find..)

I did try using no-ip, but that does the same and times out. I also tried using a program called Hamachi to see if it was a problem with the coding etc. Everything works fine with Hamachi, but the other players must also have hamachi to successfuly connect.

Could this be with something to do with router firmware?

My scripts do not currently have a "register" feature, so I'm not sure how I can help you if you are using yours or someone elses code. If you run the server and client and they connect, I don't see how this is a port-forwarding problem.

I see. I tried with your example (chapter 14) - I ran the server, then the client and they connected, (using my IP) - I then ran another client and it also connected with the server, but no messages could be sent between the client and server, and only 1 player was shown on both clients (obj_player). Do you have any idea why this might be?
  • 0

VIS Design - Quality Web Design & Development