SOLVED Client connecting to the server doesn't see already connected clients.

Hello. I am currently in the foundation phase of a making a game with multiplayer functionality.
But currently I've hit a speed bump and been unable to fix it for the last 3 days.


I've made an non-dedicated multiplayer system, where one player hosts the game, and others connect. (Host will also be a client of the server, but that is yet to be implemented.)

The code was actually more or less taken from a YouTube video series by Wizirdi (Link to the actual video with multiple players:
)

The issue is that the when a client connects, it shows up on the server's side, and also to clients that have already connected. But the already connected clients don't show up for the client that has recently connected.

server.jpgclient-1.jpgclient-2.jpg

Now, when the recent client moves, it shows up both on the first client, and the server. But as soon as the first client moves, the recent client gets thrown an exception.
1593617456699.png


If another client connects, it again is blind, the client before it only sees it, and the first client and the server see both of them, and so on.


Code for server_packet_received (Script):
GML:
buffer = argument0;
socket = argument1;

payload_id = buffer_read(buffer,buffer_u8)


switch (payload_id) {
    case network.move:
        var h_speed = buffer_read(buffer,buffer_s8);
        var v_speed = buffer_read(buffer,buffer_s8);
        var move_speed = buffer_read(buffer,buffer_f16);
        var player_id = ds_map_find_value(socket_to_instance_id,socket);
        var move_dir = point_direction(0,0,h_speed,v_speed);
        var move_x = lengthdir_x(move_speed,move_dir);
        var move_y = lengthdir_y(move_speed,move_dir);
        
        player_id.x += move_x;
        player_id.y += move_y;
        
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            buffer_seek(server_buffer,buffer_seek_start,0);
            buffer_write(server_buffer,buffer_u8,network.move);
            buffer_write(server_buffer,buffer_u8,socket);
            buffer_write(server_buffer,buffer_s8,h_speed);
            buffer_write(server_buffer,buffer_s8,v_speed);
            buffer_write(server_buffer,buffer_f16,move_speed);
            network_send_packet(_sock,server_buffer,buffer_tell(server_buffer));
            i++;
        }
}

Code for client_packet_received (Script):
GML:
buffer = argument0;
packet_id = buffer_read(buffer,buffer_u8);

switch (packet_id) {
    case network.player_connect:
        var _socket = buffer_read(buffer,buffer_u8);
        var _room = buffer_read(buffer,buffer_u8);
        var _x = buffer_read(buffer,buffer_u16);
        var _y = buffer_read(buffer,buffer_u16);
        
        var player_id = instance_create_depth(_x,_y,depth,obj_player_test);
        player_id.socket = _socket;
        ds_map_add(socket_to_instance_id,_socket,player_id);
        
        room_goto(_room);
        break;
    
    case network.player_joined:
        var _sock = buffer_read(buffer,buffer_u8);
        var _x = buffer_read(buffer,buffer_u16);
        var _y = buffer_read(buffer,buffer_u16);
        
        var other_id = instance_create_depth(_x,_y,depth,obj_player_test_other);
        show_debug_message(string(_x)+":"+string(_y));
        other_id.socket = _sock;
        ds_map_add(socket_to_instance_id,_sock,other_id);
        break;
        
    case network.player_disconnected:
        var _socket = buffer_read(buffer,buffer_u8);
        var player_id = ds_map_find_value(socket_to_instance_id,_socket);   
        instance_destroy(player_id);
        ds_map_delete(socket_to_instance_id,_socket);
        break;
        
    case network.move:
        var _sock = buffer_read(buffer,buffer_u8);
        var h_speed = buffer_read(buffer,buffer_s8);
        var v_speed = buffer_read(buffer,buffer_s8);
        var move_speed = buffer_read(buffer,buffer_f16);
        show_debug_message(string(h_speed)+":"+string(v_speed)+":"+string(move_speed))
        var player_id = ds_map_find_value(socket_to_instance_id,_sock);
        var move_dir = point_direction(0,0,h_speed,v_speed);
        var move_x = lengthdir_x(move_speed,move_dir);
        var move_y = lengthdir_y(move_speed,move_dir);
        
        player_id.x += move_x;
        player_id.y += move_y;
        break;
}

Code for obj_handler_server_create (Async - Networking):
GML:
type_event = ds_map_find_value(async_load,"type");

