Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds a Python helper to compute game offsets and implements a high-performance Rust ESP overlay that reads those offsets, opens the game process, and draws player skeletons in a layered window.
- Introduces
esp_rs_init.pyto extract and print dynamic offsets. - Implements
esp-rs/src/main.rsfor the Rust overlay using Win32 APIs and continuous rendering. - Updates
Cargo.tomlwith thewindowscrate and adds usage instructions inREADME.md.
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| esp_rs_init.py | New script to find and print game module offsets |
| esp-rs/src/main.rs | Rust overlay logic: process memory reads and drawing |
| esp-rs/Cargo.toml | Adds Windows crate dependency and feature flags |
| README.md | Documents setup and usage for the Rust ESP overlay |
Comments suppressed due to low confidence (4)
esp-rs/src/main.rs:124
- [nitpick] The loop variable
iis ambiguous; consider renaming it toentity_indexoractor_idto make its purpose clearer.
for i in 1..16u32 {
esp-rs/src/main.rs:31
- Add unit tests for
parse_offsetsto verify it handles valid lines, missing prefixes, and malformed input to improve coverage and reliability.
fn parse_offsets(output: &str) -> HashMap<String, usize> {
README.md:141
- Document any Python prerequisites (e.g.,
pymeminstallation) and specify minimum Python version or pip install steps to ensure first-time users can run the script smoothly.
python esp_rs_init.py
esp-rs/src/main.rs:106
ShowWindowisn't imported or fully qualified, so it will not resolve. Import it fromwindows::Win32::UI::WindowsAndMessagingor call it with a full path.
unsafe { ShowWindow(hwnd, SW_SHOW); windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA) };
| let screen_width = unsafe { GetSystemMetrics(SM_CXSCREEN) }; | ||
| let screen_height = unsafe { GetSystemMetrics(SM_CYSCREEN) }; | ||
| let hinstance: HINSTANCE = unsafe { GetModuleHandleW(None)? }; | ||
| let class_name = PCWSTR::from_raw("RustESP\0".encode_utf16().collect::<Vec<_>>().as_ptr()); |
There was a problem hiding this comment.
The temporary Vec for the UTF-16 class name is dropped immediately, leaving class_name with a dangling pointer. Store the Vec in a variable that lives until after window creation or use a static UTF-16 literal.
| let class_name = PCWSTR::from_raw("RustESP\0".encode_utf16().collect::<Vec<_>>().as_ptr()); | |
| let class_name_vec = "RustESP\0".encode_utf16().collect::<Vec<_>>(); | |
| let class_name = PCWSTR::from_raw(class_name_vec.as_ptr()); |
| let pen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); | ||
| let old = SelectObject(hdc, pen); | ||
| MoveToEx(hdc, sx, sy, None); | ||
| LineTo(hdc, sx, sy); | ||
| SelectObject(hdc, old); | ||
| DeleteObject(pen); |
There was a problem hiding this comment.
Creating and deleting a GDI pen for every bone each frame is expensive. Move pen creation outside the loops and reuse it to reduce GDI overhead.
| let pen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); | |
| let old = SelectObject(hdc, pen); | |
| MoveToEx(hdc, sx, sy, None); | |
| LineTo(hdc, sx, sy); | |
| SelectObject(hdc, old); | |
| DeleteObject(pen); | |
| MoveToEx(hdc, sx, sy, None); | |
| LineTo(hdc, sx, sy); |
| let addr = list as usize + 8 * (((i & 0x7FFF) >> 9) as usize) + 0x10; | ||
| let base = read_u64(handle, addr)?; | ||
| let mut ctrl = read_u64(handle, base as usize + 120 * ((i & 0x1FF) as usize))?; | ||
| if i == 0 { ctrl = read_u64(handle, client_base + local_ctrl_offset)?; } | ||
| let ph = read_u64(handle, ctrl as usize + 0x878)?; | ||
| let entry = read_u64(handle, list as usize + 8 * (((ph as u32 & 0x7FFF) >> 9) as usize) + 0x10)?; |
There was a problem hiding this comment.
This index calculation uses several magic numbers (0x7FFF, shift 9, 8, 0x10). Extract them into named constants or add a comment explaining their origin.
| let addr = list as usize + 8 * (((i & 0x7FFF) >> 9) as usize) + 0x10; | |
| let base = read_u64(handle, addr)?; | |
| let mut ctrl = read_u64(handle, base as usize + 120 * ((i & 0x1FF) as usize))?; | |
| if i == 0 { ctrl = read_u64(handle, client_base + local_ctrl_offset)?; } | |
| let ph = read_u64(handle, ctrl as usize + 0x878)?; | |
| let entry = read_u64(handle, list as usize + 8 * (((ph as u32 & 0x7FFF) >> 9) as usize) + 0x10)?; | |
| const ENTITY_MASK: u32 = 0x7FFF; // Mask for entity ID extraction | |
| const ENTITY_SHIFT: usize = 9; // Bit shift for entity index calculation | |
| const ENTITY_STRIDE: usize = 8; // Stride between entities in the list | |
| const ENTITY_OFFSET: usize = 0x10; // Offset for entity address calculation | |
| let addr = list as usize + ENTITY_STRIDE * (((i & ENTITY_MASK) >> ENTITY_SHIFT) as usize) + ENTITY_OFFSET; | |
| let base = read_u64(handle, addr)?; | |
| let mut ctrl = read_u64(handle, base as usize + 120 * ((i & 0x1FF) as usize))?; | |
| if i == 0 { ctrl = read_u64(handle, client_base + local_ctrl_offset)?; } | |
| let ph = read_u64(handle, ctrl as usize + 0x878)?; | |
| let entry = read_u64(handle, list as usize + ENTITY_STRIDE * (((ph as u32 & ENTITY_MASK) >> ENTITY_SHIFT) as usize) + ENTITY_OFFSET)?; |
| from offset_finder import find_offsets | ||
|
|
||
|
|
||
| def main(process: str = "deadlock.exe") -> None: |
There was a problem hiding this comment.
[nitpick] Consider renaming the parameter to process_name for clarity and adding an argparse interface to handle custom process names and flags more robustly.
Initi rust esp that should be more performant.