BuildZone(L2GeoData)

  • Автор темы Автор темы yoRliK
  • Дата начала Дата начала
Судя по отзывам, куча народу по сей день ищет "геодату от бога". Есть естественно "умные люди" желающие продать как билдер, так и сами билды клиента, опираясь на сложности реверса, ум, и прочий мега-бред. В свое время, озадачивался поиском ребилда локаций для новых клиентов, и создавал трид на ЗГ...выясняли кучу инфы и т.д...но ее терли с наших же просьб :-) Посему, опираясь на "потребность", создадим тридик и тут, с начинанием(лично мое "начинание" это клиент Хелиос(UNP-PTS), "что имел, то и взял" + С++) от меньшего к большему :-):
Запилим инлайн патч функцию:
Код:
bool InlinePatch(wchar_t * sModule, char * sFunction, int offset, unsigned char value)
{
    DWORD oldProtect;
    unsigned char * functionAddress;
    functionAddress = static_cast<unsigned char *>(GetModuleFunc(sModule, sFunction)) + offset;
    if(functionAddress == nullptr)
    {
        return false;
    }

    if(!VirtualProtect(functionAddress, 1, PAGE_READWRITE, &oldProtect))
    {
        return false;
    }

    *functionAddress = value;
  
    if(!VirtualProtect(functionAddress, 1, oldProtect, &oldProtect))
    {
        return false;
    }
    return true;
}
1) Для билдера, как обычно, убираем лок нитей ОМП с 4х на 1н поток(Наша задача, загрузиться ранее чем инициализация UGameEngine::Init, посему восстанавливая DirectX компонент, разворачиваемся как DSetup с функциями, и начинаем чудеса):
Код:
        if(!InlinePatch(L"engine.dll", "?Init@UGameEngine@@UAEXH@Z", 0x2CD, 0x01))
        {
            MessageBox(nullptr, L"Invalide inline patch function address 1!", L"UGameEngine::Init", MB_OK);
        }
        if(!InlinePatch(L"engine.dll", "?Init@UGameEngine@@UAEXH@Z", 0x2D1, 0x01))
        {
            MessageBox(nullptr, L"Invalide inline patch function address 2!", L"UGameEngine::Init", MB_OK);
        }
2) Далеко не отходим, и патчим 3 перехода:
Код:
        if(!InlinePatch(L"engine.dll", "?buildWorldStructure@FWorldBuilder@@QAEHPAVULevel@@PA_WPAVUViewport@@HH@Z", 0x1E61, 0x84))
        {
            MessageBox(nullptr, L"Invalide inline patch function address 3!", L"UGameEngine::Init", MB_OK);
        }
        if(!InlinePatch(L"engine.dll", "?buildWorldStructure@FWorldBuilder@@QAEHPAVULevel@@PA_WPAVUViewport@@HH@Z", 0x6D6, 0x84))
        {
            MessageBox(nullptr, L"Invalide inline patch function address 4!", L"UGameEngine::Init", MB_OK);
        }
        if(!InlinePatch(L"engine.dll", "?buildWorldStructure@FWorldBuilder@@QAEHPAVULevel@@PA_WPAVUViewport@@HH@Z", 0xD9E, 0x85))
        {
            MessageBox(nullptr, L"Invalide inline patch function address 5!", L"UGameEngine::Init", MB_OK);
        }
И билдим с командами: buildzone map=xx_yy width=65536
В итоге имеем: билд квадрата целиком + билд с закрытой локации(если чар"павн" установлен в той самой закрытой локации).
Далее что нам интересно, и как обычно это - "хочу все и сразу". Тут мы можем, либо:
1) Билдим с разных "закрытых локаций" и мержим билды.
2) Хардкод координат на квадрате(Как аналог оставлен Cruma квадрат от самих корейцев) в итоге указываем координаты руками(заведомо их зная).
3) Получить координаты ULevel'а и билдить с SIP.
4) .........(тут могут...но не хотят рассказывать люди, чьи профиты вылезли со слов Fyyre либо Sauron, и они очень любят все "впаривать")
---
В атаче билдер для Хелиос ПТС клиента руофа.
---
П.С - Совершенно не хотим претендовать к "обломщикам продаж" и прочему....Это просто наше IMHO и наши "ковыряния в клиенте" :-) Спасибо за внимание.
П.С2 - В скором времени дополним информации с pathnode информацией с самого клиента, через его ULevel. Инфой с "мануал" билдом. Инфой с инитом координат для SIP.
П.С3 - Трид еще и тупо для того, чтобы инфу не просрать :-) бывает моменты, когда тупо зыбываем :\
 

