Buffers, tudo sobre.

Ver o tópico anterior Ver o tópico seguinte Ir em baixo

Buffers, tudo sobre.

Mensagem por PedroX em Dom 02 Mar 2014, 23:25


  • Título: Tudo sobre Buffers
  • Versão do GM: Game Maker Studio 1.2 ou superior
  • Dificuldade: Média
  • Link para download da Engine: Não tem
  • Requer Extensões: Não
  • Requer DLLs: Não
  • Tags: studio, buffers, online, multiplayer


O que são buffers?

Buffers são regiões da memória física usadas para guardar temporariamente dados enquanto esses estão sendo movidos de um lugar para outro ou manipulados de alguma maneira. Por exemplo, você pode usá-los para guardar dados de packets que serão enviados ou recebidos.

O GM:S tem funções para criar, modificar, carregar e salvar buffers, mas antes de usá-las, note os pontos a seguir.

Teoria.

       - Quando um buffer é criado, ele é automaticamente limpo e preenchidoit com 0.
       - "size" é o tamanho (em bytes) de um buffer.
       - "Alignment" indica como os dados são guardados dentro de um buffer. Se o "alignment" é, digamos, 4, e você escreve 1 byte no buffer e usa buffer_tell, você terá o valor 1 como retorno. No entanto, se você escrever mais um byte e usar buffer_tell, você terá o valor 5 como retorno, visto que são usados blocos de 4. "Alignment" é valido somente na escrita em um buffer, então se você usar buffer_tell depois de escrever algo, terá como retorno a posição de escrita atual que vem lodo depois dos dados escritos. Então, se  você escrever algo novamente, a posição desses novos dados será um múltiplo de 4 (ou do valor usado).

A imagem a seguir ilustra mais ou menos como um buffer é alinhado:


Como já vimos, se o alinhamento for de 1, os dados são jogados um logo após o outro. Já se for maior que um, os novos dados ficarão numa posição múltipla do valor de alinhamento.

       - "offset" é o valor (em bytes) para rechear/preencher/completar os dados escritos no buffer.
       - Algumas funções de buffer também criam um novo buffer (por exemplo, buffer_load). Lembre-se de remover esses buffers da memória depois de usá-los pela última vez (ou no final do jogo), usando a função buffer_delete.
       - A memória usado pelos buffers é a do sistema; mesmo que o jogo não esteja em foco (por exemplo, numa ligação no celular), os dados escritos nele vão estar seguros. Mas se o app for fechado ou reiniciado, os dados serão perdidos.

Usando buffers.

É muito rápido acessar buffers, porém seu uso deve ser curto (a menos que seja muito necessário prolongá-lo), porque a memória do sistema está envolvida. Geralmente usamos buffers para guardar um checkpoint no jogo ou para guardar dados que são enviados ou recebidos num jogo online.

NOTA: Ao reiniciar o jogo, os buffers não serão apagados, mas você não conseguirá acessá-los. Isso causa um vazamento de memória (ou seja, o buffer ficará lá até o dispositivo ser reiniciado), e seu jogo poderá encerrar sozinho (dar crash). Sempre delete os buffers usados.

Tipos de buffer

Existem 4 tipos no GM:S.

buffer_fixed
Tamanho constante (significa que não pode ser modificado).

buffer_grow
Tamanho dinâmico (que aumenta conforme necessário).

buffer_wrap
Quando o buffer encher, os dados começarão a ser escritos no começo, criando um loop. Por exemplo, restam 2 bytes e você escreve 3. Então 2 serão colocados no final e o outro vai substituir o primeiro byte do buffer.

buffer_fast
Um buffer especial, super rápido de se ler e escrever. Porém, você pode escrever somente dados dos tipos buffer_u8 e buffer_s8, e o 'alignment' precisa ser 1.

Se tiver dúvidas quanto a quantos bytes vai precisar, use o buffer do tipo grow.

Tipos de dados

Ao ler ou escrever em um buffer, você pode usar diferentes tipos de dados. Os dados são sequenciais. E você sempre deve saber que tipo de dados usou. Por exemplo, escreveu um número, um nome (string), um número, um nome (string). Então você não pode querer ler um nome (string) antes de ler o número.

buffer_u8 (1 byte)
Um inteiro de 0 a 255.

buffer_s8 (1 byte)
Um inteiro de -128 a 127.

buffer_u16 (2 bytes)
Um inteiro de 0 a 65.535.

buffer_s16 (2 bytes)
Um inteiro de -32.768 a 32.767.

buffer_u32 (4 bytes)
Um inteiro de 0 a 4.294.967.295.

buffer_s32 (4 bytes)
Um inteiro de -2.147.483.648 a 2.147.483.647.

buffer_f16 (2 bytes)
Um número (não precisa ser inteiro) de -65504 a 65504. (Ainda não está disponível.)

buffer_f32 (4 bytes)
Um número (não precisa ser inteiro) de -16777216 a 16777216.

buffer_f64 (8 bytes)
Um número (não precisa ser inteiro) de -(2^52) a 2^52 - 1. (Números muito grandes)

