После того как мы научились в предыдущих статьях по программированию хорошо работать с памятью игры, то можно уже приступить к практической части. В этом уроке мы будем выводить свою собственную текстуру txd gta, на экран через свой asi плагин. Для того что-бы начать что-то рисовать на экране, вспомним что в каждой игре существует своя функция рендера, где и вызывается отрисовка и затем очистка спрайтов. Также и тут, нам просто необходимо сделать следующие шаги:
- 1. Заняться реверсивной инженерией – (но в данном уроке, мы не затроним эту часть)
- 2. Переписать не сколько структур
- 3. Как минимум объявить прототипы, функций txd
- 4. Сделать замену функции – для того что-бы захватиться за рендер
Объявляем структуры и также заголовочный файл .h
Структуры на самом деле с пакета Render Ware, но не совсем оригинальные я пока что сделал это в простом ввиде:
#pragma once
#pragma pack (push, 1)
//Пока объявим такие структуры:
struct RwRGBA {
char red;
char green;
char blue;
char alpha;
};
struct RwRect{
float X1;
float Y1;
float X2;
float Y2;
};
#pragma pack (pop)
Заголовочный файл вы можете назвать также structsVC.h. Пока этих структур для вывода txd gta на экран, на хватит вполне, но по хорошему если заниматься реверсивной инженерией, то у этих RW-ашных структур есть свои обвертки, но пока мы не будем на этом более подробно заморачиватся, так как это уже совсем отдельный разговор и требует своих навыков. После того как мы объявили сам заголовочный файл, то можно приступать уже к самому коддингу cpp файла, ниже я приведу уже готовый код, но далее мы поговорим об подробностях, как оно все работает:
#include "stdafx.h"
#include "structsVC.h"
//Объявляем пустой прототип класса CTexture
class CTexture;
////Вспомогательная функция для замены
void injectFunction (DWORD address, DWORD function) {
DWORD _old;
VirtualProtect((LPVOID)address,4, PAGE_READWRITE, &_old);
BYTE * patch = (BYTE *)address;
*patch = 0xE9; // JMP
*(DWORD *)(patch+1) = (function-(address+5));
VirtualProtect((LPVOID)address,4, _old, &_old);
}
//Объявляем прототип CTexture
auto CTexture__draw = (void (__thiscall*)(CTexture *, RwRect *posInfo, RwRGBA *v1_color))0x00578710;
//Также другие функции
auto _txdAdd = (int (__cdecl*)(char *name) )0x0580F00;
auto _txdLoad = (int (__cdecl*)(int a, char *Pathname) )0x0580CD0;
auto _txdAddRef = (int (__cdecl*)(int a) )0x0580A60;
auto txdIndexByName = (int (__cdecl*)(char *name) )0x0580D70;
auto _txdSetCurrent = (int (__cdecl*)(int index) )0x0580AD0;
auto RwReadTexture = ( CTexture * (__cdecl*)(char *name, int a2) )0x064E110;
//Здесь объявим строки
char tex_name[] = "gtavicecity";
char txd_name[] = "gtavc";
char path_txd[] = "MODELS/GTAVC.TXD";
//Объявим тут данные
RwRect Rect;
RwRGBA vcol_1;
//Отрисовка
void drawTexture() {
_txdSetCurrent(txdIndexByName(txd_name));
CTexture * tex = RwReadTexture(tex_name, 0);
//Тут мы про инициализируем цвета и положение
vcol_1.alpha = 255;
vcol_1.blue = 255;
vcol_1.green = 255;
vcol_1.red = 255;
Rect.X1 = 0.0;
Rect.Y2 = 0.0;
Rect.X2 = 256.0;
Rect.Y1 = 256.0;
//Вот сама отрисовка текстуры
CTexture__draw(tex, &Rect, &vcol_1);
};
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
//Имя самого файла txd
int ref = _txdAdd(txd_name);
//Путь по которому будем загружать txd
_txdLoad(ref, path_txd);
_txdAddRef(ref);
//Заменяем функцию на нашу
injectFunction(0x043E490, (DWORD)drawTexture);
}break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Вот у нас весь код как говорится на ладони, теперь мы его разберем по полкам, для того что-бы понять и закрепить свои навыки в программировании.
void injectFunction (DWORD address, DWORD function)
– мы о ней уже ранее говорили в этой статье, это лишь то что помогает подменить функции в игре на свою, обычным прыжком, тут все понятно двигаем дальше.
Объявление прототипов и переменных
Тут же мы объявили все нам нужные прототипы функций из базы Alien:
//Объявляем прототип CTexture
auto CTexture__draw = (void (__thiscall*)(CTexture *, RwRect *posInfo, RwRGBA *v1_color))0x00578710;
//Также другие функции
auto _txdAdd = (int (__cdecl*)(char *name) )0x0580F00;
auto _txdLoad = (int (__cdecl*)(int a, char *Pathname) )0x0580CD0;
auto _txdAddRef = (int (__cdecl*)(int a) )0x0580A60;
auto txdIndexByName = (int (__cdecl*)(char *name) )0x0580D70;
auto _txdSetCurrent = (int (__cdecl*)(int index) )0x0580AD0;
auto RwReadTexture = ( CTexture * (__cdecl*)(char *name, int a2) )0x064E110;
Если вы хотите рассмотреть более подробно как они работают, то тогда идите в базу и переходите по адресам на кнопку G, рассматривая как и где они раньше использовались и как вызывались. Пока мы эту часть также глубоко не будет рассматривать, так как урок может длиться долго.
//Здесь объявим строки
char tex_name[] = "gtavicecity";
char txd_name[] = "gtavc";
char path_txd[] = "MODELS/GTAVC.TXD";
//Объявим тут данные
RwRect Rect;
RwRGBA vcol_1;
Это уже наши переменные, с названиями самого файла txd, имени текстуры и путь MODELS/GTAVC.TXD в эту директорию мы для примера поместим нашу готовую текстуру с эмблемой “grand theft auto vice city” скачать ее можно будет с примером ниже.
Инициализация и отрисовка txd
Начнем сперва с инициализации, обратим внимание на этот код:
case DLL_PROCESS_ATTACH:
{
//Имя самого файла txd
int ref = _txdAdd(txd_name);
//Путь по которому будем загружать txd
_txdLoad(ref, path_txd);
_txdAddRef(ref);
//Заменяем функцию на нашу
injectFunction(0x043E490, (DWORD)drawTexture);
}break;
Изначально, вы выполняем наши функции прототипов, добавляя сам txd файл и при этом указывая путь к нему, все также делается как было в процессе самой оригинальной игры. Далее подменяем эту функцию 0x043E490 на нашу drawTexture(). По адресу 0x043E490, находилась совсем пустая функция, я решил за нее зацепиться прикол, в том что она также вызывается в отрисовке игры, где отрисовывается сам игровой hud. Процесс Тамйера в любом случае не прокатил бы, а вот за такие вещи для отрисовок самый раз нужно хвататься в идеальном варианте. Но имейте введу, что если будут два плагина пытаться заменять свои функции в этом участке, то будет работать последний плагин, а не первый который обратиться, обычно для таких целей разрабатывают какой нибудь плагин менеджер со своим SDK, что-бы плагины не мешали друг-другу.
//Отрисовка
void drawTexture() {
_txdSetCurrent(txdIndexByName(txd_name));
CTexture * tex = RwReadTexture(tex_name, 0);
//Тут мы про инициализируем цвета и положение
vcol_1.alpha = 255;
vcol_1.blue = 255;
vcol_1.green = 255;
vcol_1.red = 255;
Rect.X1 = 0.0;
Rect.Y2 = 0.0;
Rect.X2 = 256.0;
Rect.Y1 = 256.0;
//Вот сама отрисовка текстуры
CTexture__draw(tex, &Rect, &vcol_1);
};
Ну и наконец сама отрисовка, текстуры txd gta, принцип тут просто, мы заполняем цвета отрисовки и координаты по принципу точки A(X1, Y2) и точки B(X2, Y1). После чего если было сделано все правильно то будет выглядит в игре так:
Как видно при правильной работе с верху слева, рисуется логотип из файла текстуры, который вы должны будете скачать из примера ниже и поместить в models папку.
TXD_GTA.rar [51,64 Kb] (cкачиваний: 67)Данный урок показал, что можно создавать достаточно отличные gta vice city моды, например можно сделать новый худ и просто то что позволит ваша фантазия. Это еще один урок, который показывает что asi плагины, способны сделать все что угодно с игрой.