From cd6a572820f55389ea8d80667b5a76123f0b2104 Mon Sep 17 00:00:00 2001 From: leanhtubtk-jpg Date: Wed, 15 Oct 2025 21:49:08 +0700 Subject: [PATCH 1/4] Update main.go --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 07c2037..3ab9831 100644 --- a/main.go +++ b/main.go @@ -231,7 +231,7 @@ func getEntitiesInfo(procHandle windows.Handle, clientDll uintptr, screenWidth u continue } // entityController - err = read(procHandle, listEntry+uintptr(120)*uintptr(i&0x1FF), &entityController) + err = read(procHandle, listEntry+uintptr(112)*uintptr(i&0x1FF), &entityController) if err != nil { return entities } @@ -255,7 +255,7 @@ func getEntitiesInfo(procHandle windows.Handle, clientDll uintptr, screenWidth u continue } // entityPawn - err = read(procHandle, listEntry+uintptr(120)*uintptr(entityControllerPawn&0x1FF), &entityPawn) + err = read(procHandle, listEntry+uintptr(112)*uintptr(entityControllerPawn&0x1FF), &entityPawn) if err != nil { return entities } From 0b4c2448b958e358f9cea0c363c1d7dd17f75645 Mon Sep 17 00:00:00 2001 From: leanhtubtk-jpg Date: Wed, 15 Oct 2025 21:49:41 +0700 Subject: [PATCH 2/4] Update offsets.json --- offsets.json | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/offsets.json b/offsets.json index 1a64644..13193ea 100644 --- a/offsets.json +++ b/offsets.json @@ -1,15 +1,16 @@ { - "dwViewMatrix": 25716496, - "dwLocalPlayerPawn": 25713704, - "dwEntityList": 24741688, - "m_hPlayerPawn": 1980, - "m_iHealth": 812, - "m_lifeState": 816, - "m_iTeamNum": 959, - "m_vOldOrigin": 4628, - "m_pGameSceneNode": 784, - "m_modelState": 352, - "m_boneArray": 128, - "m_nodeToWorld": 16, - "m_sSanitizedPlayerName": 1824 + "dwViewMatrix": 31582496, + "dwLocalPlayerPawn": 29211408, + "dwEntityList": 30410384, + "m_hPlayerPawn": 2300, + "m_iHealth": 844, + "m_lifeState": 852, + "m_iTeamNum": 1003, + "m_vOldOrigin": 5536, + "m_pGameSceneNode": 816, + "m_modelState": 400, + "m_boneArray": 128, + "m_nodeToWorld": 16, + "m_sSanitizedPlayerName": 2128 } + From acc7de9c63926616c0ebc4fc4c92d9e09c86beae Mon Sep 17 00:00:00 2001 From: leanhtubtk-jpg Date: Thu, 13 Nov 2025 13:19:02 +0700 Subject: [PATCH 3/4] Update main.go --- main.go | 881 ++++++++++++++++++++------------------------------------ 1 file changed, 308 insertions(+), 573 deletions(-) diff --git a/main.go b/main.go index 3ab9831..2778ac9 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,4 @@ +// main.go package main import ( @@ -19,28 +20,9 @@ import ( ) type Matrix [4][4]float32 - -type Vector3 struct { - X float32 - Y float32 - Z float32 -} - -func (v Vector3) Dist(other Vector3) float32 { - return float32(math.Abs(float64(v.X-other.X)) + math.Abs(float64(v.Y-other.Y)) + math.Abs(float64(v.Z-other.Z))) -} - -type Vector2 struct { - X float32 - Y float32 -} - -type Rectangle struct { - Top float32 - Left float32 - Right float32 - Bottom float32 -} +type Vector3 struct{ X, Y, Z float32 } +type Vector2 struct{ X, Y float32 } +type Rectangle struct{ Top, Left, Right, Bottom float32 } type Entity struct { Health int32 @@ -69,6 +51,7 @@ type Offset struct { M_sSanitizedPlayerName uintptr `json:"m_sSanitizedPlayerName"` } +// === GDI & System DLL === var ( user32 = windows.NewLazySystemDLL("user32.dll") gdi32 = windows.NewLazySystemDLL("gdi32.dll") @@ -82,675 +65,427 @@ var ( createPen = gdi32.NewProc("CreatePen") ) +// === ESP Settings === var ( - teamCheck bool = true - headCircle bool = true - skeletonRendering bool = true - boxRendering bool = true - nameRendering bool = true - healthBarRendering bool = true - healthTextRendering bool = true - frameDelay uint32 = 15 + teamCheck = true + headCircle = true + skeletonRendering = true + boxRendering = true + nameRendering = true + healthBarRendering = true + healthTextRendering = true + + // FPS Control (từ C++) + desiredFrameRate = 60 + frameDelay uint32 + lastFrameTime time.Time ) func init() { - // Ensure main() runs on the main thread. runtime.LockOSThread() + frameDelay = uint32(1000 / desiredFrameRate) + lastFrameTime = time.Now() } -func logAndSleep(message string, err error) { - log.Printf("%s: %v\n", message, err) +// === Helper Functions === +func (v Vector3) Dist(o Vector3) float32 { + return float32(math.Abs(float64(v.X-o.X)) + math.Abs(float64(v.Y-o.Y)) + math.Abs(float64(v.Z-o.Z))) +} + +func logAndSleep(msg string, err error) { + log.Printf("%s: %v\n", msg, err) time.Sleep(5 * time.Second) } -func worldToScreen(viewMatrix Matrix, position Vector3) (float32, float32) { - var screenX float32 - var screenY float32 - screenX = viewMatrix[0][0]*position.X + viewMatrix[0][1]*position.Y + viewMatrix[0][2]*position.Z + viewMatrix[0][3] - screenY = viewMatrix[1][0]*position.X + viewMatrix[1][1]*position.Y + viewMatrix[1][2]*position.Z + viewMatrix[1][3] - w := viewMatrix[3][0]*position.X + viewMatrix[3][1]*position.Y + viewMatrix[3][2]*position.Z + viewMatrix[3][3] +func worldToScreen(m Matrix, pos Vector3) (float32, float32) { + x := m[0][0]*pos.X + m[0][1]*pos.Y + m[0][2]*pos.Z + m[0][3] + y := m[1][0]*pos.X + m[1][1]*pos.Y + m[1][2]*pos.Z + m[1][3] + w := m[3][0]*pos.X + m[3][1]*pos.Y + m[3][2]*pos.Z + m[3][3] if w < 0.01 { return -1, -1 } - invw := 1.0 / w - screenX *= invw - screenY *= invw + inv := 1.0 / w + x *= inv + y *= inv + width, _, _ := getSystemMetrics.Call(0) height, _, _ := getSystemMetrics.Call(1) - widthFloat := float32(width) - heightFloat := float32(height) - x := widthFloat / 2 - y := heightFloat / 2 - x += 0.5*screenX*widthFloat + 0.5 - y -= 0.5*screenY*heightFloat + 0.5 - return x, y + wf := float32(width) + hf := float32(height) + + return wf/2 + 0.5*x*wf + 0.5, hf/2 - 0.5*y*hf + 0.5 } func getOffsets() Offset { - var offsets Offset - - // Open the file - offsetsJson, err := os.Open("offsets.json") + data, err := os.ReadFile("offsets.json") if err != nil { - fmt.Println("Error opening offsets.json", err) - return offsets + logAndSleep("Cannot read offsets.json", err) + return Offset{} } - defer offsetsJson.Close() + var o Offset + json.Unmarshal(data, &o) + return o +} - // Decode the JSON - err = json.NewDecoder(offsetsJson).Decode(&offsets) - if err != nil { - fmt.Println("Error decoding JSON:", err) - return offsets - } - return offsets +func read(h windows.Handle, addr uintptr, v any) error { + _, err := windows.ReadProcessMemory(h, addr, (*byte)(unsafe.Pointer(&v)), unsafe.Sizeof(v), nil) + return err } -func getEntitiesInfo(procHandle windows.Handle, clientDll uintptr, screenWidth uintptr, screenHeight uintptr, offsets Offset) []Entity { - var entityList uintptr +// === Entity Reading === +func getEntitiesInfo(ph windows.Handle, base, sw, sh uintptr, off Offset) []Entity { var entities []Entity - err := read(procHandle, clientDll+offsets.DwEntityList, &entityList) - if err != nil { - return entities - } - var ( - localPlayerP uintptr - localPlayerGameScene uintptr - localPlayerSceneOrigin Vector3 - localTeam int32 - listEntry uintptr - gameScene uintptr - entityController uintptr - entityControllerPawn uintptr - entityPawn uintptr - entityNameAddress uintptr - entityBoneArray uintptr - entityTeam int32 - entityHealth int32 - entityLifeState int32 - entityName string - sanitizedNameStr string - entityOrigin Vector3 - viewMatrix Matrix - ) + var list uintptr + if read(ph, base+off.DwEntityList, &list) != nil { return entities } + + var localP, localScene, localOrigin Vector3 + var localTeam int32 + var viewMatrix Matrix + + read(ph, base+off.DwLocalPlayerPawn, &localP) + read(ph, localP+off.M_pGameSceneNode, &localScene) + read(ph, localScene+off.M_nodeToWorld, &localOrigin) + read(ph, base+off.DwViewMatrix, &viewMatrix) + bones := map[string]int{ - "head": 6, - "neck_0": 5, - "spine_1": 4, - "spine_2": 2, - "pelvis": 0, - "arm_upper_L": 8, - "arm_lower_L": 9, - "hand_L": 10, - "arm_upper_R": 13, - "arm_lower_R": 14, - "hand_R": 15, - "leg_upper_L": 22, - "leg_lower_L": 23, - "ankle_L": 24, - "leg_upper_R": 25, - "leg_lower_R": 26, - "ankle_R": 27, - } - var ( - currentBone Vector3 - entityHead Vector3 - entityHeadTop Vector3 - entityHeadBottom Vector3 - ) - // localPlayerP - err = read(procHandle, clientDll+offsets.DwLocalPlayerPawn, &localPlayerP) - if err != nil { - return entities - } - // localPlayerGameScene - err = read(procHandle, localPlayerP+offsets.M_pGameSceneNode, &localPlayerGameScene) - if err != nil { - return entities - } - // localPlayerSceneOrigin - err = read(procHandle, localPlayerGameScene+offsets.M_nodeToWorld, &localPlayerSceneOrigin) - if err != nil { - return entities - } - // viewMatrix - err = read(procHandle, clientDll+offsets.DwViewMatrix, &viewMatrix) - if err != nil { - return entities + "head": 6, "neck_0": 5, "spine_1": 4, "spine_2": 2, "pelvis": 0, + "arm_upper_L": 8, "arm_lower_L": 9, "hand_L": 10, + "arm_upper_R": 13, "arm_lower_R": 14, "hand_R": 15, + "leg_upper_L": 22, "leg_lower_L": 23, "ankle_L": 24, + "leg_upper_R": 25, "leg_lower_R": 26, "ankle_R": 27, } + for i := 0; i < 64; i++ { - var tempEntity Entity - var entityBones map[string]Vector2 = make(map[string]Vector2) - var sanitizedName strings.Builder - // listEntry - err = read(procHandle, entityList+uintptr((8*(i&0x7FFF)>>9)+16), &listEntry) - if err != nil { - return entities - } - if listEntry == 0 { - continue - } - // entityController - err = read(procHandle, listEntry+uintptr(112)*uintptr(i&0x1FF), &entityController) - if err != nil { - return entities - } - if entityController == 0 { - continue - } - // entityControllerPawn - err = read(procHandle, entityController+offsets.M_hPlayerPawn, &entityControllerPawn) - if err != nil { - return entities - } - if entityControllerPawn == 0 { - continue - } - // listEntry - err = read(procHandle, entityList+uintptr(0x8*((entityControllerPawn&0x7FFF)>>9)+16), &listEntry) - if err != nil { - return entities - } - if listEntry == 0 { - continue - } - // entityPawn - err = read(procHandle, listEntry+uintptr(112)*uintptr(entityControllerPawn&0x1FF), &entityPawn) - if err != nil { - return entities - } - if entityPawn == 0 { - continue - } - if entityPawn == localPlayerP { - continue - } - // entityLifeState - err = read(procHandle, entityPawn+offsets.M_lifeState, &entityLifeState) - if err != nil { - return entities - } - if entityLifeState != 256 { - continue - } - // entityTeam - err = read(procHandle, entityPawn+offsets.M_iTeamNum, &entityTeam) - if err != nil { - return entities - } - if entityTeam == 0 { - continue - } + var e Entity + boneMap := make(map[string]Vector2) + var listEntry, controller, pawnCtrl, pawn, scene, boneArray uintptr + var team, hp, life int32 + var origin, head, bone Vector3 + var nameAddr uintptr + var name string + var sb strings.Builder + + read(ph, list+uintptr((8*(i&0x7FFF)>>9)+16), &listEntry) + if listEntry == 0 { continue } + read(ph, listEntry+uintptr(112)*(i&0x1FF), &controller) + if controller == 0 { continue } + read(ph, controller+off.M_hPlayerPawn, &pawnCtrl) + if pawnCtrl == 0 { continue } + + read(ph, list+uintptr(0x8*((pawnCtrl&0x7FFF)>>9)+16), &listEntry) + if listEntry == 0 { continue } + read(ph, listEntry+uintptr(112)*(pawnCtrl&0x1FF), &pawn) + if pawn == 0 || pawn == localP { continue } + + read(ph, pawn+off.M_lifeState, &life) + if life != 256 { continue } + + read(ph, pawn+off.M_iTeamNum, &team) + if team == 0 { continue } if teamCheck { - // localTeam - err = read(procHandle, localPlayerP+offsets.M_iTeamNum, &localTeam) - if err != nil { - return entities - } - if localTeam == entityTeam { - continue - } - } - // entityHealth - err = read(procHandle, entityPawn+offsets.M_iHealth, &entityHealth) - if err != nil { - return entities - } - if entityHealth < 1 || entityHealth > 100 { - continue + read(ph, localP+off.M_iTeamNum, &localTeam) + if localTeam == team { continue } } - // entityNameAddress - err = read(procHandle, entityController+offsets.M_sSanitizedPlayerName, &entityNameAddress) - if err != nil { - return entities - } - // entityName - err = read(procHandle, entityNameAddress, &entityName) - if err != nil { - return entities - } - if entityName == "" { - continue - } - for _, c := range entityName { - if unicode.IsLetter(c) || unicode.IsDigit(c) || unicode.IsPunct(c) || unicode.IsSpace(c) { - sanitizedName.WriteRune(c) + + read(ph, pawn+off.M_iHealth, &hp) + if hp < 1 || hp > 100 { continue } + + read(ph, controller+off.M_sSanitizedPlayerName, &nameAddr) + read(ph, nameAddr, &name) + for _, r := range name { + if unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsPunct(r) || unicode.IsSpace(r) { + sb.WriteRune(r) } } - sanitizedNameStr = sanitizedName.String() - // gameScene - err = read(procHandle, entityPawn+offsets.M_pGameSceneNode, &gameScene) - if err != nil { - return entities - } - if gameScene == 0 { - continue - } - // entityBoneArray - err = read(procHandle, gameScene+offsets.M_modelState+offsets.M_boneArray, &entityBoneArray) - if err != nil { - return entities - } - if entityBoneArray == 0 { - continue - } - // entityOrigin - err = read(procHandle, entityPawn+offsets.M_vOldOrigin, &entityOrigin) - if err != nil { - return entities - } - // boneArray - for boneName, boneIndex := range bones { - err = read(procHandle, entityBoneArray+uintptr(boneIndex)*32, ¤tBone) - if err != nil { - return entities - } - if boneName == "head" { - entityHead = currentBone - if !skeletonRendering { - break - } - } - boneX, boneY := worldToScreen(viewMatrix, currentBone) - entityBones[boneName] = Vector2{boneX, boneY} + + read(ph, pawn+off.M_pGameSceneNode, &scene) + if scene == 0 { continue } + read(ph, scene+off.M_modelState+off.M_boneArray, &boneArray) + if boneArray == 0 { continue } + read(ph, pawn+off.M_vOldOrigin, &origin) + + for name, idx := range bones { + read(ph, boneArray+uintptr(idx)*32, &bone) + x, y := worldToScreen(viewMatrix, bone) + boneMap[name] = Vector2{x, y} + if name == "head" { head = bone } } - entityHeadTop = Vector3{entityHead.X, entityHead.Y, entityHead.Z + 7} - entityHeadBottom = Vector3{entityHead.X, entityHead.Y, entityHead.Z - 5} - screenPosHeadX, screenPosHeadTopY := worldToScreen(viewMatrix, entityHeadTop) - _, screenPosHeadBottomY := worldToScreen(viewMatrix, entityHeadBottom) - screenPosFeetX, screenPosFeetY := worldToScreen(viewMatrix, entityOrigin) - entityBoxTop := Vector3{entityOrigin.X, entityOrigin.Y, entityOrigin.Z + 70} - _, screenPosBoxTop := worldToScreen(viewMatrix, entityBoxTop) - if screenPosHeadX <= -1 || screenPosFeetY <= -1 || screenPosHeadX >= float32(screenWidth) || screenPosHeadTopY >= float32(screenHeight) { - continue + + headTop := Vector3{head.X, head.Y, head.Z + 7} + headBot := Vector3{head.X, head.Y, head.Z - 5} + hx, hty := worldToScreen(viewMatrix, headTop) + _, hby := worldToScreen(viewMatrix, headBot) + fx, fy := worldToScreen(viewMatrix, origin) + boxTop := Vector3{origin.X, origin.Y, origin.Z + 70} + _, bty := worldToScreen(viewMatrix, boxTop) + + if hx <= -1 || fy <= -1 || hx >= float32(sw) || hty >= float32(sh) { continue } + + height := fy - bty + e = Entity{ + Health: hp, + Team: team, + Name: sb.String(), + Distance: origin.Dist(localOrigin), + Position: Vector2{fx, fy}, + Bones: boneMap, + HeadPos: Vector3{hx, hty, hby}, + Rect: Rectangle{bty, fx - height/4, fx + height/4, fy}, } - boxHeight := screenPosFeetY - screenPosBoxTop - - tempEntity.Health = entityHealth - tempEntity.Team = entityTeam - tempEntity.Name = sanitizedNameStr - tempEntity.Distance = entityOrigin.Dist(localPlayerSceneOrigin) - tempEntity.Position = Vector2{screenPosFeetX, screenPosFeetY} - tempEntity.Bones = entityBones - tempEntity.HeadPos = Vector3{screenPosHeadX, screenPosHeadTopY, screenPosHeadBottomY} - tempEntity.Rect = Rectangle{screenPosBoxTop, screenPosFeetX - boxHeight/4, screenPosFeetX + boxHeight/4, screenPosFeetY} - - entities = append(entities, tempEntity) + entities = append(entities, e) } return entities } +// === Drawing === func drawSkeleton(hdc win.HDC, pen uintptr, bones map[string]Vector2) { win.SelectObject(hdc, win.HGDIOBJ(pen)) - win.MoveToEx(hdc, int(bones["head"].X), int(bones["head"].Y), nil) - win.LineTo(hdc, int32(bones["neck_0"].X), int32(bones["neck_0"].Y)) - win.LineTo(hdc, int32(bones["spine_1"].X), int32(bones["spine_1"].Y)) - win.LineTo(hdc, int32(bones["spine_2"].X), int32(bones["spine_2"].Y)) - win.LineTo(hdc, int32(bones["pelvis"].X), int32(bones["pelvis"].Y)) - win.LineTo(hdc, int32(bones["leg_upper_L"].X), int32(bones["leg_upper_L"].Y)) - win.LineTo(hdc, int32(bones["leg_lower_L"].X), int32(bones["leg_lower_L"].Y)) - win.LineTo(hdc, int32(bones["ankle_L"].X), int32(bones["ankle_L"].Y)) - win.MoveToEx(hdc, int(bones["pelvis"].X), int(bones["pelvis"].Y), nil) - win.LineTo(hdc, int32(bones["leg_upper_R"].X), int32(bones["leg_upper_R"].Y)) - win.LineTo(hdc, int32(bones["leg_lower_R"].X), int32(bones["leg_lower_R"].Y)) - win.LineTo(hdc, int32(bones["ankle_R"].X), int32(bones["ankle_R"].Y)) - win.MoveToEx(hdc, int(bones["spine_1"].X), int(bones["spine_1"].Y), nil) - win.LineTo(hdc, int32(bones["arm_upper_L"].X), int32(bones["arm_upper_L"].Y)) - win.LineTo(hdc, int32(bones["arm_lower_L"].X), int32(bones["arm_lower_L"].Y)) - win.LineTo(hdc, int32(bones["hand_L"].X), int32(bones["hand_L"].Y)) - win.MoveToEx(hdc, int(bones["spine_1"].X), int(bones["spine_1"].Y), nil) - win.LineTo(hdc, int32(bones["arm_upper_R"].X), int32(bones["arm_upper_R"].Y)) - win.LineTo(hdc, int32(bones["arm_lower_R"].X), int32(bones["arm_lower_R"].Y)) - win.LineTo(hdc, int32(bones["hand_R"].X), int32(bones["hand_R"].Y)) + lines := [][2]string{ + {"head", "neck_0"}, {"neck_0", "spine_1"}, {"spine_1", "spine_2"}, {"spine_2", "pelvis"}, + {"pelvis", "leg_upper_L"}, {"leg_upper_L", "leg_lower_L"}, {"leg_lower_L", "ankle_L"}, + {"pelvis", "leg_upper_R"}, {"leg_upper_R", "leg_lower_R"}, {"leg_lower_R", "ankle_R"}, + {"spine_1", "arm_upper_L"}, {"arm_upper_L", "arm_lower_L"}, {"arm_lower_L", "hand_L"}, + {"spine_1", "arm_upper_R"}, {"arm_upper_R", "arm_lower_R"}, {"arm_lower_R", "hand_R"}, + } + for _, l := range lines { + p1 := bones[l[0]] + p2 := bones[l[1]] + win.MoveToEx(hdc, int(p1.X), int(p1.Y), nil) + win.LineTo(hdc, int32(p2.X), int32(p2.Y)) + } } -func renderEntityInfo(hdc win.HDC, tPen uintptr, gPen uintptr, oPen uintptr, hPen uintptr, rect Rectangle, hp int32, name string, headPos Vector3) { +func renderEntityInfo(hdc win.HDC, tPen, gPen, oPen, hPen uintptr, r Rectangle, hp int32, name string, head Vector3) { if boxRendering { - // Box win.SelectObject(hdc, win.HGDIOBJ(tPen)) - win.MoveToEx(hdc, int(rect.Left), int(rect.Top), nil) - win.LineTo(hdc, int32(rect.Right), int32(rect.Top)) - win.LineTo(hdc, int32(rect.Right), int32(rect.Bottom)) - win.LineTo(hdc, int32(rect.Left), int32(rect.Bottom)) - win.LineTo(hdc, int32(rect.Left), int32(rect.Top)) - - // Box outline + win.Rectangle(hdc, int32(r.Left), int32(r.Top), int32(r.Right), int32(r.Bottom)) win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.MoveToEx(hdc, int(rect.Left)-1, int(rect.Top)-1, nil) - win.LineTo(hdc, int32(rect.Right)-1, int32(rect.Top)+1) - win.LineTo(hdc, int32(rect.Right)+1, int32(rect.Bottom)+1) - win.LineTo(hdc, int32(rect.Left)+1, int32(rect.Bottom)-1) - win.LineTo(hdc, int32(rect.Left)-1, int32(rect.Top)-1) - win.MoveToEx(hdc, int(rect.Left)+1, int(rect.Top)+1, nil) - win.LineTo(hdc, int32(rect.Right)+1, int32(rect.Top)-1) - win.LineTo(hdc, int32(rect.Right)-1, int32(rect.Bottom)-1) - win.LineTo(hdc, int32(rect.Left)-1, int32(rect.Bottom)+1) - win.LineTo(hdc, int32(rect.Left)+1, int32(rect.Top)+1) + win.Rectangle(hdc, int32(r.Left)-1, int32(r.Top)-1, int32(r.Right)+1, int32(r.Bottom)+1) } if headCircle { - // Head with outline - radius := int32((int32(headPos.Z) - int32(headPos.Y)) / 2) + rad := int32((int32(head.Z) - int32(head.Y)) / 2) win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.Ellipse(hdc, int32(headPos.X)-radius-1, int32(headPos.Y)-1, int32(headPos.X)+radius+1, int32(headPos.Z)+1) + win.Ellipse(hdc, int32(head.X)-rad-1, int32(head.Y)-1, int32(head.X)+rad+1, int32(head.Z)+1) win.SelectObject(hdc, win.HGDIOBJ(hPen)) - win.Ellipse(hdc, int32(headPos.X)-radius, int32(headPos.Y), int32(headPos.X)+radius, int32(headPos.Z)) - win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.Ellipse(hdc, int32(headPos.X)-radius+1, int32(headPos.Y)+1, int32(headPos.X)+radius-1, int32(headPos.Z)-1) + win.Ellipse(hdc, int32(head.X)-rad, int32(head.Y), int32(head.X)+rad, int32(head.Z)) } if healthBarRendering { - // Health bar + y := int(r.Bottom + 1 - float64(int(r.Bottom+1-int(r.Top))*float64(hp)/100.0)) win.SelectObject(hdc, win.HGDIOBJ(gPen)) - win.MoveToEx(hdc, int(rect.Left)-4, int(rect.Bottom)+1-int(float64(int(rect.Bottom)+1-int(rect.Top))*float64(hp)/100.0), nil) - win.LineTo(hdc, int32(rect.Left)-4, int32(rect.Bottom)+1) - - // Health bar outline + win.MoveToEx(hdc, int(r.Left)-4, y, nil) + win.LineTo(hdc, int32(r.Left)-4, int32(r.Bottom)+1) win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.MoveToEx(hdc, int(rect.Left)-5, int(rect.Top)-1, nil) - win.LineTo(hdc, int32(rect.Left)-5, int32(rect.Bottom)+1) - win.LineTo(hdc, int32(rect.Left)-3, int32(rect.Bottom)+1) - win.LineTo(hdc, int32(rect.Left)-3, int32(rect.Top)-1) - win.LineTo(hdc, int32(rect.Left)-5, int32(rect.Top)-1) + win.Rectangle(hdc, int32(r.Left)-5, int32(r.Top)-1, int32(r.Left)-3, int32(r.Bottom)+1) } if healthTextRendering { - // Health text text, _ := windows.UTF16PtrFromString(fmt.Sprintf("%d", hp)) - win.SetTextColor(hdc, win.RGB(byte(0), byte(255), byte(50))) - // Set text right alignment + win.SetTextColor(hdc, win.RGB(0, 255, 50)) setTextAlign.Call(uintptr(hdc), 0x00000002) - if healthBarRendering { - win.TextOut(hdc, int32(rect.Left)-8, int32(int(rect.Bottom)+1-int(float64(int(rect.Bottom)+1-int(rect.Top))*float64(hp)/100.0)), text, int32(len(fmt.Sprintf("%d", hp)))) - } else { - win.TextOut(hdc, int32(rect.Left)-4, int32(rect.Top), text, int32(len(fmt.Sprintf("%d", hp)))) - } + y := int(r.Bottom + 1 - float64(int(r.Bottom+1-int(r.Top))*float64(hp)/100.0)) + if !healthBarRendering { y = int(r.Top) } + win.TextOut(hdc, int32(r.Left)-8, int32(y), text, int32(len(fmt.Sprintf("%d", hp)))) } if nameRendering { - // Name text, _ := windows.UTF16PtrFromString(name) - win.SetTextColor(hdc, win.RGB(byte(255), byte(255), byte(255))) - setTextAlign.Call(uintptr(hdc), 0x00000006) // Set text alignment to center - win.TextOut(hdc, int32(rect.Left)+int32((int32(rect.Right)-int32(rect.Left))/2), int32(rect.Top)-14, text, int32(len(name))) + win.SetTextColor(hdc, win.RGB(255, 255, 255)) + setTextAlign.Call(uintptr(hdc), 0x00000006) + win.TextOut(hdc, int32(r.Left)+int32((int32(r.Right)-int32(r.Left))/2), int32(r.Top)-14, text, int32(len(name))) } } -func windowProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { - switch msg { - case win.WM_TIMER: - return 0 - case win.WM_DESTROY: +// === Window & Menu === +func windowProc(hwnd win.HWND, msg uint32, w, l uintptr) uintptr { + if msg == win.WM_DESTROY { win.PostQuitMessage(0) return 0 - default: - return win.DefWindowProc(hwnd, msg, wParam, lParam) } + return win.DefWindowProc(hwnd, msg, w, l) } -func initWindow(screenWidth uintptr, screenHeight uintptr) win.HWND { +func initWindow(w, h uintptr) win.HWND { + class, _ := windows.UTF16PtrFromString("cs2go") + title, _ := windows.UTF16PtrFromString("cs2go") - className, err := windows.UTF16PtrFromString("cs2goWindow") - if err != nil { - logAndSleep("Error creating window class name", err) - return 0 - } - windowTitle, err := windows.UTF16PtrFromString("cs2go") - if err != nil { - logAndSleep("Error creating window title", err) - return 0 - } - - // Register window class wc := win.WNDCLASSEX{ CbSize: uint32(unsafe.Sizeof(win.WNDCLASSEX{})), Style: win.CS_HREDRAW | win.CS_VREDRAW, LpfnWndProc: syscall.NewCallback(windowProc), - CbWndExtra: 0, HInstance: win.GetModuleHandle(nil), - HIcon: win.LoadIcon(0, (*uint16)(unsafe.Pointer(uintptr(win.IDI_APPLICATION)))), HCursor: win.LoadCursor(0, (*uint16)(unsafe.Pointer(uintptr(win.IDC_ARROW)))), HbrBackground: win.COLOR_WINDOW, - LpszMenuName: nil, - LpszClassName: className, - HIconSm: win.LoadIcon(0, (*uint16)(unsafe.Pointer(uintptr(win.IDI_APPLICATION)))), + LpszClassName: class, } + win.RegisterClassEx(&wc) - if atom := win.RegisterClassEx(&wc); atom == 0 { - logAndSleep("Error registering window class", fmt.Errorf("%v", win.GetLastError())) - return 0 - } - - // Create window - hInstance := win.GetModuleHandle(nil) hwnd := win.CreateWindowEx( - win.WS_EX_TOPMOST|win.WS_EX_NOACTIVATE|win.WS_EX_LAYERED, - className, - windowTitle, - win.WS_POPUP, - 0, - 0, - int32(screenWidth), - int32(screenHeight), - 0, - 0, - hInstance, - nil, + win.WS_EX_TOPMOST|win.WS_EX_NOACTIVATE|win.WS_EX_LAYERED|win.WS_EX_TRANSPARENT, + class, title, win.WS_POPUP, + 0, 0, int32(w), int32(h), + 0, 0, win.GetModuleHandle(nil), nil, ) - if hwnd == 0 { - logAndSleep("Error creating window", fmt.Errorf("%v", win.GetLastError())) - return 0 - } - - result, _, _ := setLayeredWindowAttributes.Call(uintptr(hwnd), 0x000000, 0, 0x00000001) - if result == 0 { - logAndSleep("Error setting layered window attributes", fmt.Errorf("%v", win.GetLastError())) - } - // Get the current extended window style - style := win.GetWindowLongPtr(hwnd, win.GWL_EXSTYLE) - - // Add the WS_EX_TRANSPARENT style - style |= win.WS_EX_TRANSPARENT - - // Set the new extended window style - win.SetWindowLongPtr(hwnd, win.GWL_EXSTYLE, style) - + setLayeredWindowAttributes.Call(uintptr(hwnd), 0, 0, 0x00000001) showCursor.Call(0) - - // Show window - win.ShowWindow(hwnd, win.SW_SHOWDEFAULT) + win.ShowWindow(hwnd, win.SW_SHOW) return hwnd } func cliMenu() { for { - fmt.Print(chalk.Magenta.Color(" ____ \n ___ ___|___ \\ ____ ___ \n / __/ __| __) / _ |/ _ \\ \n| (__\\__ \\/ __/ (_| | (_) |\n \\___|___/_____\\__, |\\___/ \n |___/ \n")) - fmt.Println(chalk.Dim.TextStyle("\t\tby bqj - v1.6\n")) - if teamCheck { - fmt.Println(chalk.Green.Color("[1] Team check [ON]")) - } else { - fmt.Println(chalk.Red.Color("[1] Team check [OFF]")) - } - if headCircle { - fmt.Println(chalk.Green.Color("[2] Head circle [ON]")) - } else { - fmt.Println(chalk.Red.Color("[2] Head circle [OFF]")) - } - if skeletonRendering { - fmt.Println(chalk.Green.Color("[3] Skeleton rendering [ON]")) - } else { - fmt.Println(chalk.Red.Color("[3] Skeleton rendering [OFF]")) - } - if boxRendering { - fmt.Println(chalk.Green.Color("[4] Box rendering [ON]")) - } else { - fmt.Println(chalk.Red.Color("[4] Box rendering [OFF]")) - } - if healthBarRendering { - fmt.Println(chalk.Green.Color("[5] Health bar rendering [ON]")) - } else { - fmt.Println(chalk.Red.Color("[5] Health bar rendering [OFF]")) - } - if healthTextRendering { - fmt.Println(chalk.Green.Color("[6] Health text rendering [ON]")) - } else { - fmt.Println(chalk.Red.Color("[6] Health text rendering [OFF]")) - } - if nameRendering { - fmt.Println(chalk.Green.Color("[7] Name rendering [ON]")) - } else { - fmt.Println(chalk.Red.Color("[7] Name rendering [OFF]")) - } - fmt.Println(chalk.Cyan.Color("[8] Adjust frame delay [") + fmt.Sprint(frameDelay) + chalk.Cyan.Color("]")) + fmt.Print("\033[H\033[2J") + fmt.Println(chalk.Magenta.Color(" ____ _____ ___ ___ ")) + fmt.Println(chalk.Magenta.Color(" / ___||___ / / _ \\/ _ \\ ")) + fmt.Println(chalk.Magenta.Color(" | | _ |_ \\| | | | | | |")) + fmt.Println(chalk.Magenta.Color(" | |_| |___) | |_| | |_| |")) + fmt.Println(chalk.Magenta.Color(" \\____|____/ \\___/ \\___/ \n")) + fmt.Println(chalk.Dim.TextStyle("\t\tby bqj - v1.7 (Go + FPS Lock)\n")) + + s := func(b bool, on, off string) string { + if b { return chalk.Green.Color(on) } else { return chalk.Red.Color(off) } + } + fmt.Println(s(teamCheck, "[1] Team check [ON]", "[1] Team check [OFF]")) + fmt.Println(s(headCircle, "[2] Head circle [ON]", "[2] Head circle [OFF]")) + fmt.Println(s(skeletonRendering, "[3] Skeleton [ON]", "[3] Skeleton [OFF]")) + fmt.Println(s(boxRendering, "[4] Box [ON]", "[4] Box [OFF]")) + fmt.Println(s(healthBarRendering, "[5] Health bar [ON]", "[5] Health bar [OFF]")) + fmt.Println(s(healthTextRendering, "[6] Health text [ON]", "[6] Health text [OFF]")) + fmt.Println(s(nameRendering, "[7] Name [ON]", "[7] Name [OFF]")) + fmt.Printf("%s[%d FPS → %dms]\n", chalk.Cyan.Color("[8] FPS: "), desiredFrameRate, frameDelay) fmt.Println(chalk.Red.Color("[9] Exit")) - fmt.Print(chalk.Cyan.Color("[Enter selection]: ")) - var input string - fmt.Scanln(&input) - switch input { - case "1": - teamCheck = !teamCheck - case "2": - headCircle = !headCircle - case "3": - skeletonRendering = !skeletonRendering - case "4": - boxRendering = !boxRendering - case "5": - healthBarRendering = !healthBarRendering - case "6": - healthTextRendering = !healthTextRendering - case "7": - nameRendering = !nameRendering + fmt.Print(chalk.Cyan.Color("Select: ")) + + var in string + fmt.Scanln(&in) + switch in { + case "1": teamCheck = !teamCheck + case "2": headCircle = !headCircle + case "3": skeletonRendering = !skeletonRendering + case "4": boxRendering = !boxRendering + case "5": healthBarRendering = !healthBarRendering + case "6": healthTextRendering = !healthTextRendering + case "7": nameRendering = !nameRendering case "8": - fmt.Println(chalk.Red.Color("Higer frame delay = lower performance impact but higher ESP latency")) - fmt.Print(chalk.Cyan.Color("[Enter frame delay]: ")) - var delay uint32 - fmt.Scanln(&delay) - frameDelay = delay - case "9": - os.Exit(0) - default: - fmt.Println(chalk.Red.Color("Invalid selection")) - time.Sleep(1 * time.Second) + fmt.Print(chalk.Cyan.Color("Enter FPS (30-240): ")) + var fps int + fmt.Scanln(&fps) + if fps >= 30 && fps <= 240 { + desiredFrameRate = fps + frameDelay = uint32(1000 / desiredFrameRate) + if frameDelay < 1 { frameDelay = 1 } + } + case "9": os.Exit(0) } - // Clear the console - fmt.Print("\033[H\033[2J") } } -func main() { - go cliMenu() +// === Process Utils === +func findProcessId(name string) (uint32, error) { + snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) + if err != nil { return 0, err } + defer windows.CloseHandle(snap) - screenWidth, _, _ := getSystemMetrics.Call(0) - screenHeight, _, _ := getSystemMetrics.Call(1) + var pe windows.ProcessEntry32 + pe.Size = uint32(unsafe.Sizeof(pe)) + if windows.Process32First(snap, &pe) != nil { return 0, fmt.Errorf("no process") } - hwnd := initWindow(screenWidth, screenHeight) - if hwnd == 0 { - logAndSleep("Error creating window", fmt.Errorf("%v", win.GetLastError())) - return + for { + if strings.EqualFold(windows.UTF16PtrToString(&pe.SzExeFile[0]), name) { + return pe.ProcessID, nil + } + if windows.Process32Next(snap, &pe) != nil { break } } - defer win.DestroyWindow(hwnd) + return 0, fmt.Errorf("not found") +} - // win.SetCursor() +func getModuleBase(pid uint32, mod string) (uintptr, error) { + snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE, pid) + if err != nil { return 0, err } + defer windows.CloseHandle(snap) - pid, err := findProcessId("cs2.exe") - if err != nil { - logAndSleep("Error finding process ID", err) - return - } + var me windows.ModuleEntry32 + me.Size = uint32(unsafe.Sizeof(me)) + if windows.Module32First(snap, &me) != nil { return 0, fmt.Errorf("no module") } - clientDll, err := getModuleBaseAddress(pid, "client.dll") - if err != nil { - logAndSleep("Error getting client.dll base address", err) - return + for { + if strings.EqualFold(windows.UTF16PtrToString(&me.SzModule[0]), mod) { + return uintptr(me.ModBaseAddr), nil + } + if windows.Module32Next(snap, &me) != nil { break } } + return 0, fmt.Errorf("not found") +} - procHandle, err := getProcessHandle(pid) - if err != nil { - logAndSleep("Error getting process handle", err) - return - } +func getProcessHandle(pid uint32) (windows.Handle, error) { + return windows.OpenProcess(windows.PROCESS_VM_READ, false, pid) +} - hdc := win.GetDC(hwnd) - if hdc == 0 { - logAndSleep("Error getting device context", fmt.Errorf("%v", win.GetLastError())) - return - } +// === MAIN === +func main() { + go cliMenu() - bgBrush, _, _ := createSolidBrush.Call(uintptr(0x000000)) - if bgBrush == 0 { - logAndSleep("Error creating brush", fmt.Errorf("%v", win.GetLastError())) - return - } - defer win.DeleteObject(win.HGDIOBJ(bgBrush)) - redPen, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7a78ff) - if redPen == 0 { - logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) - return - } - defer win.DeleteObject(win.HGDIOBJ(redPen)) - greenPen, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7dff78) - if greenPen == 0 { - logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) - return - } - defer win.DeleteObject(win.HGDIOBJ(greenPen)) - bluePen, _, _ := createPen.Call(win.PS_SOLID, 1, 0xff8e78) - if bluePen == 0 { - logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) - return - } - defer win.DeleteObject(win.HGDIOBJ(bluePen)) - bonePen, _, _ := createPen.Call(win.PS_SOLID, 1, 0xffffff) - if bonePen == 0 { - logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) - return - } - defer win.DeleteObject(win.HGDIOBJ(bonePen)) - outlinePen, _, _ := createPen.Call(win.PS_SOLID, 1, 0x000001) - if outlinePen == 0 { - logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) - return - } - defer win.DeleteObject(win.HGDIOBJ(outlinePen)) + sw, _, _ := getSystemMetrics.Call(0) + sh, _, _ := getSystemMetrics.Call(1) + hwnd := initWindow(sw, sh) + if hwnd == 0 { log.Fatal("Window failed") } - font, _, _ := createFont.Call(12, 0, 0, 0, win.FW_HEAVY, 0, 0, 0, win.DEFAULT_CHARSET, win.OUT_DEFAULT_PRECIS, win.CLIP_DEFAULT_PRECIS, win.DEFAULT_QUALITY, win.DEFAULT_PITCH|win.FF_DONTCARE, 0) + pid, err := findProcessId("cs2.exe") + if err != nil { logAndSleep("CS2 not found", err); return } + base, err := getModuleBase(pid, "client.dll") + if err != nil { logAndSleep("client.dll not found", err); return } + ph, err := getProcessHandle(pid) + if err != nil { logAndSleep("OpenProcess failed", err); return } + defer windows.CloseHandle(ph) + + hdc := win.GetDC(hwnd) + bg, _, _ := createSolidBrush.Call(0x000000) + red, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7a78ff) + green, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7dff78) + blue, _, _ := createPen.Call(win.PS_SOLID, 1, 0xff8e78) + bone, _, _ := createPen.Call(win.PS_SOLID, 1, 0xffffff) + outline, _, _ := createPen.Call(win.PS_SOLID, 1, 0x000001) + font, _, _ := createFont.Call(12, 0, 0, 0, win.FW_HEAVY, 0, 0, 0, win.DEFAULT_CHARSET, 0, 0, 0, 0, 0) - offsets := getOffsets() + off := getOffsets() var msg win.MSG - for win.GetMessage(&msg, 0, 0, 0) > 0 { win.TranslateMessage(&msg) win.DispatchMessage(&msg) - win.SetTimer(hwnd, 1, frameDelay, 0) + // === FPS CONTROL (từ C++) === + currentTime := time.Now() + deltaTime := currentTime.Sub(lastFrameTime).Milliseconds() - memhdc, _, _ := createCompatibleDC.Call(uintptr(hdc)) - memBitmap := win.CreateCompatibleBitmap(hdc, int32(screenWidth), int32(screenHeight)) - win.SelectObject(win.HDC(memhdc), win.HGDIOBJ(memBitmap)) - win.SelectObject(win.HDC(memhdc), win.HGDIOBJ(bgBrush)) - win.SetBkMode(win.HDC(memhdc), win.TRANSPARENT) - win.SelectObject(win.HDC(memhdc), win.HGDIOBJ(font)) + if deltaTime < int64(frameDelay) { + sleepTime := int64(frameDelay) - deltaTime + time.Sleep(time.Duration(sleepTime) * time.Millisecond) + } + lastFrameTime = currentTime + // === END FPS CONTROL === - entities := getEntitiesInfo(procHandle, clientDll, screenWidth, screenHeight, offsets) - for _, entity := range entities { - if entity.Distance < 35 { - continue - } + memDC, _, _ := createCompatibleDC.Call(uintptr(hdc)) + bitmap := win.CreateCompatibleBitmap(hdc, int32(sw), int32(sh)) + win.SelectObject(win.HDC(memDC), win.HGDIOBJ(bitmap)) + win.SelectObject(win.HDC(memDC), win.HGDIOBJ(bg)) + win.SetBkMode(win.HDC(memDC), win.TRANSPARENT) + win.SelectObject(win.HDC(memDC), win.HGDIOBJ(font)) + + entities := getEntitiesInfo(ph, base, sw, sh, off) + for _, e := range entities { + if e.Distance < 35 { continue } if skeletonRendering { - drawSkeleton(win.HDC(memhdc), bonePen, entity.Bones) - } - if entity.Team == 2 { - renderEntityInfo(win.HDC(memhdc), redPen, greenPen, outlinePen, bonePen, entity.Rect, entity.Health, entity.Name, entity.HeadPos) - } else { - renderEntityInfo(win.HDC(memhdc), bluePen, greenPen, outlinePen, bonePen, entity.Rect, entity.Health, entity.Name, entity.HeadPos) + drawSkeleton(win.HDC(memDC), bone, e.Bones) } + teamPen := red + if e.Team != 2 { teamPen = blue } + renderEntityInfo(win.HDC(memDC), teamPen, green, outline, bone, e.Rect, e.Health, e.Name, e.HeadPos) } - win.BitBlt(hdc, 0, 0, int32(screenWidth), int32(screenHeight), win.HDC(memhdc), 0, 0, win.SRCCOPY) - // Delete the memory bitmap and device context - win.DeleteObject(win.HGDIOBJ(memBitmap)) - win.DeleteDC(win.HDC(memhdc)) + win.BitBlt(hdc, 0, 0, int32(sw), int32(sh), win.HDC(memDC), 0, 0, win.SRCCOPY) + win.DeleteObject(win.HGDIOBJ(bitmap)) + win.DeleteDC(win.HDC(memDC)) } } From e80697d8d82e8c54ed6e5c1ef74c71974d965ea6 Mon Sep 17 00:00:00 2001 From: leanhtubtk-jpg Date: Thu, 13 Nov 2025 15:12:48 +0700 Subject: [PATCH 4/4] Update main.go --- main.go | 881 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 573 insertions(+), 308 deletions(-) diff --git a/main.go b/main.go index 2778ac9..3ab9831 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,3 @@ -// main.go package main import ( @@ -20,9 +19,28 @@ import ( ) type Matrix [4][4]float32 -type Vector3 struct{ X, Y, Z float32 } -type Vector2 struct{ X, Y float32 } -type Rectangle struct{ Top, Left, Right, Bottom float32 } + +type Vector3 struct { + X float32 + Y float32 + Z float32 +} + +func (v Vector3) Dist(other Vector3) float32 { + return float32(math.Abs(float64(v.X-other.X)) + math.Abs(float64(v.Y-other.Y)) + math.Abs(float64(v.Z-other.Z))) +} + +type Vector2 struct { + X float32 + Y float32 +} + +type Rectangle struct { + Top float32 + Left float32 + Right float32 + Bottom float32 +} type Entity struct { Health int32 @@ -51,7 +69,6 @@ type Offset struct { M_sSanitizedPlayerName uintptr `json:"m_sSanitizedPlayerName"` } -// === GDI & System DLL === var ( user32 = windows.NewLazySystemDLL("user32.dll") gdi32 = windows.NewLazySystemDLL("gdi32.dll") @@ -65,427 +82,675 @@ var ( createPen = gdi32.NewProc("CreatePen") ) -// === ESP Settings === var ( - teamCheck = true - headCircle = true - skeletonRendering = true - boxRendering = true - nameRendering = true - healthBarRendering = true - healthTextRendering = true - - // FPS Control (từ C++) - desiredFrameRate = 60 - frameDelay uint32 - lastFrameTime time.Time + teamCheck bool = true + headCircle bool = true + skeletonRendering bool = true + boxRendering bool = true + nameRendering bool = true + healthBarRendering bool = true + healthTextRendering bool = true + frameDelay uint32 = 15 ) func init() { + // Ensure main() runs on the main thread. runtime.LockOSThread() - frameDelay = uint32(1000 / desiredFrameRate) - lastFrameTime = time.Now() } -// === Helper Functions === -func (v Vector3) Dist(o Vector3) float32 { - return float32(math.Abs(float64(v.X-o.X)) + math.Abs(float64(v.Y-o.Y)) + math.Abs(float64(v.Z-o.Z))) -} - -func logAndSleep(msg string, err error) { - log.Printf("%s: %v\n", msg, err) +func logAndSleep(message string, err error) { + log.Printf("%s: %v\n", message, err) time.Sleep(5 * time.Second) } -func worldToScreen(m Matrix, pos Vector3) (float32, float32) { - x := m[0][0]*pos.X + m[0][1]*pos.Y + m[0][2]*pos.Z + m[0][3] - y := m[1][0]*pos.X + m[1][1]*pos.Y + m[1][2]*pos.Z + m[1][3] - w := m[3][0]*pos.X + m[3][1]*pos.Y + m[3][2]*pos.Z + m[3][3] +func worldToScreen(viewMatrix Matrix, position Vector3) (float32, float32) { + var screenX float32 + var screenY float32 + screenX = viewMatrix[0][0]*position.X + viewMatrix[0][1]*position.Y + viewMatrix[0][2]*position.Z + viewMatrix[0][3] + screenY = viewMatrix[1][0]*position.X + viewMatrix[1][1]*position.Y + viewMatrix[1][2]*position.Z + viewMatrix[1][3] + w := viewMatrix[3][0]*position.X + viewMatrix[3][1]*position.Y + viewMatrix[3][2]*position.Z + viewMatrix[3][3] if w < 0.01 { return -1, -1 } - inv := 1.0 / w - x *= inv - y *= inv - + invw := 1.0 / w + screenX *= invw + screenY *= invw width, _, _ := getSystemMetrics.Call(0) height, _, _ := getSystemMetrics.Call(1) - wf := float32(width) - hf := float32(height) - - return wf/2 + 0.5*x*wf + 0.5, hf/2 - 0.5*y*hf + 0.5 + widthFloat := float32(width) + heightFloat := float32(height) + x := widthFloat / 2 + y := heightFloat / 2 + x += 0.5*screenX*widthFloat + 0.5 + y -= 0.5*screenY*heightFloat + 0.5 + return x, y } func getOffsets() Offset { - data, err := os.ReadFile("offsets.json") + var offsets Offset + + // Open the file + offsetsJson, err := os.Open("offsets.json") if err != nil { - logAndSleep("Cannot read offsets.json", err) - return Offset{} + fmt.Println("Error opening offsets.json", err) + return offsets } - var o Offset - json.Unmarshal(data, &o) - return o -} + defer offsetsJson.Close() -func read(h windows.Handle, addr uintptr, v any) error { - _, err := windows.ReadProcessMemory(h, addr, (*byte)(unsafe.Pointer(&v)), unsafe.Sizeof(v), nil) - return err + // Decode the JSON + err = json.NewDecoder(offsetsJson).Decode(&offsets) + if err != nil { + fmt.Println("Error decoding JSON:", err) + return offsets + } + return offsets } -// === Entity Reading === -func getEntitiesInfo(ph windows.Handle, base, sw, sh uintptr, off Offset) []Entity { +func getEntitiesInfo(procHandle windows.Handle, clientDll uintptr, screenWidth uintptr, screenHeight uintptr, offsets Offset) []Entity { + var entityList uintptr var entities []Entity - var list uintptr - if read(ph, base+off.DwEntityList, &list) != nil { return entities } - - var localP, localScene, localOrigin Vector3 - var localTeam int32 - var viewMatrix Matrix - - read(ph, base+off.DwLocalPlayerPawn, &localP) - read(ph, localP+off.M_pGameSceneNode, &localScene) - read(ph, localScene+off.M_nodeToWorld, &localOrigin) - read(ph, base+off.DwViewMatrix, &viewMatrix) - + err := read(procHandle, clientDll+offsets.DwEntityList, &entityList) + if err != nil { + return entities + } + var ( + localPlayerP uintptr + localPlayerGameScene uintptr + localPlayerSceneOrigin Vector3 + localTeam int32 + listEntry uintptr + gameScene uintptr + entityController uintptr + entityControllerPawn uintptr + entityPawn uintptr + entityNameAddress uintptr + entityBoneArray uintptr + entityTeam int32 + entityHealth int32 + entityLifeState int32 + entityName string + sanitizedNameStr string + entityOrigin Vector3 + viewMatrix Matrix + ) bones := map[string]int{ - "head": 6, "neck_0": 5, "spine_1": 4, "spine_2": 2, "pelvis": 0, - "arm_upper_L": 8, "arm_lower_L": 9, "hand_L": 10, - "arm_upper_R": 13, "arm_lower_R": 14, "hand_R": 15, - "leg_upper_L": 22, "leg_lower_L": 23, "ankle_L": 24, - "leg_upper_R": 25, "leg_lower_R": 26, "ankle_R": 27, + "head": 6, + "neck_0": 5, + "spine_1": 4, + "spine_2": 2, + "pelvis": 0, + "arm_upper_L": 8, + "arm_lower_L": 9, + "hand_L": 10, + "arm_upper_R": 13, + "arm_lower_R": 14, + "hand_R": 15, + "leg_upper_L": 22, + "leg_lower_L": 23, + "ankle_L": 24, + "leg_upper_R": 25, + "leg_lower_R": 26, + "ankle_R": 27, + } + var ( + currentBone Vector3 + entityHead Vector3 + entityHeadTop Vector3 + entityHeadBottom Vector3 + ) + // localPlayerP + err = read(procHandle, clientDll+offsets.DwLocalPlayerPawn, &localPlayerP) + if err != nil { + return entities + } + // localPlayerGameScene + err = read(procHandle, localPlayerP+offsets.M_pGameSceneNode, &localPlayerGameScene) + if err != nil { + return entities + } + // localPlayerSceneOrigin + err = read(procHandle, localPlayerGameScene+offsets.M_nodeToWorld, &localPlayerSceneOrigin) + if err != nil { + return entities + } + // viewMatrix + err = read(procHandle, clientDll+offsets.DwViewMatrix, &viewMatrix) + if err != nil { + return entities } - for i := 0; i < 64; i++ { - var e Entity - boneMap := make(map[string]Vector2) - var listEntry, controller, pawnCtrl, pawn, scene, boneArray uintptr - var team, hp, life int32 - var origin, head, bone Vector3 - var nameAddr uintptr - var name string - var sb strings.Builder - - read(ph, list+uintptr((8*(i&0x7FFF)>>9)+16), &listEntry) - if listEntry == 0 { continue } - read(ph, listEntry+uintptr(112)*(i&0x1FF), &controller) - if controller == 0 { continue } - read(ph, controller+off.M_hPlayerPawn, &pawnCtrl) - if pawnCtrl == 0 { continue } - - read(ph, list+uintptr(0x8*((pawnCtrl&0x7FFF)>>9)+16), &listEntry) - if listEntry == 0 { continue } - read(ph, listEntry+uintptr(112)*(pawnCtrl&0x1FF), &pawn) - if pawn == 0 || pawn == localP { continue } - - read(ph, pawn+off.M_lifeState, &life) - if life != 256 { continue } - - read(ph, pawn+off.M_iTeamNum, &team) - if team == 0 { continue } + var tempEntity Entity + var entityBones map[string]Vector2 = make(map[string]Vector2) + var sanitizedName strings.Builder + // listEntry + err = read(procHandle, entityList+uintptr((8*(i&0x7FFF)>>9)+16), &listEntry) + if err != nil { + return entities + } + if listEntry == 0 { + continue + } + // entityController + err = read(procHandle, listEntry+uintptr(112)*uintptr(i&0x1FF), &entityController) + if err != nil { + return entities + } + if entityController == 0 { + continue + } + // entityControllerPawn + err = read(procHandle, entityController+offsets.M_hPlayerPawn, &entityControllerPawn) + if err != nil { + return entities + } + if entityControllerPawn == 0 { + continue + } + // listEntry + err = read(procHandle, entityList+uintptr(0x8*((entityControllerPawn&0x7FFF)>>9)+16), &listEntry) + if err != nil { + return entities + } + if listEntry == 0 { + continue + } + // entityPawn + err = read(procHandle, listEntry+uintptr(112)*uintptr(entityControllerPawn&0x1FF), &entityPawn) + if err != nil { + return entities + } + if entityPawn == 0 { + continue + } + if entityPawn == localPlayerP { + continue + } + // entityLifeState + err = read(procHandle, entityPawn+offsets.M_lifeState, &entityLifeState) + if err != nil { + return entities + } + if entityLifeState != 256 { + continue + } + // entityTeam + err = read(procHandle, entityPawn+offsets.M_iTeamNum, &entityTeam) + if err != nil { + return entities + } + if entityTeam == 0 { + continue + } if teamCheck { - read(ph, localP+off.M_iTeamNum, &localTeam) - if localTeam == team { continue } + // localTeam + err = read(procHandle, localPlayerP+offsets.M_iTeamNum, &localTeam) + if err != nil { + return entities + } + if localTeam == entityTeam { + continue + } } - - read(ph, pawn+off.M_iHealth, &hp) - if hp < 1 || hp > 100 { continue } - - read(ph, controller+off.M_sSanitizedPlayerName, &nameAddr) - read(ph, nameAddr, &name) - for _, r := range name { - if unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsPunct(r) || unicode.IsSpace(r) { - sb.WriteRune(r) + // entityHealth + err = read(procHandle, entityPawn+offsets.M_iHealth, &entityHealth) + if err != nil { + return entities + } + if entityHealth < 1 || entityHealth > 100 { + continue + } + // entityNameAddress + err = read(procHandle, entityController+offsets.M_sSanitizedPlayerName, &entityNameAddress) + if err != nil { + return entities + } + // entityName + err = read(procHandle, entityNameAddress, &entityName) + if err != nil { + return entities + } + if entityName == "" { + continue + } + for _, c := range entityName { + if unicode.IsLetter(c) || unicode.IsDigit(c) || unicode.IsPunct(c) || unicode.IsSpace(c) { + sanitizedName.WriteRune(c) } } - - read(ph, pawn+off.M_pGameSceneNode, &scene) - if scene == 0 { continue } - read(ph, scene+off.M_modelState+off.M_boneArray, &boneArray) - if boneArray == 0 { continue } - read(ph, pawn+off.M_vOldOrigin, &origin) - - for name, idx := range bones { - read(ph, boneArray+uintptr(idx)*32, &bone) - x, y := worldToScreen(viewMatrix, bone) - boneMap[name] = Vector2{x, y} - if name == "head" { head = bone } + sanitizedNameStr = sanitizedName.String() + // gameScene + err = read(procHandle, entityPawn+offsets.M_pGameSceneNode, &gameScene) + if err != nil { + return entities } - - headTop := Vector3{head.X, head.Y, head.Z + 7} - headBot := Vector3{head.X, head.Y, head.Z - 5} - hx, hty := worldToScreen(viewMatrix, headTop) - _, hby := worldToScreen(viewMatrix, headBot) - fx, fy := worldToScreen(viewMatrix, origin) - boxTop := Vector3{origin.X, origin.Y, origin.Z + 70} - _, bty := worldToScreen(viewMatrix, boxTop) - - if hx <= -1 || fy <= -1 || hx >= float32(sw) || hty >= float32(sh) { continue } - - height := fy - bty - e = Entity{ - Health: hp, - Team: team, - Name: sb.String(), - Distance: origin.Dist(localOrigin), - Position: Vector2{fx, fy}, - Bones: boneMap, - HeadPos: Vector3{hx, hty, hby}, - Rect: Rectangle{bty, fx - height/4, fx + height/4, fy}, + if gameScene == 0 { + continue + } + // entityBoneArray + err = read(procHandle, gameScene+offsets.M_modelState+offsets.M_boneArray, &entityBoneArray) + if err != nil { + return entities + } + if entityBoneArray == 0 { + continue + } + // entityOrigin + err = read(procHandle, entityPawn+offsets.M_vOldOrigin, &entityOrigin) + if err != nil { + return entities + } + // boneArray + for boneName, boneIndex := range bones { + err = read(procHandle, entityBoneArray+uintptr(boneIndex)*32, ¤tBone) + if err != nil { + return entities + } + if boneName == "head" { + entityHead = currentBone + if !skeletonRendering { + break + } + } + boneX, boneY := worldToScreen(viewMatrix, currentBone) + entityBones[boneName] = Vector2{boneX, boneY} + } + entityHeadTop = Vector3{entityHead.X, entityHead.Y, entityHead.Z + 7} + entityHeadBottom = Vector3{entityHead.X, entityHead.Y, entityHead.Z - 5} + screenPosHeadX, screenPosHeadTopY := worldToScreen(viewMatrix, entityHeadTop) + _, screenPosHeadBottomY := worldToScreen(viewMatrix, entityHeadBottom) + screenPosFeetX, screenPosFeetY := worldToScreen(viewMatrix, entityOrigin) + entityBoxTop := Vector3{entityOrigin.X, entityOrigin.Y, entityOrigin.Z + 70} + _, screenPosBoxTop := worldToScreen(viewMatrix, entityBoxTop) + if screenPosHeadX <= -1 || screenPosFeetY <= -1 || screenPosHeadX >= float32(screenWidth) || screenPosHeadTopY >= float32(screenHeight) { + continue } - entities = append(entities, e) + boxHeight := screenPosFeetY - screenPosBoxTop + + tempEntity.Health = entityHealth + tempEntity.Team = entityTeam + tempEntity.Name = sanitizedNameStr + tempEntity.Distance = entityOrigin.Dist(localPlayerSceneOrigin) + tempEntity.Position = Vector2{screenPosFeetX, screenPosFeetY} + tempEntity.Bones = entityBones + tempEntity.HeadPos = Vector3{screenPosHeadX, screenPosHeadTopY, screenPosHeadBottomY} + tempEntity.Rect = Rectangle{screenPosBoxTop, screenPosFeetX - boxHeight/4, screenPosFeetX + boxHeight/4, screenPosFeetY} + + entities = append(entities, tempEntity) } return entities } -// === Drawing === func drawSkeleton(hdc win.HDC, pen uintptr, bones map[string]Vector2) { win.SelectObject(hdc, win.HGDIOBJ(pen)) - lines := [][2]string{ - {"head", "neck_0"}, {"neck_0", "spine_1"}, {"spine_1", "spine_2"}, {"spine_2", "pelvis"}, - {"pelvis", "leg_upper_L"}, {"leg_upper_L", "leg_lower_L"}, {"leg_lower_L", "ankle_L"}, - {"pelvis", "leg_upper_R"}, {"leg_upper_R", "leg_lower_R"}, {"leg_lower_R", "ankle_R"}, - {"spine_1", "arm_upper_L"}, {"arm_upper_L", "arm_lower_L"}, {"arm_lower_L", "hand_L"}, - {"spine_1", "arm_upper_R"}, {"arm_upper_R", "arm_lower_R"}, {"arm_lower_R", "hand_R"}, - } - for _, l := range lines { - p1 := bones[l[0]] - p2 := bones[l[1]] - win.MoveToEx(hdc, int(p1.X), int(p1.Y), nil) - win.LineTo(hdc, int32(p2.X), int32(p2.Y)) - } + win.MoveToEx(hdc, int(bones["head"].X), int(bones["head"].Y), nil) + win.LineTo(hdc, int32(bones["neck_0"].X), int32(bones["neck_0"].Y)) + win.LineTo(hdc, int32(bones["spine_1"].X), int32(bones["spine_1"].Y)) + win.LineTo(hdc, int32(bones["spine_2"].X), int32(bones["spine_2"].Y)) + win.LineTo(hdc, int32(bones["pelvis"].X), int32(bones["pelvis"].Y)) + win.LineTo(hdc, int32(bones["leg_upper_L"].X), int32(bones["leg_upper_L"].Y)) + win.LineTo(hdc, int32(bones["leg_lower_L"].X), int32(bones["leg_lower_L"].Y)) + win.LineTo(hdc, int32(bones["ankle_L"].X), int32(bones["ankle_L"].Y)) + win.MoveToEx(hdc, int(bones["pelvis"].X), int(bones["pelvis"].Y), nil) + win.LineTo(hdc, int32(bones["leg_upper_R"].X), int32(bones["leg_upper_R"].Y)) + win.LineTo(hdc, int32(bones["leg_lower_R"].X), int32(bones["leg_lower_R"].Y)) + win.LineTo(hdc, int32(bones["ankle_R"].X), int32(bones["ankle_R"].Y)) + win.MoveToEx(hdc, int(bones["spine_1"].X), int(bones["spine_1"].Y), nil) + win.LineTo(hdc, int32(bones["arm_upper_L"].X), int32(bones["arm_upper_L"].Y)) + win.LineTo(hdc, int32(bones["arm_lower_L"].X), int32(bones["arm_lower_L"].Y)) + win.LineTo(hdc, int32(bones["hand_L"].X), int32(bones["hand_L"].Y)) + win.MoveToEx(hdc, int(bones["spine_1"].X), int(bones["spine_1"].Y), nil) + win.LineTo(hdc, int32(bones["arm_upper_R"].X), int32(bones["arm_upper_R"].Y)) + win.LineTo(hdc, int32(bones["arm_lower_R"].X), int32(bones["arm_lower_R"].Y)) + win.LineTo(hdc, int32(bones["hand_R"].X), int32(bones["hand_R"].Y)) } -func renderEntityInfo(hdc win.HDC, tPen, gPen, oPen, hPen uintptr, r Rectangle, hp int32, name string, head Vector3) { +func renderEntityInfo(hdc win.HDC, tPen uintptr, gPen uintptr, oPen uintptr, hPen uintptr, rect Rectangle, hp int32, name string, headPos Vector3) { if boxRendering { + // Box win.SelectObject(hdc, win.HGDIOBJ(tPen)) - win.Rectangle(hdc, int32(r.Left), int32(r.Top), int32(r.Right), int32(r.Bottom)) + win.MoveToEx(hdc, int(rect.Left), int(rect.Top), nil) + win.LineTo(hdc, int32(rect.Right), int32(rect.Top)) + win.LineTo(hdc, int32(rect.Right), int32(rect.Bottom)) + win.LineTo(hdc, int32(rect.Left), int32(rect.Bottom)) + win.LineTo(hdc, int32(rect.Left), int32(rect.Top)) + + // Box outline win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.Rectangle(hdc, int32(r.Left)-1, int32(r.Top)-1, int32(r.Right)+1, int32(r.Bottom)+1) + win.MoveToEx(hdc, int(rect.Left)-1, int(rect.Top)-1, nil) + win.LineTo(hdc, int32(rect.Right)-1, int32(rect.Top)+1) + win.LineTo(hdc, int32(rect.Right)+1, int32(rect.Bottom)+1) + win.LineTo(hdc, int32(rect.Left)+1, int32(rect.Bottom)-1) + win.LineTo(hdc, int32(rect.Left)-1, int32(rect.Top)-1) + win.MoveToEx(hdc, int(rect.Left)+1, int(rect.Top)+1, nil) + win.LineTo(hdc, int32(rect.Right)+1, int32(rect.Top)-1) + win.LineTo(hdc, int32(rect.Right)-1, int32(rect.Bottom)-1) + win.LineTo(hdc, int32(rect.Left)-1, int32(rect.Bottom)+1) + win.LineTo(hdc, int32(rect.Left)+1, int32(rect.Top)+1) } if headCircle { - rad := int32((int32(head.Z) - int32(head.Y)) / 2) + // Head with outline + radius := int32((int32(headPos.Z) - int32(headPos.Y)) / 2) win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.Ellipse(hdc, int32(head.X)-rad-1, int32(head.Y)-1, int32(head.X)+rad+1, int32(head.Z)+1) + win.Ellipse(hdc, int32(headPos.X)-radius-1, int32(headPos.Y)-1, int32(headPos.X)+radius+1, int32(headPos.Z)+1) win.SelectObject(hdc, win.HGDIOBJ(hPen)) - win.Ellipse(hdc, int32(head.X)-rad, int32(head.Y), int32(head.X)+rad, int32(head.Z)) + win.Ellipse(hdc, int32(headPos.X)-radius, int32(headPos.Y), int32(headPos.X)+radius, int32(headPos.Z)) + win.SelectObject(hdc, win.HGDIOBJ(oPen)) + win.Ellipse(hdc, int32(headPos.X)-radius+1, int32(headPos.Y)+1, int32(headPos.X)+radius-1, int32(headPos.Z)-1) } if healthBarRendering { - y := int(r.Bottom + 1 - float64(int(r.Bottom+1-int(r.Top))*float64(hp)/100.0)) + // Health bar win.SelectObject(hdc, win.HGDIOBJ(gPen)) - win.MoveToEx(hdc, int(r.Left)-4, y, nil) - win.LineTo(hdc, int32(r.Left)-4, int32(r.Bottom)+1) + win.MoveToEx(hdc, int(rect.Left)-4, int(rect.Bottom)+1-int(float64(int(rect.Bottom)+1-int(rect.Top))*float64(hp)/100.0), nil) + win.LineTo(hdc, int32(rect.Left)-4, int32(rect.Bottom)+1) + + // Health bar outline win.SelectObject(hdc, win.HGDIOBJ(oPen)) - win.Rectangle(hdc, int32(r.Left)-5, int32(r.Top)-1, int32(r.Left)-3, int32(r.Bottom)+1) + win.MoveToEx(hdc, int(rect.Left)-5, int(rect.Top)-1, nil) + win.LineTo(hdc, int32(rect.Left)-5, int32(rect.Bottom)+1) + win.LineTo(hdc, int32(rect.Left)-3, int32(rect.Bottom)+1) + win.LineTo(hdc, int32(rect.Left)-3, int32(rect.Top)-1) + win.LineTo(hdc, int32(rect.Left)-5, int32(rect.Top)-1) } if healthTextRendering { + // Health text text, _ := windows.UTF16PtrFromString(fmt.Sprintf("%d", hp)) - win.SetTextColor(hdc, win.RGB(0, 255, 50)) + win.SetTextColor(hdc, win.RGB(byte(0), byte(255), byte(50))) + // Set text right alignment setTextAlign.Call(uintptr(hdc), 0x00000002) - y := int(r.Bottom + 1 - float64(int(r.Bottom+1-int(r.Top))*float64(hp)/100.0)) - if !healthBarRendering { y = int(r.Top) } - win.TextOut(hdc, int32(r.Left)-8, int32(y), text, int32(len(fmt.Sprintf("%d", hp)))) + if healthBarRendering { + win.TextOut(hdc, int32(rect.Left)-8, int32(int(rect.Bottom)+1-int(float64(int(rect.Bottom)+1-int(rect.Top))*float64(hp)/100.0)), text, int32(len(fmt.Sprintf("%d", hp)))) + } else { + win.TextOut(hdc, int32(rect.Left)-4, int32(rect.Top), text, int32(len(fmt.Sprintf("%d", hp)))) + } } if nameRendering { + // Name text, _ := windows.UTF16PtrFromString(name) - win.SetTextColor(hdc, win.RGB(255, 255, 255)) - setTextAlign.Call(uintptr(hdc), 0x00000006) - win.TextOut(hdc, int32(r.Left)+int32((int32(r.Right)-int32(r.Left))/2), int32(r.Top)-14, text, int32(len(name))) + win.SetTextColor(hdc, win.RGB(byte(255), byte(255), byte(255))) + setTextAlign.Call(uintptr(hdc), 0x00000006) // Set text alignment to center + win.TextOut(hdc, int32(rect.Left)+int32((int32(rect.Right)-int32(rect.Left))/2), int32(rect.Top)-14, text, int32(len(name))) } } -// === Window & Menu === -func windowProc(hwnd win.HWND, msg uint32, w, l uintptr) uintptr { - if msg == win.WM_DESTROY { +func windowProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { + switch msg { + case win.WM_TIMER: + return 0 + case win.WM_DESTROY: win.PostQuitMessage(0) return 0 + default: + return win.DefWindowProc(hwnd, msg, wParam, lParam) } - return win.DefWindowProc(hwnd, msg, w, l) } -func initWindow(w, h uintptr) win.HWND { - class, _ := windows.UTF16PtrFromString("cs2go") - title, _ := windows.UTF16PtrFromString("cs2go") +func initWindow(screenWidth uintptr, screenHeight uintptr) win.HWND { + className, err := windows.UTF16PtrFromString("cs2goWindow") + if err != nil { + logAndSleep("Error creating window class name", err) + return 0 + } + windowTitle, err := windows.UTF16PtrFromString("cs2go") + if err != nil { + logAndSleep("Error creating window title", err) + return 0 + } + + // Register window class wc := win.WNDCLASSEX{ CbSize: uint32(unsafe.Sizeof(win.WNDCLASSEX{})), Style: win.CS_HREDRAW | win.CS_VREDRAW, LpfnWndProc: syscall.NewCallback(windowProc), + CbWndExtra: 0, HInstance: win.GetModuleHandle(nil), + HIcon: win.LoadIcon(0, (*uint16)(unsafe.Pointer(uintptr(win.IDI_APPLICATION)))), HCursor: win.LoadCursor(0, (*uint16)(unsafe.Pointer(uintptr(win.IDC_ARROW)))), HbrBackground: win.COLOR_WINDOW, - LpszClassName: class, + LpszMenuName: nil, + LpszClassName: className, + HIconSm: win.LoadIcon(0, (*uint16)(unsafe.Pointer(uintptr(win.IDI_APPLICATION)))), } - win.RegisterClassEx(&wc) + if atom := win.RegisterClassEx(&wc); atom == 0 { + logAndSleep("Error registering window class", fmt.Errorf("%v", win.GetLastError())) + return 0 + } + + // Create window + hInstance := win.GetModuleHandle(nil) hwnd := win.CreateWindowEx( - win.WS_EX_TOPMOST|win.WS_EX_NOACTIVATE|win.WS_EX_LAYERED|win.WS_EX_TRANSPARENT, - class, title, win.WS_POPUP, - 0, 0, int32(w), int32(h), - 0, 0, win.GetModuleHandle(nil), nil, + win.WS_EX_TOPMOST|win.WS_EX_NOACTIVATE|win.WS_EX_LAYERED, + className, + windowTitle, + win.WS_POPUP, + 0, + 0, + int32(screenWidth), + int32(screenHeight), + 0, + 0, + hInstance, + nil, ) - setLayeredWindowAttributes.Call(uintptr(hwnd), 0, 0, 0x00000001) + if hwnd == 0 { + logAndSleep("Error creating window", fmt.Errorf("%v", win.GetLastError())) + return 0 + } + + result, _, _ := setLayeredWindowAttributes.Call(uintptr(hwnd), 0x000000, 0, 0x00000001) + if result == 0 { + logAndSleep("Error setting layered window attributes", fmt.Errorf("%v", win.GetLastError())) + } + // Get the current extended window style + style := win.GetWindowLongPtr(hwnd, win.GWL_EXSTYLE) + + // Add the WS_EX_TRANSPARENT style + style |= win.WS_EX_TRANSPARENT + + // Set the new extended window style + win.SetWindowLongPtr(hwnd, win.GWL_EXSTYLE, style) + showCursor.Call(0) - win.ShowWindow(hwnd, win.SW_SHOW) + + // Show window + win.ShowWindow(hwnd, win.SW_SHOWDEFAULT) return hwnd } func cliMenu() { for { - fmt.Print("\033[H\033[2J") - fmt.Println(chalk.Magenta.Color(" ____ _____ ___ ___ ")) - fmt.Println(chalk.Magenta.Color(" / ___||___ / / _ \\/ _ \\ ")) - fmt.Println(chalk.Magenta.Color(" | | _ |_ \\| | | | | | |")) - fmt.Println(chalk.Magenta.Color(" | |_| |___) | |_| | |_| |")) - fmt.Println(chalk.Magenta.Color(" \\____|____/ \\___/ \\___/ \n")) - fmt.Println(chalk.Dim.TextStyle("\t\tby bqj - v1.7 (Go + FPS Lock)\n")) - - s := func(b bool, on, off string) string { - if b { return chalk.Green.Color(on) } else { return chalk.Red.Color(off) } - } - fmt.Println(s(teamCheck, "[1] Team check [ON]", "[1] Team check [OFF]")) - fmt.Println(s(headCircle, "[2] Head circle [ON]", "[2] Head circle [OFF]")) - fmt.Println(s(skeletonRendering, "[3] Skeleton [ON]", "[3] Skeleton [OFF]")) - fmt.Println(s(boxRendering, "[4] Box [ON]", "[4] Box [OFF]")) - fmt.Println(s(healthBarRendering, "[5] Health bar [ON]", "[5] Health bar [OFF]")) - fmt.Println(s(healthTextRendering, "[6] Health text [ON]", "[6] Health text [OFF]")) - fmt.Println(s(nameRendering, "[7] Name [ON]", "[7] Name [OFF]")) - fmt.Printf("%s[%d FPS → %dms]\n", chalk.Cyan.Color("[8] FPS: "), desiredFrameRate, frameDelay) + fmt.Print(chalk.Magenta.Color(" ____ \n ___ ___|___ \\ ____ ___ \n / __/ __| __) / _ |/ _ \\ \n| (__\\__ \\/ __/ (_| | (_) |\n \\___|___/_____\\__, |\\___/ \n |___/ \n")) + fmt.Println(chalk.Dim.TextStyle("\t\tby bqj - v1.6\n")) + if teamCheck { + fmt.Println(chalk.Green.Color("[1] Team check [ON]")) + } else { + fmt.Println(chalk.Red.Color("[1] Team check [OFF]")) + } + if headCircle { + fmt.Println(chalk.Green.Color("[2] Head circle [ON]")) + } else { + fmt.Println(chalk.Red.Color("[2] Head circle [OFF]")) + } + if skeletonRendering { + fmt.Println(chalk.Green.Color("[3] Skeleton rendering [ON]")) + } else { + fmt.Println(chalk.Red.Color("[3] Skeleton rendering [OFF]")) + } + if boxRendering { + fmt.Println(chalk.Green.Color("[4] Box rendering [ON]")) + } else { + fmt.Println(chalk.Red.Color("[4] Box rendering [OFF]")) + } + if healthBarRendering { + fmt.Println(chalk.Green.Color("[5] Health bar rendering [ON]")) + } else { + fmt.Println(chalk.Red.Color("[5] Health bar rendering [OFF]")) + } + if healthTextRendering { + fmt.Println(chalk.Green.Color("[6] Health text rendering [ON]")) + } else { + fmt.Println(chalk.Red.Color("[6] Health text rendering [OFF]")) + } + if nameRendering { + fmt.Println(chalk.Green.Color("[7] Name rendering [ON]")) + } else { + fmt.Println(chalk.Red.Color("[7] Name rendering [OFF]")) + } + fmt.Println(chalk.Cyan.Color("[8] Adjust frame delay [") + fmt.Sprint(frameDelay) + chalk.Cyan.Color("]")) fmt.Println(chalk.Red.Color("[9] Exit")) - fmt.Print(chalk.Cyan.Color("Select: ")) - - var in string - fmt.Scanln(&in) - switch in { - case "1": teamCheck = !teamCheck - case "2": headCircle = !headCircle - case "3": skeletonRendering = !skeletonRendering - case "4": boxRendering = !boxRendering - case "5": healthBarRendering = !healthBarRendering - case "6": healthTextRendering = !healthTextRendering - case "7": nameRendering = !nameRendering + fmt.Print(chalk.Cyan.Color("[Enter selection]: ")) + var input string + fmt.Scanln(&input) + switch input { + case "1": + teamCheck = !teamCheck + case "2": + headCircle = !headCircle + case "3": + skeletonRendering = !skeletonRendering + case "4": + boxRendering = !boxRendering + case "5": + healthBarRendering = !healthBarRendering + case "6": + healthTextRendering = !healthTextRendering + case "7": + nameRendering = !nameRendering case "8": - fmt.Print(chalk.Cyan.Color("Enter FPS (30-240): ")) - var fps int - fmt.Scanln(&fps) - if fps >= 30 && fps <= 240 { - desiredFrameRate = fps - frameDelay = uint32(1000 / desiredFrameRate) - if frameDelay < 1 { frameDelay = 1 } - } - case "9": os.Exit(0) + fmt.Println(chalk.Red.Color("Higer frame delay = lower performance impact but higher ESP latency")) + fmt.Print(chalk.Cyan.Color("[Enter frame delay]: ")) + var delay uint32 + fmt.Scanln(&delay) + frameDelay = delay + case "9": + os.Exit(0) + default: + fmt.Println(chalk.Red.Color("Invalid selection")) + time.Sleep(1 * time.Second) } + // Clear the console + fmt.Print("\033[H\033[2J") } } -// === Process Utils === -func findProcessId(name string) (uint32, error) { - snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) - if err != nil { return 0, err } - defer windows.CloseHandle(snap) +func main() { + go cliMenu() - var pe windows.ProcessEntry32 - pe.Size = uint32(unsafe.Sizeof(pe)) - if windows.Process32First(snap, &pe) != nil { return 0, fmt.Errorf("no process") } + screenWidth, _, _ := getSystemMetrics.Call(0) + screenHeight, _, _ := getSystemMetrics.Call(1) - for { - if strings.EqualFold(windows.UTF16PtrToString(&pe.SzExeFile[0]), name) { - return pe.ProcessID, nil - } - if windows.Process32Next(snap, &pe) != nil { break } + hwnd := initWindow(screenWidth, screenHeight) + if hwnd == 0 { + logAndSleep("Error creating window", fmt.Errorf("%v", win.GetLastError())) + return } - return 0, fmt.Errorf("not found") -} - -func getModuleBase(pid uint32, mod string) (uintptr, error) { - snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE, pid) - if err != nil { return 0, err } - defer windows.CloseHandle(snap) + defer win.DestroyWindow(hwnd) - var me windows.ModuleEntry32 - me.Size = uint32(unsafe.Sizeof(me)) - if windows.Module32First(snap, &me) != nil { return 0, fmt.Errorf("no module") } + // win.SetCursor() - for { - if strings.EqualFold(windows.UTF16PtrToString(&me.SzModule[0]), mod) { - return uintptr(me.ModBaseAddr), nil - } - if windows.Module32Next(snap, &me) != nil { break } + pid, err := findProcessId("cs2.exe") + if err != nil { + logAndSleep("Error finding process ID", err) + return } - return 0, fmt.Errorf("not found") -} -func getProcessHandle(pid uint32) (windows.Handle, error) { - return windows.OpenProcess(windows.PROCESS_VM_READ, false, pid) -} + clientDll, err := getModuleBaseAddress(pid, "client.dll") + if err != nil { + logAndSleep("Error getting client.dll base address", err) + return + } -// === MAIN === -func main() { - go cliMenu() + procHandle, err := getProcessHandle(pid) + if err != nil { + logAndSleep("Error getting process handle", err) + return + } - sw, _, _ := getSystemMetrics.Call(0) - sh, _, _ := getSystemMetrics.Call(1) - hwnd := initWindow(sw, sh) - if hwnd == 0 { log.Fatal("Window failed") } + hdc := win.GetDC(hwnd) + if hdc == 0 { + logAndSleep("Error getting device context", fmt.Errorf("%v", win.GetLastError())) + return + } - pid, err := findProcessId("cs2.exe") - if err != nil { logAndSleep("CS2 not found", err); return } - base, err := getModuleBase(pid, "client.dll") - if err != nil { logAndSleep("client.dll not found", err); return } - ph, err := getProcessHandle(pid) - if err != nil { logAndSleep("OpenProcess failed", err); return } - defer windows.CloseHandle(ph) + bgBrush, _, _ := createSolidBrush.Call(uintptr(0x000000)) + if bgBrush == 0 { + logAndSleep("Error creating brush", fmt.Errorf("%v", win.GetLastError())) + return + } + defer win.DeleteObject(win.HGDIOBJ(bgBrush)) + redPen, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7a78ff) + if redPen == 0 { + logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) + return + } + defer win.DeleteObject(win.HGDIOBJ(redPen)) + greenPen, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7dff78) + if greenPen == 0 { + logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) + return + } + defer win.DeleteObject(win.HGDIOBJ(greenPen)) + bluePen, _, _ := createPen.Call(win.PS_SOLID, 1, 0xff8e78) + if bluePen == 0 { + logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) + return + } + defer win.DeleteObject(win.HGDIOBJ(bluePen)) + bonePen, _, _ := createPen.Call(win.PS_SOLID, 1, 0xffffff) + if bonePen == 0 { + logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) + return + } + defer win.DeleteObject(win.HGDIOBJ(bonePen)) + outlinePen, _, _ := createPen.Call(win.PS_SOLID, 1, 0x000001) + if outlinePen == 0 { + logAndSleep("Error creating pen", fmt.Errorf("%v", win.GetLastError())) + return + } + defer win.DeleteObject(win.HGDIOBJ(outlinePen)) - hdc := win.GetDC(hwnd) - bg, _, _ := createSolidBrush.Call(0x000000) - red, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7a78ff) - green, _, _ := createPen.Call(win.PS_SOLID, 1, 0x7dff78) - blue, _, _ := createPen.Call(win.PS_SOLID, 1, 0xff8e78) - bone, _, _ := createPen.Call(win.PS_SOLID, 1, 0xffffff) - outline, _, _ := createPen.Call(win.PS_SOLID, 1, 0x000001) - font, _, _ := createFont.Call(12, 0, 0, 0, win.FW_HEAVY, 0, 0, 0, win.DEFAULT_CHARSET, 0, 0, 0, 0, 0) + font, _, _ := createFont.Call(12, 0, 0, 0, win.FW_HEAVY, 0, 0, 0, win.DEFAULT_CHARSET, win.OUT_DEFAULT_PRECIS, win.CLIP_DEFAULT_PRECIS, win.DEFAULT_QUALITY, win.DEFAULT_PITCH|win.FF_DONTCARE, 0) - off := getOffsets() + offsets := getOffsets() var msg win.MSG + for win.GetMessage(&msg, 0, 0, 0) > 0 { win.TranslateMessage(&msg) win.DispatchMessage(&msg) - // === FPS CONTROL (từ C++) === - currentTime := time.Now() - deltaTime := currentTime.Sub(lastFrameTime).Milliseconds() + win.SetTimer(hwnd, 1, frameDelay, 0) - if deltaTime < int64(frameDelay) { - sleepTime := int64(frameDelay) - deltaTime - time.Sleep(time.Duration(sleepTime) * time.Millisecond) - } - lastFrameTime = currentTime - // === END FPS CONTROL === - - memDC, _, _ := createCompatibleDC.Call(uintptr(hdc)) - bitmap := win.CreateCompatibleBitmap(hdc, int32(sw), int32(sh)) - win.SelectObject(win.HDC(memDC), win.HGDIOBJ(bitmap)) - win.SelectObject(win.HDC(memDC), win.HGDIOBJ(bg)) - win.SetBkMode(win.HDC(memDC), win.TRANSPARENT) - win.SelectObject(win.HDC(memDC), win.HGDIOBJ(font)) + memhdc, _, _ := createCompatibleDC.Call(uintptr(hdc)) + memBitmap := win.CreateCompatibleBitmap(hdc, int32(screenWidth), int32(screenHeight)) + win.SelectObject(win.HDC(memhdc), win.HGDIOBJ(memBitmap)) + win.SelectObject(win.HDC(memhdc), win.HGDIOBJ(bgBrush)) + win.SetBkMode(win.HDC(memhdc), win.TRANSPARENT) + win.SelectObject(win.HDC(memhdc), win.HGDIOBJ(font)) - entities := getEntitiesInfo(ph, base, sw, sh, off) - for _, e := range entities { - if e.Distance < 35 { continue } + entities := getEntitiesInfo(procHandle, clientDll, screenWidth, screenHeight, offsets) + for _, entity := range entities { + if entity.Distance < 35 { + continue + } if skeletonRendering { - drawSkeleton(win.HDC(memDC), bone, e.Bones) + drawSkeleton(win.HDC(memhdc), bonePen, entity.Bones) + } + if entity.Team == 2 { + renderEntityInfo(win.HDC(memhdc), redPen, greenPen, outlinePen, bonePen, entity.Rect, entity.Health, entity.Name, entity.HeadPos) + } else { + renderEntityInfo(win.HDC(memhdc), bluePen, greenPen, outlinePen, bonePen, entity.Rect, entity.Health, entity.Name, entity.HeadPos) } - teamPen := red - if e.Team != 2 { teamPen = blue } - renderEntityInfo(win.HDC(memDC), teamPen, green, outline, bone, e.Rect, e.Health, e.Name, e.HeadPos) } + win.BitBlt(hdc, 0, 0, int32(screenWidth), int32(screenHeight), win.HDC(memhdc), 0, 0, win.SRCCOPY) - win.BitBlt(hdc, 0, 0, int32(sw), int32(sh), win.HDC(memDC), 0, 0, win.SRCCOPY) - win.DeleteObject(win.HGDIOBJ(bitmap)) - win.DeleteDC(win.HDC(memDC)) + // Delete the memory bitmap and device context + win.DeleteObject(win.HGDIOBJ(memBitmap)) + win.DeleteDC(win.HDC(memhdc)) } }