• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

Understanding Sever Client Connections for Chatrooms

huenix

Member
I am building chatrooms and I am trying to understand something.
IE: i want two people who are "KNIGHTS" to be connected in a chatroom vs "MAGE" or "ARCHER"... etc...

How do you know two people are connecting to each other only under those terms?
Does it have to do with the ports? ie: make it so "Knights" use ports "987987" and "Mages" use "789789" etc?
...or am i going about it all wrong?
 

chamaeleon

Member
Encode required information in the messages being sent, or manage metadata in the server about the user connection based on login and what properties the logged in person has, as desired.
 

TomOmNom

Member
You might be going about this wrong.
When a client connects ask them what class they want to be (knight, mage etc.). Pass this info to the server. Then have the server make a list, of all the clients' sockets. Attach their class to this list. Now you have a list of the users in one class
If you want to know what class is the client sending the message, simply add a value (probably an enum is gonna be your best bet) as a part of your buffer. Then, server-side, loop through and only send this message to the other clients tagged with that class in your list. This is how I implemented names into my chatroom, but it should work with what you're trying to do.

Hope that made sense. Good luck!
 

huenix

Member
Encode required information in the messages being sent, or manage metadata in the server about the user connection based on login and what properties the logged in person has, as desired.
could you explain this a little more?
i THINK what you are saying is what i want.... i have made it simple for now, for testing.... so when user presses:
1... (class = Knight)
2... ( class = Mage)
3... (class = Archer)

if i make it so only two-four clients are able to connect to each server, how do i make sure ONLY clients that connect to it are "KNIGH"?
 
Last edited:

chamaeleon

Member
What is your plan for determining whether a player is allowed to establish a connection to the server at all? How do you plan to implement player identity?
 

Xer0botXer0

Senpai
I don't remember the code, wish i did but it's really simple to setup client server.
Once you've done that you'll see that the server has it's own socket id which the clients will store in their server connection string I believe, and when clients join the server the server will receive the clients socket id, which you then add to a ds_list or array, from there you can use the socket id to create an identity for each client based on the information they send you. The socket ID helps because the client never needs to send additional information to verify its identity.

Since the first value the server receives is which client is sending data, you then read the next data one line at a time(thanks to how gms parses the data or something like that) And the client could send this

3
1
3

the server inputs the first value into a switch statement, 3 means attack, so the switch within the switch then reads 1 as who to attack, so attack enemy 1, then server reads the third value 3 which represents the type of attack or ability.

Server calculates the data and if it works out the server sends a data back to the relevant clients to tell them to play out the attack sequence.
 

huenix

Member
Lmao, ports.
ports how? .....
i thought about this too.... but wasn't sure if i understood ports fullly & correctly....
is this true?...

if the port was changed buy there user, let's just say for example ( 1 for knight, 2 for mage, 3 for archer)

can they ONLY talk to each other, if the ports match too?
 

huenix

Member
What is your plan for determining whether a player is allowed to establish a connection to the server at all? How do you plan to implement player identity?
by their class/subclass (there are many, so it was easiest)

at the start each character has its own class with and added subclass based off the players choice at the begining:
ie:
Warrior:
-Knight
-Berserker
-Paladin

Caster:
-Mage
-Wizard
-Summoner

ETC.....
 

chamaeleon

Member
by their class/subclass (there are many, so it was easiest)

at the start each character has its own class with and added subclass based off the players choice at the begining:
ie:
Warrior:
-Knight
-Berserker
-Paladin

Caster:
-Mage
-Wizard
-Summoner

ETC.....
No, no, no... How do you technically plan to implement anything that represent player identity and whether a player connecting is in fact some given player and not someone else? Unless, of course, it is only relevant for the duration of a connection, and reconnecting means not having any prior information of this person playing retained.
 

huenix

