Gigantic update with menu
This commit is contained in:
		
							
								
								
									
										24
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,11 +1,15 @@ | |||||||
|  |  | ||||||
| # Need to use g++ because the sdk headers use classes | # Need to use g++ because the sdk headers use classes | ||||||
| CC=g++ | CC=g++ | ||||||
| INCLUDES=-Isrc/include/sdk/common -Isrc/include/sdk/public -Isrc/include/sdk/pm_shared -Isrc/include/sdk/engine | INCLUDES=-Isrc/include/sdk/common -Isrc/include/sdk/public -Isrc/include/sdk/pm_shared -Isrc/include/sdk/engine -Isrc/include | ||||||
| CFLAGS=-Wall -Wextra -Wno-write-strings -m32 -fPIC $(INCLUDES) | CFLAGS=-Wall -Wextra -Wno-write-strings -m32 -fPIC -fpermissive $(INCLUDES) | ||||||
| LDFLAGS=-lm | LDFLAGS=-lm -lGL | ||||||
|  |  | ||||||
| OBJS=obj/main.c.o obj/globals.c.o obj/cvars.c.o obj/hooks.c.o obj/detour.c.o obj/util.c.o obj/features/movement.c.o obj/features/anti_aim.c.o obj/features/fov.c.o obj/features/namechanger.c.o obj/features/esp.c.o obj/features/chams.c.o obj/features/aim.c.o obj/features/misc.c.o obj/game_detection.c.o | IMGUI_DIR=src/include/imgui | ||||||
|  | IMGUI_INCLUDES=-I$(IMGUI_DIR) | ||||||
|  | IMGUI_SRCS=$(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp | ||||||
|  | IMGUI_OBJS=$(patsubst %.cpp,%.o,$(IMGUI_SRCS)) | ||||||
|  |  | ||||||
|  | OBJS=obj/main.c.o obj/globals.c.o obj/settings.c.o obj/hooks.c.o obj/detour.c.o obj/util.c.o obj/features/movement.c.o obj/features/anti_aim.c.o obj/features/fov.c.o obj/features/namechanger.c.o obj/features/esp.c.o obj/features/chams.c.o obj/features/aim.c.o obj/features/misc.c.o obj/features/thirdperson.c.o obj/game_detection.c.o obj/menu.c.o $(IMGUI_OBJS) | ||||||
| BIN=libhlcheat.so | BIN=libhlcheat.so | ||||||
|  |  | ||||||
| .PHONY: clean all inject | .PHONY: clean all inject | ||||||
| @@ -28,6 +32,12 @@ inject: $(BIN) | |||||||
| $(BIN): $(OBJS) | $(BIN): $(OBJS) | ||||||
| 	$(CC) $(CFLAGS) -shared -o $@ $(OBJS) $(LDFLAGS) | 	$(CC) $(CFLAGS) -shared -o $@ $(OBJS) $(LDFLAGS) | ||||||
|  |  | ||||||
| $(OBJS): obj/%.c.o : src/%.c | obj/%.c.o: src/%.c | ||||||
| 	@mkdir -p obj/features/ | 	@mkdir -p $(@D) | ||||||
|  | 	$(CC) $(CFLAGS) -c -o $@ $< $(LDFLAGS) | ||||||
|  |  | ||||||
|  | $(IMGUI_DIR)/backends/%.o: $(IMGUI_DIR)/backends/%.cpp | ||||||
|  | 	$(CC) $(CFLAGS) $(IMGUI_INCLUDES) -c -o $@ $< $(LDFLAGS) | ||||||
|  |  | ||||||
|  | %.o: %.cpp | ||||||
| 	$(CC) $(CFLAGS) -c -o $@ $< $(LDFLAGS) | 	$(CC) $(CFLAGS) -c -o $@ $< $(LDFLAGS) | ||||||
|   | |||||||
							
								
								
									
										217
									
								
								inject-debug.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										217
									
								
								inject-debug.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,217 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | pid=$(pidof "hl_linux") | ||||||
|  | libpath=$(realpath "libhlcheat.so") | ||||||
|  |  | ||||||
|  | if [ "$pid" == "" ]; then | ||||||
|  |    echo "inject-debug.sh: process not running." | ||||||
|  |    exit 1 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | show_help() { | ||||||
|  |     echo "Usage: $0 [OPTIONS]" | ||||||
|  |     echo "Options:" | ||||||
|  |     echo "  --help          Show this help message" | ||||||
|  |     echo "  --unload        Debug the unload process interactively" | ||||||
|  |     echo "  --inject        Debug the injection process interactively" | ||||||
|  |     echo "" | ||||||
|  |     echo "Common GDB commands to use during debugging:" | ||||||
|  |     echo "  bt              Show backtrace" | ||||||
|  |     echo "  info locals     Show local variables" | ||||||
|  |     echo "  n               Step over (next line)" | ||||||
|  |     echo "  s               Step into function" | ||||||
|  |     echo "  c               Continue execution" | ||||||
|  |     echo "  p expression    Print value of expression" | ||||||
|  |     echo "  finish          Run until current function returns" | ||||||
|  |     echo "" | ||||||
|  |     echo "Without options, the script will inject the cheat normally." | ||||||
|  |     exit 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UNLOAD_MODE=0 | ||||||
|  | INJECT_MODE=0 | ||||||
|  |  | ||||||
|  | for arg in "$@"; do | ||||||
|  |     case $arg in | ||||||
|  |         --help) | ||||||
|  |             show_help | ||||||
|  |             ;; | ||||||
|  |         --unload) | ||||||
|  |             UNLOAD_MODE=1 | ||||||
|  |             ;; | ||||||
|  |         --inject) | ||||||
|  |             INJECT_MODE=1 | ||||||
|  |             ;; | ||||||
|  |     esac | ||||||
|  | done | ||||||
|  |  | ||||||
|  | cat > /tmp/gdbinit-goldsrc << EOF | ||||||
|  | set confirm off | ||||||
|  | set pagination off | ||||||
|  | set print pretty on | ||||||
|  |  | ||||||
|  | define hook-stop | ||||||
|  |     echo \nBREAKPOINT HIT\n | ||||||
|  |     bt | ||||||
|  |     echo \nLOCAL VARIABLES:\n | ||||||
|  |     info locals | ||||||
|  |     echo \nSTACK FRAME:\n | ||||||
|  |     info frame | ||||||
|  |     echo \nCommands: n (next), s (step), c (continue), bt (backtrace), finish (run until function returns)\n | ||||||
|  | end | ||||||
|  |  | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  | if [ $UNLOAD_MODE -eq 1 ]; then | ||||||
|  |     echo "Starting interactive unload debugging session..." | ||||||
|  |      | ||||||
|  |     cat >> /tmp/gdbinit-goldsrc << EOF | ||||||
|  | # Set up functions to help with dlopen/dlclose | ||||||
|  | set \$dlopen = (void* (*)(char*, int))dlopen | ||||||
|  | set \$dlclose = (int (*)(void*))dlclose | ||||||
|  | set \$dlerror = (char* (*)(void))dlerror | ||||||
|  |  | ||||||
|  | # Set breakpoints on critical functions | ||||||
|  | break self_unload | ||||||
|  | break unload | ||||||
|  | break safe_unload_with_debug | ||||||
|  | break UNINJECT_CommandHandler | ||||||
|  | break hooks_restore | ||||||
|  | break globals_restore | ||||||
|  | break GL_UNHOOK | ||||||
|  |  | ||||||
|  | # Command to manually invoke the unload from GDB | ||||||
|  | define uninject | ||||||
|  |     set \$self = \$dlopen("$libpath", 6) | ||||||
|  |     p \$self | ||||||
|  |     call \$dlclose(\$self) | ||||||
|  |     call \$dlclose(\$self) | ||||||
|  |     call \$dlerror() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | define call_uninject_cmd | ||||||
|  |     call UNINJECT_CommandHandler() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | echo \nType 'call_uninject_cmd' to execute the uninject command\n | ||||||
|  | echo Type 'uninject' to manually trigger the unload process\n | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  |     sudo gdb -x /tmp/gdbinit-goldsrc -p $pid | ||||||
|  |      | ||||||
|  |     echo "Interactive unload debugging session ended." | ||||||
|  |     exit 0 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if [ $INJECT_MODE -eq 1 ]; then | ||||||
|  |     echo "Starting interactive injection debugging session..." | ||||||
|  |      | ||||||
|  |     cat >> /tmp/gdbinit-goldsrc << EOF | ||||||
|  | # Set up functions to help with dlopen/dlclose | ||||||
|  | set \$dlopen = (void* (*)(char*, int))dlopen | ||||||
|  | set \$dlclose = (int (*)(void*))dlclose | ||||||
|  | set \$dlerror = (char* (*)(void))dlerror | ||||||
|  |  | ||||||
|  | # Set breakpoints on critical functions | ||||||
|  | break load | ||||||
|  | break globals_init | ||||||
|  | break cvars_init | ||||||
|  | break hooks_init | ||||||
|  |  | ||||||
|  | # Command to manually inject the library | ||||||
|  | define inject | ||||||
|  |     call \$dlopen("$libpath", 2) | ||||||
|  |     call \$dlerror() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | echo \nType 'inject' to load the library\n | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  |     sudo gdb -x /tmp/gdbinit-goldsrc -p $pid | ||||||
|  |      | ||||||
|  |     echo "Interactive injection debugging session ended." | ||||||
|  |     exit 0 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo "Injecting cheat..." | ||||||
|  |  | ||||||
|  | if grep -q "$libpath" "/proc/$pid/maps"; then | ||||||
|  |     echo -e "goldsource-cheat already loaded. Reloading...\n" | ||||||
|  |  | ||||||
|  |     cat > /tmp/gdbinit-goldsrc << EOF | ||||||
|  | set confirm off | ||||||
|  | set pagination off | ||||||
|  | set print pretty on | ||||||
|  | set \$dlopen = (void* (*)(char*, int))dlopen | ||||||
|  | set \$dlclose = (int (*)(void*))dlclose | ||||||
|  | set \$dlerror = (char* (*)(void))dlerror | ||||||
|  |  | ||||||
|  | # Reload library | ||||||
|  | define reload_lib | ||||||
|  |     set \$self = \$dlopen("$libpath", 6) | ||||||
|  |     call \$dlclose(\$self) | ||||||
|  |     call \$dlclose(\$self) | ||||||
|  |     call \$dlopen("$libpath", 2) | ||||||
|  |     call \$dlerror() | ||||||
|  |     echo "\nReload complete. Library has been reloaded.\n" | ||||||
|  |     echo "You can now debug interactively.\n" | ||||||
|  |     echo "Type 'continue' or 'c' to let the game run normally.\n" | ||||||
|  |     echo "Type 'call_uninject_cmd' to trigger the uninject command.\n" | ||||||
|  | end | ||||||
|  |  | ||||||
|  | # Command to manually trigger uninject | ||||||
|  | define call_uninject_cmd | ||||||
|  |     call UNINJECT_CommandHandler() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | # Execute reload automatically | ||||||
|  | reload_lib | ||||||
|  |  | ||||||
|  | # Break on uninject command | ||||||
|  | break UNINJECT_CommandHandler | ||||||
|  | break safe_unload_with_debug | ||||||
|  | break self_unload | ||||||
|  |  | ||||||
|  | echo "\nType 'help' for GDB commands or 'continue' to let the game run.\n" | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  |     sudo gdb -x /tmp/gdbinit-goldsrc -p $pid | ||||||
|  | else | ||||||
|  |     cat > /tmp/gdbinit-goldsrc << EOF | ||||||
|  | set confirm off | ||||||
|  | set pagination off | ||||||
|  | set print pretty on | ||||||
|  | set \$dlopen = (void* (*)(char*, int))dlopen | ||||||
|  | set \$dlclose = (int (*)(void*))dlclose | ||||||
|  | set \$dlerror = (char* (*)(void))dlerror | ||||||
|  |  | ||||||
|  | # Initial library load | ||||||
|  | define load_lib | ||||||
|  |     call \$dlopen("$libpath", 2) | ||||||
|  |     call \$dlerror() | ||||||
|  |     echo "\nInjection complete. Library has been loaded.\n" | ||||||
|  |     echo "You can now debug interactively.\n" | ||||||
|  |     echo "Type 'continue' or 'c' to let the game run normally.\n" | ||||||
|  |     echo "Type 'call_uninject_cmd' to trigger the uninject command.\n" | ||||||
|  | end | ||||||
|  |  | ||||||
|  | # Command to manually trigger uninject | ||||||
|  | define call_uninject_cmd | ||||||
|  |     call UNINJECT_CommandHandler() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | # Execute load automatically | ||||||
|  | load_lib | ||||||
|  |  | ||||||
|  | # Break on uninject command | ||||||
|  | break UNINJECT_CommandHandler | ||||||
|  | break safe_unload_with_debug | ||||||
|  | break self_unload | ||||||
|  |  | ||||||
|  | echo "\nType 'help' for GDB commands or 'continue' to let the game run.\n" | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  |     sudo gdb -x /tmp/gdbinit-goldsrc -p $pid | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo -e "\nDebug session ended."  | ||||||
							
								
								
									
										53
									
								
								src/cvars.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								src/cvars.c
									
									
									
									
									
								
							| @@ -1,53 +0,0 @@ | |||||||
