Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Гайд [Краш] Day of Defeat: Source — вылет DrawModelExecute при инжекте

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
682
Реакции
18
Классическая болячка для Source-движка и старых проектов типа Day of Defeat. Суть проблемы: если инжектить софт до захода на сервер или во время загрузки, игра намертво падает в краш. При этом, если заинжектиться уже в процессе катки — всё работает ровно.

В ходе дебага выяснилось, что при загрузке на сервер, где уже есть активные игроки, хук DrawModelExecute (DME) начинает сходить с ума и падать с ошибкой обращения к памяти. Судя по всему, идет попытка считать данные сущностей, которые еще не проинициализированы до конца.

Сам код проблемного хука:
Код:
Expand Collapse Copy
void __fastcall ModelRender::DrawModelExecute::Detour(void* __this, void* ecx, const DrawModelState_t& state, const ModelRenderInfo_t& pInfo, matrix3x4_t* pCustomBoneToWorld)
{
 FN o = VTable.Original<FN>(index);
 if (!o)
  return;

  bool didDraw = false;
  C_DODPlayer* plr = I::EntityList->GetClientEntity(I::EngineClient->GetLocalPlayer())->Cast<C_DODPlayer*>();
  C_DODPlayer* otherPlr = I::EntityList->GetClientEntity(pInfo.entity_index)->Cast<C_DODPlayer*>();

  if (I::EngineClient->IsInGame() && I::EngineClient->IsConnected() && pInfo.pRenderable && pInfo.pModel && pInfo.entity_index)
 {
  IClientEntity* ent = I::EntityList->GetClientEntity(pInfo.entity_index);
  if (ent)
  {
   ClientClass* pCC = ent->GetClientClass();
   if (pCC)
   {
    ChamItem* cham = 0;
    switch (pCC->m_ClassID)
    {
    case EClientClass::CDODPlayer:
    {
     C_DODPlayer* otherPlr = ent->Cast<C_DODPlayer*>();
     C_DODPlayer* plr = I::EntityList->GetClientEntity(I::EngineClient->GetLocalPlayer())->Cast<C_DODPlayer*>();
      if (plr && otherPlr)
     {
      cham = &Hacks::Visuals::Chams.Enemies;
     }
      break;
    }
    case EClientClass::CDODRagdoll:
     didDraw = true;
     cham = &Hacks::Visuals::Chams.Ragdoll;
      break;
    case EClientClass::CDODViewModel:
     didDraw = true;
     cham = &Hacks::Visuals::Chams.Viewmodel;
      break;
    default:
     if (U::Game.IsClassWeapon(pCC->m_ClassID))
     {
      didDraw = true;
      cham = &Hacks::Visuals::Chams.Weapons;
     }
      break;
    }

     if (didDraw)
    {
     C_DODPlayer* player = ent->Cast<C_DODPlayer*>();
          if (!player->deadflag())
     {
      IMaterial* material = 0;
      if (cham->Material != ChamMaterial::DEFAULT)
      {
       material = I::MaterialSystem->FindMaterial(Hacks::Visuals::GetMaterialFromChamType(cham->Material), TEXTURE_GROUP_MODEL);
       material->AddRef();
       material->SetMaterialVarFlag(MATERIAL_VAR_IGNOREZ, true);
      }

       I::RenderView->SetBlend(cham->clrHidden.a());
       I::RenderView->SetColorModulation(cham->clrHidden.fCol);

       if(cham->Material != ChamMaterial::DEFAULT)
       I::ModelRender->ForcedMaterialOverride(material);

       o(__this, ecx, state, pInfo, pCustomBoneToWorld);

       if(cham->Material != ChamMaterial::DEFAULT)
       material->SetMaterialVarFlag(MATERIAL_VAR_IGNOREZ, false);

       I::RenderView->SetBlend(cham->clrVisible.a());
       I::RenderView->SetColorModulation(cham->clrVisible.fCol);

       if(cham->Material != ChamMaterial::DEFAULT)
       I::ModelRender->ForcedMaterialOverride(material);

       o(__this, ecx, state, pInfo, pCustomBoneToWorld);

       constexpr float white[4] = { 1.f, 1.f, 1.f, 1.f };
       I::RenderView->SetBlend(1.f);
       I::RenderView->SetColorModulation(white);

       if (cham->Material != ChamMaterial::DEFAULT)
       I::ModelRender->ForcedMaterialOverride(nullptr);
     }
    }
   }
  }
 }
  if(!didDraw)
  o(__this, ecx, state, pInfo, pCustomBoneToWorld);
}

Как оказалось, виновником торжества была попытка проверить класс оружия через IsClassWeapon. Видимо, на этапе загрузки pCC->m_ClassID выдает какую-то дичь, из-за чего всё падает в рекурсию или обращается к невалидному адресу.

Фикс:
Просто убираем проверку оружия в дефолтном кейсе или добавляем более жесткие проверки на валидность ent и pCC перед тем, как лезть в m_ClassID.

Код:
Expand Collapse Copy
// Этот кусок вешал всё приложение
if (U::Game.IsClassWeapon(pCC->m_ClassID))
{
    didDraw = true;
    cham = &Hacks::Visuals::Chams.Weapons;
}

Интересно, это специфика DOD или на других Source-играх этот метод тоже так триггерит краши при загрузке?
 
Назад
Сверху Снизу