Member
No, no, no... How do you technically plan to implement anything that represent player identity and whether a player connecting is in fact some given player and not someone else? Unless, of course, it is only relevant for the duration of a connection, and reconnecting means not having any prior information of this person playing retained.
sorry i guess i dont understand the question :(
i have made (with tutorials) 3 different S/C tutorials and im just not understanding the HOW to decide what two clients can match to the same server, in all of the tutorials you just match with anyone that connects ......

like here... here is for joining server in chat, if you can ( feel like this is where i could try to "match" the right "class" variables

var s_id = ds_map_find_value(async_load, "id");
var type = ds_map_find_value(async_load, "type");

if (s_id == client_socket)
{
if (type == network_type_non_blocking_connect)
{
var succeeded = ds_map_find_value(async_load, "succeeded");
if (succeeded == 0)
{
show_message("Connection failed.");
game_restart();
}else
{
client_send_user_info();
room_goto(rm_chat);
}
}
}
 

chamaeleon

Member
The technical aspect of network communication is a different problem to solve than the data representation you need in clients and servers in order to do the right thing in each type of program based on the data received in your network events. You need to spend time thinking about this data representation (there's no one right solution, but you need to have something). The ds_map used by the network event is not sufficient for your purposes. You need something outside the scope of that holding some kind of information. This is the problem solving part of programming you need to get used to.

Edit: To expand on it, the network events will create or remove data from your data structures. Network events will update data in your data structures. Network events will result in other parts of code performing certain actions depending on both the content in the network event and other existing data in your data structures. Etc., etc. You "just" need to figure out what you need to represent, and how. With GMS 2.3+ you now have the very flexible structs. I recommend using them. Store them in arrays, ds_lists, ds_maps, ds_grids, whatever fits a particular purpose (again, no one correct answer, it depends on code use cases).
 
Last edited:

huenix

Member
The technical aspect of network communication is a different problem to solve than the data representation you need in clients and servers in order to do the right thing in each type of program based on the data received in your network events. You need to spend time thinking about this data representation (there's no one right solution, but you need to have something). The ds_map used by the network event is not sufficient for your purposes. You need something outside the scope of that holding some kind of information. This is the problem solving part of programming you need to get used to.
ok.... yah that i understand lol.... thank you for your help though :)
 

Xer0botXer0

Senpai
Sorry for not contributing here properly,

It feels like you've got some misconception.

You do understand that the port is only a gateway between connecting sockets, ports are assigned like numbers on a page, without the port or page number, you can send data to an IP or browse through a book but not find what you're looking for. If you've got the page number you can get back to where you were, if you've got the port number the communication can continue.

Or like intergalactic space travel, you could know where another galaxy is location, but without a wormhole between the two locations well then you've got no port. lol

So I believe you confused ports with something else..
Perhaps the structure of communication packets between sockets.

Say you've got your client<>server connection setup. 3 clients are connected to 1 server. The 1 server has 3 socket IDs which it collected as the clients connected 1 by 1 since GMS isn't multithreaded it'll deal with clients one at a time.

Each client has a different socket ID, starting at 0 or 1 I believe, the server doesn't store it automatically, you'd put it in a list for later reference/use.

The clients have 1 ID for the server, which is probably 0 or 1 as well.. it simply increments but I'm sure there's more data behind it in the metacode of GM.

Connection is up, now what ?

we play with scenarios, what usually comes first ? registration, login, character creation, verification, that sorta stuff, you've also got movement, loading other player movement, accessing inventory, pretty much everything. You could also, btw retrieve a list from the server of IP:pORTs of other connected client/players and communicate with them directly, which is known as PeerToPeer. It's just a different hierarchy of data flow.

My approach to handling these different scenarios was thinking of it as a multidimensional array, hierarchy, or switch statements within switch statements, by that I mean the absolute first thing that happens when I handle networking is setting up the server, connecting to it, then the player clicks register and sends a network packet to the server containing the integer value "0", followed by a string "bob2023"(usn) followed by a string "39fj38j4f"(psw) some other things also occur like "remember password" will be a boolean that's value is stored client/player side in a .ini file or something, since it's unnecessary for the server to remember that information for the player. The server receives the socket ID on the async data event in the relevant DS_MAP? you then as in the code you posted, check to see the event type, and then receive the packets one at a time. The server will receive the int 0, the usn and psw and compute that, ensuring it passes filters and rules, the server still having the socket_id of the client, sends back a packet to the client with the int "0", the clients switch statement knows 0 represents registration stuff, the server in the next line of code sends the int 1, or int 0 and sends the packet, so client knows that 0 means registration, and that the data that follows will be relevant to registration, the client expects either a 0 or a 1 in the switch statement, or if statement.. 0, 0 means it's a registration event and the registration attempt was a failure, 0, 1 means it's a registration event and it was a success. So the user has registered and can now login.

The server would add the registration details to a data structure and store it immediately or later on to it's database.

The client then clicks login and sends the int 1 , string "bob2023" and string " 39fijieji" to the server, the server knows that 0 means register, 1 means login, this is a 1 so the following data in order will be a username and password, read it, compute it and respond accordingly.

I've heard that it's good practice to use constants for these defining values, alternatively you can be an idiot like me and not do that until eventually you've got 30-40 primary values coming through and it gets confusing(oh it helps to document what they all mean for quicker communication).

Right, but the reason people use integers instead of strings where "0" would mean "Register_event" and "1" "Login_event" is due to bandwidth, and a whole lot of other nonsense.

I hope I clarified a thing or two. It's quite a long read but I tried to keep it somewhat simple but still valuable. Let me know if it's jargon. :cool:
 

Mr Magnus

Viking King
The client says "I am a knight" when connecting. The server says "Great!" and notes that down. Whenever the client sends the server a message the server only forwards it to the other clients who said "I am a knight" when connecting. If a mage then connects and says "I am a mage" the server will say "Great!" and only forward their messages to other mages.

You don't need split ports, nor fancy connection tricks, nor separated servers, nor anything remotely complicated: All you need is just have your clients tell the server who they are and the server handles connecting the right players together.

You can also do this if you are doing client-to-client connections: Clients say "I am a knight", and the other client goes "Hey! Me too! Let's chat!" and moves on, or goes "I am a Barbarian, I do not want to talk to you".

If you're making a chatroom you're already sending some information back and forth, nothing to stop you including a bit of information in the message for things like this.
 

huenix

Member
Sorry for not contributing here properly,

It feels like you've got some misconception.

You do understand that the port is only a gateway between connecting sockets, ports are assigned like numbers on a page, without the port or page number, you can send data to an IP or browse through a book but not find what you're looking for. If you've got the page number you can get back to where you were, if you've got the port number the communication can continue.

Or like intergalactic space travel, you could know where another galaxy is location, but without a wormhole between the two locations well then you've got no port. lol

So I believe you confused ports with something else..
Perhaps the structure of communication packets between sockets.

Say you've got your client<>server connection setup. 3 clients are connected to 1 server. The 1 server has 3 socket IDs which it collected as the clients connected 1 by 1 since GMS isn't multithreaded it'll deal with clients one at a time.

Each client has a different socket ID, starting at 0 or 1 I believe, the server doesn't store it automatically, you'd put it in a list for later reference/use.

The clients have 1 ID for the server, which is probably 0 or 1 as well.. it simply increments but I'm sure there's more data behind it in the metacode of GM.

Connection is up, now what ?

we play with scenarios, what usually comes first ? registration, login, character creation, verification, that sorta stuff, you've also got movement, loading other player movement, accessing inventory, pretty much everything. You could also, btw retrieve a list from the server of IP:pORTs of other connected client/players and communicate with them directly, which is known as PeerToPeer. It's just a different hierarchy of data flow.

My approach to handling these different scenarios was thinking of it as a multidimensional array, hierarchy, or switch statements within switch statements, by that I mean the absolute first thing that happens when I handle networking is setting up the server, connecting to it, then the player clicks register and sends a network packet to the server containing the integer value "0", followed by a string "bob2023"(usn) followed by a string "39fj38j4f"(psw) some other things also occur like "remember password" will be a boolean that's value is stored client/player side in a .ini file or something, since it's unnecessary for the server to remember that information for the player. The server receives the socket ID on the async data event in the relevant DS_MAP? you then as in the code you posted, check to see the event type, and then receive the packets one at a time. The server will receive the int 0, the usn and psw and compute that, ensuring it passes filters and rules, the server still having the socket_id of the client, sends back a packet to the client with the int "0", the clients switch statement knows 0 represents registration stuff, the server in the next line of code sends the int 1, or int 0 and sends the packet, so client knows that 0 means registration, and that the data that follows will be relevant to registration, the client expects either a 0 or a 1 in the switch statement, or if statement.. 0, 0 means it's a registration event and the registration attempt was a failure, 0, 1 means it's a registration event and it was a success. So the user has registered and can now login.

The server would add the registration details to a data structure and store it immediately or later on to it's database.

The client then clicks login and sends the int 1 , string "bob2023" and string " 39fijieji" to the server, the server knows that 0 means register, 1 means login, this is a 1 so the following data in order will be a username and password, read it, compute it and respond accordingly.

I've heard that it's good practice to use constants for these defining values, alternatively you can be an idiot like me and not do that until eventually you've got 30-40 primary values coming through and it gets confusing(oh it helps to document what they all mean for quicker communication).

Right, but the reason people use integers instead of strings where "0" would mean "Register_event" and "1" "Login_event" is due to bandwidth, and a whole lot of other nonsense.

I hope I clarified a thing or two. It's quite a long read but I tried to keep it somewhat simple but still valuable. Let me know if it's jargon. :cool:
that was a LOT lol.. BUT.... VERY helpful... and i love the page number/galaxy metaphor, i do so much better with metaphors lol.... i will need to re read a few time the middle, but i think i understand now, and what direction i need to go, especially the idea of a having clients join, and then, THEN do what i need :)

one last question... when you create a server for a game, lets say its 10 people.... what happens when a 11th+ player tries to start/play game...
-i know GML server can't host too many depending on what it is, but even still, if using AWS for server hosting....
 

huenix

Member
The client says "I am a knight" when connecting. The server says "Great!" and notes that down. Whenever the client sends the server a message the server only forwards it to the other clients who said "I am a knight" when connecting. If a mage then connects and says "I am a mage" the server will say "Great!" and only forward their messages to other mages.

You don't need split ports, nor fancy connection tricks, nor separated servers, nor anything remotely complicated: All you need is just have your clients tell the server who they are and the server handles connecting the right players together.

You can also do this if you are doing client-to-client connections: Clients say "I am a knight", and the other client goes "Hey! Me too! Let's chat!" and moves on, or goes "I am a Barbarian, I do not want to talk to you".

If you're making a chatroom you're already sending some information back and forth, nothing to stop you including a bit of information in the message for things like this.
this is EXACLTY what i am trying to do/doing... the chat room is working, i just need to implement more i guess... also, the analogy is SPOT ON!!!
 

Xer0botXer0

Senpai
I've no idea, you can test it by setting max users to 0, if 0 is possible, otherwise to 1 and compile your client project into an executable and test max_clients +1.

I believe max users is set in the server start function
 

huenix

Member
I've no idea, you can test it by setting max users to 0, if 0 is possible, otherwise to 1 and compile your client project into an executable and test max_clients +1.

I believe max users is set in the server start function
good idea lol... idk why i didn't think of that lol... (face palm)

(update) .... "connection failed" (a code i have to show if joining a room fails) good to know
 
Top