switch (type_event) {
    case network_type_connect:
        socket = ds_map_find_value(async_load,"socket");
        ds_list_add(socket_list,socket);
        var playerid = instance_create_depth(obj_playerSpawn.x,obj_playerSpawn.y,depth,obj_player_test_other);
        ds_map_add(socket_to_instance_id,socket,playerid);
        
        buffer_seek(server_buffer,buffer_seek_start,0);
        buffer_write(server_buffer,buffer_u8,network.player_connect);
        buffer_write(server_buffer,buffer_u8,socket);
        buffer_write(server_buffer,buffer_u8,room);
        buffer_write(server_buffer,buffer_u16,playerid.x);
        buffer_write(server_buffer,buffer_u16,playerid.y);
        network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
        
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            show_debug_message(string(socket_list)+":"+string(i))
            if (_sock != socket) {
                var other_id = ds_map_find_value(socket_to_instance_id,_sock);
                buffer_seek(server_buffer,buffer_seek_start,0);
                buffer_write(server_buffer,buffer_u8,network.player_joined);
                buffer_write(server_buffer,buffer_u8,_sock);
                buffer_write(server_buffer,buffer_u16,other_id.x);
                buffer_write(server_buffer,buffer_u16,other_id.y);
                network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
            }
            i++;
        }
        
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            if (_sock != socket) {
                buffer_seek(server_buffer,buffer_seek_start,0);
                buffer_write(server_buffer,buffer_u8,network.player_joined);
                buffer_write(server_buffer,buffer_u8,socket);
                buffer_write(server_buffer,buffer_u16,playerid.x);
                buffer_write(server_buffer,buffer_u16,playerid.y);
                network_send_packet(_sock,server_buffer,buffer_tell(server_buffer));
            }
            i++;
        }
        
        break;
        
    case network_type_disconnect:
        socket = ds_map_find_value(async_load,"socket");
        ds_list_delete(socket_list,ds_list_find_index(socket_list,socket));
        
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            buffer_seek(server_buffer,buffer_seek_start,0);
            buffer_write(server_buffer,buffer_u8,network.player_disconnected);
            buffer_write(server_buffer,buffer_u8,socket);
            network_send_packet(_sock,server_buffer,buffer_tell(server_buffer));
            i++;
        }
        
        with (ds_map_find_value(socket_to_instance_id,socket)) {
            instance_destroy();
        }
        
        ds_map_delete(socket_to_instance_id,socket);
        break;
    
    case network_type_data:
        buffer = ds_map_find_value(async_load,"buffer");
        socket = ds_map_find_value(async_load,"id");
        buffer_seek(buffer,buffer_seek_start,0);
        server_received_packet(buffer,socket);
        break;
}

If there is a need for any more code to be uploaded, or any questions to be answered, I'll try to be as swift as possible.
 

Mottafier

Member
I took a brief look, but I think I see the issue. In the obj_handler_server_create , in the first repeat loop, you have
GML:
buffer_seek(server_buffer,buffer_seek_start,0);
buffer_write(server_buffer,buffer_u8,network.player_joined);
buffer_write(server_buffer,buffer_u8,_sock);
buffer_write(server_buffer,buffer_u16,other_id.x);
buffer_write(server_buffer,buffer_u16,other_id.y);
network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
you have "buffer_write network.player_joined", but I think you want to write "network.player_connect" to this buffer, as this is the buffer that's supposed to send information to the recent client about the other players that have already joined.

I actually followed this tutorial recently and everything worked out fine for me, so I can verify that you're on the right track!
 

Mottafier

Member
I took a brief look, but I think I see the issue. In the obj_handler_server_create , in the first repeat loop, you have
GML:
buffer_seek(server_buffer,buffer_seek_start,0);
buffer_write(server_buffer,buffer_u8,network.player_joined);
buffer_write(server_buffer,buffer_u8,_sock);
buffer_write(server_buffer,buffer_u16,other_id.x);
buffer_write(server_buffer,buffer_u16,other_id.y);
network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
you have "buffer_write network.player_joined", but I think you want to write "network.player_connect" to this buffer, as this is the buffer that's supposed to send information to the recent client about the other players that have already joined.

I actually followed this tutorial recently and everything worked out fine for me, so I can verify that you're on the right track!
Actually hold on that was stupid, I don't think that's correct. Give me a bit I'm going to look into this thoroughly :D
 
An addition I forgot say that is on the recent client's side, in the client_packet_received, in the case network.player_joined, the most recent client DOES receive _x and _y of the first client.
In line 24, show_debug_message(string(_x)+":"+string(_y)) returns a value with the coords.
 

Mottafier

Member
I truly can't see anything wrong here... Could I see your server creation code?

Also stupid question, but your client and server are separate objects, and the exported client doesn't have a server object in it right?
 
I truly can't see anything wrong here... Could I see your server creation code?

Also stupid question, but your client and server are separate objects, and the exported client doesn't have a server object in it right?
Code for obj_handler_server_create [Create]
GML:
port = 61328;
max_clients = 4;
persistent = true;

network_create_server(network_socket_tcp,port,max_clients)

server_buffer = buffer_create(1024,buffer_fixed,1);
socket_list = ds_list_create();
socket_to_instance_id = ds_map_create();

room_goto(room_test);
Code for obj_handler_server_create [Async - Networking]
GML:
type_event = ds_map_find_value(async_load,"type");

