GMS 2 Reading from outside buffer

Squillem

Member
Hey all, I've run into a weird networking bug. I've got two projects, a client and a server. When I run both on my local computer, or both on an Azure VM, they work fine. However, if I try to run the client on my local machine and the server on a VM, I get the following error as soon as I connect:

GML:
___________________________________________
############################################################################################
ERROR in
action number 1
of Async Event: Networking
for object con_server:

Attempting to read from outside the buffer, returning 0
at gml_Script_scr_recieved_packet
############################################################################################
gml_Script_scr_recieved_packet (line -1)
gml_Object_con_server_Other_68
For context, con_server is an object that controls the networking in the server project. Whenever I get a message that is network_type_data, I send the info from it into the script scr_received_packet, where the buffer is read & interpreted. If the error gave me a non-negative line number, chasing down exactly where the issue is would be no problem. Unfortunately, as you can see, it gives me -1.

My questions are as follows:

1. What does an error occurring on line -1 of a script mean?
2. How do I start when trying to resolve such an error?
3. It seems some part of the network communication between my computer and the VM is causing a problem here. How can I go about attempting to solve this?
4. How does one debug when running a .exe file? I can't run gamemaker on the VM, only the .exe, and when I tried adding "-debugoutput file.txt" to the path in the server shortcut's properties it wouldn't show output from my show_debug_message calls.

Code from con_server's Async - Networking event:

GML:
/// @description Parse client information

// Async makes a ds_map w/ a bunch of info in it
type_event = ds_map_find_value(async_load, "type");

switch(type_event) {
   
    case network_type_connect:
        // When you get a connect message, add the client to the list
        socket = ds_map_find_value(async_load, "socket");
        ds_list_add(socket_list, socket);
        if (current_player_number < max_clients){
            current_player_number++;
            buffer_seek(server_buffer, buffer_seek_start, 0);
            buffer_write(server_buffer, buffer_u8, network.player_establish);
            buffer_write(server_buffer, buffer_u8, socket);
            network_send_packet(socket, server_buffer, buffer_tell(server_buffer));
            show_debug_message("SEND: player_establish: "+string(current_time));
        }
        else {
           
            buffer_seek(server_buffer, buffer_seek_start, 0);
            buffer_write(server_buffer, buffer_u8, network.player_denied);
            network_send_packet(socket, server_buffer, buffer_tell(server_buffer));
        }
       
        break;
       
    case network_type_disconnect:
        // When you get a disconnect message, remove the client from the list
        socket = ds_map_find_value(async_load, "socket");
        ds_list_delete(socket_list, ds_list_find_index(socket_list, socket));
       
       
        // Broadcast which player disconnected
        for(var i = 0; i < ds_list_size(socket_list); i++) {
            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_disconnect);
            buffer_write(server_buffer, buffer_u8, socket);
            network_send_packet(_sock, server_buffer, buffer_tell(server_buffer));
            show_debug_message("SEND: player_disconnect: "+string(current_time));
        }
       
        // Make the player destroy itself
        if (ds_map_find_value(socket_to_instanceid, socket) != noone and !is_undefined(ds_map_find_value(socket_to_instanceid, socket))){
            with (ds_map_find_value(socket_to_instanceid, socket)) {
                instance_destroy();  
            }
            ds_map_delete(socket_to_instanceid, socket);
        }
        current_player_number--;
       
        break;
       
    case network_type_data:
        // When you get data, send out the appropriate messages
        buffer = ds_map_find_value(async_load, "buffer");
        socket = ds_map_find_value(async_load, "id");
        scr_received_packet(buffer, socket);
        break;
}



Code from scr_received_packet:

