#pragma once #include "reflect_type_info.hpp" #include #include template emulator_hook* watch_object(windows_emulator& emu, const std::set>& modules, emulator_object object, const auto verbose) { const reflect_type_info info{}; return emu.emu().hook_memory_read( object.value(), static_cast(object.size()), [i = std::move(info), object, &emu, verbose, modules](const uint64_t address, const void*, const size_t size) { const auto rip = emu.emu().read_instruction_pointer(); const auto* mod = emu.mod_manager.find_by_address(rip); const auto is_main_access = !mod || (mod == emu.mod_manager.executable || modules.contains(mod->name)); if (!verbose && !is_main_access) { return; } if (!verbose) { static std::unordered_set logged_addresses{}; if (is_main_access && !logged_addresses.insert(address).second) { return; } } const auto start_offset = address - object.value(); const auto end_offset = start_offset + size; const auto* mod_name = mod ? mod->name.c_str() : ""; const auto& type_name = i.get_type_name(); for (auto offset = start_offset; offset < end_offset;) { const auto member_info = i.get_member_info(static_cast(offset)); if (!member_info.has_value()) { const auto remaining_size = end_offset - offset; emu.log.print(is_main_access ? color::green : color::dark_gray, "Object access: %s - 0x%" PRIx64 " 0x%" PRIx64 " () at 0x%" PRIx64 " (%s)\n", type_name.c_str(), offset, remaining_size, rip, mod_name); break; } const auto remaining_size = end_offset - offset; const auto member_end = member_info->offset + member_info->size; const auto member_access_size = member_end - offset; const auto access_size = std::min(remaining_size, member_access_size); emu.log.print(is_main_access ? color::green : color::dark_gray, "Object access: %s - 0x%" PRIx64 " 0x%" PRIx64 " (%s) at 0x%" PRIx64 " (%s)\n", type_name.c_str(), offset, access_size, member_info->get_diff_name(static_cast(offset)).c_str(), rip, mod_name); offset = member_end; } }); } template emulator_hook* watch_object(windows_emulator& emu, const std::set>& modules, const uint64_t address, const auto verbose) { return watch_object(emu, modules, emulator_object{emu.emu(), address}, verbose); }