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

Вопрос Rust — Мерцают кости в ESP и не прорисовываются игроки

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
538
Реакции
14
Парни, такая тема: пилю свой проект под Rust, и чет застрял на отрисовке скелетов. Суть в том, что кости у игроков безбожно мерцают, а у некоторых персонажей они вообще не появляются, хотя база вроде живая.

Юзаю стандартный подход через чтение иерархии и трансформаций. Смещение 0x38 для TransformAccess на месте, trsX структуру вроде не шатало, но на выходе имею дикую дискотеку на экране. Грешу либо на гонку данных при чтении через ReadPhysicalRaw, либо на то, что иерархия у Unity-объектов обновляется быстрее, чем я успеваю её переварить.

Код:
Expand Collapse Copy
void Getbones(uintptr_t& boneTransforms, std::unordered_map<int, Vector3>& bones)
{
 if (!boneTransforms)
  return;
  struct BoneData
 {
  int id;
  int hierarchyIndex;
  uintptr_t hierarchyAddr;
 };
  std::unordered_map<int, Vector3> resultBones;
 std::vector<BoneData> validBones;
 std::unordered_map<uintptr_t, int> hierarchyMaxIndex;
  const uintptr_t boneListAddress = boneTransforms + 0x28;
 constexpr int bone_count = sizeof(bone_list) / sizeof(bone_list[0]);
  for (int i = 0; i < bone_count; i++)
 {
  int boneID = bone_list[i];
   uintptr_t boneEntityPtr = process.Read<uintptr_t>(boneListAddress + (boneID * 0x8));
  if (!boneEntityPtr)
   continue;
   uintptr_t trans = process.Read<uintptr_t>(boneEntityPtr + 0x10);
  if (!trans)
   continue;
   TransformInternal::TransformAccess access =
   process.Read<TransformInternal::TransformAccess>(trans + 0x38);
   if (!access.hierarchyAddr)
   continue;
   if (access.index < 0 || access.index >= 4000)
   continue;
   validBones.push_back({ boneID, access.index, access.hierarchyAddr });
   auto it = hierarchyMaxIndex.find(access.hierarchyAddr);
  if (it == hierarchyMaxIndex.end())
   hierarchyMaxIndex[access.hierarchyAddr] = access.index;
  else if (access.index > it->second)
   it->second = access.index;
 }
  if (validBones.empty())
  return;
  std::unordered_map<uintptr_t, std::pair<std::vector<TransformInternal::trsX>, std::vector<int>>> hierarchyDataMap;
  for (const auto& pair : hierarchyMaxIndex)
 {
  uintptr_t hierarchyAddr = pair.first;
  int maxIndexRequired = pair.second;
   if (!hierarchyAddr)
   continue;
   int elementsToRead = maxIndexRequired + 1;
  if (elementsToRead <= 0 || elementsToRead > 4000)
   continue;
   bool hierarchyLoaded = false;
   for (int attempt = 0; attempt < 3 && !hierarchyLoaded; attempt++)
  {
   uintptr_t localT_1 = process.Read<uintptr_t>(hierarchyAddr + 0x18);
   uintptr_t parentI_1 = process.Read<uintptr_t>(hierarchyAddr + 0x20);
    if (!localT_1 || !parentI_1)
    continue;
    std::vector<TransformInternal::trsX> tempTRS(elementsToRead);
   std::vector<int> tempParents(elementsToRead);
    bool readParents = process.ReadPhysicalRaw(
    parentI_1,
    (uintptr_t)tempParents.data(),
    elementsToRead * sizeof(int)
   );
    if (!readParents)
    continue;
    bool readLocal = process.ReadPhysicalRaw(
    localT_1,
    (uintptr_t)tempTRS.data(),
    elementsToRead * sizeof(TransformInternal::trsX)
   );
    if (!readLocal)
    continue;
    uintptr_t localT_2 = process.Read<uintptr_t>(hierarchyAddr + 0x18);
   uintptr_t parentI_2 = process.Read<uintptr_t>(hierarchyAddr + 0x20);
    if (localT_1 != localT_2 || parentI_1 != parentI_2)
    continue;
    hierarchyDataMap[hierarchyAddr] = {
    std::move(tempTRS),
    std::move(tempParents)
   };
    hierarchyLoaded = true;
  }
   if (!hierarchyLoaded)
   continue;
 }
  for (const auto& bone : validBones)
 {
  auto it = hierarchyDataMap.find(bone.hierarchyAddr);
  if (it == hierarchyDataMap.end())
   continue;
   const auto& hd = it->second;
   if (hd.first.empty() || hd.second.empty())
   continue;
   if (bone.hierarchyIndex < 0 || bone.hierarchyIndex >= (int)hd.first.size())
   continue;
   Vector3 worldPos = hd.first[bone.hierarchyIndex].t;
  int pIndex = hd.second[bone.hierarchyIndex];
  int safety = 0;
   while (pIndex >= 0 && pIndex < (int)hd.first.size() && safety < 120)
  {
   const auto& parent = hd.first[pIndex];
    float numX = parent.q.x * 2.0f;
   float numY = parent.q.y * 2.0f;
   float numZ = parent.q.z * 2.0f;
    float num2X = parent.q.x * numX;
   float num2Y = parent.q.y * numY;
   float num2Z = parent.q.z * numZ;
    float num3X = parent.q.x * numY;
   float num3Y = parent.q.x * numZ;
   float num3Z = parent.q.y * numZ;
    float num4X = parent.q.w * numX;
   float num4Y = parent.q.w * numY;
   float num4Z = parent.q.w * numZ;
    float rotX =
    (1.0f - (num2Y + num2Z)) * worldPos.x +
    (num3X - num4Z) * worldPos.y +
    (num3Y + num4Y) * worldPos.z;
    float rotY =
    (num3X + num4Z) * worldPos.x +
    (1.0f - (num2X + num2Z)) * worldPos.y +
    (num3Z - num4X) * worldPos.z;
    float rotZ =
    (num3Y - num4Y) * worldPos.x +
    (num3Z + num4X) * worldPos.y +
    (1.0f - (num2X + num2Y)) * worldPos.z;
    worldPos.x = rotX * parent.s.x + parent.t.x;
   worldPos.y = rotY * parent.s.y + parent.t.y;
   worldPos.z = rotZ * parent.s.z + parent.t.z;
    if (pIndex < 0 || pIndex >= (int)hd.second.size())
    break;
    pIndex = hd.second[pIndex];
   safety++;
  }
   resultBones[bone.id] = worldPos;
 }
  if (!resultBones.empty())
  bones = std::move(resultBones);
}

Есть подозрение, что проблема в hierarchyAddr, которая может меняться, или в неправильной обработке спящих игроков (sleepers). Кто уже сталкивался с подобным в актуальном билде раста?

Интересно, как вы обходите мерцание при использовании RPM/PhysicalRead без использования внутреннего рендерера.
 
Назад
Сверху Снизу