Compare commits

...

16 Commits

Author SHA1 Message Date
8532e7707f 2.4.4
All checks were successful
minecraft-pi-reborn/pipeline/head This commit looks good
2022-09-25 19:53:19 -04:00
703ced337b Use File Locking 2022-09-25 19:35:51 -04:00
bedd5ea53a Replace PatcheLF With LIEF 2022-09-25 15:47:36 -04:00
eb3c5d2e6f Remove Unused File 2022-09-23 17:56:44 -04:00
ab1dbd2996 Update Docs 2022-09-23 17:55:38 -04:00
29bc6faf3d Add Disable Creative Mode Mining Delay 2022-09-23 17:08:26 -04:00
5aae95fd37 Add --wipe-cache 2022-09-23 00:31:42 -04:00
5739c5f999 Add Disable Speed Bridging 2022-09-22 23:59:44 -04:00
34ef2d51aa Small Fixes To The Launcher 2022-09-22 18:08:12 -04:00
f328800ce8 Cache Launcher Configuration 2022-09-22 17:43:21 -04:00
02c73176a5 Fix Particles In Front-Facing View 2022-09-21 23:06:58 -04:00
16ce586e9c Add Quit Button 2022-09-21 20:15:00 -04:00
6378a18494 Add 3D Anaglyph To In-Game Options 2022-09-21 18:40:09 -04:00
6994671c6d Add MCPI_API_PORT 2022-09-21 17:54:40 -04:00
58f329bb4f Bug Fixes 2022-09-21 17:34:19 -04:00
d03a1a96ff Tweaks & Fixes 2022-09-20 18:25:27 -04:00
68 changed files with 903 additions and 523 deletions

6
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -1 +1 @@
2.4.3
2.4.4

View File

@ -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)

View File

@ -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")

View File

@ -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
View 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

@ -0,0 +1 @@
Subproject commit c7b3ce3b2ce6917855a72709f73ef6d00b50e1f7

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -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")

View File

@ -1,4 +0,0 @@
project(launcher-dependencies)
# PatchELF
add_subdirectory(patchelf)

View File

@ -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

View File

@ -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

View File

@ -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[]);

View File

@ -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

View 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));
}
}

View 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();

View File

@ -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);
}

View 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);

View File

@ -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];

View File

@ -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
View 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;
}

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -5,7 +5,6 @@
#include <sys/mman.h>
#include <stdint.h>
#include <errno.h>
#include <elf.h>
#include <libreborn/libreborn.h>

View File

@ -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
View File

@ -0,0 +1,4 @@
#include <libreborn/log.h>
// Debug Tag
const char *reborn_debug_tag = "";

View File

@ -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);
}

View File

@ -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()

View File

@ -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

View File

@ -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]);
}
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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();
}

View File

@ -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)

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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();

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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());

View File

@ -0,0 +1,2 @@
# ``title-screen`` Mod
This mod improves the title screen.

View 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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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