Блог ☯

суббота, 14 января 2017 г.

Game Maker Studio : Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1 хеширование)

Всем привет! Меня зовут Данил Рафиков и я решил присоединиться к блогу econdude.pw в качестве соавтора статей. У меня есть YouTube канал - HavingTeam где вы можете найти мои уроки по Game Maker.  

Я планирую периодически писать в этом блоге статьи про Game Maker Studio и на тему программирования, постараюсь делать статью к каждому новому видео на моём канале (выходит 1-2 раза в месяц).

Например, вот моё последнее видео:


Основы Game Maker #20
Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1)

Сегодня я хочу вам рассказать о продвинутом использовании буферов. Затронем такие темы как копирование данных из одного буфера в другой, загрузка и выгрузка сурфейса в буфере, MD5 и SHA-1 хеширование.

Начнем с копирования, для этого есть специальная функция buffer_copy. 


  • Первый аргумент этой функции требует буфера, откуда вы хотите скопировать данные. 
  • Второй означает уровень смещения, иными словами с какой позиции начинать копировать. 
  • Третий значит размер этого буфера. Тут можно написать buffer_get_size(искомый буфер). 
  • Четвертый аргумент- это буфер, куда копировать. 
  • Ну и последний аргумент - уровень смещения в буфере, куда будем копировать данные.



Game Maker Studio : Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1 хеширование)


Если у вас заранее там записаны какие-то данные, то здесь надо написать buffer_tell(буфер) - функция, возвращающая последнюю позицию в буфере. 

Обязательно стоит учесть, что при копировании, смещение в буфере не произойдет как при записи. Надо будет в конце перемотать буфер на конец функцией buffer_seek(буфер, buffer_seek_end, 0), buffer_seek_end - перематывает на конец буфера.


Game Maker Studio : Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1 хеширование)


Если не учесть это правило, то при отправке буфера в Networking вы отправите "кусок" буфера, а не его целую часть.

Оформим это дело в коде. Создадим растущий буфер buff_1 и запишем в него 4 байта:

#Create

buff_1 = buffer_create(1,buffer_grow,1); 
buffer_write(buff_1,buffer_u16,mouse_x); 
buffer_write(buff_1,buffer_u16,mouse_y);

Теперь создадим аналогичный буфер buff_2 и внесем туда строковое значение:


buff_2 = buffer_create(1,buffer_grow,1); 
buffer_write(buff_2,buffer_string,"Hello").


Теперь прописываем само копирование:

buffer_copy(buff_1,0,buffer_get_size(buff_1),buff_2,buffer_tell(buff_2));

Из этой строки получается, что 4 байта пойдут после строкового значения.

Сделаем вывод. Будем копировать значения buff_1 в buff_2 при нажатии клавиши 1.


#Step

Пишем:
if keyboard_check(ord("1"))

{
buffer_copy(buff_1,0,buffer_get_size(buff_1),buff_2,buffer_tell(buff_2))
}
После копирования нам надо перемотать буфер на начало, так как если мы начнем его читать в таком виде, то вылезет ошибка о том, что мы читаем за границей буфера.

Перемотать на начало можно buffer_seek(buff_2,buffer_seek_start,0), buffer_seek_start – перемотка на начало буфера. 

Получается так:

buffer_seek(buff_2,buffer_seek_start,0);

И сделаем вывод: 

var str = buffer_read(buff_2,buffer_string);

var mx = buffer_read(buff_2,buffer_u16);

var my = buffer_read(buff_2,buffer_u16);

show_message(string(str)+" | mouse_x : "+string(mx)+" | mouse_y : "+string(my)).

Запускаем. Нажимаем 1 и видим, что данные из буфера успешно скопированы в другой.


Теперь приступим к загрузке сурфейса в буфер. Зачем это надо? 

Вообще иногда нужно сохранять сурфейсы так, чтобы их никто не смог редактировать и нужна быстрая загрузка. 

Буфера идеально справляются с этой задачей.


#Create

Создадим сурфейс surf. Сделаем его белым:

surf = surface_create(room_width,room_height);

surface_set_target(surf);

draw_clear_alpha(c_white,1);

surface_reset_target();

Стоит обязательно учесть, что сурфейсы могут пропадать при взаимодействии с окном приложения. Создадим для этого скрипт surface_rebuilding(), который будет пересоздавать сурфейс в случае его исчезновения.


#Scripts


surface_rebuilding();

surface_create(room_width,room_height);

surface_set_target(surf);

draw_clear_alpha(c_white,1);

surface_reset_target();

Теперь отрисовываем его.


#Draw


if surface_exists(surf) // Проверяем наличие сурфейса
{
draw_surface(surf,0,0);
}
else // Если его нет
{
surface_rebuilding(); // Применяем наш скрипт
}

Сделаем рисование на сурфейсе:

if mouse_check_button(mb_left)
{
surface_set_target(surf);
draw_circle(mouse_x,mouse_y,8,false);
surface_reset_target();
}

#Step

Теперь надо сделать сохранение сурфейса в буфер.

Тут надо учесть то, что вы должны создать буфер, у которого размер будет заранее подготовлен для сурфейса. Ибо даже растующий буфер автоматически не выделит места.

Как посчитать размер сурфейса? Очень просто.

Берете размеры сурфейса, в моем случае это размеры комнаты, умножаете их, и умножаете еще на 4. 

Получается так:

var buff_size = room_width*room_height*4;

Теперь, при нажатии клавиши 2 будем сохранять сурфейс в буфер. Заранее стоит проверить, существует ли сурфейс, чтобы избежать ошибки, прописываем перед нажатием клавиши условие:

if surface_exists(surf)

