Compare commits
16 Commits
35cafec1ee
...
8532e7707f
Author | SHA1 | Date | |
---|---|---|---|
8532e7707f | |||
703ced337b | |||
bedd5ea53a | |||
eb3c5d2e6f | |||
ab1dbd2996 | |||
29bc6faf3d | |||
5aae95fd37 | |||
5739c5f999 | |||
34ef2d51aa | |||
f328800ce8 | |||
02c73176a5 | |||
16ce586e9c | |||
6378a18494 | |||
6994671c6d | |||
58f329bb4f | |||
d03a1a96ff |
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -11,6 +11,6 @@
|
||||
[submodule "dependencies/zenity/src"]
|
||||
path = dependencies/zenity/src
|
||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git
|
||||
[submodule "launcher/dependencies/patchelf/src"]
|
||||
path = launcher/dependencies/patchelf/src
|
||||
url = https://github.com/NixOS/patchelf.git
|
||||
[submodule "dependencies/LIEF/src"]
|
||||
path = dependencies/LIEF/src
|
||||
url = https://github.com/lief-project/LIEF.git
|
||||
|
@ -117,6 +117,7 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(DEFAULT_PREFIX "/")
|
||||
endif()
|
||||
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
|
||||
set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE)
|
||||
endif()
|
||||
|
||||
# Required Compile Flags
|
||||
|
@ -28,6 +28,7 @@ file(WRITE "${toolchain_dir}/toolchain.cmake"
|
||||
"set(CMAKE_CXX_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-g++\")\n"
|
||||
"set(CMAKE_SYSTEM_NAME \"Linux\")\n"
|
||||
"set(CMAKE_SYSTEM_PROCESSOR \"arm\")\n"
|
||||
"set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n"
|
||||
)
|
||||
set(CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" CACHE STRING "" FORCE)
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
# Warning
|
||||
message(WARNING "i686 Builds Are Unsupported, Proceed At Your Own Risk")
|
||||
# Compile For i686
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
|
||||
# Use i686 Cross-Compiler
|
||||
setup_toolchain("i686-linux-gnu")
|
||||
# Details
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "i686")
|
4
dependencies/CMakeLists.txt
vendored
4
dependencies/CMakeLists.txt
vendored
@ -12,3 +12,7 @@ endif()
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE)
|
||||
add_subdirectory(zenity)
|
||||
endif()
|
||||
# LIEF
|
||||
if(BUILD_NATIVE_COMPONENTS OR (BUILD_ARM_COMPONENTS AND NOT MCPI_SERVER_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY))
|
||||
add_subdirectory(LIEF)
|
||||
endif()
|
||||
|
39
dependencies/LIEF/CMakeLists.txt
vendored
Normal file
39
dependencies/LIEF/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
project(LIEF)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w -Wno-psabi)
|
||||
|
||||
## LIEF
|
||||
|
||||
# Options
|
||||
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
|
||||
set(LIEF_C_API FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_EXAMPLES FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_PYTHON_API FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_TESTS FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_USE_CCACHE FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_LOGGING FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_LOGGING_DEBUG FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_ENABLE_JSON FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_ELF TRUE CACHE BOOL "" FORCE)
|
||||
set(LIEF_PE FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_MACHO FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_DEX FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_ART FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_OAT FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_VDEX FALSE CACHE BOOL "" FORCE)
|
||||
|
||||
# Download
|
||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
||||
|
||||
# Ensure Build
|
||||
add_custom_target(LIEF-build ALL DEPENDS LIB_LIEF)
|
||||
|
||||
# Install
|
||||
install(TARGETS LIB_LIEF DESTINATION "${MCPI_LIB_DIR}")
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS LIB_LIEF EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
# License
|
||||
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/LIEF")
|
1
dependencies/LIEF/src
vendored
Submodule
1
dependencies/LIEF/src
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c7b3ce3b2ce6917855a72709f73ef6d00b50e1f7
|
@ -3,20 +3,23 @@
|
||||
## Launch Sequence
|
||||
|
||||
### Common
|
||||
1. The launcher forks itself
|
||||
1. The launcher forks itself.
|
||||
1. The child process continues the launch sequence.
|
||||
2. The original process monitors the child process for crashes.
|
||||
|
||||
### Client
|
||||
1. The launcher is started by the user
|
||||
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn
|
||||
2. The launcher replaces itself with MCPI
|
||||
1. MCPI-Reborn components are loaded using ``LD_PRELOAD`` and ``LD_LIBRARY_PATH``
|
||||
2. If the Media Layer Proxy is enabled, the Media Layer Proxy Client is started as a sub-process
|
||||
1. The launcher is started by the user.
|
||||
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn.
|
||||
1. If the corresponding environmental variable for a setting is specified, it will be used instead of the dialog.
|
||||
2. If a setting is cached, then the dialog's default value will be the cached value instead of the normal default.
|
||||
3. When configuration has been completed, the settings specified will be cached.
|
||||
2. The launcher replaces itself with MCPI.
|
||||
1. MCPI-Reborn components are loaded using ``LD_PRELOAD`` and ``LD_LIBRARY_PATH``.
|
||||
2. If the Media Layer Proxy is enabled, then the Media Layer Proxy Client is started as a sub-process.
|
||||
|
||||
### Server
|
||||
1. The launcher is started by the user
|
||||
2. The launcher replaces itself with MCPI
|
||||
1. The launcher is started by the user.
|
||||
2. The launcher replaces itself with MCPI.
|
||||
|
||||
## Components
|
||||
|
||||
@ -25,7 +28,8 @@ This component configures the various environmental variables required for MCPI-
|
||||
|
||||
The environmental variables configured by this component includes:
|
||||
* ``LD_PRELOAD``
|
||||
* ``LD_LIBRAR_PATH``
|
||||
* ``LD_LIBRARY_PATH``
|
||||
* ``GCONV_PATH``
|
||||
* ``MCPI_FEATURE_FLAGS``
|
||||
* ``MCPI_RENDER_DISTANCE``
|
||||
* ``MCPI_USERNAME``
|
||||
@ -64,7 +68,7 @@ It is made of two parts:
|
||||
|
||||
While proxying all Media Layer Core API calls across UNIX pipes does hurt performance, it is better than emulating the entire graphics stack.
|
||||
|
||||
Using this in server-mode is redundant.
|
||||
Using this in server-mode is redundant (but is possible).
|
||||
|
||||
#### Extras
|
||||
This sub-component contains code that must always be linked directly to MCPI.
|
||||
@ -75,7 +79,7 @@ This is always compiled for ARM.
|
||||
This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation.
|
||||
|
||||
### Mods
|
||||
This component links directly to MCPI and patches it to modify its behavior.
|
||||
This component patches MCPI to modify its behavior. It's loaded using ``LD_PRELOAD``.
|
||||
|
||||
This is always compiled for ARM.
|
||||
|
||||
@ -95,8 +99,7 @@ This component contains all MCPI symbols.
|
||||
MCPI-Reborn has several dependencies:
|
||||
* MCPI (Bundled)
|
||||
* GLFW (Only In Client Mode; Bundled)
|
||||
* Open GL ES 2.0
|
||||
* EGL
|
||||
* OpenGL ES 2.0
|
||||
* OpenAL (Only In Client Mode)
|
||||
* ZLib (Required By LibPNG; Bundled)
|
||||
* LibPNG (Bundled)
|
||||
|
@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
**2.4.4**
|
||||
* Cache Previous Launcher Configuration
|
||||
* Add ``MCPI_API_PORT`` Environmental Variable
|
||||
* Fix Particles In Front-Facing View
|
||||
* Fixed Launch Crash On Ubuntu ARM64
|
||||
* PatchELF Replaced With LIEF
|
||||
* Moved ``3D Anaglyph`` Feature Flag To Options Screen
|
||||
* Add ``Improved Classic Title Screen`` Feature Flag (Enabled By Default)
|
||||
* Add Quit button
|
||||
* Add Options Button (Moved From ``Fix Options Screen`` Feature Flag)
|
||||
* Add ``Disable Speed Bridging`` Feature Flag (Disabled By Default)
|
||||
* Add ``Disable Creative Mode Mining Delay`` Feature Flag (Disabled By Default)
|
||||
* Improved Feature Flag Names
|
||||
* Miscellaneous Bug Fixes
|
||||
* Improved Build System
|
||||
|
||||
**2.4.3**
|
||||
* Fix Signs With CP-437
|
||||
|
||||
|
@ -5,8 +5,10 @@
|
||||
### ``--version`` (Or ``-v``)
|
||||
If you run MCPI-Reborn with ``--version`` it will print its version to ``stdout``.
|
||||
|
||||
### ``--print-available-feature-flags`` (Client Mode Only)
|
||||
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags to ``stdout`` and then immediately exit.
|
||||
### Client Mode Only
|
||||
|
||||
#### ``--print-available-feature-flags``
|
||||
This print the available feature flags (and their default values) to ``stdout`` and then immediately exit.
|
||||
|
||||
The feature flags are printed in the following format:
|
||||
```
|
||||
@ -14,22 +16,33 @@ TRUE This Flag Is On By Default
|
||||
FALSE This Flag Is Off By Default
|
||||
```
|
||||
|
||||
### ``--default`` (Client Mode Only)
|
||||
If you run MCPI-Reborn with ``--default``, it will skip the startup configuration dialogs and just use the default values.
|
||||
#### ``--default``
|
||||
This will skip the startup configuration dialogs and just use the default values. This will use the cached configuration unless ``--no-cache`` is used.
|
||||
|
||||
### ``--only-generate`` (Server Mode Only)
|
||||
If you run MCPI-Reborn with ``--only-generate``, it will immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
|
||||
|
||||
### ``--benchmark`` (Client Mode Only)
|
||||
If you run MCPI-Reborn with ``--benchmark``, it will enter a simple benchmark mode. This means automatically loading a newly generated world, then rotating the camera for a period of time. When it has finished, it will then exit and print the average FPS while the world was loaded. In this mode, all user input is blocked. However you can still modify rendering settings by changing feature flags.
|
||||
#### ``--benchmark``
|
||||
This will make MCPI-Reborn enter a simple benchmark mode. This means automatically loading a newly generated world, then rotating the camera for a period of time. When it has finished, it will then exit and print the average FPS while the world was loaded. In this mode, all user input is blocked. However you can still modify rendering settings by changing feature flags.
|
||||
|
||||
The world used will always be re-created on start and uses a hard-coded seed.
|
||||
|
||||
#### ``--no-cache``
|
||||
This will skip loading and saving the cached launcher configuration.
|
||||
|
||||
#### ``--wipe-cache``
|
||||
This will wipe the cached launcher configuration.
|
||||
|
||||
### Server Mode Only
|
||||
|
||||
#### ``--only-generate``
|
||||
This will make MCPI-Reborn immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
|
||||
|
||||
## Environmental Variables
|
||||
|
||||
### ``MCPI_DEBUG``
|
||||
This enables debug logging if it is set.
|
||||
|
||||
### ``MCPI_API_PORT``
|
||||
This configures the API to use a different port (the default is 4711).
|
||||
|
||||
### Client Mode Only
|
||||
If any of the following variables aren't set, one configuration dialog will open on startup for each unset variable.
|
||||
|
||||
|
@ -7,15 +7,15 @@ Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-rebo
|
||||
* Debian Buster/Ubuntu 18.04 Or Higher
|
||||
* QEMU User-Mode
|
||||
* Debian/Ubuntu: ``sudo apt install qemu-user``
|
||||
* Arch: ``sudo pacman -Sy qemu-user``
|
||||
* Arch: ``sudo pacman -S qemu-user``
|
||||
* Client-Only Dependencies
|
||||
* Graphics Drivers
|
||||
* GTK+ 3
|
||||
* Debian/Ubuntu: ``sudo apt install libgtk-3-0``
|
||||
* Arch: ``sudo pacman -Sy gtk3``
|
||||
* Arch: ``sudo pacman -S gtk3``
|
||||
* OpenAL
|
||||
* Debian/Ubuntu: ``sudo apt install libopenal1``
|
||||
* Arch: ``sudo pacman -Sy openal``
|
||||
* Arch: ``sudo pacman -S openal``
|
||||
|
||||
### Running
|
||||
Follow [these](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage) instructions.
|
||||
|
BIN
images/start.png
BIN
images/start.png
Binary file not shown.
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
@ -1,17 +1,14 @@
|
||||
project(launcher)
|
||||
|
||||
# Dependencies
|
||||
add_subdirectory(dependencies)
|
||||
|
||||
# Launcher
|
||||
add_executable(launcher src/bootstrap.c src/patchelf.c src/crash-report.c)
|
||||
add_executable(launcher src/bootstrap.c src/patchelf.cpp src/crash-report.c)
|
||||
if(MCPI_SERVER_MODE)
|
||||
target_sources(launcher PRIVATE src/server/launcher.c)
|
||||
else()
|
||||
embed_resource(launcher src/client/available-feature-flags)
|
||||
target_sources(launcher PRIVATE src/client/launcher.cpp)
|
||||
target_sources(launcher PRIVATE src/client/launcher.cpp src/client/cache.cpp)
|
||||
endif()
|
||||
target_link_libraries(launcher reborn-util)
|
||||
target_link_libraries(launcher reborn-util LIB_LIEF)
|
||||
# RPath
|
||||
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
project(launcher-dependencies)
|
||||
|
||||
# PatchELF
|
||||
add_subdirectory(patchelf)
|
@ -1,17 +0,0 @@
|
||||
project(patchelf)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w)
|
||||
|
||||
## PatchELF
|
||||
|
||||
# Build
|
||||
add_executable(patchelf src/src/patchelf.cc)
|
||||
target_compile_definitions(patchelf PRIVATE -D_FILE_OFFSET_BITS=64)
|
||||
set_target_properties(patchelf PROPERTIES CXX_STANDARD 17)
|
||||
|
||||
# Install
|
||||
install(TARGETS patchelf DESTINATION "${MCPI_BIN_DIR}")
|
||||
|
||||
# License
|
||||
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/patchelf")
|
@ -1 +0,0 @@
|
||||
Subproject commit c2b419dc2a0d6095eaa69b65ad5854ce847bdd01
|
@ -101,6 +101,9 @@ void pre_bootstrap(int argc, char *argv[]) {
|
||||
// Disable stdout Buffering
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Launcher) ";
|
||||
|
||||
// Set Default Native Component Environment
|
||||
#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name));
|
||||
for_each_special_environmental_variable(set_variable_default);
|
||||
@ -180,7 +183,7 @@ void pre_bootstrap(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// Copy SDK Into ~/.minecraft-pi
|
||||
static void run_simple_command(const char *const command[], const char *error) {
|
||||
void run_simple_command(const char *const command[], const char *error) {
|
||||
int status = 0;
|
||||
char *output = run_command(command, &status);
|
||||
if (output != NULL) {
|
||||
@ -190,10 +193,24 @@ static void run_simple_command(const char *const command[], const char *error) {
|
||||
ERR("%s", error);
|
||||
}
|
||||
}
|
||||
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
|
||||
static void copy_sdk(char *binary_directory) {
|
||||
// Ensure SDK Directory
|
||||
{
|
||||
char *sdk_path = NULL;
|
||||
safe_asprintf(&sdk_path, "%s" HOME_SUBDIRECTORY_FOR_SDK, getenv("HOME"));
|
||||
const char *const command[] = {"mkdir", "-p", sdk_path, NULL};
|
||||
run_simple_command(command, "Unable To Create SDK Directory");
|
||||
}
|
||||
|
||||
// Lock File
|
||||
char *lock_file_path = NULL;
|
||||
safe_asprintf(&lock_file_path, "%s" HOME_SUBDIRECTORY_FOR_SDK "/.lock", getenv("HOME"));
|
||||
int lock_file_fd = lock_file(lock_file_path);
|
||||
|
||||
// Output Directory
|
||||
char *output = NULL;
|
||||
safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk/" MCPI_SDK_DIR, getenv("HOME"));
|
||||
safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_SDK "/" MCPI_SDK_DIR, getenv("HOME"));
|
||||
// Source Directory
|
||||
char *source = NULL;
|
||||
safe_asprintf(&source, "%s/sdk/.", binary_directory);
|
||||
@ -219,6 +236,10 @@ static void copy_sdk(char *binary_directory) {
|
||||
// Free
|
||||
free(output);
|
||||
free(source);
|
||||
|
||||
// Unlock File
|
||||
unlock_file(lock_file_path, lock_file_fd);
|
||||
free(lock_file_path);
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
@ -269,10 +290,7 @@ void bootstrap(int argc, char *argv[]) {
|
||||
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
|
||||
#else
|
||||
// Use Current Linker
|
||||
char *exe = realpath("/proc/self/exe", NULL);
|
||||
ALLOC_CHECK(exe);
|
||||
linker = patch_get_interpreter(exe);
|
||||
free(exe);
|
||||
linker = patch_get_interpreter();
|
||||
#endif
|
||||
|
||||
// Patch
|
||||
|
@ -4,6 +4,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void run_simple_command(const char *const command[], const char *error);
|
||||
|
||||
void pre_bootstrap(int argc, char *argv[]);
|
||||
void bootstrap(int argc, char *argv[]);
|
||||
|
||||
|
@ -6,18 +6,17 @@ TRUE Disable Autojump By Default
|
||||
TRUE Display Nametags By Default
|
||||
TRUE Fix Sign Placement
|
||||
TRUE Show Block Outlines
|
||||
FALSE Expand Creative Inventory
|
||||
FALSE Expand Creative Mode Inventory
|
||||
FALSE Remove Creative Mode Restrictions
|
||||
TRUE Animated Water
|
||||
TRUE Remove Invalid Item Background
|
||||
TRUE Disable "gui_blocks" Atlas
|
||||
FALSE 3D Anaglyph
|
||||
TRUE Fix Camera Rendering
|
||||
TRUE Implement Chat
|
||||
FALSE Hide Chat Messages
|
||||
TRUE Implement Death Messages
|
||||
TRUE Implement Game-Mode Switching
|
||||
TRUE Allow Joining Survival Servers
|
||||
TRUE Allow Joining Survival Mode Servers
|
||||
TRUE Miscellaneous Input Fixes
|
||||
TRUE Bind "Q" Key To Item Dropping
|
||||
TRUE Bind Common Toggleable Options To Function Keys
|
||||
@ -33,7 +32,7 @@ TRUE Disable V-Sync
|
||||
TRUE Fix Options Screen
|
||||
TRUE Force Touch GUI Inventory
|
||||
TRUE Fix Pause Menu
|
||||
TRUE Improved Title Background
|
||||
TRUE Add Title Screen Background
|
||||
TRUE Force Touch GUI Button Behavior
|
||||
TRUE Improved Button Hover Behavior
|
||||
TRUE Implement Create World Dialog
|
||||
@ -42,3 +41,6 @@ TRUE Add Buckets
|
||||
TRUE Classic HUD
|
||||
TRUE Translucent Toolbar
|
||||
FALSE Force EGL
|
||||
TRUE Improved Classic Title Screen
|
||||
FALSE Disable Speed Bridging
|
||||
FALSE Disable Creative Mode Mining Delay
|
||||
|
171
launcher/src/client/cache.cpp
Normal file
171
launcher/src/client/cache.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "launcher.h"
|
||||
#include "cache.h"
|
||||
|
||||
// Get Cache Path
|
||||
static std::string get_cache_path() {
|
||||
const char *home = getenv("HOME");
|
||||
if (home == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
return std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA "/.launcher-cache";
|
||||
}
|
||||
|
||||
// Load
|
||||
launcher_cache empty_cache = {
|
||||
.username = DEFAULT_USERNAME,
|
||||
.render_distance = DEFAULT_RENDER_DISTANCE,
|
||||
.feature_flags = {}
|
||||
};
|
||||
launcher_cache load_cache() {
|
||||
// Log
|
||||
DEBUG("Loading Launcher Cache...");
|
||||
|
||||
// Lock File
|
||||
int lock_fd = lock_file(get_cache_path().c_str());
|
||||
|
||||
// Return Value
|
||||
launcher_cache ret = empty_cache;
|
||||
|
||||
// Open File
|
||||
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
|
||||
if (!stream) {
|
||||
// Fail
|
||||
struct stat s;
|
||||
// No Warning If File Doesn't Exist
|
||||
if (stat(get_cache_path().c_str(), &s) == 0) {
|
||||
WARN("Unable To Open Launcher Cache For Loading");
|
||||
}
|
||||
} else {
|
||||
// Check Version
|
||||
unsigned char cache_version;
|
||||
stream.read((char *) &cache_version, 1);
|
||||
if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) {
|
||||
// Fail
|
||||
if (!stream.eof()) {
|
||||
WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", (int) CACHE_VERSION, (int) cache_version);
|
||||
} else {
|
||||
WARN("Unable To Read Launcher Cache Version");
|
||||
}
|
||||
stream.close();
|
||||
} else {
|
||||
// Load Username And Render Distance
|
||||
launcher_cache cache;
|
||||
std::getline(stream, cache.username, '\0');
|
||||
std::getline(stream, cache.render_distance, '\0');
|
||||
|
||||
// Load Feature Flags
|
||||
std::string flag;
|
||||
while (!stream.eof() && std::getline(stream, flag, '\0')) {
|
||||
if (flag.length() > 0) {
|
||||
unsigned char is_enabled = 0;
|
||||
stream.read((char *) &is_enabled, 1);
|
||||
cache.feature_flags[flag] = is_enabled != (unsigned char) 0;
|
||||
}
|
||||
stream.peek();
|
||||
}
|
||||
|
||||
// Finish
|
||||
stream.close();
|
||||
if (!stream) {
|
||||
// Fail
|
||||
WARN("Failure While Loading Launcher Cache");
|
||||
} else {
|
||||
// Success
|
||||
ret = cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock File
|
||||
unlock_file(get_cache_path().c_str(), lock_fd);
|
||||
|
||||
// Return
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Save
|
||||
#define write_env_to_stream(stream, env) \
|
||||
{ \
|
||||
const char *env_value = getenv(env); \
|
||||
if (env == NULL) { \
|
||||
IMPOSSIBLE(); \
|
||||
} \
|
||||
stream.write(env_value, strlen(env_value) + 1); \
|
||||
}
|
||||
void save_cache() {
|
||||
// Log
|
||||
DEBUG("Saving Launcher Cache...");
|
||||
|
||||
// Lock File
|
||||
int lock_fd = lock_file(get_cache_path().c_str());
|
||||
|
||||
// Open File
|
||||
std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary);
|
||||
if (!stream) {
|
||||
// Fail
|
||||
WARN("Unable To Open Launcher Cache For Saving");
|
||||
} else {
|
||||
// Save Cache Version
|
||||
unsigned char cache_version = (unsigned char) CACHE_VERSION;
|
||||
stream.write((const char *) &cache_version, 1);
|
||||
|
||||
// Save Username And Render Distance
|
||||
write_env_to_stream(stream, "MCPI_USERNAME");
|
||||
write_env_to_stream(stream, "MCPI_RENDER_DISTANCE");
|
||||
|
||||
// Save Feature Flags
|
||||
std::unordered_map<std::string, bool> flags;
|
||||
load_available_feature_flags([&flags](std::string flag) {
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, NULL);
|
||||
flags[stripped_flag] = false;
|
||||
});
|
||||
{
|
||||
const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS");
|
||||
if (enabled_flags == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
std::istringstream enabled_flags_stream(enabled_flags);
|
||||
std::string flag;
|
||||
while (std::getline(enabled_flags_stream, flag, '|')) {
|
||||
if (flag.length() > 0) {
|
||||
flags[flag] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &it : flags) {
|
||||
stream.write(it.first.c_str(), it.first.size() + 1);
|
||||
unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0;
|
||||
stream.write((const char *) &val, 1);
|
||||
}
|
||||
|
||||
// Finish
|
||||
stream.close();
|
||||
if (!stream.good()) {
|
||||
WARN("Failure While Saving Launcher Cache");
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock File
|
||||
unlock_file(get_cache_path().c_str(), lock_fd);
|
||||
}
|
||||
|
||||
// Wipe Cache
|
||||
void wipe_cache() {
|
||||
// Log
|
||||
INFO("Wiping Launcher Cache...");
|
||||
|
||||
// Unlink File
|
||||
if (unlink(get_cache_path().c_str()) != 0) {
|
||||
WARN("Failure While Wiping Cache: %s", strerror(errno));
|
||||
}
|
||||
}
|
22
launcher/src/client/cache.h
Normal file
22
launcher/src/client/cache.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// Cache Version
|
||||
#define CACHE_VERSION 0
|
||||
|
||||
// Load Cache
|
||||
typedef struct {
|
||||
std::string username;
|
||||
std::string render_distance;
|
||||
std::unordered_map<std::string, bool> feature_flags;
|
||||
} launcher_cache;
|
||||
extern launcher_cache empty_cache;
|
||||
launcher_cache load_cache();
|
||||
|
||||
// Save Cache
|
||||
void save_cache();
|
||||
|
||||
// Wipe Cache
|
||||
void wipe_cache();
|
@ -10,9 +10,11 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../bootstrap.h"
|
||||
#include "launcher.h"
|
||||
#include "cache.h"
|
||||
|
||||
// Strip Feature Flag Default
|
||||
static std::string strip_feature_flag_default(std::string flag, bool *default_ret) {
|
||||
std::string strip_feature_flag_default(std::string flag, bool *default_ret) {
|
||||
// Valid Values
|
||||
std::string true_str = "TRUE ";
|
||||
std::string false_str = "FALSE ";
|
||||
@ -38,7 +40,7 @@ static std::string strip_feature_flag_default(std::string flag, bool *default_re
|
||||
// Load Available Feature Flags
|
||||
extern unsigned char available_feature_flags[];
|
||||
extern size_t available_feature_flags_len;
|
||||
static void load_available_feature_flags(std::function<void(std::string)> callback) {
|
||||
void load_available_feature_flags(std::function<void(std::string)> callback) {
|
||||
// Get Path
|
||||
char *binary_directory = get_binary_directory();
|
||||
std::string path = std::string(binary_directory) + "/available-feature-flags";
|
||||
@ -134,10 +136,6 @@ static void set_env_if_unset(const char *env_name, std::function<std::string()>
|
||||
}
|
||||
}
|
||||
|
||||
// Defaults
|
||||
#define DEFAULT_USERNAME "StevePi"
|
||||
#define DEFAULT_RENDER_DISTANCE "Short"
|
||||
|
||||
// Launch
|
||||
#define LIST_DIALOG_SIZE "400"
|
||||
int main(int argc, char *argv[]) {
|
||||
@ -146,8 +144,10 @@ int main(int argc, char *argv[]) {
|
||||
ERR("Don't Run As Root");
|
||||
}
|
||||
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap(argc, argv);
|
||||
// Ensure HOME
|
||||
if (getenv("HOME") == NULL) {
|
||||
ERR("$HOME Isn't Set");
|
||||
}
|
||||
|
||||
// Print Features
|
||||
for (int i = 1; i < argc; i++) {
|
||||
@ -161,18 +161,53 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap(argc, argv);
|
||||
|
||||
// Create ~/.minecraft-pi If Needed
|
||||
{
|
||||
char *minecraft_folder = NULL;
|
||||
safe_asprintf(&minecraft_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA, getenv("HOME"));
|
||||
const char *const command[] = {"mkdir", "-p", minecraft_folder, NULL};
|
||||
run_simple_command(command, "Unable To Create Data Directory");
|
||||
free(minecraft_folder);
|
||||
}
|
||||
|
||||
// --wipe-cache
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--wipe-cache") == 0) {
|
||||
wipe_cache();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --no-cache
|
||||
bool no_cache = false;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--no-cache") == 0) {
|
||||
no_cache = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Load Cache
|
||||
launcher_cache cache = no_cache ? empty_cache : load_cache();
|
||||
|
||||
// --default
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--default") == 0) {
|
||||
// Use Default Feature Flags
|
||||
set_env_if_unset("MCPI_FEATURE_FLAGS", []() {
|
||||
set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() {
|
||||
std::string feature_flags = "";
|
||||
load_available_feature_flags([&feature_flags](std::string flag) {
|
||||
bool default_value;
|
||||
load_available_feature_flags([&feature_flags, &cache](std::string flag) {
|
||||
bool value;
|
||||
// Strip Default Value
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &default_value);
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &value);
|
||||
// Use Cache
|
||||
if (cache.feature_flags.count(stripped_flag) > 0) {
|
||||
value = cache.feature_flags[stripped_flag];
|
||||
}
|
||||
// Specify Default Value
|
||||
if (default_value) {
|
||||
if (value) {
|
||||
// Enabled By Default
|
||||
feature_flags += stripped_flag + '|';
|
||||
}
|
||||
@ -182,36 +217,16 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
return feature_flags;
|
||||
});
|
||||
set_env_if_unset("MCPI_RENDER_DISTANCE", []() {
|
||||
return DEFAULT_RENDER_DISTANCE;
|
||||
set_env_if_unset("MCPI_RENDER_DISTANCE", [&cache]() {
|
||||
return cache.render_distance;
|
||||
});
|
||||
set_env_if_unset("MCPI_USERNAME", []() {
|
||||
return DEFAULT_USERNAME;
|
||||
set_env_if_unset("MCPI_USERNAME", [&cache]() {
|
||||
return cache.username;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create ~/.minecraft-pi If Needed
|
||||
// Minecraft Folder
|
||||
{
|
||||
char *minecraft_folder = NULL;
|
||||
safe_asprintf(&minecraft_folder, "%s/.minecraft-pi", getenv("HOME"));
|
||||
{
|
||||
// Check Minecraft Folder
|
||||
struct stat obj;
|
||||
if (stat(minecraft_folder, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
|
||||
// Create Minecraft Folder
|
||||
int ret = mkdir(minecraft_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
if (ret != 0) {
|
||||
// Unable To Create Folder
|
||||
ERR("Error Creating Directory: %s: %s", minecraft_folder, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
free(minecraft_folder);
|
||||
}
|
||||
|
||||
// Setup MCPI_FEATURE_FLAGS
|
||||
{
|
||||
std::vector<std::string> command;
|
||||
@ -225,12 +240,16 @@ int main(int argc, char *argv[]) {
|
||||
command.push_back("Enabled");
|
||||
command.push_back("--column");
|
||||
command.push_back("Feature");
|
||||
load_available_feature_flags([&command](std::string flag) {
|
||||
bool default_value;
|
||||
load_available_feature_flags([&command, &cache](std::string flag) {
|
||||
bool value;
|
||||
// Strip Default Value
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &default_value);
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &value);
|
||||
// Use Cache
|
||||
if (cache.feature_flags.count(stripped_flag) > 0) {
|
||||
value = cache.feature_flags[stripped_flag];
|
||||
}
|
||||
// Specify Default Value
|
||||
if (default_value) {
|
||||
if (value) {
|
||||
// Enabled By Default
|
||||
command.push_back("TRUE");
|
||||
} else {
|
||||
@ -260,7 +279,7 @@ int main(int argc, char *argv[]) {
|
||||
command.push_back("Name");
|
||||
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
|
||||
for (std::string &render_distance : render_distances) {
|
||||
command.push_back(render_distance.compare(DEFAULT_RENDER_DISTANCE) == 0 ? "TRUE" : "FALSE");
|
||||
command.push_back(render_distance.compare(cache.render_distance) == 0 ? "TRUE" : "FALSE");
|
||||
command.push_back(render_distance);
|
||||
}
|
||||
// Run
|
||||
@ -273,11 +292,16 @@ int main(int argc, char *argv[]) {
|
||||
command.push_back("--text");
|
||||
command.push_back("Enter Minecraft Username:");
|
||||
command.push_back("--entry-text");
|
||||
command.push_back(DEFAULT_USERNAME);
|
||||
command.push_back(cache.username);
|
||||
// Run
|
||||
run_zenity_and_set_env("MCPI_USERNAME", command);
|
||||
}
|
||||
|
||||
// Save Cache
|
||||
if (!no_cache) {
|
||||
save_cache();
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
bootstrap(argc, argv);
|
||||
}
|
||||
|
12
launcher/src/client/launcher.h
Normal file
12
launcher/src/client/launcher.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
// Defaults
|
||||
#define DEFAULT_USERNAME "StevePi"
|
||||
#define DEFAULT_RENDER_DISTANCE "Short"
|
||||
|
||||
// Feature Flags
|
||||
std::string strip_feature_flag_default(std::string flag, bool *default_ret);
|
||||
void load_available_feature_flags(std::function<void(std::string)> callback);
|
@ -98,6 +98,9 @@ void setup_crash_report() {
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Crash Reporter) ";
|
||||
|
||||
// Setup Logging
|
||||
#define BUFFER_SIZE 1024
|
||||
char buf[BUFFER_SIZE];
|
||||
|
@ -1,136 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "patchelf.h"
|
||||
|
||||
// Duplicate MCPI Executable Into /tmp
|
||||
static void duplicate_mcpi_executable(const char *original_path, char *new_path) {
|
||||
// Ensure Temporary Directory
|
||||
{
|
||||
// Check If It Exists
|
||||
struct stat tmp_stat;
|
||||
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
|
||||
if (!exists) {
|
||||
// Doesn't Exist
|
||||
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate New File
|
||||
int new_file_fd = mkstemp(new_path);
|
||||
if (new_file_fd == -1) {
|
||||
ERR("Unable To Create Temporary File: %s", strerror(errno));
|
||||
}
|
||||
FILE *new_file = fdopen(new_file_fd, "wb");
|
||||
if (new_file == NULL) {
|
||||
ERR("Unable To Open Temporary File: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Copy Original File
|
||||
{
|
||||
// Open Original File
|
||||
FILE *original_file = fopen(original_path, "rb");
|
||||
if (original_file == NULL) {
|
||||
ERR("Unable To Open File: %s", original_path);
|
||||
}
|
||||
|
||||
// Copy
|
||||
#define BUFFER_SIZE 1024
|
||||
char buf[BUFFER_SIZE];
|
||||
size_t bytes_read = 0;
|
||||
while ((bytes_read = fread((void *) buf, 1, BUFFER_SIZE, original_file)) > 0) {
|
||||
fwrite((void *) buf, 1, bytes_read, new_file);
|
||||
if (ferror(new_file) != 0) {
|
||||
ERR("Unable To Write File: %s", new_path);
|
||||
}
|
||||
}
|
||||
if (ferror(original_file) != 0) {
|
||||
ERR("Unable To Read File: %s", original_path);
|
||||
}
|
||||
|
||||
// Close Original File
|
||||
fclose(original_file);
|
||||
}
|
||||
|
||||
// Close New File
|
||||
fclose(new_file);
|
||||
close(new_file_fd);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
#define patch_mcpi_elf_dependencies_with_extra_patchelf_args(...) \
|
||||
({ \
|
||||
const char *const _macro_command[] = { \
|
||||
"patchelf", \
|
||||
##__VA_ARGS__, \
|
||||
"--remove-needed", "libbcm_host.so", \
|
||||
"--remove-needed", "libX11.so.6", \
|
||||
"--remove-needed", "libEGL.so", \
|
||||
"--remove-needed", "libGLESv2.so", \
|
||||
"--remove-needed", "libSDL-1.2.so.0", \
|
||||
"--add-needed", "libmedia-layer-core.so", \
|
||||
new_path, \
|
||||
NULL \
|
||||
}; \
|
||||
int _macro_return_code = 0; \
|
||||
char *_macro_output = run_command(_macro_command, &_macro_return_code); \
|
||||
if (_macro_output != NULL) { \
|
||||
free(_macro_output); \
|
||||
} \
|
||||
_macro_return_code; \
|
||||
})
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
|
||||
// Duplicate MCPI executable into /tmp so it can be modified.
|
||||
duplicate_mcpi_executable(original_path, new_path);
|
||||
|
||||
// Run patchelf
|
||||
int return_code;
|
||||
if (linker == NULL) {
|
||||
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args();
|
||||
} else {
|
||||
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args("--set-interpreter", linker);
|
||||
}
|
||||
if (!is_exit_status_success(return_code)) {
|
||||
char *exit_status_line = NULL;
|
||||
get_exit_status_string(return_code, &exit_status_line);
|
||||
ERR("patchelf Failed%s", exit_status_line);
|
||||
}
|
||||
|
||||
// Fix Permissions
|
||||
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Get Interpreter
|
||||
char *patch_get_interpreter(const char *file) {
|
||||
// Run
|
||||
const char *const command[] = {
|
||||
"patchelf",
|
||||
"--print-interpreter",
|
||||
file,
|
||||
NULL
|
||||
};
|
||||
int return_code;
|
||||
char *output = run_command(command, &return_code);
|
||||
if (!is_exit_status_success(return_code)) {
|
||||
char *exit_status_line = NULL;
|
||||
get_exit_status_string(return_code, &exit_status_line);
|
||||
ERR("patchelf Failed%s", exit_status_line);
|
||||
}
|
||||
if (output != NULL) {
|
||||
// Trim
|
||||
int length = strlen(output);
|
||||
if (output[length - 1] == '\n') {
|
||||
output[length - 1] = '\0';
|
||||
}
|
||||
}
|
||||
// Return
|
||||
return output;
|
||||
}
|
91
launcher/src/patchelf.cpp
Normal file
91
launcher/src/patchelf.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include <cstdlib>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <LIEF/ELF.hpp>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "patchelf.h"
|
||||
|
||||
// Duplicate MCPI Executable Into /tmp
|
||||
static void duplicate_mcpi_executable(char *new_path) {
|
||||
// Ensure Temporary Directory
|
||||
{
|
||||
// Check If It Exists
|
||||
struct stat tmp_stat;
|
||||
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
|
||||
if (!exists) {
|
||||
// Doesn't Exist
|
||||
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate New File
|
||||
int new_file_fd = mkstemp(new_path);
|
||||
if (new_file_fd == -1) {
|
||||
ERR("Unable To Create Temporary File: %s", strerror(errno));
|
||||
}
|
||||
close(new_file_fd);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
static const char *libraries_to_remove[] = {
|
||||
"libbcm_host.so",
|
||||
"libX11.so.6",
|
||||
"libEGL.so",
|
||||
"libGLESv2.so",
|
||||
"libSDL-1.2.so.0"
|
||||
};
|
||||
static const char *libraries_to_add[] = {
|
||||
"libmedia-layer-core.so"
|
||||
};
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
|
||||
// Duplicate MCPI executable into /tmp so it can be modified.
|
||||
duplicate_mcpi_executable(new_path);
|
||||
|
||||
// Patch File
|
||||
{
|
||||
std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
|
||||
if (linker != NULL) {
|
||||
binary->interpreter(linker);
|
||||
}
|
||||
for (size_t i = 0; i < (sizeof (libraries_to_remove) / sizeof (const char *)); i++) {
|
||||
binary->remove_library(libraries_to_remove[i]);
|
||||
}
|
||||
for (size_t i = 0; i < (sizeof (libraries_to_add) / sizeof (const char *)); i++) {
|
||||
binary->add_library(libraries_to_add[i]);
|
||||
}
|
||||
LIEF::ELF::Builder builder{*binary};
|
||||
builder.build();
|
||||
builder.write(new_path);
|
||||
}
|
||||
|
||||
// Fix Permissions
|
||||
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Get Interpreter
|
||||
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
|
||||
// Only Search Current Program
|
||||
if (strcmp(info->dlpi_name, "") == 0) {
|
||||
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||
if (info->dlpi_phdr[i].p_type == PT_INTERP) {
|
||||
// Callback
|
||||
*(char **) data = (char *) info->dlpi_phdr[i].p_vaddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
char *patch_get_interpreter() {
|
||||
char *interpreter = NULL;
|
||||
dl_iterate_phdr(dl_iterate_callback, &interpreter);
|
||||
if (interpreter != NULL) {
|
||||
interpreter = strdup(interpreter);
|
||||
}
|
||||
return interpreter;
|
||||
}
|
@ -7,7 +7,7 @@ extern "C" {
|
||||
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
|
||||
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker);
|
||||
char *patch_get_interpreter(const char *file);
|
||||
char *patch_get_interpreter();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn")
|
||||
configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
|
||||
|
||||
# Util
|
||||
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c)
|
||||
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c)
|
||||
target_include_directories(
|
||||
reborn-util
|
||||
PUBLIC
|
||||
|
@ -32,6 +32,9 @@ void chop_last_component(char **str);
|
||||
// Get Binary Directory (Remember To Free)
|
||||
char *get_binary_directory();
|
||||
|
||||
// Debug Tag
|
||||
#define CHILD_PROCESS_TAG "(Child Process) "
|
||||
|
||||
// Run Command And Get Output
|
||||
char *run_command(const char *const command[], int *exit_status);
|
||||
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||
|
@ -3,9 +3,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Debug Tag
|
||||
extern const char *reborn_debug_tag;
|
||||
|
||||
// Logging
|
||||
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
|
||||
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
|
||||
#define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: " format "\n", ##__VA_ARGS__); } }
|
||||
#define RAW_DEBUG(tag, format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: %s" format "\n", tag, ##__VA_ARGS__); } }
|
||||
#define DEBUG(format, ...) RAW_DEBUG(reborn_debug_tag, format, ##__VA_ARGS__)
|
||||
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
|
||||
#define IMPOSSIBLE() ERR("This Should Never Be Called")
|
||||
|
@ -41,6 +41,10 @@ void safe_pipe2(int pipefd[2], int flags);
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
int is_progress_difference_significant(int32_t new_val, int32_t old_val);
|
||||
|
||||
// Lock File
|
||||
int lock_file(const char *file);
|
||||
void unlock_file(const char *file, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <sys/mman.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
|
@ -38,7 +38,7 @@ __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char
|
||||
int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOENT && strcmp(argv[0], "qemu-qrm")) {
|
||||
ERR("Unable to find QEMU! To install on Ubuntu/Debian, run \"sudo apt install qemu-user\". To install on Arch Linux, run \"sudo pacman -Sy qemu-user\".");
|
||||
ERR("Unable to find QEMU! To install on Ubuntu/Debian, run \"sudo apt install qemu-user\". To install on Arch Linux, run \"sudo pacman -S qemu-user\".");
|
||||
}
|
||||
ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
|
||||
} else {
|
||||
@ -82,6 +82,9 @@ char *run_command(const char *const command[], int *exit_status) {
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = CHILD_PROCESS_TAG;
|
||||
|
||||
// Pipe stdout
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
close(output_pipe[0]);
|
||||
|
4
libreborn/src/util/log.c
Normal file
4
libreborn/src/util/log.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include <libreborn/log.h>
|
||||
|
||||
// Debug Tag
|
||||
const char *reborn_debug_tag = "";
|
@ -1,3 +1,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <libreborn/util.h>
|
||||
|
||||
// Safe Version Of pipe()
|
||||
@ -22,3 +25,21 @@ int is_progress_difference_significant(int32_t new_val, int32_t old_val) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Lock File
|
||||
int lock_file(const char *file) {
|
||||
int fd = open(file, O_WRONLY | O_CREAT, S_IWUSR);
|
||||
if (fd == -1) {
|
||||
ERR("Unable To Open Lock File: %s: %s", file, strerror(errno));
|
||||
}
|
||||
if (flock(fd, LOCK_EX) == -1) {
|
||||
ERR("Unable To Lock File: %s: %s", file, strerror(errno));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
void unlock_file(const char *file, int fd) {
|
||||
if (flock(fd, LOCK_UN) == -1) {
|
||||
ERR("Unable To Unlock File: %s: %s", file, strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
@ -28,5 +28,5 @@ if(NOT MCPI_HEADLESS_MODE)
|
||||
# OpenAL
|
||||
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw)
|
||||
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw PRIVATE LIB_LIEF)
|
||||
endif()
|
||||
|
@ -6,12 +6,12 @@ if(MCPI_HEADLESS_MODE)
|
||||
set(GLES_SRC src/stubs.c)
|
||||
elseif(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
|
||||
# GLESv1_CM Compatibility Layer
|
||||
set(GLES_SRC src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c src/compatibility-layer/buffer.cpp)
|
||||
set(GLES_SRC src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c)
|
||||
else()
|
||||
# Passthrough To glfwGetProcAddress()
|
||||
set(GLES_SRC src/passthrough.c)
|
||||
endif()
|
||||
add_library(GLESv1_CM SHARED ${GLES_SRC})
|
||||
add_library(GLESv1_CM OBJECT ${GLES_SRC})
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
target_link_libraries(GLESv1_CM PRIVATE glfw PUBLIC reborn-util PRIVATE dl PRIVATE m)
|
||||
# Shaders
|
||||
|
@ -1,35 +0,0 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include "../passthrough.h"
|
||||
|
||||
// Store Buffers
|
||||
static std::unordered_map<GLuint, GLuint> buffers_map;
|
||||
// Get Buffer
|
||||
GL_FUNC(glGenBuffers, void, (GLsizei n, GLuint *buffers));
|
||||
static GLuint get_real_buffer(GLuint fake_buffer) {
|
||||
if (buffers_map.count(fake_buffer) > 0) {
|
||||
return buffers_map[fake_buffer];
|
||||
} else {
|
||||
GLuint new_buffer;
|
||||
real_glGenBuffers()(1, &new_buffer);
|
||||
buffers_map[fake_buffer] = new_buffer;
|
||||
return get_real_buffer(fake_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert Fake Buffers To Real Buffers When Calling GL
|
||||
GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer));
|
||||
void glBindBuffer(GLenum target, GLuint buffer) {
|
||||
real_glBindBuffer()(target, get_real_buffer(buffer));
|
||||
}
|
||||
GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers));
|
||||
void glDeleteBuffers(GLsizei n, const GLuint *buffers) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (buffers_map.count(buffers[i]) > 0) {
|
||||
real_glDeleteBuffers()(1, &buffers_map[i]);
|
||||
buffers_map.erase(buffers[i]);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
|
||||
// Matrix Common
|
||||
#define MATRIX_SIZE 4
|
||||
#define MATRIX_DATA_SIZE (sizeof (float) * MATRIX_SIZE * MATRIX_SIZE)
|
||||
// OpenGL Matricies Are Column-Major
|
||||
#define MATRIX_DATA_SIZE (sizeof (GLfloat) * MATRIX_SIZE * MATRIX_SIZE)
|
||||
// OpenGL Matrices Are Column-Major
|
||||
typedef struct {
|
||||
GLfloat data[MATRIX_SIZE][MATRIX_SIZE];
|
||||
} matrix_t;
|
||||
|
@ -39,6 +39,10 @@ GL_FUNC(glDepthRangef, void, (GLclampf near, GLclampf far));
|
||||
void glDepthRangef(GLclampf near, GLclampf far) {
|
||||
real_glDepthRangef()(near, far);
|
||||
}
|
||||
GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer));
|
||||
void glBindBuffer(GLenum target, GLuint buffer) {
|
||||
real_glBindBuffer()(target, buffer);
|
||||
}
|
||||
GL_FUNC(glDepthFunc, void, (GLenum func));
|
||||
void glDepthFunc(GLenum func) {
|
||||
real_glDepthFunc()(func);
|
||||
@ -57,6 +61,10 @@ void glHint(GLenum target, GLenum mode) {
|
||||
real_glHint()(target, mode);
|
||||
}
|
||||
}
|
||||
GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers));
|
||||
void glDeleteBuffers(GLsizei n, const GLuint *buffers) {
|
||||
real_glDeleteBuffers()(n, buffers);
|
||||
}
|
||||
GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
|
||||
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
real_glColorMask()(red, green, blue, alpha);
|
||||
@ -103,3 +111,7 @@ void glShadeModel(__attribute__((unused)) GLenum mode) {
|
||||
void glNormal3f(__attribute__((unused)) GLfloat nx, __attribute__((unused)) GLfloat ny, __attribute__((unused)) GLfloat nz) {
|
||||
// Do Nothing
|
||||
}
|
||||
GL_FUNC(glGenBuffers, void, (GLsizei n, GLuint *buffers));
|
||||
void glGenBuffers(GLsizei n, GLuint *buffers) {
|
||||
real_glGenBuffers()(n, buffers);
|
||||
}
|
||||
|
@ -202,3 +202,7 @@ GL_FUNC(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GL
|
||||
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
|
||||
real_glReadPixels()(x, y, width, height, format, type, data);
|
||||
}
|
||||
GL_FUNC(glGenBuffers, void, (GLsizei n, GLuint *buffers));
|
||||
void glGenBuffers(GLsizei n, GLuint *buffers) {
|
||||
real_glGenBuffers()(n, buffers);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha
|
||||
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
|
||||
}
|
||||
void glGenTextures(GLsizei n, GLuint *textures) {
|
||||
static int i = 0;
|
||||
static int i = 1;
|
||||
for (int j = 0; j < n; j++) {
|
||||
textures[j] = i++;
|
||||
}
|
||||
@ -160,5 +160,11 @@ void glGetIntegerv(GLenum pname, GLint *data) {
|
||||
}
|
||||
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
|
||||
}
|
||||
void glGenBuffers(GLsizei n, GLuint *buffers) {
|
||||
static int i = 1;
|
||||
for (int j = 0; j < n; j++) {
|
||||
buffers[j] = i++;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
@ -1,14 +1,11 @@
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include <AL/al.h>
|
||||
|
||||
#include <LIEF/ELF.hpp>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "file.h"
|
||||
@ -16,121 +13,16 @@
|
||||
|
||||
// Load Symbol From ELF File
|
||||
static void load_symbol(const char *source, const char *name, std::function<void(unsigned char *, uint32_t)> callback) {
|
||||
// File Data
|
||||
FILE *file_obj = NULL;
|
||||
unsigned char *file_map = NULL;
|
||||
long int file_size = 0;
|
||||
|
||||
// Code
|
||||
{
|
||||
// Load Main Binary
|
||||
file_obj = fopen(source, "rb");
|
||||
|
||||
// Verify Binary
|
||||
if (!file_obj) {
|
||||
WARN("Unable To Open: %s", source);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
fseek(file_obj, 0L, SEEK_END);
|
||||
file_size = ftell(file_obj);
|
||||
fseek(file_obj, 0L, SEEK_SET);
|
||||
|
||||
// Map File To Pointer
|
||||
file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
|
||||
|
||||
// Check ELF Magic
|
||||
if (file_map[EI_MAG0] != ELFMAG0 || file_map[EI_MAG1] != ELFMAG1 || file_map[EI_MAG2] != ELFMAG2 || file_map[EI_MAG3] != ELFMAG3) {
|
||||
WARN("Not An ELF File: %s", source);
|
||||
goto end;
|
||||
}
|
||||
if (file_map[EI_CLASS] != ELFCLASS32) {
|
||||
WARN("ELF File Isn't 32-Bit: %s", source);
|
||||
goto end;
|
||||
}
|
||||
if (file_map[EI_DATA] != ELFDATA2LSB) {
|
||||
WARN("ELF File Isn't Little-Endian: %s", source);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Parse ELF
|
||||
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map;
|
||||
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff);
|
||||
int elf_section_header_count = elf_header->e_shnum;
|
||||
|
||||
// Locate Section Names
|
||||
Elf32_Shdr elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
|
||||
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
|
||||
|
||||
// Locate String Table
|
||||
unsigned char *elf_strtab_p = NULL;
|
||||
for (int i = 0; i < elf_section_header_count; ++i) {
|
||||
Elf32_Shdr header = elf_section_headers[i];
|
||||
// Check Section Type
|
||||
if (header.sh_type == SHT_STRTAB) {
|
||||
// Check Section Name
|
||||
char *section_name = (char *) (elf_shstrtab_p + header.sh_name);
|
||||
if (strcmp(section_name, ".dynstr") == 0) {
|
||||
// Found
|
||||
elf_strtab_p = file_map + header.sh_offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (elf_strtab_p == NULL) {
|
||||
WARN("Unable To Find String Table In: %s", source);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Locate Symbol Tables
|
||||
Elf32_Sym *symbol = NULL;
|
||||
for (int i = 0; i < elf_section_header_count; ++i) {
|
||||
// Exit Loop If Finished
|
||||
if (symbol != NULL) {
|
||||
break;
|
||||
}
|
||||
// Get Section Header
|
||||
Elf32_Shdr header = elf_section_headers[i];
|
||||
// Check Section Type
|
||||
if (header.sh_type == SHT_DYNSYM) {
|
||||
// Symbol Table
|
||||
Elf32_Sym *table = (Elf32_Sym *) (file_map + header.sh_offset);
|
||||
for (int j = 0; (j * sizeof (Elf32_Sym)) < header.sh_size; j++) {
|
||||
// Check Symbol Name
|
||||
char *symbol_name = (char *) (elf_strtab_p + table[j].st_name);
|
||||
if (strcmp(symbol_name, name) == 0) {
|
||||
// Found
|
||||
symbol = &table[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check Symbol
|
||||
if (symbol != NULL) {
|
||||
// Convert Virtual Address To File Offset
|
||||
Elf32_Shdr symbol_section_header = elf_section_headers[symbol->st_shndx];
|
||||
int vaddr_to_offset = -symbol_section_header.sh_addr + symbol_section_header.sh_offset;
|
||||
Elf32_Off symbol_offset = symbol->st_value + vaddr_to_offset;
|
||||
// Access Symbol
|
||||
unsigned char *value = file_map + symbol_offset;
|
||||
uint32_t size = symbol->st_size;
|
||||
callback(value, size);
|
||||
} else {
|
||||
// Unable To Find Symbol
|
||||
WARN("Unable To Find Symbol: %s", name);
|
||||
}
|
||||
static std::unique_ptr<LIEF::ELF::Binary> binary = NULL;
|
||||
if (binary == NULL) {
|
||||
binary = LIEF::ELF::Parser::parse(source);
|
||||
}
|
||||
|
||||
end:
|
||||
// Unmap And Close File
|
||||
if (file_map != NULL) {
|
||||
munmap(file_map, file_size);
|
||||
}
|
||||
if (file_obj != NULL) {
|
||||
fclose(file_obj);
|
||||
const LIEF::ELF::Symbol *symbol = binary->get_dynamic_symbol(name);
|
||||
if (symbol != NULL) {
|
||||
std::vector<uint8_t> data = binary->get_content_from_virtual_address(symbol->value(), symbol->size(), LIEF::Binary::VA_TYPES::VA);
|
||||
callback(data.data(), data.size());
|
||||
} else {
|
||||
WARN("Unable To Find Symbol: %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -41,9 +44,6 @@ extern "C" {
|
||||
#define GL_FOG_COLOR 0xb66
|
||||
#define GL_BLEND 0xbe2
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef float GLfloat;
|
||||
typedef float GLclampf;
|
||||
typedef int GLint;
|
||||
@ -107,6 +107,7 @@ void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz);
|
||||
GLboolean glIsEnabled(GLenum cap);
|
||||
void glGetIntegerv(GLenum pname, GLint *data);
|
||||
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data);
|
||||
void glGenBuffers(GLsizei n, GLuint *buffers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -168,6 +168,7 @@ CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) {
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
flush_write_cache();
|
||||
#else
|
||||
GLenum mode = (GLenum) read_int();
|
||||
GLint first = (GLint) read_int();
|
||||
@ -1242,3 +1243,30 @@ CALL(65, glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, G
|
||||
free(pixels);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int((uint32_t) n);
|
||||
|
||||
// Get Return Value
|
||||
for (GLsizei i = 0; i < n; i++) {
|
||||
buffers[i] = (GLuint) read_int();
|
||||
}
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
GLsizei n = (GLsizei) read_int();
|
||||
GLuint buffers[n];
|
||||
// Run
|
||||
glGenBuffers(n, buffers);
|
||||
// Return Value
|
||||
for (GLsizei i = 0; i < n; i++) {
|
||||
write_int((uint32_t) buffers[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -45,6 +45,9 @@ static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
|
||||
// Main
|
||||
int main(int argc, char *argv[]) {
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = PROXY_LOG_TAG;
|
||||
|
||||
// Install Signal Handlers
|
||||
signal(SIGINT, SIG_IGN);
|
||||
struct sigaction act_sigterm;
|
||||
|
@ -22,7 +22,7 @@ extern "C" {
|
||||
|
||||
#define CONNECTED_MSG "Connected"
|
||||
|
||||
#define PROXY_INFO(format, ...) DEBUG(PROXY_LOG_TAG format, ##__VA_ARGS__);
|
||||
#define PROXY_INFO(format, ...) RAW_DEBUG(PROXY_LOG_TAG, format, ##__VA_ARGS__);
|
||||
#define PROXY_ERR(format, ...) { close_connection(); ERR(PROXY_LOG_TAG format, ##__VA_ARGS__); }
|
||||
|
||||
// Safely Send/Receive Data From The Connection
|
||||
|
@ -182,6 +182,7 @@ CALL(8, media_swap_buffers, void, ()) {
|
||||
start_proxy_call();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
flush_write_cache();
|
||||
#else
|
||||
// Run
|
||||
media_swap_buffers();
|
||||
|
@ -64,6 +64,9 @@ static void start_media_layer_proxy_client(int read, int write) {
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = CHILD_PROCESS_TAG;
|
||||
|
||||
// Prepare Arguments
|
||||
char *read_str = NULL;
|
||||
safe_asprintf(&read_str, "%i", read);
|
||||
@ -164,6 +167,4 @@ void _start_proxy_call(unsigned char call_id) {
|
||||
write_byte(call_id);
|
||||
}
|
||||
void end_proxy_call() {
|
||||
// Flush Write Cache
|
||||
flush_write_cache();
|
||||
}
|
||||
|
@ -77,6 +77,9 @@ else()
|
||||
add_library(atlas SHARED src/atlas/atlas.cpp)
|
||||
target_link_libraries(atlas mods-headers reborn-patch symbols feature media-layer-core)
|
||||
|
||||
add_library(title-screen SHARED src/title-screen/title-screen.cpp)
|
||||
target_link_libraries(title-screen mods-headers reborn-patch symbols feature compat)
|
||||
|
||||
add_library(benchmark SHARED src/benchmark/benchmark.cpp)
|
||||
target_link_libraries(benchmark mods-headers reborn-patch symbols compat misc media-layer-core)
|
||||
endif()
|
||||
@ -112,7 +115,7 @@ target_link_libraries(init mods-headers reborn-util compat game-mode misc death
|
||||
if(MCPI_SERVER_MODE)
|
||||
target_link_libraries(init server)
|
||||
else()
|
||||
target_link_libraries(init multiplayer sound camera input sign touch textures atlas benchmark)
|
||||
target_link_libraries(init multiplayer sound camera input sign touch textures atlas title-screen benchmark)
|
||||
endif()
|
||||
|
||||
## Install Mods
|
||||
@ -120,7 +123,7 @@ set(MODS_TO_INSTALL init compat readdir feature game-mode misc override death op
|
||||
if(MCPI_SERVER_MODE)
|
||||
list(APPEND MODS_TO_INSTALL server)
|
||||
else()
|
||||
list(APPEND MODS_TO_INSTALL multiplayer sound camera input sign touch textures atlas benchmark)
|
||||
list(APPEND MODS_TO_INSTALL multiplayer sound camera input sign touch textures atlas title-screen benchmark)
|
||||
endif()
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
list(APPEND MODS_TO_INSTALL screenshot)
|
||||
|
@ -16,12 +16,13 @@ void init_multiplayer();
|
||||
void init_sound();
|
||||
void init_input();
|
||||
void init_sign();
|
||||
void init_creative();
|
||||
void init_camera();
|
||||
void init_touch();
|
||||
void init_textures();
|
||||
void init_atlas();
|
||||
void init_title_screen();
|
||||
#endif
|
||||
void init_creative();
|
||||
void init_game_mode();
|
||||
void init_misc();
|
||||
void init_death();
|
||||
|
@ -197,9 +197,9 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
|
||||
|
||||
// Make Liquids Selectable
|
||||
static bool is_holding_bucket = false;
|
||||
static void Mob_pick_Level_clip_injection(unsigned char *level, unsigned char *param_1, unsigned char *param_2, bool param_3, __attribute__((unused)) bool clip_liquids) {
|
||||
static HitResult Mob_pick_Level_clip_injection(unsigned char *level, unsigned char *param_1, unsigned char *param_2, __attribute__((unused)) bool clip_liquids, bool param_3) {
|
||||
// Call Original Method
|
||||
(*Level_clip)(level, param_1, param_2, param_3, is_holding_bucket);
|
||||
return (*Level_clip)(level, param_1, param_2, is_holding_bucket, param_3);
|
||||
}
|
||||
static void handle_tick(unsigned char *minecraft) {
|
||||
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
|
||||
|
@ -104,7 +104,7 @@ int creative_is_restricted() {
|
||||
// Init
|
||||
void init_creative() {
|
||||
// Add Extra Items To Creative Inventory (Only Replace Specific Function Call)
|
||||
if (feature_has("Expand Creative Inventory", server_enabled)) {
|
||||
if (feature_has("Expand Creative Mode Inventory", server_enabled)) {
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
|
||||
#endif
|
||||
@ -120,8 +120,8 @@ void init_creative() {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove Creative Restrictions (Opening Chests, Crafting, Etc)
|
||||
if (feature_has("Remove Creative Mode Restrictions", server_disabled)) {
|
||||
// Remove Creative Mode Restrictions (Opening Chests, Crafting, Etc)
|
||||
if (feature_has("Remove Creative Mode Restrictions", server_enabled)) {
|
||||
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
// Remove Restrictions
|
||||
patch((void *) 0x43ee8, nop_patch);
|
||||
|
@ -70,8 +70,8 @@ void init_game_mode() {
|
||||
_init_game_mode_ui();
|
||||
}
|
||||
|
||||
// Allow Joining Survival Servers
|
||||
if (feature_has("Allow Joining Survival Servers", server_enabled)) {
|
||||
// Allow Joining Survival Mode Servers
|
||||
if (feature_has("Allow Joining Survival Mode Servers", server_enabled)) {
|
||||
unsigned char server_patch[4] = {0x0f, 0x00, 0x00, 0xea}; // "b 0x6dcb4"
|
||||
patch((void *) 0x6dc70, server_patch);
|
||||
}
|
||||
|
@ -16,12 +16,13 @@ __attribute__((constructor)) static void init() {
|
||||
init_sound();
|
||||
init_input();
|
||||
init_sign();
|
||||
init_creative();
|
||||
init_camera();
|
||||
init_touch();
|
||||
init_textures();
|
||||
init_atlas();
|
||||
init_title_screen();
|
||||
#endif
|
||||
init_creative();
|
||||
init_game_mode();
|
||||
init_misc();
|
||||
init_death();
|
||||
|
@ -22,8 +22,8 @@ static int32_t MouseBuildInput_tickBuild_injection(unsigned char *mouse_build_in
|
||||
if (ret != 0 && is_left_click == 1 && *build_action_intention_return == 0xa) {
|
||||
// Get Target HitResult
|
||||
unsigned char *minecraft = *(unsigned char **) (local_player + LocalPlayer_minecraft_property_offset);
|
||||
unsigned char *hit_result = minecraft + Minecraft_hit_result_property_offset;
|
||||
int32_t hit_result_type = *(int32_t *) (hit_result + HitResult_type_property_offset);
|
||||
HitResult *hit_result = (HitResult *) (minecraft + Minecraft_hit_result_property_offset);
|
||||
int32_t hit_result_type = hit_result->type;
|
||||
// Check if The Target Is An Entity Using HitResult
|
||||
if (hit_result_type == 1) {
|
||||
// Change BuildActionIntention To Attack/Place Mode (Place Will Not Happen Because The HitResult Is An Entity)
|
||||
|
@ -42,32 +42,58 @@ static void _handle_toggle_options(unsigned char *minecraft) {
|
||||
}
|
||||
|
||||
// Font-Facing View
|
||||
static void invert_rotation(unsigned char *entity) {
|
||||
if (entity != NULL) {
|
||||
*(float *) (entity + Entity_yaw_property_offset) = 180.f + (*(float *) (entity + Entity_yaw_property_offset));
|
||||
*(float *) (entity + Entity_old_yaw_property_offset) = 180.f + (*(float *) (entity + Entity_old_yaw_property_offset));
|
||||
*(float *) (entity + Entity_pitch_property_offset) = -(*(float *) (entity + Entity_pitch_property_offset));
|
||||
*(float *) (entity + Entity_old_pitch_property_offset) = -(*(float *) (entity + Entity_old_pitch_property_offset));
|
||||
}
|
||||
}
|
||||
static void revert_rotation(unsigned char *entity) {
|
||||
if (entity != NULL) {
|
||||
*(float *) (entity + Entity_yaw_property_offset) = -180.f + (*(float *) (entity + Entity_yaw_property_offset));
|
||||
*(float *) (entity + Entity_old_yaw_property_offset) = -180.f + (*(float *) (entity + Entity_old_yaw_property_offset));
|
||||
*(float *) (entity + Entity_pitch_property_offset) = -(*(float *) (entity + Entity_pitch_property_offset));
|
||||
*(float *) (entity + Entity_old_pitch_property_offset) = -(*(float *) (entity + Entity_old_pitch_property_offset));
|
||||
}
|
||||
}
|
||||
static int is_front_facing = 0;
|
||||
static unsigned char *stored_player = NULL;
|
||||
static void GameRenderer_setupCamera_injection(unsigned char *game_renderer, float param_1, int param_2) {
|
||||
// Get Objects
|
||||
unsigned char *minecraft = *(unsigned char **) (game_renderer + GameRenderer_minecraft_property_offset);
|
||||
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
|
||||
stored_player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
|
||||
|
||||
// Check If In Third-Person
|
||||
unsigned char *options = minecraft + Minecraft_options_property_offset;
|
||||
int is_font_facing = (*(options + Options_third_person_property_offset) == 2);
|
||||
is_front_facing = (*(options + Options_third_person_property_offset) == 2);
|
||||
|
||||
// Invert Rotation
|
||||
if (is_font_facing && player != NULL) {
|
||||
*(float *) (player + Entity_yaw_property_offset) = 180.f + (*(float *) (player + Entity_yaw_property_offset));
|
||||
*(float *) (player + Entity_old_yaw_property_offset) = 180.f + (*(float *) (player + Entity_old_yaw_property_offset));
|
||||
*(float *) (player + Entity_pitch_property_offset) = -(*(float *) (player + Entity_pitch_property_offset));
|
||||
*(float *) (player + Entity_old_pitch_property_offset) = -(*(float *) (player + Entity_old_pitch_property_offset));
|
||||
if (is_front_facing) {
|
||||
invert_rotation(stored_player);
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
(*GameRenderer_setupCamera)(game_renderer, param_1, param_2);
|
||||
|
||||
// Revert
|
||||
if (is_font_facing && player != NULL) {
|
||||
*(float *) (player + Entity_yaw_property_offset) = -180.f + (*(float *) (player + Entity_yaw_property_offset));
|
||||
*(float *) (player + Entity_old_yaw_property_offset) = -180.f + (*(float *) (player + Entity_old_yaw_property_offset));
|
||||
*(float *) (player + Entity_pitch_property_offset) = -(*(float *) (player + Entity_pitch_property_offset));
|
||||
*(float *) (player + Entity_old_pitch_property_offset) = -(*(float *) (player + Entity_old_pitch_property_offset));
|
||||
if (is_front_facing) {
|
||||
revert_rotation(stored_player);
|
||||
}
|
||||
}
|
||||
static void ParticleEngine_render_injection(unsigned char *particle_engine, unsigned char *entity, float param_2) {
|
||||
// Invert Rotation
|
||||
if (is_front_facing && stored_player == entity) {
|
||||
invert_rotation(stored_player);
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
(*ParticleEngine_render)(particle_engine, entity, param_2);
|
||||
|
||||
// Revert
|
||||
if (is_front_facing && stored_player == entity) {
|
||||
revert_rotation(stored_player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,5 +105,6 @@ void _init_toggle() {
|
||||
// Font-Facing View
|
||||
if (enable_toggles) {
|
||||
overwrite_calls((void *) GameRenderer_setupCamera, (void *) GameRenderer_setupCamera_injection);
|
||||
overwrite_calls((void *) ParticleEngine_render, (void *) ParticleEngine_render_injection);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
@ -297,6 +299,37 @@ int32_t misc_get_real_selected_slot(unsigned char *player) {
|
||||
return selected_slot;
|
||||
}
|
||||
|
||||
// Properly Generate Buffers
|
||||
static void anGenBuffers_injection(int32_t count, uint32_t *buffers) {
|
||||
glGenBuffers(count, buffers);
|
||||
}
|
||||
|
||||
// Fix Graphics Bug When Switching To First-Person While Sneaking
|
||||
static void HumanoidMobRenderer_render_injection(unsigned char *model_renderer, unsigned char *entity, float param_2, float param_3, float param_4, float param_5, float param_6) {
|
||||
(*HumanoidMobRenderer_render)(model_renderer, entity, param_2, param_3, param_4, param_5, param_6);
|
||||
unsigned char *model = *(unsigned char **) (model_renderer + HumanoidMobRenderer_model_property_offset);
|
||||
*(bool *) (model + HumanoidModel_is_sneaking_property_offset) = 0;
|
||||
}
|
||||
|
||||
// Custom API Port
|
||||
HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) {
|
||||
const struct sockaddr *new_addr = addr;
|
||||
struct sockaddr_in in_addr;
|
||||
if (addr->sa_family == AF_INET) {
|
||||
in_addr = *(const struct sockaddr_in *) new_addr;
|
||||
if (in_addr.sin_port == ntohs(4711)) {
|
||||
const char *new_port_str = getenv("MCPI_API_PORT");
|
||||
long int new_port;
|
||||
if (new_port_str != NULL && (new_port = strtol(new_port_str, NULL, 0)) != 0L) {
|
||||
in_addr.sin_port = htons(new_port);
|
||||
}
|
||||
}
|
||||
new_addr = (const struct sockaddr *) &in_addr;
|
||||
}
|
||||
ensure_bind();
|
||||
return (*real_bind)(sockfd, new_addr, addrlen);
|
||||
}
|
||||
|
||||
// Init
|
||||
static void nop() {
|
||||
}
|
||||
@ -379,6 +412,24 @@ void init_misc() {
|
||||
overwrite_calls((void *) sleepMs, (void *) nop);
|
||||
}
|
||||
|
||||
// Properly Generate Buffers
|
||||
overwrite((void *) anGenBuffers, (void *) anGenBuffers_injection);
|
||||
|
||||
// Fix Graphics Bug When Switching To First-Person While Sneaking
|
||||
patch_address(PlayerRenderer_render_vtable_addr, (void *) HumanoidMobRenderer_render_injection);
|
||||
|
||||
// Disable Speed Bridging
|
||||
if (feature_has("Disable Speed Bridging", server_disabled)) {
|
||||
unsigned char disable_speed_bridging_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
|
||||
patch((void *) 0x494b4, disable_speed_bridging_patch);
|
||||
}
|
||||
|
||||
// Disable Creative Mode Mining Delay
|
||||
if (feature_has("Disable Creative Mode Mining Delay", server_disabled)) {
|
||||
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
patch((void *) 0x19fa0, nop_patch);
|
||||
}
|
||||
|
||||
// Init C++ And Logging
|
||||
_init_misc_cpp();
|
||||
_init_misc_logging();
|
||||
|
@ -50,15 +50,6 @@ static void PauseScreen_init_injection(unsigned char *screen) {
|
||||
}
|
||||
}
|
||||
|
||||
// Improved Title Background
|
||||
static void StartMenuScreen_render_Screen_renderBackground_injection(unsigned char *screen) {
|
||||
// Draw
|
||||
unsigned char *minecraft = *(unsigned char **) (screen + Screen_minecraft_property_offset);
|
||||
unsigned char *textures = *(unsigned char **) (minecraft + Minecraft_textures_property_offset);
|
||||
(*Textures_loadAndBindTexture)(textures, "gui/titleBG.png");
|
||||
(*GuiComponent_blit)(screen, 0, 0, 0, 0, *(int32_t *) (screen + Screen_width_property_offset), *(int32_t *) (screen + Screen_height_property_offset), 0x100, 0x100);
|
||||
}
|
||||
|
||||
// Init
|
||||
void _init_misc_cpp() {
|
||||
// Implement AppPlatform::readAssetFile So Translations Work
|
||||
@ -71,14 +62,4 @@ void _init_misc_cpp() {
|
||||
// Add Missing Buttons To Pause Menu
|
||||
patch_address(PauseScreen_init_vtable_addr, (void *) PauseScreen_init_injection);
|
||||
}
|
||||
|
||||
// Improved Title Background
|
||||
if (feature_has("Improved Title Background", server_disabled)) {
|
||||
// Switch Background
|
||||
overwrite_call((void *) 0x39528, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
|
||||
overwrite_call((void *) 0x3dee0, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
|
||||
// Text Color
|
||||
patch_address((void *) 0x397ac, (void *) 0xffffffff);
|
||||
patch_address((void *) 0x3e10c, (void *) 0xffffffff);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ __attribute__((destructor)) static void _free_safe_username() {
|
||||
free(safe_username);
|
||||
}
|
||||
|
||||
static int anaglyph;
|
||||
static int render_distance;
|
||||
// Configure Options
|
||||
unsigned char *stored_options = NULL;
|
||||
@ -68,8 +67,6 @@ static void Minecraft_init_injection(unsigned char *minecraft) {
|
||||
unsigned char *options = minecraft + Minecraft_options_property_offset;
|
||||
// Enable Crosshair In Touch GUI
|
||||
*(options + Options_split_controls_property_offset) = 1;
|
||||
// 3D Anaglyph
|
||||
*(options + Options_3d_anaglyph_property_offset) = anaglyph;
|
||||
// Render Distance
|
||||
*(int32_t *) (options + Options_render_distance_property_offset) = render_distance;
|
||||
}
|
||||
@ -90,8 +87,6 @@ void init_options() {
|
||||
overwrite((void *) LevelData_getSpawnMobs, (void *) LevelData_getSpawnMobs_injection);
|
||||
}
|
||||
|
||||
// 3D Anaglyph
|
||||
anaglyph = feature_has("3D Anaglyph", server_disabled);
|
||||
// Render Distance
|
||||
render_distance = get_render_distance();
|
||||
DEBUG("Setting Render Distance: %i", render_distance);
|
||||
|
@ -33,6 +33,9 @@ static void Options_save_Options_addOptionToSaveOutput_injection(unsigned char *
|
||||
// Save Fancy Graphics
|
||||
(*Options_addOptionToSaveOutput)(options, data, "gfx_fancygraphics", *(options + Options_fancy_graphics_property_offset));
|
||||
|
||||
// Save 3D Anaglyph
|
||||
(*Options_addOptionToSaveOutput)(options, data, "gfx_anaglyph", *(options + Options_3d_anaglyph_property_offset));
|
||||
|
||||
// Save File
|
||||
unsigned char *options_file = options + Options_options_file_property_offset;
|
||||
(*OptionsFile_save)(options_file, data);
|
||||
@ -117,6 +120,11 @@ static void OptionsPane_unknown_toggle_creating_function_injection(unsigned char
|
||||
|
||||
// Call Original Method
|
||||
(*OptionsPane_unknown_toggle_creating_function)(options_pane, group_id, new_name, option);
|
||||
|
||||
// Add 3D Anaglyph
|
||||
if (option == Options_Option_GRAPHICS) {
|
||||
(*OptionsPane_unknown_toggle_creating_function)(options_pane, group_id, "3D Anaglyph", Options_Option_ANAGLYPH);
|
||||
}
|
||||
}
|
||||
|
||||
// Add Missing Options To Options::getBooleanValue
|
||||
@ -130,19 +138,6 @@ static bool Options_getBooleanValue_injection(unsigned char *options, unsigned c
|
||||
}
|
||||
}
|
||||
|
||||
// Add Options Button Back To Classic Start Screen
|
||||
static void StartMenuScreen_init_injection(unsigned char *screen) {
|
||||
// Call Original Method
|
||||
(*StartMenuScreen_init)(screen);
|
||||
|
||||
// Add Button
|
||||
std::vector<unsigned char *> *rendered_buttons = (std::vector<unsigned char *> *) (screen + Screen_rendered_buttons_property_offset);
|
||||
std::vector<unsigned char *> *selectable_buttons = (std::vector<unsigned char *> *) (screen + Screen_selectable_buttons_property_offset);
|
||||
unsigned char *options_button = screen + StartMenuScreen_options_button_property_offset;
|
||||
rendered_buttons->push_back(options_button);
|
||||
selectable_buttons->push_back(options_button);
|
||||
}
|
||||
|
||||
// Init C++
|
||||
void _init_options_cpp() {
|
||||
// NOP
|
||||
@ -167,26 +162,6 @@ void _init_options_cpp() {
|
||||
|
||||
// Add Missing Options To Options::getBooleanValue
|
||||
overwrite_calls((void *) Options_getBooleanValue, (void *) Options_getBooleanValue_injection);
|
||||
|
||||
// Add Options Button Back To Classic Start Screen
|
||||
patch_address(StartMenuScreen_init_vtable_addr, (void *) StartMenuScreen_init_injection);
|
||||
// Fix Classic UI Options Button Size
|
||||
unsigned char classic_options_button_width_patch[4] = {0xa0, 0x00, 0xa0, 0xe3}; // "mov r0, #0xa0"
|
||||
patch((void *) 0x39a98, classic_options_button_width_patch);
|
||||
unsigned char classic_options_button_height_patch[4] = {0x18, 0x30, 0xa0, 0xe3}; // "mov r3, #0x18"
|
||||
patch((void *) 0x39a9c, classic_options_button_height_patch);
|
||||
// Fix Classic UI Buttons Spacing
|
||||
{
|
||||
// Join Button
|
||||
unsigned char classic_join_button_spacing_patch[4] = {0x12, 0x20, 0x83, 0xe2}; // "add r2, r3, #0x12"
|
||||
patch((void *) 0x39894, classic_join_button_spacing_patch);
|
||||
// Start Button
|
||||
unsigned char classic_start_button_spacing_patch[4] = {0x08, 0x20, 0x43, 0xe2}; // "sub r2, r3, #0x08"
|
||||
patch((void *) 0x3988c, classic_start_button_spacing_patch);
|
||||
// Options Button
|
||||
unsigned char classic_options_button_spacing_patch[4] = {0x2c, 0x30, 0x83, 0xe2}; // "add r3, r3, #0x2c"
|
||||
patch((void *) 0x39898, classic_options_button_spacing_patch);
|
||||
}
|
||||
}
|
||||
|
||||
// Actually Save options.txt
|
||||
@ -213,18 +188,27 @@ void _init_options_cpp() {
|
||||
// Replace "feedback_vibration" Loading/Saving With "gfx_ao"
|
||||
{
|
||||
// Replace String
|
||||
static const char *new_feedback_vibration_options_txt_nam = "gfx_ao";
|
||||
patch_address((void *) feedback_vibration_options_txt_name_1, (void *) &new_feedback_vibration_options_txt_nam);
|
||||
patch_address((void *) feedback_vibration_options_txt_name_2, (void *) &new_feedback_vibration_options_txt_nam);
|
||||
static const char *new_feedback_vibration_options_txt_name = "gfx_ao";
|
||||
patch_address((void *) feedback_vibration_options_txt_name_1, (void *) &new_feedback_vibration_options_txt_name);
|
||||
patch_address((void *) feedback_vibration_options_txt_name_2, (void *) &new_feedback_vibration_options_txt_name);
|
||||
// Loading
|
||||
unsigned char gfx_ao_loading_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x10, 0x84, 0xe2}; // "add param_2, r4, #OFFSET"
|
||||
unsigned char gfx_ao_loading_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET"
|
||||
patch((void *) 0x193b8, gfx_ao_loading_patch);
|
||||
// Saving
|
||||
unsigned char gfx_ao_saving_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x30, 0xd4, 0xe5}; // "ldrb r3, [r4, #OFFSET]"
|
||||
patch((void *) 0x197f8, gfx_ao_saving_patch);
|
||||
}
|
||||
|
||||
// Disable "gfx_lowquality" Loading
|
||||
patch((void *) 0x19414, nop_patch);
|
||||
patch((void *) 0x1941c, nop_patch);
|
||||
// Replace "gfx_lowquality" Loading With "gfx_anaglyph"
|
||||
{
|
||||
// Replace String
|
||||
static const char *new_gfx_lowquality_options_txt_name = "gfx_anaglyph";
|
||||
patch_address((void *) gfx_lowquality_options_txt_name, (void *) &new_gfx_lowquality_options_txt_name);
|
||||
// Loading
|
||||
unsigned char gfx_anaglyph_loading_patch[4] = {(unsigned char) Options_3d_anaglyph_property_offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET"
|
||||
patch((void *) 0x19400, gfx_anaglyph_loading_patch);
|
||||
// Disable Loading Side Effects
|
||||
patch((void *) 0x19414, nop_patch);
|
||||
patch((void *) 0x1941c, nop_patch);
|
||||
}
|
||||
}
|
||||
|
@ -503,6 +503,7 @@ static unsigned char get_max_players() {
|
||||
return (unsigned char) val;
|
||||
}
|
||||
|
||||
// Real Init Server
|
||||
static void server_init() {
|
||||
// Open Properties File
|
||||
std::string file(home_get());
|
||||
|
2
mods/src/title-screen/README.md
Normal file
2
mods/src/title-screen/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# ``title-screen`` Mod
|
||||
This mod improves the title screen.
|
86
mods/src/title-screen/title-screen.cpp
Normal file
86
mods/src/title-screen/title-screen.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/feature/feature.h>
|
||||
#include <mods/init/init.h>
|
||||
#include <mods/compat/compat.h>
|
||||
|
||||
// Improved Title Screen Background
|
||||
static void StartMenuScreen_render_Screen_renderBackground_injection(unsigned char *screen) {
|
||||
// Draw
|
||||
unsigned char *minecraft = *(unsigned char **) (screen + Screen_minecraft_property_offset);
|
||||
unsigned char *textures = *(unsigned char **) (minecraft + Minecraft_textures_property_offset);
|
||||
(*Textures_loadAndBindTexture)(textures, "gui/titleBG.png");
|
||||
(*GuiComponent_blit)(screen, 0, 0, 0, 0, *(int32_t *) (screen + Screen_width_property_offset), *(int32_t *) (screen + Screen_height_property_offset), 0x100, 0x100);
|
||||
}
|
||||
|
||||
// Add Buttons Back To Classic Start Screen
|
||||
static void StartMenuScreen_init_injection(unsigned char *screen) {
|
||||
// Call Original Method
|
||||
(*StartMenuScreen_init)(screen);
|
||||
|
||||
// Add Button
|
||||
std::vector<unsigned char *> *rendered_buttons = (std::vector<unsigned char *> *) (screen + Screen_rendered_buttons_property_offset);
|
||||
std::vector<unsigned char *> *selectable_buttons = (std::vector<unsigned char *> *) (screen + Screen_selectable_buttons_property_offset);
|
||||
unsigned char *options_button = screen + StartMenuScreen_options_button_property_offset;
|
||||
rendered_buttons->push_back(options_button);
|
||||
selectable_buttons->push_back(options_button);
|
||||
unsigned char *create_button = screen + StartMenuScreen_create_button_property_offset; // Repurpose Unused "Create" Button As Quit Button
|
||||
rendered_buttons->push_back(create_button);
|
||||
selectable_buttons->push_back(create_button);
|
||||
}
|
||||
|
||||
// Add Functionality To Quit Button
|
||||
static void StartMenuScreen_buttonClicked_injection(unsigned char *screen, unsigned char *button) {
|
||||
unsigned char *quit_button = screen + StartMenuScreen_create_button_property_offset;
|
||||
if (button == quit_button) {
|
||||
// Quit
|
||||
compat_request_exit();
|
||||
} else {
|
||||
// Call Original Method
|
||||
(*StartMenuScreen_buttonClicked)(screen, button);
|
||||
}
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_title_screen() {
|
||||
// Improved Title Screen Background
|
||||
if (feature_has("Add Title Screen Background", server_disabled)) {
|
||||
// Switch Background
|
||||
overwrite_call((void *) 0x39528, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
|
||||
overwrite_call((void *) 0x3dee0, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
|
||||
// Text Color
|
||||
patch_address((void *) 0x397ac, (void *) 0xffffffff);
|
||||
patch_address((void *) 0x3e10c, (void *) 0xffffffff);
|
||||
}
|
||||
|
||||
// Improved Classic Title Screen
|
||||
if (feature_has("Improved Classic Title Screen", server_disabled)) {
|
||||
// Add Options Button Back To Classic Start Screen
|
||||
patch_address(StartMenuScreen_init_vtable_addr, (void *) StartMenuScreen_init_injection);
|
||||
|
||||
// Fix Classic UI Button Size
|
||||
unsigned char classic_button_height_patch[4] = {0x18, 0x30, 0xa0, 0xe3}; // "mov r3, #0x18"
|
||||
patch((void *) 0x39a9c, classic_button_height_patch);
|
||||
patch((void *) 0x39ae0, classic_button_height_patch);
|
||||
|
||||
// Fix Classic UI Buttons Spacing
|
||||
{
|
||||
// Join Button
|
||||
unsigned char classic_join_button_spacing_patch[4] = {0x12, 0x20, 0x83, 0xe2}; // "add r2, r3, #0x12"
|
||||
patch((void *) 0x39894, classic_join_button_spacing_patch);
|
||||
// Start Button
|
||||
unsigned char classic_start_button_spacing_patch[4] = {0x08, 0x20, 0x43, 0xe2}; // "sub r2, r3, #0x08"
|
||||
patch((void *) 0x3988c, classic_start_button_spacing_patch);
|
||||
// Options Button
|
||||
unsigned char classic_options_button_spacing_patch[4] = {0x2c, 0x30, 0x83, 0xe2}; // "add r3, r3, #0x2c"
|
||||
patch((void *) 0x39898, classic_options_button_spacing_patch);
|
||||
}
|
||||
|
||||
// Rename "Create" Button To "Quit"
|
||||
patch_address((void *) classic_create_button_text, (void *) "Quit");
|
||||
|
||||
// Add Functionality To Quit Button
|
||||
patch_address(StartMenuScreen_buttonClicked_vtable_addr, (void *) StartMenuScreen_buttonClicked_injection);
|
||||
}
|
||||
}
|
@ -87,9 +87,4 @@ void init_touch() {
|
||||
int block_outlines = feature_has("Show Block Outlines", server_disabled);
|
||||
unsigned char outline_patch[4] = {(unsigned char) (block_outlines ? !touch_gui : touch_gui), 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" or "cmp r0, #0x0"
|
||||
patch((void *) 0x4a210, outline_patch);
|
||||
if (block_outlines) {
|
||||
// Disable Broken Touchscreen-Specific Block Outline Behavior
|
||||
unsigned char block_highlight_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
|
||||
patch((void *) 0x494b4, block_highlight_patch);
|
||||
}
|
||||
}
|
||||
|
@ -31,4 +31,4 @@ export _MCPI_SKIP_ROOT_CHECK=1
|
||||
|
||||
# Run Benchmark
|
||||
export HOME="$(pwd)/build/test"
|
||||
minecraft-pi-reborn-client --default --benchmark
|
||||
minecraft-pi-reborn-client --default --no-cache --benchmark
|
||||
|
@ -21,6 +21,9 @@ static sleepMs_t sleepMs = (sleepMs_t) 0x13cf4;
|
||||
typedef int32_t (*sdl_key_to_minecraft_key_t)(int32_t sdl_key);
|
||||
static sdl_key_to_minecraft_key_t sdl_key_to_minecraft_key = (sdl_key_to_minecraft_key_t) 0x1243c;
|
||||
|
||||
typedef void (*anGenBuffers_t)(int32_t count, uint32_t *buffers);
|
||||
static anGenBuffers_t anGenBuffers = (anGenBuffers_t) 0x5f28c;
|
||||
|
||||
static char **default_path = (char **) 0xe264; // /.minecraft/
|
||||
static char **default_username = (char **) 0x18fd4; // StevePi
|
||||
static char **minecraft_pi_version = (char **) 0x39d94; // v0.1.1 alpha
|
||||
@ -28,6 +31,8 @@ static char **options_txt_path = (char **) 0x19bc8; // options.txt
|
||||
static char **options_txt_fopen_mode_when_loading = (char **) 0x19d24; // w
|
||||
static char ***feedback_vibration_options_txt_name_1 = (char ***) 0x198a0; // feedback_vibration
|
||||
static char ***feedback_vibration_options_txt_name_2 = (char ***) 0x194bc; // feedback_vibration
|
||||
static char ***gfx_lowquality_options_txt_name = (char ***) 0x194c4; // gfx_lowquality
|
||||
static char **classic_create_button_text = (char **) 0x39bec; // Create
|
||||
|
||||
static unsigned char **Material_stone = (unsigned char **) 0x180a9c; // Material
|
||||
|
||||
@ -65,6 +70,7 @@ static float *InvGuiScale = (float *) 0x135d98;
|
||||
|
||||
static unsigned char *Options_Option_GRAPHICS = (unsigned char *) 0x136c2c; // Option
|
||||
static unsigned char *Options_Option_AMBIENT_OCCLUSION = (unsigned char *) 0x136c38; // Option
|
||||
static unsigned char *Options_Option_ANAGLYPH = (unsigned char *) 0x136c08; // Option
|
||||
|
||||
static bool *Minecraft_useAmbientOcclusion = (bool *) 0x136b90;
|
||||
|
||||
@ -220,6 +226,11 @@ static GameRenderer_setupCamera_t GameRenderer_setupCamera = (GameRenderer_setup
|
||||
|
||||
static uint32_t GameRenderer_minecraft_property_offset = 0x4; // Minecraft *
|
||||
|
||||
// ParticleEngine
|
||||
|
||||
typedef void (*ParticleEngine_render_t)(unsigned char *particle_engine, unsigned char *entity, float param_2);
|
||||
static ParticleEngine_render_t ParticleEngine_render = (ParticleEngine_render_t) 0x43060;
|
||||
|
||||
// Mouse
|
||||
|
||||
typedef int (*Mouse_get_t)();
|
||||
@ -261,9 +272,26 @@ static uint32_t StartGamePacket_game_mode_property_offset = 0x14; // int32_t
|
||||
|
||||
static uint32_t ChatPacket_message_property_offset = 0xc; // char *
|
||||
|
||||
// Vec3
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} Vec3;
|
||||
|
||||
// HitResult
|
||||
|
||||
static uint32_t HitResult_type_property_offset = 0x0;
|
||||
typedef struct {
|
||||
int32_t type;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t z;
|
||||
int32_t side;
|
||||
Vec3 exact;
|
||||
unsigned char *entity;
|
||||
unsigned char unknown;
|
||||
} HitResult;
|
||||
|
||||
// Options
|
||||
|
||||
@ -470,7 +498,7 @@ static Level_getTile_t Level_getTile = (Level_getTile_t) 0xa3380;
|
||||
typedef unsigned char *(*Level_getMaterial_t)(unsigned char *level, int32_t x, int32_t y, int32_t z);
|
||||
static Level_getMaterial_t Level_getMaterial = (Level_getMaterial_t) 0xa27f8;
|
||||
|
||||
typedef void (*Level_clip_t)(unsigned char *level, unsigned char *param_1, unsigned char *param_2, bool param_3, bool clip_liquids);
|
||||
typedef HitResult (*Level_clip_t)(unsigned char *level, unsigned char *param_1, unsigned char *param_2, bool clip_liquids, bool param_3);
|
||||
static Level_clip_t Level_clip = (Level_clip_t) 0xa3db0;
|
||||
|
||||
static uint32_t Level_players_property_offset = 0x60; // std::vector<ServerPlayer *>
|
||||
@ -552,6 +580,8 @@ static Screen_render_t Screen_render = (Screen_render_t) 0x28a00;
|
||||
|
||||
typedef int32_t (*Screen_handleBackEvent_t)(unsigned char *screen, bool param_1);
|
||||
|
||||
typedef void (*Screen_buttonClicked_t)(unsigned char *screen, unsigned char *button);
|
||||
|
||||
static uint32_t Screen_minecraft_property_offset = 0x14; // Minecraft *
|
||||
static uint32_t Screen_rendered_buttons_property_offset = 0x18; // std::vector<Button *>
|
||||
static uint32_t Screen_selectable_buttons_property_offset = 0x30; // std::vector<Button *>
|
||||
@ -574,7 +604,11 @@ static uint32_t Button_y_property_offset = 0x10; // int32_t
|
||||
static Screen_init_t StartMenuScreen_init = (Screen_init_t) 0x39cc0;
|
||||
static void *StartMenuScreen_init_vtable_addr = (void *) 0x105194;
|
||||
|
||||
static Screen_buttonClicked_t StartMenuScreen_buttonClicked = (Screen_buttonClicked_t) 0x397b0;
|
||||
static void *StartMenuScreen_buttonClicked_vtable_addr = (void *) 0x1051e8;
|
||||
|
||||
static uint32_t StartMenuScreen_options_button_property_offset = 0x98; // Button
|
||||
static uint32_t StartMenuScreen_create_button_property_offset = 0xc0; // Button
|
||||
|
||||
// PauseScreen
|
||||
|
||||
@ -799,6 +833,21 @@ static Recipes_t Recipes = (Recipes_t) 0x9cabc;
|
||||
|
||||
static Recipes_t FurnaceRecipes = (Recipes_t) 0xa0778;
|
||||
|
||||
// HumanoidMobRenderer
|
||||
|
||||
typedef void (*HumanoidMobRenderer_render_t)(unsigned char *model_renderer, unsigned char *entity, float param_2, float param_3, float param_4, float param_5, float param_6);
|
||||
static HumanoidMobRenderer_render_t HumanoidMobRenderer_render = (HumanoidMobRenderer_render_t) 0x62b8c;
|
||||
|
||||
static uint32_t HumanoidMobRenderer_model_property_offset = 0x14; // HumanoidModel *
|
||||
|
||||
// HumanoidModel
|
||||
|
||||
static uint32_t HumanoidModel_is_sneaking_property_offset = 0x236; // bool
|
||||
|
||||
// PlayerRenderer
|
||||
|
||||
static void *PlayerRenderer_render_vtable_addr = (void *) 0x107f08;
|
||||
|
||||
// Method That Require C++ Types
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user