Compare commits

...
6 Commits
Author SHA1 Message Date
dkeruza a5633bbf1d Fixed an indentation in the Flatpak script. 2025-04-06 12:38:17 -04:00
dkeruza d72ac379ea Fixed Flatpak script.
There was a bug in the script preventing it to launch.
2025-04-06 11:34:49 -04:00
dkeruza 988a9ee6e3 Merge pull request #86 from dkeruza-neo/master
libCg.so path, better folder redirection.
2025-04-06 04:31:52 -04:00
dkeruza-neo ea19a688cc Recompiled shaders redirectio, and lib path. 2025-04-06 04:30:09 -04:00
dkeruza c5fa5871d1 Merge pull request #85 from dkeruza-neo/master
changelog and guide.
2025-04-05 18:17:04 -04:00
dkeruza-neo 5be9aef4e0 changelog and guide 2025-04-05 18:16:04 -04:00
10 changed files with 517 additions and 164 deletions
+6 -1
View File
@@ -1,9 +1,14 @@
# 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.
- lindbergh elf mostly redone to make the loader work as a stand alone mode (read guide.md).
## [2.0.8]
### Added
+44
View File
@@ -224,3 +224,47 @@ flatpak install com.github.tchx84.Flatseal
```
Then, run Flatseal and grant Lindbergh Loader access to additional directories.
### Stand alone mode
Now, you have the option to run the games without copying any files to the game's folder.
Your system's 32 bit library folder, your current folder and the game's folder will be added to LD_LIBRARY_PATH env variable,
so you can han the loader libs in any of those locations.
Passing -c option you can specify the location of the .conf file like this:
```
./lindbergh -c /my/custom/folder/myconfig.conf
```
## -g or --gamepath
With this new option, you can specify the location of the game, where the game's ELF resides.
```
./lindbergh -g /my/custom/folder/hod4/elf
```
The loader will search for known elf files in that folder but you can also run it like this:
```
./lindbergh myCustom.elf -g /my/custom/folder/hod4/elf
```
The loader will load `myCustom.elf` inside the passed folder.
## Passing a folder containing an elf
With this option, you pass a full path, including an ELF name like this:
```
./lindbergh /my/custom/folder/hod4/elf/myCustom.elf
```
The loader will load the ELF in that folder.
You can combine all options.
You can have the needed libraries in the folder where `lindbergh` resides, in the system's 32 bit lib folder or in the game's folder.
The loader will try to find the files.
If by mistake, you pass both, a full path including an ELF and a path with -g option, the path passed with -g option will be omitted.
Remember that if the path containg spaces, which is not recommended, pass the path inside double quotes or `\` before the space.
+4
View File
@@ -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
+55 -103
View File
@@ -1,18 +1,17 @@
app-id: com.github.lindberghloader
runtime: org.freedesktop.Platform
runtime-version: &runtime-version '24.08' # Define runtime version alias
runtime-version: &runtime-version '24.08'
sdk: org.freedesktop.Sdk
# Define reusable aliases
x-gl-versions: &gl-versions '24.08;1.4' # Define GL versions list alias
x-gl-versions: &gl-versions '24.08;1.4'
x-gl-merge-dirs: &gl-merge-dirs vulkan/icd.d;glvnd/egl_vendor.d;egl/egl_external_platform.d;OpenCL/vendors;lib/dri;lib/d3d;lib/gbm;vulkan/explicit_layer.d;vulkan/implicit_layer.d # Define GL merge dirs alias
x-i386-build-options: &i386-build-options # Define 32-bit build options alias
libdir: /app/lib32 # Default library install dir for autotools/meson etc.
x-i386-build-options: &i386-build-options
libdir: /app/lib32
env:
CC: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc
CXX: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-g++
LD: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ld
LDFLAGS: "-L/app/lib32" # Add custom lib dir to linker search path during build
LDFLAGS: "-L/app/lib32"
command: lindbergh
@@ -21,41 +20,33 @@ sdk-extensions:
- org.freedesktop.Sdk.Extension.toolchain-i386
- org.freedesktop.Sdk.Compat.i386
# Runtime arguments and permissions
finish-args:
# Environment variables needed at runtime
- --env=LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH # Make custom 32-bit libs findable
- --env=LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH
- --env=LDFLAGS="-L/app/lib32"
- --env=PATH=/app/bin:/usr/bin
# Permissions
- --allow=multiarch # Needed for running 32-bit code
- --allow=multiarch
- --share=ipc
- --share=network
- --socket=x11
- --socket=wayland
- --socket=pulseaudio
# WARNING: --device=all grants broad hardware access. Consider using --device=dri and specific devices if possible.
- --device=all
# Filesystem access - adjust path as needed
- --socket=pulseaudio
- --filesystem=~/Games
# Runtime extensions automatically downloaded and installed with the app
# Runtime extensions automatically downloaded and installed with the app (For some reason does not work)
add-extensions:
# 32-bit compatibility libraries from the runtime
org.freedesktop.Platform.Compat.i386:
directory: lib/i386-linux-gnu
version: *runtime-version # Match the main runtime version
# no-autodownload removed (or set to false) to ensure installation
version: *runtime-version
# 32-bit graphics driver extension
org.freedesktop.Platform.GL32:
directory: lib/i386-linux-gnu/GL
versions: *gl-versions # Use defined GL versions list
versions: *gl-versions
subdirectories: true
# no-autodownload removed (or set to false) to ensure installation
autodelete: false
add-ld-path: lib
merge-dirs: *gl-merge-dirs # Use defined merge dirs list
# Conditions for downloading and enabling the GL driver extension
merge-dirs: *gl-merge-dirs
download-if: active-gl-driver
enable-if: active-gl-driver
autoprune-unless: active-gl-driver
@@ -75,12 +66,11 @@ modules:
- name: libGLU
buildsystem: autotools
config-opts:
- --host=i686-unknown-linux-gnu # Specify 32-bit target host
- --prefix=/app # Base install prefix
# --libdir=/app/lib32 should be handled by build-options->libdir
- --host=i686-unknown-linux-gnu
- --prefix=/app
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options on 64-bit host
x86_64: *i386-build-options
sources:
- type: archive
url: https://mesa.freedesktop.org/archive/glu/glu-9.0.2.tar.xz
@@ -91,15 +81,15 @@ modules:
buildsystem: cmake
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_INSTALL_PREFIX=/app # Base install prefix
- -DCMAKE_INSTALL_LIBDIR=/app/lib32 # Explicitly set library install dir for CMake
- -DCMAKE_INSTALL_PREFIX=/app
- -DCMAKE_INSTALL_LIBDIR=/app/lib32
sources:
- type: archive
url: https://downloads.sourceforge.net/freeglut/freeglut-3.2.2.tar.gz
sha256: c5944a082df0bba96b5756dddb1f75d0cd72ce27b5395c6c1dde85c2ff297a50
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
# Build 32-bit libFAudio (dynamic)
- name: libFAudio-Dynamic
@@ -107,40 +97,37 @@ modules:
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_INSTALL_PREFIX=/app
- -DBUILD_SDL3=off # Assuming SDL3 integration is not needed
- -DCMAKE_INSTALL_LIBDIR=/app/lib32 # Explicitly set library install dir
- -DBUILD_SDL3=off
- -DCMAKE_INSTALL_LIBDIR=/app/lib32
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
env:
# Specific flags needed for FAudio 32-bit build?
CFLAGS: "-m32 -mstackrealign"
CXXFLAGS: "-m32 -mstackrealign"
sources:
- type: git
url: https://github.com/FNA-XNA/FAudio.git
tag: "24.12" # Using a specific tag
tag: "24.12"
# Build 32-bit libXmu
- name: libxmu
buildsystem: autotools
config-opts:
# --libdir=/app/lib32 should be handled by build-options->libdir
- --prefix=/app
- --with-shared # Ensure shared library is built
- --with-shared
sources:
- type: archive
url: https://xorg.freedesktop.org/releases/individual/lib/libXmu-1.2.1.tar.gz
sha256: bf0902583dd1123856c11e0a5085bd3c6e9886fbbd44954464975fd7d52eb599
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options (Standardized)
x86_64: *i386-build-options
# Build 32-bit libmd
- name: libmd
buildsystem: autotools
config-opts:
# --libdir=/app/lib32 should be handled by build-options->libdir
- --prefix=/app
sources:
- type: archive
@@ -148,13 +135,12 @@ modules:
sha256: 1bd6aa42275313af3141c7cf2e5b964e8b1fd488025caf2f971f43b00776b332
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
# Build 32-bit libbsd
- name: libbsd
buildsystem: autotools
config-opts:
# --libdir=/app/lib32 should be handled by build-options->libdir
- --prefix=/app
sources:
- type: archive
@@ -162,14 +148,12 @@ modules:
sha256: b88cc9163d0c652aaf39a99991d974ddba1c3a9711db8f1b5838af2a14731014
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
# Build 32-bit ncurses (very old version)
- name: ncurses
# WARNING: ncurses 5.9 is very old. Consider updating if possible.
buildsystem: autotools
config-opts:
# --libdir=/app/lib32 should be handled by build-options->libdir
- --prefix=/app
- --with-shared
- --without-debug
@@ -178,24 +162,22 @@ modules:
url: https://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz
sha256: 9046298fb440324c9d4135ecea7879ffed8546dd1b58e59430ea07a4633f563b
- type: patch
path: ./assets/ncurses-5.9.patch # Assuming this patch is necessary
path: ./assets/ncurses-5.9.patch
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
env:
CPPFLAGS: "-P" # Often needed for ncurses builds
CXXFLAGS: "-std=c++14" # Is C++14 really needed for ncurses build? Check this.
CPPFLAGS: "-P"
CXXFLAGS: "-std=c++14"
# Install pre-built 32-bit Nvidia Cg Toolkit (old)
- name: nvidia-cg-toolkit
# WARNING: Cg Toolkit is deprecated and old.
buildsystem: simple
build-commands:
- install -Dm755 usr/lib/libCg.so /app/lib32/libCg.so
- install -Dm755 usr/lib/libCgGL.so /app/lib32/libCgGL.so
sources:
- type: archive
# Consider hosting this locally or finding a more reliable source if possible
url: http://developer.download.nvidia.com/cg/Cg_3.1/Cg-3.1_April2012_x86.tgz
sha256: cef3591e436f528852db0e8c145d3842f920e0c89bcfb219c466797cb7b18879
@@ -203,32 +185,27 @@ modules:
- name: libsndio-dynamic
buildsystem: autotools
config-opts:
# --libdir=/app/lib32 should be handled by build-options->libdir
- --prefix=/app
- --enable-dynamic # Build shared library
# - --disable-static # Don't build static library
- --enable-alsa # Enable ALSA backend
- --enable-dynamic
- --enable-alsa
sources:
- type: archive
url: https://www.sndio.org/sndio-1.10.0.tar.gz
sha256: bebd3bfd01c50c9376cf3e7814b9379bed9e17d0393b5113b7eb7a3d0d038c54
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
# Build 32-bit libopenal (old version)
- name: libopenal
# WARNING: OpenAL Soft 1.17.2 is quite old. Consider updating.
buildsystem: cmake
config-opts:
- -DCMAKE_INSTALL_PREFIX=/app
- -DCMAKE_INSTALL_LIBDIR=/app/lib32 # Explicitly set library install dir
# Backend selection
- -DCMAKE_INSTALL_LIBDIR=/app/lib32
- -DALSOFT_BACKEND_PULSEAUDIO=ON
- -DALSOFT_BACKEND_ALSA=ON
- -DALSOFT_BACKEND_JACK=OFF
- -DALSOFT_BACKEND_SNDIO=ON # Depends on libsndio-dynamic
# Point to the previously built sndio library/headers
- -DALSOFT_BACKEND_SNDIO=ON
- -DSOUNDIO_INCLUDE_DIR=/app/include
- -DSOUNDIO_LIBRARY=/app/lib32/libsndio.so
sources:
@@ -237,29 +214,20 @@ modules:
sha256: 11ea176f6cbf9763dbce0953dd77ab72d032b4ad95f07afffb91844abb174033
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
env:
# Specific flags needed for OpenAL 32-bit build?
CFLAGS: "-m32 -mstackrealign"
CXXFLAGS: "-m32 -std=c++14 -mstackrealign" # Needs C++14?
CXXFLAGS: "-m32 -std=c++14 -mstackrealign"
# Build 32-bit OpenSSL (extremely old and insecure version)
- name: openssl
# CRITICAL WARNING: OpenSSL 0.9.7 is extremely old, unsupported, and has known vulnerabilities.
# This should be updated or removed if at all possible. Using it poses a security risk.
buildsystem: simple
build-commands:
# Configure for 32-bit Linux (pentium target), shared libs, install to /app
- ./Configure --prefix=/app --openssldir=/app/etc/ssl shared 386 no-asm no-krb5 linux-pentium
# Build using the 32-bit toolchain
# - make -j$(nproc) CC=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc RANLIB=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ranlib
- make CC=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc RANLIB=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ranlib
# Manually move built libraries to the target lib32 directory
- install -d /app/lib32
- mv libcrypto.so* /app/lib32/
- mv libssl.so* /app/lib32/
# Install headers (needed by other modules?) - will be cleaned later if not
# - make install_hdrs
sources:
- type: archive
url: https://github.com/openssl/openssl/archive/refs/tags/OpenSSL_0_9_7.tar.gz
@@ -269,23 +237,16 @@ modules:
- name: libpcsclite
buildsystem: meson
config-opts:
# --libdir=/app/lib32 should be handled by build-options->libdir
# - -Dprefix=/app
- -Dpolkit=false # Disable polkit integration
- -Dlibsystemd=false # Disable systemd integration
# -Dudevrulesdir=no # Might be needed if it tries to install udev rules
- -Dpolkit=false
- -Dlibsystemd=false
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options
x86_64: *i386-build-options
env:
# Meson cross-compilation setup often requires explicit flags and paths
CFLAGS: "-m32"
CXXFLAGS: "-m32"
LDFLAGS: "-m32 -L/app/lib32" # Ensure LDFLAGS includes -L/app/lib32
# Point pkg-config to custom and SDK 32-bit locations
LDFLAGS: "-m32 -L/app/lib32"
PKG_CONFIG_PATH: "/app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/sdk/toolchain-i386/lib/pkgconfig"
# LD_LIBRARY_PATH might not be needed here if LDFLAGS is sufficient for linking stage
# LD_LIBRARY_PATH: "/app/lib32:/usr/lib/i386-linux-gnu/pkgconfig:$LD_LIBRARY_PATH"
sources:
- type: archive
url: https://pcsclite.apdu.fr/files/pcsc-lite-2.3.1.tar.xz
@@ -295,59 +256,50 @@ modules:
- name: lindbergh-loader
buildsystem: simple
build-commands:
# Ensure make finds the libraries built in previous steps
- export LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH
- make -j$(nproc) # Build the application
# Install application binary and required libraries/symlinks
- make -j$(nproc)
- mkdir -p /app/lib/i386-linux-gnu
- mkdir -p /app/lib/i386-linux-gnu/GL
- install -Dm755 ./build/lindbergh /app/bin/
- install -Dm755 ./build/lindbergh.so /app/lib32/
- install -Dm755 ./build/libsegaapi.so /app/lib32/
- install -Dm755 ./build/libkswapapi.so /app/lib32/
- install -Dm755 ./build/libposixtime.so /app/lib32/
# Install bundled library? Make sure this doesn't conflict with nvidia-cg-toolkit
- install -Dm755 ./libs/libCg.so /app/lib32/libCg2.so
# Create necessary symlinks in the lib32 directory
- ln -sf libposixtime.so /app/lib32/libposixtime.so.1
- ln -sf libposixtime.so /app/lib32/libposixtime.so.2.4
- ln -sf libopenal.so.1 /app/lib32/libopenal.so.0 # Link to correct openal versioned so
- ln -sf libopenal.so.1 /app/lib32/libopenal.so.0
- ln -sf libkswapapi.so /app/lib32/libGLcore.so.1
- ln -sf libkswapapi.so /app/lib32/libnvidia-tls.so.1
- mv /app/lib/libopenal* /app/lib32/
build-options:
arch:
x86_64: *i386-build-options # Apply 32-bit build options (for env vars mainly)
x86_64: *i386-build-options
sources:
- type: dir
path: ../.. # Assumes source code is one level up from manifest directory
path: ../..
# Setup dynamic linker configuration
- name: bundle-setup
buildsystem: simple
build-commands:
# Install ld.so.conf to ensure /app/lib32 is searched by the dynamic linker
- install -Dm644 -t /app/etc ld.so.conf
sources:
- type: file
path: ./assets/ld.so.conf # Assumes this file contains "/app/lib32"
path: ./assets/ld.so.conf
# Cleanup unnecessary files to reduce final flatpak size
- name: cleanup
buildsystem: simple
build-commands:
# Remove static libraries and libtool archives
- find /app/lib32 -name '*.a' -type f -delete
- find /app/lib32 -name '*.la' -type f -delete
# Remove any executables other than the main command
#- find /app/bin -mindepth 1 ! -name "lindbergh" -exec rm -f {} \;
# Remove development/debugging/documentation files
#- rm -rf /app/lib/pkgconfig /app/lib32/pkgconfig /app/share/pkgconfig
#- rm -rf /app/lib32/cmake /app/lib/debug /app/include /app/man /app/share /app/etc/bash_completion.d
# Remove specific libraries if they are not needed at runtime
# (These were in the original, assuming they are safe to remove)
- find /app/bin -mindepth 1 ! -name "lindbergh" -exec rm -f {} \;
- rm -rf /app/lib/pkgconfig /app/lib32/pkgconfig /app/share/pkgconfig
- rm -rf /app/lib32/cmake /app/lib/debug /app/include /app/man /app/share /app/etc/bash_completion.d
- rm -f /app/lib32/libmenu.so*
- rm -f /app/lib32/libform.so*
- rm -f /app/lib32/libpanel.so*
- rm -f /app/lib32/libXmuu.so*
#- rm -f /app/lib32/libbsd.so*
# Remove ncurses terminfo db if not needed
- rm -rf /app/lib/terminfo
- rm -f /app/lib32/libbsd.so*
- rm -rf /app/lib/terminfo
+4
View File
@@ -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");
+1
View File
@@ -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];
+284 -10
View File
@@ -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 *) =
+31 -15
View File
@@ -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);
}
+4 -11
View File
@@ -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);
}
+84 -24
View File
@@ -1,6 +1,7 @@
#ifndef __i386__
#define __i386__
#include "log.h"
#include <stdint.h>
#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;