This is the 3d camera I am building. If anyone needs it, they can fix it as they wish. Currently, I cannot fix the zoom by delta +- but it is relying on an intermediate offset float 30 to keep the mouse in the middle. I have also tried some ways but currently the zoom still does not work by delta +-. If anyone needs it, they can continue to develop it. By the way, if anyone has a way to fix it, please post it here to discuss.
#include "Camera3D.h"
#include <Windows.h>
#include <atomic>
#include <cmath>
#include <gl/GLU.h>
#include <math.h>
typedef void(__stdcall* SetZoomFunc)(void* pThis, float zoomValue);
SetZoomFunc g_originalSetZoom = nullptr;
DWORD WINAPI FixFOVThread(LPVOID);
#define CAMERA_ZOOM 0x01CD0B3C
#define CAMERA_ROTY 0x01A8BC48
#define CAMERA_ROTZ 0x0A3AF78C
#define CAMERA_POSZ 0x01A42828
#define CAMERA_CLIPX 0x01A8C2CC
#define CAMERA_CLIPY 0x01A8C2D8
#define CAMERA_GLCLIP 0x01A41E08
#define ZOOM_MIN 20.0f
#define ZOOM_MAX 79.0f
#define CAMERA_ZOOM_X 0x01A6FF24
#define CAMERA_ZOOM_Y 0x01AB0CD8
#define GAMESTATE_ADDR 0x01CFCE50 // trạng thái của games = 6
// ==== GIÁ TRỬa MẶC ĐỊNH ====
const float ZOOM_DEFAULT = 79.0f;
const float ROT_X_DEFAULT = -48.5f;
const float ROT_Z_DEFAULT = -45.0f;
const float POS_Z_DEFAULT = 150.0f;
const float CLIPX_DEFAULT = 1190.0f;
const float CLIPY_DEFAULT = 2400.0f;
const float GLCLIP_DEFAULT = 3000.0f;
// CHECK CỬA SỔ MU
bool IsMuWindowForeground()
{
HWND hMu = FindWindowA("MU", NULL);
return (GetForegroundWindow() == hMu);
}
// HHOOK CHUỘT BÀN PHÍM
HHOOK MouseHook = NULL;
HHOOK KeyboardHook = NULL;
HINSTANCE hInstance = NULL;
POINT g_mouseLastPos = { 0 };
DWORD g_uiThreadId = 0;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL MouseSetHook(BOOL enable);
BOOL KeyboardSetHook(BOOL enable);
// ==== TTHÔNG BÁO MÀN HÌNH ====
typedef void(__cdecl* tShowCenterMessage)(char* szText, BYTE mode);
tShowCenterMessage ShowCenterMessage = (tShowCenterMessage)(0x017117FF);
static char g_msgOn[] = "3D Camera: ON";
static char g_msgOff[] = "3D Camera: OFF";
extern "C" void APIENTRY glDisable(GLenum cap);
// kiểm tra trạng thái của game khi vào hăn game
bool IsInGame()
{
int* gameState = (int*)GAMESTATE_ADDR;
return (gameState && *gameState >= 6); // 6: InGame
}
// ==== BIẾN TOÀN CỤC ====
float g_zoomLevel = ZOOM_DEFAULT;
std::atomic<bool> g_enabled = false;
std::atomic<bool> g_rotating = false;
POINT g_lastPos = { 0 };
// ==== TEMPLATE ĐỌC/GHI RAM ====
template<typename T>
T Read(DWORD addr) {
return *(T*)addr;
}
template<typename T>
void Write(DWORD addr, T value) {
DWORD oldProtect;
VirtualProtect((void*)addr, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
*(T*)addr = value;
VirtualProtect((void*)addr, sizeof(T), oldProtect, &oldProtect);
}
extern DWORD g_uiThreadId;
BOOL KeyboardSetHook(BOOL set_or_remove)
{
if (set_or_remove == TRUE)
{
if (KeyboardHook == NULL)
{
KeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, hInstance, g_uiThreadId);
if (!KeyboardHook) return FALSE;
}
}
else
{
UnhookWindowsHookEx(KeyboardHook);
KeyboardHook = NULL;
}
return TRUE;
}
BOOL MouseSetHook(BOOL set_or_remove)
{
if (set_or_remove == TRUE)
{
if (MouseHook == NULL)
{
MouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, hInstance, g_uiThreadId);
if (!MouseHook) return FALSE;
}
}
else
{
UnhookWindowsHookEx(MouseHook);
MouseHook = NULL;
}
return TRUE;
}
// ==== ZOOM CAMERA ====
void ZoomCamera(short delta) {
float* zoom = (float*)CAMERA_ZOOM;
float* posZ = (float*)CAMERA_POSZ;
float* clipX = (float*)CAMERA_CLIPX;
float* clipY = (float*)CAMERA_CLIPY;
float* glclip = (float*)CAMERA_GLCLIP;
float* roty = (float*)CAMERA_ROTY;
if (*zoom < 40.0f) {
*roty = -30.0f + (*zoom - 20.0f) * 0.75f;
*posZ = 150.0f + (40.0f - *zoom) * 2.5f;
}
else {
*roty = -48.5f;
*posZ = 150.0f;
}
int direction = delta;
if (direction > 0 && *zoom < ZOOM_MAX) *zoom += 2.0f;
if (direction < 0 && *zoom > ZOOM_MIN) *zoom -= 2.0f;
float offset = fabs(*posZ - 150.0f) * 3.0f;
*clipX = 1190.0f + offset + 1000.0f;
*clipY = 2400.0f + offset + 1000.0f;
*glclip = 3000.0f + offset + 1000.0f;
}
// ==== XOAY CAMERA ====
void RotateCamera(float deltaRotZ, float deltaRotY) {
float zoom = Read<float>(CAMERA_ZOOM);
float roty = Read<float>(CAMERA_ROTY);
float rotz = Read<float>(CAMERA_ROTZ);
float posZ = Read<float>(CAMERA_POSZ);
const float smoothZ = 0.6f;
const float smoothY = 0.9f;
// Xoay ngang (RotZ)
rotz += deltaRotZ * smoothZ;
if (rotz > 315.0f || rotz < -405.0f)
rotz = ROT_Z_DEFAULT;
if (zoom >= 20.0f && zoom <= 79.0f)
{
float deltaY = fabs(deltaRotY * smoothY / 5.0f);
// Tính thử roty mới
float roty_new = roty;
if (deltaRotY > 0 && roty < -30.0f) {
roty_new += 2.42f * deltaY;
// Nếu vượt -39, dừng tại -39 và không thay đổi posZ
if (g_enabled && roty_new > -39.0f) {
roty_new = -39.0f;
}
else {
posZ -= 44.0f * deltaY;
}
}
else if (deltaRotY < 0 && roty > -85.0f) {
roty_new -= 2.42f * deltaY;
posZ += 44.0f * deltaY;
}
else if (roty < -85.0f || posZ > 870.0f) {
roty_new = -85.0f;
posZ = 870.0f;
}
roty = roty_new;
}
// Giới hạn cuối cùng (bảo vệ)
if (g_enabled && roty > -39.0f)
roty = -39.0f;
// Ghi kết quả
Write<float>(CAMERA_ROTY, roty);
Write<float>(CAMERA_ROTZ, rotz);
Write<float>(CAMERA_POSZ, posZ);
float offset = fabs(posZ - POS_Z_DEFAULT) * 3.0f;
Write<float>(CAMERA_CLIPX, CLIPX_DEFAULT + offset + 1000.0f);
Write<float>(CAMERA_CLIPY, CLIPY_DEFAULT + offset + 1000.0f);
Write<float>(CAMERA_GLCLIP, GLCLIP_DEFAULT + offset + 1000.0f);
}
// ==== BẮT/TẮT CAMERA ====
void ToggleCamera(bool enable) {
if (enable) {
Write<float>(CAMERA_ZOOM, ZOOM_MAX);
Write<float>(CAMERA_ROTY, ROT_X_DEFAULT);
Write<float>(CAMERA_ROTZ, ROT_Z_DEFAULT);
Write<float>(CAMERA_POSZ, POS_Z_DEFAULT);
CreateThread(0, 0, FixFOVThread, 0, 0, 0);
}
else {
Write<float>(CAMERA_ZOOM, ZOOM_DEFAULT);
Write<float>(CAMERA_ROTY, ROT_X_DEFAULT);
Write<float>(CAMERA_ROTZ, ROT_Z_DEFAULT);
Write<float>(CAMERA_POSZ, POS_Z_DEFAULT);
}
}
// ==== VÒNG LẮp CHÍNH CAMERA ====
void CameraMainLoopStep() {
if (!g_enabled) return;
if (!g_enabled || !IsMuWindowForeground()) return;
if (GetAsyncKeyState(VK_RBUTTON) & 0x8000) {
POINT pt;
GetCursorPos(&pt);
if (!g_rotating) {
g_rotating = true;
g_lastPos = pt;
ShowCursor(FALSE);
}
else {
float dx = (float)(pt.x - g_lastPos.x);
float dy = (float)(pt.y - g_lastPos.y);
if (dx != 0.0f || dy != 0.0f) {
RotateCamera(dx * 0.5f, dy * 1.0f);
g_lastPos = pt;
}
}
}
else if (g_rotating) {
g_rotating = false;
ShowCursor(TRUE);
}
Write<float>(CAMERA_ZOOM_X, 0.0f);
Write<float>(CAMERA_ZOOM_Y, 0.0f);
}
// ==== THREAD CHÍNH ====
DWORD WINAPI CameraMainLoop(LPVOID) {
bool lastF10 = false;
while (true) {
if (IsInGame()) {
bool curF10 = (GetAsyncKeyState(VK_F10) & 0x8000);
if (curF10 && !lastF10 && IsMuWindowForeground()) {
g_enabled = !g_enabled;
ToggleCamera(g_enabled);
ShowCenterMessage(g_enabled ? g_msgOn : g_msgOff, 1);
}
lastF10 = curF10;
float posZ = Read<float>(CAMERA_POSZ);
float offset = fabs(posZ - POS_Z_DEFAULT) * 3.0f;
Write<float>(CAMERA_CLIPX, CLIPX_DEFAULT + offset + 1000.0f);
Write<float>(CAMERA_CLIPY, CLIPY_DEFAULT + offset + 1000.0f);
Write<float>(CAMERA_GLCLIP, GLCLIP_DEFAULT + offset + 1000.0f);
if (g_enabled)
CameraMainLoopStep();
else
Sleep(10);
}
else {
g_enabled = false; // reset khi thoát game
lastF10 = false; // tránh giữ phím
Sleep(200);
}
Sleep(1);
}
return 0;
}
// ==== THREAD GIÁM SÁT FOV ====
DWORD WINAPI FixFOVThread(LPVOID) {
while (true) {
float zoom = Read<float>(CAMERA_ZOOM);
zoom = roundf(zoom * 10.0f) / 10.0f;
if (zoom < ZOOM_MIN) zoom = ZOOM_MIN;
if (zoom > ZOOM_MAX) zoom = ZOOM_MAX;
Write<float>(CAMERA_ZOOM, zoom);
Sleep(200);
}
return 0;
}
void __stdcall HookedSetZoom(void* pThis, float zoomValue)
{
// Bỏ qua giá trị giật mặc định
if (zoomValue == 20.0f || zoomValue == 30.0f || zoomValue == 79.0f)
return;
// Clamp zoomValue
if (zoomValue < ZOOM_MIN) zoomValue = ZOOM_MIN;
if (zoomValue > ZOOM_MAX) zoomValue = ZOOM_MAX;
// Ghi trực tiếp
*(float*)((DWORD)pThis + 0x10) = zoomValue;
// Cập nhật clip plane
float posZ = Read<float>(CAMERA_POSZ);
float offset = fabs(posZ - POS_Z_DEFAULT) * 3.0f;
Write<float>(CAMERA_CLIPX, CLIPX_DEFAULT + offset + 1000.0f);
Write<float>(CAMERA_CLIPY, CLIPY_DEFAULT + offset + 1000.0f);
Write<float>(CAMERA_GLCLIP, GLCLIP_DEFAULT + offset + 1000.0f);
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && IsMuWindowForeground()) {
if (wParam == WM_MOUSEWHEEL) {
short delta = GET_WHEEL_DELTA_WPARAM(((MOUSEHOOKSTRUCTEX*)lParam)->mouseData);
ZoomCamera(delta);
return 1; // chặn event gốc nếu cần
}
}
return CallNextHookEx(MouseHook, nCode, wParam, lParam);
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && IsMuWindowForeground()) {
// xử lý phím nếu cần
if (wParam == VK_ESCAPE && g_enabled) {
g_enabled = false;
ToggleCamera(false);
ShowCenterMessage(g_msgOff, 1);
return 1;
}
}
return CallNextHookEx(KeyboardHook, nCode, wParam, lParam);
}