20120817

Direct3D - Часть 0: Вступительная

Как я написал чуток ниже, писать нашу менюшку мы будем на С++. Поэтому в качестве первой части видео мы сделаем простейшее приложение с использованием Direct3D и всё что оно будет уметь - показывать окно, красить его заданным цветом и корректно завершаться.

Ребята, если вы до этого никогда не писали на плюсах (а я и сам почти никогда на них не писал) - не переживайте, он сильно похож на C# - оба имеют синтаксис, очень похожий на их далёкого предка - С.

Ну, тем хардкорщикам, которые до этого писали только на ассемблере, придётся немного попривыкнуть. :D

Его и будем ломать в дальнейшем. :)

[Ссылка] на видеоурок.
[Ссылка] на исходный код + скомпилированную программу.

PS: Всё-таки выложу исходник ещё и тут - прокомментирую:


#include //Подключаем необходимые заголовочные файлы, чтобы оно соображало,
#include //где какие функции, что какие структуры обозначают и всё такое

#pragma comment(lib, "d3d9.lib") //До кучи добавляем библиотечку d3d

LPDIRECT3D9 d3d; //Объявляем глобальную переменную для объекта d3d
LPDIRECT3DDEVICE9 d3ddev; //Такую же, но для устройства d3d

void CleanD3D() //Функция, завершающая работу D3D
{
d3ddev->Release(); //У обоих объектов вызываем функцию "УбитьСебя"
d3d->Release();
}

void RenderFrame() //Функция, рисующая что-нибудь на экране
{
        //Говорим нашему устройству d3d очистить наше окно цветом FF0000 - красным!
d3ddev->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0);
d3ddev->BeginScene(); //Типа начинаем рисовать
d3ddev->EndScene(); //Сразу заканчиваем, так ничего и не нарисовав
d3ddev->Present(0, 0, 0, 0); //Меняем местами буфер на экране и тот, который мы заполнили цветом
}

//Функция, инициализирующая D3D
void InitD3D(HWND hWnd) //hWnd - аргумент, идентификатор нашего окна
{
d3d = Direct3DCreate9(D3D_SDK_VERSION); //Создаём объект d3d, запихиваем в переменную
D3DPRESENT_PARAMETERS d3dpp; //Объявляем переменную со структурой настроек
ZeroMemory(&d3dpp, sizeof(d3dpp)); //Очищаем выделенную под неё память
d3dpp.Windowed = 1; //Говорим, что рисовать будем в окне
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //В один буфер рисуем, когда первый уже отобразили
        //Создаём устройство d3d, скармливая ему идентификатор нашего окна
        //Результат тоже записываем в глобальную переменную
d3d->CreateDevice(0, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
}

//Функция, управляющая нашим окном. Аргументы:
//hWnd - идентификатор окна
//message - сообщение для обработки
//wParam и lParam - дополнения к сообщению
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) //Смотрим, что за сообщение
{
case WM_DESTROY: //Если "Убить окно"
{
PostQuitMessage(0); //Пишем завещание, говорим что окно умирает
return 0; //Возвращаем 0
}
}
return DefWindowProc(hWnd, message, wParam, lParam); //Иначе - возвращаем значение по умолчанию
}

