Персонажи отмечаются на всех картах кроме Священной войны (guildwar и guildwar2).
Выкладываю исходный код C++ DLL, которая заставляет ру. оф. 1.3x клиент отмечать персонажей кругами.
dllmain.cpp
#include <string>
#include <windows.h>
#include <detours.h>
// Адрес персонажа игрока
const DWORD MainChaStaticAddr = 0x0067061C; // Для EN клиента 0x0067052C;
// Адрес функции NetSwitchMap( )
const DWORD NetSwitchMapAddr = 0x005071A0; // Для EN клиента 0x00507090;
// Адрес метода CCharacter::setSideID( )
const DWORD SetSideIdAddr = 0x004A2950; //Для EN клиента 0x004A2840;
// Класс персонажа
class CCharacter
{
public:
// Получить ID персонажа
int get_id() const {
return m_id;
}
// Получить ID гильдии
int get_guild_id() const {
return m_guildId;
}
private:
char m_nop1[0x04E4]; // Смещение 1
int m_guildId; // ID гильдии
char m_nop2[0x07FC]; // Смещение 2
int m_id; // ID персонажа
};
// Структура с информацией о смене карты
struct stNetSwitchMap
{
short sEnterRet;
char *szMapName;
char chEnterType;
bool bIsNewCha;
bool bCanTeam;
};
// Тип указателя на оригинальный
// метод void CCharacter::setSideID(long side_id)
typedef void (__thiscall *setSideIdPtr)(void *, unsigned int);
// Тип указателя на оригинальную функцию
// void NetSwitchMap(stNetSwitchMap &switchmap)
typedef void (__cdecl *netSwitchMapPtr)(stNetSwitchMap&);
// Указатель на оригинальный метод
// void CCharacter::setSideID(long side_id)
setSideIdPtr original_SetChaSide = (setSideIdPtr)(void *)(SetSideIdAddr);
// Указатель на оригинальную функцию
// void NetSwitchMap(stNetSwitchMap &switchmap)
netSwitchMapPtr original_SwitchMap = (netSwitchMapPtr)(void *)(NetSwitchMapAddr);
// Текущая карта персонажа
std::string OurMap = "";
// Прочитать целое число из памяти по
// указанному адресу
DWORD ReadDword(DWORD address)
{
DWORD Temp = 0;
ReadProcessMemory( GetCurrentProcess(), (void *)address, &Temp, sizeof(Temp), 0 );
return Temp;
}
// Функция, которая выполняет перехват функции смены карты
void __cdecl hooked_SwitchMap(stNetSwitchMap &switchmap)
{
// Получим текущую карту персонажа
OurMap = switchmap.szMapName;
// Вызываем оригинальную функцию
original_SwitchMap(switchmap);
}
// Функция, которая выполняет перехват установки цветного круга
// в зависимости от стороны персонажа
void __fastcall hooked_SetChaSide(void *This,
void *notUsed, unsigned int side_id)
{
// Указатель на нашего персонажа
CCharacter *pMainCha = reinterpret_cast<CCharacter *>( ReadDword(MainChaStaticAddr) );
// Указатель на персонажа
CCharacter *pCha = reinterpret_cast<CCharacter *>(This);
if ( pMainCha != nullptr && pCha != nullptr )
{
if ( pMainCha->get_id() != pCha->get_id() )
{
// Проверим, что персонажи не находятся в СВ
if ( OurMap != "guildwar" && OurMap != "guildwar2")
{
if (pMainCha->get_guild_id() == pCha->get_guild_id())
{
// Если персонажи в одной гильдии
// то устанавливаем зеленый круг
side_id = 1;
}
else
{
// Если персонажи не в одной гильдии
// то устанавливаем красный круг
side_id = 2;
}
}
}
}
// Вызываем оригинальный метод
original_SetChaSide(This, side_id);
}
// Точка входа
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// Устанавливаем хуки
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)original_SwitchMap, hooked_SwitchMap);
DetourAttach(&(PVOID&)original_SetChaSide, hooked_SetChaSide);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
// Снимаем хуки
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)original_SwitchMap, hooked_SwitchMap);
DetourDetach(&(PVOID&)original_SetChaSide, hooked_SetChaSide);
DetourTransactionCommit();
break;
}
return TRUE;
}
Предоставляю замечательную возможность изучить код и скомпилировать DLL, а также подключить её к клиенту самостоятельно. Для этого понадобятся Microsoft Visual Studio Community 2017 и библиотека Microsoft Detours. Как собрать библиотеку Detours можно почитать на Хабре. Как присоединить DLL к Game.exe можно найти в гугле.