GML:
/// @description Determine what to do based on data recieved
function scr_received_packet(buffer, socket) {
    buffer_seek(buffer, buffer_seek_start, 0); // Go to start of buffer
    msgid = buffer_read(buffer, buffer_u8);
   
    // All the possible things we may need the server to do should be in here
    switch (msgid) {
        case network.player_establish:
            #region player_establish
            show_debug_message("RECEIVE: player_establish: "+string(current_time));
           
            /*
            var _username = buffer_read(buffer, buffer_string);
            var _sprite_sheet = buffer_read(buffer, buffer_u8);
            scr_network_player_join(_username, _sprite_sheet);
            */
           
            // If this player's establishment fills the server, tell all the players that the server is now full.
            if (con_server.current_player_number == con_server.max_clients) {
                for(var i = 0; i < ds_list_size(socket_list); i++) {
                    var _sock = ds_list_find_value(socket_list, i);
                    buffer_seek(server_buffer, buffer_seek_start, 0);                // Start from top of buffer
                    buffer_write(server_buffer, buffer_u8, network.server_full);    // Message ID           
                    network_send_packet(_sock, server_buffer, buffer_tell(server_buffer));
                    show_debug_message("SEND: server_full: "+string(current_time));
                }
            }
           
            #endregion
            break;
       
        case network.server_full:
            #region server_full
           
            show_debug_message("RECEIVE: server_full: "+string(current_time));
            var _username = buffer_read(buffer, buffer_string);
            var _sprite_sheet = buffer_read(buffer, buffer_u8);
            scr_network_player_join(_username, _sprite_sheet);
           
            #endregion
            break;
       
        case network.move:
            #region move
            show_debug_message("RECEIVE: move: "+string(current_time));
           
            // Make sure your reads & writes match. Write string -> read string.
            var h_input = buffer_read(buffer, buffer_s8);
            var v_input = buffer_read(buffer, buffer_s8);
            var walk_speed = buffer_read(buffer, buffer_u8);
           
            var _player = ds_map_find_value(socket_to_instanceid, socket);
           
            // Move the player
            if (global.show_visuals) {
                with (_player) {
                    if (h_input != 0 or v_input != 0) {
                        var move_dir = point_direction(0, 0, h_input, v_input);
                        var move_x = lengthdir_x(walk_speed, move_dir);
                        var move_y = lengthdir_y(walk_speed, move_dir);   
                   
                        x += move_x;
                        y += move_y;
                   
                        // Set sprites based on move direction
                        switch(move_dir) {
                            case 0: sprite_index = spr_r_strip4; break;            // Right
                            case 45: sprite_index = spr_ur_strip4; break;        // Up-Right
                            case 90: sprite_index = spr_u_strip4; break;        // Up
                            case 135: sprite_index = spr_ul_strip4; break;        // Up-Left
                            case 180: sprite_index = spr_l_strip4; break;        // Left
                            case 225: sprite_index = spr_dl_strip4; break;        // Down-Left
                            case 270: sprite_index = spr_d_strip4; break;        // Down
                            case 315: sprite_index = spr_dr_strip4; break;        // Down-Right
                        }
                    } else {
                        image_index = 0;
                    }
                }
            }
           
            // Broadcast movement to all players
            for(var i = 0; i < ds_list_size(socket_list); i++) {
               
                var _sock = ds_list_find_value(socket_list, i);
               
                buffer_seek(server_buffer, buffer_seek_start, 0);        // Start from top of buffer
                buffer_write(server_buffer, buffer_u8, network.move);    // Message ID
               
                buffer_write(server_buffer, buffer_u8, socket);            // Socket of the moving player
               
                buffer_write(server_buffer, buffer_s8, h_input);        // Horizontal input
                buffer_write(server_buffer, buffer_s8, v_input);        // Vertical input
                buffer_write(server_buffer, buffer_u8, walk_speed);        // Walk speed
               
                network_send_packet(_sock, server_buffer, buffer_tell(server_buffer));
                show_debug_message("SEND: move: "+string(current_time));
            }
           
            #endregion
            break;
           
        case network.chat:
            #region chat
            //show_debug_message("RECEIVE: chat: "+string(current_time));
           
            var _chat = buffer_read(buffer, buffer_string);
            var    _player = ds_map_find_value(socket_to_instanceid, socket);
           
            _chat = _player.username + ":" + _chat;                    // Append username to show who it's from
            ds_list_insert(global.chat, 0, _chat);
           
            //TODO: Potential issues here, 32:44 in networking video (https://youtu.be/NbsXRuNijlo) (Could be another one in the series)
            var _color1 = buffer_read(buffer, buffer_u8);
            var _color2 = buffer_read(buffer, buffer_u8);
            var _color3 = buffer_read(buffer, buffer_u8);
            ds_list_insert(global.chat_color, 0, make_color_rgb(_color1, _color2, _color3));
           
            for(var i = 0; i < ds_list_size(socket_list); i++) {
               
                var _sock = ds_list_find_value(socket_list, i);
               
                buffer_seek(server_buffer, buffer_seek_start, 0);        // Start from top of buffer
                buffer_write(server_buffer, buffer_u8, network.chat);    // Message ID
                buffer_write(server_buffer, buffer_string, _chat);        // Message contents
                buffer_write(server_buffer, buffer_u8, _color1);        // Message color (number that maps to it)
                buffer_write(server_buffer, buffer_u8, _color2);        // Message color (number that maps to it)
                buffer_write(server_buffer, buffer_u8, _color3);        // Message color (number that maps to it)
                network_send_packet(_sock, server_buffer, buffer_tell(server_buffer));
                //show_debug_message("SEND: chat: "+string(current_time));
            }
            #endregion
            break;
   
        case network.task:
            #region task
            //show_debug_message("RECEIVE: task: "+string(current_time));
           
            var add_to_taskbar = buffer_read(buffer, buffer_u8);

            // Add to total taskbar
            global.task += add_to_taskbar;
           
            // Broadcast taskbar status to all players
            for(var i = 0; i < ds_list_size(socket_list); i++) {
               
                var _sock = ds_list_find_value(socket_list, i);
               
                buffer_seek(server_buffer, buffer_seek_start, 0);        // Start from top of buffer
                buffer_write(server_buffer, buffer_u8, network.task);    // Message ID
               
                buffer_write(server_buffer, buffer_u8, global.task);            // Taskbar
               
                network_send_packet(_sock, server_buffer, buffer_tell(server_buffer));
                //show_debug_message("SEND: task: "+string(current_time));
            }
            #endregion
            break;
           
        case network.pause:
            #region pause
            //show_debug_message("RECEIVE: pause: "+string(current_time));
           
            var _player = ds_map_find_value(socket_to_instanceid, socket);
           
            // Stop player from animating
            _player.image_index = 0;
            _player.image_speed = 0;
           
            // Echo the message out
            for(var i = 0; i < ds_list_size(socket_list); i++) {
                var recipient_socket = ds_list_find_value(socket_list, i);
               
                if (recipient_socket != socket) {
                    buffer_seek(server_buffer, buffer_seek_start, 0);
                    buffer_write(server_buffer, buffer_u8, network.pause);
                    buffer_write(server_buffer, buffer_u8, socket);            // Socket of the pausing player
                    network_send_packet(recipient_socket, server_buffer, buffer_tell(server_buffer));
                    //show_debug_message("SEND: pause: "+string(current_time));
                }
            }
           
            #endregion
            break;
           
        case network.unpause:
            #region unpause
            //show_debug_message("RECEIVE: unpause: "+string(current_time));
           
            var _player = ds_map_find_value(socket_to_instanceid, socket);
           
            // Restore normal animation
            _player.image_speed = _player.default_image_speed;
           
            // Echo it out
            for(var i = 0; i < ds_list_size(socket_list); i++) {
                var recipient_socket = ds_list_find_value(socket_list, i);
               
                if (recipient_socket != socket) {
                    buffer_seek(server_buffer, buffer_seek_start, 0);
                    buffer_write(server_buffer, buffer_u8, network.unpause);
                    buffer_write(server_buffer, buffer_u8, socket);            // Socket of the unpausing player
                    network_send_packet(recipient_socket, server_buffer, buffer_tell(server_buffer));
                    //show_debug_message("SEND: unpause: "+string(current_time));
                }
            }
           
            #endregion
            break;
       
        case network.revive:
            #region revive
           
            #endregion
            break;
       
        case network.update_infection_level:
            #region update_infection_level
            var _player = ds_map_find_value(socket_to_instanceid, socket);
            var infection_level = buffer_read(buffer, buffer_u8);
           
            // Echo it out
            for(var i = 0; i < ds_list_size(socket_list); i++) {
                var recipient_socket = ds_list_find_value(socket_list, i);
               
                if (recipient_socket != socket) {
                    buffer_seek(server_buffer, buffer_seek_start, 0);
                    buffer_write(server_buffer, buffer_u8, network.update_infection_level);
                    buffer_write(server_buffer, buffer_u8, socket);            // Socket of the unpausing player
                    buffer_write(server_buffer, buffer_u8, infection_level);
                    network_send_packet(recipient_socket, server_buffer, buffer_tell(server_buffer));
                    //show_debug_message("SEND: unpause: "+string(current_time));
                }
            }
           
            #endregion
            break;
       
        case network.duotask:
            #region duotask
            //show_debug_message("RECEIVE: duotask: " + string(current_time));
           
            var object_id = buffer_read(buffer, buffer_u32);
            var add = buffer_read(buffer, buffer_s8);
           
            //show_debug_message("add is " + string(add));

            if ds_map_exists(global.duotask_map, object_id){
                if ((ds_map_find_value(global.duotask_map, object_id) == 0) && (add == 1)){
                    //show_debug_message("add 1 player");
                    ds_map_replace(global.duotask_map, object_id, 1);
                }
               
                else if ((ds_map_find_value(global.duotask_map, object_id) == 1) && (add == -1)) {
                    //show_debug_message("remove 1 player");
                    ds_map_replace(global.duotask_map, object_id, 0);
                }
               
                else if ((ds_map_find_value(global.duotask_map, object_id) == 1) && (add == 1)) {
                    //show_debug_message("complete duotask");
                    ds_map_replace(global.duotask_map, object_id, 0);

                    // Broadcast completion status to all players
                    for(var i = 0; i < ds_list_size(socket_list); i++) {

                        var _sock = ds_list_find_value(socket_list, i);

                        buffer_seek(server_buffer, buffer_seek_start, 0);            // Start from top of buffer
                        buffer_write(server_buffer, buffer_u8, network.duotask);    // Message ID

                        buffer_write(server_buffer, buffer_u32, object_id);            // Send back object id
               
                        network_send_packet(_sock, server_buffer, buffer_tell(server_buffer));
                    }
                }
               
            } else if (add == 1) {
                //show_debug_message("add new object");
                ds_map_add(global.duotask_map, object_id, 1);
            }
            #endregion
            break;
    }
}
 
Last edited:

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
1. What does an error occurring on line -1 of a script mean?
If you have compiled your game in VM (as opposed to YYC) and are not running from IDE, line numbers are not preserved.
2. How do I start when trying to resolve such an error?
The easiest would be to replicate your error while running in debug mode so that you could look at your variables and the buffer inspector in debug tools (which by default is on Others tab IIRC). Failing that, compile with YYC to have line numbers in error messages.
3. It seems some part of the network communication between my computer and the VM is causing a problem here. How can I go about attempting to solve this?
If you are using TCP and network_connect_raw, you should be aware that packets can concatenate since TCP does not actually have a concept of a datagram - it's a stream-based protocol.
4. How does one debug when running a .exe file? I can't run gamemaker on the VM, only the .exe, and when I tried adding "-debugoutput file.txt" to the path in the server shortcut's properties it wouldn't show output from my show_debug_message calls.
There is -output and -debugoutput. IIRC -debugoutput is GM's messages while -output is your show_debug_message-s.
 
Top