diff --git a/src/auto-splitter.c b/src/auto-splitter.c index fd067de..a73a61c 100644 --- a/src/auto-splitter.c +++ b/src/auto-splitter.c @@ -21,11 +21,15 @@ char auto_splitter_file[PATH_MAX]; int refresh_rate = 60; int maps_cache_cycles = 0; // 0=off, 1=current cycle, +1=multiple cycles int maps_cache_cycles_value = 0; // same as `maps_cache_cycles` but this one represents the current value rather than the reference from the script +atomic_bool timer_started = false; atomic_bool auto_splitter_enabled = true; atomic_bool call_start = false; +atomic_bool call_on_start = false; atomic_bool call_split = false; +atomic_bool call_on_split = false; atomic_bool toggle_loading = false; atomic_bool call_reset = false; +atomic_bool call_on_reset = false; bool prev_is_loading; static const char* disabled_functions[] = { @@ -245,18 +249,37 @@ bool call_va(lua_State* L, const char* func, const char* sig, ...) return true; } +int get_process_names(lua_State* L, char process_names[100][256], int* num_process_names) +{ + lua_getglobal(L, "State"); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + if (lua_istable(L, -1)) { + const char* process_name = lua_tostring(L, -2); + + strncpy(process_names[*num_process_names], process_name, 255); + process_names[*num_process_names][255] = '\0'; + (*num_process_names)++; + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + return *num_process_names; +} + void startup(lua_State* L) { - lua_getglobal(L, "startup"); - lua_pcall(L, 0, 0, 0); + call_va(L, "Startup", ""); - lua_getglobal(L, "refreshRate"); + lua_getglobal(L, "RefreshRate"); if (lua_isnumber(L, -1)) { refresh_rate = lua_tointeger(L, -1); } lua_pop(L, 1); // Remove 'refreshRate' from the stack - lua_getglobal(L, "mapsCacheCycles"); + lua_getglobal(L, "MapsCacheCycles"); if (lua_isnumber(L, -1)) { maps_cache_cycles = lua_tointeger(L, -1); maps_cache_cycles_value = maps_cache_cycles; @@ -264,77 +287,153 @@ void startup(lua_State* L) lua_pop(L, 1); // Remove 'mapsCacheCycles' from the stack } -void state(lua_State* L) -{ - call_va(L, "state", ""); -} - -void update(lua_State* L) +bool update(lua_State* L) { - call_va(L, "update", ""); + bool ret; + if (call_va(L, "Update", ">b", &ret)) { + lua_pop(L, 1); + return ret; + } + lua_pop(L, 1); + return true; } -void start(lua_State* L) +bool start(lua_State* L) { bool ret; - if (call_va(L, "start", ">b", &ret)) { - atomic_store(&call_start, ret); + if (call_va(L, "Start", ">b", &ret) && ret) { + atomic_store(&call_start, true); + printf("Start: true\n"); + lua_pop(L, 1); + return true; } lua_pop(L, 1); // Remove the return value from the stack + return false; } -void split(lua_State* L) +bool split(lua_State* L) { bool ret; - if (call_va(L, "split", ">b", &ret)) { - atomic_store(&call_split, ret); + if (call_va(L, "Split", ">b", &ret) && ret) { + atomic_store(&call_split, true); + printf("Split: true\n"); + lua_pop(L, 1); + return true; } lua_pop(L, 1); // Remove the return value from the stack + return false; } void is_loading(lua_State* L) { - bool loading; - if (call_va(L, "isLoading", ">b", &loading)) { - if (loading != prev_is_loading) { + bool ret; + if (call_va(L, "IsLoading", ">b", &ret)) { + if (ret != prev_is_loading) { atomic_store(&toggle_loading, true); + printf("IsLoading: %s\n", ret ? "true" : "false"); prev_is_loading = !prev_is_loading; } } lua_pop(L, 1); // Remove the return value from the stack } -void reset(lua_State* L) +bool reset(lua_State* L) +{ + bool ret; + if (call_va(L, "Reset", ">b", &ret) && ret) { + atomic_store(&call_reset, true); + printf("Reset: true\n"); + lua_pop(L, 1); + return true; + } + lua_pop(L, 1); + return false; +} + +const char* version(lua_State* L) { - bool shouldReset; - if (call_va(L, "reset", ">b", &shouldReset)) { - if (shouldReset) - atomic_store(&call_reset, true); + lua_getglobal(L, "Version"); + if (lua_isstring(L, -1)) { + const char* version = lua_tostring(L, -1); + lua_pop(L, 1); + printf("Version: %s\n", version); + return version; + } + lua_pop(L, 1); + return NULL; +} + +bool lua_function_exists(lua_State* L, const char* func_name) +{ + lua_getglobal(L, func_name); + bool exists = lua_isfunction(L, -1); + lua_pop(L, 1); + return exists; +} + +void run_auto_splitter_cycle( + lua_State* L, + bool memory_map_exists, + bool start_exists, + bool on_start_exists, + bool split_exists, + bool on_split_exists, + bool is_loading_exists, + bool reset_exists, + bool on_reset_exists, + bool update_exists) +{ + if ((update_exists && !update(L)) || !memory_map_exists) { + return; + } + + read_address(L); + + if (is_loading_exists) { + is_loading(L); + } + + if (!atomic_load(&timer_started)) { + if (start_exists) { + start(L); + } + } else if (reset_exists) { + reset(L); + } else if (split_exists) { + split(L); + } + + if (on_start_exists && atomic_load(&call_on_start)) { + call_va(L, "OnStart", ""); + atomic_store(&call_on_start, false); + } + + if (on_split_exists && atomic_load(&call_on_split)) { + call_va(L, "OnSplit", ""); + atomic_store(&call_on_split, false); + } + + if (on_reset_exists && atomic_load(&call_on_reset)) { + call_va(L, "OnReset", ""); + atomic_store(&call_on_reset, false); + } + + // Clear the memory maps cache if needed + maps_cache_cycles_value--; + if (maps_cache_cycles_value < 1) { + p_maps_cache_size = 0; // We dont need to "empty" the list as the elements after index 0 are considered invalid + maps_cache_cycles_value = maps_cache_cycles; + // printf("Cleared maps cache\n"); } - lua_pop(L, 1); // Remove the return value from the stack } void run_auto_splitter() { lua_State* L = luaL_newstate(); - luaL_openlibs(L); - disable_functions(L, disabled_functions); - lua_pushcfunction(L, find_process_id); - lua_setglobal(L, "process"); - lua_pushcfunction(L, read_address); - lua_setglobal(L, "readAddress"); - lua_pushcfunction(L, getPid); - lua_setglobal(L, "getPID"); - - char current_file[PATH_MAX]; - strcpy(current_file, auto_splitter_file); // Load the Lua file if (luaL_loadfile(L, auto_splitter_file) != LUA_OK) { - // Error loading the file - const char* error_msg = lua_tostring(L, -1); - lua_pop(L, 1); // Remove the error message from the stack - fprintf(stderr, "Lua syntax error: %s\n", error_msg); + fprintf(stderr, "Lua syntax error: %s\n", lua_tostring(L, -1)); lua_close(L); atomic_store(&auto_splitter_enabled, false); return; @@ -342,42 +441,36 @@ void run_auto_splitter() // Execute the Lua file if (lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) { - // Error executing the file - const char* error_msg = lua_tostring(L, -1); - lua_pop(L, 1); // Remove the error message from the stack - fprintf(stderr, "Lua runtime error: %s\n", error_msg); + fprintf(stderr, "Lua runtime error: %s\n", lua_tostring(L, -1)); lua_close(L); atomic_store(&auto_splitter_enabled, false); return; } - lua_getglobal(L, "state"); - bool state_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'state' from the stack - - lua_getglobal(L, "start"); - bool start_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'start' from the stack - - lua_getglobal(L, "split"); - bool split_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'split' from the stack - - lua_getglobal(L, "isLoading"); - bool is_loading_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'isLoading' from the stack - - lua_getglobal(L, "startup"); - bool startup_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'startup' from the stack + luaL_openlibs(L); + disable_functions(L, disabled_functions); + lua_pushcfunction(L, getPid); + lua_setglobal(L, "getPID"); + lua_newtable(L); + lua_setglobal(L, "vars"); - lua_getglobal(L, "reset"); - bool reset_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'reset' from the stack + char current_file[PATH_MAX]; + strcpy(current_file, auto_splitter_file); - lua_getglobal(L, "update"); - bool update_exists = lua_isfunction(L, -1); - lua_pop(L, 1); // Remove 'update' from the stack + bool start_exists = lua_function_exists(L, "Start"); + bool on_start_exists = lua_function_exists(L, "OnStart"); + bool split_exists = lua_function_exists(L, "Split"); + bool on_split_exists = lua_function_exists(L, "OnSplit"); + bool is_loading_exists = lua_function_exists(L, "IsLoading"); + bool startup_exists = lua_function_exists(L, "Startup"); + bool reset_exists = lua_function_exists(L, "Reset"); + bool on_reset_exists = lua_function_exists(L, "OnReset"); + bool update_exists = lua_function_exists(L, "Update"); + bool init_exists = lua_function_exists(L, "Init"); + bool memory_map_exists = false; + atomic_store(&call_on_start, false); + atomic_store(&call_on_split, false); + atomic_store(&call_on_reset, false); if (startup_exists) { startup(L); @@ -386,45 +479,44 @@ void run_auto_splitter() printf("Refresh rate: %d\n", refresh_rate); int rate = 1000000 / refresh_rate; + char process_names[100][256]; + int num_process_names = 0; + const char* version_str; + if (get_process_names(L, process_names, &num_process_names)) { + if (find_process_id(process_names, num_process_names)) { + if (init_exists) { + call_va(L, "Init", ""); + } + lua_newtable(L); + lua_setglobal(L, "old"); + lua_newtable(L); + lua_setglobal(L, "current"); + version_str = version(L); + memory_map_exists = store_memory_tables(L, version_str); + } + } + while (1) { struct timespec clock_start; clock_gettime(CLOCK_MONOTONIC, &clock_start); - if (!atomic_load(&auto_splitter_enabled) || strcmp(current_file, auto_splitter_file) != 0 || !process_exists() || process.pid == 0) { + if (!process_exists() && find_process_id(process_names, num_process_names) && init_exists) { + call_va(L, "Init", ""); + } else if (!atomic_load(&auto_splitter_enabled) || strcmp(current_file, auto_splitter_file) != 0) { break; } - if (state_exists) { - state(L); - } - - if (update_exists) { - update(L); - } - - if (start_exists) { - start(L); - } - - if (split_exists) { - split(L); - } - - if (is_loading_exists) { - is_loading(L); - } - - if (reset_exists) { - reset(L); - } - - // Clear the memory maps cache if needed - maps_cache_cycles_value--; - if (maps_cache_cycles_value < 1) { - p_maps_cache_size = 0; // We dont need to "empty" the list as the elements after index 0 are considered invalid - maps_cache_cycles_value = maps_cache_cycles; - // printf("Cleared maps cache\n"); - } + run_auto_splitter_cycle( + L, + memory_map_exists, + start_exists, + on_start_exists, + split_exists, + on_split_exists, + is_loading_exists, + reset_exists, + on_reset_exists, + update_exists); struct timespec clock_end; clock_gettime(CLOCK_MONOTONIC, &clock_end); diff --git a/src/auto-splitter.h b/src/auto-splitter.h index d43c962..78f4751 100644 --- a/src/auto-splitter.h +++ b/src/auto-splitter.h @@ -4,11 +4,15 @@ #include #include +extern atomic_bool timer_started; extern atomic_bool auto_splitter_enabled; extern atomic_bool call_start; +extern atomic_bool call_on_start; extern atomic_bool call_split; +extern atomic_bool call_on_split; extern atomic_bool toggle_loading; extern atomic_bool call_reset; +extern atomic_bool call_on_reset; extern char auto_splitter_file[PATH_MAX]; extern int maps_cache_cycles_value; diff --git a/src/main.c b/src/main.c index b9b8eee..4527800 100644 --- a/src/main.c +++ b/src/main.c @@ -150,6 +150,7 @@ static gboolean ls_app_window_step(gpointer data) if (win->timer) { ls_timer_step(win->timer, now); + atomic_store(&timer_started, win->timer->started); if (atomic_load(&auto_splitter_enabled)) { if (atomic_load(&call_start) && !win->timer->loading) { timer_start(win); diff --git a/src/memory.c b/src/memory.c index 92191f1..eaa9845 100644 --- a/src/memory.c +++ b/src/memory.c @@ -11,7 +11,8 @@ #include "memory.h" #include "process.h" -bool memory_error; +MemoryTable memory_tables[MAX_MEMORY_TABLES]; +int memory_table_count = 0; extern game_process process; #define READ_MEMORY_FUNCTION(value_type) \ @@ -30,7 +31,6 @@ extern game_process process; ssize_t mem_n_read = process_vm_readv(process.pid, &mem_local, 1, &mem_remote, 1, 0); \ if (mem_n_read == -1) { \ *err = (int32_t)errno; \ - memory_error = true; \ } else if (mem_n_read != (ssize_t)mem_remote.iov_len) { \ printf("Error reading process memory: short read of %ld bytes\n", (long)mem_n_read); \ exit(1); \ @@ -51,7 +51,7 @@ READ_MEMORY_FUNCTION(float) READ_MEMORY_FUNCTION(double) READ_MEMORY_FUNCTION(bool) -char* read_memory_string(uint64_t mem_address, int buffer_size) +char* read_memory_string(uint64_t mem_address, int buffer_size, int32_t* err) { char* buffer = (char*)malloc(buffer_size); if (buffer == NULL) { @@ -70,6 +70,7 @@ char* read_memory_string(uint64_t mem_address, int buffer_size) ssize_t mem_n_read = process_vm_readv(process.pid, &mem_local, 1, &mem_remote, 1, 0); if (mem_n_read == -1) { buffer[0] = '\0'; + *err = (int32_t)errno; } else if (mem_n_read != (ssize_t)mem_remote.iov_len) { printf("Error reading process memory: short read of %ld bytes\n", (long)mem_n_read); exit(1); @@ -83,16 +84,17 @@ char* read_memory_string(uint64_t mem_address, int buffer_size) True if the error was printed False if the error is unknown */ -bool handle_memory_error(uint32_t err) +bool handle_memory_error(uint32_t err, const char* table_name) { if (err == 0) return false; + printf("%s\t", table_name); switch (err) { case EFAULT: printf("EFAULT: Invalid memory space/address\n"); break; case EINVAL: - printf("EINVAL: An error ocurred while reading memory\n"); + printf("EINVAL: An error occurred while reading memory\n"); break; case ENOMEM: printf("ENOMEM: Please get more memory\n"); @@ -107,92 +109,203 @@ bool handle_memory_error(uint32_t err) return true; } -int read_address(lua_State* L) +void read_address(lua_State* L) { - memory_error = false; - uint64_t address; - const char* value_type = lua_tostring(L, 1); - int i; - - if (lua_isnumber(L, 2)) { - address = process.base_address + lua_tointeger(L, 2); - i = 3; - } else { - const char* module = lua_tostring(L, 2); - if (strcmp(process.name, module) != 0) { - process.dll_address = find_base_address(module); + for (int i = 0; i < memory_table_count; i++) { + uint64_t address = 0; + int error = 0; + const MemoryTable* table = &memory_tables[i]; + + const char* table_name = table->name; + const char* value_type = table->type; + + if (table->module) { + if (strcmp(process.name, table->module) != 0) { + process.dll_address = find_base_address(table->module); + } + address = process.dll_address + table->address; + } else { + address = process.base_address + table->address; + } + + for (int i = 0; i < table->offset_count; i++) { + if (address <= UINT32_MAX) { + address = read_memory_uint32_t((uint64_t)address, &error); + if (error) + break; + } else { + address = read_memory_uint64_t(address, &error); + if (error) + break; + } + address += table->offsets[i]; } - address = process.dll_address + lua_tointeger(L, 3); - i = 4; - } - int error = 0; + // Set the old value to the current value + lua_getglobal(L, "current"); + if (lua_istable(L, -1)) { + lua_getfield(L, -1, table_name); + if (!lua_isnil(L, -1)) { + lua_getglobal(L, "old"); + lua_pushvalue(L, -2); + lua_setfield(L, -2, table_name); + lua_pop(L, 1); // Old table + } + lua_pop(L, 1); // current value or nil + } - for (; i <= lua_gettop(L); i++) { - if (address <= UINT32_MAX) { - address = read_memory_uint32_t((uint64_t)address, &error); - if (memory_error) - break; + // Read the new value + if (strcmp(value_type, "sbyte") == 0) { + int8_t value = read_memory_int8_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "byte") == 0) { + uint8_t value = read_memory_uint8_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "short") == 0) { + short value = read_memory_int16_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "ushort") == 0) { + unsigned short value = read_memory_uint16_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "int") == 0) { + int value = read_memory_int32_t(address, &error); + lua_pushinteger(L, value); + } else if (strcmp(value_type, "uint") == 0) { + unsigned int value = read_memory_uint32_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "long") == 0) { + long value = read_memory_int64_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "ulong") == 0) { + unsigned long value = read_memory_uint64_t(address, &error); + lua_pushinteger(L, (int)value); + } else if (strcmp(value_type, "float") == 0) { + float value = read_memory_float(address, &error); + lua_pushnumber(L, (double)value); + } else if (strcmp(value_type, "double") == 0) { + double value = read_memory_double(address, &error); + lua_pushnumber(L, value); + } else if (strcmp(value_type, "bool") == 0) { + bool value = read_memory_bool(address, &error); + lua_pushboolean(L, value ? 1 : 0); + } else if (strstr(value_type, "string") != NULL) { + int buffer_size = atoi(value_type + 6); + if (buffer_size < 2) { + printf("Invalid string size, please read documentation"); + exit(1); + } + char* value = read_memory_string(address, buffer_size, &error); + lua_pushstring(L, value != NULL ? value : ""); + free(value); } else { - address = read_memory_uint64_t(address, &error); - if (memory_error) - break; + printf("Invalid value type: %s\n", value_type); + exit(1); + } + + if (error) { + handle_memory_error(error, table_name); + continue; } - address += lua_tointeger(L, i); + + lua_setfield(L, -2, table_name); + lua_pop(L, 1); // current table } +} - if (strcmp(value_type, "sbyte") == 0) { - int8_t value = read_memory_int8_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "byte") == 0) { - uint8_t value = read_memory_uint8_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "short") == 0) { - short value = read_memory_int16_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "ushort") == 0) { - unsigned short value = read_memory_uint16_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "int") == 0) { - int value = read_memory_int32_t(address, &error); - lua_pushinteger(L, value); - } else if (strcmp(value_type, "uint") == 0) { - unsigned int value = read_memory_uint32_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "long") == 0) { - long value = read_memory_int64_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "ulong") == 0) { - unsigned long value = read_memory_uint64_t(address, &error); - lua_pushinteger(L, (int)value); - } else if (strcmp(value_type, "float") == 0) { - float value = read_memory_float(address, &error); - lua_pushnumber(L, (double)value); - } else if (strcmp(value_type, "double") == 0) { - double value = read_memory_double(address, &error); - lua_pushnumber(L, value); - } else if (strcmp(value_type, "bool") == 0) { - bool value = read_memory_bool(address, &error); - lua_pushboolean(L, value ? 1 : 0); - } else if (strstr(value_type, "string") != NULL) { - int buffer_size = atoi(value_type + 6); - if (buffer_size < 2) { - printf("Invalid string size, please read documentation"); - exit(1); +int store_memory_tables(lua_State* L, const char* version) +{ + memory_table_count = 0; + + lua_getglobal(L, "State"); + lua_getfield(L, -1, process.name); + + if (version != NULL) { + lua_getfield(L, -1, version); + if (!lua_istable(L, -1)) { + lua_pop(L, 3); // Pop the non-tables + printf("Could not find version table %s for process %s\n", version, process.name); + return 0; } - char* value = read_memory_string(address, buffer_size); - lua_pushstring(L, value != NULL ? value : ""); - free(value); - return 1; - } else { - printf("Invalid value type: %s\n", value_type); - exit(1); } - if (memory_error) { - lua_pushinteger(L, -1); - handle_memory_error(error); + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int has_nested_table = 0; + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + if (lua_istable(L, -1)) { + has_nested_table = 1; + lua_pop(L, 2); // Nested table and its key + break; + } + lua_pop(L, 1); + } + } + + if (!has_nested_table) { + const char* table_name; + if (lua_isstring(L, -2)) { + table_name = lua_tostring(L, -2); + } else { + lua_pop(L, 1); + continue; + } + MemoryTable* table = &memory_tables[memory_table_count++]; + table->name = strdup(table_name); + table->type = NULL; + table->module = NULL; + table->address = 0; + table->offset_count = 0; + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L, -2)) { + int key = lua_tointeger(L, -2); + if (key == 1) { // Type + table->type = strdup(lua_tostring(L, -1)); + } else if (key == 2) { // Module or Address + if (lua_isnumber(L, -1)) { // Address + table->address = lua_tointeger(L, -1); + } else if (lua_isstring(L, -1)) { // Module + table->module = strdup(lua_tostring(L, -1)); + } + } else if (key == 3 && table->module != NULL) { // Address when module exists + if (lua_isnumber(L, -1)) { + table->address = lua_tointeger(L, -1); + } + } else if ((key > 2 && key <= MAX_OFFSETS + 2 && table->module == NULL) || (key > 3 && key <= MAX_OFFSETS + 3 && table->module != NULL)) { // Offsets + if (lua_isnumber(L, -1)) { + table->offsets[table->offset_count++] = lua_tointeger(L, -1); + } + } + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + + if (version != NULL) { + lua_pop(L, 3); // version, process, and state tables + } else { + lua_pop(L, 2); // process and state tables } - return 1; + for (int i = 0; i < memory_table_count; i++) { + MemoryTable* table = &memory_tables[i]; + printf("%s ", table->name); + printf("%s ", table->type); + if (table->module) { + printf("%s ", table->module); + } + printf("0x%lX ", table->address); + if (table->offset_count) { + for (int i = 0; i < table->offset_count; i++) { + printf("0x%X ", table->offsets[i]); + } + } + printf("\n"); + } + return memory_table_count; } diff --git a/src/memory.h b/src/memory.h index 4173ed8..9891755 100644 --- a/src/memory.h +++ b/src/memory.h @@ -2,11 +2,24 @@ #define __MEMORY_H__ #include +#include #include #include -ssize_t process_vm_readv(int pid, struct iovec* mem_local, int liovcnt, struct iovec* mem_remote, int riovcnt, int flags); +#define MAX_OFFSETS 10 +#define MAX_MEMORY_TABLES 100 + +typedef struct { + char* name; + char* type; + char* module; + uint64_t address; + int offsets[MAX_OFFSETS]; + int offset_count; +} MemoryTable; -int read_address(lua_State* L); +ssize_t process_vm_readv(int pid, struct iovec* mem_local, int liovcnt, struct iovec* mem_remote, int riovcnt, int flags); +int store_memory_tables(lua_State* L, const char* version); +void read_address(lua_State* L); #endif /* __MEMORY_H__ */ diff --git a/src/process.c b/src/process.c index fc8d7a7..7fa7de4 100644 --- a/src/process.c +++ b/src/process.c @@ -7,6 +7,7 @@ #include #include +#include #include "auto-splitter.h" #include "process.h" @@ -75,42 +76,54 @@ uintptr_t find_base_address(const char* module) return 0; } -void stock_process_id(const char* pid_command) +int stock_process_id(const char* pid_command, const char* process_name) { char pid_output[PATH_MAX + 100]; pid_output[0] = '\0'; - while (atomic_load(&auto_splitter_enabled)) { - execute_command(pid_command, pid_output); - process.pid = strtoul(pid_output, NULL, 10); - printf("\033[2J\033[1;1H"); // Clear the console - if (process.pid) { - size_t newlinePos = strcspn(pid_output, "\n"); - if (newlinePos != strlen(pid_output) - 1 && pid_output[0] != '\0') { - printf("Multiple PID's found for process: %s\n", process.name); - } - break; - } else { - printf("%s isn't running.\n", process.name); - usleep(100000); // Sleep for 100ms - } + execute_command(pid_command, pid_output); + process.pid = strtoul(pid_output, NULL, 10); + if (process.pid) { + process.name = process_name; + return 1; } - - printf("Process: %s\n", process.name); - printf("PID: %u\n", process.pid); - process.base_address = find_base_address(NULL); - process.dll_address = process.base_address; + return 0; } -int find_process_id(lua_State* L) +int find_process_id(char process_names[100][256], int num_process_names) { - process.name = lua_tostring(L, 1); - char command[256]; - printf("\033[2J\033[1;1H"); // Clear the console - snprintf(command, sizeof(command), "pgrep \"%.*s\"", (int)strnlen(process.name, 15), process.name); + int found = 0; + + while (atomic_load(&auto_splitter_enabled)) { + printf("\r\033[KSearching for processes: "); + for (int i = 0; i < num_process_names; i++) { + printf("%s", process_names[i]); + if (i < num_process_names - 1) { + printf(", "); + } + } + fflush(stdout); - stock_process_id(command); + for (int i = 0; i < num_process_names; i++) { + char command[256]; + snprintf(command, sizeof(command), "pgrep \"%.*s\"", (int)strnlen(process_names[i], 15), process_names[i]); + + if (stock_process_id(command, process_names[i])) { + found = 1; + break; + } + } + if (found) { + printf("\r\033[KProcess: %s\n", process.name); + printf("PID: %u\n", process.pid); + process.base_address = find_base_address(NULL); + process.dll_address = process.base_address; + return 1; + } else { + usleep(100000); // Sleep for 100ms before retrying + } + } return 0; } diff --git a/src/process.h b/src/process.h index 27a5fa7..db232ab 100644 --- a/src/process.h +++ b/src/process.h @@ -6,6 +6,7 @@ #include #include +#include struct game_process { const char* name; @@ -23,7 +24,7 @@ extern uint32_t p_maps_cache_size; uintptr_t find_base_address(const char* module); int process_exists(); -int find_process_id(lua_State* L); +int find_process_id(char process_names[100][256], int num_process_names); int getPid(lua_State* L); bool parseMapsLine(char* line, ProcessMap* map); diff --git a/src/timer.c b/src/timer.c index a3c4888..fcc1016 100644 --- a/src/timer.c +++ b/src/timer.c @@ -1,10 +1,13 @@ #include "timer.h" #include +#include #include #include #include #include +#include "auto-splitter.h" + long long ls_time_now(void) { struct timespec timespec; @@ -597,6 +600,7 @@ int ls_timer_start(ls_timer* timer) if (!timer->started) { ++*timer->attempt_count; timer->started = 1; + atomic_store(&call_on_start, true); } timer->running = 1; } @@ -641,6 +645,7 @@ int ls_timer_split(ls_timer* timer) ls_timer_stop(timer); ls_game_update_splits((ls_game*)timer->game, timer); } + atomic_store(&call_on_split, true); return timer->curr_split; } } @@ -691,9 +696,11 @@ int ls_timer_reset(ls_timer* timer) { if (!timer->running) { if (timer->started && timer->time <= 0) { + atomic_store(&call_on_reset, true); return ls_timer_cancel(timer); } reset_timer(timer); + atomic_store(&call_on_reset, true); return 1; } return 0;