You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AM2R-Multitroid/scripts/nat_handle_tcp_message.gml

156 lines
5.8 KiB

/// nat_handle_tcp_message(message_map)
// Handles incoming TCP messages from mediation server
// message_map: ds_map returned from json_parse_nat_message()
// Call this from Async Networking event
var msg = argument0;
if (!ds_exists(msg, ds_type_map)) {
exit;
}
var msg_id = ds_map_find_value(msg, "ID");
if (is_undefined(msg_id)) {
exit;
}
switch (msg_id) {
case MSG_CONNECTED:
// Connected to mediation server - start NAT detection
mediation_connected = true;
nat_state = NAT_STATE_NAT_DETECTING;
// Send NAT type request
var params = ds_map_create();
ds_map_add(params, "LocalPort", nat_local_port);
ds_map_add(params, "ClientID", nat_client_id);
nat_send_tcp_message(mediation_socket, MSG_NAT_TYPE_REQUEST, params);
ds_map_destroy(params);
break;
case MSG_NAT_TEST_BEGIN:
// Mediation server wants us to send UDP to test ports
var test_port_one = ds_map_find_value(msg, "NATTestPortOne");
var test_port_two = ds_map_find_value(msg, "NATTestPortTwo");
if (!is_undefined(test_port_one) && !is_undefined(test_port_two)) {
// Send NAT test packets to both ports
var test_params = ds_map_create();
ds_map_add(test_params, "ClientID", nat_client_id);
var test_json = json_encode_nat_message(MSG_NAT_TEST, test_params);
ds_map_destroy(test_params);
var test_buf = buffer_create(string_length(test_json) + 1, buffer_fixed, 1);
buffer_seek(test_buf, buffer_seek_start, 0);
buffer_write(test_buf, buffer_text, test_json);
network_send_udp_raw(socket, mediation_server_ip, test_port_one, test_buf, buffer_tell(test_buf));
network_send_udp_raw(socket, mediation_server_ip, test_port_two, test_buf, buffer_tell(test_buf));
buffer_delete(test_buf);
}
break;
case MSG_NAT_TYPE_RESPONSE:
// Received NAT type from server
nat_type = ds_map_find_value(msg, "NATType");
if (!is_undefined(nat_type)) {
nat_state = NAT_STATE_WAITING;
var type_name = "Unknown";
if (nat_type == NAT_TYPE_DIRECT_MAPPING) type_name = "Direct Mapping (Full Cone)";
else if (nat_type == NAT_TYPE_RESTRICTED) type_name = "Restricted";
else if (nat_type == NAT_TYPE_SYMMETRIC) type_name = "Symmetric";
// Now request connection to the game server
nat_request_connection();
}
break;
case MSG_CONNECTION_BEGIN:
// Mediation server is coordinating connection - start hole punching
var endpoint_str = ds_map_find_value(msg, "EndpointString");
var peer_nat = ds_map_find_value(msg, "NATType");
var conn_id = ds_map_find_value(msg, "ConnectionID");
if (!is_undefined(endpoint_str) && !is_undefined(peer_nat)) {
// Parse endpoint "ip:port"
var colon_pos = string_pos(":", endpoint_str);
if (colon_pos > 0) {
nat_peer_ip = string_copy(endpoint_str, 1, colon_pos - 1);
nat_peer_port = real(string_copy(endpoint_str, colon_pos + 1, string_length(endpoint_str) - colon_pos));
nat_peer_nat_type = peer_nat;
nat_connection_id = conn_id;
// Check for unsupported Symmetric-to-Symmetric
if (nat_type == NAT_TYPE_SYMMETRIC && nat_peer_nat_type == NAT_TYPE_SYMMETRIC) {
show_message("Connection not possible - both sides have Symmetric NAT");
nat_state = NAT_STATE_ERROR;
exit;
}
// Start hole punching
nat_state = NAT_STATE_PUNCHING;
nat_hole_punch_timer = 0;
nat_hole_punch_count = 0;
nat_hole_punch_received = 0;
}
}
break;
case MSG_CONNECTION_COMPLETE:
// Connection established!
nat_state = NAT_STATE_CONNECTED;
// Update oClient to use the discovered endpoint
server_ip = nat_peer_ip;
server_port = nat_peer_port;
// Mark as connected so game protocol can start
isConnected = 1;
connected = true; // Mark as connected to prevent duplicate connection flow in Step event
popup_text("Connected to server!");
// Send initial connection packet to server
buffer_delete(buffer);
var size, type, alignment;
size = 1024;
type = buffer_grow;
alignment = 1;
buffer = buffer_create(size, type, alignment);
buffer_seek(buffer, buffer_seek_start, 0);
buffer_write(buffer, buffer_u8, 1);
buffer_write(buffer, buffer_string, name + "," + global.multitroid_version);
buffer_write(buffer, buffer_u8, global.sax);
var bufferSize = buffer_tell(buffer);
buffer_seek(buffer, buffer_seek_start, 0);
buffer_write(buffer, buffer_s32, bufferSize);
buffer_write(buffer, buffer_u8, 1);
buffer_write(buffer, buffer_string, name + "," + global.multitroid_version);
buffer_write(buffer, buffer_u8, global.sax);
network_send_udp(socket, server_ip, server_port, buffer, buffer_tell(buffer));
// Create nametag instance
instance_create(x, y, oNametag);
// Disconnect from mediation server - we don't need it anymore
if (mediation_socket != -1) {
network_destroy(mediation_socket);
mediation_socket = -1;
mediation_connected = false;
}
break;
case MSG_SERVER_NOT_AVAILABLE:
show_message("Server not available");
nat_state = NAT_STATE_ERROR;
break;
case MSG_CONNECTION_TIMEOUT:
show_message("Connection timeout");
nat_state = NAT_STATE_ERROR;
break;
}