Вложения


Отличная вещь. обкатана мной на картах Grand Crusade. Есть свои ньюансы. Но этот на данный момент лутший билдер из тех что есть в шаре)
 
А под хф нет?)
 
В шаре он достаточно давно уже. Как то ALF делал подарок на нг.
А так самое главное упустили билд всех закрытых мест за раз.
И если сделать немного автоматизации то можно фул гео делать за 5-10часов в зависимости от мощности компа.
 
Описанные выше вводные в "базис" реализации анлока билдера геодаты == верным шагом, за исключением фактов:
1) Билдер априори не знает о наличии ранее инициализированных объектов карты, т.к по итогу инициализации квадрата, происходят вещи аля "Seamles", и блалал. Не суть крч :)
2) Мы в ранее существующем коде не произвели важные "before" манипуляции!
3) Нам необходим дополнительный хук на ULevel::postLoad, забрать с нее указатель на ULevel(с учетом инициализации первых 2х Entry и SkyLevel карт, которые мы скипаем по кол. обьектов, если смогете, сумеете :) а в реалиях это
Код:
*reinterpret_cast<DWORD *>(pULevel + 0x3C);
Ну и для реальности, добросим Example:
Код:
    int nMapObjectCount = *reinterpret_cast<DWORD *>(pULevel + 0x3C);
    if(nMapObjectCount > 40)
на выходе с функции мы поимеем - полностью инициализированный квадрат карты(если вы его сумели засторить(забрать указатель на обьект в свои закрома) в "куда ни будь" ;) )
4) При необходимости и навыкам, вы можете убрать с квадрата "двери", дабы банально их не вырезать из клиент карт.
Код:
                    DWORD AMoverStatic = reinterpret_cast<DWORD>(GetProcAddress(GetModuleHandle("engine.dll"), "?PrivateStaticClass@AMover@@0VUClass@@A"));
                    for(int i = 0; i < *reinterpret_cast<DWORD *>(pULevel + 0x3С); i++)
                    {
                        DWORD * actorArray = reinterpret_cast<DWORD *>(pULevel + 0x38);
                        DWORD actor = *reinterpret_cast<DWORD *>(*actorArray + 4 * i);
                        if(IsA(actor, AMoverStatic))
                        {
                            reinterpret_cast<FARPROC &>(TTransArray_RemoveItem) = reinterpret_cast<FARPROC>(0x20181340); // Addr to TTransArray remover pseudo func
                            removedDoorCount += TTransArray_RemoveItem(actorArray, &actor);
                        }
                    }
...
хотя вот вам и IsA функция клиента:
Код:
bool IsA(DWORD pUObject, DWORD pUClassStatic)
{
    if(pUObject == 0 || pUClassStatic == 0)
    {
        return false;
    }

    for(DWORD pUClass = *reinterpret_cast<DWORD *>(pUObject + 0x24); pUClass; pUClass = *reinterpret_cast<DWORD *>(pUClass + 0x34)) // Size UClass
    {
        if(static_cast<int>(pUClass) == static_cast<int>(pUClassStatic))
        {
            return true;
        }
    }
    return false;
}
Далее собираем все в кучу, и передавая FWorldBuilder'у указатель не на то что он жрет после UInput'а, а то что мы "собрали" для него ;)
Для Перфекционистов, в buildWorldчтототам есть куча "второстепенных" реализаций, в стиле "скипа точек APlayerStart и а точнее их инит координат, только в лице коллизион бокса установленного на эту точку(это как у Скриптов и Дизера, по 100500 бадПойнтов на квадрате).
Тут на самом деле еще куча ТОДО можно забросить, но для реально чистого билда достаточно и этой инфы. Если совесть позволит, эксемпл в виде кода будет слит позже.
П.С - весь "Ридми" выше был исключительно для Salvation клиента Угновы(140протокол)!!!! Все оффсеты и бонусы только в реалиях Салвейшена(Увы, новее\старее нам не нужен, если вам нужен - изучайте на основе данной инфы, клиенты и билдФункции не отличаются от ГФ до Салвейшена).
 

Похожие темы

Назад
Сверху Снизу