From ea19a688cc7dd70fbe745f7f4ebe954912162ae5 Mon Sep 17 00:00:00 2001 From: dkeruza-neo Date: Sun, 6 Apr 2025 04:30:09 -0400 Subject: [PATCH] Recompiled shaders redirectio, and lib path. --- docs/changelog | 5 + docs/lindbergh.conf | 4 + src/lindbergh/config.c | 4 + src/lindbergh/config.h | 1 + src/lindbergh/hook.c | 294 +++++++++++++++++++++++++++++++-- src/lindbergh/lindbergh.c | 46 ++++-- src/lindbergh/patch.c | 15 +- src/lindbergh/shader_patches.c | 108 +++++++++--- 8 files changed, 417 insertions(+), 60 deletions(-) diff --git a/docs/changelog b/docs/changelog index dfc73ae..6600e6c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. +## [2.0.10] +### Added + - Config option to specify a path for the library libCg.so required for some shader compilation. + - Improved folder patching for recompiled shaders (2Spicy, Rambo, Harly and HOD-EX). + - Cleaned a bit of lindbergh elf. ## [2.0.9] - lindbergh elf mostly redone to make the loader work as a stand alone mode (read guide.md). diff --git a/docs/lindbergh.conf b/docs/lindbergh.conf index d9e124b..5e04619 100644 --- a/docs/lindbergh.conf +++ b/docs/lindbergh.conf @@ -72,6 +72,10 @@ EMULATE_CARDREADER AUTO # Define the path to the eeprom.bin file # EEPROM_PATH eeprom.bin +# If set, the library libCG.so needed for 2Spicy, Harley, Rambo and HOD-Ex shader recompilation +# will be loaded from the specifyied location. (include the name of file in the location) +# LIBCG_PATH /my/file/location/myLibCg.so + # Set the GPU vendor (0 = Autodetect / 1 = NVidia / 2 = AMD / 3 = ATI(AMD-PRO) / 4 = Intel / 5 = Unknown) # GPU_VENDOR 0 diff --git a/src/lindbergh/config.c b/src/lindbergh/config.c index 1ae5b8c..f2dd92b 100644 --- a/src/lindbergh/config.c +++ b/src/lindbergh/config.c @@ -1113,6 +1113,9 @@ int readConfig(FILE *configFile, EmulatorConfig *config) else if (strcmp(command, "SRAM_PATH") == 0) strcpy(config->sramPath, getNextToken(NULL, " ", &saveptr)); + else if (strcmp(command, "LIBCG_PATH") == 0) + strcpy(config->libCgPath, getNextToken(NULL, " ", &saveptr)); + else if (strcmp(command, "EMULATE_RIDEBOARD") == 0) { int defaultValue = config->emulateRideboard; config->emulateRideboard = getNextIntOrAuto(saveptr, defaultValue); @@ -1529,6 +1532,7 @@ int initConfig(const char* configFilePath) config.lindberghColour = YELLOW; strcpy(config.eepromPath, "eeprom.bin"); strcpy(config.sramPath, "sram.bin"); + strcpy(config.libCgPath, ""); strcpy(config.jvsPath, "/dev/ttyUSB0"); strcpy(config.serial1Path, "/dev/ttyS0"); strcpy(config.serial2Path, "/dev/ttyS1"); diff --git a/src/lindbergh/config.h b/src/lindbergh/config.h index c0a3b48..9ce7933 100644 --- a/src/lindbergh/config.h +++ b/src/lindbergh/config.h @@ -232,6 +232,7 @@ typedef struct int fullscreen; char eepromPath[MAX_PATH_LENGTH]; char sramPath[MAX_PATH_LENGTH]; + char libCgPath[MAX_PATH_LENGTH]; char jvsPath[MAX_PATH_LENGTH]; char serial1Path[MAX_PATH_LENGTH]; char serial2Path[MAX_PATH_LENGTH]; diff --git a/src/lindbergh/hook.c b/src/lindbergh/hook.c index 590df02..3a69cb7 100644 --- a/src/lindbergh/hook.c +++ b/src/lindbergh/hook.c @@ -95,6 +95,12 @@ static int callback(struct dl_phdr_info *info, size_t size, void *data); uint16_t basePortAddress = 0xFFFF; +/** + * @brief Signal handler for SIGSEGV. + * + * This function handles segmentation faults (SIGSEGV) and attempts to recover + * from certain types of memory access errors, particularly those related to I/O ports. + */ /** * Signal handler for the SIGSEGV signal, which is triggered when a process tries to access an illegal memory location. * @param signal @@ -177,6 +183,13 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr) } } +/** + * @brief Trims leading and trailing whitespace and quotes from a string. + * + * This function removes leading and trailing whitespace characters, as well as + * single and double quotes, from the input string. + * @param str The string to trim. + */ char *trimOS_ID(char *str) { if (!str) @@ -198,6 +211,12 @@ char *trimOS_ID(char *str) return str; } +/** + * @brief Checks if the operating system is Debian-based. + * + * This function reads the /etc/os-release file to determine if the current + * operating system is Debian or Ubuntu, or a derivative of them. + */ bool checkOS_ID() { FILE *fp = fopen("/etc/os-release", "r"); @@ -249,6 +268,12 @@ bool checkOS_ID() return found; } +/** + * @brief Initialization function for the hook library. + * + * This function is called automatically when the library is loaded. It sets up + * signal handlers, initializes configuration, and performs other setup tasks. + */ void __attribute__((constructor)) hook_init() { // Get offsets of the Game's ELF and calculate CRC32. @@ -277,7 +302,6 @@ void __attribute__((constructor)) hook_init() } getGPUVendor(); - if (initPatch() != 0) exit(1); @@ -360,6 +384,13 @@ void __attribute__((constructor)) hook_init() } } +/** + * @brief Hook for the opendir function. + * + * This function intercepts calls to opendir and redirects them to different + * directories based on the game ID. + * @param dirname The name of the directory to open. + */ DIR *opendir(const char *dirname) { DIR *(*_opendir)(const char *dirname) = dlsym(RTLD_NEXT, "opendir"); @@ -395,6 +426,13 @@ DIR *opendir(const char *dirname) return _opendir(dirname); } +/** + * @brief Hook for the remove function. + * + * This function intercepts calls to remove and redirects them to different + * paths based on the game ID. + * @param path The path to remove. + */ int remove(const char *path) { int (*_remove)(const char *path) = dlsym(RTLD_NEXT, "remove"); @@ -416,6 +454,13 @@ int remove(const char *path) return _remove(path); } +/** + * @brief Hook for the mkdir function. + * + * This function intercepts calls to mkdir and redirects them to different + * paths based on the game ID. + * @param path The path to create. + */ int mkdir(const char *path, mode_t mode) { int (*_mkdir)(const char *path, mode_t mode) = dlsym(RTLD_NEXT, "mkdir"); @@ -437,6 +482,13 @@ int mkdir(const char *path, mode_t mode) return _mkdir(path, mode); } +/** + * @brief Hook for the __xstat64 function. + * + * This function intercepts calls to __xstat64 and redirects them to different + * paths based on the game ID. + * @param path The path to stat. + */ int __xstat64(int ver, const char *path, struct stat64 *stat_buf) { int (*___xstat64)(int ver, const char *path, struct stat64 *stat_buf) = dlsym(RTLD_NEXT, "__xstat64"); @@ -448,6 +500,13 @@ int __xstat64(int ver, const char *path, struct stat64 *stat_buf) return ___xstat64(ver, path, stat_buf); } +/** + * @brief Hook for the open function. + * + * This function intercepts calls to open and redirects them to different + * files or devices based on the pathname. + * @param pathname The path to open. + */ int open(const char *pathname, int flags, ...) { va_list args; @@ -534,6 +593,13 @@ int open(const char *pathname, int flags, ...) return _open(pathname, flags, mode); } +/** + * @brief Hook for the open64 function. + * + * This function intercepts calls to open64 and redirects them to different + * files or devices based on the pathname. + * @param pathname The path to open. + */ int open64(const char *pathname, int flags, ...) { va_list args; @@ -544,6 +610,13 @@ int open64(const char *pathname, int flags, ...) return open(pathname, flags, mode); } +/** + * @brief Hook for the fopen function. + * + * This function intercepts calls to fopen and redirects them to different + * files based on the pathname. + * @param pathname The path to open. + */ FILE *fopen(const char *restrict pathname, const char *restrict mode) { FILE *(*_fopen)(const char *restrict pathname, const char *restrict mode) = dlsym(RTLD_NEXT, "fopen"); @@ -690,7 +763,6 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) { return 0; } - if (cachedShaderFilesLoaded) { void *addr = __builtin_return_address(0); @@ -757,6 +829,13 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) return _fopen(pathname, mode); } +/** + * @brief Hook for the fopen64 function. + * + * This function intercepts calls to fopen64 and redirects them to different + * files based on the pathname. + * @param pathname The path to open. + */ FILE *fopen64(const char *pathname, const char *mode) { FILE *(*_fopen64)(const char *restrict pathname, const char *restrict mode) = dlsym(RTLD_NEXT, "fopen64"); @@ -857,6 +936,13 @@ FILE *fopen64(const char *pathname, const char *mode) return _fopen64(pathname, mode); } +/** + * @brief Hook for the fclose function. + * + * This function intercepts calls to fclose and performs cleanup operations + * for the file hooks. + * @param stream The file stream to close. + */ int fclose(FILE *stream) { int (*_fclose)(FILE *stream) = dlsym(RTLD_NEXT, "fclose"); @@ -878,6 +964,14 @@ int fclose(FILE *stream) } return _fclose(stream); } + +/** + * @brief Hook for the openat function. + * + * This function intercepts calls to openat and redirects them to different + * files or devices based on the pathname. + * @param pathname The path to open. + */ int openat(int dirfd, const char *pathname, int flags, ...) { int (*_openat)(int dirfd, const char *pathname, int flags) = dlsym(RTLD_NEXT, "openat"); @@ -892,6 +986,13 @@ int openat(int dirfd, const char *pathname, int flags, ...) return _openat(dirfd, pathname, flags); } +/** + * @brief Hook for the close function. + * + * This function intercepts calls to close and performs cleanup operations + * for the file hooks. + * @param fd The file descriptor to close. + */ int close(int fd) { int (*_close)(int fd) = dlsym(RTLD_NEXT, "close"); @@ -908,6 +1009,13 @@ int close(int fd) return _close(fd); } +/** + * @brief Hook for the fgets function. + * + * This function intercepts calls to fgets and redirects them to different + * files based on the stream. + * @param stream The file stream to read from. + */ char *fgets(char *str, int n, FILE *stream) { char *(*_fgets)(char *str, int n, FILE *stream) = dlsym(RTLD_NEXT, "fgets"); @@ -945,6 +1053,13 @@ char *fgets(char *str, int n, FILE *stream) return _fgets(str, n, stream); } +/** + * @brief Hook for the read function. + * + * This function intercepts calls to read and redirects them to different + * files or devices based on the file descriptor. + * @param fd The file descriptor to read from. + */ ssize_t read(int fd, void *buf, size_t count) { int (*_read)(int fd, void *buf, size_t count) = dlsym(RTLD_NEXT, "read"); @@ -994,6 +1109,13 @@ ssize_t read(int fd, void *buf, size_t count) return _read(fd, buf, count); } +/** + * @brief Hook for the fread function. + * + * This function intercepts calls to fread and redirects them to different + * files based on the stream. + * @param stream The file stream to read from. + */ size_t fread(void *buf, size_t size, size_t count, FILE *stream) { size_t (*_fread)(void *buf, size_t size, size_t count, FILE *stream) = dlsym(RTLD_NEXT, "fread"); @@ -1046,6 +1168,13 @@ size_t fread(void *buf, size_t size, size_t count, FILE *stream) return _fread(buf, size, count, stream); } +/** + * @brief Hook for the ftell function. + * + * This function intercepts calls to ftell and redirects them to different + * files based on the stream. + * @param stream The file stream to get the position from. + */ long int ftell(FILE *stream) { long int (*_ftell)(FILE *stream) = dlsym(RTLD_NEXT, "ftell"); @@ -1067,6 +1196,13 @@ long int ftell(FILE *stream) return _ftell(stream); } +/** + * @brief Hook for the fseek function. + * + * This function intercepts calls to fseek and redirects them to different + * files based on the stream. + * @param stream The file stream to seek in. + */ int fseek(FILE *stream, long int offset, int whence) { int (*_fseek)(FILE *stream, long int offset, int whence) = dlsym(RTLD_NEXT, "fseek"); @@ -1090,6 +1226,13 @@ int fseek(FILE *stream, long int offset, int whence) return _fseek(stream, offset, whence); } +/** + * @brief Hook for the rewind function. + * + * This function intercepts calls to rewind and redirects them to different + * files based on the stream. + * @param stream The file stream to rewind. + */ void rewind(FILE *stream) { void (*_rewind)(FILE *stream) = dlsym(RTLD_NEXT, "rewind"); @@ -1103,6 +1246,13 @@ void rewind(FILE *stream) _rewind(stream); } +/** + * @brief Hook for the write function. + * + * This function intercepts calls to write and redirects them to different + * files or devices based on the file descriptor. + * @param fd The file descriptor to write to. + */ ssize_t write(int fd, const void *buf, size_t count) { int (*_write)(int fd, const void *buf, size_t count) = dlsym(RTLD_NEXT, "write"); @@ -1141,6 +1291,13 @@ ssize_t write(int fd, const void *buf, size_t count) return _write(fd, buf, count); } +/** + * @brief Hook for the ioctl function. + * + * This function intercepts calls to ioctl and redirects them to different + * devices based on the file descriptor. + * @param fd The file descriptor to perform the ioctl on. + */ int ioctl(int fd, unsigned int request, void *data) { int (*_ioctl)(int fd, int request, void *data) = dlsym(RTLD_NEXT, "ioctl"); @@ -1170,6 +1327,13 @@ int ioctl(int fd, unsigned int request, void *data) return _ioctl(fd, request, data); } +/** + * @brief Hook for the tcgetattr function. + * + * This function intercepts calls to tcgetattr and redirects them to different + * devices based on the file descriptor. + * @param fd The file descriptor to get the attributes from. + */ int tcgetattr(int fd, struct termios *termios_p) { int (*_tcgetattr)(int fd, struct termios *termios_p) = dlsym(RTLD_NEXT, "tcgetattr"); @@ -1180,6 +1344,13 @@ int tcgetattr(int fd, struct termios *termios_p) return _tcgetattr(fd, termios_p); } +/** + * @brief Hook for the tcsetattr function. + * + * This function intercepts calls to tcsetattr and redirects them to different + * devices based on the file descriptor. + * @param fd The file descriptor to set the attributes on. + */ int tcsetattr(int fd, int optional_actions, const struct termios *termios_p) { int (*_tcsetattr)(int fd, int optional_actions, const struct termios *termios_p) = dlsym(RTLD_NEXT, "tcsetattr"); @@ -1190,6 +1361,13 @@ int tcsetattr(int fd, int optional_actions, const struct termios *termios_p) return _tcsetattr(fd, optional_actions, termios_p); } +/** + * @brief Hook for the cfgetispeed function. + * + * This function intercepts calls to cfgetispeed and redirects them to different + * devices based on the file descriptor. + * @param termios_p The termios structure to get the input speed from. + */ speed_t cfgetispeed(const struct termios *termios_p) { speed_t (*_cfgetispeed)(const struct termios *termios_p) = dlsym(RTLD_NEXT, "cfgetispeed"); @@ -1200,6 +1378,13 @@ speed_t cfgetispeed(const struct termios *termios_p) return _cfgetispeed(termios_p); } +/** + * @brief Hook for the cfgetospeed function. + * + * This function intercepts calls to cfgetospeed and redirects them to different + * devices based on the file descriptor. + * @param termios_p The termios structure to get the output speed from. + */ speed_t cfgetospeed(const struct termios *termios_p) { speed_t (*_cfgetospeed)(const struct termios *termios_p) = dlsym(RTLD_NEXT, "cfgetospeed"); @@ -1210,6 +1395,13 @@ speed_t cfgetospeed(const struct termios *termios_p) return _cfgetospeed(termios_p); } +/** + * @brief Hook for the cfsetispeed function. + * + * This function intercepts calls to cfsetispeed and redirects them to different + * devices based on the file descriptor. + * @param termios_p The termios structure to set the input speed on. + */ int cfsetispeed(struct termios *termios_p, speed_t speed) { int (*_cfsetispeed)(struct termios *termios_p, speed_t speed) = dlsym(RTLD_NEXT, "cfsetispeed"); @@ -1220,6 +1412,13 @@ int cfsetispeed(struct termios *termios_p, speed_t speed) return _cfsetispeed(termios_p, speed); } +/** + * @brief Hook for the cfsetospeed function. + * + * This function intercepts calls to cfsetospeed and redirects them to different + * devices based on the file descriptor. + * @param termios_p The termios structure to set the output speed on. + */ int cfsetospeed(struct termios *termios_p, speed_t speed) { int (*_cfsetospeed)(struct termios *termios_p, speed_t speed) = dlsym(RTLD_NEXT, "cfsetospeed"); @@ -1230,6 +1429,14 @@ int cfsetospeed(struct termios *termios_p, speed_t speed) return _cfsetospeed(termios_p, speed); } +/** + * @brief Hook for the select function. + * + * This function intercepts calls to select and redirects them to different + * devices based on the file descriptor. + * @param nfds The highest file descriptor number plus one. + * @param readfds The file descriptors to check for readability. + */ int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict timeout) { @@ -1254,6 +1461,13 @@ int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set return _select(nfds, readfds, writefds, exceptfds, timeout); } +/** + * @brief Hook for the system function. + * + * This function intercepts calls to system and redirects them to different + * commands based on the command string. + * @param command The command to execute. + */ int system(const char *command) { int (*_system)(const char *command) = dlsym(RTLD_NEXT, "system"); @@ -1291,6 +1505,36 @@ int system(const char *command) return _system(command); } +/** + * @brief Hook for the strncpy function. + * + * This function intercepts calls to strncpy and redirects them to different + * strings based on the game ID. + * @param dest The destination string. + */ +char *strncpy(char *dest, const char *src, size_t n) +{ + char *(*_strncpy)(char *dest, const char *src, size_t n) = dlsym(RTLD_NEXT, "strncpy"); + + switch (gId) + { + case HARLEY_DAVIDSON: + case RAMBO: + case THE_HOUSE_OF_THE_DEAD_EX: + case TOO_SPICY: + if (getConfig()->GPUVendor != NVIDIA_GPU && (strstr(src, "../fs/compiledshader") != NULL || strstr(src, "../fs/compiled") != NULL)) + return _strncpy(dest, "../fs/compiledmesa", n); + } + return _strncpy(dest, src, n); +} + +/** + * @brief Hook for the iopl function. + * + * This function intercepts calls to iopl and always returns 0. + * @param level The I/O privilege level to set. + * @return Always returns 0. + */ int iopl(int level) { return 0; @@ -1306,10 +1550,11 @@ void kswap_collect(void *p) } /** - * Hook for function used by Primevil - * @param base The number to raise to the exponent - * @param exp The exponent to raise the number to - * @return The result of raising the number to the exponent + * @brief Hook for the powf function. + * + * This function intercepts calls to powf and redirects them to pow. + * @param base The base number. + * @param exponent The exponent. */ float powf(float base, float exponent) { @@ -1324,6 +1569,13 @@ int sem_wait(sem_t *sem) } */ +/** + * @brief Gets the machine's IP address. + * + * This function retrieves the machine's IP address and stores it in the + * provided sockaddr_in structure. + * @param addr The sockaddr_in structure to store the IP address in. + */ int get_machine_ip(struct sockaddr_in *addr) { struct ifaddrs *ifaddr, *ifa; @@ -1396,7 +1648,11 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) } /** - * Callback function to get the offset and size of the execution program in memory of the ELF we hook to. + * @brief Callback function for dl_iterate_phdr. + * + * This function is called for each program header in the loaded shared + * objects. It is used to calculate the CRC32 of the ELF file. + * @param info Information about the program header. */ static int callback(struct dl_phdr_info *info, size_t size, void *data) { @@ -1408,7 +1664,11 @@ static int callback(struct dl_phdr_info *info, size_t size, void *data) } /** - * Stop the game changing the DISPLAY environment variable + * @brief Hook for the setenv function. + * + * This function intercepts calls to setenv and prevents the game from + * changing the DISPLAY environment variable. + * @param name The name of the environment variable. */ int setenv(const char *name, const char *value, int overwrite) { @@ -1423,7 +1683,10 @@ int setenv(const char *name, const char *value, int overwrite) } /** - * Fake the TEA_DIR environment variable to games that require it to run + * @brief Hook for the getenv function. + * + * This function iFake the TEA_DIR environment variable to games that require it to run + * @param name The name of the environment variable. */ char *getenv(const char *name) { @@ -1470,7 +1733,11 @@ char *getenv(const char *name) } /** - * Stop the game unsetting the DISPLAY environment variable + * @brief Hook for the unsetenv function. + * + * This function intercepts calls to unsetenv and prevents the game from + * unsetting the DISPLAY environment variable. + * @param name The name of the environment variable. */ int unsetenv(const char *name) { @@ -1497,6 +1764,13 @@ char *__strdup(const char *string) return ___strdup(string); } +/** + * @brief Hook for the localtime_r function. + * + * This function intercepts calls to localtime_r and redirects them to different + * times based on the game ID. + * @param timep The time to convert. + */ struct tm *localtime_r(const time_t *timep, struct tm *result) { struct tm *(*_localtime_r)(const time_t *, struct tm *) = diff --git a/src/lindbergh/lindbergh.c b/src/lindbergh/lindbergh.c index 65673e8..2a055aa 100644 --- a/src/lindbergh/lindbergh.c +++ b/src/lindbergh/lindbergh.c @@ -19,6 +19,7 @@ #define PRELOAD_FILE_NAME "lindbergh.so" #define TEAM "bobbydilley, retrofan, dkeruza-neo, doozer, francesco, rolel, caviar-x" #define LINDBERGH_CONFIG_PATH "LINDBERGH_CONFIG_PATH" +#define LINDBERGH_LOADER_CURRENT_DIR "LINDBERGH_LOADER_CURRENT_DIR" #define MAX_PATH_LEN 1024 /** @@ -230,6 +231,19 @@ int calculateFileCRC32(const char *filename, uint32_t *crc) return 0; } +bool hasSpaces(const char *str) +{ + if (!str) + return false; + while (*str) + { + if (*str == ' ') + return true; + str++; + } + return false; +} + /** * @brief Checks if the ELF file is clean based on its CRC32. * @@ -237,7 +251,7 @@ int calculateFileCRC32(const char *filename, uint32_t *crc) * against a list of known clean ELF CRC32 values. * @param command The command line string containing the path to the ELF file. */ -void isCleanElf(char *command) +void checkIfElfisClean(char *command) { char *last_space = strrchr(command, ' '); size_t length; @@ -511,6 +525,7 @@ void setEnvironmentVariables(char *ldLibPath, char *curDir, char *gameDir, int z setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", 1); setenv("__NV_PRIME_RENDER_OFFLOAD", "1", 1); } + setenv("LINDBERGH_LOADER_CURRENT_DIR", curDir, 1); } /** @@ -690,6 +705,12 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + if (hasSpaces(curDir)) + { + log_warn("The current path contains spaces, this most likely will cause issues."); + log_warn("Please, make sure you don't use spaces in the path."); + } + char command[PATH_MAX] = {0}; char *forcedGameDir; char *forcedGameElf; @@ -796,26 +817,16 @@ int main(int argc, char *argv[]) char *ldPreloadLibrary = findLDPreloadLibrary(); - if (strcmp(ldPreloadLibrary, PRELOAD_FILE_NAME) == 0) - { - char lindberghSoPath[MAX_PATH_LEN]; - if (gameDir[0] != '\0') - snprintf(lindberghSoPath, strlen(gameDir) + sizeof(PRELOAD_FILE_NAME) + 1, "%s/%s", gameDir, PRELOAD_FILE_NAME); - - if (access(lindberghSoPath, F_OK) != 0) - { - log_error("The preload object lindbergh.so was not found."); - return EXIT_FAILURE; - } - ldPreloadLibrary = strdup(lindberghSoPath); - } + if (strcmp(curDir, gameDir) == 0) + ldPreloadLibrary = PRELOAD_FILE_NAME; // Ensure environment variables are set correctly setEnvironmentVariables(ldPreloadLibrary, curDir, gameDir, zink, nvidia); if (testMode) testModePath(command); - isCleanElf(command); + + checkIfElfisClean(command); if (gdb) { @@ -827,6 +838,11 @@ int main(int argc, char *argv[]) if (extConfigPath != NULL && extConfigPath[0] != '\0') { + if (hasSpaces(extConfigPath)) + { + log_warn("The config path contains spaces, this most likely will cause issues."); + log_warn("Please, make sure you don't use spaces in the path."); + } setenv(LINDBERGH_CONFIG_PATH, extConfigPath, 1); } diff --git a/src/lindbergh/patch.c b/src/lindbergh/patch.c index ccbb639..67a01be 100644 --- a/src/lindbergh/patch.c +++ b/src/lindbergh/patch.c @@ -628,11 +628,9 @@ int initPatch() if (GPUVendor != NVIDIA_GPU) { - cacheModedShaderFiles(); loadLibCg(); + cacheModedShaderFiles(); cacheNnstdshader(); - patchMemory(0x082d4437, "9090909090"); // Stop the folder rename - patchMemory(0x088a6127, "66732f636f6d70696c65646d657361"); // Change folder to compiledshdmesa patchMemory(0x082646b3, "01"); // Compile using CGC replaceCallAtAddress(0x082d48ac, compileWithCGC); replaceCallAtAddress(0x082d4b3b, compileWithCGC); @@ -2059,12 +2057,9 @@ int initPatch() { loadLibCg(); cacheNnstdshader(); - patchMemory(0x08200c17, "9090909090"); // Stop the folder rename - patchMemory(0x084173e7, "66732f636f6d70696c65646d657361"); // Change folder to compiledshdmesa patchMemory(0x080b3d71, "01"); // Compile using CGC replaceCallAtAddress(0x082015bf, compileWithCGC); replaceCallAtAddress(0x082012c1, compileWithCGC); - // patchMemory(0x080b3d65, "00"); // Force recompile shaders } } break; @@ -2487,9 +2482,8 @@ int initPatch() // Mesa Patches if (GPUVendor != NVIDIA_GPU) { - patchMemory(0x08503bfa, "6d657361"); // Rename compile folder to compmesa - cacheModedShaderFiles(); loadLibCg(); + cacheModedShaderFiles(); cacheNnstdshader(); replaceCallAtAddress(0x08370aa7, compileWithCGC); replaceCallAtAddress(0x08370bb6, compileWithCGC); @@ -2550,10 +2544,9 @@ int initPatch() if (GPUVendor != NVIDIA_GPU) { loadLibCg(); - cacheNnstdshader(); - patchMemory(0x081ef9d8, "01"); // Force the game to recompile the shaders using cgc - patchMemory(0x08413f04, "646d657361"); // Changes compiledshader folder to compiledshdmesa cacheModedShaderFiles(); + cacheNnstdshader(); + patchMemory(0x081ef9d8, "01"); // Force the game to recompile the shaders using cgc replaceCallAtAddress(0x08259fe5, compileWithCGC); replaceCallAtAddress(0x0825a089, compileWithCGC); } diff --git a/src/lindbergh/shader_patches.c b/src/lindbergh/shader_patches.c index a901dca..49ea0d5 100644 --- a/src/lindbergh/shader_patches.c +++ b/src/lindbergh/shader_patches.c @@ -1,6 +1,7 @@ #ifndef __i386__ #define __i386__ +#include "log.h" #include #endif #undef __x86_64__ @@ -22,6 +23,7 @@ #include "../libxdiff/xdiff/xdiff.h" #include "config.h" #include "patch.h" +#include "log.h" #include "shader_work/2spicy.h" #include "shader_work/abc.h" @@ -1541,41 +1543,99 @@ int parseCgcArgs(const char *input, const char ***compilerArgs, const char **out return 0; } -void loadLibCg() +char *findLibCg() { - int isFlatpak = 0; - void *handle = dlopen("./libCg.so", RTLD_NOW); - if (!handle) + const char *foundPath = NULL; + FILE *libCgF = NULL; + + char *pathsToCheck[] = {NULL, "/app/lib32/libCg2.so", "./libCg.so", NULL}; + + if (strcmp(getConfig()->libCgPath, "") != 0) { - handle = dlopen("/app/lib32/libCg2.so", RTLD_NOW); - if (!handle) + pathsToCheck[0] = getConfig()->libCgPath; + } + + const char *currentDir = getenv("LINDBERGH_LOADER_CURRENT_DIR"); + if (currentDir != NULL) + { + size_t pathLen = strlen(currentDir) + strlen("/libCg.so") + 1; + pathsToCheck[3] = malloc(pathLen); + if (pathsToCheck[3] != NULL) { - fprintf(stderr, "Error: Unable to load library libCg.so %s\n", dlerror()); - fprintf(stderr, "Error: libCg.so version 2.0 is needed to compile the shaders in the game's folder.\n"); - exit(1); - } - else - { - isFlatpak = 1; + snprintf(pathsToCheck[3], pathLen, "%s/%s", currentDir, "libCg.so"); } } - char libCgVersion[9]; - FILE *libF; - if (isFlatpak) - libF = fopen("/app/lib32/libCg2.so", "r"); - else - libF = fopen("./libCg.so", "r"); + for (int i = 0; i < 4; ++i) + { + if (pathsToCheck[i] == NULL) + continue; - fseek(libF, 0x226d84, SEEK_SET); - fread(libCgVersion, 9, 1, libF); - fclose(libF); + if (access(pathsToCheck[i], F_OK) == 0) + { + foundPath = pathsToCheck[i]; + break; + } + } + + if (foundPath != pathsToCheck[3] && pathsToCheck[3] != NULL) + { + free(pathsToCheck[3]); + } + + if (foundPath == NULL) + { + log_error("Error: Unable to find library libCg.so\n"); + log_error("Error: libCg.so version 2.0 is needed to compile the shaders in the game's folder.\n"); + exit(EXIT_FAILURE); + } + + char libCgVersion[9] = {0}; + libCgF = fopen(foundPath, "rb"); + if (libCgF == NULL) + { + log_error("Failed to open: %s\n", foundPath); + exit(EXIT_FAILURE); + } + + fseek(libCgF, 0x226d84L, SEEK_SET); + if (fread(libCgVersion, 1, sizeof(libCgVersion) - 1, libCgF) != sizeof(libCgVersion) - 1) + { + log_error("Failed to read version from: %s\n", foundPath); + fclose(libCgF); + exit(EXIT_FAILURE); + } + fclose(libCgF); if (strcmp(libCgVersion, "2.0.0.12") != 0) { - printf("ERROR: Wrong libCg.so, version 2.0.0.12 is needed.\n"); - exit(1); + log_error("ERROR: Wrong libCg.so version '%s', version 2.0.0.12 is needed.\n", libCgVersion); + exit(EXIT_FAILURE); } + + char *resultPath = strdup(foundPath); + if (resultPath == NULL) + { + log_error("Error allocating memory for result path"); + exit(EXIT_FAILURE); + } + + return resultPath; +} + +void loadLibCg() +{ + void *handle; + char *libCgFilePath = findLibCg(); + + handle = dlopen(libCgFilePath, RTLD_NOW); + if (!handle) + { + log_error("Error: Unable to find library libCg.so\n"); + log_error("Error: libCg.so version 2.0 is needed to compile the shaders in the game's folder.\n"); + exit(EXIT_FAILURE); + } + free(libCgFilePath); dlerror(); char *error;