/ src / core / esp_manager.cpp
esp_manager.cpp
  1  // 作者: feng_xingzhe_cn_.86
  2  
  3  #include <onyx/core/esp_manager.hpp>
  4  #include <onyx/core/settings.hpp>
  5  #include <onyx/sdk/game/GameplayModule.hpp>
  6  #include <onyx/sdk/game/Character.hpp>
  7  #include <onyx/sdk/game/Skeleton.hpp>
  8  #include <onyx/sdk/game/LocalPlayer.hpp>
  9  #include <onyx/utils/Memory.hpp>
 10  #include <thread>
 11  #include <chrono>
 12  #include <algorithm>
 13  
 14  namespace onyx::core {
 15  
 16      using namespace sdk::game;
 17  
 18      void EspManager::update_loop(uintptr_t base_address, sdk::game::CameraSystem& camera) noexcept {
 19  
 20          using PlayerEntry = ::onyx::Dictionary<int32_t, uintptr_t>::Entry;
 21  
 22          std::vector<PlayerData> current_batch;
 23          std::vector<PlayerEntry> entry_buffer;
 24  
 25          while (true) {
 26  
 27              std::this_thread::sleep_for(std::chrono::milliseconds(4)); // ~240hz
 28  
 29              current_batch.clear();
 30  
 31              auto gameplay = GameplayModule::instance();
 32  
 33              if (!gameplay.is_valid()) {
 34                  clear_players();
 35                  continue;
 36              }
 37  
 38              camera = gameplay.camera_system;
 39  
 40              if (!camera.is_valid()) {
 41                  clear_players();
 42                  continue;
 43              }
 44  
 45              auto game_system = gameplay.game_system;
 46  
 47              if (!game_system.is_valid()) {
 48                  clear_players();
 49                  continue;
 50              }
 51  
 52              uintptr_t dict_addr = game_system.player_dict;
 53  
 54              if (!utils::Memory::is_valid_ptr(dict_addr)) {
 55                  clear_players();
 56                  continue;
 57              }
 58  
 59              auto dict = utils::Memory::read<::onyx::Dictionary<int32_t, uintptr_t>>(dict_addr);
 60  
 61              uintptr_t entries_addr = reinterpret_cast<uintptr_t>(dict.entries);
 62  
 63              if (!utils::Memory::is_valid_ptr(reinterpret_cast<uintptr_t>(dict.entries)) || dict.count <= 0 || dict.count >= 1000) {
 64                  clear_players();
 65                  continue;
 66              }
 67  
 68              current_batch.reserve(dict.count);
 69  
 70              const float screen_w = ImGui::GetIO().DisplaySize.x;
 71              const float screen_h = ImGui::GetIO().DisplaySize.y;
 72  
 73              const uintptr_t vector_base = entries_addr + 0x20;
 74  
 75              entry_buffer.resize(dict.count);
 76  
 77              utils::Memory::read_raw(vector_base, entry_buffer.data(), dict.count * sizeof(PlayerEntry));
 78  
 79              uintptr_t closest_addr = 0;
 80  
 81              float min_dist = 1000000.0f;
 82  
 83              sdk::Vector3 cam_pos = camera.main_camera.position;
 84  
 85              for (int32_t i = 0; i < dict.count; ++i) {
 86  
 87                  PlayerEntry& entry = entry_buffer[i];
 88  
 89                  if (entry.hashCode < 0 || !utils::Memory::is_valid_ptr(entry.value)) continue;
 90  
 91                  Character character(entry.value);
 92  
 93                  float d = sdk::Vector3::Distance(character.transform.position(), cam_pos);
 94  
 95                  if (d < min_dist) {
 96  
 97                      min_dist = d;
 98                      closest_addr = entry.value;
 99  
100                  }
101  
102              }
103  
104              {
105  
106                  std::lock_guard<std::mutex> lock(m_mutex);
107  
108                  if (closest_addr != 0) {
109  
110                      m_local_player = sdk::game::LocalPlayer(closest_addr);
111  
112                  }
113  
114              }
115  
116              for (int32_t i = 0; i < dict.count; ++i) {
117  
118                  PlayerEntry& entry = entry_buffer[i];
119  
120                  if (entry.hashCode < 0 || !utils::Memory::is_valid_ptr(entry.value)) { continue; }
121  
122                  if (entry.value == closest_addr) { continue; }
123  
124                  Character character(entry.value);
125  
126                  sdk::Vector3 world_pos = character.transform.position();
127  
128                  float d = sdk::Vector3::Distance(world_pos, cam_pos);
129  
130                  PlayerData& p_data = current_batch.emplace_back();
131  
132                  if (camera.world_to_screen(world_pos, p_data.screen_pos, screen_w, screen_h)) {
133  
134                      p_data.world_pos = world_pos;
135                      p_data.health = character.health;
136                      p_data.distance = d;
137                      p_data.is_visible = true;
138  
139                      auto skel = Skeleton::find_from_character(character.transform, world_pos);
140  
141                      if (skel) {
142  
143                          auto& joints = skel->joints;
144  
145                          int32_t num = static_cast<int32_t>(joints.size());
146  
147                          if (num > k_max_bones) num = k_max_bones;
148  
149                          p_data.bone_count = num;
150  
151                          if (num > 0) {
152  
153                              sdk::Vector3 bmin = joints[0].world_position;
154                              sdk::Vector3 bmax = bmin;
155  
156                              for (int32_t b = 0; b < num; ++b) {
157  
158                                  sdk::Vector3 wp = joints[b].world_position;
159  
160                                  wp.y += Settings::get().esp_skeleton_y_offset;
161  
162                                  if (wp.x < bmin.x) bmin.x = wp.x;
163                                  if (wp.y < bmin.y) bmin.y = wp.y;
164                                  if (wp.z < bmin.z) bmin.z = wp.z;
165                                  if (wp.x > bmax.x) bmax.x = wp.x;
166                                  if (wp.y > bmax.y) bmax.y = wp.y;
167                                  if (wp.z > bmax.z) bmax.z = wp.z;
168  
169                                  ImVec2 sp;
170  
171                                  if (camera.world_to_screen(wp, sp, screen_w, screen_h)) {
172  
173                                      p_data.bones[b].screen_pos = sp;
174                                      p_data.bones[b].parent_index = joints[b].parent_index;
175                                      p_data.bones[b].is_valid = true;
176  
177                                  }
178                              }
179  
180                              constexpr float k_padding = 0.12f;
181  
182                              bmin.x -= k_padding; bmin.y -= k_padding; bmin.z -= k_padding;
183                              bmax.x += k_padding; bmax.y += k_padding; bmax.z += k_padding;
184  
185                              p_data.aabb_min = bmin;
186                              p_data.aabb_max = bmax;
187                              p_data.has_bounds = true;
188  
189                          }
190  
191                      }
192  
193                  } else {
194  
195                      p_data.world_pos = world_pos;
196                      p_data.distance = d;
197                      p_data.is_visible = false;
198                      p_data.bone_count = 0;
199                      p_data.has_bounds = false;
200  
201                  }
202  
203              }
204  
205              {
206  
207                  std::lock_guard<std::mutex> lock(m_mutex);
208  
209                  m_players = current_batch;
210  
211              }
212  
213          }
214  
215      }
216  
217      [[nodiscard]] std::vector<PlayerData> EspManager::players() const noexcept {
218  
219          std::lock_guard<std::mutex> lock(m_mutex);
220  
221          return m_players;
222  
223      }
224  
225      void EspManager::clear_players() noexcept {
226  
227          std::lock_guard<std::mutex> lock(m_mutex);
228  
229          m_players.clear();
230  
231      }
232  
233  } // namespace onyx::core