//Точка входа в программу. Аргументы:
//hInstance - идентификатор процесса в системе
//hPrevInstance - идентификатор процесса-родителя (если есть)
//Оставшиеся два устарели и не используются, так что там всегда 0
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc; //Объявляем переменную под структуру описания нашего окна
ZeroMemory(&wc, sizeof(WNDCLASSEX)); //Очищаем под неё память
wc.cbSize = sizeof(WNDCLASSEX); //Задаём её размер
wc.style = CS_HREDRAW | CS_VREDRAW; //Говорим, как окно будет рисоваться
wc.lpfnWndProc = WindowProc; //Говорим, какая функция будет окном управлять
wc.hInstance = hInstance; //Указываем идентификатор процесса-родителя окна
wc.hCursor = LoadCursor(0, IDC_ARROW); //Использовать будем этот курсор-стрелочку
wc.lpszClassName = L"WindowClass"; //Имя структуры, описывающей окно
RegisterClassEx(&wc); //Регистрируем структуру в системе
HWND hWnd = CreateWindowEx(0, L"WindowClass", L"Test D3D9", 0, 0, 0, 640, 480, 0, 0, hInstance, 0); //Создаём окно с заголовком "Test D3D9" в верхнем левом углу экрана (0:0) размером в 640х480 пикселей, получаем его идентификатор
ShowWindow(hWnd, nCmdShow); //Показываем окно на экране
InitD3D(hWnd); //Инициализируем d3d
MSG msg; //Объявляем переменную под хранение сообщений для окна
while(1) //Делаем бесконечный цикл
{
while(PeekMessage(&msg, 0, 0, 0, 1)) //В нём в цикле получаем сообщения
{
TranslateMessage(&msg); //Переводим их в понятный окну формат
DispatchMessage(&msg); //Отправляем на растерзание процедуре окна
}
if(msg.message == WM_QUIT) //Если получили сообщение к выходу
{
break; //Прерываем цикл
}
RenderFrame(); //Иначе - рисуем при помощи d3d
}
CleanD3D(); //Если цикл прервался - завершаем работу d3d
return msg.wParam; //И выходим
}

20120816

Direct3D: Финишная прямая

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

Завтра будет Видео №0, до его просмотра рекомендую скачать и установить две вещи:

1. [Visual C++ Express] - на момент написания этого поста, 2010 версия.
2. [DirectX SDK] - на момент написания этого поста, версия от июня 2010 года.

На первом пункте особо останавливаться не буду. Скажу только, что без С++ нам пока что не обойтись. Почему? Потому что DirectX, при помощи которого и создаются 99% игр под Windows - это набор интерфейсов ([API]) для работы с графикой, выполненный в виде сборника [COM]-объектов. Страшные слова заставляют написать, о чём же это, в кратце - а о том, что есть вещь под названием [ООП] - Объектно-ориентированное программирование. Это такой подход, при котором любая вещь в программе - переменная, функция или ещё что-то - является объектом.

В детали я вдаваться не очень хочу, т.к. это довольно нудно и не очень нужно для нашей затеи, но вся штука в том, что лучше всего на работу с такой задачей подходит именно С++.

Не бойтесь, для особо терминальных случаев (как мой, к примеру) можно будет всё переписать и на более низкоуровневых языках (скажем, ассемблере ;), равно как и на аналогах (например, C#).

Моя основная задача - продемонстрировать и объяснить принцип, а вот на каком языке реализовывать идею и какими мелками рисовать картину - это уже дело вашего вкуса, я тут не в праве своё мнение навязывать. :)

20120815

Взлом по заявкам - Prince of Persia: Sands of Time - Часть 1

Итак, товарищ с форума [gamehacklab] под именем LogDog попросил меня записать видеоурок по взлому замечательной игры про принца в шароварах. Попросил он несколько опций, так что это будет серия видеоуроков.

Т.к. я не знаю, насколько круто LogDog умеет ломать игр (может круче меня и он просто приколоться решил), то объяснять буду максимально подробно.

[Ссылка] на первую часть.

PS: Если кого-то смутил момент с float / 4 байта целое, попробую объяснить:

Что float, что 4 байта целое занимают в памяти 4 байта памяти. По сути, это просто два разных представления содержимого одного и того же адреса, т.е. компьютер знает и понимает только байты - всякие там 4 байта, 8 байт, double, float - компьютеру до лампочки, так что можно найти 4 байта целое а потом выяснится, что это на самом деле float - с человеческой точки зрения видеть 100.0 понятнее, чем 34576858, ну и наоборот - вместо 0.6+11Е куда понятнее видеть ровно 500, к примеру.

20120813

Структуры! Структуры!

Новый [видеоурок], в котором я вам показываю ещё одну отличную фичу Cheat Engine - возможность наглядно сравнивать структуры. Под классическую музыку!

Ломаю на примере обучающей программы, которую можно найти в папке установки СЕ - под рукой не оказалось игры. Но это не так важно, важно понимание способа взлома (а способ очень мощный, гарантирую!).