Участник
-
Автор темы
- #21
в общем попрофилировал и пришел к выводу что вроде такая итерация напрямую через массив быстрее на пару фпс(разница не больше 6 фпс иногда ее практически нет в доте фпс нестабильный).А не пробовал как в Mcdota через Reinit predictables найти энтити лист ?
Пожалуйста, авторизуйтесь для просмотра ссылки.
найти по Reinit Predictables не получится, такая строка только на линуксе есть.
Вот по этой можно найти.
CL: reinitialized %i predictable entities\n
GetHighestEntityIndex там просто инлайнится как я понял, в отличии от линукс версии. Вот эти две строки вместо нее.
НУ или v4 в дизасемблере
Самый первый вызов функции это GetBaseEntity(индекс).
перед вызовом this (EntitySystem) кладется в rcx
text:0000000180810AA0 sub_180810AA0 proc near
.text:0000000180810AA0 push rsi
.text:0000000180810AA2 sub rsp, 30h
.text:0000000180810AA6 mov rax, cs:qword_182EAE0A8 ; Вот тут
.text:0000000180810AAD mov [rsp+38h+arg_0], rbx
.text:0000000180810AB2 mov [rsp+38h+arg_8], rbp
.text:0000000180810AB7 xor ebp, ebp
.text:0000000180810AB9 mov [rsp+38h+arg_10], rdi
.text:0000000180810ABE mov ebx, ebp
.text:0000000180810AC0 mov byte ptr [rcx+100h], 1
.text:0000000180810AC7 mov edi, [rax+2060h] ; И вот тут
.text:0000000180810ACD mov [rsp+38h+var_10], r14
.text:0000000180810AD2 mov r14, rcx
.text:0000000180810AD5 test edi, edi
.text:0000000180810AD7 js loc_180810B94
.text:0000000180810ADD
.text:0000000180810ADD loc_180810ADD:
.text:0000000180810ADD
.text:0000000180810ADD mov [rsp+38h+var_18], r15
.text:0000000180810AE2 lea r15, qword_182E98388
.text:0000000180810AE9 nop dword ptr [rax+00000000h]
.text:0000000180810AF0
.text:0000000180810AF0 loc_180810AF0:
.text:0000000180810AF0 cmp ebx, 0FFFFFFFFh
.text:0000000180810AF3 jl loc_180810B85
.text:0000000180810AF9 mov rcx, cs:qword_182EAE0A8 ; entitySystem указатель.
.text:0000000180810B00 mov edx, ebx
.text:0000000180810B02 add rcx, 10h
.text:0000000180810B06 call sub_180164B30 ; Вот эта функция - GetBaseEntity
.text:0000000180810B0B test rax, rax
Не проверял, но похоже, что все так и есть.
Пример итераций энтитиПожалуйста, авторизуйтесь для просмотра ссылки.
плюсы итерации через Next как в этом туторе:
во-первых она красивая, обернутая(что собственно значит надежная, малоошибочная)
во-вторых можно получить инфу о том находится ли сущность в тумане основываясь на том что если в итерации через Next сущности не было то она в тумане.
минусы Next:
во-первых вроде куча мусорных сущностей(то есть итерируем лишний хлам и поэтому -фпс)
во-вторых сама по себе медленная так как это обертка(любая обертка медленнее прямого управления данными)
в-третьих нельзя получить сущность по индексу не убив немножко фпс.(основная проблема которая ваще заставила меня задуматься)
плюсы голой итерации через массив:
во-первых быстрая так как голая + нету мусорных сущностей как в Next
во-вторых сущностей можно легко получить по индексу так как они в массиве по индексам расположены друг за другом
минусы голой итерации через массив:
во-первых эстетически уродливая(ну на это думаю всем насрать)
во-вторых нельзя получить инфу о сущности в тумане чисто на основе итерации(так как в этом массиве сущность всегда будет пока не удалится, а в тумане она не удаляется она просто засыпает)
в итоге я выбрал +парочку фпс и итерирую через массив а проблему с инфой о сущности в тумане решил по-другому.
C++:
class CENTITYIDENTITY {
...
char flags[4];//оффсет 0x30
bool IsDormant() {//true когда в тумане
return (flags[0] & 0x80);
}
C++:
Function GetClassInfoByName = 0;
u64 GCIBN = FindPattern("client.dll",
"33 ff 48 39 3d ?? ?? ?? ?? 0f 84 ?? ?? ?? ?? 48 39 3d ?? ?? ?? ?? 0f 84 ?? ?? ?? ?? 4c 8d 44 24 ",
"getclassinfobyname not found");//dylib CEntitySystem::FindClassByName
GetClassInfoByName = GCIBN - 0x51;
...
Pointer<u64> CDOTABASENPC_HERO_CLASS = 0;
u64 HeroBaseClass = 0;
//runframe:
...
//GameState = GameRules->GameState()
if(Engine->InGame() && GameState == Game_Rules::DOTA_GAMERULES_PREGAME ||
GameState == Game_Rules::DOTA_GAMERULES_GAME_IN_PROGRESS)
if (!CDOTABASENPC_HERO_CLASS|| !HeroBaseClass) {
CDOTABASENPC_HERO_CLASS = GetClassInfoByName(EntitySystem, "C_DOTA_BaseNPC_Hero");
if(CDOTABASENPC_HERO_CLASS)
HeroBaseClass = *CDOTABASENPC_HERO_CLASS;
}
...
//centityidentity
u64 baseinfo;//offset 8
bool IsHero() {
return *(u64*)baseinfo == HeroBaseClass;
}
...
//iteration:
...
if(entity_identity->IsHero())
и вот в итоге сама голая итерация:
C++:
void IterateARRAY() {//dylib CGameEntitySystem::GetBaseEntity(CEntityIndex)
//массив разделен на 64 листа по 512 сущностей
short LocalPlayerIndex = 0;
if (!LocalPlayer) LocalPlayerIndex = Engine->GetLocalPlayerIndex();
auto LPstack = LocalPlayer;
u64 EntSys = EntitySystem;
u64 HeroBC = HeroBaseClass;
int highestindex = EntitySystem->Member(0x2060);
int highestlist = highestindex >> 9;//целая часть от деления на 512
int maxent = highestindex & 0x1ff;//последние 9 бит, то есть остаток деления на 512 кароче
int entc = 0;
for (int list = 0; list <= highestlist; list++) {
u64 EntityList = *(u64*)(EntSys + 0x10 + list * 8);
if (!EntityList) return;
for (int ent = 0; ent < 512; ent++) {
if (list == highestlist && ent >= maxent) break;//если последний лист до не до конца 512 итерировать а до maxent
auto entident = (CENTITYIDENTITY*)(EntityList + ent * 0x78);//sizeof(centityidentity) = 0x78
if (!entident||!entident->entity) continue;
if (!LPstack) {//беру из стека/регистра а не напрямую из оперативки каждый цикл, +наносекунды быстроты
if (entident->Index() == LocalPlayerIndex) {
LocalPlayer = entident->entity;
LocalTeam = LocalPlayer->Team();
continue;
}
}
if (entident->DerefBaseInfo() == HeroBC) {//HeroBC загружаю из регистра/стека а не напрямую из оперативы это дает мне пару наносекунд быстроты... мда
if (!entident->entity->IsIllusion()) {//m_hReplicatingOtherHeroModel равна -1 у настоящего
//делаю ченибудь
}
}
}
}
}
//и плюс еще
Entity* GetEntityByIndex(u64 CEntSysPlusTen,int index) {
//if index > 0x7ffe return 0; //вырубил для скорости
int sar = index >> 9;
//if sar > 0x3e return 0; //вырубил для скорости, хотя пара наносекунд(10 в минус девятой) ничего не меняют на самом деле поэтому можете включать спокойно
u64 list = *(u64*)(CEntSysPlusTen + sar*8);
auto ent = (CENTITYIDENTITY*)(list + 0x78 * (index & 0x1ff));
return ent->entity;
return 0;
}