Avatar do usuário
Tutoriais & Aulas
Colaborador
Colaborador
Autor
Mensagens: 174
Registrado em: Qui Abr 28, 2016 11:37 am
Karma: 240

[NET] Networking

Sex Abr 29, 2016 9:17 am

Autor original: PedroX


Tradução livre do tutorial: http://gmc.yoyogames.com/index.php?showtopic=582029

Networking tutorial, step by step.

Descrição: Tutorial que ensina como o Networking funciona e como criar um servidor e um cliente simples.

Dificuldade: Mediana

Para GM:Studio registrado.
Não requer nada além do Game Maker : Studio.

Crie dois projetos. Um será o servidor e o outro o cliente.

No projeto do cliente, crie um objeto obj_client; no projeto do servidor, crie um objeto obj_server; coloque ambos (em cada projeto) em uma room (que criar).

obj_server.create:
server = network_create_server(network_socket_tcp, 6510, 32)
buff = buffer_create(16384, buffer_fixed, 1);


obj_client.create:
client = network_create_socket (network_socket_tcp)
network_connect( client, "127.0.0.1", 6510)
buff = buffer_create( 256, buffer_grow, 1)


O número "6510" é a porta usado pelo jogo para acessar o servidor. O "32" é o número máximo de clientes que o servidor pode gerenciar ao mesmo tempo. O "127.0.0.1" é o ip do servidor; este número indica que o servidor se encontra no mesmo pc.

A função buffer_create() irá criar um buffer tanto no cliente quanto no server. O buffer é como uma folha, em que você escreve as mensagens que irá enviar para os outros jogadores.

O buffer do servidor é maior, pois sua folha irá guardar mensagens de todos os jogadores. O argumento "buffer_grow" indica que o buffer pode crescer.

Adicione isso ao obj_server.create:
clients_sockets = ds_list_create() //guardará o socket de cada jogador
clients_name = ds_list_create() //guardará o nome de cada jogador
clients_x = ds_list_create() //guardará o valor de x de cada jogador
clients_y = ds_list_create() //guardará o valor de y de cada jogador


E isso ao obj_client.create:
clients_name = ds_list_create()
clients_x = ds_list_create()
clients_y = ds_list_create()


Para que cada jogador saiba de quem é qual mensagem, o nome de cada um será único.

Adicione isso ao obj_client.create:
randomize()
setup=1
login=0
name_creation_phrase="Insert your character name :"
alarm[0]=10


Crie dois eventos (alarm0 e alarm1) no obj_client.

Ao alarm0, adicione:
client_name=get_string(name_creation_phrase, "player"+string(round(random(9999))))
buffer_seek(buff, buffer_seek_start, 0) //garantir que escreverá no inicio da folha
buffer_write(buff , buffer_string, "check_name") //escreve na folha 'buff' uma 'string' com valor "check_name", que é o assunto
buffer_write(buff , buffer_string, client_name)
buffer_size = buffer_tell(buff) //pega o tamanho da mensagem (ou seja, onde ela termina)
network_send_packet( client, buff, buffer_size ) //envia a 'carta'


Importante: podemos enviar mensagens em qualquer evento, mas, para receber, há um evento específico.

Adicione isso a obj_server.networking:
net_buff = ds_map_find_value(async_load, "buffer")
buff_info = buffer_read(net_buff , buffer_string )  //pega o assunto
sock = ds_map_find_value(async_load, "id") //pega o id do player

if buff_info="check_name" //se o assunto é "check_name"
    {
    b_name=buffer_read(net_buff , buffer_string )
    count=ds_list_size(clients_name)
    name_exists=0 //ainda não há um nome igual ao enviado
for(i=0;i<count;i++)
{
if b_name=ds_list_find_value(clients_name, i) name_exists=1 //se tiver um nome igual, a variável fica com o seu valor igual a 1
}

buffer_seek(buff, buffer_seek_start, 0)  
buffer_write(buff, buffer_string, "name_exists")
buffer_write(buff, buffer_bool, name_exists) //resultado do teste (true ou false)
var buffer_size = buffer_tell(buff);
network_send_packet( sock, buff, buffer_size );
}


"async_load" é um mapa padrão do networking. O evento Networking é disparado quando chega uma nova mensagem ou conexão.

Importante: a parte que você lê do buffer é deletada, então não é possível ler duas vezes a mesma informação (a menos que você tenha a escrito duas ou mais vezes).