Если нет, то применяем наш скрипт surface_rebuilding();


Получается так:

if surface_exists(surf)
{
if keyboard_check(ord("2"))
{
var buff_3 = buffer_create(buff_size,buffer_grow,1);
}
}
else
{
surface_rebuilding();
}

Чтобы загрузить сурфейс в буфер существует функция buffet_get_surface.

Первый аргумент значит буфер, куда будем копировать.

Второй - это сурфейс, который копировать.

Третий - данные, которые получить с сурфейса. Здесь ставим значение 0, то есть это будет значит, что мы будем копировать все данные с сурфейса.

Четвертый аргумент - это уровень смещения в буфере, то есть в какую позицию копировать данные, ну и пятый - это смещение от конца линии к началу следующего, ставим здесь 0.


Game Maker Studio : Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1 хеширование)


#Step

Получается это так:

buffer_get_surface(buff_3,surf,0,0,0);


Теперь сохраняем буфер в файл:

buffer_save(buff_3,"surface.b");

И удаляем буфер для освобождения памяти:

buffer_delete(buff_3);

Теперь сделаем загрузку сурфейса из буфера.


Загрузка будет происходит при нажатии клавиши 3:

if keyboard_check(ord("3"))
{
if file_exists("surface.b") // Проверяем, есть ли наш файл с буфером{
var buff_4 = buffer_load("surface.b") //Загружаем буфер
}
}

Для выгрузки сурфейса из буфера есть функция buffer_set_surface.

Ее аргументы аналогичны той функции, что загружает сурфейс в буфер. Но мы здесь уже выгружаем сурфейс.


Game Maker Studio : Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1 хеширование)


Обязательно проверяем, есть ли наш сурфейс, если нет, то пересоздаем его.


Получается так:

if surface_exists(surf)
{
buffer_set_surface(buff_4,surf,0,0,0);
}
else
{
surface_rebuilding();
}

Теперь удалим буфер:

buffer_delete(buff_4);

Запускаем.

Давайте что-нибудь нарисуем. Теперь загружаем сурфейс в буфер и сохраняем его клавишей 2. Сохранили. Чего-нибудь еще нарисуем. Загрузим сурфейс клавишей 3. Отобразилась наша первая фигура, а другая удалилась, так как ее не было до загрузки сурфейса в буфер.

Переходим к хешированию MD5 и SHA-1. Их надобность в том, что они позволяют проверять целостность буфера. Это может помочь в том случае, когда у вас сохранение работает на буферах, и вам нужно проверить наличие изменений в файле сохранения. По-другому это защита. То есть MD5 и SHA-1 возвращают контрольную сумму буфера. Вы занесли в него какие-то данные и из этого получается некоторое значение для проверки целостности данных.

Данные будут проверяться так: мы будем записывать в буфер после записи всех нужных данных контрольную сумма. И при загрузке будем возвращать контрольную сумму загруженных данных и сверять их с записанной контрольной суммой.

Если оба значения будут равны, то это будет значит, что файл не подвергался модификации. Приступим к реализации. Возьмем SHA-1, так как он лучше MD5 в плане безопасности хеширования данных.

#Step

При нажатии клавиши 4 мы будем записывать в буфер какое-нибудь значение, далее его сохранять. После этого будем загружать клавишей 5. Тут же встроим SHA-1 хеширования.


if keyboard_check(ord("4")) 
var buff_5 = buffer_create(1,buffer_grow,1); 
buffer_write(buff_5,buffer_string,get_string("Ваше секретное слово","")); // Тут записываем какое нибудь значение
}


Теперь нам надо после этого записать в буфер строковое значение, полученное функцией buffer_sha1. Первый аргумент значит буфер, из которого составить контрольную сумму, второй - уровень смещения, с какой позиции хешировать, третий - размер буфера, тут прописываем buffer_tell(buff_5).


Game Maker Studio : Продвинутое использование буферов (Копирование, Сурфейсы, SHA-1 хеширование)


Записываем:

buffer_write(buff_5,buffer_string,buffer_sha1(buff_5,0,buffer_tell(buff_5)));

Теперь сохраняем буфер в файл:

buffer_save(buff_5,"buffer.b");

И удаляем его:

buffer_delete(buff_5);


Осталось добавить загрузку буфера:

if keyboard_check(ord("5")) 
if file_exists("buffer.b") // Проверяем наличие файла 

var buff_6 = buffer_load("buffer.b"); //Загружаем буфер 
var str = buffer_read(buff_6,buffer_string); // Читаем из него записанное значение 
var sha_1_test = buffer_sha1(buff_6,0,buffer_tell(buff_6)); // Возвращаем контрольную сумму данных в буфере, не считая той контрольной суммы, которую мы записали. 
var sha_1_check = buffer_read(buff_6,buffer_string); // Читаем записанную контрольную сумму 
if sha_1_test == sha_1_check // Проверяем, равны ли получены значения 
show_message(string(Str)); 
}

else // Если нет 
show_message("Файл был подвергнут модификации!") 
}
}
}

Вот мы и рассмотрели 3 варианта использования буферов в Game Maker Studio.

Всем спасибо за внимание!

Исходник: Advanced Buffers.gmz

Всем спасибо за внимание! Я надеюсь что у нас с Econ Dude получиться долгое и плодотворное сотрудничество. В скором времени в шапке этого блога появиться новая страница где я буду собирать все свои статьи и уроки. Так-же, возможно, с моей помощью мы прокачаем дизайн этого блога, так-как кроме Game Maker я изучаю еще и web языки.

Подписывайтесь на мой YouTube канал HavingTeam и ждите новых статей тут!