buffer_bool (1 byte)
1 ou 0 (true ou false)

buffer_string
Uma string UTF-8 terminada com 'null' (0x00). Um 0 é colocado depois da string para determinar quando ela acaba.

Então, suponde que escreva no buffer:

Código:
buffer_write(buff, buffer_bool, global.Sound);
buffer_write(buff, buffer_bool, global.Music);
buffer_write(buff, buffer_s16, obj_Player.x);
buffer_write(buff, buffer_s16, obj_Player.y);
buffer_write(buff, buffer_string, global.Player_Name);

Você deve ler na mesma ordem, assim:
Código:
global.Sound = buffer_read(buff, buffer_bool);
global.Music = buffer_read(buff, buffer_bool);
obj_Player.x = buffer_read(buff, buffer_s16);
obj_Player.y = buffer_read(buff, buffer_s16);
global.Player_Name = buffer_read(buff, buffer_string);

Esse é o básico sobre buffers. Mais sobre eles podem ser vistos no tutorial do Fred:

http://gmbr.forumeiros.com/t27638-tutorial-de-multiplayer-networking-nativo-gms

Boa leitura!

PedroX

Ranking : Nota C
Número de Mensagens : 6034
Idade : 21
Data de inscrição : 26/07/2008
Notas recebidas : C+B
Reputação : 286
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   :
   :
   :

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Gabreel em Seg 03 Mar 2014, 06:37

Não sabia que o GMS já trabalhava com buffers de uma forma tão completa. É bom saber, me bati muito com os jogos online no tempo do GM8.

Gabreel

Número de Mensagens : 2227
Idade : 20
Data de inscrição : 02/10/2009
Reputação : 52
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por fredcobain em Qui 13 Mar 2014, 16:24

Excelente, este é um assunto que faltava um tuto.

Vou até fazer referência a este tutorial no meu tuto de networking.

Obrigado, Pedro!

fredcobain

Ranking : Sem avaliações
Número de Mensagens : 691
Idade : 35
Data de inscrição : 14/04/2011
Reputação : 162
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Witen em Qui 19 Jun 2014, 12:41

É ficou muito bom, mas poderia me dizer para que serve buffer_seek, seus arguments e suas constantes Happy"
No tutorial de fredcobain falou somente que serve para preparar o pacote.

Código:
buffer_seek(buffer,base,offset)
Constantes:
buffer_seek_start
buffer_seek_end
buffer_seek_relative

Witen

Ranking : Sem avaliações
Número de Mensagens : 515
Idade : 17
Data de inscrição : 23/05/2012
Reputação : 36
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

http://www.wibix.webs.com

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por PedroX em Qui 19 Jun 2014, 12:56

Talvez esse tutorial ajude:
http://gmbr.forumeiros.com/t29549-exemplos-de-buffer

Adiantando, buffer_seek serve para definir a posição do buffer em que deve começar a escrita/leitura.

PedroX

Ranking : Nota C
Número de Mensagens : 6034
Idade : 21
Data de inscrição : 26/07/2008
Notas recebidas : C+B
Reputação : 286
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   :
   :
   :

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Witen em Qui 19 Jun 2014, 13:45

Não nesse tuto a unica referencia com explicação é esta:
Código:
buffer_seek(buff, buffer_seek_start, 0); // vamos para o começo do buffer

e qual é mesma a plicação deste recurso  tonto 

Witen

Ranking : Sem avaliações
Número de Mensagens : 515
Idade : 17
Data de inscrição : 23/05/2012
Reputação : 36
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

http://www.wibix.webs.com

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Markituh em Qui 19 Jun 2014, 17:20

@Witen: Tendo a estrutura do seu buffer em mente, as vezes você pode querer abrir o buffer só para pegar um dado em específico. Não se esqueça de que essa posição é por bytes, não por número de elementos. Então, por exemplo, se você quer acessar o terceiro dado e os dois primeiros são do tipo buffer_u16 (16 bits = 2 bytes), então você vai querer acessar a posição 4 do buffer: 0+2+2. Daí, você dá um buffer_read com o tipo adequado do terceiro dado. buffer_seek_start lerá do começo, relative da posição atual, e end do fim. Mas ué, porque raios eu poderia ler algo do fim? Acontece que você também pode atribuir um valor negativo para a posição, então se quisesse pegar o 4 últimos bytes do buffer em um buffer_u32 por exemplo, só era dar:
Código:
buffer_seek(buffer, buffer_seek_end, -4);
dado = buffer_read(buffer, buffer_u32);

O problema é que o alinhamento é um fator que pode influenciar na determinação da posição correta. Um alinhamento de 1 vai funcionar tranquilo nessa lógica, mas outros valores será preciso calcular melhor. Detalhe que, um alinhamento diferente de 1 só deve ser usado se o buffer apenas contiver dados de um tipo, se você escrever vários tipos de dados então use alinhamento 1 mesmo.
Caso não saiba, signed e unsigned são duas formas de leitura de um dado, é algo determinado pela especificação do formato. O primeiro tipo é um número inteiro, positivo e negativo, e diz que o bit mais significante (o último bit, vai depender do tamanho do dado e de coisas como endianess) irá determinar se o valor é positivo e negativo - por esse motivo, o intervalo numérico é diminuido para a metade do alcance de um unsigned, que é justamente um número natural, de números apenas positivos (incluindo o zero). Leia isso aqui da Wikipedia.