Agora adicione isso ao obj_client.networking:
if ds_map_exists(async_load, "buffer")
    {
net_buff = ds_map_find_value(async_load, "buffer")
    buff_info = buffer_read(net_buff, buffer_string )

if buff_info="name_exists"
        {
        setup=buffer_read(net_buff , buffer_bool )
        if setup = 1
            {
            name_creation_phrase="Name already beeing used, please insert another name :"
            alarm[0]=1
            }
else
            {
            alarm[1]=1
            show_message("Welcome "+client_name+"!")
            }
        }
}


A parte do login não é especial, é apenas um pacote que repassa o nome e a posição do cliente.

Evento obj_client.alarm 1:
buffer_seek(buff, buffer_seek_start, 0)
buffer_write(buff , buffer_string, "client_setup")
buffer_write(buff , buffer_string, client_name)
buffer_write(buff , buffer_s16, x)
buffer_write(buff , buffer_s16, y)
buffer_size = buffer_tell(buff)
network_send_packet( client, buff, buffer_size )
login=1


Como pode ver, foram escritos quatro dados, e então devem ser lidos quatro dados, na mesma ordem de escrita.

Troque o contéudo de obj_server.networking por isto:
   
net_buff = ds_map_find_value(async_load, "buffer")
    buff_info = buffer_read(net_buff , buffer_string )
    sock = ds_map_find_value(async_load, "id")
    
    if buff_info="client_status"//client stats
        {
        index=ds_list_find_index( clients_sockets, sock)
        b_x=buffer_read(net_buff , buffer_s16 )
        b_y=buffer_read(net_buff , buffer_s16 )
        ds_list_replace(clients_x, index, b_x)
        ds_list_replace(clients_y, index, b_y)
        }
    
    else if buff_info="check_name"//check if name exists
        {
        b_name=buffer_read(net_buff , buffer_string )
        count=ds_list_size(clients_name)
        name_exists=0
        for(i=0;i<count;i++)
            {
            if b_name=ds_list_find_value(clients_name, i) name_exists=1
            }
        buffer_seek(buff, buffer_seek_start, 0)  
        buffer_write(buff, buffer_string, "name_exists")
        buffer_write(buff, buffer_bool, name_exists)
        var buffer_size = buffer_tell(buff);
        network_send_packet( sock, buff, buffer_size );
        }
        
        
    else if buff_info="client_setup"//client setup
        {
        b_name=buffer_read(net_buff , buffer_string )
        b_x=buffer_read(net_buff , buffer_s16 )
        b_y=buffer_read(net_buff , buffer_s16 )
        ds_list_add(clients_sockets,sock)
        ds_list_add(clients_name,b_name)
        ds_list_add(clients_x,b_x)
        ds_list_add(clients_y,b_y)
        //show_message(b_name+" joined at pos x:"+string(b_x)+" y:"+string(b_y))
        //show_message("list sizes, socket="+string(ds_list_size(clients_sockets))+" name="+string(ds_list_size(clients_name))+" x="+string(ds_list_size(clients_x))+" y="+string(ds_list_size(clients_y)))
        }


Para enviar o "status" visto acima, adicione no obj_client.step:
if login=1 //só manda se já logou
    {
    buffer_seek(buff, buffer_seek_start, 0)
    buffer_write(buff , buffer_string, "client_status")
    buffer_write(buff , buffer_s16, mouse_x)
    buffer_write(buff , buffer_s16, mouse_y)
    buffer_size = buffer_tell(buff)
    network_send_packet( client, buff, buffer_size )
    }


Agora que o servidor recebe as mensagens, vamos compartilhá-las com todos os jogadores:

No obj_server.End Step:
count = ds_list_size(clients_sockets)
if count>0
    {
    buffer_seek(buff, buffer_seek_start, 0)
    buffer_write(buff, buffer_string, "all_clients")
    buffer_write(buff, buffer_s16, count)
    for(i=0;i<count;i++)
        {
        buffer_write(buff, buffer_string, string(ds_list_find_value(clients_name,i)) )//clients_name
        buffer_write(buff, buffer_s16, ds_list_find_value(clients_x,i))//clients_x
        buffer_write(buff, buffer_s16, ds_list_find_value(clients_y,i) )//clients_y
        }
    var buffer_size = buffer_tell(buff);
        
    // Enviar para todos os jogadores
    for(i=0;i<count;i++)
        {  
        sock = ds_list_find_value(clients_sockets,i);
        network_send_packet( sock, buff, buffer_size );
        }
    }