switch (type_event) {
    case network_type_connect:
        socket = ds_map_find_value(async_load,"socket");
        ds_list_add(socket_list,socket);
        var playerid = instance_create_depth(obj_playerSpawn.x,obj_playerSpawn.y,depth,obj_player_test_other);
        ds_map_add(socket_to_instance_id,socket,playerid);
       
        buffer_seek(server_buffer,buffer_seek_start,0);
        buffer_write(server_buffer,buffer_u8,network.player_connect);
        buffer_write(server_buffer,buffer_u8,socket);
        buffer_write(server_buffer,buffer_u8,room);
        buffer_write(server_buffer,buffer_u16,playerid.x);
        buffer_write(server_buffer,buffer_u16,playerid.y);
        network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
       
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            show_debug_message(string(socket_list)+":"+string(i))
            if (_sock != socket) {
                var other_id = ds_map_find_value(socket_to_instance_id,_sock);
                buffer_seek(server_buffer,buffer_seek_start,0);
                buffer_write(server_buffer,buffer_u8,network.player_joined);
                buffer_write(server_buffer,buffer_u8,_sock);
                buffer_write(server_buffer,buffer_u16,other_id.x);
                buffer_write(server_buffer,buffer_u16,other_id.y);
                network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
            }
            i++;
        }
       
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            if (_sock != socket) {
                buffer_seek(server_buffer,buffer_seek_start,0);
                buffer_write(server_buffer,buffer_u8,network.player_joined);
                buffer_write(server_buffer,buffer_u8,socket);
                buffer_write(server_buffer,buffer_u16,playerid.x);
                buffer_write(server_buffer,buffer_u16,playerid.y);
                network_send_packet(_sock,server_buffer,buffer_tell(server_buffer));
            }
            i++;
        }
       
        break;
       
    case network_type_disconnect:
        socket = ds_map_find_value(async_load,"socket");
        ds_list_delete(socket_list,ds_list_find_index(socket_list,socket));
       
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            buffer_seek(server_buffer,buffer_seek_start,0);
            buffer_write(server_buffer,buffer_u8,network.player_disconnected);
            buffer_write(server_buffer,buffer_u8,socket);
            network_send_packet(_sock,server_buffer,buffer_tell(server_buffer));
            i++;
        }
       
        with (ds_map_find_value(socket_to_instance_id,socket)) {
            instance_destroy();
        }
       
        ds_map_delete(socket_to_instance_id,socket);
        break;
   
    case network_type_data:
        buffer = ds_map_find_value(async_load,"buffer");
        socket = ds_map_find_value(async_load,"id");
        buffer_seek(buffer,buffer_seek_start,0);
        server_received_packet(buffer,socket);
        break;
}

If anything else is needed, I'll try to respond as swiftly as I can.
 
Last edited:

Yal

🍋 *lemon noises*
GMC Elder
But the already connected clients don't show up for the client that has recently connected.
When connecting a new client, you should also give them a list of all currently existing clients connected to the server. They won't magically know about anything that happened BEFORE they got connected.

At first glance, I'd guess the error is because you don't create instances matching pre-connected clients, then try to use their IDs.
 
When connecting a new client, you should also give them a list of all currently existing clients connected to the server. They won't magically know about anything that happened BEFORE they got connected.

At first glance, I'd guess the error is because you don't create instances matching pre-connected clients, then try to use their IDs.
By idea this is what the for loop in obj_handler_server_create [Async - Networking] (line 18-32) does.
GML:
        var i = 0;
        repeat(ds_list_size(socket_list)) {
            var _sock = ds_list_find_value(socket_list,i);
            show_debug_message(string(socket_list)+":"+string(i))
            if (_sock != socket) {
                var other_id = ds_map_find_value(socket_to_instance_id,_sock);
                buffer_seek(server_buffer,buffer_seek_start,0);
                buffer_write(server_buffer,buffer_u8,network.player_joined);
                buffer_write(server_buffer,buffer_u8,_sock);
                buffer_write(server_buffer,buffer_u16,other_id.x);
                buffer_write(server_buffer,buffer_u16,other_id.y);
                network_send_packet(socket,server_buffer,buffer_tell(server_buffer));
            }
            i++;
        }
It sends each connected client's id (_sock), and their coords (other_id.x and other_id.y) to the newly connected client (network_send_packet(socket,server_buffer,buffer_tell(server_buffer));)
 
SOLVED.

I have solved this issue myself and figured out why it happens.
It appears that when new clients connect, they're expected to be in the same room as the others to create their respective instances.

Solution:
I created another handler object specifically for this room. Once the client parses and goes to the room sent by the server, they are immediately introduced with the the handler object.
On Create, the handler sets an alarm for ~20 steps, and then begins creating the instances.

This issue is now resolved. Others will come with time. Thanks to anyone that participated in this thread.
 
Top