|  |  | ||||||
| #include "include/cvars.h" |  | ||||||
| #include "include/sdk.h" |  | ||||||
| #include "include/globals.h" |  | ||||||
| #include "include/game_detection.h" |  | ||||||
|  |  | ||||||
| DECL_CVAR(movement_bhop); |  | ||||||
| DECL_CVAR(movement_autostrafe); |  | ||||||
| DECL_CVAR(aim_aimbot); |  | ||||||
| DECL_CVAR(aim_autoshoot); |  | ||||||
| DECL_CVAR(visuals_esp); |  | ||||||
| DECL_CVAR(visuals_chams); |  | ||||||
| DECL_CVAR(visuals_crosshair); |  | ||||||
| DECL_CVAR(visuals_tracers); |  | ||||||
| DECL_CVAR(movement_clmove); |  | ||||||
| DECL_CVAR(watermark); |  | ||||||
| DECL_CVAR(watermark_rainbow); |  | ||||||
| DECL_CVAR(aim_aimbot_silent); |  | ||||||
| DECL_CVAR(visuals_friendly); |  | ||||||
| DECL_CVAR(movement_antiaim); |  | ||||||
| DECL_CVAR(movement_antiaim_view); |  | ||||||
| DECL_CVAR(movement_fakeduck); |  | ||||||
| DECL_CVAR(misc_namechanger); |  | ||||||
| DECL_CVAR(misc_namechanger_speed); |  | ||||||
| DECL_CVAR(visuals_fov); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| bool cvars_init(void) { |  | ||||||
|     REGISTER_CVAR(movement_bhop, 1); |  | ||||||
|     REGISTER_CVAR(movement_autostrafe, 1); |  | ||||||
|     REGISTER_CVAR(aim_aimbot, 0); |  | ||||||
|     REGISTER_CVAR(aim_autoshoot, 0); /* Only works with aimbot enabled */ |  | ||||||
|     REGISTER_CVAR(visuals_esp, 3); |  | ||||||
|     REGISTER_CVAR(visuals_chams, 1); |  | ||||||
|     REGISTER_CVAR(visuals_crosshair, 0); |  | ||||||
|     REGISTER_CVAR(movement_clmove, 0); |  | ||||||
|     REGISTER_CVAR(watermark, 1); |  | ||||||
|     REGISTER_CVAR(watermark_rainbow, 1); |  | ||||||
|     REGISTER_CVAR(aim_aimbot_silent, 1); |  | ||||||
|     REGISTER_CVAR(visuals_friendly, 0); |  | ||||||
|     REGISTER_CVAR(movement_antiaim, 0); |  | ||||||
|     REGISTER_CVAR(movement_antiaim_view, 0); |  | ||||||
|     REGISTER_CVAR(movement_fakeduck, 0); |  | ||||||
|     REGISTER_CVAR(misc_namechanger, 0); |  | ||||||
|     REGISTER_CVAR(misc_namechanger_speed, 10); |  | ||||||
|     REGISTER_CVAR(visuals_fov, 90); |  | ||||||
|     if (IsCS16()) { |  | ||||||
|     REGISTER_CVAR(visuals_tracers, 0); |  | ||||||
|     } else { |  | ||||||
|     REGISTER_CVAR(visuals_tracers, 1); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
							
								
								
									
										101
									
								
								src/detour.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								src/detour.c
									
									
									
									
									
								
							| @@ -11,6 +11,7 @@ | |||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <unistd.h>   /* getpagesize */ | #include <unistd.h>   /* getpagesize */ | ||||||
| #include <sys/mman.h> /* mprotect */ | #include <sys/mman.h> /* mprotect */ | ||||||
|  | #include <stdio.h>    /* printf */ | ||||||
|  |  | ||||||
| #include "include/detour.h" | #include "include/detour.h" | ||||||
|  |  | ||||||
| @@ -19,6 +20,11 @@ | |||||||
| #define PAGE_ALIGN(x)      ((x + PAGE_SIZE - 1) & PAGE_MASK) | #define PAGE_ALIGN(x)      ((x + PAGE_SIZE - 1) & PAGE_MASK) | ||||||
| #define PAGE_ALIGN_DOWN(x) (PAGE_ALIGN(x) - PAGE_SIZE) | #define PAGE_ALIGN_DOWN(x) (PAGE_ALIGN(x) - PAGE_SIZE) | ||||||
|  |  | ||||||
|  | /* Store detour data for functions we've hooked */ | ||||||
|  | #define MAX_HOOKS 32 | ||||||
|  | static detour_data_t g_hooks[MAX_HOOKS]; | ||||||
|  | static int g_hook_count = 0; | ||||||
|  |  | ||||||
| static bool protect_addr(void* ptr, int new_flags) { | static bool protect_addr(void* ptr, int new_flags) { | ||||||
|     void* p  = (void*)PAGE_ALIGN_DOWN((detour_ptr_t)ptr); |     void* p  = (void*)PAGE_ALIGN_DOWN((detour_ptr_t)ptr); | ||||||
|     int pgsz = getpagesize(); |     int pgsz = getpagesize(); | ||||||
| @@ -49,6 +55,9 @@ static uint8_t def_jmp_bytes[] = { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| void detour_init(detour_data_t* data, void* orig, void* hook) { | void detour_init(detour_data_t* data, void* orig, void* hook) { | ||||||
|  |     if (!orig || !hook) | ||||||
|  |         return; | ||||||
|  |          | ||||||
|     data->detoured = false; |     data->detoured = false; | ||||||
|     data->orig     = orig; |     data->orig     = orig; | ||||||
|     data->hook     = hook; |     data->hook     = hook; | ||||||
| @@ -108,3 +117,95 @@ bool detour_del(detour_data_t* d) { | |||||||
|  |  | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Get existing hook data for an original function pointer */ | ||||||
|  | static detour_data_t* find_hook_data(void* orig) { | ||||||
|  |     for (int i = 0; i < g_hook_count; i++) { | ||||||
|  |         if (g_hooks[i].orig == orig) { | ||||||
|  |             return &g_hooks[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Wrapper functions for backward compatibility with code using  | ||||||
|  |  * DetourFunction and DetourRemove naming convention */ | ||||||
|  |  | ||||||
|  | /*  | ||||||
|  |  * Wrapper for detour_add that saves and returns the original  | ||||||
|  |  * function pointer as required by the DetourFunction interface | ||||||
|  |  */ | ||||||
|  | void* DetourFunction(void* orig, void* hook) { | ||||||
|  |     if (!orig || !hook) { | ||||||
|  |         printf("DetourFunction error: NULL pointer provided\n"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Check if we already have a hook for this function */ | ||||||
|  |     detour_data_t* existing = find_hook_data(orig); | ||||||
|  |     if (existing) { | ||||||
|  |         /* If the function was already hooked but with a different hook, | ||||||
|  |            restore the original first */ | ||||||
|  |         if (existing->hook != hook) { | ||||||
|  |             printf("DetourFunction: Function at %p already hooked, updating\n", orig); | ||||||
|  |             detour_del(existing); | ||||||
|  |             existing->hook = hook; | ||||||
|  |             /* Recreate the jump instruction with new hook */ | ||||||
|  |             memcpy(existing->jmp_bytes, &def_jmp_bytes, sizeof(def_jmp_bytes)); | ||||||
|  |             memcpy(&existing->jmp_bytes[JMP_BYTES_PTR], &hook, sizeof(detour_ptr_t)); | ||||||
|  |             if (!detour_add(existing)) { | ||||||
|  |                 printf("DetourFunction error: Failed to update hook for %p\n", orig); | ||||||
|  |                 return NULL; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return existing->orig; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* No existing hook, create a new one if we have space */ | ||||||
|  |     if (g_hook_count >= MAX_HOOKS) { | ||||||
|  |         printf("DetourFunction error: Max hooks (%d) reached\n", MAX_HOOKS); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     detour_data_t* data = &g_hooks[g_hook_count++]; | ||||||
|  |     memset(data, 0, sizeof(detour_data_t)); // Clear memory before use | ||||||
|  |     detour_init(data, orig, hook); | ||||||
|  |     if (detour_add(data)) | ||||||
|  |         return data->orig; | ||||||
|  |          | ||||||
|  |     /* If detour failed, decrement the counter */ | ||||||
|  |     printf("DetourFunction error: Failed to add hook for %p\n", orig); | ||||||
|  |     g_hook_count--; | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Wrapper for detour_del that takes the original and hook | ||||||
|  |  * function pointers directly | ||||||
|  |  */ | ||||||
|  | bool DetourRemove(void* orig, void* hook) { | ||||||
|  |     if (!orig) { | ||||||
|  |         printf("DetourRemove error: NULL original function pointer\n"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /* Find the hook in our array */ | ||||||
|  |     detour_data_t* data = find_hook_data(orig); | ||||||
|  |     if (!data) { | ||||||
|  |         printf("DetourRemove error: Hook for function %p not found\n", orig); | ||||||
|  |         return false;  /* Not found */ | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /* If hook is specified, make sure it matches */ | ||||||
|  |     if (hook && data->hook != hook) { | ||||||
|  |         printf("DetourRemove error: Hook function mismatch for %p\n", orig); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /* Remove the hook */ | ||||||
|  |     bool result = detour_del(data); | ||||||
|  |     if (!result) { | ||||||
|  |         printf("DetourRemove error: Failed to remove hook for %p\n", orig); | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,142 +1,356 @@ | |||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <cfloat> | #include <string.h> | ||||||
|  |  | ||||||
| #include "features.h" |  | ||||||
| #include "../include/sdk.h" | #include "../include/sdk.h" | ||||||
| #include "../include/cvars.h" |  | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
| #include "../include/game_detection.h" | #include "../include/entityutil.h" | ||||||
|  | #include "../include/mathutil.h" | ||||||
|  | #include "../include/menu.h" | ||||||
|  | #include "../include/settings.h" | ||||||
|  | #include "features.h" | ||||||
|  |  | ||||||
| /* Game units to add to the entity origin to get the head */ | #define HITBOX_HEAD      0 | ||||||
| #define HL1_HEAD_OFFSET 25.f | #define HITBOX_CHEST     1 | ||||||
| #define CS16_HEAD_OFFSET 22.f | #define HITBOX_STOMACH   2 | ||||||
| #define CS16_HORIZONTAL_OFFSET 8.0f | #define HITBOX_PELVIS    3 | ||||||
| #define DOD_HEAD_OFFSET 22.f | #define HITBOX_LEFTARM   4 | ||||||
| #define DOD_HORIZONTAL_OFFSET 8.0f | #define HITBOX_RIGHTARM  5 | ||||||
|  | #define HITBOX_LEFTLEG   6 | ||||||
|  | #define HITBOX_RIGHTLEG  7 | ||||||
|  | #define HITBOX_NEAREST   4 | ||||||
|  | #define MAX_HITBOXES     7 | ||||||
|  |  | ||||||
| /* Scale factor for aim punch */ | #define AIM_PUNCH_MULT 2.0f | ||||||
| #define AIM_PUNCH_MULT 2 |  | ||||||
|  |  | ||||||
| static float vec_length(vec3_t v) { | #define SMOOTHING_FACTOR 3.0f | ||||||
|     return sqrt(v.x * v.x + v.y * v.y + v.z * v.z); |  | ||||||
|  | #define PITCH 0 | ||||||
|  | #define YAW   1 | ||||||
|  | #define ROLL  2 | ||||||
|  |  | ||||||
|  | #define PRIORITY_NONE   0 | ||||||
|  | #define PRIORITY_LOW    1 | ||||||
|  | #define PRIORITY_MEDIUM 2  | ||||||
|  | #define PRIORITY_HIGH   3 | ||||||
|  |  | ||||||
|  | extern const char* hitbox_options[]; | ||||||
|  | extern int current_hitbox; | ||||||
|  |  | ||||||
|  | const char* hitbox_names[] = { | ||||||
|  |     "Head", | ||||||
|  |     "Chest",  | ||||||
|  |     "Stomach", | ||||||
|  |     "Pelvis", | ||||||
|  |     "Nearest Point" | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int current_hitbox = HITBOX_HEAD; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     vec3_t mins; | ||||||
|  |     vec3_t maxs; | ||||||
|  |     vec3_t origin; | ||||||
|  |     float radius; | ||||||
|  | } hitbox_t; | ||||||
|  |  | ||||||
|  | bool get_hitbox(cl_entity_t* ent, int hitbox_index, hitbox_t* out_hitbox) { | ||||||
|  |     if (!ent || !ent->model || !out_hitbox) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     studiohdr_t* studio_model = (studiohdr_t*)i_enginestudio->Mod_Extradata(ent->model); | ||||||
|  |     if (!studio_model) | ||||||
|  |         return false; | ||||||
|  |      | ||||||
|  |     mstudiobbox_t* studio_box = NULL; | ||||||
|  |     if (studio_model->hitboxindex) { | ||||||
|  |         studio_box = (mstudiobbox_t*)((byte*)studio_model + studio_model->hitboxindex); | ||||||
|  |         if (hitbox_index >= studio_model->numhitboxes || hitbox_index < 0) | ||||||
|  |             return false; | ||||||
|  |              | ||||||
|  |         studio_box += hitbox_index; | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     vec_copy(out_hitbox->mins, studio_box->bbmin); | ||||||
|  |     vec_copy(out_hitbox->maxs, studio_box->bbmax); | ||||||
|      |      | ||||||
| static bool is_visible(vec3_t start, vec3_t end) { |     vec3_t center; | ||||||
|     pmtrace_t* tr = i_engine->PM_TraceLine(start, end, PM_TRACELINE_PHYSENTSONLY, 2, -1); |     center.x = (out_hitbox->mins.x + out_hitbox->maxs.x) * 0.5f; | ||||||
|     if (tr->ent <= 0) return false; |     center.y = (out_hitbox->mins.y + out_hitbox->maxs.y) * 0.5f; | ||||||
|     const int ent_idx = i_pmove->physents[tr->ent].info; |     center.z = (out_hitbox->mins.z + out_hitbox->maxs.z) * 0.5f; | ||||||
|     return get_player(ent_idx) != NULL; |      | ||||||
|  |     vec3_t angles; | ||||||
|  |     vec_copy(angles, ent->angles); | ||||||
|  |      | ||||||
|  |     int bone = studio_box->bone; | ||||||
|  |     if (bone >= 0 && bone < studio_model->numbones) { | ||||||
|  |         mstudiobone_t* pbone = (mstudiobone_t*)((byte*)studio_model + studio_model->boneindex); | ||||||
|  |         pbone += bone; | ||||||
|  |          | ||||||
|  |         angles[0] = pbone->value[0];  | ||||||
|  |         angles[1] = pbone->value[1]; | ||||||
|  |         angles[2] = pbone->value[2]; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| static vec3_t get_closest_delta(vec3_t viewangles) { |     vec3_t forward, right, up; | ||||||
|     // Compensate for aim punch |     i_engine->pfnAngleVectors(angles, forward, right, up); | ||||||
|     viewangles.x += g_punchAngles.x * AIM_PUNCH_MULT; |  | ||||||
|     viewangles.y += g_punchAngles.y * AIM_PUNCH_MULT; |  | ||||||
|     viewangles.z += g_punchAngles.z * AIM_PUNCH_MULT; |  | ||||||
|      |      | ||||||
|     vec3_t view_height; |     vec3_t offset; | ||||||
|     i_engine->pEventAPI->EV_LocalPlayerViewheight(view_height); |     offset.x = center.x * forward.x + center.y * right.x + center.z * up.x; | ||||||
|     vec3_t local_eyes = vec_add(localplayer->origin, view_height); |     offset.y = center.x * forward.y + center.y * right.y + center.z * up.y; | ||||||
|  |     offset.z = center.x * forward.z + center.y * right.z + center.z * up.z; | ||||||
|      |      | ||||||
|     float min_distance = FLT_MAX;  // For tracking the closest player |     out_hitbox->origin = vec_add(ent->origin, offset); | ||||||
|     float best_fov = dz_aim_aimbot->value; |      | ||||||
|     vec3_t best_delta = { 0, 0, 0 }; |     if (hitbox_index == HITBOX_HEAD) { | ||||||
|  |         out_hitbox->origin.z += 8.0f; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     vec3_t size; | ||||||
|  |     size.x = fabs(out_hitbox->maxs.x - out_hitbox->mins.x) * 0.5f; | ||||||
|  |     size.y = fabs(out_hitbox->maxs.y - out_hitbox->mins.y) * 0.5f; | ||||||
|  |     size.z = fabs(out_hitbox->maxs.z - out_hitbox->mins.z) * 0.5f; | ||||||
|  |      | ||||||
|  |     out_hitbox->radius = sqrtf(size.x * size.x + size.y * size.y + size.z * size.z); | ||||||
|  |      | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool is_hitbox_visible(vec3_t eye_pos, hitbox_t* hitbox) { | ||||||
|  |     if (!hitbox) | ||||||
|  |         return false; | ||||||
|  |          | ||||||
|  |     pmtrace_t* trace = i_engine->PM_TraceLine(eye_pos, hitbox->origin, PM_TRACELINE_PHYSENTSONLY, 2, -1); | ||||||
|  |      | ||||||
|  |     if (g_settings.aimbot_rage_mode && trace->fraction > 0.5f) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (trace->fraction < 1.0f && trace->ent <= 0) | ||||||
|  |         return false; | ||||||
|  |      | ||||||
|  |     if (trace->ent > 0) { | ||||||
|  |         const int ent_idx = i_pmove->physents[trace->ent].info; | ||||||
|  |         if (get_player(ent_idx)) | ||||||
|  |             return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     cl_entity_t* entity; | ||||||
|  |     float fov; | ||||||
|  |     vec3_t aim_point; | ||||||
|  |     bool is_visible; | ||||||
|  |     int priority; | ||||||
|  |     float distance; | ||||||
|  | } target_t; | ||||||
|  |  | ||||||
|  | int get_target_priority(cl_entity_t* ent) { | ||||||
|  |     if (!ent) | ||||||
|  |         return PRIORITY_NONE; | ||||||
|  |      | ||||||
|  |     if (g_settings.aimbot_rage_mode) { | ||||||
|  |         return PRIORITY_HIGH; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return PRIORITY_MEDIUM; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool get_best_hitbox(cl_entity_t* ent, vec3_t eye_pos, hitbox_t* out_hitbox) { | ||||||
|  |     if (!ent || !out_hitbox) | ||||||
|  |         return false; | ||||||
|  |      | ||||||
|  |     if (current_hitbox == HITBOX_NEAREST) { | ||||||
|  |         float best_distance = 9999.0f; | ||||||
|  |         bool found_hitbox = false; | ||||||
|  |          | ||||||
|  |         for (int i = 0; i < MAX_HITBOXES; i++) { | ||||||
|  |             hitbox_t temp_hitbox; | ||||||
|  |             if (get_hitbox(ent, i, &temp_hitbox)) { | ||||||
|  |                 if (is_hitbox_visible(eye_pos, &temp_hitbox)) { | ||||||
|  |                     vec3_t to_hitbox = vec_sub(temp_hitbox.origin, eye_pos); | ||||||
|  |                     float distance = vec_len2d(to_hitbox); | ||||||
|  |                      | ||||||
|  |                     if (distance < best_distance) { | ||||||
|  |                         best_distance = distance; | ||||||
|  |                         *out_hitbox = temp_hitbox; | ||||||
|  |                         found_hitbox = true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return found_hitbox; | ||||||
|  |     }  | ||||||
|  |     else { | ||||||
|  |         if (get_hitbox(ent, current_hitbox, out_hitbox)) { | ||||||
|  |             return is_hitbox_visible(eye_pos, out_hitbox); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static target_t get_best_target(vec3_t viewangles, vec3_t eye_pos) { | ||||||
|  |     target_t best_target = {NULL, 0.0f, {0, 0, 0}, false, PRIORITY_NONE, 9999.0f}; | ||||||
|  |     float best_score = 0.0f; | ||||||
|  |     float max_fov = g_settings.aimbot_fov; | ||||||
|  |      | ||||||
|  |     if (g_settings.aimbot_rage_mode && max_fov < 90.0f) { | ||||||
|  |         max_fov = 90.0f; | ||||||
|  |     } | ||||||
|      |      | ||||||
|     for (int i = 1; i <= i_engine->GetMaxClients(); i++) { |     for (int i = 1; i <= i_engine->GetMaxClients(); i++) { | ||||||
|         cl_entity_t* ent = get_player(i); |         cl_entity_t* ent = get_player(i); | ||||||
|          |          | ||||||
|         if (!is_alive(ent) || is_friend(ent)) { |         if (!ent || !is_alive(ent)) | ||||||
|             continue; // Skip if not alive or is a friend |             continue; | ||||||
|  |              | ||||||
|  |         if (!g_settings.aimbot_friendly_fire && is_friend(ent)) | ||||||
|  |             continue; | ||||||
|  |          | ||||||
|  |         hitbox_t target_hitbox; | ||||||
|  |         bool hitbox_found = false; | ||||||
|  |          | ||||||
|  |         hitbox_found = get_best_hitbox(ent, eye_pos, &target_hitbox); | ||||||
|  |          | ||||||
|  |         if (!hitbox_found) | ||||||
|  |             continue; | ||||||
|  |          | ||||||
|  |         vec3_t to_target = vec_sub(target_hitbox.origin, eye_pos); | ||||||
|  |         vec3_t aim_angles = vec_to_ang(to_target); | ||||||
|  |          | ||||||
|  |         vec3_t angle_delta = vec_sub(aim_angles, viewangles); | ||||||
|  |         vec_norm(&angle_delta); | ||||||
|  |         ang_clamp(&angle_delta); | ||||||
|  |          | ||||||
|  |         float fov_distance = sqrtf(angle_delta.x * angle_delta.x + angle_delta.y * angle_delta.y); | ||||||
|  |          | ||||||
|  |         if (fov_distance > max_fov) | ||||||
|  |             continue; | ||||||
|  |          | ||||||
|  |         float distance = sqrtf(to_target.x * to_target.x + to_target.y * to_target.y + to_target.z * to_target.z); | ||||||
|  |              | ||||||
|  |         float fov_score = 1.0f - (fov_distance / max_fov); | ||||||
|  |          | ||||||
|  |         float priority_score = 0.0f; | ||||||
|  |         if (g_settings.aimbot_rage_mode) { | ||||||
|  |             int priority = get_target_priority(ent); | ||||||
|  |             priority_score = priority / (float)PRIORITY_HIGH; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         vec3_t head_pos = ent->origin; |         float final_score = fov_score; | ||||||
|  |         if (g_settings.aimbot_rage_mode) { | ||||||
|  |             final_score = (fov_score * 0.5f) + (priority_score * 0.5f); | ||||||
|  |         } | ||||||
|          |          | ||||||
|         if (ent->curstate.usehull != 1) {  // Not crouched |         if (final_score > best_score) { | ||||||
|             if (IsCS16()) { |             best_score = final_score; | ||||||
|                 head_pos.z += CS16_HEAD_OFFSET; |             best_target.entity = ent; | ||||||
|                 head_pos.x += CS16_HORIZONTAL_OFFSET; |             best_target.fov = fov_distance; | ||||||
|             } else if (IsDayOfDefeat()) { |             vec_copy(best_target.aim_point, target_hitbox.origin); | ||||||
|                 head_pos.z += DOD_HEAD_OFFSET; |             best_target.is_visible = true; | ||||||
|                 head_pos.x += DOD_HORIZONTAL_OFFSET; |             best_target.priority = get_target_priority(ent); | ||||||
|             } else { |             best_target.distance = distance; | ||||||
|                 head_pos.z += HL1_HEAD_OFFSET; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     return best_target; | ||||||
|          |  | ||||||
|         float distance = vec_length(vec_sub(ent->origin, local_eyes)); |  | ||||||
|         if (distance > min_distance) { |  | ||||||
|             continue; // Skip players that are further than the current closest target |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const vec3_t enemy_angle = vec_to_ang(vec_sub(head_pos, local_eyes)); |  | ||||||
|         const vec3_t delta = vec_sub(enemy_angle, viewangles); |  | ||||||
|         vec_norm(delta); |  | ||||||
|  |  | ||||||
|         float fov = hypotf(delta.x, delta.y); |  | ||||||
|         if (fov > 360.0f) { |  | ||||||
|             fov = remainderf(fov, 360.0f); |  | ||||||
|         } |  | ||||||
|         if (fov > 180.0f) { |  | ||||||
|             fov = 360.0f - fov; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Only check visibility for potential targets |  | ||||||
|         if (fov < best_fov && is_visible(local_eyes, head_pos)) { |  | ||||||
|             best_fov = fov; |  | ||||||
|             vec_copy(best_delta, delta); |  | ||||||
|             min_distance = distance;  // Update the closest target's distance |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return best_delta; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void aimbot(usercmd_t* cmd) { | void aimbot(usercmd_t* cmd) { | ||||||
|     static bool shouldShootNextFrame = false;  // If you're not using this variable, you can remove it. |     if (!g_settings.aimbot_enabled) | ||||||
|     static bool hasAdjustedView = false; |  | ||||||
|  |  | ||||||
|     if (!CVAR_ON(aim_aimbot) || !can_shoot()) |  | ||||||
|         return; |         return; | ||||||
|      |      | ||||||
|  |     bool should_run_aimbot = true; | ||||||
|  |     bool should_autoshoot = g_settings.aimbot_autoshoot; | ||||||
|  |      | ||||||
|  |     switch (0) { | ||||||
|  |         case 0: | ||||||
|  |             should_run_aimbot = true; | ||||||
|  |             break; | ||||||
|  |         case 1: | ||||||
|  |             should_run_aimbot = (cmd->buttons & IN_ATTACK) != 0; | ||||||
|  |             break; | ||||||
|  |         case 2: | ||||||
|  |             should_run_aimbot = (cmd->buttons & IN_ATTACK2) != 0; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             should_run_aimbot = true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (!should_run_aimbot && !g_settings.aimbot_rage_mode) | ||||||
|  |         return; | ||||||
|  |      | ||||||
|  |     if (g_settings.aimbot_rage_mode) | ||||||
|  |         should_run_aimbot = true; | ||||||
|  |      | ||||||
|  |     bool can_fire = can_shoot(); | ||||||
|  |      | ||||||
|  |     vec3_t view_height; | ||||||
|  |     i_engine->pEventAPI->EV_LocalPlayerViewheight(view_height); | ||||||
|  |     vec3_t eye_pos = vec_add(localplayer->origin, view_height); | ||||||
|  |      | ||||||
|     vec3_t engine_viewangles; |     vec3_t engine_viewangles; | ||||||
|     i_engine->GetViewAngles(engine_viewangles); |     i_engine->GetViewAngles(engine_viewangles); | ||||||
|     vec3_t best_delta = get_closest_delta(engine_viewangles); |  | ||||||
|      |      | ||||||
|     if (!vec_is_zero(best_delta)) { |     vec3_t adjusted_viewangles = engine_viewangles; | ||||||
|         /* |     if (g_settings.aimbot_norecoil) { | ||||||
|         if (!lastShotHit) { |         adjusted_viewangles.x += g_punchAngles.x * AIM_PUNCH_MULT; | ||||||
|             // If the last shot missed, adjust the angle slightly |         adjusted_viewangles.y += g_punchAngles.y * AIM_PUNCH_MULT; | ||||||
|             // This is a simple approach and might need further tweaking |         adjusted_viewangles.z += g_punchAngles.z * AIM_PUNCH_MULT; | ||||||
|             best_delta.y += 0.5f;  // Adjust yaw slightly |  | ||||||
|     } |     } | ||||||
|         */ |  | ||||||
|         engine_viewangles.x += best_delta.x; |  | ||||||
|         engine_viewangles.y += best_delta.y; |  | ||||||
|         engine_viewangles.z += best_delta.z; |  | ||||||
|      |      | ||||||
|         if (CVAR_ON(aim_aimbot_silent)) { |     target_t best_target = get_best_target(adjusted_viewangles, eye_pos); | ||||||
|             vec_copy(cmd->viewangles, engine_viewangles); |      | ||||||
|             if (cmd->buttons & IN_ATTACK) { |     if (best_target.entity && best_target.is_visible) { | ||||||
|  |         vec3_t to_target = vec_sub(best_target.aim_point, eye_pos); | ||||||
|  |         vec3_t aim_angles = vec_to_ang(to_target); | ||||||
|  |          | ||||||
|  |         vec3_t delta = vec_sub(aim_angles, engine_viewangles); | ||||||
|  |         vec_norm(&delta); | ||||||
|  |         ang_clamp(&delta); | ||||||
|  |          | ||||||
|  |         if (g_settings.aimbot_silent) { | ||||||
|  |             cmd->viewangles.x = engine_viewangles.x + delta.x; | ||||||
|  |             cmd->viewangles.y = engine_viewangles.y + delta.y; | ||||||
|  |             cmd->viewangles.z = engine_viewangles.z + delta.z; | ||||||
|  |         } else { | ||||||
|  |             float smoothing = SMOOTHING_FACTOR; | ||||||
|  |              | ||||||
|  |             smoothing = g_settings.aimbot_smooth > 0 ? g_settings.aimbot_smooth : SMOOTHING_FACTOR; | ||||||
|  |              | ||||||
|  |             if (g_settings.aimbot_rage_mode) { | ||||||
|  |                 smoothing = 1.2f; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             engine_viewangles.x += delta.x / smoothing; | ||||||
|  |             engine_viewangles.y += delta.y / smoothing; | ||||||
|  |             engine_viewangles.z += delta.z / smoothing; | ||||||
|  |              | ||||||
|  |             ang_clamp(&engine_viewangles); | ||||||
|  |              | ||||||
|  |             i_engine->SetViewAngles(engine_viewangles); | ||||||
|  |              | ||||||
|  |             cmd->viewangles.x = engine_viewangles.x; | ||||||
|  |             cmd->viewangles.y = engine_viewangles.y; | ||||||
|  |             cmd->viewangles.z = engine_viewangles.z; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (should_autoshoot && can_fire) { | ||||||
|  |             if (g_settings.aimbot_rage_mode) { | ||||||
|  |                 cmd->buttons |= IN_ATTACK; | ||||||
|  |             } else { | ||||||
|  |                 float aim_error = sqrtf(delta.x * delta.x + delta.y * delta.y); | ||||||
|  |                 if (aim_error < 5.0f) { | ||||||
|                     cmd->buttons |= IN_ATTACK; |                     cmd->buttons |= IN_ATTACK; | ||||||
|                 } |                 } | ||||||
|         } else { |  | ||||||
|             if (cmd->buttons & IN_ATTACK) {   |  | ||||||
|                 if (hasAdjustedView) { |  | ||||||
|                     hasAdjustedView = false; // Reset flag |  | ||||||
|                 } else { |  | ||||||
|                     i_engine->SetViewAngles(engine_viewangles); |  | ||||||
|                     hasAdjustedView = true; |  | ||||||
|                     cmd->buttons &= ~IN_ATTACK; // Defer the shot to the next frame |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         } |     } else if (should_autoshoot) { | ||||||
|     } else if (CVAR_ON(aim_autoshoot) && (cmd->buttons & IN_ATTACK)) { |  | ||||||
|         cmd->buttons &= ~IN_ATTACK; |         cmd->buttons &= ~IN_ATTACK; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ | |||||||
|  |  | ||||||
| #include "features.h" | #include "features.h" | ||||||
| #include "../include/sdk.h" | #include "../include/sdk.h" | ||||||
| #include "../include/cvars.h" | #include "../include/settings.h" | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
|  |  | ||||||
| float random_float(float min, float max) { | float random_float(float min, float max) { | ||||||
| @@ -16,7 +16,7 @@ float random_float(float min, float max) { | |||||||
| bool isSpacebarPressed() { | bool isSpacebarPressed() { | ||||||
|     Display* display = XOpenDisplay(NULL); |     Display* display = XOpenDisplay(NULL); | ||||||
|     if (!display) { |     if (!display) { | ||||||
|         return false;  // Could not open the display, assume not pressed |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     char keys_return[32]; |     char keys_return[32]; | ||||||
| @@ -38,7 +38,7 @@ void anti_aim(usercmd_t* cmd) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!CVAR_ON(movement_antiaim)) { |     if (!g_settings.antiaim) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -68,8 +68,7 @@ void anti_aim(usercmd_t* cmd) { | |||||||
|     bool isBunnyHopping = cmd->buttons & IN_JUMP; |     bool isBunnyHopping = cmd->buttons & IN_JUMP; | ||||||
|     bool isStationary = (cmd->forwardmove == 0.0f && cmd->sidemove == 0.0f); |     bool isStationary = (cmd->forwardmove == 0.0f && cmd->sidemove == 0.0f); | ||||||
|      |      | ||||||
|     // This shit busted right now |     if (g_settings.fakeduck && (isStationary || isBunnyHopping || isSpacebarPressed())) { | ||||||
|     if (CVAR_ON(movement_fakeduck) && (isStationary || isBunnyHopping || isSpacebarPressed())) { |  | ||||||
|         static int duckCounter = 0; |         static int duckCounter = 0; | ||||||
|         if (duckCounter < 2) { |         if (duckCounter < 2) { | ||||||
|             cmd->buttons |= IN_DUCK; |             cmd->buttons |= IN_DUCK; | ||||||
| @@ -84,7 +83,7 @@ void anti_aim(usercmd_t* cmd) { | |||||||
|     if (view_angles.y > 180.0f) view_angles.y -= 360.0f; |     if (view_angles.y > 180.0f) view_angles.y -= 360.0f; | ||||||
|     if (view_angles.y < -180.0f) view_angles.y += 360.0f; |     if (view_angles.y < -180.0f) view_angles.y += 360.0f; | ||||||
|  |  | ||||||
|     if (CVAR_ON(movement_antiaim_view)) { |     if (g_settings.antiaim_view) { | ||||||
|         i_engine->SetViewAngles(view_angles); |         i_engine->SetViewAngles(view_angles); | ||||||
|         i_engine->pfnClientCmd("echo \"Set view angles directly using movement_antiaim_view.\""); |         i_engine->pfnClientCmd("echo \"Set view angles directly using movement_antiaim_view.\""); | ||||||
|     } else { |     } else { | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
|  |  | ||||||
| #include "features.h" | #include "features.h" | ||||||
| #include "../include/globals.h" | #include "../include/globals.h" | ||||||
| #include "../include/cvars.h" | #include "../include/settings.h" | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
|  |  | ||||||
| #include <GL/gl.h> | #include <GL/gl.h> | ||||||
| @@ -15,7 +14,7 @@ enum chams_settings { | |||||||
| visible_flags visible_mode; | visible_flags visible_mode; | ||||||
|  |  | ||||||
| bool chams(void* this_ptr) { | bool chams(void* this_ptr) { | ||||||
|     const int setting = dz_visuals_chams->value == 5.0f ? 7 : dz_visuals_chams->value; |     const int setting = g_settings.chams ? PLAYER_CHAMS : DISABLED; | ||||||
|     if (setting == DISABLED) |     if (setting == DISABLED) | ||||||
|         return false; |         return false; | ||||||
|  |  | ||||||
| @@ -39,8 +38,7 @@ bool chams(void* this_ptr) { | |||||||
|  |  | ||||||
|     const bool friendly = is_friend(ent); |     const bool friendly = is_friend(ent); | ||||||
|  |  | ||||||
|     // Check if the player is friendly and if visuals_friendly is 0 |     if (friendly && !g_settings.esp_friendly) | ||||||
|     if (friendly && dz_visuals_friendly->value == 0) |  | ||||||
|         return false;  // Do not render chams for friendlies |         return false;  // Do not render chams for friendlies | ||||||
|  |  | ||||||
|     /* If we got here it means we are rendering a valid player */ |     /* If we got here it means we are rendering a valid player */ | ||||||
|   | |||||||
| @@ -1,18 +1,11 @@ | |||||||
|  |  | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include "features.h" | #include "features.h" | ||||||
| #include "../include/globals.h" | #include "../include/globals.h" | ||||||
| #include "../include/cvars.h" | #include "../include/settings.h" | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
| #include "../include/game_detection.h" | #include "../include/game_detection.h" | ||||||
|  |  | ||||||
| /* For dz_esp */ | // ESP enums moved to settings.h as esp_mode_t | ||||||
| enum esp_values { |  | ||||||
|     ESP_OFF  = 0, |  | ||||||
|     ESP_BOX  = 1, |  | ||||||
|     ESP_NAME = 2, |  | ||||||
|     /* ESP_ALL should be 3 but we can just OR box and name */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| bool gl_draw3dbox(vec3_t o, int bh, int bw, int lw) { | bool gl_draw3dbox(vec3_t o, int bh, int bw, int lw) { | ||||||
|     /* |     /* | ||||||
| @@ -99,7 +92,7 @@ static bool gl_draw2dbox(vec3_t o, int bh) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void esp(void) { | void esp(void) { | ||||||
|     const int setting = (int)dz_visuals_esp->value; |     const int setting = g_settings.esp_mode; | ||||||
|     if (setting == ESP_OFF) |     if (setting == ESP_OFF) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
| @@ -109,7 +102,7 @@ void esp(void) { | |||||||
|         if (!valid_player(ent) || !is_alive(ent) || vec_is_zero(ent->origin)) |         if (!valid_player(ent) || !is_alive(ent) || vec_is_zero(ent->origin)) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         if (is_friend(ent) && dz_visuals_friendly->value == 0) |         if (is_friend(ent) && !g_settings.esp_friendly) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         int bh = 70; |         int bh = 70; | ||||||
|   | |||||||
| @@ -1,4 +1,3 @@ | |||||||
|  |  | ||||||
| #ifndef FEATURES_H_ | #ifndef FEATURES_H_ | ||||||
| #define FEATURES_H_ | #define FEATURES_H_ | ||||||
|  |  | ||||||
| @@ -11,8 +10,13 @@ enum visible_flags { | |||||||
|     FRIEND_VISIBLE     = 3, |     FRIEND_VISIBLE     = 3, | ||||||
|     FRIEND_NOT_VISIBLE = 4, |     FRIEND_NOT_VISIBLE = 4, | ||||||
|     HANDS              = 5, |     HANDS              = 5, | ||||||
|  |     SCOPE              = 6, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
| /* src/features/movement.c */ | /* src/features/movement.c */ | ||||||
| @@ -42,4 +46,13 @@ void anti_aim(usercmd_t* cmd); | |||||||
| /* src/features/fov.c */ | /* src/features/fov.c */ | ||||||
| void fov_adjust(usercmd_t* cmd); | void fov_adjust(usercmd_t* cmd); | ||||||
|  |  | ||||||
|  | /* src/features/thirdperson.c */ | ||||||
|  | void thirdperson_init(void); | ||||||
|  | void thirdperson_update(void); | ||||||
|  | bool thirdperson_key_event(int keynum, int down); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif /* FEATURES_H_ */ | #endif /* FEATURES_H_ */ | ||||||
| @@ -2,9 +2,9 @@ | |||||||
| #include "../include/globals.h" | #include "../include/globals.h" | ||||||
| #include "../include/sdk.h" | #include "../include/sdk.h" | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
|  | #include "../include/settings.h" | ||||||
| #include "features.h" | #include "features.h" | ||||||
|  |  | ||||||
| extern cvar_t* dz_visuals_fov; |  | ||||||
| extern float* scr_fov_value; | extern float* scr_fov_value; | ||||||
|  |  | ||||||
| void fov_adjust(usercmd_t* cmd) { | void fov_adjust(usercmd_t* cmd) { | ||||||
| @@ -13,7 +13,7 @@ void fov_adjust(usercmd_t* cmd) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (dz_visuals_fov->value) { |     if (g_settings.fov > 0) { | ||||||
|         *scr_fov_value = dz_visuals_fov->value; |         *scr_fov_value = g_settings.fov; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,13 +1,12 @@ | |||||||
|  |  | ||||||
| #include "features.h" | #include "features.h" | ||||||
| #include "../include/sdk.h" | #include "../include/sdk.h" | ||||||
| #include "../include/globals.h" | #include "../include/globals.h" | ||||||
| #include "../include/cvars.h" |  | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
| #include "../include/game_detection.h" | #include "../include/game_detection.h" | ||||||
|  | #include "../include/settings.h" | ||||||
|  |  | ||||||
| void custom_crosshair(void) { | void custom_crosshair(void) { | ||||||
|     if (!CVAR_ON(visuals_crosshair)) |     if (!g_settings.custom_crosshair) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     /* Get window size, and then the center. */ |     /* Get window size, and then the center. */ | ||||||
| @@ -15,7 +14,7 @@ void custom_crosshair(void) { | |||||||
|     int my = game_info->m_height / 2; |     int my = game_info->m_height / 2; | ||||||
|  |  | ||||||
|     /* The real length is sqrt(2 * (len^2)) */ |     /* The real length is sqrt(2 * (len^2)) */ | ||||||
|     const int len   = dz_visuals_crosshair->value; |     const int len   = 5; | ||||||
|     const int gap   = 1; |     const int gap   = 1; | ||||||
|     const float w   = 1; |     const float w   = 1; | ||||||
|     const rgb_t col = { 255, 255, 255 }; |     const rgb_t col = { 255, 255, 255 }; | ||||||
| @@ -37,7 +36,7 @@ static double lastTracerTime = 0; | |||||||
| static bool attackReleased = true; | static bool attackReleased = true; | ||||||
|  |  | ||||||
| void bullet_tracers(usercmd_t* cmd) { | void bullet_tracers(usercmd_t* cmd) { | ||||||
|     if (!CVAR_ON(visuals_tracers) || !is_alive(localplayer)) |     if (!g_settings.tracers || !is_alive(localplayer)) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     if (IsCS16()) { |     if (IsCS16()) { | ||||||
|   | |||||||
| @@ -1,11 +1,10 @@ | |||||||
|  |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
|  |  | ||||||
| #include "features.h" | #include "features.h" | ||||||
| #include "../include/sdk.h" | #include "../include/sdk.h" | ||||||
| #include "../include/globals.h" | #include "../include/globals.h" | ||||||
| #include "../include/cvars.h" | #include "../include/settings.h" | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
|  |  | ||||||
| static void autostrafe_legit(usercmd_t* cmd) { | static void autostrafe_legit(usercmd_t* cmd) { | ||||||
| @@ -65,7 +64,7 @@ static void autostrafe_rage(usercmd_t* cmd) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void bhop(usercmd_t* cmd) { | void bhop(usercmd_t* cmd) { | ||||||
|     if (!CVAR_ON(movement_bhop) || i_pmove->movetype != MOVETYPE_WALK) |     if (!g_settings.bhop || i_pmove->movetype != MOVETYPE_WALK) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     static bool was_in_air = false; |     static bool was_in_air = false; | ||||||
| @@ -81,18 +80,8 @@ void bhop(usercmd_t* cmd) { | |||||||
|     was_in_air = (i_pmove->flags & FL_ONGROUND) == 0; |     was_in_air = (i_pmove->flags & FL_ONGROUND) == 0; | ||||||
|  |  | ||||||
|     /* Autostrafe if enabled. Check if we are in the air and holding space. */ |     /* Autostrafe if enabled. Check if we are in the air and holding space. */ | ||||||
|     if (is_jumping) { |     if (is_jumping && g_settings.autostrafe) { | ||||||
|         switch ((int)dz_movement_autostrafe->value) { |  | ||||||
|             case 1: |  | ||||||
|         autostrafe_rage(cmd); |         autostrafe_rage(cmd); | ||||||
|                 break; |  | ||||||
|             case 2: |  | ||||||
|                 autostrafe_legit(cmd); |  | ||||||
|                 break; |  | ||||||
|             case 0: |  | ||||||
|             default: |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| #include <vector> | #include <vector> | ||||||
| #include "features.h" | #include "features.h" | ||||||
| #include "../include/globals.h" | #include "../include/globals.h" | ||||||
| #include "../include/cvars.h" | #include "../include/settings.h" | ||||||
| #include "../include/util.h" | #include "../include/util.h" | ||||||
| #include "../include/game_detection.h" | #include "../include/game_detection.h" | ||||||
|  |  | ||||||
| @@ -70,14 +70,20 @@ void change_name_all_players() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void change_name_based_on_mode(usercmd_t* cmd) { | void change_name_based_on_mode(usercmd_t* cmd) { | ||||||
|     if (!CVAR_ON(misc_namechanger)) return; |     if (!g_settings.namechanger) return; | ||||||
|  |  | ||||||
|     if (++change_counter < dz_misc_namechanger_speed->value) { |     if (++change_counter < g_settings.namechanger_speed) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     change_counter = 0; |     change_counter = 0; | ||||||
|  |  | ||||||
|     switch ((int)dz_misc_namechanger->value) { |     int mode = 3; | ||||||
|  |      | ||||||
|  |     if (g_settings.namechanger) { | ||||||
|  |         mode = 3; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     switch (mode) { | ||||||
|         case 1: |         case 1: | ||||||
|             change_name_teammates(); |             change_name_teammates(); | ||||||
|             break; |             break; | ||||||
| @@ -93,7 +99,7 @@ void change_name_based_on_mode(usercmd_t* cmd) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void check_namechanger_mode_and_execute(usercmd_t* cmd) { | void check_namechanger_mode_and_execute(usercmd_t* cmd) { | ||||||
|     if (!CVAR_ON(misc_namechanger)) return; |     if (!g_settings.namechanger) return; | ||||||
|  |  | ||||||
|     change_name_based_on_mode(cmd); |     change_name_based_on_mode(cmd); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								src/features/no_recoil.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/features/no_recoil.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | #include "../include/sdk.h" | ||||||
|  | #include "../include/settings.h" | ||||||
|  | #include "../include/util.h" | ||||||
|  | #include "../include/globals.h" | ||||||
|  | #include <stdio.h> // For printf | ||||||
|  | #include <time.h>  // For time | ||||||
|  |  | ||||||
|  | static time_t last_log_time = 0; | ||||||
|  |  | ||||||
|  | void no_recoil(usercmd_t* cmd) { | ||||||
|  |     if (!g_settings.aimbot_norecoil || !is_alive(localplayer)) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     time_t current_time = time(NULL); | ||||||
|  |     if (current_time - last_log_time >= 5) { | ||||||
|  |         printf("Applying anti-recoil: Punch Angles (X: %f, Y: %f)\n", g_punchAngles[0], g_punchAngles[1]); | ||||||
|  |         last_log_time = current_time; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     float anti_recoil_value = 100.0f; | ||||||
|  |     cmd->viewangles[0] -= (g_punchAngles[0] * anti_recoil_value); | ||||||
|  |     cmd->viewangles[1] -= (g_punchAngles[1] * anti_recoil_value); | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								src/features/no_recoil.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/features/no_recoil.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | #ifndef NO_RECOIL_H | ||||||
|  | #define NO_RECOIL_H | ||||||
|  |  | ||||||
|  | #include "../include/sdk.h" | ||||||
|  |  | ||||||
|  | void aim_no_recoil(usercmd_t* cmd); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										122
									
								
								src/features/thirdperson.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/features/thirdperson.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | #include "../include/sdk.h" | ||||||
|  | #include "../include/settings.h" | ||||||
|  | #include "../include/globals.h" | ||||||
|  | #include "../include/util.h" | ||||||
|  | #include "thirdperson.h" | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | #define TP_MIN_DIST 30.0f | ||||||
|  | #define TP_MAX_DIST 800.0f | ||||||
|  | #define TP_DEFAULT_DIST 150.0f | ||||||
|  |  | ||||||
|  | #define YAW   1 | ||||||
|  | #define PITCH 0 | ||||||
|  | #define ROLL  2 | ||||||
|  |  | ||||||
|  | static bool s_initialized = false; | ||||||
|  | static bool s_thirdperson_enabled = false; | ||||||
|  | static vec3_t s_camera_origin = {0, 0, 0}; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void thirdperson_init(void) { | ||||||
|  |     s_initialized = true; | ||||||
|  |     s_thirdperson_enabled = false; | ||||||
|  |     i_engine->Con_Printf("Third-person system initialized\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void thirdperson_toggle(void) { | ||||||
|  |     g_settings.thirdperson = !g_settings.thirdperson; | ||||||
|  |     s_thirdperson_enabled = g_settings.thirdperson; | ||||||
|  |      | ||||||
|  |     if (s_thirdperson_enabled) { | ||||||
|  |         i_engine->Con_Printf("Third-person view enabled (distance: %.1f)\n", g_settings.thirdperson_dist); | ||||||
|  |     } else { | ||||||
|  |         i_engine->Con_Printf("Third-person view disabled\n"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool thirdperson_key_event(int keynum, int down) { | ||||||
|  |     if (down && (keynum == 'C' || keynum == 'c' || keynum == 99)) { | ||||||
|  |         thirdperson_toggle(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (down && keynum == g_settings.thirdperson_key &&  | ||||||
|  |         g_settings.thirdperson_key != 'C' && g_settings.thirdperson_key != 'c') { | ||||||
|  |         thirdperson_toggle(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void thirdperson_modify_view(ref_params_t* pparams) { | ||||||
|  |     if (!g_settings.thirdperson) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     float distance = g_settings.thirdperson_dist; | ||||||
|  |      | ||||||
|  |     vec3_t forward, right, up; | ||||||
|  |      | ||||||
|  |     i_engine->pfnAngleVectors(pparams->viewangles, forward, right, up); | ||||||
|  |      | ||||||
|  |     vec3_t camera_offset; | ||||||
|  |     for (int i = 0; i < 3; i++) { | ||||||
|  |         camera_offset[i] = -forward[i] * distance; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     vec3_t newOrigin; | ||||||
|  |     for (int i = 0; i < 3; i++) { | ||||||
|  |         newOrigin[i] = pparams->vieworg[i] + camera_offset[i]; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     vec_copy(s_camera_origin, newOrigin); | ||||||
|  |      | ||||||
|  |     pmtrace_t trace; | ||||||
|  |     i_engine->pEventAPI->EV_SetTraceHull(2); | ||||||
|  |     i_engine->pEventAPI->EV_PlayerTrace(pparams->vieworg, newOrigin, PM_NORMAL, -1, &trace); | ||||||
|  |      | ||||||
|  |     if (trace.fraction < 1.0) { | ||||||
|  |         vec3_t dir; | ||||||
|  |         for (int i = 0; i < 3; i++) { | ||||||
|  |             dir[i] = newOrigin[i] - pparams->vieworg[i]; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         float len = sqrtf(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); | ||||||
|  |         if (len > 0) { | ||||||
|  |             for (int i = 0; i < 3; i++) { | ||||||
|  |                 dir[i] /= len; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         vec3_t collisionPoint; | ||||||
|  |         for (int i = 0; i < 3; i++) { | ||||||
|  |             collisionPoint[i] = pparams->vieworg[i] + (trace.fraction * distance - 5.0f) * forward[i]; | ||||||
|  |         } | ||||||
|  |         vec_copy(newOrigin, collisionPoint); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     vec_copy(pparams->vieworg, newOrigin); | ||||||
|  |      | ||||||
|  |     static int debug_count = 0; | ||||||
|  |     if (++debug_count % 300 == 0) { | ||||||
|  |         i_engine->Con_Printf("Camera position: [%.1f, %.1f, %.1f], distance=%.1f\n",  | ||||||
|  |                            newOrigin[0], newOrigin[1], newOrigin[2], distance); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void thirdperson_update(void) { | ||||||
|  |     s_thirdperson_enabled = g_settings.thirdperson; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int thirdperson_is_active(void) { | ||||||
|  |     return g_settings.thirdperson ? 1 : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif  | ||||||
							
								
								
									
										28
									
								
								src/features/thirdperson.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/features/thirdperson.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | #ifndef THIRDPERSON_H_ | ||||||
|  | #define THIRDPERSON_H_ | ||||||
|  |  | ||||||
|  | #include "../include/sdk.h" | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void thirdperson_init(void); | ||||||
|  |  | ||||||
|  | int thirdperson_is_active(void); | ||||||
|  |  | ||||||
|  | void thirdperson_get_offset(float* offset); | ||||||
|  |  | ||||||
|  | void thirdperson_update(void); | ||||||
|  |  | ||||||
|  | void thirdperson_toggle(void); | ||||||
|  |  | ||||||
|  | bool thirdperson_key_event(int keynum, int down); | ||||||
|  |  | ||||||
|  | void thirdperson_modify_view(ref_params_t* pparams); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -2,7 +2,7 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <dlfcn.h> | #include <dlfcn.h> | ||||||
| #include <sys/mman.h> /* PROT_* */ | #include <sys/mman.h> | ||||||
|  |  | ||||||
| #include "include/globals.h" | #include "include/globals.h" | ||||||
| #include "include/sdk.h" | #include "include/sdk.h" | ||||||
| @@ -11,7 +11,6 @@ | |||||||
| game_id this_game_id = HL; | game_id this_game_id = HL; | ||||||
| vec3_t g_punchAngles = { 0, 0, 0 }; | vec3_t g_punchAngles = { 0, 0, 0 }; | ||||||
|  |  | ||||||
| /* Weapon info */ |  | ||||||
| float g_flNextAttack = 0.f, g_flNextPrimaryAttack = 0.f; | float g_flNextAttack = 0.f, g_flNextPrimaryAttack = 0.f; | ||||||
| int g_iClip = 0; | int g_iClip = 0; | ||||||
|  |  | ||||||
| @@ -26,13 +25,10 @@ DECL_INTF(playermove_t, pmove); | |||||||
| DECL_INTF(engine_studio_api_t, enginestudio); | DECL_INTF(engine_studio_api_t, enginestudio); | ||||||
| DECL_INTF(StudioModelRenderer_t, studiomodelrenderer); | DECL_INTF(StudioModelRenderer_t, studiomodelrenderer); | ||||||
|  |  | ||||||
| /* Game struct with some useful info */ |  | ||||||
| game_t* game_info; | game_t* game_info; | ||||||
|  |  | ||||||
| /* Array of extra_player_info's for each player */ |  | ||||||
| void* player_extra_info; | void* player_extra_info; | ||||||
|  |  | ||||||
| /* Updated in CL_CreateMove hook */ |  | ||||||
| cl_entity_t* localplayer = NULL; | cl_entity_t* localplayer = NULL; | ||||||
|  |  | ||||||
| float* scr_fov_value = NULL; | float* scr_fov_value = NULL; | ||||||
| @@ -40,11 +36,6 @@ float* scr_fov_value = NULL; | |||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
| bool globals_init(void) { | bool globals_init(void) { | ||||||
|     /* |  | ||||||
|      * Get handler for hw.so |  | ||||||
|      *  RTLD_LAZY: If the symbol is never referenced, then it is never resolved. |  | ||||||
|      *  RTLD_NOLOAD: Don't load the shared object. |  | ||||||
|      */ |  | ||||||
|     hw = dlopen("hw.so", RTLD_LAZY | RTLD_NOLOAD); |     hw = dlopen("hw.so", RTLD_LAZY | RTLD_NOLOAD); | ||||||
|     if (!hw) { |     if (!hw) { | ||||||
|         printf("goldsource-cheat: globals_init: can't open hw.so\n"); |         printf("goldsource-cheat: globals_init: can't open hw.so\n"); | ||||||
| @@ -57,7 +48,6 @@ bool globals_init(void) { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Get symbol addresses using dlsym and the handler we just opened */ |  | ||||||
|     i_engine       = (cl_enginefunc_t*)dlsym(hw, "cl_enginefuncs"); |     i_engine       = (cl_enginefunc_t*)dlsym(hw, "cl_enginefuncs"); | ||||||
|     i_client       = (cl_clientfunc_t*)dlsym(hw, "cl_funcs"); |     i_client       = (cl_clientfunc_t*)dlsym(hw, "cl_funcs"); | ||||||
|     i_pmove        = *(playermove_t**)dlsym(hw, "pmove"); |     i_pmove        = *(playermove_t**)dlsym(hw, "pmove"); | ||||||
|   | |||||||
							
								
								
									
										446
									
								
								src/hooks.c
									
									
									
									
									
								
							
							
						
						
									
										446
									
								
								src/hooks.c
									
									
									
									
									
								
							| @@ -1,11 +1,43 @@ | |||||||
|  | #include <stdio.h> | ||||||
|  | #include <math.h> | ||||||
|  |  | ||||||
|  | #include "include/settings.h" | ||||||
| #include "include/hooks.h" | #include "include/hooks.h" | ||||||
| #include "include/sdk.h" |  | ||||||
| #include "include/globals.h" |  | ||||||
| #include "include/util.h" | #include "include/util.h" | ||||||
| #include "include/cvars.h" | #include "include/sdk.h" | ||||||
| #include "include/detour.h"    /* 8dcc/detour-lib */ | #include "include/detour.h"    /* 8dcc/detour-lib */ | ||||||
|  | #include "include/main.h"      /* For self_unload() */ | ||||||
|  | #include "include/menu.h"      /* ImGui menu */ | ||||||
| #include "features/features.h" /* bhop(), esp(), etc. */ | #include "features/features.h" /* bhop(), esp(), etc. */ | ||||||
|  | #include "include/entityutil.h" | ||||||
|  | #include "include/game_detection.h" | ||||||
|  | #include "features/thirdperson.h" | ||||||
|  |  | ||||||
|  | // For ImGui context access | ||||||
|  | #define IMGUI_IMPLEMENTATION | ||||||
|  | #include "include/imgui/imgui.h" | ||||||
|  | #include "include/imgui/backends/imgui_impl_opengl2.h" | ||||||
|  |  | ||||||
|  | // Include for mouse button constants | ||||||
|  | #include "include/sdk/public/keydefs.h" | ||||||
|  |  | ||||||
|  | #include <dlfcn.h> | ||||||
|  | #include <GL/gl.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <unistd.h> // usleep() | ||||||
|  |  | ||||||
|  | // For DetourFunction and DetourRemove | ||||||
|  | extern void* DetourFunction(void* orig, void* hook); | ||||||
|  | extern bool DetourRemove(void* orig, void* hook); | ||||||
|  |  | ||||||
|  | // Define BYTE as unsigned char for GL hooks | ||||||
|  | typedef unsigned char BYTE; | ||||||
|  |  | ||||||
|  | /* Forward declarations of hook functions */ | ||||||
|  | void h_glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); | ||||||
|  | void h_CL_Move(void); | ||||||
|  | int h_CL_IsThirdPerson(void); | ||||||
|  | void h_CL_CameraOffset(float* ofs); | ||||||
|  |  | ||||||
| /* Normal VMT hooks */ | /* Normal VMT hooks */ | ||||||
| DECL_HOOK(CL_CreateMove); | DECL_HOOK(CL_CreateMove); | ||||||
| @@ -13,18 +45,45 @@ DECL_HOOK(HUD_Redraw); | |||||||
| DECL_HOOK(StudioRenderModel); | DECL_HOOK(StudioRenderModel); | ||||||
| DECL_HOOK(CalcRefdef); | DECL_HOOK(CalcRefdef); | ||||||
| DECL_HOOK(HUD_PostRunCmd); | DECL_HOOK(HUD_PostRunCmd); | ||||||
|  | key_event_func_t ho_HUD_Key_Event = NULL;  // Manually declare the hook | ||||||
|  |  | ||||||
| /* OpenGL hooks */ | // Manual declarations for third-person hooks | ||||||
| DECL_HOOK(glColor4f); | int (*ho_CL_IsThirdPerson)(void) = NULL; | ||||||
|  | void (*ho_CL_CameraOffset)(float* ofs) = NULL; | ||||||
|  |  | ||||||
|  | /* OpenGL hooks - use function pointer as we get actual addresses from game */ | ||||||
|  | void (*real_glColor4f)(GLfloat, GLfloat, GLfloat, GLfloat) = NULL; | ||||||
|  |  | ||||||
| /* Detour hooks */ | /* Detour hooks */ | ||||||
| static detour_data_t detour_data_clmove; | static detour_data_t detour_data_clmove; | ||||||
| DECL_DETOUR_TYPE(void, clmove_type); |  | ||||||
| DECL_HOOK(CL_Move); | /* Flag to delay uninject until next frame */ | ||||||
|  | static bool g_should_uninject = false; | ||||||
|  |  | ||||||
|  | /* Mouse position tracking independent from the game engine */ | ||||||
|  | static int g_menu_mouse_x = 0; | ||||||
|  | static int g_menu_mouse_y = 0; | ||||||
|  | static bool g_mouse_down[5] = {false, false, false, false, false}; // Tracking mouse buttons | ||||||
|  |  | ||||||
|  | /* Store last known camera angles for locking */ | ||||||
|  | static vec3_t s_locked_view_angles = {0, 0, 0}; | ||||||
|  | static bool s_lock_initialized = false; | ||||||
|  |  | ||||||
|  | /* Forward declarations */ | ||||||
|  | static void force_view_angles(void); | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
| bool hooks_init(void) { | bool hooks_init(void) { | ||||||
|  |     /* Initialize ImGui menu before hooking any rendering functions */ | ||||||
|  |     if (!menu_init()) { | ||||||
|  |         i_engine->Con_Printf("Failed to initialize ImGui menu\n"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Initialize third-person camera system */ | ||||||
|  |     thirdperson_init(); | ||||||
|  |  | ||||||
|     /* VMT hooking */ |     /* VMT hooking */ | ||||||
|     HOOK(i_client, CL_CreateMove); |     HOOK(i_client, CL_CreateMove); | ||||||
|     HOOK(i_client, HUD_Redraw); |     HOOK(i_client, HUD_Redraw); | ||||||
| @@ -32,35 +91,147 @@ bool hooks_init(void) { | |||||||
|     HOOK(i_client, CalcRefdef); |     HOOK(i_client, CalcRefdef); | ||||||
|     HOOK(i_client, HUD_PostRunCmd); |     HOOK(i_client, HUD_PostRunCmd); | ||||||
|      |      | ||||||
|     /* OpenGL hooks */ |     /* Third-person hooks - use direct replacement approach */ | ||||||
|     GL_HOOK(glColor4f); |     ho_CL_IsThirdPerson = i_client->CL_IsThirdPerson; | ||||||
|  |     i_client->CL_IsThirdPerson = h_CL_IsThirdPerson; | ||||||
|  |     i_engine->Con_Printf("CL_IsThirdPerson hook installed at %p -> %p\n",  | ||||||
|  |                        ho_CL_IsThirdPerson, h_CL_IsThirdPerson); | ||||||
|  |      | ||||||
|  |     /* Camera offset hook - critical for third-person view */ | ||||||
|  |     ho_CL_CameraOffset = i_client->CL_CameraOffset; | ||||||
|  |     i_client->CL_CameraOffset = h_CL_CameraOffset; | ||||||
|  |     i_engine->Con_Printf("CL_CameraOffset hook installed at %p -> %p\n",  | ||||||
|  |                        ho_CL_CameraOffset, h_CL_CameraOffset); | ||||||
|  |      | ||||||
|  |     /* Manual hook for HUD_Key_Event - avoiding type cast issues */ | ||||||
|  |     ho_HUD_Key_Event = (key_event_func_t)i_client->HUD_Key_Event; | ||||||
|  |     i_client->HUD_Key_Event = (key_event_func_t)h_HUD_Key_Event; | ||||||
|  |  | ||||||
|  |     /* Manual OpenGL hooks - get functions from the game engine's GL context */ | ||||||
|  |     real_glColor4f = (void (*)(GLfloat, GLfloat, GLfloat, GLfloat))glColor4f; | ||||||
|  |     if (real_glColor4f) { | ||||||
|  |         void* result = DetourFunction((void*)real_glColor4f, (void*)h_glColor4f); | ||||||
|  |         if (!result) { | ||||||
|  |             i_engine->Con_Printf("Failed to hook glColor4f\n"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* We don't hook swap buffers directly anymore - we use HUD_Redraw instead  | ||||||
|  |        which is more reliable in GoldSrc engine */ | ||||||
|      |      | ||||||
|     /* Detour hooks */ |     /* Detour hooks */ | ||||||
|     void* clmove_ptr = dlsym(hw, "CL_Move"); |     void* clmove_ptr = dlsym(hw, "CL_Move"); | ||||||
|     if (!clmove_ptr) |     if (!clmove_ptr) { | ||||||
|  |         i_engine->Con_Printf("Failed to find CL_Move\n"); | ||||||
|         return false; |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* Initialize detour_data_clmove struct for detour, and add the hook */ |     /* Initialize detour_data_clmove struct for detour, and add the hook */ | ||||||
|     detour_init(&detour_data_clmove, clmove_ptr, (void*)h_CL_Move); |     detour_init(&detour_data_clmove, clmove_ptr, (void*)h_CL_Move); | ||||||
|     detour_add(&detour_data_clmove); |     if (!detour_add(&detour_data_clmove)) { | ||||||
|  |         i_engine->Con_Printf("Failed to hook CL_Move\n"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Initialize debug info */ | ||||||
|  |     if (g_settings.thirdperson) { | ||||||
|  |         i_engine->Con_Printf("Third-person mode initialized with distance %.1f\n",  | ||||||
|  |                            g_settings.thirdperson_dist); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     i_engine->Con_Printf("All hooks initialized successfully\n"); | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| void hooks_restore(void) { | void hooks_restore(void) { | ||||||
|  |     /* First shut down ImGui to prevent any rendering after hooks are removed */ | ||||||
|  |     menu_shutdown(); | ||||||
|  |      | ||||||
|  |     /* Remove CL_Move detour */ | ||||||
|  |     if (detour_data_clmove.detoured) { | ||||||
|         detour_del(&detour_data_clmove); |         detour_del(&detour_data_clmove); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     /* Remove OpenGL hooks */ | ||||||
|  |     if (real_glColor4f) { | ||||||
|  |         DetourRemove((void*)real_glColor4f, (void*)h_glColor4f); | ||||||
|  |         real_glColor4f = NULL; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* Restore VMT hooks */ | ||||||
|  |     if (i_client) { | ||||||
|  |         i_client->CL_CreateMove = ho_CL_CreateMove; | ||||||
|  |         i_client->HUD_Redraw = ho_HUD_Redraw; | ||||||
|  |         i_client->CalcRefdef = ho_CalcRefdef; | ||||||
|  |         i_client->HUD_PostRunCmd = ho_HUD_PostRunCmd; | ||||||
|  |         i_client->CL_IsThirdPerson = ho_CL_IsThirdPerson; | ||||||
|  |         i_client->CL_CameraOffset = ho_CL_CameraOffset; | ||||||
|  |          | ||||||
|  |         if (ho_HUD_Key_Event) { | ||||||
|  |             i_client->HUD_Key_Event = ho_HUD_Key_Event; | ||||||
|  |             ho_HUD_Key_Event = NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (i_studiomodelrenderer) { | ||||||
|  |         i_studiomodelrenderer->StudioRenderModel = ho_StudioRenderModel; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     i_engine->Con_Printf("All hooks restored\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void hooks_schedule_uninject(void) { | ||||||
|  |     g_should_uninject = true; | ||||||
|  | } | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
| void h_CL_CreateMove(float frametime, usercmd_t* cmd, int active) { | void h_CL_CreateMove(float frametime, usercmd_t* cmd, int active) { | ||||||
|     ORIGINAL(CL_CreateMove, frametime, cmd, active); |     /* Check if we should uninject before doing anything else */ | ||||||
|  |     if (g_should_uninject) { | ||||||
|     vec3_t old_angles = cmd->viewangles; |         g_should_uninject = false; | ||||||
|  |         self_unload(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* Declared in globals.c */ |     /* Declared in globals.c */ | ||||||
|     localplayer = i_engine->GetLocalPlayer(); |     localplayer = i_engine->GetLocalPlayer(); | ||||||
|  |  | ||||||
|  |     // First call original function to let the game set up movement commands | ||||||
|  |     ORIGINAL(CL_CreateMove, frametime, cmd, active); | ||||||
|  |  | ||||||
|  |     vec3_t old_angles = cmd->viewangles; | ||||||
|  |      | ||||||
|  |     // Store original movement commands | ||||||
|  |     float origForward = cmd->forwardmove; | ||||||
|  |     float origSide = cmd->sidemove; | ||||||
|  |     float origUp = cmd->upmove; | ||||||
|  |     int origButtons = cmd->buttons; | ||||||
|  |  | ||||||
|  |     // If menu is open and movement is not allowed, zero out movement commands | ||||||
|  |     if (g_menu_open && !g_settings.menu_allow_movement) { | ||||||
|  |         cmd->forwardmove = 0.0f; | ||||||
|  |         cmd->sidemove = 0.0f; | ||||||
|  |         cmd->upmove = 0.0f; | ||||||
|  |         cmd->buttons = 0; | ||||||
|  |          | ||||||
|  |         // If menu is open and movement is not allowed, only force angles | ||||||
|  |         if (s_lock_initialized) { | ||||||
|  |             vec_copy(cmd->viewangles, s_locked_view_angles); | ||||||
|  |         } | ||||||
|  |     }  | ||||||
|  |     else { | ||||||
|  |         // Menu is closed OR movement is allowed, process all features | ||||||
|  |          | ||||||
|  |         // Restore original movement values if menu is open with movement allowed | ||||||
|  |         if (g_menu_open && g_settings.menu_allow_movement) { | ||||||
|  |             cmd->forwardmove = origForward; | ||||||
|  |             cmd->sidemove = origSide; | ||||||
|  |             cmd->upmove = origUp; | ||||||
|  |             cmd->buttons = origButtons; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Always process features if movement is allowed or menu is closed | ||||||
|         bhop(cmd); |         bhop(cmd); | ||||||
|         aimbot(cmd); |         aimbot(cmd); | ||||||
|         bullet_tracers(cmd); |         bullet_tracers(cmd); | ||||||
| @@ -68,8 +239,15 @@ void h_CL_CreateMove(float frametime, usercmd_t* cmd, int active) { | |||||||
|         check_namechanger_mode_and_execute(cmd); |         check_namechanger_mode_and_execute(cmd); | ||||||
|         fov_adjust(cmd); |         fov_adjust(cmd); | ||||||
|          |          | ||||||
|  |         // If menu is open with movement allowed, still need to lock view angles | ||||||
|  |         if (g_menu_open && s_lock_initialized) { | ||||||
|  |             vec_copy(cmd->viewangles, s_locked_view_angles); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Always maintain view angle control and clamp angles | ||||||
|     correct_movement(cmd, old_angles); |     correct_movement(cmd, old_angles); | ||||||
|     vec_clamp(cmd->viewangles); |     ang_clamp(&cmd->viewangles); | ||||||
| } | } | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
| @@ -85,24 +263,54 @@ rgb_t rainbow_color(float time) { | |||||||
| } | } | ||||||
|  |  | ||||||
| int h_HUD_Redraw(float time, int intermission) { | int h_HUD_Redraw(float time, int intermission) { | ||||||
|  |     // Force set view angles every frame when menu is open | ||||||
|  |     force_view_angles(); | ||||||
|  |      | ||||||
|  |     // Call original function to let the game draw | ||||||
|     int ret = ORIGINAL(HUD_Redraw, time, intermission); |     int ret = ORIGINAL(HUD_Redraw, time, intermission); | ||||||
|  |  | ||||||
|     if (dz_watermark->value) { |     // Draw watermark if enabled | ||||||
|         /* Determine the color for the watermark */ |     if (g_settings.watermark) { | ||||||
|         rgb_t color; |         rgb_t color = g_settings.watermark_rainbow ? rainbow_color(time) : (rgb_t){ 0, 255, 255 }; | ||||||
|  |  | ||||||
|         if (dz_watermark_rainbow->value) { |  | ||||||
|             color = rainbow_color(time); |  | ||||||
|         } else { |  | ||||||
|             color = (rgb_t){ 0, 255, 255 }; // default color |  | ||||||
|         } |  | ||||||
|         /* Watermark */ |  | ||||||
|         engine_draw_text(5, 5, "https://git.deadzone.lol/Wizzard/goldsrc-cheat", color); |         engine_draw_text(5, 5, "https://git.deadzone.lol/Wizzard/goldsrc-cheat", color); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Draw ESP | ||||||
|     esp(); |     esp(); | ||||||
|  |      | ||||||
|  |     // Draw custom crosshair | ||||||
|     custom_crosshair(); |     custom_crosshair(); | ||||||
|      |      | ||||||
|  |     // Handle cursor for ImGui when menu is open | ||||||
|  |     if (g_menu_open && g_imgui_context) { | ||||||
|  |         // Get screen dimensions | ||||||
|  |         SCREENINFO scr_inf; | ||||||
|  |         scr_inf.iSize = sizeof(SCREENINFO); | ||||||
|  |         i_engine->pfnGetScreenInfo(&scr_inf); | ||||||
|  |          | ||||||
|  |         // Get mouse position from engine | ||||||
|  |         int mouse_x, mouse_y; | ||||||
|  |         i_engine->GetMousePosition(&mouse_x, &mouse_y); | ||||||
|  |          | ||||||
|  |         // Update ImGui mouse position | ||||||
|  |         ImGui::SetCurrentContext(g_imgui_context); | ||||||
|  |         ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |          | ||||||
|  |         // Update mouse buttons - using our tracked state from key events | ||||||
|  |         io.MouseDown[0] = g_mouse_down[0]; | ||||||
|  |         io.MouseDown[1] = g_mouse_down[1]; | ||||||
|  |          | ||||||
|  |         // Update mouse position (clamped to screen) | ||||||
|  |         if (mouse_x >= 0 && mouse_x < scr_inf.iWidth &&  | ||||||
|  |             mouse_y >= 0 && mouse_y < scr_inf.iHeight) { | ||||||
|  |             io.MousePos.x = (float)mouse_x; | ||||||
|  |             io.MousePos.y = (float)mouse_y; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Render ImGui menu (if open) | ||||||
|  |     menu_render(); | ||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -119,7 +327,13 @@ void h_CalcRefdef(ref_params_t* params) { | |||||||
|     /* Store punch angles for CreateMove */ |     /* Store punch angles for CreateMove */ | ||||||
|     vec_copy(g_punchAngles, params->punchangle); |     vec_copy(g_punchAngles, params->punchangle); | ||||||
|      |      | ||||||
|  |     /* Call original CalcRefdef */ | ||||||
|     ORIGINAL(CalcRefdef, params); |     ORIGINAL(CalcRefdef, params); | ||||||
|  |      | ||||||
|  |     /* Apply third-person camera with direct view modification */ | ||||||
|  |     if (g_settings.thirdperson) { | ||||||
|  |         thirdperson_modify_view(params); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
| @@ -181,16 +395,186 @@ void h_glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { | |||||||
|             break; |             break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ORIGINAL(glColor4f, r, g, b, a); |     /* This part is executed regardless of the visible_mode. | ||||||
|  |      * NOTE: Not calling original breaks chams. */ | ||||||
|  |     if (real_glColor4f) | ||||||
|  |         real_glColor4f(r, g, b, a); | ||||||
| } | } | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
| void h_CL_Move() { | /* | ||||||
|     if (dz_movement_clmove->value != 0) { |  * Simple passthrough to thirdperson module | ||||||
|         for (int i = 0; i < (int)dz_movement_clmove->value; i++) |  */ | ||||||
|             CALL_ORIGINAL(detour_data_clmove, clmove_type); | int h_CL_IsThirdPerson(void) { | ||||||
|  |     // We still need this to tell the engine we're in third person view | ||||||
|  |     return thirdperson_is_active(); | ||||||
| } | } | ||||||
|  |  | ||||||
|     CALL_ORIGINAL(detour_data_clmove, clmove_type); | /* | ||||||
|  |  * This isn't used anymore - our direct camera control in CalcRefdef handles everything | ||||||
|  |  */ | ||||||
|  | void h_CL_CameraOffset(float* ofs) { | ||||||
|  |     // Not used by our new implementation | ||||||
|  |     ofs[0] = ofs[1] = ofs[2] = 0.0f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Function to handle CL_Move | ||||||
|  | void h_CL_Move(void) | ||||||
|  | { | ||||||
|  |     // Get original function address safely | ||||||
|  |     void (*original_func)(void) = NULL; | ||||||
|  |     if (detour_data_clmove.detoured) { | ||||||
|  |         detour_del(&detour_data_clmove); | ||||||
|  |         original_func = (void (*)(void))detour_data_clmove.orig; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Call original function if we have it | ||||||
|  |     if (original_func) { | ||||||
|  |         original_func(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Update third-person camera every frame | ||||||
|  |     thirdperson_update(); | ||||||
|  |      | ||||||
|  |     // Restore the detour | ||||||
|  |     if (detour_data_clmove.orig) { | ||||||
|  |         detour_add(&detour_data_clmove); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
|  | int h_HUD_Key_Event(int down, int keynum, const char* pszCurrentBinding) { | ||||||
|  |     // Debug output but only for specific keys to avoid spam | ||||||
|  |     if (keynum == 'C' || keynum == g_settings.thirdperson_key || keynum == K_INS) { | ||||||
|  |         i_engine->Con_Printf("Key event: down=%d, keynum=%d, binding=%s\n",  | ||||||
|  |                            down, keynum, pszCurrentBinding ? pszCurrentBinding : "none"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check if thirdperson feature wants to handle this key | ||||||
|  |     if (thirdperson_key_event(down, keynum)) { | ||||||
|  |         return 0; // The key was handled by thirdperson | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Toggle menu with Insert key or specific binding | ||||||
|  |     if (down && (keynum == K_INS || (pszCurrentBinding && strcmp(pszCurrentBinding, "dz_menu") == 0))) { | ||||||
|  |         i_engine->Con_Printf("Menu toggle key detected!\n"); | ||||||
|  |         menu_key_event(keynum, down); | ||||||
|  |         return 0; // Block this key from reaching the game | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // ImGui gets priority on all input when menu is open | ||||||
|  |     if (g_menu_open) { | ||||||
|  |         // For mouse buttons, update our own tracking to help ImGui | ||||||
|  |         if (keynum == K_MOUSE1 || keynum == K_MOUSE2) { | ||||||
|  |             if (keynum == K_MOUSE1) | ||||||
|  |                 g_mouse_down[0] = down ? true : false; | ||||||
|  |             else if (keynum == K_MOUSE2) | ||||||
|  |                 g_mouse_down[1] = down ? true : false; | ||||||
|  |  | ||||||
|  |             return 0; // Block mouse buttons from game | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Let ESC pass through to the game to close console/etc. | ||||||
|  |         if (keynum == K_ESCAPE && down) { | ||||||
|  |             if (ho_HUD_Key_Event) | ||||||
|  |                 return ho_HUD_Key_Event(down, keynum, pszCurrentBinding); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Allow WASD movement keys if the setting is enabled | ||||||
|  |         if (g_settings.menu_allow_movement) { | ||||||
|  |             // Check for movement key bindings instead of specific keys | ||||||
|  |             if (pszCurrentBinding && ( | ||||||
|  |                 strstr(pszCurrentBinding, "+forward") || | ||||||
|  |                 strstr(pszCurrentBinding, "+back") || | ||||||
|  |                 strstr(pszCurrentBinding, "+moveleft") || | ||||||
|  |                 strstr(pszCurrentBinding, "+moveright") || | ||||||
|  |                 strstr(pszCurrentBinding, "+jump") || | ||||||
|  |                 strstr(pszCurrentBinding, "+duck") || | ||||||
|  |                 strstr(pszCurrentBinding, "+speed"))) { | ||||||
|  |                  | ||||||
|  |                 i_engine->Con_Printf("Passing movement key to game: %s\n", pszCurrentBinding); | ||||||
|  |                 if (ho_HUD_Key_Event) | ||||||
|  |                     return ho_HUD_Key_Event(down, keynum, pszCurrentBinding); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Also allow WASD keys directly | ||||||
|  |             if (keynum == 'W' || keynum == 'A' || keynum == 'S' || keynum == 'D' || | ||||||
|  |                 keynum == ' ' || // Space for jump | ||||||
|  |                 keynum == K_CTRL || // Crouch | ||||||
|  |                 keynum == K_SHIFT) { // Walk | ||||||
|  |                  | ||||||
|  |                 i_engine->Con_Printf("Passing direct movement key to game: %d\n", keynum); | ||||||
|  |                 if (ho_HUD_Key_Event) | ||||||
|  |                     return ho_HUD_Key_Event(down, keynum, pszCurrentBinding); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Block all other keys from reaching the game | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // When menu is closed, let all keys pass to the game | ||||||
|  |     if (ho_HUD_Key_Event) { | ||||||
|  |         return ho_HUD_Key_Event(down, keynum, pszCurrentBinding); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
|  | // Force set view angles through the engine when menu is open | ||||||
|  | static void force_view_angles(void) { | ||||||
|  |     // Only do anything when menu is open/closed state changes | ||||||
|  |     static bool s_was_menu_open = false; | ||||||
|  |      | ||||||
|  |     // Get the current time for smoother transitions | ||||||
|  |     float current_time = i_engine->GetClientTime(); | ||||||
|  |     static float s_menu_close_time = 0.0f; | ||||||
|  |     static bool s_is_restoring = false; | ||||||
|  |      | ||||||
|  |     // Handle menu state changes | ||||||
|  |     if (g_menu_open != s_was_menu_open) { | ||||||
|  |         // Menu state changed | ||||||
|  |         if (g_menu_open) { | ||||||
|  |             // Menu just opened - store current view angles | ||||||
|  |             i_engine->GetViewAngles(s_locked_view_angles); | ||||||
|  |             s_lock_initialized = true; | ||||||
|  |             i_engine->Con_Printf("Stored view angles: %.1f %.1f %.1f\n",  | ||||||
|  |                                s_locked_view_angles[0], s_locked_view_angles[1], s_locked_view_angles[2]); | ||||||
|  |             s_is_restoring = false; | ||||||
|  |         } else { | ||||||
|  |             // Menu just closed - set up restoration timing | ||||||
|  |             s_menu_close_time = current_time; | ||||||
|  |             s_is_restoring = true; | ||||||
|  |              | ||||||
|  |             // Immediately restore angles | ||||||
|  |             if (s_lock_initialized) { | ||||||
|  |                 i_engine->SetViewAngles(s_locked_view_angles); | ||||||
|  |                 i_engine->Con_Printf("Restored view angles: %.1f %.1f %.1f\n",  | ||||||
|  |                                    s_locked_view_angles[0], s_locked_view_angles[1], s_locked_view_angles[2]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         s_was_menu_open = g_menu_open; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // When menu is open, continuously force the locked view angles | ||||||
|  |     if (g_menu_open && s_lock_initialized) { | ||||||
|  |         // Force the engine angles to match our locked angles | ||||||
|  |         i_engine->SetViewAngles(s_locked_view_angles); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Continue restoring angles for a short time after menu close to prevent flicker | ||||||
|  |     if (!g_menu_open && s_is_restoring) { | ||||||
|  |         if (current_time - s_menu_close_time < 0.2f) { | ||||||
|  |             // Still in restoration period, keep forcing angles | ||||||
|  |             i_engine->SetViewAngles(s_locked_view_angles); | ||||||
|  |         } else { | ||||||
|  |             // Done restoring | ||||||
|  |             s_is_restoring = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,57 +0,0 @@ | |||||||
|  |  | ||||||
| #ifndef CVARS_H_ |  | ||||||
| #define CVARS_H_ |  | ||||||
|  |  | ||||||
| #include "sdk.h" |  | ||||||
| #include "globals.h" |  | ||||||
|  |  | ||||||
| #define CVAR_PREFIX  "dz_" |  | ||||||
| #define CVAR_HACK_ID 0x4000 /* (1<<14) One that is not in use by the game */ |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  *  DECL_CVAR: Declares cvar variable in source file. |  | ||||||
|  *  DECL_CVAR_EXTERN: Same but for headers. |  | ||||||
|  *  REGISTER_CVAR: Create the cvar, return cvar_t* |  | ||||||
|  *  CVAR_ON: Returns true if the cvar is non-zero |  | ||||||
|  * |  | ||||||
|  * prefix | meaning |  | ||||||
|  * -------+------------------------------- |  | ||||||
|  * dz_*   | cvar variable |  | ||||||
|  */ |  | ||||||
| #define DECL_CVAR(name) cvar_t* dz_##name = NULL; |  | ||||||
|  |  | ||||||
| #define DECL_CVAR_EXTERN(name) extern cvar_t* dz_##name; |  | ||||||
|  |  | ||||||
| #define REGISTER_CVAR(name, value) \ |  | ||||||
|     dz_##name =                    \ |  | ||||||
|       i_engine->pfnRegisterVariable(CVAR_PREFIX #name, #value, CVAR_HACK_ID); |  | ||||||
|  |  | ||||||
| #define CVAR_ON(name) (dz_##name->value != 0.0f) |  | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ |  | ||||||
|  |  | ||||||
| DECL_CVAR_EXTERN(movement_bhop); |  | ||||||
| DECL_CVAR_EXTERN(movement_autostrafe); |  | ||||||
| DECL_CVAR_EXTERN(aim_aimbot); |  | ||||||
| DECL_CVAR_EXTERN(aim_autoshoot); |  | ||||||
| DECL_CVAR_EXTERN(visuals_esp); |  | ||||||
| DECL_CVAR_EXTERN(visuals_chams); |  | ||||||
| DECL_CVAR_EXTERN(visuals_crosshair); |  | ||||||
| DECL_CVAR_EXTERN(visuals_tracers); |  | ||||||
| DECL_CVAR_EXTERN(movement_clmove); |  | ||||||
| DECL_CVAR_EXTERN(watermark); |  | ||||||
| DECL_CVAR_EXTERN(watermark_rainbow); |  | ||||||
| DECL_CVAR_EXTERN(aim_aimbot_silent); |  | ||||||
| DECL_CVAR_EXTERN(visuals_friendly); |  | ||||||
| DECL_CVAR_EXTERN(movement_antiaim); |  | ||||||
| DECL_CVAR_EXTERN(movement_antiaim_view); |  | ||||||
| DECL_CVAR_EXTERN(movement_fakeduck); |  | ||||||
| DECL_CVAR_EXTERN(misc_namechanger) |  | ||||||
| DECL_CVAR_EXTERN(misc_namechanger_speed) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ |  | ||||||
|  |  | ||||||
| bool cvars_init(void); |  | ||||||
|  |  | ||||||
| #endif /* CVARS_H_ */ |  | ||||||
							
								
								
									
										14
									
								
								src/include/entityutil.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/include/entityutil.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  |  | ||||||
|  | #ifndef ENTITY_H_ | ||||||
|  | #define ENTITY_H_ 1 | ||||||
|  |  | ||||||
|  | #include "sdk.h" | ||||||
|  |  | ||||||
|  | cl_entity_t* get_player(int ent_idx); | ||||||
|  | bool is_alive(cl_entity_t* ent); | ||||||
|  | bool valid_player(cl_entity_t* ent); | ||||||
|  | bool is_friend(cl_entity_t* ent); | ||||||
|  | bool can_shoot(void); | ||||||
|  | char* get_name(int ent_idx); | ||||||
|  |  | ||||||
|  | #endif /* ENTITY_H_ */ | ||||||
| @@ -1,4 +1,3 @@ | |||||||
|  |  | ||||||
| #ifndef HOOKS_H_ | #ifndef HOOKS_H_ | ||||||
| #define HOOKS_H_ | #define HOOKS_H_ | ||||||
|  |  | ||||||
| @@ -8,6 +7,12 @@ | |||||||
|  |  | ||||||
| #include <dlfcn.h> /* dlsym */ | #include <dlfcn.h> /* dlsym */ | ||||||
| #include <GL/gl.h> /* GLFloat */ | #include <GL/gl.h> /* GLFloat */ | ||||||
|  | #include <stdint.h> | ||||||
|  |  | ||||||
|  | typedef void (*hook_func_t)(void); | ||||||
|  |  | ||||||
|  | typedef int (*key_event_func_t)(int down, int keynum, const char* pszCurrentBinding); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Table of prefixes: |  * Table of prefixes: | ||||||
|  *   prefix | meaning |  *   prefix | meaning | ||||||
| @@ -51,18 +56,15 @@ | |||||||
|  * GL_HOOK: Hooks a OpenGL function. Example: |  * GL_HOOK: Hooks a OpenGL function. Example: | ||||||
|  * |  * | ||||||
|  *   GL_HOOK(glColor4f); |  *   GL_HOOK(glColor4f); | ||||||
|  *     void** hp_glColor4f = (void**)dlsym(hw, "qglColor4f"); // Ptr |  | ||||||
|  *     ho_glColor4f = (glColor4f_t)(*hp_glColor4f);      // Original from ptr |  | ||||||
|  *     *hp_glColor4f = (void*)h_glColor4f;               // Set ptr to our func |  | ||||||
|  |  | ||||||
|  * Note: ho_glColor4f and h_glColor4f sould be declared with DECL_HOOK_EXTERN |  | ||||||
|  * |  * | ||||||
|  |  *   Will store the original function in o_glColor4f and set the function to | ||||||
|  |  *   h_glColor4f (which must be defined) | ||||||
|  * |  * | ||||||
|  * GL_UNHOOK: Restores a OpenGL hook created by GL_HOOK. Example: |  * GL_UNHOOK: Restores a OpenGL hook created by GL_HOOK. Example: | ||||||
|  * |  * | ||||||
|  *   GL_UNHOOK(glColor4f); |  *   GL_UNHOOK(glColor4f); | ||||||
|  *     void** hp_glColor4f = (void**)dlsym(hw, "qglColor4f"); // Ptr |  * | ||||||
|  *     *hp_glColor4f = (void*)ho_glColor4f;                   // Set to original |  *   Will restore the original function from o_glColor4f to the original pointer. | ||||||
|  */ |  */ | ||||||
| #define DECL_HOOK_EXTERN(type, name, ...)  \ | #define DECL_HOOK_EXTERN(type, name, ...)  \ | ||||||
|     typedef type (*name##_t)(__VA_ARGS__); \ |     typedef type (*name##_t)(__VA_ARGS__); \ | ||||||
| @@ -77,19 +79,27 @@ | |||||||
|  |  | ||||||
| #define ORIGINAL(name, ...) ho_##name(__VA_ARGS__); | #define ORIGINAL(name, ...) ho_##name(__VA_ARGS__); | ||||||
|  |  | ||||||
| #define GL_HOOK(name)                                \ | #define GL_HOOK(ret_type, name, ...) \ | ||||||
|     void** hp_##name = (void**)dlsym(hw, "q" #name); \ |     typedef ret_type (*name##_t)(__VA_ARGS__); \ | ||||||
|     ho_##name        = (name##_t)(*hp_##name);       \ |     name##_t h_##name; \ | ||||||
|     *hp_##name       = (void*)h_##name; |     name##_t o_##name; | ||||||
|  |  | ||||||
| #define GL_UNHOOK(name) \ | #define GL_UNHOOK(name) \ | ||||||
|     void** hp_##name = (void**)dlsym(hw, "q" #name); \ |     o_##name = h_##name; | ||||||
|     *hp_##name       = (void*)ho_##name; |  | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /* For GL hooking */ | ||||||
|  | typedef void (*glColor4f_t)(GLfloat r, GLfloat g, GLfloat b, GLfloat a); | ||||||
|  | typedef void* (*wglSwapBuffers_t)(void*); | ||||||
|  |  | ||||||
| bool hooks_init(void); | /* OpenGL hooks */ | ||||||
| void hooks_restore(void); | extern void h_glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); | ||||||
|  | extern void* o_glColor4f; | ||||||
|  |  | ||||||
|  | extern wglSwapBuffers_t o_wglSwapBuffers; | ||||||
|  |  | ||||||
|  | /* HUD_Key_Event hook */ | ||||||
|  | extern int h_HUD_Key_Event(int down, int keynum, const char* pszCurrentBinding); | ||||||
|  | extern key_event_func_t ho_HUD_Key_Event; | ||||||
|  |  | ||||||
| /* VMT hooks */ | /* VMT hooks */ | ||||||
| DECL_HOOK_EXTERN(void, CL_CreateMove, float, usercmd_t*, int); | DECL_HOOK_EXTERN(void, CL_CreateMove, float, usercmd_t*, int); | ||||||
| @@ -100,10 +110,16 @@ DECL_HOOK_EXTERN(void, HUD_PostRunCmd, struct local_state_s*, | |||||||
|                  struct local_state_s*, struct usercmd_s*, int, double, |                  struct local_state_s*, struct usercmd_s*, int, double, | ||||||
|                  unsigned int); |                  unsigned int); | ||||||
|  |  | ||||||
| /* OpenGL hooks */ |  | ||||||
| DECL_HOOK_EXTERN(void, glColor4f, GLfloat, GLfloat, GLfloat, GLfloat); |  | ||||||
|  |  | ||||||
| /* Detour hooks */ | /* Detour hooks */ | ||||||
| DECL_HOOK_EXTERN(void, CL_Move); | DECL_HOOK_EXTERN(void, CL_Move); | ||||||
|  |  | ||||||
|  | /* Detour for CL_Move */ | ||||||
|  | #define ORIGINAL_DETOUR(type) ((type)detour_get_original(&detour_data_clmove))() | ||||||
|  |  | ||||||
|  | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
|  | bool hooks_init(void); | ||||||
|  | void hooks_restore(void); | ||||||
|  | void hooks_schedule_uninject(void); | ||||||
|  |  | ||||||
| #endif /* HOOKS_H_ */ | #endif /* HOOKS_H_ */ | ||||||
|   | |||||||
							
								
								
									
										321
									
								
								src/include/imgui/backends/imgui_impl_opengl2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								src/include/imgui/backends/imgui_impl_opengl2.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,321 @@ | |||||||
|  | // dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline) | ||||||
|  | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) | ||||||
|  |  | ||||||
|  | // Implemented features: | ||||||
|  | //  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! | ||||||
|  | // Missing features or Issues: | ||||||
|  | //  [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). | ||||||
|  |  | ||||||
|  | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. | ||||||
|  | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. | ||||||
|  | // Learn about Dear ImGui: | ||||||
|  | // - FAQ                  https://dearimgui.com/faq | ||||||
|  | // - Getting Started      https://dearimgui.com/getting-started | ||||||
|  | // - Documentation        https://dearimgui.com/docs (same as your local docs/ folder). | ||||||
|  | // - Introduction, links and more at the top of imgui.cpp | ||||||
|  |  | ||||||
|  | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** | ||||||
|  | // **Prefer using the code in imgui_impl_opengl3.cpp** | ||||||
|  | // This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. | ||||||
|  | // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more | ||||||
|  | // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might | ||||||
|  | // confuse your GPU driver. | ||||||
|  | // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. | ||||||
|  |  | ||||||
|  | // CHANGELOG | ||||||
|  | // (minor and older changes stripped away, please see git history for details) | ||||||
|  | //  2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. | ||||||
|  | //  2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) | ||||||
|  | //  2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. | ||||||
|  | //  2021-12-08: OpenGL: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. | ||||||
|  | //  2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). | ||||||
|  | //  2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) | ||||||
|  | //  2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications. | ||||||
|  | //  2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications. | ||||||
|  | //  2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. | ||||||
|  | //  2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. | ||||||
|  | //  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. | ||||||
|  | //  2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications. | ||||||
|  | //  2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples. | ||||||
|  | //  2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. | ||||||
|  | //  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself. | ||||||
|  | //  2017-09-01: OpenGL: Save and restore current polygon mode. | ||||||
|  | //  2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal). | ||||||
|  | //  2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. | ||||||
|  |  | ||||||
|  | #include "imgui.h" | ||||||
|  | #ifndef IMGUI_DISABLE | ||||||
|  | #include "imgui_impl_opengl2.h" | ||||||
|  | #include <stdint.h>     // intptr_t | ||||||
|  |  | ||||||
|  | // Clang/GCC warnings with -Weverything | ||||||
|  | #if defined(__clang__) | ||||||
|  | #pragma clang diagnostic push | ||||||
|  | #pragma clang diagnostic ignored "-Wunused-macros"                      // warning: macro is not used | ||||||
|  | #pragma clang diagnostic ignored "-Wnonportable-system-include-path" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // Include OpenGL header (without an OpenGL loader) requires a bit of fiddling | ||||||
|  | #if defined(_WIN32) && !defined(APIENTRY) | ||||||
|  | #define APIENTRY __stdcall                  // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms.  Additionally, the Windows OpenGL header needs APIENTRY. | ||||||
|  | #endif | ||||||
|  | #if defined(_WIN32) && !defined(WINGDIAPI) | ||||||
|  | #define WINGDIAPI __declspec(dllimport)     // Some Windows OpenGL headers need this | ||||||
|  | #endif | ||||||
|  | #if defined(__APPLE__) | ||||||
|  | #define GL_SILENCE_DEPRECATION | ||||||
|  | #include <OpenGL/gl.h> | ||||||
|  | #else | ||||||
|  | #include <GL/gl.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // [Debugging] | ||||||
|  | //#define IMGUI_IMPL_OPENGL_DEBUG | ||||||
|  | #ifdef IMGUI_IMPL_OPENGL_DEBUG | ||||||
|  | #include <stdio.h> | ||||||
|  | #define GL_CALL(_CALL)      do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0)  // Call with error check | ||||||
|  | #else | ||||||
|  | #define GL_CALL(_CALL)      _CALL   // Call without error check | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // OpenGL data | ||||||
|  | struct ImGui_ImplOpenGL2_Data | ||||||
|  | { | ||||||
|  |     GLuint       FontTexture; | ||||||
|  |  | ||||||
|  |     ImGui_ImplOpenGL2_Data() { memset((void*)this, 0, sizeof(*this)); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts | ||||||
|  | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. | ||||||
|  | static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData() | ||||||
|  | { | ||||||
|  |     return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Functions | ||||||
|  | bool    ImGui_ImplOpenGL2_Init() | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     IMGUI_CHECKVERSION(); | ||||||
|  |     IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); | ||||||
|  |  | ||||||
|  |     // Setup backend capabilities flags | ||||||
|  |     ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)(); | ||||||
|  |     io.BackendRendererUserData = (void*)bd; | ||||||
|  |     io.BackendRendererName = "imgui_impl_opengl2"; | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void    ImGui_ImplOpenGL2_Shutdown() | ||||||
|  | { | ||||||
|  |     ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); | ||||||
|  |     IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |  | ||||||
|  |     ImGui_ImplOpenGL2_DestroyDeviceObjects(); | ||||||
|  |     io.BackendRendererName = nullptr; | ||||||
|  |     io.BackendRendererUserData = nullptr; | ||||||
|  |     IM_DELETE(bd); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void    ImGui_ImplOpenGL2_NewFrame() | ||||||
|  | { | ||||||
|  |     ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); | ||||||
|  |     IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL2_Init()?"); | ||||||
|  |  | ||||||
|  |     if (!bd->FontTexture) | ||||||
|  |         ImGui_ImplOpenGL2_CreateDeviceObjects(); | ||||||
|  |     if (!bd->FontTexture) | ||||||
|  |         ImGui_ImplOpenGL2_CreateFontsTexture(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) | ||||||
|  | { | ||||||
|  |     // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. | ||||||
|  |     glEnable(GL_BLEND); | ||||||
|  |     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|  |     //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha | ||||||
|  |     glDisable(GL_CULL_FACE); | ||||||
|  |     glDisable(GL_DEPTH_TEST); | ||||||
|  |     glDisable(GL_STENCIL_TEST); | ||||||
|  |     glDisable(GL_LIGHTING); | ||||||
|  |     glDisable(GL_COLOR_MATERIAL); | ||||||
|  |     glEnable(GL_SCISSOR_TEST); | ||||||
|  |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glEnableClientState(GL_COLOR_ARRAY); | ||||||
|  |     glDisableClientState(GL_NORMAL_ARRAY); | ||||||
|  |     glEnable(GL_TEXTURE_2D); | ||||||
|  |     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||||
|  |     glShadeModel(GL_SMOOTH); | ||||||
|  |     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | ||||||
|  |  | ||||||
|  |     // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), | ||||||
|  |     // you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below. | ||||||
|  |     // (DO NOT MODIFY THIS FILE! Add the code in your calling function) | ||||||
|  |     //   GLint last_program; | ||||||
|  |     //   glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); | ||||||
|  |     //   glUseProgram(0); | ||||||
|  |     //   ImGui_ImplOpenGL2_RenderDrawData(...); | ||||||
|  |     //   glUseProgram(last_program) | ||||||
|  |     // There are potentially many more states you could need to clear/setup that we can't access from default headers. | ||||||
|  |     // e.g. glBindBuffer(GL_ARRAY_BUFFER, 0), glDisable(GL_TEXTURE_CUBE_MAP). | ||||||
|  |  | ||||||
|  |     // Setup viewport, orthographic projection matrix | ||||||
|  |     // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. | ||||||
|  |     GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); | ||||||
|  |     glMatrixMode(GL_PROJECTION); | ||||||
|  |     glPushMatrix(); | ||||||
|  |     glLoadIdentity(); | ||||||
|  |     glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f); | ||||||
|  |     glMatrixMode(GL_MODELVIEW); | ||||||
|  |     glPushMatrix(); | ||||||
|  |     glLoadIdentity(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // OpenGL2 Render function. | ||||||
|  | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. | ||||||
|  | // This is in order to be able to run within an OpenGL engine that doesn't do so. | ||||||
|  | void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) | ||||||
|  | { | ||||||
|  |     // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) | ||||||
|  |     int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); | ||||||
|  |     int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); | ||||||
|  |     if (fb_width == 0 || fb_height == 0) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     // Backup GL state | ||||||
|  |     GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); | ||||||
|  |     GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); | ||||||
|  |     GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); | ||||||
|  |     GLint last_shade_model; glGetIntegerv(GL_SHADE_MODEL, &last_shade_model); | ||||||
|  |     GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode); | ||||||
|  |     glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); | ||||||
|  |  | ||||||
|  |     // Setup desired GL state | ||||||
|  |     ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); | ||||||
|  |  | ||||||
|  |     // Will project scissor/clipping rectangles into framebuffer space | ||||||
|  |     ImVec2 clip_off = draw_data->DisplayPos;         // (0,0) unless using multi-viewports | ||||||
|  |     ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) | ||||||
|  |  | ||||||
|  |     // Render command lists | ||||||
|  |     for (int n = 0; n < draw_data->CmdListsCount; n++) | ||||||
|  |     { | ||||||
|  |         const ImDrawList* draw_list = draw_data->CmdLists[n]; | ||||||
|  |         const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; | ||||||
|  |         const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; | ||||||
|  |         glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, pos))); | ||||||
|  |         glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, uv))); | ||||||
|  |         glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, col))); | ||||||
|  |  | ||||||
|  |         for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) | ||||||
|  |         { | ||||||
|  |             const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; | ||||||
|  |             if (pcmd->UserCallback) | ||||||
|  |             { | ||||||
|  |                 // User callback, registered via ImDrawList::AddCallback() | ||||||
|  |                 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) | ||||||
|  |                 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) | ||||||
|  |                     ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); | ||||||
|  |                 else | ||||||
|  |                     pcmd->UserCallback(draw_list, pcmd); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 // Project scissor/clipping rectangles into framebuffer space | ||||||
|  |                 ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); | ||||||
|  |                 ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); | ||||||
|  |                 if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) | ||||||
|  |                     continue; | ||||||
|  |  | ||||||
|  |                 // Apply scissor/clipping rectangle (Y is inverted in OpenGL) | ||||||
|  |                 glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)); | ||||||
|  |  | ||||||
|  |                 // Bind texture, Draw | ||||||
|  |                 glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()); | ||||||
|  |                 glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Restore modified GL state | ||||||
|  |     glDisableClientState(GL_COLOR_ARRAY); | ||||||
|  |     glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glDisableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); | ||||||
|  |     glMatrixMode(GL_MODELVIEW); | ||||||
|  |     glPopMatrix(); | ||||||
|  |     glMatrixMode(GL_PROJECTION); | ||||||
|  |     glPopMatrix(); | ||||||
|  |     glPopAttrib(); | ||||||
|  |     glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); | ||||||
|  |     glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); | ||||||
|  |     glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); | ||||||
|  |     glShadeModel(last_shade_model); | ||||||
|  |     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ImGui_ImplOpenGL2_CreateFontsTexture() | ||||||
|  | { | ||||||
|  |     // Build texture atlas | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); | ||||||
|  |     unsigned char* pixels; | ||||||
|  |     int width, height; | ||||||
|  |     io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. | ||||||
|  |  | ||||||
|  |     // Upload texture to graphics system | ||||||
|  |     // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) | ||||||
|  |     GLint last_texture; | ||||||
|  |     glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     glGenTextures(1, &bd->FontTexture); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, bd->FontTexture); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | ||||||
|  |     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||||
|  |     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||||
|  |  | ||||||
|  |     // Store our identifier | ||||||
|  |     io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); | ||||||
|  |  | ||||||
|  |     // Restore state | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, last_texture); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplOpenGL2_DestroyFontsTexture() | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); | ||||||
|  |     if (bd->FontTexture) | ||||||
|  |     { | ||||||
|  |         glDeleteTextures(1, &bd->FontTexture); | ||||||
|  |         io.Fonts->SetTexID(0); | ||||||
|  |         bd->FontTexture = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool    ImGui_ImplOpenGL2_CreateDeviceObjects() | ||||||
|  | { | ||||||
|  |     return ImGui_ImplOpenGL2_CreateFontsTexture(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void    ImGui_ImplOpenGL2_DestroyDeviceObjects() | ||||||
|  | { | ||||||
|  |     ImGui_ImplOpenGL2_DestroyFontsTexture(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //----------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | #if defined(__clang__) | ||||||
|  | #pragma clang diagnostic pop | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif // #ifndef IMGUI_DISABLE | ||||||
							
								
								
									
										41
									
								
								src/include/imgui/backends/imgui_impl_opengl2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/include/imgui/backends/imgui_impl_opengl2.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | // dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline) | ||||||
|  | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) | ||||||
|  |  | ||||||
|  | // Implemented features: | ||||||
|  | //  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! | ||||||
|  | // Missing features or Issues: | ||||||
|  | //  [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). | ||||||
|  |  | ||||||
|  | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. | ||||||
|  | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. | ||||||
|  | // Learn about Dear ImGui: | ||||||
|  | // - FAQ                  https://dearimgui.com/faq | ||||||
|  | // - Getting Started      https://dearimgui.com/getting-started | ||||||
|  | // - Documentation        https://dearimgui.com/docs (same as your local docs/ folder). | ||||||
|  | // - Introduction, links and more at the top of imgui.cpp | ||||||
|  |  | ||||||
|  | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** | ||||||
|  | // **Prefer using the code in imgui_impl_opengl3.cpp** | ||||||
|  | // This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. | ||||||
|  | // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more | ||||||
|  | // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might | ||||||
|  | // confuse your GPU driver. | ||||||
|  | // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include "../imgui.h"      // IMGUI_IMPL_API | ||||||
|  | #ifndef IMGUI_DISABLE | ||||||
|  |  | ||||||
|  | // Follow "Getting Started" link and check examples/ folder to learn about using backends! | ||||||
|  | IMGUI_IMPL_API bool     ImGui_ImplOpenGL2_Init(); | ||||||
|  | IMGUI_IMPL_API void     ImGui_ImplOpenGL2_Shutdown(); | ||||||
|  | IMGUI_IMPL_API void     ImGui_ImplOpenGL2_NewFrame(); | ||||||
|  | IMGUI_IMPL_API void     ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data); | ||||||
|  |  | ||||||
|  | // Called by Init/NewFrame/Shutdown | ||||||
|  | IMGUI_IMPL_API bool     ImGui_ImplOpenGL2_CreateFontsTexture(); | ||||||
|  | IMGUI_IMPL_API void     ImGui_ImplOpenGL2_DestroyFontsTexture(); | ||||||
|  | IMGUI_IMPL_API bool     ImGui_ImplOpenGL2_CreateDeviceObjects(); | ||||||
|  | IMGUI_IMPL_API void     ImGui_ImplOpenGL2_DestroyDeviceObjects(); | ||||||
|  |  | ||||||
|  | #endif // #ifndef IMGUI_DISABLE | ||||||
							
								
								
									
										141
									
								
								src/include/imgui/imconfig.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/include/imgui/imconfig.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | //----------------------------------------------------------------------------- | ||||||
|  | // DEAR IMGUI COMPILE-TIME OPTIONS | ||||||
|  | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. | ||||||
|  | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. | ||||||
|  | //----------------------------------------------------------------------------- | ||||||
|  | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) | ||||||
|  | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. | ||||||
|  | //----------------------------------------------------------------------------- | ||||||
|  | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp | ||||||
|  | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. | ||||||
|  | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. | ||||||
|  | // Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. | ||||||
|  | //----------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | //---- Define assertion handler. Defaults to calling assert(). | ||||||
|  | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. | ||||||
|  | //#define IM_ASSERT(_EXPR)  MyAssert(_EXPR) | ||||||
|  | //#define IM_ASSERT(_EXPR)  ((void)(_EXPR))     // Disable asserts | ||||||
|  |  | ||||||
|  | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows | ||||||
|  | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. | ||||||
|  | // - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() | ||||||
|  | //   for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. | ||||||
|  | //#define IMGUI_API __declspec(dllexport)                   // MSVC Windows: DLL export | ||||||
|  | //#define IMGUI_API __declspec(dllimport)                   // MSVC Windows: DLL import | ||||||
|  | //#define IMGUI_API __attribute__((visibility("default")))  // GCC/Clang: override visibility when set is hidden | ||||||
|  |  | ||||||
|  | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. | ||||||
|  | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS | ||||||
|  |  | ||||||
|  | //---- Disable all of Dear ImGui or don't implement standard windows/tools. | ||||||
|  | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. | ||||||
|  | //#define IMGUI_DISABLE                                     // Disable everything: all headers and source files will be empty. | ||||||
|  | //#define IMGUI_DISABLE_DEMO_WINDOWS                        // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. | ||||||
|  | //#define IMGUI_DISABLE_DEBUG_TOOLS                         // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty. | ||||||
|  |  | ||||||
|  | //---- Don't implement some functions to reduce linkage requirements. | ||||||
|  | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS   // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) | ||||||
|  | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS          // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) | ||||||
|  | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS         // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) | ||||||
|  | //#define IMGUI_DISABLE_WIN32_FUNCTIONS                     // [Win32] Won't use and link with any Win32 function (clipboard, IME). | ||||||
|  | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS      // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). | ||||||
|  | //#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS             // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")). | ||||||
|  | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS            // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) | ||||||
|  | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS              // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. | ||||||
|  | //#define IMGUI_DISABLE_FILE_FUNCTIONS                      // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) | ||||||
|  | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS              // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. | ||||||
|  | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS                  // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). | ||||||
|  | //#define IMGUI_DISABLE_DEFAULT_FONT                        // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert. | ||||||
|  | //#define IMGUI_DISABLE_SSE                                 // Disable use of SSE intrinsics even if available | ||||||
|  |  | ||||||
|  | //---- Enable Test Engine / Automation features. | ||||||
|  | //#define IMGUI_ENABLE_TEST_ENGINE                          // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details. | ||||||
|  |  | ||||||
|  | //---- Include imgui_user.h at the end of imgui.h as a convenience | ||||||
|  | // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included. | ||||||
|  | //#define IMGUI_INCLUDE_IMGUI_USER_H | ||||||
|  | //#define IMGUI_USER_H_FILENAME         "my_folder/my_imgui_user.h" | ||||||
|  |  | ||||||
|  | //---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support. | ||||||
|  | //#define IMGUI_USE_BGRA_PACKED_COLOR | ||||||
|  |  | ||||||
|  | //---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate. | ||||||
|  | //#define IMGUI_USE_LEGACY_CRC32_ADLER | ||||||
|  |  | ||||||
|  | //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) | ||||||
|  | //#define IMGUI_USE_WCHAR32 | ||||||
|  |  | ||||||
|  | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version | ||||||
|  | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. | ||||||
|  | //#define IMGUI_STB_TRUETYPE_FILENAME   "my_folder/stb_truetype.h" | ||||||
|  | //#define IMGUI_STB_RECT_PACK_FILENAME  "my_folder/stb_rect_pack.h" | ||||||
|  | //#define IMGUI_STB_SPRINTF_FILENAME    "my_folder/stb_sprintf.h"    // only used if IMGUI_USE_STB_SPRINTF is defined. | ||||||
|  | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION | ||||||
|  | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION | ||||||
|  | //#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION                   // only disabled if IMGUI_USE_STB_SPRINTF is defined. | ||||||
|  |  | ||||||
|  | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) | ||||||
|  | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. | ||||||
|  | //#define IMGUI_USE_STB_SPRINTF | ||||||
|  |  | ||||||
|  | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) | ||||||
|  | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). | ||||||
|  | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. | ||||||
|  | //#define IMGUI_ENABLE_FREETYPE | ||||||
|  |  | ||||||
|  | //---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT) | ||||||
|  | // Only works in combination with IMGUI_ENABLE_FREETYPE. | ||||||
|  | // - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions. | ||||||
|  | // - Both require headers to be available in the include path + program to be linked with the library code (not provided). | ||||||
|  | // - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) | ||||||
|  | //#define IMGUI_ENABLE_FREETYPE_PLUTOSVG | ||||||
|  | //#define IMGUI_ENABLE_FREETYPE_LUNASVG | ||||||
|  |  | ||||||
|  | //---- Use stb_truetype to build and rasterize the font atlas (default) | ||||||
|  | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. | ||||||
|  | //#define IMGUI_ENABLE_STB_TRUETYPE | ||||||
|  |  | ||||||
|  | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. | ||||||
|  | // This will be inlined as part of ImVec2 and ImVec4 class declarations. | ||||||
|  | /* | ||||||
|  | #define IM_VEC2_CLASS_EXTRA                                                     \ | ||||||
|  |         constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {}                   \ | ||||||
|  |         operator MyVec2() const { return MyVec2(x,y); } | ||||||
|  |  | ||||||
|  | #define IM_VEC4_CLASS_EXTRA                                                     \ | ||||||
|  |         constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {}   \ | ||||||
|  |         operator MyVec4() const { return MyVec4(x,y,z,w); } | ||||||
|  | */ | ||||||
|  | //---- ...Or use Dear ImGui's own very basic math operators. | ||||||
|  | //#define IMGUI_DEFINE_MATH_OPERATORS | ||||||
|  |  | ||||||
|  | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. | ||||||
|  | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). | ||||||
|  | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. | ||||||
|  | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. | ||||||
|  | //#define ImDrawIdx unsigned int | ||||||
|  |  | ||||||
|  | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) | ||||||
|  | //struct ImDrawList; | ||||||
|  | //struct ImDrawCmd; | ||||||
|  | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); | ||||||
|  | //#define ImDrawCallback MyImDrawCallback | ||||||
|  |  | ||||||
|  | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) | ||||||
|  | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) | ||||||
|  | //#define IM_DEBUG_BREAK  IM_ASSERT(0) | ||||||
|  | //#define IM_DEBUG_BREAK  __debugbreak() | ||||||
|  |  | ||||||
|  | //---- Debug Tools: Enable slower asserts | ||||||
|  | //#define IMGUI_DEBUG_PARANOID | ||||||
|  |  | ||||||
|  | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) | ||||||
|  | /* | ||||||
|  | namespace ImGui | ||||||
|  | { | ||||||
|  |     void MyFunction(const char* name, MyMatrix44* mtx); | ||||||
|  | } | ||||||
|  | */ | ||||||
							
								
								
									
										17080
									
								
								src/include/imgui/imgui.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17080
									
								
								src/include/imgui/imgui.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3777
									
								
								src/include/imgui/imgui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3777
									
								
								src/include/imgui/imgui.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4831
									
								
								src/include/imgui/imgui_draw.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4831
									
								
								src/include/imgui/imgui_draw.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3638
									
								
								src/include/imgui/imgui_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3638
									
								
								src/include/imgui/imgui_internal.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4525
									
								
								src/include/imgui/imgui_tables.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4525
									
								
								src/include/imgui/imgui_tables.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10452
									
								
								src/include/imgui/imgui_widgets.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10452
									
								
								src/include/imgui/imgui_widgets.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										627
									
								
								src/include/imgui/imstb_rectpack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								src/include/imgui/imstb_rectpack.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,627 @@ | |||||||
|  | // [DEAR IMGUI] | ||||||
|  | // This is a slightly modified version of stb_rect_pack.h 1.01. | ||||||
|  | // Grep for [DEAR IMGUI] to find the changes. | ||||||
|  | //  | ||||||
|  | // stb_rect_pack.h - v1.01 - public domain - rectangle packing | ||||||
|  | // Sean Barrett 2014 | ||||||
|  | // | ||||||
|  | // Useful for e.g. packing rectangular textures into an atlas. | ||||||
|  | // Does not do rotation. | ||||||
|  | // | ||||||
|  | // Before #including, | ||||||
|  | // | ||||||
|  | //    #define STB_RECT_PACK_IMPLEMENTATION | ||||||
|  | // | ||||||
|  | // in the file that you want to have the implementation. | ||||||
|  | // | ||||||
|  | // Not necessarily the awesomest packing method, but better than | ||||||
|  | // the totally naive one in stb_truetype (which is primarily what | ||||||
|  | // this is meant to replace). | ||||||
|  | // | ||||||
|  | // Has only had a few tests run, may have issues. | ||||||
|  | // | ||||||
|  | // More docs to come. | ||||||
|  | // | ||||||
|  | // No memory allocations; uses qsort() and assert() from stdlib. | ||||||
|  | // Can override those by defining STBRP_SORT and STBRP_ASSERT. | ||||||
|  | // | ||||||
|  | // This library currently uses the Skyline Bottom-Left algorithm. | ||||||
|  | // | ||||||
|  | // Please note: better rectangle packers are welcome! Please | ||||||
|  | // implement them to the same API, but with a different init | ||||||
|  | // function. | ||||||
|  | // | ||||||
|  | // Credits | ||||||
|  | // | ||||||
|  | //  Library | ||||||
|  | //    Sean Barrett | ||||||
|  | //  Minor features | ||||||
|  | //    Martins Mozeiko | ||||||
|  | //    github:IntellectualKitty | ||||||
|  | // | ||||||
|  | //  Bugfixes / warning fixes | ||||||
|  | //    Jeremy Jaussaud | ||||||
|  | //    Fabian Giesen | ||||||
|  | // | ||||||
|  | // Version history: | ||||||
|  | // | ||||||
|  | //     1.01  (2021-07-11)  always use large rect mode, expose STBRP__MAXVAL in public section | ||||||
|  | //     1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles | ||||||
|  | //     0.99  (2019-02-07)  warning fixes | ||||||
|  | //     0.11  (2017-03-03)  return packing success/fail result | ||||||
|  | //     0.10  (2016-10-25)  remove cast-away-const to avoid warnings | ||||||
|  | //     0.09  (2016-08-27)  fix compiler warnings | ||||||
|  | //     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0) | ||||||
|  | //     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0) | ||||||
|  | //     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort | ||||||
|  | //     0.05:  added STBRP_ASSERT to allow replacing assert | ||||||
|  | //     0.04:  fixed minor bug in STBRP_LARGE_RECTS support | ||||||
|  | //     0.01:  initial release | ||||||
|  | // | ||||||
|  | // LICENSE | ||||||
|  | // | ||||||
|  | //   See end of file for license information. | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | //       INCLUDE SECTION | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef STB_INCLUDE_STB_RECT_PACK_H | ||||||
|  | #define STB_INCLUDE_STB_RECT_PACK_H | ||||||
|  |  | ||||||
|  | #define STB_RECT_PACK_VERSION  1 | ||||||
|  |  | ||||||
|  | #ifdef STBRP_STATIC | ||||||
|  | #define STBRP_DEF static | ||||||
|  | #else | ||||||
|  | #define STBRP_DEF extern | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef struct stbrp_context stbrp_context; | ||||||
|  | typedef struct stbrp_node    stbrp_node; | ||||||
|  | typedef struct stbrp_rect    stbrp_rect; | ||||||
|  |  | ||||||
|  | typedef int            stbrp_coord; | ||||||
|  |  | ||||||
|  | #define STBRP__MAXVAL  0x7fffffff | ||||||
|  | // Mostly for internal use, but this is the maximum supported coordinate value. | ||||||
|  |  | ||||||
|  | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); | ||||||
|  | // Assign packed locations to rectangles. The rectangles are of type | ||||||
|  | // 'stbrp_rect' defined below, stored in the array 'rects', and there | ||||||
|  | // are 'num_rects' many of them. | ||||||
|  | // | ||||||
|  | // Rectangles which are successfully packed have the 'was_packed' flag | ||||||
|  | // set to a non-zero value and 'x' and 'y' store the minimum location | ||||||
|  | // on each axis (i.e. bottom-left in cartesian coordinates, top-left | ||||||
|  | // if you imagine y increasing downwards). Rectangles which do not fit | ||||||
|  | // have the 'was_packed' flag set to 0. | ||||||
|  | // | ||||||
|  | // You should not try to access the 'rects' array from another thread | ||||||
|  | // while this function is running, as the function temporarily reorders | ||||||
|  | // the array while it executes. | ||||||
|  | // | ||||||
|  | // To pack into another rectangle, you need to call stbrp_init_target | ||||||
|  | // again. To continue packing into the same rectangle, you can call | ||||||
|  | // this function again. Calling this multiple times with multiple rect | ||||||
|  | // arrays will probably produce worse packing results than calling it | ||||||
|  | // a single time with the full rectangle array, but the option is | ||||||
|  | // available. | ||||||
|  | // | ||||||
|  | // The function returns 1 if all of the rectangles were successfully | ||||||
|  | // packed and 0 otherwise. | ||||||
|  |  | ||||||
|  | struct stbrp_rect | ||||||
|  | { | ||||||
|  |    // reserved for your use: | ||||||
|  |    int            id; | ||||||
|  |  | ||||||
|  |    // input: | ||||||
|  |    stbrp_coord    w, h; | ||||||
|  |  | ||||||
|  |    // output: | ||||||
|  |    stbrp_coord    x, y; | ||||||
|  |    int            was_packed;  // non-zero if valid packing | ||||||
|  |  | ||||||
|  | }; // 16 bytes, nominally | ||||||
|  |  | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); | ||||||
|  | // Initialize a rectangle packer to: | ||||||
|  | //    pack a rectangle that is 'width' by 'height' in dimensions | ||||||
|  | //    using temporary storage provided by the array 'nodes', which is 'num_nodes' long | ||||||
|  | // | ||||||
|  | // You must call this function every time you start packing into a new target. | ||||||
|  | // | ||||||
|  | // There is no "shutdown" function. The 'nodes' memory must stay valid for | ||||||
|  | // the following stbrp_pack_rects() call (or calls), but can be freed after | ||||||
|  | // the call (or calls) finish. | ||||||
|  | // | ||||||
|  | // Note: to guarantee best results, either: | ||||||
|  | //       1. make sure 'num_nodes' >= 'width' | ||||||
|  | //   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' | ||||||
|  | // | ||||||
|  | // If you don't do either of the above things, widths will be quantized to multiples | ||||||
|  | // of small integers to guarantee the algorithm doesn't run out of temporary storage. | ||||||
|  | // | ||||||
|  | // If you do #2, then the non-quantized algorithm will be used, but the algorithm | ||||||
|  | // may run out of temporary storage and be unable to pack some rectangles. | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); | ||||||
|  | // Optionally call this function after init but before doing any packing to | ||||||
|  | // change the handling of the out-of-temp-memory scenario, described above. | ||||||
|  | // If you call init again, this will be reset to the default (false). | ||||||
|  |  | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); | ||||||
|  | // Optionally select which packing heuristic the library should use. Different | ||||||
|  | // heuristics will produce better/worse results for different data sets. | ||||||
|  | // If you call init again, this will be reset to the default. | ||||||
|  |  | ||||||
|  | enum | ||||||
|  | { | ||||||
|  |    STBRP_HEURISTIC_Skyline_default=0, | ||||||
|  |    STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, | ||||||
|  |    STBRP_HEURISTIC_Skyline_BF_sortHeight | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | // the details of the following structures don't matter to you, but they must | ||||||
|  | // be visible so you can handle the memory allocations for them | ||||||
|  |  | ||||||
|  | struct stbrp_node | ||||||
|  | { | ||||||
|  |    stbrp_coord  x,y; | ||||||
|  |    stbrp_node  *next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct stbrp_context | ||||||
|  | { | ||||||
|  |    int width; | ||||||
|  |    int height; | ||||||
|  |    int align; | ||||||
|  |    int init_mode; | ||||||
|  |    int heuristic; | ||||||
|  |    int num_nodes; | ||||||
|  |    stbrp_node *active_head; | ||||||
|  |    stbrp_node *free_head; | ||||||
|  |    stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | //     IMPLEMENTATION SECTION | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifdef STB_RECT_PACK_IMPLEMENTATION | ||||||
|  | #ifndef STBRP_SORT | ||||||
|  | #include <stdlib.h> | ||||||
|  | #define STBRP_SORT qsort | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef STBRP_ASSERT | ||||||
|  | #include <assert.h> | ||||||
|  | #define STBRP_ASSERT assert | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef _MSC_VER | ||||||
|  | #define STBRP__NOTUSED(v)  (void)(v) | ||||||
|  | #define STBRP__CDECL       __cdecl | ||||||
|  | #else | ||||||
|  | #define STBRP__NOTUSED(v)  (void)sizeof(v) | ||||||
|  | #define STBRP__CDECL | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | enum | ||||||
|  | { | ||||||
|  |    STBRP__INIT_skyline = 1 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) | ||||||
|  | { | ||||||
|  |    switch (context->init_mode) { | ||||||
|  |       case STBRP__INIT_skyline: | ||||||
|  |          STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); | ||||||
|  |          context->heuristic = heuristic; | ||||||
|  |          break; | ||||||
|  |       default: | ||||||
|  |          STBRP_ASSERT(0); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) | ||||||
|  | { | ||||||
|  |    if (allow_out_of_mem) | ||||||
|  |       // if it's ok to run out of memory, then don't bother aligning them; | ||||||
|  |       // this gives better packing, but may fail due to OOM (even though | ||||||
|  |       // the rectangles easily fit). @TODO a smarter approach would be to only | ||||||
|  |       // quantize once we've hit OOM, then we could get rid of this parameter. | ||||||
|  |       context->align = 1; | ||||||
|  |    else { | ||||||
|  |       // if it's not ok to run out of memory, then quantize the widths | ||||||
|  |       // so that num_nodes is always enough nodes. | ||||||
|  |       // | ||||||
|  |       // I.e. num_nodes * align >= width | ||||||
|  |       //                  align >= width / num_nodes | ||||||
|  |       //                  align = ceil(width/num_nodes) | ||||||
|  |  | ||||||
|  |       context->align = (context->width + context->num_nodes-1) / context->num_nodes; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) | ||||||
|  | { | ||||||
|  |    int i; | ||||||
|  |  | ||||||
|  |    for (i=0; i < num_nodes-1; ++i) | ||||||
|  |       nodes[i].next = &nodes[i+1]; | ||||||
|  |    nodes[i].next = NULL; | ||||||
|  |    context->init_mode = STBRP__INIT_skyline; | ||||||
|  |    context->heuristic = STBRP_HEURISTIC_Skyline_default; | ||||||
|  |    context->free_head = &nodes[0]; | ||||||
|  |    context->active_head = &context->extra[0]; | ||||||
|  |    context->width = width; | ||||||
|  |    context->height = height; | ||||||
|  |    context->num_nodes = num_nodes; | ||||||
|  |    stbrp_setup_allow_out_of_mem(context, 0); | ||||||
|  |  | ||||||
|  |    // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) | ||||||
|  |    context->extra[0].x = 0; | ||||||
|  |    context->extra[0].y = 0; | ||||||
|  |    context->extra[0].next = &context->extra[1]; | ||||||
|  |    context->extra[1].x = (stbrp_coord) width; | ||||||
|  |    context->extra[1].y = (1<<30); | ||||||
|  |    context->extra[1].next = NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // find minimum y position if it starts at x1 | ||||||
|  | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) | ||||||
|  | { | ||||||
|  |    stbrp_node *node = first; | ||||||
|  |    int x1 = x0 + width; | ||||||
|  |    int min_y, visited_width, waste_area; | ||||||
|  |  | ||||||
|  |    STBRP__NOTUSED(c); | ||||||
|  |  | ||||||
|  |    STBRP_ASSERT(first->x <= x0); | ||||||
|  |  | ||||||
|  |    #if 0 | ||||||
|  |    // skip in case we're past the node | ||||||
|  |    while (node->next->x <= x0) | ||||||
|  |       ++node; | ||||||
|  |    #else | ||||||
|  |    STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency | ||||||
|  |    #endif | ||||||
|  |  | ||||||
|  |    STBRP_ASSERT(node->x <= x0); | ||||||
|  |  | ||||||
|  |    min_y = 0; | ||||||
|  |    waste_area = 0; | ||||||
|  |    visited_width = 0; | ||||||
|  |    while (node->x < x1) { | ||||||
|  |       if (node->y > min_y) { | ||||||
|  |          // raise min_y higher. | ||||||
|  |          // we've accounted for all waste up to min_y, | ||||||
|  |          // but we'll now add more waste for everything we've visted | ||||||
|  |          waste_area += visited_width * (node->y - min_y); | ||||||
|  |          min_y = node->y; | ||||||
|  |          // the first time through, visited_width might be reduced | ||||||
|  |          if (node->x < x0) | ||||||
|  |             visited_width += node->next->x - x0; | ||||||
|  |          else | ||||||
|  |             visited_width += node->next->x - node->x; | ||||||
|  |       } else { | ||||||
|  |          // add waste area | ||||||
|  |          int under_width = node->next->x - node->x; | ||||||
|  |          if (under_width + visited_width > width) | ||||||
|  |             under_width = width - visited_width; | ||||||
|  |          waste_area += under_width * (min_y - node->y); | ||||||
|  |          visited_width += under_width; | ||||||
|  |       } | ||||||
|  |       node = node->next; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    *pwaste = waste_area; | ||||||
|  |    return min_y; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | typedef struct | ||||||
|  | { | ||||||
|  |    int x,y; | ||||||
|  |    stbrp_node **prev_link; | ||||||
|  | } stbrp__findresult; | ||||||
|  |  | ||||||
|  | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) | ||||||
|  | { | ||||||
|  |    int best_waste = (1<<30), best_x, best_y = (1 << 30); | ||||||
|  |    stbrp__findresult fr; | ||||||
|  |    stbrp_node **prev, *node, *tail, **best = NULL; | ||||||
|  |  | ||||||
|  |    // align to multiple of c->align | ||||||
|  |    width = (width + c->align - 1); | ||||||
|  |    width -= width % c->align; | ||||||
|  |    STBRP_ASSERT(width % c->align == 0); | ||||||
|  |  | ||||||
|  |    // if it can't possibly fit, bail immediately | ||||||
|  |    if (width > c->width || height > c->height) { | ||||||
|  |       fr.prev_link = NULL; | ||||||
|  |       fr.x = fr.y = 0; | ||||||
|  |       return fr; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    node = c->active_head; | ||||||
|  |    prev = &c->active_head; | ||||||
|  |    while (node->x + width <= c->width) { | ||||||
|  |       int y,waste; | ||||||
|  |       y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); | ||||||
|  |       if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL | ||||||
|  |          // bottom left | ||||||
|  |          if (y < best_y) { | ||||||
|  |             best_y = y; | ||||||
|  |             best = prev; | ||||||
|  |          } | ||||||
|  |       } else { | ||||||
|  |          // best-fit | ||||||
|  |          if (y + height <= c->height) { | ||||||
|  |             // can only use it if it first vertically | ||||||
|  |             if (y < best_y || (y == best_y && waste < best_waste)) { | ||||||
|  |                best_y = y; | ||||||
|  |                best_waste = waste; | ||||||
|  |                best = prev; | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |       prev = &node->next; | ||||||
|  |       node = node->next; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    best_x = (best == NULL) ? 0 : (*best)->x; | ||||||
|  |  | ||||||
|  |    // if doing best-fit (BF), we also have to try aligning right edge to each node position | ||||||
|  |    // | ||||||
|  |    // e.g, if fitting | ||||||
|  |    // | ||||||
|  |    //     ____________________ | ||||||
|  |    //    |____________________| | ||||||
|  |    // | ||||||
|  |    //            into | ||||||
|  |    // | ||||||
|  |    //   |                         | | ||||||
|  |    //   |             ____________| | ||||||
|  |    //   |____________| | ||||||
|  |    // | ||||||
|  |    // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned | ||||||
|  |    // | ||||||
|  |    // This makes BF take about 2x the time | ||||||
|  |  | ||||||
|  |    if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { | ||||||
|  |       tail = c->active_head; | ||||||
|  |       node = c->active_head; | ||||||
|  |       prev = &c->active_head; | ||||||
|  |       // find first node that's admissible | ||||||
|  |       while (tail->x < width) | ||||||
|  |          tail = tail->next; | ||||||
|  |       while (tail) { | ||||||
|  |          int xpos = tail->x - width; | ||||||
|  |          int y,waste; | ||||||
|  |          STBRP_ASSERT(xpos >= 0); | ||||||
|  |          // find the left position that matches this | ||||||
|  |          while (node->next->x <= xpos) { | ||||||
|  |             prev = &node->next; | ||||||
|  |             node = node->next; | ||||||
|  |          } | ||||||
|  |          STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); | ||||||
|  |          y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); | ||||||
|  |          if (y + height <= c->height) { | ||||||
|  |             if (y <= best_y) { | ||||||
|  |                if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { | ||||||
|  |                   best_x = xpos; | ||||||
|  |                   //STBRP_ASSERT(y <= best_y); [DEAR IMGUI] | ||||||
|  |                   best_y = y; | ||||||
|  |                   best_waste = waste; | ||||||
|  |                   best = prev; | ||||||
|  |                } | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |          tail = tail->next; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    fr.prev_link = best; | ||||||
|  |    fr.x = best_x; | ||||||
|  |    fr.y = best_y; | ||||||
|  |    return fr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) | ||||||
|  | { | ||||||
|  |    // find best position according to heuristic | ||||||
|  |    stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); | ||||||
|  |    stbrp_node *node, *cur; | ||||||
|  |  | ||||||
|  |    // bail if: | ||||||
|  |    //    1. it failed | ||||||
|  |    //    2. the best node doesn't fit (we don't always check this) | ||||||
|  |    //    3. we're out of memory | ||||||
|  |    if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { | ||||||
|  |       res.prev_link = NULL; | ||||||
|  |       return res; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // on success, create new node | ||||||
|  |    node = context->free_head; | ||||||
|  |    node->x = (stbrp_coord) res.x; | ||||||
|  |    node->y = (stbrp_coord) (res.y + height); | ||||||
|  |  | ||||||
|  |    context->free_head = node->next; | ||||||
|  |  | ||||||
|  |    // insert the new node into the right starting point, and | ||||||
|  |    // let 'cur' point to the remaining nodes needing to be | ||||||
|  |    // stiched back in | ||||||
|  |  | ||||||
|  |    cur = *res.prev_link; | ||||||
|  |    if (cur->x < res.x) { | ||||||
|  |       // preserve the existing one, so start testing with the next one | ||||||
|  |       stbrp_node *next = cur->next; | ||||||
|  |       cur->next = node; | ||||||
|  |       cur = next; | ||||||
|  |    } else { | ||||||
|  |       *res.prev_link = node; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // from here, traverse cur and free the nodes, until we get to one | ||||||
|  |    // that shouldn't be freed | ||||||
|  |    while (cur->next && cur->next->x <= res.x + width) { | ||||||
|  |       stbrp_node *next = cur->next; | ||||||
|  |       // move the current node to the free list | ||||||
|  |       cur->next = context->free_head; | ||||||
|  |       context->free_head = cur; | ||||||
|  |       cur = next; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // stitch the list back in | ||||||
|  |    node->next = cur; | ||||||
|  |  | ||||||
|  |    if (cur->x < res.x + width) | ||||||
|  |       cur->x = (stbrp_coord) (res.x + width); | ||||||
|  |  | ||||||
|  | #ifdef _DEBUG | ||||||
|  |    cur = context->active_head; | ||||||
|  |    while (cur->x < context->width) { | ||||||
|  |       STBRP_ASSERT(cur->x < cur->next->x); | ||||||
|  |       cur = cur->next; | ||||||
|  |    } | ||||||
|  |    STBRP_ASSERT(cur->next == NULL); | ||||||
|  |  | ||||||
|  |    { | ||||||
|  |       int count=0; | ||||||
|  |       cur = context->active_head; | ||||||
|  |       while (cur) { | ||||||
|  |          cur = cur->next; | ||||||
|  |          ++count; | ||||||
|  |       } | ||||||
|  |       cur = context->free_head; | ||||||
|  |       while (cur) { | ||||||
|  |          cur = cur->next; | ||||||
|  |          ++count; | ||||||
|  |       } | ||||||
|  |       STBRP_ASSERT(count == context->num_nodes+2); | ||||||
|  |    } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |    return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) | ||||||
|  | { | ||||||
|  |    const stbrp_rect *p = (const stbrp_rect *) a; | ||||||
|  |    const stbrp_rect *q = (const stbrp_rect *) b; | ||||||
|  |    if (p->h > q->h) | ||||||
|  |       return -1; | ||||||
|  |    if (p->h < q->h) | ||||||
|  |       return  1; | ||||||
|  |    return (p->w > q->w) ? -1 : (p->w < q->w); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int STBRP__CDECL rect_original_order(const void *a, const void *b) | ||||||
|  | { | ||||||
|  |    const stbrp_rect *p = (const stbrp_rect *) a; | ||||||
|  |    const stbrp_rect *q = (const stbrp_rect *) b; | ||||||
|  |    return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) | ||||||
|  | { | ||||||
|  |    int i, all_rects_packed = 1; | ||||||
|  |  | ||||||
|  |    // we use the 'was_packed' field internally to allow sorting/unsorting | ||||||
|  |    for (i=0; i < num_rects; ++i) { | ||||||
|  |       rects[i].was_packed = i; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // sort according to heuristic | ||||||
|  |    STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); | ||||||
|  |  | ||||||
|  |    for (i=0; i < num_rects; ++i) { | ||||||
|  |       if (rects[i].w == 0 || rects[i].h == 0) { | ||||||
|  |          rects[i].x = rects[i].y = 0;  // empty rect needs no space | ||||||
|  |       } else { | ||||||
|  |          stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); | ||||||
|  |          if (fr.prev_link) { | ||||||
|  |             rects[i].x = (stbrp_coord) fr.x; | ||||||
|  |             rects[i].y = (stbrp_coord) fr.y; | ||||||
|  |          } else { | ||||||
|  |             rects[i].x = rects[i].y = STBRP__MAXVAL; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // unsort | ||||||
|  |    STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); | ||||||
|  |  | ||||||
|  |    // set was_packed flags and all_rects_packed status | ||||||
|  |    for (i=0; i < num_rects; ++i) { | ||||||
|  |       rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); | ||||||
|  |       if (!rects[i].was_packed) | ||||||
|  |          all_rects_packed = 0; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // return the all_rects_packed status | ||||||
|  |    return all_rects_packed; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | This software is available under 2 licenses -- choose whichever you prefer. | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | ALTERNATIVE A - MIT License | ||||||
|  | Copyright (c) 2017 Sean Barrett | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||||
|  | this software and associated documentation files (the "Software"), to deal in | ||||||
|  | the Software without restriction, including without limitation the rights to | ||||||
|  | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||||||
|  | of the Software, and to permit persons to whom the Software is furnished to do | ||||||
|  | so, subject to the following conditions: | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | ALTERNATIVE B - Public Domain (www.unlicense.org) | ||||||
|  | This is free and unencumbered software released into the public domain. | ||||||
|  | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | ||||||
|  | software, either in source code form or as a compiled binary, for any purpose, | ||||||
|  | commercial or non-commercial, and by any means. | ||||||
|  | In jurisdictions that recognize copyright laws, the author or authors of this | ||||||
|  | software dedicate any and all copyright interest in the software to the public | ||||||
|  | domain. We make this dedication for the benefit of the public at large and to | ||||||
|  | the detriment of our heirs and successors. We intend this dedication to be an | ||||||
|  | overt act of relinquishment in perpetuity of all present and future rights to | ||||||
|  | this software under copyright law. | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||||
|  | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
|  | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | */ | ||||||
							
								
								
									
										1469
									
								
								src/include/imgui/imstb_textedit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1469
									
								
								src/include/imgui/imstb_textedit.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5085
									
								
								src/include/imgui/imstb_truetype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5085
									
								
								src/include/imgui/imstb_truetype.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,9 +1,10 @@ | |||||||
|  |  | ||||||
| #ifndef MAIN_H_ | #ifndef MAIN_H_ | ||||||
| #define MAIN_H_ | #define MAIN_H_ | ||||||
|  |  | ||||||
| void load(void); | void load(void); | ||||||
| void unload(void); | void unload(void); | ||||||
| void self_unload(void); | void self_unload(void); | ||||||
|  | void UNINJECT_CommandHandler(void); | ||||||
|  | void safe_unload_with_debug(void); | ||||||
|  |  | ||||||
| #endif /* MAIN_H_ */ | #endif /* MAIN_H_ */ | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								src/include/mathutil.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/include/mathutil.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  |  | ||||||
|  | #ifndef MATHUTIL_H_ | ||||||
|  | #define MATHUTIL_H_ 1 | ||||||
|  |  | ||||||
|  | #include "sdk.h" | ||||||
|  |  | ||||||
|  | /* Vector 2 for 2d points */ | ||||||
|  | typedef float vec2_t[2]; | ||||||
|  |  | ||||||
|  | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
|  | #define DEG2RAD(n) ((n)*M_PI / 180.0f) | ||||||
|  | #define RAD2DEG(n) ((n)*180.0f / M_PI) | ||||||
|  | #define CLAMP(val, min, max)                                                   \ | ||||||
|  |     (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) | ||||||
|  |  | ||||||
|  | /* Use indexes so it works for float[] as well as vec3_t */ | ||||||
|  | #define vec_copy(dst, src)                                                     \ | ||||||
|  |     do {                                                                       \ | ||||||
|  |         dst[0] = src[0];                                                       \ | ||||||
|  |         dst[1] = src[1];                                                       \ | ||||||
|  |         dst[2] = src[2];                                                       \ | ||||||
|  |     } while (0) | ||||||
|  |  | ||||||
|  | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
|  | vec3_t vec3(float x, float y, float z); | ||||||
|  | vec3_t vec_add(vec3_t a, vec3_t b); | ||||||
|  | vec3_t vec_sub(vec3_t a, vec3_t b); | ||||||
|  | bool vec_is_zero(vec3_t v); | ||||||
|  | float vec_len2d(vec3_t v); | ||||||
|  | void ang_clamp(vec3_t* v); | ||||||
|  | void vec_norm(vec3_t* v); | ||||||
|  | float angle_delta_rad(float a, float b); | ||||||
|  | vec3_t vec_to_ang(vec3_t v); | ||||||
|  | vec3_t matrix_3x4_origin(matrix_3x4 m); | ||||||
|  | bool world_to_screen(vec3_t vec, vec2_t screen); | ||||||
|  |  | ||||||
|  | #endif /* MATHUTIL_H_ */ | ||||||
							
								
								
									
										23
									
								
								src/include/menu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/include/menu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include "imgui/imgui.h" | ||||||
|  | #include "imgui/backends/imgui_impl_opengl2.h" | ||||||
|  | #include "sdk.h" | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | bool menu_init(void); | ||||||
|  | void menu_shutdown(void); | ||||||
|  | void menu_render(void); | ||||||
|  | void menu_key_event(int keynum, int down); | ||||||
|  |  | ||||||
|  | extern bool g_menu_open; | ||||||
|  | extern bool g_imgui_initialized; | ||||||
|  | extern ImGuiContext* g_imgui_context; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif  | ||||||
| @@ -35,6 +35,38 @@ | |||||||
| /* engine_studio_api_t */ | /* engine_studio_api_t */ | ||||||
| #include "sdk/common/r_studioint.h" | #include "sdk/common/r_studioint.h" | ||||||
|  |  | ||||||
|  | #define K_TAB           9 | ||||||
|  | #define K_ENTER         13 | ||||||
|  | #define K_ESCAPE        27 | ||||||
|  | #define K_SPACE         32 | ||||||
|  | #define K_BACKSPACE     127 | ||||||
|  | #define K_UPARROW       128 | ||||||
|  | #define K_DOWNARROW     129 | ||||||
|  | #define K_LEFTARROW     130 | ||||||
|  | #define K_RIGHTARROW    131 | ||||||
|  | #define K_ALT           132 | ||||||
|  | #define K_CTRL          133 | ||||||
|  | #define K_SHIFT         134 | ||||||
|  | #define K_F1            135 | ||||||
|  | #define K_F2            136 | ||||||
|  | #define K_F3            137 | ||||||
|  | #define K_F4            138 | ||||||
|  | #define K_F5            139 | ||||||
|  | #define K_F6            140 | ||||||
|  | #define K_F7            141 | ||||||
|  | #define K_F8            142 | ||||||
|  | #define K_F9            143 | ||||||
|  | #define K_F10           144 | ||||||
|  | #define K_F11           145 | ||||||
|  | #define K_F12           146 | ||||||
|  | #define K_INS           147 | ||||||
|  | #define K_DEL           148 | ||||||
|  | #define K_PGDN          149 | ||||||
|  | #define K_PGUP          150 | ||||||
|  | #define K_HOME          151 | ||||||
|  | #define K_END           152 | ||||||
|  | #define K_PAUSE         255 | ||||||
|  |  | ||||||
| typedef float matrix_3x4[3][4]; | typedef float matrix_3x4[3][4]; | ||||||
| typedef matrix_3x4 bone_matrix[128]; | typedef matrix_3x4 bone_matrix[128]; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										82
									
								
								src/include/settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/include/settings.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     ESP_OFF  = 0, | ||||||
|  |     ESP_BOX  = 1, | ||||||
|  |     ESP_NAME = 2, | ||||||
|  |     ESP_ALL  = 3 | ||||||
|  | } esp_mode_t; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     esp_mode_t esp_mode; | ||||||
|  |     bool esp_friendly; | ||||||
|  |     float fov; | ||||||
|  |     bool chams; | ||||||
|  |     bool tracers; | ||||||
|  |     bool custom_crosshair; | ||||||
|  |     bool watermark; | ||||||
|  |     bool watermark_rainbow; | ||||||
|  |      | ||||||
|  |     bool aimbot_enabled; | ||||||
|  |     float aimbot_fov; | ||||||
|  |     float aimbot_smooth; | ||||||
|  |     bool aimbot_silent; | ||||||
|  |     bool aimbot_autoshoot; | ||||||
|  |     bool aimbot_norecoil; | ||||||
|  |     bool aimbot_recoil_comp; | ||||||
|  |     bool aimbot_friendly_fire; | ||||||
|  |     bool aimbot_rage_mode; | ||||||
|  |     bool aimbot_team_attack; | ||||||
|  |     int aimbot_hitbox; | ||||||
|  |      | ||||||
|  |     bool bhop; | ||||||
|  |     bool autostrafe; | ||||||
|  |     bool antiaim; | ||||||
|  |     bool antiaim_view; | ||||||
|  |     bool fakeduck; | ||||||
|  |     bool clmove; | ||||||
|  |      | ||||||
|  |     bool namechanger; | ||||||
|  |     float namechanger_speed; | ||||||
|  |     bool menu_allow_movement; | ||||||
|  |      | ||||||
|  |     bool thirdperson; | ||||||
|  |     int thirdperson_key; | ||||||
|  |     float thirdperson_dist; | ||||||
|  | } cheat_settings_t; | ||||||
|  |  | ||||||
|  | extern cheat_settings_t g_settings; | ||||||
|  |  | ||||||
|  | void settings_init(void); | ||||||
|  |  | ||||||
|  | void settings_reset(void); | ||||||
|  |  | ||||||
|  | inline void init_default_settings(void) { | ||||||
|  |     memset(&g_settings, 0, sizeof(g_settings)); | ||||||
|  |      | ||||||
|  |     g_settings.aimbot_fov = 5.0f; | ||||||
|  |     g_settings.aimbot_smooth = 10.0f; | ||||||
|  |     g_settings.aimbot_hitbox = 0; | ||||||
|  |      | ||||||
|  |     g_settings.esp_mode = ESP_OFF; | ||||||
|  |     g_settings.fov = 90.0f; | ||||||
|  |      | ||||||
|  |     g_settings.namechanger_speed = 5.0f; | ||||||
|  |      | ||||||
|  |     g_settings.thirdperson = false; | ||||||
|  |     g_settings.thirdperson_dist = 300.0f; | ||||||
|  |     g_settings.thirdperson_key = 'C'; | ||||||
|  |      | ||||||
|  |     g_settings.menu_allow_movement = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif  | ||||||
| @@ -14,6 +14,13 @@ typedef struct { | |||||||
|     uint8_t r, g, b; |     uint8_t r, g, b; | ||||||
| } rgb_t; | } rgb_t; | ||||||
|  |  | ||||||
|  | #define ERR(...)                                     \ | ||||||
|  |     do {                                             \ | ||||||
|  |         fprintf(stderr, "hl-cheat: %s: ", __func__); \ | ||||||
|  |         fprintf(stderr, __VA_ARGS__);                \ | ||||||
|  |         fputc('\n', stderr);                         \ | ||||||
|  |     } while (0) | ||||||
|  |  | ||||||
| #define DEG2RAD(n) ((n)*M_PI / 180.0f) | #define DEG2RAD(n) ((n)*M_PI / 180.0f) | ||||||
| #define RAD2DEG(n) ((n)*180.0f / M_PI) | #define RAD2DEG(n) ((n)*180.0f / M_PI) | ||||||
| #define CLAMP(val, min, max) \ | #define CLAMP(val, min, max) \ | ||||||
| @@ -24,9 +31,11 @@ typedef struct { | |||||||
|  |  | ||||||
| /* Use indexes so it works for float[] as well as vec3_t */ | /* Use indexes so it works for float[] as well as vec3_t */ | ||||||
| #define vec_copy(dst, src) \ | #define vec_copy(dst, src) \ | ||||||
|  |     do {                   \ | ||||||
|         dst[0] = src[0];   \ |         dst[0] = src[0];   \ | ||||||
|         dst[1] = src[1];   \ |         dst[1] = src[1];   \ | ||||||
|     dst[2] = src[2]; |         dst[2] = src[2];   \ | ||||||
|  |     } while (0) | ||||||
|  |  | ||||||
| /*----------------------------------------------------------------------------*/ | /*----------------------------------------------------------------------------*/ | ||||||
|  |  | ||||||
| @@ -36,13 +45,14 @@ bool valid_player(cl_entity_t* ent); | |||||||
| bool is_friend(cl_entity_t* ent); | bool is_friend(cl_entity_t* ent); | ||||||
| bool can_shoot(void); | bool can_shoot(void); | ||||||
| char* get_name(int ent_idx); | char* get_name(int ent_idx); | ||||||
|  | game_id get_cur_game(void); | ||||||
| vec3_t vec3(float x, float y, float z); | vec3_t vec3(float x, float y, float z); | ||||||
| vec3_t vec_add(vec3_t a, vec3_t b); | vec3_t vec_add(vec3_t a, vec3_t b); | ||||||
| vec3_t vec_sub(vec3_t a, vec3_t b); | vec3_t vec_sub(vec3_t a, vec3_t b); | ||||||
| bool vec_is_zero(vec3_t v); | bool vec_is_zero(vec3_t v); | ||||||
| float vec_len2d(vec3_t v); | float vec_len2d(vec3_t v); | ||||||
| void vec_clamp(vec3_t v); | void ang_clamp(vec3_t* v); | ||||||
| void vec_norm(vec3_t v); | void vec_norm(vec3_t* v); | ||||||
| float angle_delta_rad(float a, float b); | float angle_delta_rad(float a, float b); | ||||||
| vec3_t vec_to_ang(vec3_t v); | vec3_t vec_to_ang(vec3_t v); | ||||||
| vec3_t matrix_3x4_origin(matrix_3x4 m); | vec3_t matrix_3x4_origin(matrix_3x4 m); | ||||||
|   | |||||||
							
								
								
									
										158
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -1,18 +1,128 @@ | |||||||
|  |  | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <dlfcn.h> | #include <dlfcn.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  |  | ||||||
| #include "include/main.h" | #include "include/main.h" | ||||||
| #include "include/sdk.h" | #include "include/sdk.h" | ||||||
| #include "include/globals.h" | #include "include/globals.h" | ||||||
| #include "include/cvars.h" | #include "include/settings.h" | ||||||
| #include "include/hooks.h" | #include "include/hooks.h" | ||||||
| #include "include/util.h" | #include "include/util.h" | ||||||
| #include "include/game_detection.h" | #include "include/game_detection.h" | ||||||
|  |  | ||||||
| static bool loaded = false; | static bool loaded = false; | ||||||
|  |  | ||||||
|  | /* Create a debug log file */ | ||||||
|  | void debug_log(const char* message) { | ||||||
|  |     FILE* logfile = fopen("/tmp/cheat-unload-debug.log", "a"); | ||||||
|  |     if (logfile) { | ||||||
|  |         time_t now = time(NULL); | ||||||
|  |         char timestamp[64]; | ||||||
|  |         strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", localtime(&now)); | ||||||
|  |         fprintf(logfile, "[%s] %s\n", timestamp, message); | ||||||
|  |         fclose(logfile); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Enhanced unloading with debug logging */ | ||||||
|  | void safe_unload_with_debug(void) { | ||||||
|  |     debug_log("Starting safe unload with debug logging"); | ||||||
|  |      | ||||||
|  |     /* Log important function addresses for debugging */ | ||||||
|  |     char buf[256]; | ||||||
|  |     snprintf(buf, sizeof(buf), "Function addresses - self_unload: %p, unload: %p, hooks_restore: %p",  | ||||||
|  |              (void*)self_unload, (void*)unload, (void*)hooks_restore); | ||||||
|  |     debug_log(buf); | ||||||
|  |      | ||||||
|  |     /* Reset all settings to safe values */ | ||||||
|  |     debug_log("Resetting all settings to default values"); | ||||||
|  |     i_engine->pfnClientCmd("echo \"Step 0: Resetting all settings...\""); | ||||||
|  |     settings_reset(); | ||||||
|  |      | ||||||
|  |     /* Unhook everything first in an orderly manner */ | ||||||
|  |     i_engine->pfnClientCmd("echo \"Step 1: Unhooking functions...\""); | ||||||
|  |     debug_log("Unhooking all functions"); | ||||||
|  |      | ||||||
|  |     /* First OpenGL hooks since they're most likely to crash if not restored */ | ||||||
|  |     debug_log("Restoring OpenGL hooks"); | ||||||
|  |     // Don't manually unhook GL functions, it's already handled in hooks_restore | ||||||
|  |      | ||||||
|  |     /* Then restore other hooks */ | ||||||
|  |     debug_log("Restoring VMT hooks"); | ||||||
|  |     hooks_restore(); | ||||||
|  |      | ||||||
|  |     /* Restore globals */ | ||||||
|  |     debug_log("Restoring globals"); | ||||||
|  |     globals_restore(); | ||||||
|  |      | ||||||
|  |     /* Remove our command */ | ||||||
|  |     debug_log("Removing custom commands"); | ||||||
|  |     i_engine->pfnClientCmd("echo \"Step 2: Removing custom commands...\""); | ||||||
|  |      | ||||||
|  |     /* Wait a bit to ensure all hooks are properly removed */ | ||||||
|  |     debug_log("Waiting for hooks to settle"); | ||||||
|  |     i_engine->pfnClientCmd("echo \"Step 3: Waiting for hooks to settle...\""); | ||||||
|  |     usleep(250000); /* 250ms */ | ||||||
|  |      | ||||||
|  |     /* Now try to unload the library */ | ||||||
|  |     debug_log("Beginning library unload sequence"); | ||||||
|  |     i_engine->pfnClientCmd("echo \"Step 4: Unloading library...\""); | ||||||
|  |      | ||||||
|  |     /* | ||||||
|  |      * RTLD_LAZY: If the symbol is never referenced, then it is never resolved. | ||||||
|  |      * RTLD_NOLOAD: Don't load the shared object. | ||||||
|  |      */ | ||||||
|  |     void* self = dlopen("libhlcheat.so", RTLD_LAZY | RTLD_NOLOAD); | ||||||
|  |      | ||||||
|  |     snprintf(buf, sizeof(buf), "dlopen result: %p", self); | ||||||
|  |     debug_log(buf); | ||||||
|  |      | ||||||
|  |     if (self) { | ||||||
|  |         /* Close the call we just made to dlopen() */ | ||||||
|  |         debug_log("Closing first dlopen reference"); | ||||||
|  |         int result = dlclose(self); | ||||||
|  |         snprintf(buf, sizeof(buf), "First dlclose result: %d", result); | ||||||
|  |         debug_log(buf); | ||||||
|  |          | ||||||
|  |         /* Close the call our injector made */ | ||||||
|  |         debug_log("Closing second dlopen reference"); | ||||||
|  |         result = dlclose(self); | ||||||
|  |         snprintf(buf, sizeof(buf), "Second dlclose result: %d", result); | ||||||
|  |         debug_log(buf); | ||||||
|  |     } else { | ||||||
|  |         debug_log("ERROR: Failed to get handle to library"); | ||||||
|  |         const char* error = dlerror(); | ||||||
|  |         if (error) { | ||||||
|  |             debug_log(error); | ||||||
|  |             i_engine->pfnClientCmd("echo \"ERROR: Failed to get handle to library\""); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     debug_log("Safe unload completed"); | ||||||
|  |     i_engine->pfnClientCmd("echo \"Unload procedure completed\""); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Handler for dz_uninject command */ | ||||||
|  | void UNINJECT_CommandHandler(void) { | ||||||
|  |     i_engine->pfnClientCmd("echo \"Uninjecting goldsource-cheat with debug logging...\""); | ||||||
|  |      | ||||||
|  |     /* Use the safe unload with debug instead of scheduling uninjection */ | ||||||
|  |     safe_unload_with_debug(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Handler for dz_menu command */ | ||||||
|  | void MENU_CommandHandler(void) { | ||||||
|  |     extern bool g_menu_open; | ||||||
|  |     g_menu_open = !g_menu_open; | ||||||
|  |     i_engine->Con_Printf("Menu toggled to %s\n", g_menu_open ? "open" : "closed"); | ||||||
|  | } | ||||||
|  |  | ||||||
| __attribute__((constructor)) /* Entry point when injected */ | __attribute__((constructor)) /* Entry point when injected */ | ||||||
| void load(void) { | void load(void) { | ||||||
|     printf("goldsource-cheat injected!\n"); |     printf("goldsource-cheat injected!\n"); | ||||||
| @@ -24,12 +134,8 @@ void load(void) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Create cvars for settings */ |     /* Initialize settings with defaults */ | ||||||
|     if (!cvars_init()) { |     settings_init(); | ||||||
|         fprintf(stderr, "goldsource-cheat: load: error creating cvars, aborting\n"); |  | ||||||
|         self_unload(); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* Hook functions */ |     /* Hook functions */ | ||||||
|     if (!hooks_init()) { |     if (!hooks_init()) { | ||||||
| @@ -38,33 +144,42 @@ void load(void) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Get game version after injecting */ |     /* Register custom commands */ | ||||||
|  |     i_engine->pfnAddCommand("dz_uninject", UNINJECT_CommandHandler); | ||||||
|  |     i_engine->pfnAddCommand("dz_menu", MENU_CommandHandler); | ||||||
|      |      | ||||||
|  |     // Bind INSERT key to dz_menu command (for menu toggle) | ||||||
|  |     i_engine->pfnClientCmd("bind INS dz_menu"); | ||||||
|  |     i_engine->Con_Printf("Bound INSERT key to menu toggle\n"); | ||||||
|  |  | ||||||
|  |     /* Play sound to indicate successful injection */ | ||||||
|     if (IsCS16()) { |     if (IsCS16()) { | ||||||
|         i_engine->pfnClientCmd("play 'sound/radio/go.wav'"); |         i_engine->pfnClientCmd("play weapons/knife_deploy1.wav"); | ||||||
|  |         i_engine->pfnClientCmd("speak \"Cheat successfully loaded\""); | ||||||
|     } |     } | ||||||
|     else if (IsDayOfDefeat()) { |     else if (IsDayOfDefeat()) { | ||||||
|         i_engine->pfnClientCmd("play 'sound/player/gersniper.wav'"); |         i_engine->pfnClientCmd("play weapons/kar_cock.wav"); | ||||||
|  |         i_engine->pfnClientCmd("speak \"Cheat successfully loaded\""); | ||||||
|     } |     } | ||||||
|     else if (IsTFC()) { |     else if (IsTFC()) { | ||||||
|         i_engine->pfnClientCmd("play 'sound/misc/party2.wav'"); |         i_engine->pfnClientCmd("play misc/party2.wav"); | ||||||
|  |         i_engine->pfnClientCmd("speak \"Cheat successfully loaded\""); | ||||||
|     } |     } | ||||||
|     else if (IsDeathmatchClassic()) { |     else if (IsDeathmatchClassic()) { | ||||||
|         i_engine->pfnClientCmd("play 'sound/items/suit.wav'"); |         i_engine->pfnClientCmd("play items/r_item1.wav"); | ||||||
|     } |         i_engine->pfnClientCmd("speak \"Cheat successfully loaded\""); | ||||||
|     else if (IsSpaceLife()) { |  | ||||||
|         i_engine->pfnClientCmd("play 'sound/finley/soccer_ball.wav'"); |  | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         i_engine->pfnClientCmd("play 'valve/sound/vox/suit.wav'"); |         i_engine->pfnClientCmd("play weapons/cbar_hit1.wav"); | ||||||
|  |         i_engine->pfnClientCmd("speak \"Cheat successfully loaded\""); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     i_engine->pfnClientCmd("echo \"goldsource-cheat loaded successfully!\""); |     i_engine->pfnClientCmd("echo \"goldsource-cheat loaded successfully!\""); | ||||||
|     i_engine->pfnClientCmd("echo \"Deadzone rulez!\""); |     i_engine->pfnClientCmd("echo \"Deadzone rulez!\""); | ||||||
|     i_engine->pfnClientCmd("echo \"https://git.deadzone.lol/Wizzard/goldsrc-cheat\""); |     i_engine->pfnClientCmd("echo \"https://git.deadzone.lol/Wizzard/goldsrc-cheat\""); | ||||||
|  |  | ||||||
|  |     /* Get game version after injecting */ | ||||||
|     GameType game = get_current_game(); |     GameType game = get_current_game(); | ||||||
|     switch(game) { |     switch(game) { | ||||||
|         case GAME_HALFLIFE: |         case GAME_HALFLIFE: | ||||||
| @@ -90,20 +205,19 @@ void load(void) { | |||||||
|             break; |             break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return; |  | ||||||
|  |  | ||||||
|     loaded = true; |     loaded = true; | ||||||
| } | } | ||||||
|  |  | ||||||
| __attribute__((destructor)) /* Entry point when unloaded */ | __attribute__((destructor)) /* Entry point when unloaded */ | ||||||
| void unload(void) { | void unload(void) { | ||||||
|     if (loaded) { |     if (loaded) { | ||||||
|         /* TODO: Remove our cvars */ |         /* Reset all settings to default values */ | ||||||
|  |         settings_reset(); | ||||||
|          |          | ||||||
|         globals_restore(); |         globals_restore(); | ||||||
|         hooks_restore(); |         hooks_restore(); | ||||||
|  |  | ||||||
|         GL_UNHOOK(glColor4f); /* Manually restore OpenGL hooks here */ |         // Don't manually unhook GL functions, it's already handled in hooks_restore | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     printf("goldsource-cheat unloaded.\n\n"); |     printf("goldsource-cheat unloaded.\n\n"); | ||||||
|   | |||||||
							
								
								
									
										580
									
								
								src/menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										580
									
								
								src/menu.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,580 @@ | |||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | // This file needs to be compiled as C++ | ||||||
|  | #define IMGUI_IMPLEMENTATION | ||||||
|  | #include "include/menu.h" | ||||||
|  | #include "include/sdk.h" | ||||||
|  | #include "include/globals.h" | ||||||
|  | #include "include/settings.h" | ||||||
|  | #include "include/hooks.h"  // For hook function declarations | ||||||
|  | #include <GL/gl.h> | ||||||
|  |  | ||||||
|  | // Include for mouse button constants | ||||||
|  | #include "include/sdk/public/keydefs.h" | ||||||
|  |  | ||||||
|  | // Access to hitbox enum from aim.c | ||||||
|  | extern const char* hitbox_names[]; | ||||||
|  | extern int current_hitbox; | ||||||
|  |  | ||||||
|  | // Menu state | ||||||
|  | bool g_menu_open = false; | ||||||
|  |  | ||||||
|  | // ImGui context and state | ||||||
|  | ImGuiContext* g_imgui_context = NULL; | ||||||
|  | bool g_imgui_initialized = false; | ||||||
|  |  | ||||||
|  | // Key binding state | ||||||
|  | static bool g_waiting_for_key_bind = false; | ||||||
|  | static const char* g_current_key_binding_action = NULL; | ||||||
|  |  | ||||||
|  | // Fallback menu if ImGui fails | ||||||
|  | static void render_fallback_menu(void); | ||||||
|  |  | ||||||
|  | // Verify OpenGL state is valid | ||||||
|  | static bool check_gl_state(void) { | ||||||
|  |     GLenum error = glGetError(); | ||||||
|  |     if (error != GL_NO_ERROR) { | ||||||
|  |         const char* err_str = "Unknown"; | ||||||
|  |         switch (error) { | ||||||
|  |             case GL_INVALID_ENUM: err_str = "GL_INVALID_ENUM"; break; | ||||||
|  |             case GL_INVALID_VALUE: err_str = "GL_INVALID_VALUE"; break; | ||||||
|  |             case GL_INVALID_OPERATION: err_str = "GL_INVALID_OPERATION"; break; | ||||||
|  |             case GL_STACK_OVERFLOW: err_str = "GL_STACK_OVERFLOW"; break; | ||||||
|  |             case GL_STACK_UNDERFLOW: err_str = "GL_STACK_UNDERFLOW"; break; | ||||||
|  |             case GL_OUT_OF_MEMORY: err_str = "GL_OUT_OF_MEMORY"; break; | ||||||
|  |         } | ||||||
|  |         printf("OpenGL error: %s (0x%x)\n", err_str, error); | ||||||
|  |         i_engine->Con_Printf("OpenGL error: %s (0x%x)\n", err_str, error); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | extern "C" bool menu_init(void) { | ||||||
|  |     // Print debug message | ||||||
|  |     printf("Initializing ImGui menu...\n"); | ||||||
|  |     i_engine->Con_Printf("Initializing ImGui menu...\n"); | ||||||
|  |      | ||||||
|  |     // Check for existing context and cleanup | ||||||
|  |     if (g_imgui_context) { | ||||||
|  |         printf("ImGui context already exists, shutting down first\n"); | ||||||
|  |         menu_shutdown(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check OpenGL state | ||||||
|  |     if (!check_gl_state()) { | ||||||
|  |         printf("OpenGL not ready for ImGui initialization\n"); | ||||||
|  |         i_engine->Con_Printf("Warning: OpenGL state not clean, continuing anyway\n"); | ||||||
|  |         // Not fatal, just a warning | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Create ImGui context | ||||||
|  |     g_imgui_context = ImGui::CreateContext(); | ||||||
|  |     if (!g_imgui_context) { | ||||||
|  |         printf("Failed to create ImGui context\n"); | ||||||
|  |         i_engine->Con_Printf("Error: Failed to create ImGui context\n"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     printf("ImGui context created successfully\n"); | ||||||
|  |     i_engine->Con_Printf("ImGui context created successfully\n"); | ||||||
|  |      | ||||||
|  |     // Configure ImGui | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; | ||||||
|  |     io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; | ||||||
|  |      | ||||||
|  |     // Enable mouse input | ||||||
|  |     io.MouseDrawCursor = false;  // Don't draw cursor until menu is open | ||||||
|  |      | ||||||
|  |     // Get initial screen dimensions | ||||||
|  |     SCREENINFO scr_inf; | ||||||
|  |     scr_inf.iSize = sizeof(SCREENINFO); | ||||||
|  |     i_engine->pfnGetScreenInfo(&scr_inf); | ||||||
|  |      | ||||||
|  |     // Verify and set default dimensions | ||||||
|  |     if (scr_inf.iWidth <= 0 || scr_inf.iHeight <= 0) { | ||||||
|  |         scr_inf.iWidth = 800; | ||||||
|  |         scr_inf.iHeight = 600; | ||||||
|  |         i_engine->Con_Printf("Using default screen dimensions: %dx%d\n",  | ||||||
|  |                            scr_inf.iWidth, scr_inf.iHeight); | ||||||
|  |     } else { | ||||||
|  |         i_engine->Con_Printf("Screen dimensions: %dx%d\n",  | ||||||
|  |                            scr_inf.iWidth, scr_inf.iHeight); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Set initial display size - critical for NewFrame to succeed | ||||||
|  |     io.DisplaySize = ImVec2((float)scr_inf.iWidth, (float)scr_inf.iHeight); | ||||||
|  |      | ||||||
|  |     // Initialize OpenGL implementation for ImGui | ||||||
|  |     bool init_result = ImGui_ImplOpenGL2_Init(); | ||||||
|  |     if (!init_result) { | ||||||
|  |         printf("Failed to initialize ImGui OpenGL2 backend\n"); | ||||||
|  |         i_engine->Con_Printf("Error: Failed to initialize ImGui OpenGL2 backend\n"); | ||||||
|  |         ImGui::DestroyContext(g_imgui_context); | ||||||
|  |         g_imgui_context = NULL; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     printf("ImGui OpenGL2 backend initialized successfully\n"); | ||||||
|  |     i_engine->Con_Printf("ImGui OpenGL2 backend initialized successfully\n"); | ||||||
|  |      | ||||||
|  |     // Set ImGui style | ||||||
|  |     ImGui::StyleColorsDark(); | ||||||
|  |     ImGuiStyle& style = ImGui::GetStyle(); | ||||||
|  |     style.WindowRounding = 5.0f; | ||||||
|  |     style.FrameRounding = 3.0f; | ||||||
|  |     style.ItemSpacing = ImVec2(8, 4); | ||||||
|  |     style.Colors[ImGuiCol_WindowBg] = ImVec4(0.1f, 0.1f, 0.1f, 0.9f); | ||||||
|  |     style.Colors[ImGuiCol_TitleBg] = ImVec4(0.15f, 0.15f, 0.15f, 1.0f); | ||||||
|  |     style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.0f); | ||||||
|  |     style.Colors[ImGuiCol_Button] = ImVec4(0.2f, 0.2f, 0.2f, 1.0f); | ||||||
|  |     style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.3f, 0.3f, 0.3f, 1.0f); | ||||||
|  |     style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.4f, 0.4f, 0.4f, 1.0f); | ||||||
|  |      | ||||||
|  |     // Menu starts closed | ||||||
|  |     g_menu_open = false; | ||||||
|  |     g_imgui_initialized = true; | ||||||
|  |      | ||||||
|  |     // Ensure game has mouse control at start | ||||||
|  |     i_client->IN_ActivateMouse(); | ||||||
|  |      | ||||||
|  |     i_engine->Con_Printf("ImGui menu initialized successfully\n"); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | extern "C" void menu_shutdown(void) { | ||||||
|  |     if (g_imgui_initialized) { | ||||||
|  |         i_engine->Con_Printf("Shutting down ImGui...\n"); | ||||||
|  |          | ||||||
|  |         if (g_imgui_context) { | ||||||
|  |             ImGui_ImplOpenGL2_Shutdown(); | ||||||
|  |             ImGui::DestroyContext(g_imgui_context); | ||||||
|  |             g_imgui_context = NULL; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         g_imgui_initialized = false; | ||||||
|  |         i_engine->Con_Printf("ImGui shutdown complete\n"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Always reset menu state on shutdown | ||||||
|  |     g_menu_open = false; | ||||||
|  |      | ||||||
|  |     // Make sure the game mouse is active when we shut down | ||||||
|  |     i_client->IN_ActivateMouse(); | ||||||
|  |      | ||||||
|  |     // Restore mouse bindings | ||||||
|  |     i_engine->pfnClientCmd("bind mouse1 +attack; bind mouse2 +attack2"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | extern "C" void menu_render(void) { | ||||||
|  |     // Skip rendering if menu is not open | ||||||
|  |     if (!g_menu_open) | ||||||
|  |         return; | ||||||
|  |      | ||||||
|  |     if (g_imgui_initialized && g_imgui_context) { | ||||||
|  |         // Set the current context | ||||||
|  |         ImGui::SetCurrentContext(g_imgui_context); | ||||||
|  |          | ||||||
|  |         // Get screen dimensions | ||||||
|  |         SCREENINFO scr_inf; | ||||||
|  |         scr_inf.iSize = sizeof(SCREENINFO); | ||||||
|  |         i_engine->pfnGetScreenInfo(&scr_inf); | ||||||
|  |          | ||||||
|  |         // Validate screen dimensions | ||||||
|  |         if (scr_inf.iWidth <= 0 || scr_inf.iHeight <= 0) { | ||||||
|  |             i_engine->Con_Printf("Warning: Invalid screen dimensions, using defaults\n"); | ||||||
|  |             scr_inf.iWidth = 800; | ||||||
|  |             scr_inf.iHeight = 600; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Set display size for ImGui | ||||||
|  |         ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |         io.DisplaySize = ImVec2((float)scr_inf.iWidth, (float)scr_inf.iHeight); | ||||||
|  |          | ||||||
|  |         // Start new ImGui frame | ||||||
|  |         ImGui_ImplOpenGL2_NewFrame(); | ||||||
|  |         ImGui::NewFrame(); | ||||||
|  |          | ||||||
|  |         // Set window position and size | ||||||
|  |         ImGui::SetNextWindowPos(ImVec2(scr_inf.iWidth * 0.5f, scr_inf.iHeight * 0.5f),  | ||||||
|  |                                ImGuiCond_Once, ImVec2(0.5f, 0.5f)); | ||||||
|  |         ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Once); | ||||||
|  |          | ||||||
|  |         // Begin main window | ||||||
|  |         if (ImGui::Begin("GoldSource Cheat", &g_menu_open,  | ||||||
|  |                         ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize)) { | ||||||
|  |              | ||||||
|  |             // Create tabs | ||||||
|  |             if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) { | ||||||
|  |                  | ||||||
|  |                 // Aimbot tab | ||||||
|  |                 if (ImGui::BeginTabItem("Aimbot")) { | ||||||
|  |                     if (ImGui::Checkbox("Enable Aimbot", &g_settings.aimbot_enabled)) { | ||||||
|  |                         // No need to set cvar value | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     if (g_settings.aimbot_enabled) { | ||||||
|  |                         if (ImGui::SliderFloat("FOV", &g_settings.aimbot_fov, 0.1f, 180.0f, "%.1f")) { | ||||||
|  |                             // No need to set cvar value | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         if (ImGui::SliderFloat("Smoothing", &g_settings.aimbot_smooth, 1.0f, 100.0f, "%.1f")) { | ||||||
|  |                             // No need to set cvar value | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         const char* hitbox_items[] = { "Head", "Chest", "Stomach", "Pelvis", "Nearest" }; | ||||||
|  |                         if (ImGui::Combo("Hitbox", &g_settings.aimbot_hitbox, hitbox_items, 5)) { | ||||||
|  |                             current_hitbox = g_settings.aimbot_hitbox; | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         ImGui::Checkbox("Auto Shoot", &g_settings.aimbot_autoshoot); | ||||||
|  |                         ImGui::Checkbox("Silent Aim", &g_settings.aimbot_silent); | ||||||
|  |                         ImGui::Checkbox("No Recoil", &g_settings.aimbot_norecoil); | ||||||
|  |                         ImGui::Checkbox("Recoil Compensation", &g_settings.aimbot_recoil_comp); | ||||||
|  |                         ImGui::Checkbox("Shoot Teammates", &g_settings.aimbot_team_attack); | ||||||
|  |                         ImGui::Checkbox("Rage Mode", &g_settings.aimbot_rage_mode); | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::EndTabItem(); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // Visuals tab | ||||||
|  |                 if (ImGui::BeginTabItem("Visuals")) { | ||||||
|  |                     const char* esp_modes[] = {"Off", "2D Box", "Name", "All"}; | ||||||
|  |                     int esp_mode = (int)g_settings.esp_mode; | ||||||
|  |                     if (ImGui::Combo("ESP", &esp_mode, esp_modes, 4)) { | ||||||
|  |                         g_settings.esp_mode = (esp_mode_t)esp_mode; | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("ESP Friendly", &g_settings.esp_friendly); | ||||||
|  |                      | ||||||
|  |                     if (ImGui::SliderFloat("FOV Changer", &g_settings.fov, 70.0f, 140.0f, "%.1f")) { | ||||||
|  |                         // No need to set cvar value | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Chams", &g_settings.chams); | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Custom Crosshair", &g_settings.custom_crosshair); | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Bullet Tracers", &g_settings.tracers); | ||||||
|  |                      | ||||||
|  |                     ImGui::EndTabItem(); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // Movement tab | ||||||
|  |                 if (ImGui::BeginTabItem("Movement")) { | ||||||
|  |                     ImGui::Checkbox("Bunny Hop", &g_settings.bhop); | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Auto Strafe", &g_settings.autostrafe); | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Anti-Aim", &g_settings.antiaim); | ||||||
|  |                      | ||||||
|  |                     if (g_settings.antiaim) { | ||||||
|  |                         ImGui::Checkbox("Anti-Aim View", &g_settings.antiaim_view); | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Fake Duck", &g_settings.fakeduck); | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("CL_Move", &g_settings.clmove); | ||||||
|  |                      | ||||||
|  |                     ImGui::EndTabItem(); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // Misc tab with extra options | ||||||
|  |                 if (ImGui::BeginTabItem("Misc")) { | ||||||
|  |                     ImGui::Checkbox("Name Changer", &g_settings.namechanger); | ||||||
|  |                      | ||||||
|  |                     if (g_settings.namechanger) { | ||||||
|  |                         ImGui::SliderFloat("Name Change Speed", &g_settings.namechanger_speed, 1.0f, 50.0f, "%.1f"); | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::Checkbox("Watermark", &g_settings.watermark); | ||||||
|  |                      | ||||||
|  |                     if (g_settings.watermark) { | ||||||
|  |                         ImGui::Checkbox("Rainbow Watermark", &g_settings.watermark_rainbow); | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::Separator(); | ||||||
|  |                      | ||||||
|  |                     // Menu options | ||||||
|  |                     ImGui::Text("Menu Settings:"); | ||||||
|  |                     ImGui::Checkbox("Allow Movement (WASD) With Menu Open", &g_settings.menu_allow_movement); | ||||||
|  |                      | ||||||
|  |                     ImGui::Separator(); | ||||||
|  |                      | ||||||
|  |                     if (ImGui::Button("Uninject Cheat", ImVec2(150, 30))) { | ||||||
|  |                         i_engine->pfnClientCmd("dz_uninject"); | ||||||
|  |                         g_menu_open = false; | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::EndTabItem(); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // View settings tab | ||||||
|  |                 if (ImGui::BeginTabItem("View")) { | ||||||
|  |                     ImGui::Text("Camera Settings:"); | ||||||
|  |                      | ||||||
|  |                     // Third-person settings | ||||||
|  |                     bool thirdperson_changed = ImGui::Checkbox("Third-Person View", &g_settings.thirdperson); | ||||||
|  |                      | ||||||
|  |                     if (g_settings.thirdperson) { | ||||||
|  |                         // Distance preset buttons with direct setting of values | ||||||
|  |                         ImGui::BeginGroup(); | ||||||
|  |                         if (ImGui::Button("100")) { | ||||||
|  |                             g_settings.thirdperson_dist = 100.0f; | ||||||
|  |                         } | ||||||
|  |                         ImGui::SameLine(); | ||||||
|  |                         if (ImGui::Button("270")) { | ||||||
|  |                             g_settings.thirdperson_dist = 270.0f; | ||||||
|  |                         } | ||||||
|  |                         ImGui::SameLine(); | ||||||
|  |                         if (ImGui::Button("500")) { | ||||||
|  |                             g_settings.thirdperson_dist = 500.0f; | ||||||
|  |                         } | ||||||
|  |                         ImGui::EndGroup(); | ||||||
|  |                          | ||||||
|  |                         // Distance slider - DIRECTLY changes the value without console commands | ||||||
|  |                         ImGui::SliderFloat("Camera Distance", &g_settings.thirdperson_dist, 30.0f, 800.0f, "%.1f"); | ||||||
|  |                          | ||||||
|  |                         // Remove multiplier message since we don't multiply anymore | ||||||
|  |                         ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Camera distance updates in real-time"); | ||||||
|  |                          | ||||||
|  |                         // Key binding for third-person toggle | ||||||
|  |                         ImGui::Separator(); | ||||||
|  |                         ImGui::Text("Keybind for Third-Person Toggle:"); | ||||||
|  |                          | ||||||
|  |                         // Display current key binding | ||||||
|  |                         const char* key_name = "None"; | ||||||
|  |                         if (g_settings.thirdperson_key > 0) { | ||||||
|  |                             // Get better key names | ||||||
|  |                             switch(g_settings.thirdperson_key) { | ||||||
|  |                                 case 'F': key_name = "F"; break; | ||||||
|  |                                 case 'V': key_name = "V"; break; | ||||||
|  |                                 case 'T': key_name = "T"; break; | ||||||
|  |                                 case 'P': key_name = "P"; break; | ||||||
|  |                                 case 'C': key_name = "C"; break; | ||||||
|  |                                 case K_F1: key_name = "F1"; break; | ||||||
|  |                                 case K_F2: key_name = "F2"; break; | ||||||
|  |                                 case K_F3: key_name = "F3"; break; | ||||||
|  |                                 case K_F4: key_name = "F4"; break; | ||||||
|  |                                 case K_F5: key_name = "F5"; break; | ||||||
|  |                                 case K_TAB: key_name = "Tab"; break; | ||||||
|  |                                 case K_SPACE: key_name = "Space"; break; | ||||||
|  |                                 case K_CTRL: key_name = "Ctrl"; break; | ||||||
|  |                                 case K_SHIFT: key_name = "Shift"; break; | ||||||
|  |                                 case K_ALT: key_name = "Alt"; break; | ||||||
|  |                                 case K_MOUSE1: key_name = "Mouse1"; break; | ||||||
|  |                                 case K_MOUSE2: key_name = "Mouse2"; break; | ||||||
|  |                                 case K_MOUSE3: key_name = "Mouse3"; break; | ||||||
|  |                                 default: { | ||||||
|  |                                     // For printable characters | ||||||
|  |                                     if (g_settings.thirdperson_key >= 32 && g_settings.thirdperson_key <= 126) { | ||||||
|  |                                         static char chr[2] = {0}; | ||||||
|  |                                         chr[0] = (char)g_settings.thirdperson_key; | ||||||
|  |                                         key_name = chr; | ||||||
|  |                                     } else { | ||||||
|  |                                         // For other keys, show keycode | ||||||
|  |                                         static char code[32] = {0}; | ||||||
|  |                                         snprintf(code, sizeof(code), "Key %d", g_settings.thirdperson_key); | ||||||
|  |                                         key_name = code; | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         ImGui::Text("Current Key: %s", key_name); | ||||||
|  |                          | ||||||
|  |                         // TEMP: Disabled key binding until fixed | ||||||
|  |                         // Disable any active key bindings | ||||||
|  |                         if (g_waiting_for_key_bind) { | ||||||
|  |                             g_waiting_for_key_bind = false; | ||||||
|  |                             g_current_key_binding_action = NULL; | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         // Show preset buttons instead | ||||||
|  |                         if (ImGui::Button("Bind to C", ImVec2(100, 25))) { | ||||||
|  |                             g_settings.thirdperson_key = 'C'; | ||||||
|  |                             i_engine->Con_Printf("Third-person toggle bound to C key\n"); | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         ImGui::SameLine(); | ||||||
|  |                          | ||||||
|  |                         if (ImGui::Button("Bind to V", ImVec2(100, 25))) { | ||||||
|  |                             g_settings.thirdperson_key = 'V'; | ||||||
|  |                             i_engine->Con_Printf("Third-person toggle bound to V key\n"); | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         ImGui::SameLine(); | ||||||
|  |                          | ||||||
|  |                         if (ImGui::Button("Bind to F", ImVec2(100, 25))) { | ||||||
|  |                             g_settings.thirdperson_key = 'F'; | ||||||
|  |                             i_engine->Con_Printf("Third-person toggle bound to F key\n"); | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         ImGui::SameLine(); | ||||||
|  |                          | ||||||
|  |                         if (ImGui::Button("Clear", ImVec2(80, 25))) { | ||||||
|  |                             g_settings.thirdperson_key = 0; | ||||||
|  |                             i_engine->Con_Printf("Third-person key binding cleared\n"); | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         ImGui::Text("Note: Default binding is C key"); | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     ImGui::EndTabItem(); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 ImGui::EndTabBar(); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             ImGui::End(); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Render ImGui | ||||||
|  |         ImGui::Render(); | ||||||
|  |         ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); | ||||||
|  |     } else { | ||||||
|  |         render_fallback_menu(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // This is our fallback menu that we know works | ||||||
|  | static void render_fallback_menu(void) { | ||||||
|  |     // Get screen dimensions | ||||||
|  |     SCREENINFO scr_inf; | ||||||
|  |     scr_inf.iSize = sizeof(SCREENINFO); | ||||||
|  |     i_engine->pfnGetScreenInfo(&scr_inf); | ||||||
|  |      | ||||||
|  |     // Draw simple menu background | ||||||
|  |     int x1 = scr_inf.iWidth / 4; | ||||||
|  |     int y1 = scr_inf.iHeight / 4; | ||||||
|  |     int x2 = scr_inf.iWidth * 3 / 4; | ||||||
|  |     int y2 = scr_inf.iHeight * 3 / 4; | ||||||
|  |      | ||||||
|  |     // More visible background (darker black with higher alpha) | ||||||
|  |     i_engine->pfnFillRGBA(x1, y1, x2-x1, y2-y1, 0, 0, 0, 230); | ||||||
|  |      | ||||||
|  |     // Draw bright border for visibility | ||||||
|  |     i_engine->pfnFillRGBA(x1, y1, x2-x1, 2, 255, 0, 0, 255);  // Top | ||||||
|  |     i_engine->pfnFillRGBA(x1, y2-2, x2-x1, 2, 255, 0, 0, 255); // Bottom | ||||||
|  |     i_engine->pfnFillRGBA(x1, y1, 2, y2-y1, 255, 0, 0, 255);  // Left | ||||||
|  |     i_engine->pfnFillRGBA(x2-2, y1, 2, y2-y1, 255, 0, 0, 255); // Right | ||||||
|  |      | ||||||
|  |     // Title | ||||||
|  |     i_engine->pfnDrawSetTextColor(1.0f, 1.0f, 0.0f); | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+10, y1+10, "===== GoldSource Cheat Menu (Fallback) ====="); | ||||||
|  |      | ||||||
|  |     // Reset color for menu items | ||||||
|  |     i_engine->pfnDrawSetTextColor(0.0f, 1.0f, 1.0f); | ||||||
|  |      | ||||||
|  |     // Draw menu items | ||||||
|  |     int y = y1 + 40; | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+20, y, "-- Aimbot Settings --"); | ||||||
|  |     y += 20; | ||||||
|  |      | ||||||
|  |     char buffer[128]; | ||||||
|  |      | ||||||
|  |     bool aimbot_enabled = g_settings.aimbot_enabled; | ||||||
|  |     snprintf(buffer, sizeof(buffer), "- Aimbot: %s", aimbot_enabled ? "ON" : "OFF"); | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+30, y, buffer); | ||||||
|  |     y += 15; | ||||||
|  |      | ||||||
|  |     if (aimbot_enabled) { | ||||||
|  |         snprintf(buffer, sizeof(buffer), "- FOV: %.1f", g_settings.aimbot_fov); | ||||||
|  |         i_engine->pfnDrawConsoleString(x1+30, y, buffer); | ||||||
|  |         y += 15; | ||||||
|  |          | ||||||
|  |         snprintf(buffer, sizeof(buffer), "- Smoothing: %.1f", g_settings.aimbot_smooth); | ||||||
|  |         i_engine->pfnDrawConsoleString(x1+30, y, buffer); | ||||||
|  |         y += 15; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     y += 10; | ||||||
|  |     i_engine->pfnDrawSetTextColor(0.0f, 1.0f, 1.0f); | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+20, y, "-- Visual Settings --"); | ||||||
|  |     y += 20; | ||||||
|  |      | ||||||
|  |     int esp_mode = (int)g_settings.esp_mode; | ||||||
|  |     snprintf(buffer, sizeof(buffer), "- ESP: %s", esp_mode > 0 ? "ON" : "OFF"); | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+30, y, buffer); | ||||||
|  |     y += 15; | ||||||
|  |      | ||||||
|  |     bool chams_enabled = g_settings.chams; | ||||||
|  |     snprintf(buffer, sizeof(buffer), "- Chams: %s", chams_enabled ? "ON" : "OFF"); | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+30, y, buffer); | ||||||
|  |     y += 30; | ||||||
|  |      | ||||||
|  |     // Instructions | ||||||
|  |     i_engine->pfnDrawSetTextColor(1.0f, 1.0f, 0.0f); | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+20, y, "Press INSERT to close menu"); | ||||||
|  |     y += 20; | ||||||
|  |     i_engine->pfnDrawConsoleString(x1+20, y, "Use console to change settings"); | ||||||
|  |      | ||||||
|  |     // Draw help in bottom corner | ||||||
|  |     i_engine->pfnDrawSetTextColor(0.7f, 0.7f, 0.7f); | ||||||
|  |     i_engine->pfnDrawConsoleString(5, scr_inf.iHeight - 20, "Type 'dz_menu' in console to toggle menu"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Update the key event handler to support key binding | ||||||
|  | extern "C" void menu_key_event(int keynum, int down) { | ||||||
|  |     // Add debug output | ||||||
|  |     i_engine->Con_Printf("menu_key_event called: keynum=%d, down=%d\n", keynum, down); | ||||||
|  |      | ||||||
|  |     // If we're waiting for a key bind and a key is pressed down | ||||||
|  |     if (g_waiting_for_key_bind && down && keynum != K_ESCAPE) { | ||||||
|  |         // Don't bind mouse wheel or menu toggle key | ||||||
|  |         if (keynum != K_MWHEELDOWN && keynum != K_MWHEELUP && keynum != K_INS) { | ||||||
|  |             // Bind the key based on current action | ||||||
|  |             if (g_current_key_binding_action && strcmp(g_current_key_binding_action, "thirdperson") == 0) { | ||||||
|  |                 g_settings.thirdperson_key = keynum; | ||||||
|  |                 i_engine->Con_Printf("Third-person key bound to keycode: %d\n", keynum); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Exit binding mode | ||||||
|  |             g_waiting_for_key_bind = false; | ||||||
|  |             g_current_key_binding_action = NULL; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Cancel key binding if escape is pressed | ||||||
|  |     if (g_waiting_for_key_bind && down && keynum == K_ESCAPE) { | ||||||
|  |         g_waiting_for_key_bind = false; | ||||||
|  |         g_current_key_binding_action = NULL; | ||||||
|  |         i_engine->Con_Printf("Key binding canceled\n"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (keynum == K_INS && down) { | ||||||
|  |         // Toggle menu state | ||||||
|  |         g_menu_open = !g_menu_open; | ||||||
|  |         i_engine->Con_Printf("Menu %s\n", g_menu_open ? "opened" : "closed"); | ||||||
|  |          | ||||||
|  |         // Update ImGui IO if initialized | ||||||
|  |         if (g_imgui_initialized && g_imgui_context) { | ||||||
|  |             ImGui::SetCurrentContext(g_imgui_context); | ||||||
|  |             ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |             io.MouseDrawCursor = g_menu_open; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Activate or deactivate mouse based on menu state | ||||||
|  |         if (g_menu_open) { | ||||||
|  |             // When opening menu, deactivate mouse in game and use our own cursor | ||||||
|  |             i_client->IN_DeactivateMouse(); | ||||||
|  |             i_client->IN_ClearStates(); | ||||||
|  |              | ||||||
|  |             // Fixes potential issues with key state | ||||||
|  |             i_engine->pfnClientCmd("unbind mouse1; unbind mouse2"); | ||||||
|  |             i_engine->Con_Printf("Mouse deactivated for game, using ImGui cursor\n"); | ||||||
|  |         } else { | ||||||
|  |             // When closing menu, reactivate mouse in game | ||||||
|  |             i_client->IN_ActivateMouse(); | ||||||
|  |              | ||||||
|  |             // Restore default bindings | ||||||
|  |             i_engine->pfnClientCmd("bind mouse1 +attack; bind mouse2 +attack2"); | ||||||
|  |             i_engine->Con_Printf("Mouse reactivated for game\n"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }  | ||||||
							
								
								
									
										56
									
								
								src/settings.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/settings.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | #include "include/settings.h" | ||||||
|  | #include "include/sdk.h" | ||||||
|  | #include "include/globals.h" | ||||||
|  | #include "include/game_detection.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | cheat_settings_t g_settings; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void settings_init(void) { | ||||||
|  |      | ||||||
|  |     init_default_settings(); | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     g_settings.thirdperson_key = 'C'; | ||||||
|  |      | ||||||
|  |     i_engine->Con_Printf("Settings initialized with defaults. Third-person key bound to C.\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void settings_reset(void) { | ||||||
|  |      | ||||||
|  |     g_settings.esp_mode = ESP_OFF; | ||||||
|  |     g_settings.esp_friendly = false; | ||||||
|  |     g_settings.chams = false; | ||||||
|  |     g_settings.tracers = false; | ||||||
|  |     g_settings.custom_crosshair = false; | ||||||
|  |     g_settings.watermark = false; | ||||||
|  |     g_settings.watermark_rainbow = false; | ||||||
|  |      | ||||||
|  |     g_settings.aimbot_enabled = false; | ||||||
|  |     g_settings.aimbot_autoshoot = false; | ||||||
|  |     g_settings.aimbot_silent = false; | ||||||
|  |     g_settings.aimbot_norecoil = false; | ||||||
|  |     g_settings.aimbot_recoil_comp = false; | ||||||
|  |     g_settings.aimbot_friendly_fire = false; | ||||||
|  |     g_settings.aimbot_rage_mode = false; | ||||||
|  |     g_settings.aimbot_team_attack = false; | ||||||
|  |      | ||||||
|  |     g_settings.bhop = false; | ||||||
|  |     g_settings.autostrafe = false; | ||||||
|  |     g_settings.antiaim = false; | ||||||
|  |     g_settings.antiaim_view = false; | ||||||
|  |     g_settings.fakeduck = false; | ||||||
|  |     g_settings.clmove = false; | ||||||
|  |      | ||||||
|  |     g_settings.namechanger = false; | ||||||
|  |      | ||||||
|  |     g_settings.fov = 90.0f; | ||||||
|  |      | ||||||
|  |     g_settings.thirdperson = false; | ||||||
|  |     g_settings.thirdperson_key = 0; | ||||||
|  |     g_settings.thirdperson_dist = 150.0f; | ||||||
|  |      | ||||||
|  |     i_engine->pfnClientCmd("echo \"All cheat settings have been reset to default values\""); | ||||||
|  | }  | ||||||
							
								
								
									
										16
									
								
								src/util.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/util.c
									
									
									
									
									
								
							| @@ -108,16 +108,16 @@ float vec_len2d(vec3_t v) { | |||||||
|     return sqrtf(v.x * v.x + v.y * v.y); |     return sqrtf(v.x * v.x + v.y * v.y); | ||||||
| } | } | ||||||
|  |  | ||||||
| void vec_clamp(vec3_t v) { | void ang_clamp(vec3_t* v) { | ||||||
|     v.x = CLAMP(v.x, -89.0f, 89.0f); |     v->x = CLAMP(v->x, -89.0f, 89.0f); | ||||||
|     v.y = CLAMP(remainderf(v.y, 360.0f), -180.0f, 180.0f); /* v.y % 360 */ |     v->y = CLAMP(remainderf(v->y, 360.0f), -180.0f, 180.0f); | ||||||
|     v.z = CLAMP(v.z, -50.0f, 50.0f); |     v->z = CLAMP(v->z, -50.0f, 50.0f); | ||||||
| } | } | ||||||
|  |  | ||||||
| void vec_norm(vec3_t v) { | void vec_norm(vec3_t* v) { | ||||||
|     v.x = isfinite(v.x) ? remainder(v.x, 360) : 0; |     v->x = isfinite(v->x) ? remainderf(v->x, 360.f) : 0.f; | ||||||
|     v.y = isfinite(v.y) ? remainder(v.y, 360) : 0; |     v->y = isfinite(v->y) ? remainderf(v->y, 360.f) : 0.f; | ||||||
|     v.z = 0.0f; |     v->z = 0.0f; | ||||||
| } | } | ||||||
|  |  | ||||||
| float angle_delta_rad(float a, float b) { | float angle_delta_rad(float a, float b) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user