Troque o conteúdo de obj_client.networking por:
if ds_map_exists(async_load, "buffer")
    {
    net_buff = ds_map_find_value(async_load, "buffer")
    buff_info = buffer_read(net_buff, buffer_string )
    
    if buff_info="all_clients"
        {
        count=buffer_read(net_buff , buffer_s16 )
        ds_list_clear(clients_name)
        ds_list_clear(clients_x)
        ds_list_clear(clients_y)
        for(i=0;i<count;i++)
            {
            ds_list_add(clients_name,buffer_read(net_buff , buffer_string ))
            ds_list_add(clients_x,buffer_read(net_buff , buffer_s16 ))
            ds_list_add(clients_y,buffer_read(net_buff , buffer_s16 ))
            }
        }
    
    else if buff_info="name_exists"
        {
        setup=buffer_read(net_buff , buffer_bool )
        if setup = 1
            {
            name_creation_phrase="Name already beeing used, please insert another name :"
            alarm[0]=1
            }
        if setup = 0
            {
            alarm[1]=1
            show_message("Welcome "+client_name+"!")
            }
        }
    }


No obj_client.draw:
count = ds_list_size(clients_name)
if count>0
    {
    for(i=0;i<count;i++)
            {
            name=ds_list_find_value(clients_name,i)//name
            xx=ds_list_find_value(clients_x,i)//x
            yy=ds_list_find_value(clients_y,i)//y
            if name != client_name
                {
                draw_circle(xx,yy,10,true)
                draw_set_halign(fa_center)
                draw_set_valign(fa_middle)
                draw_text(xx,yy-32,name)
                }
            }
    }
draw_circle(mouse_x,mouse_y,10,false)


Troque o conteúdo de obj_server.networking por:
eventid = ds_map_find_value(async_load, "id")
if server = eventid
    {
    //disconnect of a client
    t = ds_map_find_value(async_load, "type");
    sock = ds_map_find_value(async_load, "socket");


    if( t!=network_type_connect)
        {
        index=ds_list_find_index( clients_sockets, sock)
        //show_message(ds_list_find_value(clients_name, index)+" disconected")
        ds_list_delete(clients_sockets,index)
        ds_list_delete(clients_name, index)//name
        ds_list_delete(clients_x, index )//x
        ds_list_delete(clients_y, index )//y
        }
    }
else
    {
    net_buff = ds_map_find_value(async_load, "buffer")
    buff_info = buffer_read(net_buff , buffer_string )
    sock = ds_map_find_value(async_load, "id")
    
    if buff_info="client_status"//client stats
        {
        index=ds_list_find_index( clients_sockets, sock)
        b_x=buffer_read(net_buff , buffer_s16 )
        b_y=buffer_read(net_buff , buffer_s16 )
        ds_list_replace(clients_x, index, b_x)
        ds_list_replace(clients_y, index, b_y)
        }
    
    else if buff_info="check_name"//check if name exists
        {
        b_name=buffer_read(net_buff , buffer_string )
        count=ds_list_size(clients_name)
        name_exists=0
        for(i=0;i<count;i++)
            {
            if b_name=ds_list_find_value(clients_name, i) name_exists=1
            }
        buffer_seek(buff, buffer_seek_start, 0)  
        buffer_write(buff, buffer_string, "name_exists")
        buffer_write(buff, buffer_bool, name_exists)
        var buffer_size = buffer_tell(buff);
        network_send_packet( sock, buff, buffer_size );
        }
        
        
    else if buff_info="client_setup"//client setup
        {
        b_name=buffer_read(net_buff , buffer_string )
        b_x=buffer_read(net_buff , buffer_s16 )
        b_y=buffer_read(net_buff , buffer_s16 )
        ds_list_add(clients_sockets,sock)
        ds_list_add(clients_name,b_name)
        ds_list_add(clients_x,b_x)
        ds_list_add(clients_y,b_y)
        //show_message(b_name+" joined at pos x:"+string(b_x)+" y:"+string(b_y))
        //show_message("list sizes, socket="+string(ds_list_size(clients_sockets))+" name="+string(ds_list_size(clients_name))+" x="+string(ds_list_size(clients_x))+" y="+string(ds_list_size(clients_y)))
        }        
    }


Ruben -> Artigo original
PedroX -> Tradução (e um pouco de adaptação)

Tags:

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 2 visitantes