A escolha entre signed e unsigned vai depender do uso que você quer para o dado em questão. Para posições de objetos, por exemplo, os valores podem ser negativos ou positivos, daí você usa signed. E também, uma room provaelmente não vai ser 255x255 (bom, você pode fazer um jogo assim mas, não é comum), então você poderia utilizar um de 16 bits. Se você não coloca nada fora da tela em seu projeto e possui um vasto espaço de room, então é mais viável usar o tipo unsigned para obter um range maior.

Muita coisa em relação a isso já está escrita no próprio tópico.

A parada não é tão simples assim, para entender melhor sobre buffers você teria que entender sobre como funcionam os tipos de dados e sua estrutura na memória. Mas sem dúvida a aplicação mais usada (na programação em geral) é lidar com um "arquivo empacotado", formatos que utilizam ponteiros para dado no arquivo, como em muitos arquivos de jogos.
Vamos dizer que você estivesse gerando um formato e no cabeçalho dele iria conter um endereço para os textos do jogo, não dá pra colocar o valor de cara se a lista de textos não for o primeiro conjunto depois do cabeçalho. Então, você salva a posição atual no cabeçalho (no GM, com buffer_tell), escreve um dado qualquer e quando chegar a hora de escrever os textos você pega a posição atual novamente, dá um seek para a posição salva no cabeçalho (buffer_seek(buffer, buffer_seek_start, posicao), iniciando do começo), e escreve por cima essa outra posição que você acabou de pegar com buffer_write. Daí você dá um seek de volta para a posiçao dos textos e começa a colocar os dados.

Bom, é isso. Espero que tenha ficado claro pra você e para alguém com a mesma duvida.
Abraços o/

___________

"Não deixe para amanhã o que se pode fazer hoje"

Links úteis:
Índice de Tutoriais
Manual online do GMS

Markituh

Ranking : Sem avaliações
Número de Mensagens : 2183
Data de inscrição : 11/10/2009
Reputação : 106
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Witen em Qui 19 Jun 2014, 19:30

Nossa quando você explica explica muito bem, em  fim de forma geral do que eu entendi foi que buffer_seek e como um ponteiro que vai determinar o lugar da leitura e escrita dos bytes.

No signed e unsigned deu pra entender bem, por exemplo nas próprias constantes buffer_ são representadas com a primeira letra de signed e unsigned de pois do _,são estas as letras s(signed) e o u(unsigned).

Como por exemplo:
buffer_u8  (unsigned)
buffer_s16 (signed)


Última edição por Witen em Sex 20 Jun 2014, 14:11, editado 1 vez(es)

Witen

Ranking : Sem avaliações
Número de Mensagens : 515
Idade : 17
Data de inscrição : 23/05/2012
Reputação : 36
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

http://www.wibix.webs.com

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Markituh em Qui 19 Jun 2014, 20:30

Exato. Quanto mais informação numérica você precisar armazenar, mais bits você usa. Para armazenar booleans (true e false), você usa um buffer_u8, pois é uma informação simples e não precisa de muita coisa. Se quiser fazer a parada do "jeito dos mano", dava pra você armazenar uns 8 valores boolean em um byte: lia esse byte e usava um script pra extrair cada bit. A questão é a endianess que falei antes que pode influenciar um pouco, mas já que o buffer foi escrito no próprio PC então não haverá problemas. Depois que você se acostumar a usar buffers não vai querer mais saber de INIs, hehe Happy

Entendeu bem o conceito de signed, né? Boa dedução! A diferença mesmo como pode ver no tópico é o intervalos de valores que a "bitagem" pode trabalhar. O esquema do buffer_seek não é algo tão crucial não, só em aplicações onde há partes no buffer interligadas como no exemplo anterior no meu último post. Uma vez eu fiz um extrator de recursos de .gmk e além de dar bastante seek para ir para o começo de cada entrada, alguns eu precisava descompactar e deixar as paradas alinhadas Laughing Quer uma outra aplicação de seek? Pra pular dados que não precisam ser alterados num savegame, em vez de reescrever tudo denovo.

(eu sei, escrevo muito rsrs)
Abraços o/

___________

"Não deixe para amanhã o que se pode fazer hoje"

Links úteis:
Índice de Tutoriais
Manual online do GMS

Markituh

Ranking : Sem avaliações
Número de Mensagens : 2183
Data de inscrição : 11/10/2009
Reputação : 106
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 0
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: Buffers, tudo sobre.

Mensagem por Conteúdo patrocinado Hoje à(s) 02:43


Conteúdo patrocinado


Voltar ao Topo Ir em baixo

Ver o tópico anterior Ver o tópico seguinte Voltar ao Topo

- Tópicos similares

 
Permissão deste fórum:
Você não pode responder aos tópicos neste fórum