Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Bigjango13 | cfce26b3ba | |
Bigjango13 | 7566890c7c | |
Bigjango13 | d7c6771cdd | |
Bigjango13 | e03caceb6d | |
Bigjango13 | 2401fa3a6f | |
Bigjango13 | 0feef96eca | |
Bigjango13 | d9c25f22ad |
|
@ -120,7 +120,7 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||
endif()
|
||||
|
||||
# Install Prebuilt ARMHF Toolchain Sysroot
|
||||
if(BUILD_NATIVE_COMPONENTS AND MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||
if(BUILD_ARM_COMPONENTS AND MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||
install_arm_sysroot()
|
||||
endif()
|
||||
|
||||
|
@ -152,13 +152,13 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||
set(ARM_OPTIONS "${MCPI_OPTIONS}")
|
||||
list(APPEND ARM_OPTIONS "-DMCPI_BUILD_MODE:STRING=arm")
|
||||
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_MESSAGE:STRING=NEVER")
|
||||
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>")
|
||||
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>/install")
|
||||
if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${MCPI_CMAKE_TOOLCHAIN_FILE}")
|
||||
list(APPEND ARM_OPTIONS "-DMCPI_USE_PREBUILT_ARMHF_TOOLCHAIN:BOOL=TRUE")
|
||||
endif()
|
||||
list(APPEND ARM_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}")
|
||||
# Build
|
||||
|
@ -166,9 +166,7 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||
DOWNLOAD_COMMAND ""
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
CMAKE_CACHE_ARGS ${ARM_OPTIONS}
|
||||
INSTALL_COMMAND
|
||||
"${CMAKE_COMMAND}" "-E"
|
||||
"rm" "-rf" "<INSTALL_DIR>/${MCPI_INSTALL_DIR}"
|
||||
INSTALL_COMMAND "${CMAKE_COMMAND}" "-E" "rm" "-rf" "<INSTALL_DIR>/install"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" "-E" "env"
|
||||
"DESTDIR="
|
||||
|
@ -180,5 +178,5 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||
)
|
||||
# Install
|
||||
ExternalProject_Get_Property(arm-components INSTALL_DIR)
|
||||
install(DIRECTORY "${INSTALL_DIR}/${MCPI_INSTALL_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
install(DIRECTORY "${INSTALL_DIR}/install/${MCPI_INSTALL_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
endif()
|
||||
|
|
|
@ -19,3 +19,11 @@ function(mcpi_option name description type default)
|
|||
list(APPEND MCPI_OPTIONS "-D${full_name}:${type}=${${full_name}}")
|
||||
set(MCPI_OPTIONS "${MCPI_OPTIONS}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Prebuilt ARMHF Toolchain
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
mcpi_option(USE_PREBUILT_ARMHF_TOOLCHAIN "Whether To Use A Prebuilt ARMHF Toolchain For Building ARM Components" BOOL FALSE)
|
||||
if(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/prebuilt-armhf-toolchain.cmake")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -16,38 +16,25 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||
if(NOT IS_ARM_TARGETING)
|
||||
set(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN TRUE)
|
||||
endif()
|
||||
if(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/prebuilt-armhf-toolchain.cmake")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Media Layer
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_PROXY FALSE)
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE TRUE)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_PROXY TRUE)
|
||||
endif()
|
||||
mcpi_option(USE_MEDIA_LAYER_TRAMPOLINE "Whether To Enable The Media Layer Trampoline (Requires QEMU)" BOOL "${DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE}")
|
||||
mcpi_option(USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" BOOL "${DEFAULT_USE_MEDIA_LAYER_PROXY}")
|
||||
mcpi_option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" BOOL TRUE)
|
||||
else()
|
||||
set(MCPI_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
|
||||
set(MCPI_USE_MEDIA_LAYER_PROXY FALSE)
|
||||
endif()
|
||||
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
set(BUILD_MEDIA_LAYER_CORE "${BUILD_NATIVE_COMPONENTS}")
|
||||
else()
|
||||
set(BUILD_MEDIA_LAYER_CORE "${BUILD_ARM_COMPONENTS}")
|
||||
endif()
|
||||
|
||||
# QEMU
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists("__ARM_ARCH" "" MCPI_IS_ARM32_OR_ARM64_TARGETING)
|
||||
set(MCPI_USE_QEMU TRUE)
|
||||
if(MCPI_IS_ARM32_OR_ARM64_TARGETING AND NOT MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
|
||||
set(MCPI_USE_QEMU FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Specify Variant Name
|
||||
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
|
||||
if(MCPI_SERVER_MODE)
|
||||
|
@ -63,7 +50,7 @@ if(MCPI_SERVER_MODE)
|
|||
else()
|
||||
string(APPEND DEFAULT_APP_ID "Client")
|
||||
endif()
|
||||
mcpi_option(APP_ID "App ID" STRING "${DEFAULT_APP_ID}")
|
||||
set(MCPI_APP_ID "${DEFAULT_APP_ID}" CACHE STRING "App ID")
|
||||
|
||||
# App Title
|
||||
mcpi_option(APP_BASE_TITLE "Base App Title" STRING "Minecraft: Pi Edition: Reborn")
|
||||
|
@ -78,5 +65,12 @@ mcpi_option(APP_TITLE "App Title" STRING "${DEFAULT_APP_TITLE}")
|
|||
# Skin Server
|
||||
mcpi_option(SKIN_SERVER "Skin Server" STRING "https://raw.githubusercontent.com/MCPI-Revival/Skins/data")
|
||||
|
||||
# Discord Invite
|
||||
mcpi_option(DISCORD_INVITE "Discord Invite URL" STRING "https://discord.gg/mcpi-revival-740287937727561779")
|
||||
# QEMU
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists("__ARM_ARCH" "" MCPI_IS_ARM32_OR_ARM64_TARGETING)
|
||||
set(MCPI_USE_QEMU TRUE)
|
||||
if(MCPI_IS_ARM32_OR_ARM64_TARGETING)
|
||||
set(MCPI_USE_QEMU FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -26,7 +26,7 @@ file(WRITE "${toolchain_dir}/toolchain.cmake"
|
|||
"set(CMAKE_SYSTEM_PROCESSOR \"arm\")\n"
|
||||
"set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n"
|
||||
)
|
||||
set(MCPI_CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" CACHE FILEPATH "" FORCE)
|
||||
|
||||
# Build Sysroot
|
||||
set(sysroot_dir "${CMAKE_CURRENT_BINARY_DIR}/bundled-armhf-sysroot")
|
||||
|
|
|
@ -6,9 +6,9 @@ project(qemu)
|
|||
set(QEMU_VERSION "8.2.1")
|
||||
|
||||
# Flatpak Support
|
||||
set(QEMU_FLATPAK_PATCH "")
|
||||
set(QEMU_PATCH "")
|
||||
if(MCPI_IS_FLATPAK_BUILD)
|
||||
set(QEMU_FLATPAK_PATCH "sed" "-i" "s/libdrm/libdrm-dis/g" "<SOURCE_DIR>/meson.build")
|
||||
set(QEMU_PATCH "sed" "-i" "s/libdrm/libdrm-dis/g" "<SOURCE_DIR>/meson.build")
|
||||
endif()
|
||||
|
||||
# Build
|
||||
|
@ -19,7 +19,6 @@ if(DEFINED ENV{PKG_CONFIG_LIBDIR})
|
|||
endif()
|
||||
ExternalProject_Add(qemu
|
||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/../../archives/qemu-${QEMU_VERSION}.tar.xz"
|
||||
# Configure Build
|
||||
CONFIGURE_COMMAND
|
||||
"${CMAKE_COMMAND}" "-E" "env"
|
||||
${PKGCONFIG_ENV}
|
||||
|
@ -30,21 +29,16 @@ ExternalProject_Add(qemu
|
|||
"--cross-prefix="
|
||||
"--cc=${CMAKE_C_COMPILER}"
|
||||
"--cxx=${CMAKE_CXX_COMPILER}"
|
||||
"--extra-ldflags=-ldl -Wl,-rpath=$ORIGIN/../lib/native -Wl,--disable-new-dtags"
|
||||
"--disable-debug-info"
|
||||
"--target-list=arm-linux-user"
|
||||
"--without-default-features"
|
||||
USES_TERMINAL_CONFIGURE TRUE
|
||||
# Build Command
|
||||
BUILD_COMMAND "ninja" "qemu-arm"
|
||||
BUILD_BYPRODUCTS "<BINARY_DIR>/qemu-arm"
|
||||
BUILD_COMMAND ninja "qemu-arm"
|
||||
USES_TERMINAL_BUILD TRUE
|
||||
# Disable Install/Test Commands
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
# Patch Command
|
||||
PATCH_COMMAND "patch" "-p1" "<" "${CMAKE_CURRENT_SOURCE_DIR}/trampoline.patch"
|
||||
COMMAND ${QEMU_FLATPAK_PATCH}
|
||||
PATCH_COMMAND ${QEMU_PATCH}
|
||||
BUILD_BYPRODUCTS "<BINARY_DIR>/qemu-arm"
|
||||
)
|
||||
|
||||
# Install
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
--- a/linux-user/syscall.c
|
||||
+++ b/linux-user/syscall.c
|
||||
@@ -17,6 +17,7 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define _ATFILE_SOURCE
|
||||
+#include <dlfcn.h>
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/path.h"
|
||||
@@ -9070,6 +9071,17 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname,
|
||||
int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
|
||||
#endif
|
||||
|
||||
+// g2h For Trampoline
|
||||
+static CPUState *_trampoline_g2h_cpu = NULL;
|
||||
+static void *_trampoline_g2h(uint32_t guest_addr) {
|
||||
+ if (guest_addr == 0) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return g2h(_trampoline_g2h_cpu, guest_addr);
|
||||
+}
|
||||
+// Trampoline Function
|
||||
+typedef void (*_trampoline_t)(typeof(_trampoline_g2h) *g2h, uint32_t id, uint32_t *args);
|
||||
+
|
||||
/* This is an internal helper for do_syscall so that it is easier
|
||||
* to have a single return point, so that actions, such as logging
|
||||
* of syscall results, can be performed.
|
||||
@@ -9095,6 +9107,27 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
||||
void *p;
|
||||
|
||||
switch(num) {
|
||||
+ case 0x1337: {
|
||||
+ // Load Trampoline
|
||||
+ static _trampoline_t _trampoline = NULL;
|
||||
+ if (_trampoline == NULL) {
|
||||
+ // Open Library
|
||||
+ void *_trampoline_handle = dlopen("libmedia-layer-trampoline.so", RTLD_NOW);
|
||||
+ // Load Function
|
||||
+ if (_trampoline_handle != NULL) {
|
||||
+ _trampoline = dlsym(_trampoline_handle, "trampoline");
|
||||
+ }
|
||||
+ }
|
||||
+ if (_trampoline == NULL) {
|
||||
+ // Failed To Load
|
||||
+ qemu_log_mask(LOG_UNIMP, "Unable To Load Media Layer Trampoline: %s\n", dlerror());
|
||||
+ return -TARGET_ENOSYS;
|
||||
+ }
|
||||
+ // Call Trampoline
|
||||
+ _trampoline_g2h_cpu = cpu;
|
||||
+ _trampoline(_trampoline_g2h, arg1, g2h(cpu, arg2));
|
||||
+ return 0;
|
||||
+ }
|
||||
case TARGET_NR_exit:
|
||||
/* In old applications this may be used to implement _exit(2).
|
||||
However in threaded applications it is used for thread termination,
|
|
@ -1 +1 @@
|
|||
Subproject commit fbb9b6d6da1a9dfa9290d420d1b2c34f91026111
|
||||
Subproject commit db3879f7a51c5413e1c17e17cd6949d711132468
|
|
@ -3,7 +3,6 @@
|
|||
**3.0.0**
|
||||
* Modding API Revamped
|
||||
* `*(unsigned char **)` Is Dead!
|
||||
* Now C++ Only
|
||||
* Add Peaceful Mode To Options Screen
|
||||
* Proper Create New World Screen
|
||||
* Proper Chat Screen
|
||||
|
@ -15,15 +14,6 @@
|
|||
* Add `Display Date In Select World Screen` Feature Flag (Enabled By Default)
|
||||
* Add `Optimized Chunk Sorting` Feature Flag (Enabled By Default)
|
||||
* Add `Add Cake` Feature Flag (Enabled By Default)
|
||||
* Add `Add Reborn Info To Options` Feature Flag (Enabled By Default)
|
||||
* Add `Track FPS` Feature Flag (Disabled By Default)
|
||||
* Split Up `Remove Creative Mode Restrictions` Feature Flag
|
||||
* `Remove Creative Mode Restrictions` (Disabled By Default)
|
||||
* `Display Slot Count In Creative Mode` (Disabled By Default)
|
||||
* `Force Survival Mode Inventory UI` (Disabled By Default)
|
||||
* `Force Survival Mode Inventory Behavior` (Disabled By Default)
|
||||
* `Maximize Creative Mode Inventory Stack Size` (Disabled By Default)
|
||||
* Rename `Disable Buggy Held Item Caching` Feature Flag To `Fix Held Item Caching`
|
||||
* Add Milk Buckets
|
||||
* Implement Crafting Remainders
|
||||
* Improve Death Messages
|
||||
|
|
|
@ -15,7 +15,7 @@ HOOK(chat_handle_packet_send, void, (Minecraft *minecraft, ChatPacket *packet))
|
|||
if (out.length() > 0 && out[out.length() - 1] == '\n') {
|
||||
out[out.length() - 1] = '\0';
|
||||
}
|
||||
gui->addMessage(&out);
|
||||
misc_add_message(gui, out.c_str());
|
||||
} else {
|
||||
// Call Original Method
|
||||
ensure_chat_handle_packet_send();
|
||||
|
|
|
@ -2,19 +2,19 @@ project(launcher)
|
|||
|
||||
# Launcher
|
||||
add_executable(launcher
|
||||
src/bootstrap.cpp
|
||||
src/bootstrap.c
|
||||
src/patchelf.cpp
|
||||
src/util.c
|
||||
src/crash-report.c
|
||||
src/sdk.cpp
|
||||
src/mods.cpp
|
||||
src/options/parser.cpp
|
||||
src/main.cpp
|
||||
src/sdk.c
|
||||
src/mods.c
|
||||
)
|
||||
if(NOT MCPI_SERVER_MODE)
|
||||
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/configuration.cpp
|
||||
src/client/launcher.cpp
|
||||
src/client/cache.cpp
|
||||
src/client/available-feature-flags # Show In IDE
|
||||
)
|
||||
|
@ -22,7 +22,6 @@ endif()
|
|||
target_link_libraries(launcher reborn-util LIB_LIEF)
|
||||
# RPath
|
||||
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
||||
target_link_options(launcher PRIVATE "LINKER:--disable-new-dtags")
|
||||
|
||||
# Install
|
||||
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "bootstrap.h"
|
||||
#include "patchelf.h"
|
||||
#include "crash-report.h"
|
||||
|
||||
#define MCPI_BINARY "minecraft-pi"
|
||||
#define QEMU_BINARY "qemu-arm"
|
||||
|
||||
#define REQUIRED_PAGE_SIZE 4096
|
||||
#define _STR(x) #x
|
||||
#define STR(x) _STR(x)
|
||||
|
||||
// Exit Handler
|
||||
static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
// Pass Signal To Child
|
||||
murder_children();
|
||||
while (wait(NULL) > 0) {}
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Debug Information
|
||||
static void run_debug_command(const char *const command[], const char *prefix) {
|
||||
int status = 0;
|
||||
char *output = run_command(command, &status, NULL);
|
||||
if (output != NULL) {
|
||||
// Remove Newline
|
||||
size_t length = strlen(output);
|
||||
if (length > 0 && output[length - 1] == '\n') {
|
||||
output[length - 1] = '\0';
|
||||
}
|
||||
|
||||
// Print
|
||||
DEBUG("%s: %s", prefix, output);
|
||||
free(output);
|
||||
}
|
||||
if (!is_exit_status_success(status)) {
|
||||
ERR("Unable To Gather Debug Information");
|
||||
}
|
||||
}
|
||||
static void print_debug_information() {
|
||||
// System Information
|
||||
const char *const command[] = {"uname", "-a", NULL};
|
||||
run_debug_command(command, "System Information");
|
||||
|
||||
// Version
|
||||
DEBUG("Reborn Version: v%s", MCPI_VERSION);
|
||||
|
||||
// Architecture
|
||||
const char *arch = "Unknown";
|
||||
#ifdef __x86_64__
|
||||
arch = "AMD64";
|
||||
#elif defined(__aarch64__)
|
||||
arch = "ARM64";
|
||||
#elif defined(__arm__)
|
||||
arch = "ARM32";
|
||||
#endif
|
||||
DEBUG("Reborn Target Architecture: %s", arch);
|
||||
}
|
||||
|
||||
// Pre-Bootstrap
|
||||
void pre_bootstrap(int argc, char *argv[]) {
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Launcher) ";
|
||||
|
||||
// Disable stdout Buffering
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
// Print Version
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
|
||||
// Print
|
||||
printf("Reborn v%s\n", MCPI_VERSION);
|
||||
fflush(stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Logging
|
||||
setup_log_file();
|
||||
|
||||
// --debug
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--debug") == 0) {
|
||||
set_and_print_env("MCPI_DEBUG", "1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// GTK Dark Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
set_and_print_env("GTK_THEME", "Adwaita:dark");
|
||||
#endif
|
||||
|
||||
// Configure PATH
|
||||
{
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
|
||||
// Add Library Directory
|
||||
char *new_path = NULL;
|
||||
safe_asprintf(&new_path, "%s/bin", binary_directory);
|
||||
// Add Existing PATH
|
||||
{
|
||||
char *value = getenv("PATH");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&new_path, ":%s", value);
|
||||
}
|
||||
}
|
||||
// Set And Free
|
||||
set_and_print_env("PATH", new_path);
|
||||
free(new_path);
|
||||
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
}
|
||||
|
||||
// --copy-sdk
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--copy-sdk") == 0) {
|
||||
char *binary_directory = get_binary_directory();
|
||||
copy_sdk(binary_directory, 0);
|
||||
free(binary_directory);
|
||||
fflush(stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Crash Reports
|
||||
setup_crash_report();
|
||||
|
||||
// AppImage
|
||||
#ifdef MCPI_IS_APPIMAGE_BUILD
|
||||
{
|
||||
char *owd = getenv("OWD");
|
||||
if (owd != NULL && chdir(owd) != 0) {
|
||||
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Install Signal Handlers
|
||||
struct sigaction act_sigint;
|
||||
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, NULL);
|
||||
struct sigaction act_sigterm;
|
||||
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, NULL);
|
||||
|
||||
// Check Page Size (Not Needed When Using QEMU)
|
||||
#ifndef MCPI_USE_QEMU
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size != REQUIRED_PAGE_SIZE) {
|
||||
ERR("Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Debug Information
|
||||
print_debug_information();
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
void bootstrap(int argc, char *argv[]) {
|
||||
INFO("Configuring Game...");
|
||||
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
DEBUG("Binary Directory: %s", binary_directory);
|
||||
|
||||
// Copy SDK
|
||||
copy_sdk(binary_directory, 1);
|
||||
|
||||
// Set MCPI_REBORN_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = realpath("/proc/self/exe", NULL);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_REBORN_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
||||
char *resolved_path = NULL;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Resolving File Paths...");
|
||||
|
||||
// Resolve Full Binary Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
|
||||
resolved_path = realpath(full_path, NULL);
|
||||
ALLOC_CHECK(resolved_path);
|
||||
free(full_path);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
||||
{
|
||||
// Log
|
||||
DEBUG("Patching ELF Dependencies...");
|
||||
|
||||
// Find Linker
|
||||
char *linker = NULL;
|
||||
// Select Linker
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
// Use ARM Sysroot Linker
|
||||
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
|
||||
#else
|
||||
// Use Current Linker
|
||||
linker = patch_get_interpreter();
|
||||
#endif
|
||||
|
||||
// Patch
|
||||
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
|
||||
|
||||
// Free Linker Path
|
||||
if (linker != NULL) {
|
||||
free(linker);
|
||||
}
|
||||
|
||||
// Verify
|
||||
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Set MCPI_VANILLA_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = strdup(resolved_path);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Free Resolved Path
|
||||
free(resolved_path);
|
||||
|
||||
// Configure Library Search Path
|
||||
{
|
||||
// Log
|
||||
DEBUG("Setting Linker Search Paths...");
|
||||
|
||||
// Prepare
|
||||
char *transitive_ld_path = NULL;
|
||||
char *mcpi_ld_path = NULL;
|
||||
|
||||
// Library Search Path For Native Components
|
||||
{
|
||||
// Add Native Library Directory
|
||||
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
|
||||
|
||||
// Add Host LD_LIBRARY_PATH
|
||||
{
|
||||
char *value = getenv("LD_LIBRARY_PATH");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&transitive_ld_path, ":%s", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path);
|
||||
free(transitive_ld_path);
|
||||
}
|
||||
|
||||
// Library Search Path For ARM Components
|
||||
{
|
||||
// Add ARM Library Directory
|
||||
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
|
||||
|
||||
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory);
|
||||
#endif
|
||||
|
||||
// Add Host LD_LIBRARY_PATH
|
||||
{
|
||||
char *value = getenv("LD_LIBRARY_PATH");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&mcpi_ld_path, ":%s", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
|
||||
free(mcpi_ld_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Configure Preloaded Objects
|
||||
{
|
||||
// Log
|
||||
DEBUG("Locating Mods...");
|
||||
|
||||
// Native Components
|
||||
char *host_ld_preload = getenv("LD_PRELOAD");
|
||||
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
|
||||
|
||||
// ARM Components
|
||||
bootstrap_mods(binary_directory);
|
||||
}
|
||||
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
|
||||
// Start Game
|
||||
INFO("Starting Game...");
|
||||
|
||||
// Arguments
|
||||
int argv_start = 1; // argv = &new_args[argv_start]
|
||||
const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
|
||||
|
||||
// Copy Existing Arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
new_args[i + argv_start] = argv[i];
|
||||
}
|
||||
// NULL-Terminator
|
||||
new_args[argv_start + argc] = NULL;
|
||||
|
||||
// Set Executable Argument
|
||||
new_args[argv_start] = new_mcpi_exe_path;
|
||||
|
||||
// Non-ARM Systems Need QEMU
|
||||
#ifdef MCPI_USE_QEMU
|
||||
argv_start--;
|
||||
new_args[argv_start] = QEMU_BINARY;
|
||||
// Use 4k Page Size
|
||||
set_and_print_env("QEMU_PAGESIZE", STR(REQUIRED_PAGE_SIZE));
|
||||
#endif
|
||||
|
||||
// Setup Environment
|
||||
setup_exec_environment(1);
|
||||
|
||||
// Pass LD_* Variables Through QEMU
|
||||
#ifdef MCPI_USE_QEMU
|
||||
char *qemu_set_env = NULL;
|
||||
#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name));
|
||||
for_each_special_environmental_variable(pass_variable_through_qemu);
|
||||
set_and_print_env("QEMU_SET_ENV", qemu_set_env);
|
||||
free(qemu_set_env);
|
||||
// Treat QEMU Itself As A Native Component
|
||||
setup_exec_environment(0);
|
||||
#endif
|
||||
|
||||
// Run
|
||||
const char **new_argv = &new_args[argv_start];
|
||||
safe_execvpe(new_argv, (const char *const *) environ);
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "bootstrap.h"
|
||||
#include "patchelf.h"
|
||||
|
||||
#define MCPI_BINARY "minecraft-pi"
|
||||
#define QEMU_BINARY "qemu-arm"
|
||||
|
||||
#define REQUIRED_PAGE_SIZE 4096
|
||||
#define _STR(x) #x
|
||||
#define STR(x) _STR(x)
|
||||
|
||||
// Debug Information
|
||||
static void run_debug_command(const char *const command[], const char *prefix) {
|
||||
int status = 0;
|
||||
char *output = run_command(command, &status, nullptr);
|
||||
if (output != nullptr) {
|
||||
// Remove Newline
|
||||
size_t length = strlen(output);
|
||||
if (length > 0 && output[length - 1] == '\n') {
|
||||
output[length - 1] = '\0';
|
||||
}
|
||||
|
||||
// Print
|
||||
DEBUG("%s: %s", prefix, output);
|
||||
free(output);
|
||||
}
|
||||
if (!is_exit_status_success(status)) {
|
||||
ERR("Unable To Gather Debug Information");
|
||||
}
|
||||
}
|
||||
static void print_debug_information() {
|
||||
// System Information
|
||||
const char *const command[] = {"uname", "-a", nullptr};
|
||||
run_debug_command(command, "System Information");
|
||||
|
||||
// Version
|
||||
DEBUG("Reborn Version: v%s", MCPI_VERSION);
|
||||
|
||||
// Architecture
|
||||
const char *arch = "Unknown";
|
||||
#ifdef __x86_64__
|
||||
arch = "AMD64";
|
||||
#elif defined(__aarch64__)
|
||||
arch = "ARM64";
|
||||
#elif defined(__arm__)
|
||||
arch = "ARM32";
|
||||
#endif
|
||||
DEBUG("Reborn Target Architecture: %s", arch);
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
void bootstrap() {
|
||||
// Debug Information
|
||||
print_debug_information();
|
||||
|
||||
// Check Page Size (Not Needed When Using QEMU)
|
||||
#ifndef MCPI_USE_QEMU
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size != REQUIRED_PAGE_SIZE) {
|
||||
ERR("Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
|
||||
}
|
||||
#else
|
||||
set_and_print_env("QEMU_PAGESIZE", STR(REQUIRED_PAGE_SIZE));
|
||||
#endif
|
||||
|
||||
// Get Binary Directory
|
||||
char *binary_directory_raw = get_binary_directory();
|
||||
const std::string binary_directory = binary_directory_raw;
|
||||
free(binary_directory_raw);
|
||||
DEBUG("Binary Directory: %s", binary_directory.c_str());
|
||||
|
||||
// Copy SDK
|
||||
copy_sdk(binary_directory, true);
|
||||
|
||||
// Set MCPI_REBORN_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = realpath("/proc/self/exe", nullptr);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_REBORN_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
||||
char *resolved_path = nullptr;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Resolving File Paths...");
|
||||
|
||||
// Resolve Full Binary Path
|
||||
const std::string full_path = binary_directory + ("/" MCPI_BINARY);
|
||||
resolved_path = realpath(full_path.c_str(), nullptr);
|
||||
ALLOC_CHECK(resolved_path);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
||||
{
|
||||
// Log
|
||||
DEBUG("Patching ELF Dependencies...");
|
||||
|
||||
// Find Linker
|
||||
char *linker = nullptr;
|
||||
// Select Linker
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
// Use ARM Sysroot Linker
|
||||
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory.c_str());
|
||||
#else
|
||||
// Use Current Linker
|
||||
linker = patch_get_interpreter();
|
||||
#endif
|
||||
|
||||
// Patch
|
||||
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
|
||||
|
||||
// Free Linker Path
|
||||
if (linker != nullptr) {
|
||||
free(linker);
|
||||
}
|
||||
|
||||
// Verify
|
||||
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Set MCPI_VANILLA_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = strdup(resolved_path);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Free Resolved Path
|
||||
free(resolved_path);
|
||||
|
||||
// Configure Library Search Path
|
||||
{
|
||||
// Log
|
||||
DEBUG("Setting Linker Search Paths...");
|
||||
|
||||
// Prepare
|
||||
std::string mcpi_ld_path = "";
|
||||
|
||||
// Library Search Path For ARM Components
|
||||
{
|
||||
// Add ARM Library Directory
|
||||
mcpi_ld_path += binary_directory + "/lib/arm:";
|
||||
|
||||
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
mcpi_ld_path += binary_directory + "/sysroot/lib:";
|
||||
mcpi_ld_path += binary_directory + "/sysroot/lib/arm-linux-gnueabihf:";
|
||||
mcpi_ld_path += binary_directory + "/sysroot/usr/lib:";
|
||||
mcpi_ld_path += binary_directory + "/sysroot/usr/lib/arm-linux-gnueabihf:";
|
||||
#endif
|
||||
|
||||
// Add Host LD_LIBRARY_PATH
|
||||
{
|
||||
char *value = getenv("LD_LIBRARY_PATH");
|
||||
if (value != nullptr && strlen(value) > 0) {
|
||||
mcpi_ld_path += value;
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env(MCPI_LD_VARIABLE_PREFIX "LD_LIBRARY_PATH", mcpi_ld_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Configure Preloaded Objects
|
||||
{
|
||||
// Log
|
||||
DEBUG("Locating Mods...");
|
||||
|
||||
// ARM Components
|
||||
bootstrap_mods(binary_directory);
|
||||
}
|
||||
|
||||
// Start Game
|
||||
INFO("Starting Game...");
|
||||
|
||||
// Arguments
|
||||
std::vector<std::string> args;
|
||||
// Non-ARM Systems Need QEMU
|
||||
#ifdef MCPI_USE_QEMU
|
||||
args.insert(args.begin(), QEMU_BINARY);
|
||||
#endif
|
||||
|
||||
// Preserve Existing LD_* Variables
|
||||
#define preserve_variable(name) set_and_print_env(MCPI_ORIGINAL_LD_VARIABLE_PREFIX name, getenv(name))
|
||||
for_each_special_environmental_variable(preserve_variable);
|
||||
set_and_print_env(MCPI_ORIGINAL_LD_VARIABLES_PRESERVED_ENV, "1");
|
||||
// Setup Environment
|
||||
setup_exec_environment(1);
|
||||
|
||||
// Pass LD_* Variables Through QEMU
|
||||
#ifdef MCPI_USE_QEMU
|
||||
#define pass_variable_through_qemu(name) args.push_back("-E"); args.push_back(std::string(name) + "=" + getenv(name))
|
||||
for_each_special_environmental_variable(pass_variable_through_qemu);
|
||||
// Treat QEMU Itself As A Native Component
|
||||
setup_exec_environment(0);
|
||||
#endif
|
||||
|
||||
// Specify MCPI Binary
|
||||
args.push_back(new_mcpi_exe_path);
|
||||
|
||||
// Run
|
||||
const char *new_argv[args.size() + 1];
|
||||
for (std::vector<std::string>::size_type i = 0; i < args.size(); i++) {
|
||||
new_argv[i] = args[i].c_str();
|
||||
}
|
||||
new_argv[args.size()] = nullptr;
|
||||
safe_execvpe(new_argv, environ);
|
||||
}
|
|
@ -1,7 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bootstrap();
|
||||
void copy_sdk(const std::string &binary_directory, bool log_with_debug);
|
||||
void bootstrap_mods(const std::string &binary_directory);
|
||||
void pre_bootstrap(int argc, char *argv[]);
|
||||
void bootstrap(int argc, char *argv[]);
|
||||
void copy_sdk(char *binary_directory, int log_with_debug);
|
||||
void bootstrap_mods(char *binary_directory);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,10 +8,6 @@ TRUE Fix Sign Placement
|
|||
TRUE Show Block Outlines
|
||||
FALSE Expand Creative Mode Inventory
|
||||
FALSE Remove Creative Mode Restrictions
|
||||
FALSE Display Slot Count In Creative Mode
|
||||
FALSE Force Survival Mode Inventory UI
|
||||
FALSE Force Survival Mode Inventory Behavior
|
||||
FALSE Maximize Creative Mode Inventory Stack Size
|
||||
TRUE Animated Water
|
||||
TRUE Animated Lava
|
||||
TRUE Animated Fire
|
||||
|
@ -64,6 +60,4 @@ FALSE Food Overlay
|
|||
TRUE Add Splashes
|
||||
TRUE Display Date In Select World Screen
|
||||
TRUE Optimized Chunk Sorting
|
||||
TRUE Fix Held Item Caching
|
||||
TRUE Add Reborn Info To Options
|
||||
FALSE Track FPS
|
||||
TRUE Disable Buggy Held Item Caching
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "configuration.h"
|
||||
#include "launcher.h"
|
||||
#include "cache.h"
|
||||
|
||||
// Get Cache Path
|
||||
static std::string get_cache_path() {
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
if (home == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
return std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA "/.launcher-cache";
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "../options/parser.h"
|
||||
|
||||
// Defaults
|
||||
#define DEFAULT_USERNAME "StevePi"
|
||||
#define DEFAULT_RENDER_DISTANCE "Short"
|
||||
|
||||
// Feature Flags
|
||||
std::string strip_feature_flag_default(const std::string& flag, bool *default_ret);
|
||||
void load_available_feature_flags(const std::function<void(std::string)> &callback);
|
||||
|
||||
// Handle Non-Launch Commands
|
||||
void handle_non_launch_client_only_commands(const options_t &options);
|
||||
|
||||
// Check Environment
|
||||
void check_environment_client();
|
||||
|
||||
// Configure Client Options
|
||||
void configure_client(const options_t &options);
|
|
@ -10,24 +10,25 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../util.h"
|
||||
#include "configuration.h"
|
||||
#include "../bootstrap.h"
|
||||
#include "launcher.h"
|
||||
#include "cache.h"
|
||||
|
||||
// Strip Feature Flag Default
|
||||
std::string strip_feature_flag_default(const 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 ";
|
||||
// Test
|
||||
if (flag.rfind(true_str, 0) == 0) {
|
||||
// Enabled By Default
|
||||
if (default_ret != nullptr) {
|
||||
if (default_ret != NULL) {
|
||||
*default_ret = true;
|
||||
}
|
||||
return flag.substr(true_str.length(), std::string::npos);
|
||||
} else if (flag.rfind(false_str, 0) == 0) {
|
||||
// Disabled By Default
|
||||
if (default_ret != nullptr) {
|
||||
if (default_ret != NULL) {
|
||||
*default_ret = false;
|
||||
}
|
||||
return flag.substr(false_str.length(), std::string::npos);
|
||||
|
@ -40,7 +41,7 @@ std::string strip_feature_flag_default(const std::string &flag, bool *default_re
|
|||
// Load Available Feature Flags
|
||||
extern unsigned char available_feature_flags[];
|
||||
extern size_t available_feature_flags_len;
|
||||
void load_available_feature_flags(const 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";
|
||||
|
@ -54,7 +55,7 @@ void load_available_feature_flags(const std::function<void(std::string)> &callba
|
|||
{
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) {
|
||||
if (!line.empty()) {
|
||||
if (line.length() > 0) {
|
||||
// Verify Line
|
||||
if (line.find('|') == std::string::npos) {
|
||||
lines.push_back(line);
|
||||
|
@ -66,15 +67,15 @@ void load_available_feature_flags(const std::function<void(std::string)> &callba
|
|||
}
|
||||
}
|
||||
// Sort
|
||||
std::sort(lines.begin(), lines.end(), [](const std::string &a, const std::string &b) {
|
||||
std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) {
|
||||
// Strip Defaults
|
||||
std::string stripped_a = strip_feature_flag_default(a, nullptr);
|
||||
std::string stripped_b = strip_feature_flag_default(b, nullptr);
|
||||
std::string stripped_a = strip_feature_flag_default(a, NULL);
|
||||
std::string stripped_b = strip_feature_flag_default(b, NULL);
|
||||
// Sort
|
||||
return stripped_a < stripped_b;
|
||||
});
|
||||
// Run Callbacks
|
||||
for (const std::string &line : lines) {
|
||||
for (std::string &line : lines) {
|
||||
callback(line);
|
||||
}
|
||||
}
|
||||
|
@ -82,11 +83,11 @@ void load_available_feature_flags(const std::function<void(std::string)> &callba
|
|||
// Run Command And Set Environmental Variable
|
||||
static void run_command_and_set_env(const char *env_name, const char *command[]) {
|
||||
// Only Run If Environmental Variable Is NULL
|
||||
if (getenv(env_name) == nullptr) {
|
||||
if (getenv(env_name) == NULL) {
|
||||
// Run
|
||||
int return_code;
|
||||
char *output = run_command(command, &return_code, nullptr);
|
||||
if (output != nullptr) {
|
||||
char *output = run_command(command, &return_code, NULL);
|
||||
if (output != NULL) {
|
||||
// Trim
|
||||
int length = strlen(output);
|
||||
if (output[length - 1] == '\n') {
|
||||
|
@ -121,14 +122,14 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
|
|||
for (std::vector<std::string>::size_type i = 0; i < full_command.size(); i++) {
|
||||
full_command_array[i] = full_command[i].c_str();
|
||||
}
|
||||
full_command_array[full_command.size()] = nullptr;
|
||||
full_command_array[full_command.size()] = NULL;
|
||||
// Run
|
||||
run_command_and_set_env(env_name, full_command_array);
|
||||
}
|
||||
|
||||
// Set Variable If Not Already Set
|
||||
static void set_env_if_unset(const char *env_name, const std::function<std::string()> &callback) {
|
||||
if (getenv(env_name) == nullptr) {
|
||||
static void set_env_if_unset(const char *env_name, std::function<std::string()> callback) {
|
||||
if (getenv(env_name) == NULL) {
|
||||
char *value = strdup(callback().c_str());
|
||||
ALLOC_CHECK(value);
|
||||
set_and_print_env(env_name, value);
|
||||
|
@ -136,74 +137,102 @@ static void set_env_if_unset(const char *env_name, const std::function<std::stri
|
|||
}
|
||||
}
|
||||
|
||||
// Handle Non-Launch Commands
|
||||
void handle_non_launch_client_only_commands(const options_t &options) {
|
||||
// Print Available Feature Flags
|
||||
if (options.print_available_feature_flags) {
|
||||
load_available_feature_flags([](const std::string &line) {
|
||||
printf("%s\n", line.c_str());
|
||||
fflush(stdout);
|
||||
});
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Check Environment
|
||||
void check_environment_client() {
|
||||
// Launch
|
||||
#define LIST_DIALOG_SIZE "400"
|
||||
int main(int argc, char *argv[]) {
|
||||
// Don't Run As Root
|
||||
if (getenv("_MCPI_SKIP_ROOT_CHECK") == nullptr && (getuid() == 0 || geteuid() == 0)) {
|
||||
if (getenv("_MCPI_SKIP_ROOT_CHECK") == NULL && (getuid() == 0 || geteuid() == 0)) {
|
||||
ERR("Don't Run As Root");
|
||||
}
|
||||
|
||||
// Ensure HOME
|
||||
if (getenv("HOME") == NULL) {
|
||||
ERR("$HOME Isn't Set");
|
||||
}
|
||||
|
||||
// Check For Display
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (getenv("DISPLAY") == nullptr && getenv("WAYLAND_DISPLAY") == nullptr) {
|
||||
if (getenv("DISPLAY") == NULL && getenv("WAYLAND_DISPLAY") == NULL) {
|
||||
ERR("No display attached! Make sure $DISPLAY or $WAYLAND_DISPLAY is set.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Configure Client Options
|
||||
#define LIST_DIALOG_SIZE "400"
|
||||
void configure_client(const options_t &options) {
|
||||
// Wipe Cache If Needed
|
||||
if (options.wipe_cache) {
|
||||
wipe_cache();
|
||||
// Print Features
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--print-available-feature-flags") == 0) {
|
||||
// Print Available Feature Flags
|
||||
load_available_feature_flags([](std::string line) {
|
||||
printf("%s\n", line.c_str());
|
||||
fflush(stdout);
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = options.no_cache ? empty_cache : load_cache();
|
||||
launcher_cache cache = no_cache ? empty_cache : load_cache();
|
||||
|
||||
// --default
|
||||
if (options.use_default) {
|
||||
// Use Default Feature Flags
|
||||
set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() {
|
||||
std::string feature_flags = "";
|
||||
load_available_feature_flags([&feature_flags, &cache](const std::string &flag) {
|
||||
bool value;
|
||||
// Strip 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 (value) {
|
||||
// Enabled By Default
|
||||
feature_flags += stripped_flag + '|';
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--default") == 0) {
|
||||
// Use Default Feature Flags
|
||||
set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() {
|
||||
std::string feature_flags = "";
|
||||
load_available_feature_flags([&feature_flags, &cache](std::string flag) {
|
||||
bool value;
|
||||
// Strip 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 (value) {
|
||||
// Enabled By Default
|
||||
feature_flags += stripped_flag + '|';
|
||||
}
|
||||
});
|
||||
if (feature_flags.length() > 0 && feature_flags[feature_flags.length() - 1] == '|') {
|
||||
feature_flags.pop_back();
|
||||
}
|
||||
return feature_flags;
|
||||
});
|
||||
if (!feature_flags.empty() && feature_flags[feature_flags.length() - 1] == '|') {
|
||||
feature_flags.pop_back();
|
||||
}
|
||||
return feature_flags;
|
||||
});
|
||||
set_env_if_unset("MCPI_RENDER_DISTANCE", [&cache]() {
|
||||
return cache.render_distance;
|
||||
});
|
||||
set_env_if_unset("MCPI_USERNAME", [&cache]() {
|
||||
return cache.username;
|
||||
});
|
||||
set_env_if_unset("MCPI_RENDER_DISTANCE", [&cache]() {
|
||||
return cache.render_distance;
|
||||
});
|
||||
set_env_if_unset("MCPI_USERNAME", [&cache]() {
|
||||
return cache.username;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup MCPI_FEATURE_FLAGS
|
||||
|
@ -219,7 +248,7 @@ void configure_client(const options_t &options) {
|
|||
command.push_back("Enabled");
|
||||
command.push_back("--column");
|
||||
command.push_back("Feature");
|
||||
load_available_feature_flags([&command, &cache](const std::string &flag) {
|
||||
load_available_feature_flags([&command, &cache](std::string flag) {
|
||||
bool value;
|
||||
// Strip Default Value
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &value);
|
||||
|
@ -258,7 +287,7 @@ void configure_client(const options_t &options) {
|
|||
command.push_back("Name");
|
||||
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
|
||||
for (std::string &render_distance : render_distances) {
|
||||
command.push_back(render_distance == cache.render_distance ? "TRUE" : "FALSE");
|
||||
command.push_back(render_distance.compare(cache.render_distance) == 0 ? "TRUE" : "FALSE");
|
||||
command.push_back(render_distance);
|
||||
}
|
||||
// Run
|
||||
|
@ -277,7 +306,10 @@ void configure_client(const options_t &options) {
|
|||
}
|
||||
|
||||
// Save Cache
|
||||
if (!options.no_cache) {
|
||||
if (!no_cache) {
|
||||
save_cache();
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
bootstrap(argc, argv);
|
||||
}
|
|
@ -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);
|
|
@ -34,7 +34,7 @@ static void show_report(const char *log_filename) {
|
|||
"--width", CRASH_REPORT_DIALOG_WIDTH,
|
||||
"--height", CRASH_REPORT_DIALOG_HEIGHT,
|
||||
"--text-info",
|
||||
"--text", MCPI_APP_BASE_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"" MCPI_DISCORD_INVITE "\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_BASE_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
|
||||
"--text", MCPI_APP_BASE_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_BASE_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
|
||||
"--filename", log_filename,
|
||||
"--no-wrap",
|
||||
"--font", "Monospace",
|
||||
|
@ -58,6 +58,7 @@ static void exit_handler(__attribute__((unused)) int signal) {
|
|||
#define PIPE_WRITE 1
|
||||
#define MCPI_LOGS_DIR "/tmp/.minecraft-pi-logs"
|
||||
static char log_filename[] = MCPI_LOGS_DIR "/XXXXXX";
|
||||
static int log_file_fd = -1;
|
||||
void setup_log_file() {
|
||||
// Ensure Temporary Directory
|
||||
{
|
||||
|
@ -73,12 +74,16 @@ void setup_log_file() {
|
|||
}
|
||||
|
||||
// Create Temporary File
|
||||
int log_file_fd = mkstemp(log_filename);
|
||||
log_file_fd = mkstemp(log_filename);
|
||||
if (log_file_fd == -1) {
|
||||
ERR("Unable To Create Log File: %s", strerror(errno));
|
||||
}
|
||||
close(log_file_fd);
|
||||
reborn_set_log(log_filename);
|
||||
|
||||
// Setup Environment
|
||||
char *log_file_fd_env = NULL;
|
||||
safe_asprintf(&log_file_fd_env, "%i", log_file_fd);
|
||||
set_and_print_env("MCPI_LOG_FILE_FD", log_file_fd_env);
|
||||
free(log_file_fd_env);
|
||||
}
|
||||
void setup_crash_report() {
|
||||
// Store Output
|
||||
|
@ -116,11 +121,13 @@ void setup_crash_report() {
|
|||
track_child(ret);
|
||||
|
||||
// Install Signal Handlers
|
||||
struct sigaction act_sigint = {0};
|
||||
struct sigaction act_sigint;
|
||||
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, NULL);
|
||||
struct sigaction act_sigterm = {0};
|
||||
struct sigaction act_sigterm;
|
||||
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, NULL);
|
||||
|
@ -171,17 +178,17 @@ void setup_crash_report() {
|
|||
bytes_available = 0;
|
||||
}
|
||||
// Read
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, buf, BUFFER_SIZE);
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Input: %s", strerror(errno));
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
// Write To Child
|
||||
if (write(input_pipe[PIPE_WRITE], buf, bytes_read) == -1) {
|
||||
if (write(input_pipe[PIPE_WRITE], (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Input To Child: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
// Data Available From Child's stdout/stderr
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
|
@ -191,11 +198,9 @@ void setup_crash_report() {
|
|||
fprintf(poll_fds[i].fd == output_pipe[PIPE_READ] ? stdout : stderr, "%s", buf);
|
||||
|
||||
// Write To log
|
||||
reborn_lock_log();
|
||||
if (write(reborn_get_log_fd(), buf, bytes_read) == -1) {
|
||||
if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Log Data: %s", strerror(errno));
|
||||
}
|
||||
reborn_unlock_log();
|
||||
}
|
||||
} else {
|
||||
// File Descriptor No Longer Accessible
|
||||
|
@ -229,18 +234,18 @@ void setup_crash_report() {
|
|||
fprintf(stderr, "%s", exit_code_line);
|
||||
|
||||
// Write Exit Code Log Line
|
||||
reborn_lock_log();
|
||||
if (write(reborn_get_log_fd(), exit_code_line, strlen(exit_code_line)) == -1) {
|
||||
if (write(log_file_fd, (void *) exit_code_line, strlen(exit_code_line)) == -1) {
|
||||
ERR("Unable To Write Exit Code To Log: %s", strerror(errno));
|
||||
}
|
||||
reborn_unlock_log();
|
||||
|
||||
// Free Exit Code Log Line
|
||||
free(exit_code_line);
|
||||
}
|
||||
|
||||
// Close Log File
|
||||
reborn_close_log();
|
||||
// Close Log File FD
|
||||
if (close(log_file_fd) == -1) {
|
||||
ERR("Unable To Close Log File Descriptor: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Show Crash Log
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
#include <cstdlib>
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "options/parser.h"
|
||||
#include "crash-report.h"
|
||||
#include "util.h"
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#include "client/configuration.h"
|
||||
#endif
|
||||
|
||||
// Bind Options To Environmental Variable
|
||||
static void bind_to_env(const char *env, const bool value) {
|
||||
const bool force = env[0] == '_';
|
||||
if (force || value) {
|
||||
set_and_print_env(env, value ? "1" : nullptr);
|
||||
}
|
||||
}
|
||||
static void setup_environment(const options_t &options) {
|
||||
// Passthrough Options To Game
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
bind_to_env("_MCPI_BENCHMARK", options.benchmark);
|
||||
#else
|
||||
bind_to_env("_MCPI_ONLY_GENERATE", options.only_generate);
|
||||
#endif
|
||||
|
||||
// GTK Dark Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
set_and_print_env("GTK_THEME", "Adwaita:dark");
|
||||
#endif
|
||||
|
||||
// Configure PATH
|
||||
{
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
std::string new_path = std::string(binary_directory) + "/bin";
|
||||
free(binary_directory);
|
||||
// Add Existing PATH
|
||||
{
|
||||
char *value = getenv("PATH");
|
||||
if (value != nullptr && strlen(value) > 0) {
|
||||
new_path += std::string(":") + value;
|
||||
}
|
||||
}
|
||||
// Set And Free
|
||||
set_and_print_env("PATH", new_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Non-Launch Commands
|
||||
static void handle_non_launch_commands(const options_t &options) {
|
||||
if (options.copy_sdk) {
|
||||
char *binary_directory = get_binary_directory();
|
||||
copy_sdk(binary_directory, false);
|
||||
free(binary_directory);
|
||||
fflush(stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit Handler
|
||||
static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
// Pass Signal To Child
|
||||
murder_children();
|
||||
while (wait(nullptr) > 0) {}
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Start The Game
|
||||
static void start_game(const options_t &options) {
|
||||
// Disable stdout Buffering
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
// Environemntal Variable Options
|
||||
setup_environment(options);
|
||||
|
||||
// Setup Crash Reporting
|
||||
if (!options.disable_crash_report) {
|
||||
setup_log_file();
|
||||
setup_crash_report();
|
||||
}
|
||||
|
||||
// Install Signal Handlers
|
||||
struct sigaction act_sigint = {};
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, nullptr);
|
||||
struct sigaction act_sigterm = {};
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, nullptr);
|
||||
|
||||
// Setup Home
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
// Ensure $HOME
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
ERR("$HOME Isn't Set");
|
||||
}
|
||||
// Create If Needed
|
||||
{
|
||||
std::string minecraft_folder = std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA;
|
||||
struct stat tmp_stat = {};
|
||||
bool exists = stat(minecraft_folder.c_str(), &tmp_stat) != 0 ? false : S_ISDIR(tmp_stat.st_mode);
|
||||
if (!exists) {
|
||||
// Doesn't Exist
|
||||
if (mkdir(minecraft_folder.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Create Data Directory: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Set Home To Current Directory, So World Data Is Stored There
|
||||
char *launch_directory = getcwd(NULL, 0);
|
||||
set_and_print_env("HOME", launch_directory);
|
||||
free(launch_directory);
|
||||
#endif
|
||||
|
||||
// Configure Client Options
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
configure_client(options);
|
||||
#endif
|
||||
|
||||
// Bootstrap
|
||||
bootstrap();
|
||||
}
|
||||
|
||||
// Main
|
||||
int main(int argc, char *argv[]) {
|
||||
// Parse Options
|
||||
options_t options = parse_options(argc, argv);
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Launcher) ";
|
||||
|
||||
// Debug Logging
|
||||
unsetenv(MCPI_LOG_ENV);
|
||||
bind_to_env(MCPI_DEBUG_ENV, options.debug);
|
||||
|
||||
// Handle Non-Launch Commands (Copy SDK, Print Feature Flags, Etc)
|
||||
handle_non_launch_commands(options);
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
handle_non_launch_client_only_commands(options);
|
||||
#endif
|
||||
|
||||
// Check Environment
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
// Code After This Can Safely Open A Window
|
||||
check_environment_client();
|
||||
#endif
|
||||
|
||||
// Start The Game
|
||||
start_game(options);
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
|
||||
// Get All Mods In Folder
|
||||
static void load(char **ld_preload, const char *folder) {
|
||||
int folder_name_length = strlen(folder);
|
||||
// Open Folder
|
||||
DIR *dp = opendir(folder);
|
||||
if (dp != NULL) {
|
||||
// Loop Through Folder
|
||||
struct dirent *entry = NULL;
|
||||
errno = 0;
|
||||
while (1) {
|
||||
errno = 0;
|
||||
entry = readdir(dp);
|
||||
if (entry != NULL) {
|
||||
// Check If File Is Regular
|
||||
if (entry->d_type == DT_REG) {
|
||||
// Get Full Name
|
||||
int name_length = strlen(entry->d_name);
|
||||
int total_length = folder_name_length + name_length;
|
||||
char name[total_length + 1];
|
||||
|
||||
// Concatenate Folder Name And File Name
|
||||
for (int i = 0; i < folder_name_length; i++) {
|
||||
name[i] = folder[i];
|
||||
}
|
||||
for (int i = 0; i < name_length; i++) {
|
||||
name[folder_name_length + i] = entry->d_name[i];
|
||||
}
|
||||
// Add Terminator
|
||||
name[total_length] = '\0';
|
||||
|
||||
// Check If File Is Accessible
|
||||
int result = access(name, R_OK);
|
||||
if (result == 0) {
|
||||
// Add To LD_PRELOAD
|
||||
string_append(ld_preload, "%s%s", *ld_preload == NULL ? "" : ":", name);
|
||||
} else if (result == -1 && errno != 0) {
|
||||
// Fail
|
||||
WARN("Unable To Access: %s: %s", name, strerror(errno));
|
||||
errno = 0;
|
||||
}
|
||||
}
|
||||
} else if (errno != 0) {
|
||||
// Error Reading Contents Of Folder
|
||||
ERR("Error Reading Directory: %s: %s", folder, strerror(errno));
|
||||
} else {
|
||||
// Done!
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Close Folder
|
||||
closedir(dp);
|
||||
} else if (errno == ENOENT) {
|
||||
// Folder Doesn't Exist
|
||||
} else {
|
||||
// Unable To Open Folder
|
||||
ERR("Error Opening Directory: %s: %s", folder, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Bootstrap Mods
|
||||
void bootstrap_mods(char *binary_directory) {
|
||||
// Prepare
|
||||
char *preload = NULL;
|
||||
|
||||
// ~/.minecraft-pi/mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
char *mods_folder = NULL;
|
||||
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
|
||||
// Load Mods From ./mods
|
||||
load(&preload, mods_folder);
|
||||
// Free Mods Folder
|
||||
free(mods_folder);
|
||||
}
|
||||
|
||||
// Built-In Mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
char *mods_folder = NULL;
|
||||
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
|
||||
// Load Mods From ./mods
|
||||
load(&preload, mods_folder);
|
||||
// Free Mods Folder
|
||||
free(mods_folder);
|
||||
}
|
||||
|
||||
// Add LD_PRELOAD
|
||||
{
|
||||
char *value = getenv("LD_PRELOAD");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&preload, ":%s", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env("MCPI_ARM_LD_PRELOAD", preload);
|
||||
free(preload);
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
#include <dirent.h>
|
||||
#include <cerrno>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
|
||||
// Get All Mods In Folder
|
||||
static void load(std::string &ld_preload, const std::string &folder) {
|
||||
// Open Folder
|
||||
DIR *dp = opendir(folder.c_str());
|
||||
if (dp != nullptr) {
|
||||
// Loop Through Folder
|
||||
while (true) {
|
||||
errno = 0;
|
||||
dirent *entry = readdir(dp);
|
||||
if (entry != nullptr) {
|
||||
// Check If File Is Regular
|
||||
if (entry->d_type == DT_REG) {
|
||||
// Get Full Name
|
||||
std::string name = folder + entry->d_name;
|
||||
|
||||
// Check If File Is Accessible
|
||||
int result = access(name.c_str(), R_OK);
|
||||
if (result == 0) {
|
||||
// Add To LD_PRELOAD
|
||||
ld_preload += name + ":";
|
||||
} else if (result == -1 && errno != 0) {
|
||||
// Fail
|
||||
WARN("Unable To Access: %s: %s", name.c_str(), strerror(errno));
|
||||
errno = 0;
|
||||
}
|
||||
}
|
||||
} else if (errno != 0) {
|
||||
// Error Reading Contents Of Folder
|
||||
ERR("Error Reading Directory: %s: %s", folder.c_str(), strerror(errno));
|
||||
} else {
|
||||
// Done!
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Close Folder
|
||||
closedir(dp);
|
||||
} else if (errno == ENOENT) {
|
||||
// Folder Doesn't Exist
|
||||
} else {
|
||||
// Unable To Open Folder
|
||||
ERR("Error Opening Directory: %s: %s", folder.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Bootstrap Mods
|
||||
#define SUBDIRECTORY_FOR_MODS "/mods/"
|
||||
void bootstrap_mods(const std::string &binary_directory) {
|
||||
// Prepare
|
||||
std::string preload = "";
|
||||
|
||||
// ~/.minecraft-pi/mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
std::string mods_folder = std::string(getenv("HOME")) + HOME_SUBDIRECTORY_FOR_GAME_DATA SUBDIRECTORY_FOR_MODS;
|
||||
// Load Mods From ./mods
|
||||
load(preload, mods_folder);
|
||||
}
|
||||
|
||||
// Built-In Mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
std::string mods_folder = binary_directory + SUBDIRECTORY_FOR_MODS;
|
||||
// Load Mods From ./mods
|
||||
load(preload, mods_folder);
|
||||
}
|
||||
|
||||
// Add LD_PRELOAD
|
||||
{
|
||||
const char *value = getenv("LD_PRELOAD");
|
||||
if (value != nullptr && strlen(value) > 0) {
|
||||
preload += value;
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env(MCPI_LD_VARIABLE_PREFIX "LD_PRELOAD", preload.c_str());
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
OPTION(debug, "debug", 'd', "Enable Debug Logging (" MCPI_DEBUG_ENV ")")
|
||||
OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit")
|
||||
OPTION(disable_crash_report, "disable-crash-report", -1, "Disable Crash Report Dialog")
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
OPTION(use_default, "default", -3, "Skip Configuration Dialogs")
|
||||
OPTION(no_cache, "no-cache", -4, "Disable Configuration Cache")
|
||||
OPTION(wipe_cache, "wipe-cache", -5, "Wipe Cached Configuration")
|
||||
OPTION(print_available_feature_flags, "print-available-feature-flags", -6, "Print Available Feature Flags")
|
||||
OPTION(benchmark, "benchmark", -7, "Run Benchmark")
|
||||
#else
|
||||
OPTION(only_generate, "only-generate", -8, "Generate World And Exit")
|
||||
#endif
|
|
@ -1,38 +0,0 @@
|
|||
#include <argp.h>
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
// Globals
|
||||
const char *argp_program_version = "Reborn v" MCPI_VERSION;
|
||||
const char *argp_program_bug_address = "<" MCPI_DISCORD_INVITE ">";
|
||||
static char doc[] = "Minecraft: Pi Edition Modding Project";
|
||||
|
||||
// Options
|
||||
#define OPTION(ignored, name, key, doc) {name, key, nullptr, 0, doc, 0},
|
||||
static argp_option options_data[] = {
|
||||
#include "option-list.h"
|
||||
{nullptr, 0, nullptr, 0, nullptr, 0}
|
||||
};
|
||||
#undef OPTION
|
||||
|
||||
// Parse Options
|
||||
#define OPTION(name, ignored, key, ...) \
|
||||
case key: \
|
||||
options->name = true; \
|
||||
break;
|
||||
static error_t parse_opt(int key, __attribute__((unused)) char *arg, argp_state *state) {
|
||||
options_t *options = (options_t *) state->input;
|
||||
switch (key) {
|
||||
#include "option-list.h"
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#undef OPTION
|
||||
static argp argp = {options_data, parse_opt, nullptr, doc, nullptr, nullptr, nullptr};
|
||||
options_t parse_options(int argc, char *argv[]) {
|
||||
options_t options = {};
|
||||
argp_parse(&argp, argc, argv, 0, nullptr, &options);
|
||||
return options;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#define OPTION(name, ...) bool name;
|
||||
struct options_t {
|
||||
#include "option-list.h"
|
||||
};
|
||||
#undef OPTION
|
||||
options_t parse_options(int argc, char *argv[]);
|
|
@ -0,0 +1,67 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "util.h"
|
||||
|
||||
// Log
|
||||
#define LOG(is_debug, ...) \
|
||||
{ \
|
||||
if (is_debug) { \
|
||||
DEBUG(__VA_ARGS__); \
|
||||
} else { \
|
||||
INFO(__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Copy SDK Into ~/.minecraft-pi
|
||||
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
|
||||
void copy_sdk(char *binary_directory, int log_with_debug) {
|
||||
// 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_SDK "/" MCPI_SDK_DIR, getenv("HOME"));
|
||||
// Source Directory
|
||||
char *source = NULL;
|
||||
safe_asprintf(&source, "%s/sdk/.", binary_directory);
|
||||
|
||||
// Clean
|
||||
{
|
||||
const char *const command[] = {"rm", "-rf", output, NULL};
|
||||
run_simple_command(command, "Unable To Clean SDK Output Directory");
|
||||
}
|
||||
|
||||
// Make Directory
|
||||
{
|
||||
const char *const command[] = {"mkdir", "-p", output, NULL};
|
||||
run_simple_command(command, "Unable To Create SDK Output Directory");
|
||||
}
|
||||
|
||||
// Copy
|
||||
{
|
||||
const char *const command[] = {"cp", "-ar", source, output, NULL};
|
||||
run_simple_command(command, "Unable To Copy SDK");
|
||||
}
|
||||
|
||||
// Log
|
||||
LOG(log_with_debug, "Copied SDK To: %s", output);
|
||||
|
||||
// Free
|
||||
free(output);
|
||||
free(source);
|
||||
|
||||
// Unlock File
|
||||
unlock_file(lock_file_path, lock_file_fd);
|
||||
free(lock_file_path);
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "util.h"
|
||||
|
||||
// Log
|
||||
#define LOG(is_debug, ...) \
|
||||
{ \
|
||||
if (is_debug) { \
|
||||
DEBUG(__VA_ARGS__); \
|
||||
} else { \
|
||||
INFO(__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Copy SDK Into ~/.minecraft-pi
|
||||
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
|
||||
void copy_sdk(const std::string &binary_directory, const bool log_with_debug) {
|
||||
// Ensure SDK Directory
|
||||
std::string sdk_path;
|
||||
{
|
||||
sdk_path = std::string(getenv("HOME")) + HOME_SUBDIRECTORY_FOR_SDK;
|
||||
const char *const command[] = {"mkdir", "-p", sdk_path.c_str(), nullptr};
|
||||
run_simple_command(command, "Unable To Create SDK Directory");
|
||||
}
|
||||
|
||||
// Lock File
|
||||
std::string lock_file_path = sdk_path + "/.lock";
|
||||
int lock_file_fd = lock_file(lock_file_path.c_str());
|
||||
|
||||
// Output Directory
|
||||
std::string output = sdk_path + "/" MCPI_SDK_DIR;
|
||||
// Source Directory
|
||||
std::string source = binary_directory + "/sdk/.";
|
||||
|
||||
// Clean
|
||||
{
|
||||
const char *const command[] = {"rm", "-rf", output.c_str(), nullptr};
|
||||
run_simple_command(command, "Unable To Clean SDK Output Directory");
|
||||
}
|
||||
|
||||
// Make Directory
|
||||
{
|
||||
const char *const command[] = {"mkdir", "-p", output.c_str(), nullptr};
|
||||
run_simple_command(command, "Unable To Create SDK Output Directory");
|
||||
}
|
||||
|
||||
// Copy
|
||||
{
|
||||
const char *const command[] = {"cp", "-ar", source.c_str(), output.c_str(), nullptr};
|
||||
run_simple_command(command, "Unable To Copy SDK");
|
||||
}
|
||||
|
||||
// Log
|
||||
LOG(log_with_debug, "Copied SDK To: %s", output.c_str());
|
||||
|
||||
// Unlock File
|
||||
unlock_file(lock_file_path.c_str(), lock_file_fd);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../bootstrap.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap(argc, argv);
|
||||
|
||||
// Set Home To Current Directory, So World Data Is Stored There
|
||||
char *launch_directory = getcwd(NULL, 0);
|
||||
set_and_print_env("HOME", launch_directory);
|
||||
free(launch_directory);
|
||||
|
||||
// Bootstrap
|
||||
bootstrap(argc, argv);
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
#cmakedefine MCPI_SERVER_MODE
|
||||
#cmakedefine MCPI_HEADLESS_MODE
|
||||
#cmakedefine MCPI_IS_APPIMAGE_BUILD
|
||||
#cmakedefine MCPI_IS_FLATPAK_BUILD
|
||||
#cmakedefine MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
#cmakedefine MCPI_USE_GLES1_COMPATIBILITY_LAYER
|
||||
#cmakedefine MCPI_APP_BASE_TITLE "@MCPI_APP_BASE_TITLE@"
|
||||
|
@ -14,4 +13,3 @@
|
|||
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"
|
||||
#cmakedefine MCPI_SKIN_SERVER "@MCPI_SKIN_SERVER@"
|
||||
#cmakedefine MCPI_USE_QEMU
|
||||
#cmakedefine MCPI_DISCORD_INVITE "@MCPI_DISCORD_INVITE@"
|
||||
|
|
|
@ -20,12 +20,9 @@ extern "C" {
|
|||
void set_and_print_env(const char *name, const char *value);
|
||||
|
||||
// Safe execvpe()
|
||||
#define MCPI_LD_VARIABLE_PREFIX "_MCPI_"
|
||||
#define MCPI_ORIGINAL_LD_VARIABLE_PREFIX MCPI_LD_VARIABLE_PREFIX "ORIGINAL_"
|
||||
#define MCPI_ORIGINAL_LD_VARIABLES_PRESERVED_ENV MCPI_ORIGINAL_LD_VARIABLE_PREFIX "PRESERVED"
|
||||
#define for_each_special_environmental_variable(handle) \
|
||||
handle("LD_LIBRARY_PATH"); \
|
||||
handle("LD_PRELOAD")
|
||||
handle("LD_PRELOAD");
|
||||
void setup_exec_environment(int is_arm_component);
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
|
||||
|
||||
|
|
|
@ -7,24 +7,14 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Log File
|
||||
#define MCPI_LOG_ENV "_MCPI_LOG"
|
||||
int reborn_get_log_fd();
|
||||
void reborn_lock_log();
|
||||
void reborn_unlock_log();
|
||||
void reborn_close_log();
|
||||
void reborn_set_log(const char *file);
|
||||
// Debug Logging
|
||||
#define MCPI_DEBUG_ENV "MCPI_DEBUG"
|
||||
// Debug
|
||||
extern const char *reborn_debug_tag;
|
||||
int reborn_get_debug_fd();
|
||||
void reborn_lock_debug();
|
||||
void reborn_unlock_debug();
|
||||
|
||||
// Logging
|
||||
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
|
||||
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
|
||||
#define RAW_DEBUG(tag, format, ...) { reborn_lock_debug(); dprintf(reborn_get_debug_fd(), "[DEBUG]: %s" format "\n", tag, ##__VA_ARGS__); reborn_unlock_debug(); }
|
||||
#define RAW_DEBUG(tag, format, ...) { int debug_fd = reborn_get_debug_fd(); if (debug_fd != -1) { dprintf(debug_fd, "[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")
|
||||
|
|
|
@ -10,74 +10,55 @@ extern "C" {
|
|||
|
||||
void reborn_init_patch();
|
||||
|
||||
// Replace Call Located At start With A Call To target
|
||||
void _overwrite_call(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target)
|
||||
|
||||
#define _setup_fancy_overwrite(start, name, target) \
|
||||
if (!_is_new_method_##name()) { \
|
||||
ERR("Method Is Not \"New\""); \
|
||||
} \
|
||||
static name##_t _original_for_##target = start; \
|
||||
static name##_t _helper_for_##target = __overwrite_helper_for_##name(target, _original_for_##target)
|
||||
static name##_t _helper_for_##target = _overwrite_helper_for_##name(target, _original_for_##target)
|
||||
|
||||
// Replace All Calls To Method start With target
|
||||
void *_overwrite_calls(const char *file, int line, void *start, void *target);
|
||||
#define _update_references(from, to) \
|
||||
{ \
|
||||
void *old_reference = (void *) from; \
|
||||
for (int i = 0; _all_method_symbols[i] != nullptr; i++) { \
|
||||
if (_all_method_symbols[i] == old_reference) { \
|
||||
_all_method_symbols[i] = (void *) to; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
void _overwrite_calls(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_calls_manual(start, target) _overwrite_calls(__FILE__, __LINE__, start, target)
|
||||
#define overwrite_calls(start, target) \
|
||||
{ \
|
||||
_setup_fancy_overwrite(start, start, target); \
|
||||
start = (start##_t) overwrite_calls_manual((void *) start, (void *) _helper_for_##target); \
|
||||
overwrite_calls_manual((void *) start, (void *) _helper_for_##target); \
|
||||
_update_references(start, _helper_for_##target); \
|
||||
}
|
||||
|
||||
// Replace All Calls To Virtual Method start With target
|
||||
#define _check_if_method_is_new(name) \
|
||||
{ \
|
||||
if (!__is_new_method_##name()) { \
|
||||
ERR("Method Is Not \"New\""); \
|
||||
} \
|
||||
}
|
||||
#define overwrite_virtual_calls(start, target) \
|
||||
{ \
|
||||
_check_if_method_is_new(start); \
|
||||
_setup_fancy_overwrite(*start##_vtable_addr, start, target); \
|
||||
overwrite_calls_manual((void *) *start##_vtable_addr, (void *) _helper_for_##target); \
|
||||
}
|
||||
|
||||
// Replace All Calls To start With target Within [to, from)
|
||||
void _overwrite_calls_within(const char *file, int line, void *from, void *to, void *start, void *target);
|
||||
#define overwrite_calls_within_manual(from, to, start, target) _overwrite_calls_within(__FILE__, __LINE__, from, to, start, target)
|
||||
#define overwrite_calls_within(from, to, start, target) \
|
||||
{ \
|
||||
start##_t type_check = target; \
|
||||
overwrite_calls_within_manual(from, to, (void *) start, (void *) type_check); \
|
||||
}
|
||||
#define overwrite_calls_within(from, to, start, target) _overwrite_calls_within(__FILE__, __LINE__, from, to, start, target)
|
||||
|
||||
// Get Target Address From BL Instruction
|
||||
void *extract_from_bl_instruction(unsigned char *from);
|
||||
|
||||
// Replace Method start With target
|
||||
void _overwrite(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_manual(start, target) _overwrite(__FILE__, __LINE__, (void *) start, (void *) target)
|
||||
#define overwrite(start, target) \
|
||||
{ \
|
||||
start##_t type_check = target; \
|
||||
overwrite_manual((void *) start, (void *) type_check); \
|
||||
}
|
||||
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, (void *) start, (void *) target)
|
||||
|
||||
// Patch Instruction
|
||||
void _patch(const char *file, int line, void *start, unsigned char patch[4]);
|
||||
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch)
|
||||
|
||||
// Patch 4 Bytes Of Data
|
||||
void _patch_address(const char *file, int line, void *start, void *target);
|
||||
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, (void *) start, (void *) target)
|
||||
|
||||
// Patch VTable Entry
|
||||
// This does not affect sub-classes.
|
||||
#define patch_vtable(start, target) \
|
||||
{ \
|
||||
start##_t type_check = target; \
|
||||
patch_address(start##_vtable_addr, (void *) type_check); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -77,7 +77,7 @@ static int _overwrite_calls_within_internal(const char *file, int line, void *fr
|
|||
#define TEXT_END 0x1020c0
|
||||
// Overwrite All B(L) Intrusctions That Target The Specified Address
|
||||
#define NO_CALLSITE_ERROR "(%s:%i) Unable To Find Callsites For %p"
|
||||
void *_overwrite_calls(const char *file, int line, void *start, void *target) {
|
||||
void _overwrite_calls(const char *file, int line, void *start, void *target) {
|
||||
// Add New Target To Code Block
|
||||
void *code_block = update_code_block(target);
|
||||
|
||||
|
@ -93,9 +93,6 @@ void *_overwrite_calls(const char *file, int line, void *start, void *target) {
|
|||
if (found < 1) {
|
||||
ERR(NO_CALLSITE_ERROR, file, line, start);
|
||||
}
|
||||
|
||||
// Return
|
||||
return code_block;
|
||||
}
|
||||
void _overwrite_calls_within(const char *file, int line, void *from /* inclusive */, void *to /* exclusive */, void *target, void *replacement) {
|
||||
// Add New Target To Code Block
|
||||
|
|
|
@ -21,14 +21,12 @@ void set_and_print_env(const char *name, const char *value) {
|
|||
// Safe execvpe()
|
||||
#define handle_environmental_variable(var) \
|
||||
{ \
|
||||
const char *full_var = is_arm_component ? MCPI_LD_VARIABLE_PREFIX var : MCPI_ORIGINAL_LD_VARIABLE_PREFIX var; \
|
||||
const char *full_var = is_arm_component ? "MCPI_ARM_" var : "MCPI_NATIVE_" var; \
|
||||
const char *var_value = getenv(full_var); \
|
||||
set_and_print_env(var, var_value); \
|
||||
}
|
||||
void setup_exec_environment(int is_arm_component) {
|
||||
if (is_arm_component || getenv(MCPI_ORIGINAL_LD_VARIABLES_PRESERVED_ENV) != NULL) {
|
||||
for_each_special_environmental_variable(handle_environmental_variable);
|
||||
}
|
||||
for_each_special_environmental_variable(handle_environmental_variable);
|
||||
}
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
|
||||
// Log
|
||||
|
@ -66,8 +64,13 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_
|
|||
close(output_pipe[1]);
|
||||
|
||||
// Setup stderr
|
||||
reborn_lock_debug(); // Lock Released On Process Exit
|
||||
dup2(reborn_get_debug_fd(), STDERR_FILENO);
|
||||
if (getenv("MCPI_DEBUG") == NULL) {
|
||||
const char *log_file_fd_env = getenv("MCPI_LOG_FILE_FD");
|
||||
if (log_file_fd_env == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
dup2(atoi(log_file_fd_env), STDERR_FILENO);
|
||||
}
|
||||
|
||||
// Setup Environment
|
||||
setup_exec_environment(0);
|
||||
|
@ -86,7 +89,7 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_
|
|||
char buf[BUFFER_SIZE];
|
||||
size_t position = 0;
|
||||
ssize_t bytes_read = 0;
|
||||
while ((bytes_read = read(output_pipe[0], buf, BUFFER_SIZE)) > 0) {
|
||||
while ((bytes_read = read(output_pipe[0], (void *) buf, BUFFER_SIZE)) > 0) {
|
||||
// Grow Output If Needed
|
||||
size_t needed_size = position + bytes_read;
|
||||
if (needed_size > size) {
|
||||
|
|
|
@ -1,73 +1,23 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <libreborn/log.h>
|
||||
#include <libreborn/exec.h>
|
||||
|
||||
// Debug Tag
|
||||
const char *reborn_debug_tag = "";
|
||||
|
||||
// Log File
|
||||
static int log_fd = -1;
|
||||
int reborn_get_log_fd() {
|
||||
if (log_fd >= 0) {
|
||||
return log_fd;
|
||||
}
|
||||
// Open Log File
|
||||
const char *file = getenv(MCPI_LOG_ENV);
|
||||
if (file == NULL) {
|
||||
file = "/dev/null";
|
||||
}
|
||||
log_fd = open(file, O_WRONLY | O_APPEND | O_CLOEXEC);
|
||||
// Check FD
|
||||
if (log_fd < 0) {
|
||||
ERR("Unable To Open Log: %s", strerror(errno));
|
||||
}
|
||||
// Return
|
||||
return reborn_get_log_fd();
|
||||
}
|
||||
void reborn_lock_log() {
|
||||
int ret = flock(reborn_get_log_fd(), LOCK_EX);
|
||||
if (ret != 0) {
|
||||
ERR("Unable To Lock Log: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
void reborn_unlock_log() {
|
||||
int ret = flock(reborn_get_log_fd(), LOCK_UN);
|
||||
if (ret != 0) {
|
||||
ERR("Unable To Unlock Log: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
__attribute__((destructor)) void reborn_close_log() {
|
||||
if (log_fd >= 0) {
|
||||
close(log_fd);
|
||||
log_fd = -1;
|
||||
}
|
||||
}
|
||||
void reborn_set_log(const char *file) {
|
||||
// Close Current Log
|
||||
reborn_close_log();
|
||||
// Set Variable
|
||||
set_and_print_env(MCPI_LOG_ENV, file);
|
||||
}
|
||||
|
||||
// Debug Logging
|
||||
static int should_print_debug_to_stderr() {
|
||||
return getenv(MCPI_DEBUG_ENV) != NULL;
|
||||
}
|
||||
// Debug FD
|
||||
int reborn_get_debug_fd() {
|
||||
return should_print_debug_to_stderr() ? STDERR_FILENO : reborn_get_log_fd();
|
||||
}
|
||||
void reborn_lock_debug() {
|
||||
if (!should_print_debug_to_stderr()) {
|
||||
reborn_lock_log();
|
||||
if (getenv("MCPI_DEBUG") != NULL) {
|
||||
return STDERR_FILENO;
|
||||
} else {
|
||||
static int debug_fd = -1;
|
||||
if (debug_fd == -1) {
|
||||
const char *log_file_fd_env = getenv("MCPI_LOG_FILE_FD");
|
||||
if (log_file_fd_env == NULL) {
|
||||
return -1;
|
||||
}
|
||||
debug_fd = atoi(log_file_fd_env);
|
||||
}
|
||||
return debug_fd;
|
||||
}
|
||||
}
|
||||
void reborn_unlock_debug() {
|
||||
if (!should_print_debug_to_stderr()) {
|
||||
reborn_unlock_log();
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ if(BUILD_MEDIA_LAYER_CORE)
|
|||
add_subdirectory(core)
|
||||
endif()
|
||||
|
||||
# Add Trampoline
|
||||
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE OR BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(trampoline)
|
||||
# Add Proxy
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY OR BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(proxy)
|
||||
endif()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <media-layer/internal.h>
|
||||
#include <media-layer/core.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// SDL Is Replaced With GLFW
|
||||
|
||||
|
|
|
@ -435,15 +435,13 @@ static void glfw_controller_look(float x, float y) {
|
|||
verify_controller_axis_value(y, CONTROLLER_LOOK_AXIS_THRESHOLD);
|
||||
|
||||
// Send Event
|
||||
if (is_interactable) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.x = last_mouse_x;
|
||||
event.motion.y = last_mouse_y;
|
||||
event.motion.xrel = x * CONTROLLER_LOOK_AXIS_SENSITIVITY;
|
||||
event.motion.yrel = y * CONTROLLER_LOOK_AXIS_SENSITIVITY;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
SDL_Event event;
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.x = last_mouse_x;
|
||||
event.motion.y = last_mouse_y;
|
||||
event.motion.xrel = x * CONTROLLER_LOOK_AXIS_SENSITIVITY;
|
||||
event.motion.yrel = y * CONTROLLER_LOOK_AXIS_SENSITIVITY;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Internal Methods
|
||||
// Internal Methods (Not Handled By Media Layer Proxy)
|
||||
|
||||
__attribute__((visibility("internal"))) void _media_handle_SDL_PollEvent();
|
||||
__attribute__((visibility("internal"))) void _media_handle_SDL_Quit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
project(media-layer-proxy)
|
||||
|
||||
# Configuration
|
||||
set(MEDIA_LAYER_PROXY_SRC src/common/common.c src/media-layer-core.c) # Media Layer Proxy Source
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
list(APPEND MEDIA_LAYER_PROXY_SRC src/GLESv1_CM.c)
|
||||
endif()
|
||||
|
||||
# Build
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
# Build Media Layer Proxy Client
|
||||
add_executable(media-layer-proxy-client src/client/client.cpp ${MEDIA_LAYER_PROXY_SRC})
|
||||
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-util media-layer-core GLESv1_CM)
|
||||
target_compile_definitions(media-layer-proxy-client PRIVATE -DMEDIA_LAYER_PROXY_CLIENT)
|
||||
# Install
|
||||
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}")
|
||||
elseif(BUILD_ARM_COMPONENTS)
|
||||
# Build Media Layer Proxy Server
|
||||
add_library(media-layer-core SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC} $<TARGET_OBJECTS:media-layer-extras>)
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-util)
|
||||
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_PROXY_SERVER)
|
||||
# Install
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,107 @@
|
|||
#include <vector>
|
||||
#include <cerrno>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <sys/prctl.h>
|
||||
#include <csignal>
|
||||
#include <exception>
|
||||
|
||||
#include "../common/common.h"
|
||||
|
||||
// Store Handlers
|
||||
#define MAX_HANDLERS 100
|
||||
static proxy_handler_t handlers[MAX_HANDLERS];
|
||||
void _add_handler(unsigned char unique_id, proxy_handler_t handler) {
|
||||
if (unique_id >= MAX_HANDLERS) {
|
||||
PROXY_ERR("ID Too Big: %i", (int) unique_id);
|
||||
}
|
||||
if (handlers[unique_id] != NULL) {
|
||||
PROXY_ERR("Duplicate ID: %i", (int) unique_id);
|
||||
}
|
||||
handlers[unique_id] = handler;
|
||||
}
|
||||
|
||||
// Store Parent PID
|
||||
static int parent_is_alive = 1;
|
||||
static void sigusr1_handler(__attribute__((unused)) int sig) {
|
||||
// Mark Parent As Dead
|
||||
parent_is_alive = 0;
|
||||
}
|
||||
// Check State Of Proxy And Exit If Invalid
|
||||
void _check_proxy_state() {
|
||||
// Check Server State
|
||||
if (!parent_is_alive) {
|
||||
void_write_cache(); // Parent Is Dead, No Reason To Send A Dead Process Data
|
||||
PROXY_ERR("Server Terminated");
|
||||
}
|
||||
}
|
||||
|
||||
// Exit Handler
|
||||
static volatile int exit_requested = 0;
|
||||
static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
// Request Exit
|
||||
exit_requested = 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, NULL);
|
||||
|
||||
// Send Signal On Parent Death To Interrupt Connection Read/Write And Exit
|
||||
prctl(PR_SET_PDEATHSIG, SIGUSR1);
|
||||
struct sigaction sa;
|
||||
memset((void *) &sa, 0, sizeof (struct sigaction));
|
||||
sa.sa_flags = SA_NOCLDSTOP;
|
||||
sa.sa_handler = &sigusr1_handler;
|
||||
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
|
||||
PROXY_ERR("Unable To Install Signal Handler: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Get Connection
|
||||
if (argc != 3) {
|
||||
PROXY_ERR("Invalid Arguments");
|
||||
}
|
||||
char *read_str = argv[1];
|
||||
char *write_str = argv[2];
|
||||
set_connection(atoi(read_str), atoi(write_str));
|
||||
PROXY_INFO("Connected");
|
||||
|
||||
// Send Connection Message
|
||||
write_string((char *) CONNECTED_MSG);
|
||||
flush_write_cache();
|
||||
|
||||
// Loop
|
||||
int running = is_connection_open();
|
||||
while (running && !exit_requested) {
|
||||
unsigned char unique_id = read_byte();
|
||||
if (handlers[unique_id] != NULL) {
|
||||
// Run Method
|
||||
handlers[unique_id]();
|
||||
// Check If Connection Is Still Open
|
||||
if (!is_connection_open()) {
|
||||
// Exit
|
||||
running = 0;
|
||||
} else {
|
||||
// Flush Write Cache
|
||||
flush_write_cache();
|
||||
}
|
||||
} else {
|
||||
PROXY_ERR("Invalid Method ID: %i", (int) unique_id);
|
||||
}
|
||||
}
|
||||
if (is_connection_open()) {
|
||||
close_connection();
|
||||
}
|
||||
|
||||
// Exit
|
||||
PROXY_INFO("Stopped");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#define PROXY_LOG_TAG "(Media Layer Proxy Client) "
|
||||
|
||||
typedef void (*proxy_handler_t)();
|
||||
__attribute__((visibility("internal"))) void _add_handler(unsigned char id, proxy_handler_t handler);
|
||||
|
||||
#define CALL(unique_id, name, return_type, args) \
|
||||
static void _run_##name (); \
|
||||
__attribute__((constructor)) static void _init_##name() { \
|
||||
_add_handler(unique_id, _run_##name); \
|
||||
} \
|
||||
static void _run_##name ()
|
|
@ -0,0 +1,245 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
// Safely Send/Receive Data From The Connection
|
||||
#define CHECK_CONNECTION() \
|
||||
{ \
|
||||
_check_proxy_state(); \
|
||||
if (!is_connection_open()) { \
|
||||
PROXY_ERR("Attempting To Access Closed Connection"); \
|
||||
} \
|
||||
}
|
||||
// Buffer Reads
|
||||
static void *_read_cache = NULL;
|
||||
__attribute__((destructor)) static void _free_read_cache() {
|
||||
if (_read_cache != NULL) {
|
||||
free(_read_cache);
|
||||
}
|
||||
}
|
||||
static size_t _read_cache_size = 0;
|
||||
static size_t _read_cache_actual_size = 0;
|
||||
static size_t _read_cache_position = 0;
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
void safe_read(void *buf, size_t len) {
|
||||
// Check Data
|
||||
if (buf == NULL) {
|
||||
PROXY_ERR("Attempting To Read Into NULL Buffer");
|
||||
}
|
||||
// Setup
|
||||
size_t to_read = len;
|
||||
// Copy From Read Buffer
|
||||
if (_read_cache != NULL && _read_cache_size > 0) {
|
||||
char *read_cache = (void *) (((unsigned char *) _read_cache) + _read_cache_position);
|
||||
size_t read_cache_size = _read_cache_size - _read_cache_position;
|
||||
if (read_cache_size > 0) {
|
||||
size_t to_copy = min(to_read, read_cache_size);
|
||||
memcpy(buf, read_cache, to_copy);
|
||||
to_read -= to_copy;
|
||||
_read_cache_position += to_copy;
|
||||
}
|
||||
}
|
||||
// Check If Done
|
||||
if (to_read < 1) {
|
||||
return;
|
||||
}
|
||||
if (_read_cache_position < _read_cache_size) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
// Flush Write Cache
|
||||
flush_write_cache();
|
||||
// Read Remaining Data
|
||||
size_t to_read_to_cache = 0;
|
||||
while (to_read_to_cache < 1) {
|
||||
CHECK_CONNECTION();
|
||||
int bytes_available;
|
||||
if (ioctl(get_connection_read(), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
}
|
||||
to_read_to_cache = max((size_t) bytes_available, to_read);
|
||||
}
|
||||
// Resize Buffer
|
||||
_read_cache_position = 0;
|
||||
_read_cache_size = to_read_to_cache;
|
||||
if (_read_cache == NULL) {
|
||||
_read_cache_actual_size = _read_cache_size;
|
||||
_read_cache = malloc(_read_cache_actual_size);
|
||||
} else if (_read_cache_size > _read_cache_actual_size) {
|
||||
_read_cache_actual_size = _read_cache_size;
|
||||
_read_cache = realloc(_read_cache, _read_cache_actual_size);
|
||||
}
|
||||
ALLOC_CHECK(_read_cache);
|
||||
// Read Into Buffer
|
||||
while (to_read_to_cache > 0) {
|
||||
CHECK_CONNECTION();
|
||||
ssize_t x = read(get_connection_read(), (void *) (((unsigned char *) _read_cache) + (_read_cache_size - to_read_to_cache)), to_read_to_cache);
|
||||
if (x == -1 && errno != EINTR) {
|
||||
PROXY_ERR("Failed Reading Data To Connection: %s", strerror(errno));
|
||||
}
|
||||
to_read_to_cache -= x;
|
||||
}
|
||||
// Copy Remaining Data
|
||||
safe_read((void *) (((unsigned char *) buf) + (len - to_read)), to_read);
|
||||
}
|
||||
// Buffer Writes
|
||||
static void *_write_cache = NULL;
|
||||
__attribute__((destructor)) static void _free_write_cache() {
|
||||
if (_write_cache != NULL) {
|
||||
free(_write_cache);
|
||||
}
|
||||
}
|
||||
static size_t _write_cache_size = 0;
|
||||
static size_t _write_cache_position = 0;
|
||||
void safe_write(void *buf, size_t len) {
|
||||
// Check Data
|
||||
if (buf == NULL) {
|
||||
PROXY_ERR("Attempting To Send NULL Data");
|
||||
}
|
||||
// Expand Write Cache If Needed
|
||||
size_t needed_size = _write_cache_position + len;
|
||||
if (_write_cache == NULL) {
|
||||
_write_cache_size = needed_size;
|
||||
_write_cache = malloc(_write_cache_size);
|
||||
} else if (needed_size > _write_cache_size) {
|
||||
_write_cache_size = needed_size;
|
||||
_write_cache = realloc(_write_cache, _write_cache_size);
|
||||
}
|
||||
ALLOC_CHECK(_write_cache);
|
||||
// Copy Data
|
||||
memcpy((void *) (((unsigned char *) _write_cache) + _write_cache_position), buf, len);
|
||||
// Advance Position
|
||||
_write_cache_position += len;
|
||||
}
|
||||
// Flush Write Cache
|
||||
void flush_write_cache() {
|
||||
// Check Cache
|
||||
if (_write_cache == NULL || _write_cache_position < 1) {
|
||||
// Nothing To Write
|
||||
return;
|
||||
}
|
||||
// Check Connection
|
||||
if (!is_connection_open()) {
|
||||
// Connection Closed
|
||||
return;
|
||||
}
|
||||
// Write & Reset
|
||||
size_t to_write = _write_cache_position;
|
||||
size_t old_write_cache_position = _write_cache_position;
|
||||
_write_cache_position = 0;
|
||||
while (to_write > 0) {
|
||||
CHECK_CONNECTION();
|
||||
ssize_t x = write(get_connection_write(), (void *) (((unsigned char *) _write_cache) + (old_write_cache_position - to_write)), to_write);
|
||||
if (x == -1 && errno != EINTR) {
|
||||
PROXY_ERR("Failed Writing Data To Connection: %s", strerror(errno));
|
||||
}
|
||||
to_write -= x;
|
||||
}
|
||||
}
|
||||
void void_write_cache() {
|
||||
_write_cache_position = 0;
|
||||
}
|
||||
|
||||
// Read/Write 32-Bit Integers
|
||||
uint32_t read_int() {
|
||||
uint32_t ret = 0;
|
||||
safe_read((void *) &ret, sizeof (ret));
|
||||
return ret;
|
||||
}
|
||||
void write_int(uint32_t x) {
|
||||
safe_write((void *) &x, sizeof (x));
|
||||
}
|
||||
|
||||
// Read/Write Floats
|
||||
float read_float() {
|
||||
float ret = 0;
|
||||
safe_read((void *) &ret, sizeof (ret));
|
||||
return ret;
|
||||
}
|
||||
void write_float(float x) {
|
||||
safe_write((void *) &x, sizeof (x));
|
||||
}
|
||||
|
||||
// Read/Write Bytes
|
||||
unsigned char read_byte() {
|
||||
unsigned char ret = 0;
|
||||
safe_read((void *) &ret, sizeof (ret));
|
||||
return ret;
|
||||
}
|
||||
void write_byte(unsigned char x) {
|
||||
safe_write((void *) &x, sizeof (x));
|
||||
}
|
||||
|
||||
// Read/Write Strings
|
||||
char *read_string() {
|
||||
// Check NULL
|
||||
unsigned char is_null = read_byte();
|
||||
if (is_null) {
|
||||
return NULL;
|
||||
}
|
||||
// Allocate String
|
||||
unsigned char length = read_byte();
|
||||
char *str = malloc((size_t) length + 1);
|
||||
// Read String
|
||||
safe_read((void *) str, length);
|
||||
// Add Terminator
|
||||
str[length] = '\0';
|
||||
// Return String
|
||||
return strdup(str);
|
||||
}
|
||||
#define MAX_STRING_SIZE 256
|
||||
void write_string(const char *str) {
|
||||
unsigned char is_null = str == NULL;
|
||||
write_byte(is_null);
|
||||
if (!is_null) {
|
||||
int length = strlen(str);
|
||||
if (length > MAX_STRING_SIZE) {
|
||||
PROXY_ERR("Unable To Write String To Connection: Larger Than %i Bytes", MAX_STRING_SIZE);
|
||||
}
|
||||
write_byte((unsigned char) length);
|
||||
safe_write((void *) str, length);
|
||||
}
|
||||
}
|
||||
|
||||
// Close Connection
|
||||
void close_connection() {
|
||||
// Flush Write Cache
|
||||
flush_write_cache();
|
||||
// Close
|
||||
int state_changed = 0;
|
||||
if (get_connection_read() != -1) {
|
||||
close(get_connection_read());
|
||||
state_changed = 1;
|
||||
}
|
||||
if (get_connection_write() != -1) {
|
||||
close(get_connection_write());
|
||||
state_changed = 1;
|
||||
}
|
||||
set_connection(-1, -1);
|
||||
if (state_changed) {
|
||||
PROXY_INFO("Connection Closed");
|
||||
}
|
||||
}
|
||||
// Check If Connection Is Open
|
||||
int is_connection_open() {
|
||||
return get_connection_read() != -1 && get_connection_write() != -1;
|
||||
}
|
||||
// Pipe
|
||||
static int _read = -1;
|
||||
static int _write = -1;
|
||||
// Set Pipe
|
||||
void set_connection(int read, int write) {
|
||||
_read = read;
|
||||
_write = write;
|
||||
}
|
||||
// Get Pipe
|
||||
int get_connection_read() {
|
||||
return _read;
|
||||
}
|
||||
int get_connection_write() {
|
||||
return _write;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER != __LITTLE_ENDIAN
|
||||
#error "Only Little Endian Is Supported"
|
||||
#endif
|
||||
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
#include "../server/server.h"
|
||||
#elif defined(MEDIA_LAYER_PROXY_CLIENT)
|
||||
#include "../client/client.h"
|
||||
#else
|
||||
#error "Invalid Configuration"
|
||||
#endif
|
||||
|
||||
#define CONNECTED_MSG "Connected"
|
||||
|
||||
#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
|
||||
__attribute__((visibility("internal"))) void safe_read(void *buf, size_t len);
|
||||
__attribute__((visibility("internal"))) void safe_write(void *buf, size_t len);
|
||||
__attribute__((visibility("internal"))) void flush_write_cache();
|
||||
__attribute__((visibility("internal"))) void void_write_cache();
|
||||
|
||||
// Read/Write 32-Bit Integers
|
||||
__attribute__((visibility("internal"))) uint32_t read_int();
|
||||
__attribute__((visibility("internal"))) void write_int(uint32_t x);
|
||||
|
||||
// Read/Write Bytes
|
||||
__attribute__((visibility("internal"))) unsigned char read_byte();
|
||||
__attribute__((visibility("internal"))) void write_byte(unsigned char x);
|
||||
|
||||
// Read/Write Floats
|
||||
__attribute__((visibility("internal"))) float read_float();
|
||||
__attribute__((visibility("internal"))) void write_float(float x);
|
||||
|
||||
// Read/Write Strings
|
||||
__attribute__((visibility("internal"))) char *read_string(); // Remember To free()
|
||||
__attribute__((visibility("internal"))) void write_string(const char *str);
|
||||
|
||||
// Manipulate Connection
|
||||
__attribute__((visibility("internal"))) void set_connection(int read, int write);
|
||||
__attribute__((visibility("internal"))) int get_connection_read();
|
||||
__attribute__((visibility("internal"))) int get_connection_write();
|
||||
__attribute__((visibility("internal"))) void close_connection();
|
||||
__attribute__((visibility("internal"))) int is_connection_open();
|
||||
|
||||
// Check State Of Proxy And Exit If Invalid
|
||||
__attribute__((visibility("internal"))) void _check_proxy_state();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,354 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <media-layer/core.h>
|
||||
#include <media-layer/audio.h>
|
||||
#include <media-layer/internal.h>
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
// SDL Functions
|
||||
|
||||
CALL(0, SDL_Init, int, (uint32_t flags)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int(flags);
|
||||
|
||||
// Get Return Value
|
||||
int32_t ret = (int32_t) read_int();
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
|
||||
// Return
|
||||
return ret;
|
||||
#else
|
||||
uint32_t flags = read_int();
|
||||
// Run
|
||||
int ret = SDL_Init(flags);
|
||||
// Return Values
|
||||
write_int((uint32_t) ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(1, SDL_PollEvent, int, (SDL_Event *event)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// No Arguments
|
||||
|
||||
// Get Return Value
|
||||
int32_t ret = (int32_t) read_int();
|
||||
if (ret) {
|
||||
safe_read((void *) event, sizeof (SDL_Event));
|
||||
}
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
|
||||
// Return Value
|
||||
return ret;
|
||||
#else
|
||||
SDL_Event event;
|
||||
// Run
|
||||
int ret = (int32_t) SDL_PollEvent(&event);
|
||||
// Return Values
|
||||
write_int(ret);
|
||||
if (ret) {
|
||||
safe_write((void *) &event, sizeof (SDL_Event));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(2, SDL_PushEvent, int, (SDL_Event *event)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
safe_write((void *) event, sizeof (SDL_Event));
|
||||
|
||||
// Get Return Value
|
||||
int32_t ret = (int32_t) read_int();
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
|
||||
// Return Value
|
||||
return ret;
|
||||
#else
|
||||
SDL_Event event;
|
||||
safe_read((void *) &event, sizeof (SDL_Event));
|
||||
// Run
|
||||
int ret = SDL_PushEvent(&event);
|
||||
// Return Value
|
||||
write_int((uint32_t) ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_string((char *) title);
|
||||
write_string((char *) icon);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
char *title = read_string();
|
||||
char *icon = read_string();
|
||||
// Run
|
||||
SDL_WM_SetCaption(title, icon);
|
||||
// Free
|
||||
free(title);
|
||||
free(icon);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(4, media_toggle_fullscreen, void, ()) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
// Run
|
||||
media_toggle_fullscreen();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int((uint32_t) mode);
|
||||
|
||||
// Get Return Value
|
||||
SDL_GrabMode ret = (SDL_GrabMode) read_int();
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
|
||||
// Return Value
|
||||
return ret;
|
||||
#else
|
||||
SDL_GrabMode mode = (SDL_GrabMode) read_int();
|
||||
// Run
|
||||
SDL_GrabMode ret = SDL_WM_GrabInput(mode);
|
||||
// Return Value
|
||||
write_int((uint32_t) ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(6, SDL_ShowCursor, int, (int32_t toggle)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int((uint32_t) toggle);
|
||||
|
||||
// Get Return Value
|
||||
int32_t ret = (int32_t) read_int();
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
|
||||
// Return Value
|
||||
return ret;
|
||||
#else
|
||||
int mode = (int) read_int();
|
||||
// Run
|
||||
int ret = SDL_ShowCursor(mode);
|
||||
// Return Value
|
||||
write_int((uint32_t) ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(8, media_swap_buffers, void, ()) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
flush_write_cache();
|
||||
#else
|
||||
// Run
|
||||
media_swap_buffers();
|
||||
#endif
|
||||
}
|
||||
|
||||
// This Method May Be Called In A Situation Where The Proxy Is Disconnected
|
||||
CALL(9, media_cleanup, void, ()) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Check Connection
|
||||
if (is_connection_open()) {
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
// Block Until Cleanup Is Complete
|
||||
flush_write_cache();
|
||||
read_byte();
|
||||
// Close The Connection
|
||||
close_connection();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
}
|
||||
#else
|
||||
// Run
|
||||
media_cleanup();
|
||||
// Confirm Cleanup
|
||||
write_byte(0);
|
||||
// Close The Connection
|
||||
close_connection();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(10, media_get_framebuffer_size, void, (int *width, int *height)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Get Return Values
|
||||
*width = (int) read_int();
|
||||
*height = (int) read_int();
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
int width;
|
||||
int height;
|
||||
// Run
|
||||
media_get_framebuffer_size(&width, &height);
|
||||
// Return Values
|
||||
write_int((uint32_t) width);
|
||||
write_int((uint32_t) height);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_float(volume);
|
||||
write_float(x);
|
||||
write_float(y);
|
||||
write_float(z);
|
||||
write_float(yaw);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
float volume = read_float();
|
||||
float x = read_float();
|
||||
float y = read_float();
|
||||
float z = read_float();
|
||||
float yaw = read_float();
|
||||
// Run
|
||||
media_audio_update(volume, x, y, z, yaw);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_string(source);
|
||||
write_string(name);
|
||||
write_float(x);
|
||||
write_float(y);
|
||||
write_float(z);
|
||||
write_float(pitch);
|
||||
write_float(volume);
|
||||
write_int(is_ui);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
char *source = read_string();
|
||||
char *name = read_string();
|
||||
float x = read_float();
|
||||
float y = read_float();
|
||||
float z = read_float();
|
||||
float pitch = read_float();
|
||||
float volume = read_float();
|
||||
int is_ui = read_int();
|
||||
// Run
|
||||
media_audio_play(source, name, x, y, z, pitch, volume, is_ui);
|
||||
// Free
|
||||
free(source);
|
||||
free(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(62, media_set_interactable, void, (int is_interactable)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int(is_interactable);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
int is_interactable = read_int();
|
||||
// Run
|
||||
media_set_interactable(is_interactable);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(63, media_disable_vsync, void, ()) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
// Run
|
||||
media_disable_vsync();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_int(enabled);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
int enabled = read_int();
|
||||
// Run
|
||||
media_set_raw_mouse_motion_enabled(enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(66, media_force_egl, void, ()) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
// Run
|
||||
media_force_egl();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <csignal>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <fstream>
|
||||
|
||||
#include <media-layer/core.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
|
||||
// Track Client State
|
||||
static int _client_is_alive = 0;
|
||||
static int _client_status = 0;
|
||||
static void update_client_state(int is_alive, int status) {
|
||||
_client_is_alive = is_alive;
|
||||
_client_status = status;
|
||||
}
|
||||
// Check State Of Proxy And Exit If Invalid
|
||||
void _check_proxy_state() {
|
||||
// Check Client State
|
||||
if (!_client_is_alive) {
|
||||
void_write_cache(); // Child Is Dead, No Reason To Send A Dead Process Data
|
||||
char *exit_status = NULL;
|
||||
get_exit_status_string(_client_status, &exit_status);
|
||||
PROXY_ERR("Client Terminated%s", exit_status);
|
||||
}
|
||||
}
|
||||
|
||||
// Start Proxy Client
|
||||
static pid_t _client_pid;
|
||||
static void sigchld_handler(__attribute__((unused)) int sig) {
|
||||
// Track
|
||||
int status;
|
||||
|
||||
// Reap
|
||||
int saved_errno = errno;
|
||||
// Only waitpid() Proxy Client, Other Sub-Processes Are Handled By pclose()
|
||||
if (waitpid(_client_pid, &status, WNOHANG) == _client_pid) {
|
||||
// Handle Client Death
|
||||
untrack_child(_client_pid);
|
||||
update_client_state(0, status);
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
static void start_media_layer_proxy_client(int read, int write) {
|
||||
// Reap Children
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_NOCLDSTOP;
|
||||
sa.sa_handler = &sigchld_handler;
|
||||
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
|
||||
PROXY_ERR("Unable To Install Signal Handler: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Fork And Start
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
PROXY_ERR("Unable To Launch Client: %s", strerror(errno));
|
||||
} 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);
|
||||
char *write_str = NULL;
|
||||
safe_asprintf(&write_str, "%i", write);
|
||||
const char *argv[] = {"media-layer-proxy-client", read_str, write_str, NULL};
|
||||
|
||||
// Setup Environment
|
||||
setup_exec_environment(0);
|
||||
|
||||
// Run
|
||||
safe_execvpe(argv, (const char *const *) environ);
|
||||
} else {
|
||||
// Parent Process
|
||||
_client_pid = ret;
|
||||
track_child(_client_pid);
|
||||
}
|
||||
update_client_state(1, 0);
|
||||
}
|
||||
|
||||
// Maximize Pipe Buffer Size
|
||||
static void maximize_pipe_fd_size(int fd) {
|
||||
// Read Maximum Pipe Size
|
||||
std::ifstream max_size_file("/proc/sys/fs/pipe-max-size");
|
||||
if (!max_size_file.good()) {
|
||||
PROXY_ERR("%s", "Unable To Open Maximum Pipe Size File");
|
||||
}
|
||||
// Read One Line
|
||||
int max_size;
|
||||
std::string line;
|
||||
if (std::getline(max_size_file, line) && line.size() > 0) {
|
||||
max_size = std::stoi(line);
|
||||
} else {
|
||||
PROXY_ERR("%s", "Unable To Read Maximum Pipe Size File");
|
||||
}
|
||||
// Close
|
||||
max_size_file.close();
|
||||
// Set Maximum Pipe Size
|
||||
errno = 0;
|
||||
if (fcntl(fd, F_SETPIPE_SZ, max_size) < max_size) {
|
||||
PROXY_ERR("Unable To Set Maximum Pipe Size: %s", errno != 0 ? strerror(errno) : "Unknown Error");
|
||||
}
|
||||
}
|
||||
static void maximize_pipe_size(int pipe[2]) {
|
||||
maximize_pipe_fd_size(pipe[0]);
|
||||
maximize_pipe_fd_size(pipe[1]);
|
||||
}
|
||||
|
||||
// Start Server
|
||||
static int loaded = 0;
|
||||
__attribute__((constructor)) void media_ensure_loaded() {
|
||||
if (!loaded) {
|
||||
loaded = 1;
|
||||
|
||||
// Log
|
||||
PROXY_INFO("Starting...");
|
||||
|
||||
// Create Connection
|
||||
int server_to_client_pipe[2];
|
||||
safe_pipe2(server_to_client_pipe, 0);
|
||||
maximize_pipe_size(server_to_client_pipe);
|
||||
int client_to_server_pipe[2];
|
||||
safe_pipe2(client_to_server_pipe, 0);
|
||||
maximize_pipe_size(client_to_server_pipe);
|
||||
// Set Connection
|
||||
set_connection(client_to_server_pipe[0], server_to_client_pipe[1]);
|
||||
|
||||
// Start Client
|
||||
start_media_layer_proxy_client(server_to_client_pipe[0], client_to_server_pipe[1]);
|
||||
|
||||
// Wait For Connection Message
|
||||
char *str = read_string();
|
||||
if (strcmp(str, CONNECTED_MSG) == 0) {
|
||||
PROXY_INFO("Connected");
|
||||
} else {
|
||||
PROXY_ERR("Unable To Connect");
|
||||
}
|
||||
// Free
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign Unique ID To Function
|
||||
static std::unordered_map<std::string, unsigned char> &get_unique_ids() {
|
||||
static std::unordered_map<std::string, unsigned char> unique_ids;
|
||||
return unique_ids;
|
||||
}
|
||||
void _assign_unique_id(const char *name, unsigned char id) {
|
||||
get_unique_ids()[name] = id;
|
||||
}
|
||||
unsigned char _get_unique_id(const char *name) {
|
||||
return get_unique_ids()[name]; // Assume ID Exists
|
||||
}
|
||||
|
||||
// Proxy Call Functions
|
||||
void _start_proxy_call(unsigned char call_id) {
|
||||
// Start Call
|
||||
write_byte(call_id);
|
||||
}
|
||||
void end_proxy_call() {
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#define PROXY_LOG_TAG "(Media Layer Proxy Server) "
|
||||
|
||||
// Assign Unique ID To Function
|
||||
__attribute__((visibility("internal"))) void _assign_unique_id(const char *name, unsigned char id);
|
||||
__attribute__((visibility("internal"))) unsigned char _get_unique_id(const char *name);
|
||||
|
||||
// Must Call After Every Call
|
||||
__attribute__((visibility("internal"))) void _start_proxy_call(unsigned char call_id);
|
||||
#define start_proxy_call() \
|
||||
{ \
|
||||
static int _loaded_id = 0; \
|
||||
static unsigned char _call_id; \
|
||||
if (!_loaded_id) { \
|
||||
_loaded_id = 1; \
|
||||
_call_id = _get_unique_id(__func__); \
|
||||
} \
|
||||
_start_proxy_call(_call_id); \
|
||||
}
|
||||
__attribute__((visibility("internal"))) void end_proxy_call();
|
||||
|
||||
#define CALL(unique_id, name, return_type, args) \
|
||||
__attribute__((constructor)) static void _init_##name() { \
|
||||
_assign_unique_id(#name, unique_id); \
|
||||
} \
|
||||
return_type name args
|
|
@ -1,30 +0,0 @@
|
|||
project(media-layer-trampoline)
|
||||
|
||||
# Configuration
|
||||
set(MEDIA_LAYER_TRAMPOLINE_SRC src/media-layer-core.c) # Media Layer Trampoline Source
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
list(APPEND MEDIA_LAYER_TRAMPOLINE_SRC src/GLESv1_CM.c)
|
||||
endif()
|
||||
|
||||
# Build
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
# Host Component
|
||||
add_library(media-layer-trampoline src/host/host.c ${MEDIA_LAYER_TRAMPOLINE_SRC})
|
||||
target_link_libraries(media-layer-trampoline reborn-util media-layer-core)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
target_link_libraries(media-layer-trampoline GLESv1_CM)
|
||||
endif()
|
||||
target_compile_definitions(media-layer-trampoline PRIVATE -DMEDIA_LAYER_TRAMPOLINE_HOST)
|
||||
# Install
|
||||
install(TARGETS media-layer-trampoline DESTINATION "${MCPI_LIB_DIR}")
|
||||
elseif(BUILD_ARM_COMPONENTS)
|
||||
# Guest Component
|
||||
add_library(media-layer-core SHARED src/guest/guest.c ${MEDIA_LAYER_TRAMPOLINE_SRC} $<TARGET_OBJECTS:media-layer-extras>)
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-util)
|
||||
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_TRAMPOLINE_GUEST)
|
||||
# Install
|
||||
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
|
||||
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
|
@ -1,581 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <GLES/gl.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pname, (uint32_t) params);
|
||||
#else
|
||||
GLenum pname = next_int();
|
||||
GLfloat *params = next_ptr();
|
||||
// Run
|
||||
func(pname, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 'pointer' Is Only Supported As An Integer, Not As An Actual Pointer
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
#define CALL_GL_POINTER(unique_id, name) \
|
||||
CALL(unique_id, name, void, (GLint size, GLenum type, GLsizei stride, const void *pointer)) \
|
||||
trampoline(size, type, stride, (uint32_t) pointer); \
|
||||
}
|
||||
#else
|
||||
#define CALL_GL_POINTER(unique_id, name) \
|
||||
CALL(unique_id, name, unused, unused) \
|
||||
GLint size = next_int(); \
|
||||
GLenum type = next_int(); \
|
||||
GLsizei stride = next_int(); \
|
||||
const void *pointer = (const void *) (uint64_t) next_int(); \
|
||||
/* Run */ \
|
||||
func(size, type, stride, pointer); \
|
||||
}
|
||||
#endif
|
||||
|
||||
CALL_GL_POINTER(12, glVertexPointer)
|
||||
|
||||
CALL(13, glLineWidth, void, (GLfloat width))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, width));
|
||||
#else
|
||||
GLfloat width = next_float();
|
||||
// Run
|
||||
func(width);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(14, glBlendFunc, void, (GLenum sfactor, GLenum dfactor))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(sfactor, dfactor);
|
||||
#else
|
||||
GLenum sfactor = next_int();
|
||||
GLenum dfactor = next_int();
|
||||
// Run
|
||||
func(sfactor, dfactor);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(mode, first, count);
|
||||
#else
|
||||
GLenum mode = next_int();
|
||||
GLint first = next_int();
|
||||
GLsizei count = next_int();
|
||||
// Run
|
||||
func(mode, first, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha));
|
||||
#else
|
||||
GLfloat red = next_float();
|
||||
GLfloat green = next_float();
|
||||
GLfloat blue = next_float();
|
||||
GLfloat alpha = next_float();
|
||||
// Run
|
||||
func(red, green, blue, alpha);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(17, glClear, void, (GLbitfield mask))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(mask);
|
||||
#else
|
||||
GLbitfield mask = next_int();
|
||||
// Run
|
||||
func(mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, size, (uint32_t) data, usage);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLsizeiptr size = next_int();
|
||||
const void *data = next_ptr();
|
||||
GLenum usage = next_int();
|
||||
// Run
|
||||
func(target, size, data, usage);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(19, glFogx, void, (GLenum pname, GLfixed param))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pname, param);
|
||||
#else
|
||||
GLenum pname = next_int();
|
||||
GLfixed param = next_int();
|
||||
// Run
|
||||
func(pname, param);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(20, glFogf, void, (GLenum pname, GLfloat param))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pname, pun_to(uint32_t, param));
|
||||
#else
|
||||
GLenum pname = next_int();
|
||||
GLfloat param = next_float();
|
||||
// Run
|
||||
func(pname, param);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(21, glMatrixMode, void, (GLenum mode))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(mode);
|
||||
#else
|
||||
GLenum mode = next_int();
|
||||
// Run
|
||||
func(mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL_GL_POINTER(22, glColorPointer)
|
||||
|
||||
CALL(23, glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(x, y, width, height);
|
||||
#else
|
||||
GLint x = next_int();
|
||||
GLint y = next_int();
|
||||
GLsizei width = next_int();
|
||||
GLsizei height = next_int();
|
||||
// Run
|
||||
func(x, y, width, height);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, pname, param);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLenum pname = next_int();
|
||||
GLint param = next_int();
|
||||
// Run
|
||||
func(target, pname, param);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, level, internalformat, width, height, border, format, type, (uint32_t) pixels);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLint level = next_int();
|
||||
GLint internalformat = next_int();
|
||||
GLsizei width = next_int();
|
||||
GLsizei height = next_int();
|
||||
GLint border = next_int();
|
||||
GLenum format = next_int();
|
||||
GLenum type = next_int();
|
||||
const void *pixels = next_ptr();
|
||||
// Run
|
||||
func(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(26, glEnable, void, (GLenum cap))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(cap);
|
||||
#else
|
||||
GLenum cap = next_int();
|
||||
// Run
|
||||
func(cap);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(27, glEnableClientState, void, (GLenum array))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(array);
|
||||
#else
|
||||
GLenum array = next_int();
|
||||
// Run
|
||||
func(array);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, factor), pun_to(uint32_t, units));
|
||||
#else
|
||||
GLfloat factor = next_float();
|
||||
GLfloat units = next_float();
|
||||
// Run
|
||||
func(factor, units);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL_GL_POINTER(41, glTexCoordPointer)
|
||||
|
||||
CALL(29, glDisableClientState, void, (GLenum array))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(array);
|
||||
#else
|
||||
GLenum array = next_int();
|
||||
// Run
|
||||
func(array);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(30, glDepthRangef, void, (GLclampf near, GLclampf far))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, near), pun_to(uint32_t, far));
|
||||
#else
|
||||
GLclampf near = next_float();
|
||||
GLclampf far = next_float();
|
||||
// Run
|
||||
func(near, far);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(31, glDepthFunc, void, (GLenum func))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(func);
|
||||
#else
|
||||
GLenum func2 = next_int();
|
||||
// Run
|
||||
func(func2);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(32, glBindBuffer, void, (GLenum target, GLuint buffer))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, buffer);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLenum buffer = next_int();
|
||||
// Run
|
||||
func(target, buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(33, glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha));
|
||||
#else
|
||||
GLclampf red = next_float();
|
||||
GLclampf green = next_float();
|
||||
GLclampf blue = next_float();
|
||||
GLclampf alpha = next_float();
|
||||
// Run
|
||||
func(red, green, blue, alpha);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(34, glPopMatrix, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(35, glLoadIdentity, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(36, glScalef, void, (GLfloat x, GLfloat y, GLfloat z))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
|
||||
#else
|
||||
GLfloat x = next_float();
|
||||
GLfloat y = next_float();
|
||||
GLfloat z = next_float();
|
||||
// Run
|
||||
func(x, y, z);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(37, glPushMatrix, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(38, glDepthMask, void, (GLboolean flag))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(flag);
|
||||
#else
|
||||
GLboolean flag = next_int();
|
||||
// Run
|
||||
func(flag);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(39, glHint, void, (GLenum target, GLenum mode))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, mode);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLenum mode = next_int();
|
||||
// Run
|
||||
func(target, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(40, glMultMatrixf, void, (const GLfloat *m))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline((uint32_t) m);
|
||||
#else
|
||||
GLfloat *m = next_ptr();
|
||||
// Run
|
||||
func(m);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(42, glDeleteBuffers, void, (GLsizei n, const GLuint *buffers))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(n, (uint32_t) buffers);
|
||||
#else
|
||||
GLsizei n = next_int();
|
||||
GLuint *buffers = next_ptr();
|
||||
// Run
|
||||
func(n, buffers);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(43, glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(red, green, blue, alpha);
|
||||
#else
|
||||
GLboolean red = next_int();
|
||||
GLboolean green = next_int();
|
||||
GLboolean blue = next_int();
|
||||
GLboolean alpha = next_int();
|
||||
// Run
|
||||
func(red, green, blue, alpha);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, level, xoffset, yoffset, width, height, format, type, (uint32_t) pixels);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLint level = next_int();
|
||||
GLint xoffset = next_int();
|
||||
GLint yoffset = next_int();
|
||||
GLsizei width = next_int();
|
||||
GLsizei height = next_int();
|
||||
GLenum format = next_int();
|
||||
GLenum type = next_int();
|
||||
const void *pixels = next_ptr();
|
||||
// Run
|
||||
func(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(45, glGenTextures, void, (GLsizei n, GLuint *textures))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(n, (uint32_t) textures);
|
||||
#else
|
||||
GLsizei n = next_int();
|
||||
GLuint *textures = next_ptr();
|
||||
// Run
|
||||
func(n, textures);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(46, glDeleteTextures, void, (GLsizei n, const GLuint *textures))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(n, (uint32_t) textures);
|
||||
#else
|
||||
GLsizei n = next_int();
|
||||
GLuint *textures = next_ptr();
|
||||
// Run
|
||||
func(n, textures);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(47, glAlphaFunc, void, (GLenum func, GLclampf ref))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(func, pun_to(uint32_t, ref));
|
||||
#else
|
||||
GLenum func2 = next_int();
|
||||
GLclampf ref = next_float();
|
||||
// Run
|
||||
func(func2, ref);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(48, glGetFloatv, void, (GLenum pname, GLfloat *params))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pname, (uint32_t) params);
|
||||
#else
|
||||
GLenum pname = next_int();
|
||||
GLfloat *params = next_ptr();
|
||||
// Run
|
||||
func(pname, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(49, glBindTexture, void, (GLenum target, GLuint texture))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(target, texture);
|
||||
#else
|
||||
GLenum target = next_int();
|
||||
GLuint texture = next_int();
|
||||
// Run
|
||||
func(target, texture);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(50, glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
|
||||
#else
|
||||
GLfloat x = next_float();
|
||||
GLfloat y = next_float();
|
||||
GLfloat z = next_float();
|
||||
// Run
|
||||
func(x, y, z);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(51, glShadeModel, void, (GLenum mode))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(mode);
|
||||
#else
|
||||
GLenum mode = next_int();
|
||||
// Run
|
||||
func(mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(52, glOrthof, void, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, left), pun_to(uint32_t, right), pun_to(uint32_t, bottom), pun_to(uint32_t, top), pun_to(uint32_t, near), pun_to(uint32_t, far));
|
||||
#else
|
||||
GLfloat left = next_float();
|
||||
GLfloat right = next_float();
|
||||
GLfloat bottom = next_float();
|
||||
GLfloat top = next_float();
|
||||
GLfloat near = next_float();
|
||||
GLfloat far = next_float();
|
||||
// Run
|
||||
func(left, right, bottom, top, near, far);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(53, glDisable, void, (GLenum cap))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(cap);
|
||||
#else
|
||||
GLenum cap = next_int();
|
||||
// Run
|
||||
func(cap);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(54, glCullFace, void, (GLenum mode))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(mode);
|
||||
#else
|
||||
GLenum mode = next_int();
|
||||
// Run
|
||||
func(mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(55, glRotatef, void, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, angle), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
|
||||
#else
|
||||
GLfloat angle = next_float();
|
||||
GLfloat x = next_float();
|
||||
GLfloat y = next_float();
|
||||
GLfloat z = next_float();
|
||||
// Run
|
||||
func(angle, x, y, z);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(56, glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(x, y, width, height);
|
||||
#else
|
||||
GLint x = next_int();
|
||||
GLint y = next_int();
|
||||
GLsizei width = next_int();
|
||||
GLsizei height = next_int();
|
||||
// Run
|
||||
func(x, y, width, height);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(57, glNormal3f, void, (GLfloat nx, GLfloat ny, GLfloat nz))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, nx), pun_to(uint32_t, ny), pun_to(uint32_t, nz));
|
||||
#else
|
||||
GLfloat nx = next_float();
|
||||
GLfloat ny = next_float();
|
||||
GLfloat nz = next_float();
|
||||
// Run
|
||||
func(nx, ny, nz);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(58, glIsEnabled, GLboolean, (GLenum cap))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline(cap);
|
||||
#else
|
||||
GLenum cap = next_int();
|
||||
// Run
|
||||
ret(func(cap));
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(61, glGetIntegerv, void, (GLenum pname, GLint *params))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pname, (uint32_t) params);
|
||||
#else
|
||||
GLenum pname = next_int();
|
||||
GLint *params = next_ptr();
|
||||
// Run
|
||||
func(pname, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(65, glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(x, y, width, height, format, type, (uint32_t) data);
|
||||
#else
|
||||
GLint x = next_int();
|
||||
GLint y = next_int();
|
||||
GLsizei width = next_int();
|
||||
GLsizei height = next_int();
|
||||
GLenum format = next_int();
|
||||
GLenum type = next_int();
|
||||
void *data = next_ptr();
|
||||
// Run
|
||||
func(x, y, width, height, format, type, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(n, (uint32_t) buffers);
|
||||
#else
|
||||
GLsizei n = next_int();
|
||||
GLuint *buffers = next_ptr();
|
||||
// Run
|
||||
func(n, buffers);
|
||||
#endif
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#if __BYTE_ORDER != __LITTLE_ENDIAN
|
||||
#error "Only Little Endian Is Supported"
|
||||
#endif
|
||||
|
||||
#if defined(MEDIA_LAYER_TRAMPOLINE_HOST)
|
||||
#include "../host/host.h"
|
||||
#elif defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
|
||||
#include "../guest/guest.h"
|
||||
#else
|
||||
#error "Invalid Configuration"
|
||||
#endif
|
||||
|
||||
//#define pun_to(type, x) (*(type *) &(x))
|
||||
#define pun_to(type, x) \
|
||||
({ \
|
||||
union { typeof(x) a; type b; } _pun; \
|
||||
_pun.a = x; \
|
||||
_pun.b; \
|
||||
})
|
|
@ -1,15 +0,0 @@
|
|||
#include <unistd.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "guest.h"
|
||||
|
||||
uint32_t _trampoline(uint32_t id, uint32_t *args) {
|
||||
// Make Syscall
|
||||
long ret = syscall(0x1337 /* See trampoline.patch */, id, args);
|
||||
if (ret == -1) {
|
||||
// Error
|
||||
ERR("Trampoline Error: %s", strerror(errno));
|
||||
}
|
||||
// Return
|
||||
return args[0];
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Trampoline Function
|
||||
uint32_t _trampoline(uint32_t id, uint32_t *args);
|
||||
#define trampoline(...) _trampoline(_id, (uint32_t[]){__VA_ARGS__})
|
||||
|
||||
// Macro
|
||||
#define CALL(unique_id, name, return_type, args) \
|
||||
return_type name args { \
|
||||
static unsigned char _id = unique_id;
|
|
@ -1,17 +0,0 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "host.h"
|
||||
|
||||
// Registration
|
||||
static handler_t *handlers[256];
|
||||
void _add_handler(unsigned char id, handler_t *handler) {
|
||||
if (handlers[id]) {
|
||||
ERR("Conflicting Trampolines For ID: %i", (int) id);
|
||||
}
|
||||
handlers[id] = handler;
|
||||
}
|
||||
|
||||
// Trampoline
|
||||
void trampoline(g2h_t g2h, uint32_t id, uint32_t *args) {
|
||||
handlers[id](g2h, args);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Trampoline Function
|
||||
typedef void *(*g2h_t)(uint32_t guest_addr);
|
||||
void trampoline(g2h_t g2h, uint32_t id, uint32_t *args); // See trampoline.patch
|
||||
|
||||
// Macro
|
||||
typedef void handler_t(g2h_t g2h, uint32_t *args);
|
||||
__attribute__((visibility("internal"))) void _add_handler(unsigned char id, handler_t *handler);
|
||||
#define CALL(unique_id, name, ignored1, ignored2) \
|
||||
static handler_t _run_##name; \
|
||||
__attribute__((constructor)) static void _init_##name() { \
|
||||
_add_handler(unique_id, _run_##name); \
|
||||
} \
|
||||
static void _run_##name(__attribute__((unused)) g2h_t g2h, __attribute__((unused)) uint32_t *args) { \
|
||||
__attribute__((unused)) int _current_arg = 0; \
|
||||
static typeof(name) *func = name;
|
||||
|
||||
// Helper Macros
|
||||
#define next_int() args[_current_arg++]
|
||||
#define next_ptr() g2h(next_int())
|
||||
#define next_float() pun_to(float, next_int())
|
||||
#define ret(x) \
|
||||
args[0] = x; \
|
||||
return;
|
|
@ -1,188 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <media-layer/core.h>
|
||||
#include <media-layer/audio.h>
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
// SDL Functions
|
||||
|
||||
CALL(0, SDL_Init, int, (uint32_t flags))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline(flags);
|
||||
#else
|
||||
uint32_t flags = next_int();
|
||||
// Run
|
||||
ret(func(flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(1, SDL_PollEvent, int, (SDL_Event *event))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline((uint32_t) event);
|
||||
#else
|
||||
SDL_Event *event = next_ptr();
|
||||
// Run
|
||||
ret(func(event));
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(2, SDL_PushEvent, int, (SDL_Event *event))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline((uint32_t) event);
|
||||
#else
|
||||
SDL_Event *event = next_ptr();
|
||||
// Run
|
||||
ret(func(event));
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline((uint32_t) title, (uint32_t) icon);
|
||||
#else
|
||||
char *title = next_ptr();
|
||||
char *icon = next_ptr();
|
||||
// Run
|
||||
func(title, icon);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(4, media_toggle_fullscreen, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline(mode);
|
||||
#else
|
||||
SDL_GrabMode mode = next_int();
|
||||
// Run
|
||||
ret(func(mode));
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(6, SDL_ShowCursor, int, (int32_t toggle))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline(toggle);
|
||||
#else
|
||||
int mode = next_int();
|
||||
// Run
|
||||
ret(func(mode));
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(8, media_swap_buffers, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(9, media_cleanup, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(10, media_get_framebuffer_size, void, (int *width, int *height))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline((uint32_t) width, (uint32_t) height);
|
||||
#else
|
||||
int *width = next_ptr();
|
||||
int *height = next_ptr();
|
||||
// Run
|
||||
func(width, height);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(pun_to(uint32_t, volume), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, yaw));
|
||||
#else
|
||||
float volume = next_float();
|
||||
float x = next_float();
|
||||
float y = next_float();
|
||||
float z = next_float();
|
||||
float yaw = next_float();
|
||||
// Run
|
||||
func(volume, x, y, z, yaw);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline((uint32_t) source, (uint32_t) name, pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, pitch), pun_to(uint32_t, volume), is_ui);
|
||||
#else
|
||||
char *source = next_ptr();
|
||||
char *name = next_ptr();
|
||||
float x = next_float();
|
||||
float y = next_float();
|
||||
float z = next_float();
|
||||
float pitch = next_float();
|
||||
float volume = next_float();
|
||||
int is_ui = next_int();
|
||||
// Run
|
||||
func(source, name, x, y, z, pitch, volume, is_ui);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(62, media_set_interactable, void, (int is_interactable))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(is_interactable);
|
||||
#else
|
||||
int is_interactable = next_int();
|
||||
// Run
|
||||
func(is_interactable);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(63, media_disable_vsync, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(enabled);
|
||||
#else
|
||||
int enabled = next_int();
|
||||
// Run
|
||||
func(enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(66, media_force_egl, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(68, media_ensure_loaded, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline();
|
||||
#else
|
||||
// Run
|
||||
func();
|
||||
#endif
|
||||
}
|
|
@ -31,19 +31,12 @@ set(SRC
|
|||
src/misc/api.cpp
|
||||
# options
|
||||
src/options/options.cpp
|
||||
src/options/ui.cpp
|
||||
src/options/info.cpp
|
||||
# bucket
|
||||
src/bucket/bucket.cpp
|
||||
# cake
|
||||
src/cake/cake.cpp
|
||||
# home
|
||||
src/home/home.cpp
|
||||
# touch
|
||||
src/touch/touch.cpp
|
||||
# text-input-box
|
||||
src/text-input-box/TextInputBox.cpp
|
||||
src/text-input-box/TextInputScreen.cpp
|
||||
# test
|
||||
src/test/test.cpp
|
||||
# init
|
||||
|
@ -89,6 +82,8 @@ else()
|
|||
src/input/crafting.cpp
|
||||
# sign
|
||||
src/sign/sign.cpp
|
||||
# touch
|
||||
src/touch/touch.cpp
|
||||
# atlas
|
||||
src/atlas/atlas.cpp
|
||||
# title-screen
|
||||
|
@ -102,6 +97,9 @@ else()
|
|||
# textures
|
||||
src/textures/textures.cpp
|
||||
src/textures/lava.cpp
|
||||
# text-input-box
|
||||
src/text-input-box/TextInputBox.cpp
|
||||
src/text-input-box/TextInputScreen.cpp
|
||||
# fps
|
||||
src/fps/fps.cpp
|
||||
)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
extern "C" {
|
||||
void run_tests();
|
||||
void init_version();
|
||||
|
@ -8,19 +10,19 @@ void init_compat();
|
|||
void init_server();
|
||||
#else
|
||||
void init_multiplayer();
|
||||
void init_benchmark();
|
||||
void init_benchmark(int argc, char *argv[]);
|
||||
#endif
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
void init_sound();
|
||||
void init_input();
|
||||
void init_sign();
|
||||
void init_camera();
|
||||
void init_touch();
|
||||
void init_atlas();
|
||||
void init_title_screen();
|
||||
void init_skin();
|
||||
void init_fps();
|
||||
#endif
|
||||
void init_touch();
|
||||
void init_textures();
|
||||
void init_creative();
|
||||
void init_game_mode();
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
extern "C" {
|
||||
int32_t misc_get_real_selected_slot(Player *player);
|
||||
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height);
|
||||
|
||||
typedef void (*misc_update_function_Minecraft_t)(Minecraft *obj);
|
||||
void misc_run_on_update(misc_update_function_Minecraft_t function); // obj == Minecraft *
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
|
||||
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
|
||||
static void ItemRenderer_renderGuiItemCorrect_injection(ItemRenderer_renderGuiItemCorrect_t original, Font *font, Textures *textures, ItemInstance *item_instance, int32_t param_1, int32_t param_2) {
|
||||
int32_t leaves_id = Tile::leaves->id;
|
||||
int32_t grass_id = Tile::grass->id;
|
||||
int32_t leaves_id = Tile_leaves->id;
|
||||
int32_t grass_id = Tile_grass->id;
|
||||
// Replace Rendered Item With Carried Variant
|
||||
ItemInstance carried_item_instance;
|
||||
bool use_carried = false;
|
||||
if (item_instance != nullptr) {
|
||||
if (item_instance->id == leaves_id) {
|
||||
carried_item_instance.constructor_tile_extra(Tile::leaves_carried, item_instance->count, item_instance->auxiliary);
|
||||
ItemInstance_constructor_tile_extra(&carried_item_instance, Tile_leaves_carried, item_instance->count, item_instance->auxiliary);
|
||||
use_carried = true;
|
||||
} else if (item_instance->id == grass_id) {
|
||||
carried_item_instance.constructor_tile_extra(Tile::grass_carried, item_instance->count, item_instance->auxiliary);
|
||||
ItemInstance_constructor_tile_extra(&carried_item_instance, Tile_grass_carried, item_instance->count, item_instance->auxiliary);
|
||||
use_carried = true;
|
||||
}
|
||||
}
|
||||
|
@ -64,12 +64,12 @@ static void Tesselator_begin_injection(Tesselator_begin_t original, Tesselator *
|
|||
// Fix Furnace UI
|
||||
if (item_color_fix_mode != 0) {
|
||||
// Implict Translucent
|
||||
tesselator->color(0xff, 0xff, 0xff, 0xff);
|
||||
Tesselator_color(tesselator, 0xff, 0xff, 0xff, 0xff);
|
||||
}
|
||||
}
|
||||
static void InventoryPane_renderBatch_Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_t g, int32_t b) {
|
||||
// Call Original Method
|
||||
tesselator->color(r, g, b, 0xff);
|
||||
Tesselator_color(tesselator, r, g, b, 0xff);
|
||||
|
||||
// Enable Item Color Fix
|
||||
item_color_fix_mode = 2;
|
||||
|
@ -86,7 +86,7 @@ static void FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection(Font *
|
|||
item_color_fix_mode = 1;
|
||||
|
||||
// Call Original Method
|
||||
ItemRenderer::renderGuiItem_one(font, textures, item_instance, param_1, param_2, param_3);
|
||||
ItemRenderer_renderGuiItem_one(font, textures, item_instance, param_1, param_2, param_3);
|
||||
}
|
||||
|
||||
// Init
|
||||
|
|
|
@ -32,18 +32,18 @@ static void start_world(Minecraft *minecraft) {
|
|||
settings.seed = BENCHMARK_SEED;
|
||||
|
||||
// Delete World If It Already Exists
|
||||
LevelStorageSource *level_source = minecraft->getLevelSource();
|
||||
LevelStorageSource *level_source = Minecraft_getLevelSource(minecraft);
|
||||
std::string name = BENCHMARK_WORLD_NAME;
|
||||
level_source->deleteLevel(&name);
|
||||
level_source->vtable->deleteLevel(level_source, &name);
|
||||
|
||||
// Select Level
|
||||
minecraft->selectLevel(&name, &name, &settings);
|
||||
minecraft->vtable->selectLevel(minecraft, &name, &name, &settings);
|
||||
|
||||
// Open ProgressScreen
|
||||
ProgressScreen *screen = new ProgressScreen;
|
||||
ProgressScreen *screen = alloc_ProgressScreen();
|
||||
ALLOC_CHECK(screen);
|
||||
screen = screen->constructor();
|
||||
minecraft->setScreen((Screen *) screen);
|
||||
screen = ProgressScreen_constructor(screen);
|
||||
Minecraft_setScreen(minecraft, (Screen *) screen);
|
||||
}
|
||||
|
||||
// Track Frames
|
||||
|
@ -93,7 +93,7 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
|
|||
}
|
||||
|
||||
// Detect World Loaded
|
||||
if (!world_loaded && minecraft->isLevelGenerated()) {
|
||||
if (!world_loaded && Minecraft_isLevelGenerated(minecraft)) {
|
||||
world_loaded = 1;
|
||||
world_loaded_time = get_time();
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
@ -158,9 +158,17 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
|
|||
}
|
||||
|
||||
// Init Benchmark
|
||||
void init_benchmark() {
|
||||
void init_benchmark(int argc, char *argv[]) {
|
||||
// --benchmark: Activate Benchmark
|
||||
bool active = getenv("_MCPI_BENCHMARK") != nullptr;
|
||||
bool active = false;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
// Check Argument
|
||||
if (strcmp(argv[i], "--benchmark") == 0) {
|
||||
// Enabled
|
||||
active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (active) {
|
||||
misc_run_on_update(Minecraft_update_injection);
|
||||
// Track Ticks
|
||||
|
|
|
@ -11,9 +11,9 @@ static FoodItem *bucket = nullptr;
|
|||
|
||||
// Description And Texture
|
||||
static std::string BucketItem_getDescriptionId(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance) {
|
||||
if (item_instance->auxiliary == Tile::water->id) {
|
||||
if (item_instance->auxiliary == Tile_water->id) {
|
||||
return "item.bucketWater";
|
||||
} else if (item_instance->auxiliary == Tile::lava->id) {
|
||||
} else if (item_instance->auxiliary == Tile_lava->id) {
|
||||
return "item.bucketLava";
|
||||
} else if (item_instance->auxiliary == 1) {
|
||||
return "item.bucketMilk";
|
||||
|
@ -22,9 +22,9 @@ static std::string BucketItem_getDescriptionId(__attribute__((unused)) FoodItem
|
|||
}
|
||||
}
|
||||
static int32_t BucketItem_getIcon(__attribute__((unused)) FoodItem *item, int32_t auxiliary) {
|
||||
if (auxiliary == Tile::water->id) {
|
||||
if (auxiliary == Tile_water->id) {
|
||||
return 75;
|
||||
} else if (auxiliary == Tile::lava->id) {
|
||||
} else if (auxiliary == Tile_lava->id) {
|
||||
return 76;
|
||||
} else if (auxiliary == 1) {
|
||||
return 77;
|
||||
|
@ -45,7 +45,7 @@ static bool fill_bucket(ItemInstance *item_instance, Player *player, int new_aux
|
|||
new_item.count = 1;
|
||||
new_item.auxiliary = new_auxiliary;
|
||||
Inventory *inventory = player->inventory;
|
||||
if (inventory->add(&new_item)) {
|
||||
if (inventory->vtable->add(inventory, &new_item)) {
|
||||
// Added To Inventory
|
||||
success = true;
|
||||
item_instance->count -= 1;
|
||||
|
@ -62,16 +62,16 @@ static int32_t BucketItem_useOn(__attribute__((unused)) FoodItem *item, ItemInst
|
|||
} else if (item_instance->auxiliary == 0) {
|
||||
// Empty Bucket
|
||||
int32_t new_auxiliary = 0;
|
||||
int32_t tile = level->getTile(x, y, z);
|
||||
if (tile == Tile::calmWater->id) {
|
||||
new_auxiliary = Tile::water->id;
|
||||
} else if (tile == Tile::calmLava->id) {
|
||||
new_auxiliary = Tile::lava->id;
|
||||
int32_t tile = level->vtable->getTile(level, x, y, z);
|
||||
if (tile == Tile_calmWater->id) {
|
||||
new_auxiliary = Tile_water->id;
|
||||
} else if (tile == Tile_calmLava->id) {
|
||||
new_auxiliary = Tile_lava->id;
|
||||
}
|
||||
if (new_auxiliary != 0) {
|
||||
// Valid
|
||||
if (fill_bucket(item_instance, player, new_auxiliary)) {
|
||||
level->setTileAndData(x, y, z, 0, 0);
|
||||
Level_setTileAndData(level, x, y, z, 0, 0);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -110,15 +110,15 @@ static int32_t BucketItem_useOn(__attribute__((unused)) FoodItem *item, ItemInst
|
|||
}
|
||||
// Get Current Tile
|
||||
bool valid = false;
|
||||
Material *material = level->getMaterial(x, y, z);
|
||||
Material *material = level->vtable->getMaterial(level, x, y, z);
|
||||
if (material != nullptr) {
|
||||
valid = !material->isSolid();
|
||||
valid = !material->vtable->isSolid(material);
|
||||
}
|
||||
if (item_instance->auxiliary != Tile::water->id && item_instance->auxiliary != Tile::lava->id) {
|
||||
if (item_instance->auxiliary != Tile_water->id && item_instance->auxiliary != Tile_lava->id) {
|
||||
valid = false;
|
||||
}
|
||||
if (valid) {
|
||||
level->setTileAndData(x, y, z, item_instance->auxiliary, 0);
|
||||
Level_setTileAndData(level, x, y, z, item_instance->auxiliary, 0);
|
||||
item_instance->auxiliary = 0;
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -163,7 +163,7 @@ static ItemInstance *BucketItem_getCraftingRemainingItem(FoodItem *item, ItemIns
|
|||
if (item_instance->auxiliary == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
ItemInstance *ret = new ItemInstance;
|
||||
ItemInstance *ret = alloc_ItemInstance();
|
||||
ret->id = item->id;
|
||||
ret->count = item_instance->count;
|
||||
ret->auxiliary = 0;
|
||||
|
@ -186,16 +186,16 @@ CUSTOM_VTABLE(bucket, FoodItem) {
|
|||
// Create Items
|
||||
static FoodItem *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) {
|
||||
// Construct
|
||||
FoodItem *item = new FoodItem;
|
||||
FoodItem *item = alloc_FoodItem();
|
||||
ALLOC_CHECK(item);
|
||||
Item_constructor((Item *) item, id); // FoodItem's Constructor Was Inlined
|
||||
Item_constructor((Item *) item, id);
|
||||
|
||||
// Set VTable
|
||||
item->vtable = get_bucket_vtable();
|
||||
|
||||
// Setup
|
||||
item->setIcon(texture_x, texture_y);
|
||||
item->setDescriptionId(&name);
|
||||
item->vtable->setIcon(item, texture_x, texture_y);
|
||||
item->vtable->setDescriptionId(item, &name);
|
||||
item->is_stacked_by_data = 1;
|
||||
item->category = 2;
|
||||
item->max_damage = 0;
|
||||
|
@ -224,7 +224,7 @@ static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance_getMaxStackSi
|
|||
|
||||
// Milking
|
||||
bool Cow_interact_injection(Cow_interact_t original, Cow *self, Player *player) {
|
||||
ItemInstance *item = player->inventory->getSelected();
|
||||
ItemInstance *item = Inventory_getSelected(player->inventory);
|
||||
if (item && item->id == bucket->id && item->auxiliary == 0) {
|
||||
// Fill with milk
|
||||
fill_bucket(item, player, 1);
|
||||
|
@ -237,13 +237,13 @@ bool Cow_interact_injection(Cow_interact_t original, Cow *self, Player *player)
|
|||
static void inventory_add_item(FillingContainer *inventory, FoodItem *item, int32_t auxiliary) {
|
||||
ItemInstance *item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(item_instance);
|
||||
item_instance = item_instance->constructor_item_extra((Item *) item, 1, auxiliary);
|
||||
inventory->addItem(item_instance);
|
||||
item_instance = ItemInstance_constructor_item_extra(item_instance, (Item *) item, 1, auxiliary);
|
||||
FillingContainer_addItem(inventory, item_instance);
|
||||
}
|
||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
|
||||
inventory_add_item(filling_container, bucket, 0);
|
||||
inventory_add_item(filling_container, bucket, Tile::water->id);
|
||||
inventory_add_item(filling_container, bucket, Tile::lava->id);
|
||||
inventory_add_item(filling_container, bucket, Tile_water->id);
|
||||
inventory_add_item(filling_container, bucket, Tile_lava->id);
|
||||
inventory_add_item(filling_container, bucket, 1);
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
static bool is_holding_bucket = false;
|
||||
static HitResult Mob_pick_Level_clip_injection(Level *level, unsigned char *param_1, unsigned char *param_2, __attribute__((unused)) bool clip_liquids, bool param_3) {
|
||||
// Call Original Method
|
||||
return level->clip(param_1, param_2, is_holding_bucket, param_3);
|
||||
return Level_clip(level, param_1, param_2, is_holding_bucket, param_3);
|
||||
}
|
||||
static void handle_tick(Minecraft *minecraft) {
|
||||
LocalPlayer *player = minecraft->player;
|
||||
|
@ -261,7 +261,7 @@ static void handle_tick(Minecraft *minecraft) {
|
|||
Inventory *inventory = player->inventory;
|
||||
|
||||
// Get Item
|
||||
ItemInstance *inventory_item = inventory->getItem(selected_slot);
|
||||
ItemInstance *inventory_item = inventory->vtable->getItem(inventory, selected_slot);
|
||||
// Check
|
||||
is_holding_bucket = inventory_item != nullptr && inventory_item->id == bucket->id && inventory_item->auxiliary == 0;
|
||||
}
|
||||
|
@ -269,9 +269,9 @@ static void handle_tick(Minecraft *minecraft) {
|
|||
|
||||
// Prevent Breaking Liquid
|
||||
static bool is_calm_liquid(int32_t id) {
|
||||
if (id == Tile::calmWater->id) {
|
||||
if (id == Tile_calmWater->id) {
|
||||
return true;
|
||||
} else if (id == Tile::calmLava->id) {
|
||||
} else if (id == Tile_calmLava->id) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -284,7 +284,7 @@ static void Minecraft_handleMouseDown_injection(Minecraft_handleMouseDown_t orig
|
|||
int32_t x = minecraft->hit_result.x;
|
||||
int32_t y = minecraft->hit_result.y;
|
||||
int32_t z = minecraft->hit_result.z;
|
||||
int32_t tile = level->getTile(x, y, z);
|
||||
int32_t tile = level->vtable->getTile(level, x, y, z);
|
||||
if (is_calm_liquid(tile)) {
|
||||
can_destroy = false;
|
||||
}
|
||||
|
@ -315,12 +315,12 @@ static void Recipes_injection(Recipes *recipes) {
|
|||
std::string line1 = "# #";
|
||||
std::string line2 = " # ";
|
||||
std::vector<Recipes_Type> types = {type1};
|
||||
recipes->addShapedRecipe_2(&result, &line1, &line2, &types);
|
||||
Recipes_addShapedRecipe_2(recipes, &result, &line1, &line2, &types);
|
||||
}
|
||||
|
||||
// Custom Furnace Fuel
|
||||
static int32_t FurnaceTileEntity_getBurnDuration_injection(FurnaceTileEntity_getBurnDuration_t original, ItemInstance *item_instance) {
|
||||
if (item_instance->count > 0 && item_instance->id == bucket->id && item_instance->auxiliary == Tile::lava->id) {
|
||||
if (item_instance->count > 0 && item_instance->id == bucket->id && item_instance->auxiliary == Tile_lava->id) {
|
||||
return 20000;
|
||||
} else {
|
||||
// Call Original Method
|
||||
|
@ -341,7 +341,7 @@ static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *
|
|||
|
||||
// Add the bucket name to the language file
|
||||
static void Language_injection(__attribute__((unused)) void *null) {
|
||||
I18n::_strings.insert(std::make_pair("item.bucketMilk.name", "Milk Bucket"));
|
||||
I18n__strings.insert(std::make_pair("item.bucketMilk.name", "Milk Bucket"));
|
||||
}
|
||||
|
||||
// Init
|
||||
|
|
|
@ -31,7 +31,7 @@ static int Cake_getTexture2(__attribute__((unused)) Tile *tile, int face, __attr
|
|||
static int Cake_getTexture3(__attribute__((unused)) Tile *tile, LevelSource *level, int x, int y, int z, int face) {
|
||||
// Eaten face
|
||||
if (face == 3) {
|
||||
int data = level->getData(x, y, z);
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data != 0 && data < 6) {
|
||||
// Sliced texture
|
||||
return 123;
|
||||
|
@ -59,7 +59,8 @@ static bool Cake_isCubeShaped(__attribute__((unused)) Tile *tile) {
|
|||
// Size
|
||||
static void Cake_updateDefaultShape(Tile *tile) {
|
||||
// Set the default shape
|
||||
tile->setShape(
|
||||
tile->vtable->setShape(
|
||||
tile,
|
||||
CAKE_LEN, 0.0, CAKE_LEN,
|
||||
1.0 - CAKE_LEN, 0.5, 1.0 - CAKE_LEN
|
||||
);
|
||||
|
@ -67,7 +68,7 @@ static void Cake_updateDefaultShape(Tile *tile) {
|
|||
|
||||
static AABB *Cake_getAABB(Tile *tile, Level *level, int x, int y, int z) {
|
||||
// Get the size of the slices
|
||||
int data = level->getData(x, y, z);
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data >= 6) data = 0;
|
||||
float slice_size = (1.0 / 7.0) * (float) data;
|
||||
|
||||
|
@ -87,11 +88,12 @@ static AABB *Cake_getAABB(Tile *tile, Level *level, int x, int y, int z) {
|
|||
|
||||
static void Cake_updateShape(Tile *tile, LevelSource *level, int x, int y, int z) {
|
||||
// Set cake
|
||||
int data = level->getData(x, y, z);
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data >= 6) data = 0;
|
||||
// Get slice amount
|
||||
float slice_size = (1.0 / 7.0) * (float) data;
|
||||
tile->setShape(
|
||||
tile->vtable->setShape(
|
||||
tile,
|
||||
CAKE_LEN, 0.0, CAKE_LEN,
|
||||
1.0 - CAKE_LEN, 0.5, (1.0 - CAKE_LEN) - slice_size
|
||||
);
|
||||
|
@ -100,15 +102,15 @@ static void Cake_updateShape(Tile *tile, LevelSource *level, int x, int y, int z
|
|||
// Eating
|
||||
static int Cake_use(__attribute__((unused)) Tile *tile, Level *level, int x, int y, int z, Player *player) {
|
||||
// Eat
|
||||
player->foodData.eat(3);
|
||||
SimpleFoodData_eat(&player->foodData, 3);
|
||||
// Set the new tile
|
||||
int data = level->getData(x, y, z);
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data >= 5) {
|
||||
// Remove the cake, it has been completely gobbled up
|
||||
level->setTileAndData(x, y, z, 0, 0);
|
||||
Level_setTileAndData(level, x, y, z, 0, 0);
|
||||
} else {
|
||||
// Remove a slice
|
||||
level->setTileAndData(x, y, z, 92, data + 1);
|
||||
Level_setTileAndData(level, x, y, z, 92, data + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -116,10 +118,10 @@ static int Cake_use(__attribute__((unused)) Tile *tile, Level *level, int x, int
|
|||
// Makes the cakes
|
||||
static void make_cake() {
|
||||
// Construct
|
||||
cake = new Tile;
|
||||
cake = alloc_Tile();
|
||||
ALLOC_CHECK(cake);
|
||||
int texture = 122;
|
||||
cake->constructor(92, texture, Material::dirt);
|
||||
Tile_constructor(cake, 92, texture, Material_dirt);
|
||||
cake->texture = texture;
|
||||
|
||||
// Set VTable
|
||||
|
@ -127,7 +129,8 @@ static void make_cake() {
|
|||
ALLOC_CHECK(cake->vtable);
|
||||
|
||||
// Set shape
|
||||
cake->setShape(
|
||||
cake->vtable->setShape(
|
||||
cake,
|
||||
CAKE_LEN, 0.0, CAKE_LEN,
|
||||
1.0 - CAKE_LEN, 0.5, 1.0 - CAKE_LEN
|
||||
);
|
||||
|
@ -145,12 +148,12 @@ static void make_cake() {
|
|||
cake->vtable->use = Cake_use;
|
||||
|
||||
// Init
|
||||
cake->init();
|
||||
cake->setDestroyTime(1.0f);
|
||||
cake->setExplodeable(20.0f);
|
||||
Tile_init(cake);
|
||||
cake->vtable->setDestroyTime(cake, 1.0f);
|
||||
cake->vtable->setExplodeable(cake, 20.0f);
|
||||
cake->category = 4;
|
||||
std::string name = "Cake";
|
||||
cake->setDescriptionId(&name);
|
||||
cake->vtable->setDescriptionId(cake, &name);
|
||||
}
|
||||
|
||||
static void Tile_initTiles_injection(__attribute__((unused)) void *null) {
|
||||
|
@ -164,7 +167,7 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
cake_instance->count = 255;
|
||||
cake_instance->auxiliary = 0;
|
||||
cake_instance->id = 92;
|
||||
filling_container->addItem(cake_instance);
|
||||
FillingContainer_addItem(filling_container, cake_instance);
|
||||
}
|
||||
|
||||
// Recipe (only when buckets are enabled)
|
||||
|
@ -224,7 +227,7 @@ static void Recipes_injection(Recipes *recipes) {
|
|||
std::string line2 = "ses";
|
||||
std::string line3 = "www";
|
||||
std::vector<Recipes_Type> ingredients = {milk, sugar, wheat, eggs};
|
||||
recipes->addShapedRecipe_3(&cake_item, &line1, &line2, &line3, &ingredients);
|
||||
Recipes_addShapedRecipe_3(recipes, &cake_item, &line1, &line2, &line3, &ingredients);
|
||||
}
|
||||
|
||||
void init_cake() {
|
||||
|
|
|
@ -19,10 +19,10 @@ static EntityRenderDispatcher *EntityRenderDispatcher_injection(EntityRenderDisp
|
|||
original(dispatcher);
|
||||
|
||||
// Register TripodCameraRenderer
|
||||
TripodCameraRenderer *renderer = new TripodCameraRenderer;
|
||||
TripodCameraRenderer *renderer = alloc_TripodCameraRenderer();
|
||||
ALLOC_CHECK(renderer);
|
||||
renderer->constructor();
|
||||
dispatcher->assign((unsigned char) 0x5, (EntityRenderer *) renderer);
|
||||
TripodCameraRenderer_constructor(renderer);
|
||||
EntityRenderDispatcher_assign(dispatcher, (unsigned char) 0x5, (EntityRenderer *) renderer);
|
||||
|
||||
return dispatcher;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ static EntityRenderDispatcher *EntityRenderDispatcher_injection(EntityRenderDisp
|
|||
// Display Smoke From TripodCamera Higher
|
||||
static void TripodCamera_tick_Level_addParticle_call_injection(Level *level, std::string *particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count) {
|
||||
// Call Original Method
|
||||
level->addParticle(particle, x, y + 0.5, z, deltaX, deltaY, deltaZ, count);
|
||||
Level_addParticle(level, particle, x, y + 0.5, z, deltaX, deltaY, deltaZ, count);
|
||||
}
|
||||
|
||||
// Init
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// Message Limitations
|
||||
#define MAX_CHAT_MESSAGE_LENGTH 256
|
||||
|
@ -11,7 +11,11 @@
|
|||
__attribute__((visibility("internal"))) std::string _chat_get_prefix(char *username);
|
||||
|
||||
// Queue Message For Sending
|
||||
__attribute__((visibility("internal"))) void _chat_send_message(Minecraft *minecraft, const char *message);
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
__attribute__((visibility("internal"))) void _chat_queue_message(const char *message);
|
||||
#endif
|
||||
|
||||
// Init Chat UI
|
||||
__attribute__((visibility("internal"))) void _init_chat_ui();
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
__attribute__((visibility("internal"))) void _init_chat_ui();
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
// Config Needs To Load First
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#include <media-layer/core.h>
|
||||
#endif
|
||||
|
||||
#include <mods/init/init.h>
|
||||
#include <mods/feature/feature.h>
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#include <mods/input/input.h>
|
||||
#endif
|
||||
#include "chat-internal.h"
|
||||
#include <mods/chat/chat.h>
|
||||
|
||||
|
@ -19,12 +27,13 @@ std::string chat_send_api_command(Minecraft *minecraft, std::string str) {
|
|||
client.time = 0;
|
||||
CommandServer *command_server = minecraft->command_server;
|
||||
if (command_server != nullptr) {
|
||||
return command_server->parse(&client, &str);
|
||||
return CommandServer_parse(command_server, &client, &str);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Send API Chat Command
|
||||
static void send_api_chat_command(Minecraft *minecraft, char *str) {
|
||||
char *command = nullptr;
|
||||
|
@ -32,6 +41,7 @@ static void send_api_chat_command(Minecraft *minecraft, char *str) {
|
|||
chat_send_api_command(minecraft, command);
|
||||
free(command);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send Message To Players
|
||||
std::string _chat_get_prefix(char *username) {
|
||||
|
@ -43,19 +53,19 @@ void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, ch
|
|||
sanitize_string(&full_message, MAX_CHAT_MESSAGE_LENGTH, 0);
|
||||
std::string cpp_string = full_message;
|
||||
free(full_message);
|
||||
server_side_network_handler->displayGameMessage(&cpp_string);
|
||||
ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &cpp_string);
|
||||
}
|
||||
// Handle Chat packet Send
|
||||
void chat_handle_packet_send(Minecraft *minecraft, ChatPacket *packet) {
|
||||
RakNetInstance *rak_net_instance = minecraft->rak_net_instance;
|
||||
if (rak_net_instance->isServer()) {
|
||||
if (rak_net_instance->vtable->isServer(rak_net_instance)) {
|
||||
// Hosting Multiplayer
|
||||
const char *message = packet->message.c_str();
|
||||
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) minecraft->network_handler;
|
||||
chat_send_message(server_side_network_handler, Strings::default_username, (char *) message);
|
||||
chat_send_message(server_side_network_handler, Strings_default_username, (char *) message);
|
||||
} else {
|
||||
// Client
|
||||
rak_net_instance->send((Packet *) packet);
|
||||
rak_net_instance->vtable->send(rak_net_instance, (Packet *) packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +79,7 @@ static void CommandServer_parse_CommandServer_dispatchPacket_injection(CommandSe
|
|||
|
||||
// Handle ChatPacket Server-Side
|
||||
static void ServerSideNetworkHandler_handle_ChatPacket_injection(ServerSideNetworkHandler *server_side_network_handler, RakNet_RakNetGUID *rak_net_guid, ChatPacket *chat_packet) {
|
||||
Player *player = server_side_network_handler->getPlayer(rak_net_guid);
|
||||
Player *player = ServerSideNetworkHandler_getPlayer(server_side_network_handler, rak_net_guid);
|
||||
if (player != nullptr) {
|
||||
const char *username = player->username.c_str();
|
||||
const char *message = chat_packet->message.c_str();
|
||||
|
@ -77,10 +87,25 @@ static void ServerSideNetworkHandler_handle_ChatPacket_injection(ServerSideNetwo
|
|||
}
|
||||
}
|
||||
|
||||
// Send Message
|
||||
void _chat_send_message(Minecraft *minecraft, const char *message) {
|
||||
send_api_chat_command(minecraft, (char *) message);
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Message Queue
|
||||
static std::vector<std::string> queue;
|
||||
// Add To Queue
|
||||
void _chat_queue_message(const char *message) {
|
||||
// Add
|
||||
std::string str = message;
|
||||
queue.push_back(str);
|
||||
}
|
||||
// Empty Queue
|
||||
unsigned int old_chat_counter = 0;
|
||||
static void send_queued_messages(Minecraft *minecraft) {
|
||||
// Loop
|
||||
for (unsigned int i = 0; i < queue.size(); i++) {
|
||||
send_api_chat_command(minecraft, (char *) queue[i].c_str());
|
||||
}
|
||||
queue.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init
|
||||
void init_chat() {
|
||||
|
@ -91,9 +116,13 @@ void init_chat() {
|
|||
// Manually Send (And Loopback) ChatPacket
|
||||
overwrite_call((void *) 0x6b518, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
|
||||
// Re-Broadcast ChatPacket
|
||||
patch_vtable(ServerSideNetworkHandler_handle_ChatPacket, ServerSideNetworkHandler_handle_ChatPacket_injection);
|
||||
patch_address(ServerSideNetworkHandler_handle_ChatPacket_vtable_addr, ServerSideNetworkHandler_handle_ChatPacket_injection);
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Send Messages On Input Tick
|
||||
input_run_on_tick(send_queued_messages);
|
||||
// Init UI
|
||||
_init_chat_ui();
|
||||
#endif
|
||||
// Disable Built-In Chat Message Limiting
|
||||
unsigned char message_limit_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r4, r4"
|
||||
patch((void *) 0x6b4c0, message_limit_patch);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "chat-internal.h"
|
||||
// Config Needs To Load First
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// Chat UI Code Is Useless In Headless Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
#include "chat-internal.h"
|
||||
#include <mods/chat/chat.h>
|
||||
#include <mods/text-input-box/TextInputScreen.h>
|
||||
#include <mods/misc/misc.h>
|
||||
|
@ -34,7 +39,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
|
|||
local_history = get_history();
|
||||
local_history.push_back("");
|
||||
// Determine Max Length
|
||||
std::string prefix = _chat_get_prefix(Strings::default_username);
|
||||
std::string prefix = _chat_get_prefix(Strings_default_username);
|
||||
int max_length = MAX_CHAT_MESSAGE_LENGTH - prefix.length();
|
||||
self->chat->setMaxLength(max_length);
|
||||
// Send Button
|
||||
|
@ -51,15 +56,15 @@ CUSTOM_VTABLE(chat_screen, Screen) {
|
|||
is_in_chat = false;
|
||||
ChatScreen *self = (ChatScreen *) super;
|
||||
delete self->chat;
|
||||
self->send->destructor_deleting();
|
||||
self->send->vtable->destructor_deleting(self->send);
|
||||
};
|
||||
// Rendering
|
||||
static Screen_render_t original_render = vtable->render;
|
||||
vtable->render = [](Screen *super, int x, int y, float param_1) {
|
||||
// Background
|
||||
super->renderBackground();
|
||||
super->vtable->renderBackground(super);
|
||||
// Render Chat
|
||||
super->minecraft->gui.renderChatMessages(super->height, 20, true, super->font);
|
||||
Gui_renderChatMessages(&super->minecraft->gui, super->height, 20, true, super->font);
|
||||
// Call Original Method
|
||||
original_render(super, x, y, param_1);
|
||||
};
|
||||
|
@ -89,9 +94,9 @@ CUSTOM_VTABLE(chat_screen, Screen) {
|
|||
if (get_history().size() == 0 || text != get_history().back()) {
|
||||
get_history().push_back(text);
|
||||
}
|
||||
_chat_send_message(super->minecraft, text.c_str());
|
||||
_chat_queue_message(text.c_str());
|
||||
}
|
||||
super->minecraft->setScreen(nullptr);
|
||||
Minecraft_setScreen(super->minecraft, nullptr);
|
||||
} else if (key == 0x26) {
|
||||
// Up
|
||||
local_history.at(self->history_pos) = self->chat->getText();
|
||||
|
@ -120,7 +125,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
|
|||
if (button == self->send) {
|
||||
// Send
|
||||
self->chat->setFocused(true);
|
||||
super->keyPressed(0x0d);
|
||||
super->vtable->keyPressed(super, 0x0d);
|
||||
} else {
|
||||
// Call Original Method
|
||||
original_buttonClicked(super, button);
|
||||
|
@ -131,7 +136,7 @@ static Screen *create_chat_screen() {
|
|||
// Construct
|
||||
ChatScreen *screen = new ChatScreen;
|
||||
ALLOC_CHECK(screen);
|
||||
screen->super.super.constructor();
|
||||
Screen_constructor(&screen->super.super);
|
||||
|
||||
// Set VTable
|
||||
screen->super.super.vtable = get_chat_screen_vtable();
|
||||
|
@ -144,8 +149,8 @@ static Screen *create_chat_screen() {
|
|||
void _init_chat_ui() {
|
||||
misc_run_on_game_key_press([](Minecraft *minecraft, int key) {
|
||||
if (key == 0x54) {
|
||||
if (minecraft->isLevelGenerated() && minecraft->screen == nullptr) {
|
||||
minecraft->setScreen(create_chat_screen());
|
||||
if (Minecraft_isLevelGenerated(minecraft) && minecraft->screen == nullptr) {
|
||||
Minecraft_setScreen(minecraft, create_chat_screen());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -153,3 +158,5 @@ void _init_chat_ui() {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,23 +11,23 @@
|
|||
static void inventory_add_item(FillingContainer *inventory, Item *item) {
|
||||
ItemInstance *item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(item_instance);
|
||||
item_instance = item_instance->constructor_item(item);
|
||||
inventory->addItem(item_instance);
|
||||
item_instance = ItemInstance_constructor_item(item_instance, item);
|
||||
FillingContainer_addItem(inventory, item_instance);
|
||||
}
|
||||
static void inventory_add_item(FillingContainer *inventory, Tile *item) {
|
||||
ItemInstance *item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(item_instance);
|
||||
item_instance = item_instance->constructor_tile(item);
|
||||
inventory->addItem(item_instance);
|
||||
item_instance = ItemInstance_constructor_tile(item_instance, item);
|
||||
FillingContainer_addItem(inventory, item_instance);
|
||||
}
|
||||
|
||||
// Expand Creative Inventory
|
||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
|
||||
// Add Items
|
||||
inventory_add_item(filling_container, Item::flintAndSteel);
|
||||
inventory_add_item(filling_container, Item::snowball);
|
||||
inventory_add_item(filling_container, Item::egg);
|
||||
inventory_add_item(filling_container, Item::shears);
|
||||
inventory_add_item(filling_container, Item_flintAndSteel);
|
||||
inventory_add_item(filling_container, Item_snowball);
|
||||
inventory_add_item(filling_container, Item_egg);
|
||||
inventory_add_item(filling_container, Item_shears);
|
||||
// Dyes
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == 15) {
|
||||
|
@ -36,23 +36,23 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
}
|
||||
ItemInstance *new_item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(new_item_instance);
|
||||
new_item_instance = new_item_instance->constructor_item_extra(Item::dye_powder, 1, i);
|
||||
filling_container->addItem(new_item_instance);
|
||||
new_item_instance = ItemInstance_constructor_item_extra(new_item_instance, Item_dye_powder, 1, i);
|
||||
FillingContainer_addItem(filling_container, new_item_instance);
|
||||
}
|
||||
inventory_add_item(filling_container, Item::camera);
|
||||
inventory_add_item(filling_container, Item_camera);
|
||||
// Add Tiles
|
||||
inventory_add_item(filling_container, Tile::water);
|
||||
inventory_add_item(filling_container, Tile::lava);
|
||||
inventory_add_item(filling_container, Tile::calmWater);
|
||||
inventory_add_item(filling_container, Tile::calmLava);
|
||||
inventory_add_item(filling_container, Tile::glowingObsidian);
|
||||
inventory_add_item(filling_container, Tile::web);
|
||||
inventory_add_item(filling_container, Tile::topSnow);
|
||||
inventory_add_item(filling_container, Tile::ice);
|
||||
inventory_add_item(filling_container, Tile::invisible_bedrock);
|
||||
inventory_add_item(filling_container, Tile::bedrock);
|
||||
inventory_add_item(filling_container, Tile::info_updateGame1);
|
||||
inventory_add_item(filling_container, Tile::info_updateGame2);
|
||||
inventory_add_item(filling_container, Tile_water);
|
||||
inventory_add_item(filling_container, Tile_lava);
|
||||
inventory_add_item(filling_container, Tile_calmWater);
|
||||
inventory_add_item(filling_container, Tile_calmLava);
|
||||
inventory_add_item(filling_container, Tile_glowingObsidian);
|
||||
inventory_add_item(filling_container, Tile_web);
|
||||
inventory_add_item(filling_container, Tile_topSnow);
|
||||
inventory_add_item(filling_container, Tile_ice);
|
||||
inventory_add_item(filling_container, Tile_invisible_bedrock);
|
||||
inventory_add_item(filling_container, Tile_bedrock);
|
||||
inventory_add_item(filling_container, Tile_info_updateGame1);
|
||||
inventory_add_item(filling_container, Tile_info_updateGame2);
|
||||
// Nether Reactor
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i == 0) {
|
||||
|
@ -61,8 +61,8 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
}
|
||||
ItemInstance *new_item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(new_item_instance);
|
||||
new_item_instance = new_item_instance->constructor_tile_extra(Tile::netherReactor, 1, i);
|
||||
filling_container->addItem(new_item_instance);
|
||||
new_item_instance = ItemInstance_constructor_tile_extra(new_item_instance, Tile_netherReactor, 1, i);
|
||||
FillingContainer_addItem(filling_container, new_item_instance);
|
||||
}
|
||||
// Tall Grass
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -72,15 +72,15 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
}
|
||||
ItemInstance *new_item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(new_item_instance);
|
||||
new_item_instance = new_item_instance->constructor_tile_extra(Tile::tallgrass, 1, i);
|
||||
filling_container->addItem(new_item_instance);
|
||||
new_item_instance = ItemInstance_constructor_tile_extra(new_item_instance, Tile_tallgrass, 1, i);
|
||||
FillingContainer_addItem(filling_container, new_item_instance);
|
||||
}
|
||||
// Smooth Stone Slab
|
||||
{
|
||||
ItemInstance *new_item_instance = new ItemInstance;
|
||||
ALLOC_CHECK(new_item_instance);
|
||||
new_item_instance = new_item_instance->constructor_tile_extra(Tile::stoneSlab, 1, 6);
|
||||
filling_container->addItem(new_item_instance);
|
||||
new_item_instance = ItemInstance_constructor_tile_extra(new_item_instance, Tile_stoneSlab, 1, 6);
|
||||
FillingContainer_addItem(filling_container, new_item_instance);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -88,14 +88,14 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
|
|||
// Hook Specific TileItem Constructor
|
||||
static TileItem *Tile_initTiles_TileItem_injection(TileItem *tile_item, int32_t id) {
|
||||
// Call Original Method
|
||||
tile_item->constructor(id);
|
||||
TileItem_constructor(tile_item, id);
|
||||
|
||||
// Switch VTable
|
||||
tile_item->vtable = (TileItem_vtable *) AuxDataTileItem_vtable_base;
|
||||
// Configure Item
|
||||
tile_item->is_stacked_by_data = true;
|
||||
tile_item->max_damage = 0;
|
||||
((AuxDataTileItem *) tile_item)->icon_tile = Tile::tiles[id + 0x100];
|
||||
((AuxDataTileItem *) tile_item)->icon_tile = Tile_tiles[id + 0x100];
|
||||
|
||||
// Return
|
||||
return tile_item;
|
||||
|
@ -119,7 +119,7 @@ void init_creative() {
|
|||
// Inventory can have arbitrary auxiliary values.
|
||||
{
|
||||
// Fix Size
|
||||
unsigned char size_patch[4] = {sizeof(AuxDataTileItem), 0x00, 0xa0, 0xe3}; // "mov r0, #AUX_DATA_TILE_ITEM_SIZE"
|
||||
unsigned char size_patch[4] = {AUX_DATA_TILE_ITEM_SIZE, 0x00, 0xa0, 0xe3}; // "mov r0, #AUX_DATA_TILE_ITEM_SIZE"
|
||||
patch((void *) 0xc6f64, size_patch);
|
||||
// Hook Constructor
|
||||
overwrite_call((void *) 0xc6f74, (void *) Tile_initTiles_TileItem_injection);
|
||||
|
@ -127,49 +127,38 @@ void init_creative() {
|
|||
}
|
||||
|
||||
// Remove Creative Mode Restrictions (Opening Chests, Crafting, Etc)
|
||||
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
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);
|
||||
patch((void *) 0x43f3c, nop_patch);
|
||||
patch((void *) 0x43f8c, nop_patch);
|
||||
patch((void *) 0x43fd8, nop_patch);
|
||||
patch((void *) 0x99010, nop_patch);
|
||||
// Fix UI
|
||||
patch((void *) 0x341c0, nop_patch);
|
||||
patch((void *) 0x3adb4, nop_patch);
|
||||
patch((void *) 0x3b374, nop_patch);
|
||||
// Fix Inventory
|
||||
patch((void *) 0x8d080, nop_patch);
|
||||
patch((void *) 0x8d090, nop_patch);
|
||||
patch((void *) 0x91d48, nop_patch);
|
||||
patch((void *) 0x92098, nop_patch);
|
||||
unsigned char inv_creative_check_r3_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
|
||||
patch((void *) 0x923c0, inv_creative_check_r3_patch);
|
||||
patch((void *) 0x92828, nop_patch);
|
||||
patch((void *) 0x92830, nop_patch);
|
||||
// Display Slot Count
|
||||
patch((void *) 0x1e3f4, nop_patch);
|
||||
unsigned char slot_count_patch[4] = {0x18, 0x00, 0x00, 0xea}; // "b 0x27110"
|
||||
patch((void *) 0x270a8, slot_count_patch);
|
||||
patch((void *) 0x33954, nop_patch);
|
||||
// Maximize Creative Inventory Stack Size
|
||||
unsigned char maximize_stack_patch[4] = {0xff, 0xc0, 0xa0, 0xe3}; // "mov r12, 0xff"
|
||||
patch((void *) 0x8e104, maximize_stack_patch);
|
||||
// Allow Nether Reactor
|
||||
patch((void *) 0xc0290, nop_patch);
|
||||
// Disable Other Restrictions
|
||||
is_restricted = 0;
|
||||
}
|
||||
|
||||
// Inventory Behavior
|
||||
if (feature_has("Force Survival Mode Inventory Behavior", server_enabled)) {
|
||||
patch((void *) 0x8d080, nop_patch); // Inventory::add
|
||||
patch((void *) 0x92828, nop_patch); // FillingContainer::add
|
||||
patch((void *) 0x91d48, nop_patch); // FillingContainer::hasResource
|
||||
patch((void *) 0x92098, nop_patch); // FillingContainer::removeResource(int)
|
||||
unsigned char inv_creative_check_r3_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
|
||||
patch((void *) 0x923c0, inv_creative_check_r3_patch); // FillingContainer::removeResource(ItemInstance const&, bool)
|
||||
}
|
||||
|
||||
// "Craft" And "Armor" Buttons
|
||||
if (feature_has("Force Survival Mode Inventory UI", server_enabled)) {
|
||||
patch((void *) 0x341c0, nop_patch); // Add "Armor" Button To Classic Inventory
|
||||
unsigned char inv_creative_check_r5_patch[4] = {0x05, 0x00, 0x55, 0xe1}; // "cmp r5, r5"
|
||||
patch((void *) 0x3adb0, inv_creative_check_r5_patch); // Reposition "Select blocks" In Touch Inventory
|
||||
patch((void *) 0x3b374, nop_patch); // Add "Armor" And "Craft" Buttons To Touch Inventory
|
||||
}
|
||||
|
||||
// Display Slot Count
|
||||
if (feature_has("Display Slot Count In Creative Mode", server_enabled)) {
|
||||
patch((void *) 0x1e3f4, nop_patch);
|
||||
unsigned char slot_count_patch[4] = {0x18, 0x00, 0x00, 0xea}; // "b 0x27110"
|
||||
patch((void *) 0x270a8, slot_count_patch);
|
||||
patch((void *) 0x33954, nop_patch);
|
||||
}
|
||||
|
||||
// Maximize Creative Inventory Stack Size
|
||||
if (feature_has("Maximize Creative Mode Inventory Stack Size", server_enabled)) {
|
||||
unsigned char maximize_stack_patch[4] = {0xff, 0xc0, 0xa0, 0xe3}; // "mov r12, 0xff"
|
||||
patch((void *) 0x8e104, maximize_stack_patch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ std::string get_death_message(Player *player, Entity *cause, bool was_shot = fal
|
|||
std::string message = player->username;
|
||||
if (cause) {
|
||||
// Entity cause
|
||||
int type_id = cause->getEntityTypeId();
|
||||
int aux = cause->getAuxData();
|
||||
bool is_player = cause->isPlayer();
|
||||
if (cause->getCreatureBaseType() != 0 || is_player) {
|
||||
int type_id = cause->vtable->getEntityTypeId(cause);
|
||||
int aux = cause->vtable->getAuxData(cause);
|
||||
bool is_player = cause->vtable->isPlayer(cause);
|
||||
if (cause->vtable->getCreatureBaseType(cause) != 0 || is_player) {
|
||||
// Killed by a creature
|
||||
if (was_shot) {
|
||||
message += " was shot by ";
|
||||
|
@ -38,12 +38,12 @@ std::string get_death_message(Player *player, Entity *cause, bool was_shot = fal
|
|||
} else if (aux) {
|
||||
// Killed by a throwable with owner
|
||||
Level *level = player->level;
|
||||
Entity *shooter = level->getEntity(aux);
|
||||
Entity *shooter = Level_getEntity(level, aux);
|
||||
return get_death_message(player, shooter, true);
|
||||
} else if (type_id == 65) {
|
||||
// Blown up by TNT
|
||||
return message + " was blown apart";
|
||||
} else if (cause->isHangingEntity()) {
|
||||
} else if (cause->vtable->isHangingEntity(cause)) {
|
||||
// Painting?
|
||||
return message + " admired too much art";
|
||||
}
|
||||
|
@ -73,21 +73,22 @@ static bool Mob_hurt_injection(Mob_hurt_t original, Mob *mob, Entity *source, in
|
|||
}
|
||||
|
||||
// Death Message Logic
|
||||
#define Player_die_injections(type, original_method_self) \
|
||||
static void type##_die_injection(original_method_self##_die_t original, type *player, Entity *cause) { \
|
||||
#define Player_die_injections(type) \
|
||||
static type##_die_t original_##type##_die; \
|
||||
static void type##_die_injection(type *player, Entity *cause) { \
|
||||
/* Call Original Method */ \
|
||||
original((original_method_self *) player, cause); \
|
||||
original_##type##_die(player, cause); \
|
||||
\
|
||||
/* Get Variable */ \
|
||||
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
|
||||
/* Only Run On Server-Side */ \
|
||||
if (rak_net_instance->isServer()) { \
|
||||
if (rak_net_instance->vtable->isServer(rak_net_instance)) { \
|
||||
/* Get Death Message */ \
|
||||
std::string message = get_death_message((Player *) player, cause); \
|
||||
\
|
||||
/* Post Death Message */ \
|
||||
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \
|
||||
server_side_network_handler->displayGameMessage(&message); \
|
||||
ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &message); \
|
||||
} \
|
||||
}
|
||||
#define Player_actuallyHurt_injections(type) \
|
||||
|
@ -105,7 +106,7 @@ static bool Mob_hurt_injection(Mob_hurt_t original, Mob *mob, Entity *source, in
|
|||
/* Get Variables */ \
|
||||
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
|
||||
/* Only Run On Server-Side */ \
|
||||
if (rak_net_instance->isServer()) { \
|
||||
if (rak_net_instance->vtable->isServer(rak_net_instance)) { \
|
||||
/* Check Health */ \
|
||||
if (new_health < 1 && old_health >= 1) { \
|
||||
/* Get Death Message */ \
|
||||
|
@ -113,13 +114,13 @@ static bool Mob_hurt_injection(Mob_hurt_t original, Mob *mob, Entity *source, in
|
|||
\
|
||||
/* Post Death Message */ \
|
||||
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \
|
||||
server_side_network_handler->displayGameMessage(&message); \
|
||||
ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &message); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
Player_die_injections(LocalPlayer, LocalPlayer)
|
||||
Player_die_injections(ServerPlayer, Player)
|
||||
Player_die_injections(LocalPlayer)
|
||||
Player_die_injections(ServerPlayer)
|
||||
|
||||
Player_actuallyHurt_injections(LocalPlayer)
|
||||
Player_actuallyHurt_injections(ServerPlayer)
|
||||
|
@ -128,12 +129,10 @@ Player_actuallyHurt_injections(ServerPlayer)
|
|||
void init_death() {
|
||||
// Death Messages
|
||||
if (feature_has("Implement Death Messages", server_auto)) {
|
||||
patch_vtable(ServerPlayer_die, [](ServerPlayer *player, Entity *cause) {
|
||||
ServerPlayer_die_injection(*Player_die_vtable_addr, player, cause);
|
||||
});
|
||||
overwrite_virtual_calls(LocalPlayer_die, LocalPlayer_die_injection);
|
||||
patch_vtable(LocalPlayer_actuallyHurt, LocalPlayer_actuallyHurt_injection);
|
||||
patch_vtable(ServerPlayer_actuallyHurt, ServerPlayer_actuallyHurt_injection);
|
||||
patch_address(ServerPlayer_die_vtable_addr, ServerPlayer_die_injection);
|
||||
patch_address(LocalPlayer_die_vtable_addr, LocalPlayer_die_injection);
|
||||
patch_address(LocalPlayer_actuallyHurt_vtable_addr, LocalPlayer_actuallyHurt_injection);
|
||||
patch_address(ServerPlayer_actuallyHurt_vtable_addr, ServerPlayer_actuallyHurt_injection);
|
||||
overwrite_virtual_calls(Mob_hurt, Mob_hurt_injection);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
__attribute__((visibility("internal"))) void _init_game_mode_ui();
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__attribute__((visibility("internal"))) void _init_game_mode_ui();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,7 @@ static void set_is_survival(bool new_is_survival) {
|
|||
patch((void *) 0x16efc, inventory_patch);
|
||||
|
||||
// Use Correct Size For GameMode Object
|
||||
unsigned char size_patch[4] = {(unsigned char) (new_is_survival ? sizeof(SurvivalMode) : sizeof(CreatorMode)), 0x00, 0xa0, 0xe3}; // "mov r0, #SURVIVAL_MODE_SIZE" or "mov r0, #CREATOR_MODE_SIZE"
|
||||
unsigned char size_patch[4] = {(unsigned char) (new_is_survival ? SURVIVAL_MODE_SIZE : CREATOR_MODE_SIZE), 0x00, 0xa0, 0xe3}; // "mov r0, #SURVIVAL_MODE_SIZE" or "mov r0, #CREATOR_MODE_SIZE"
|
||||
patch((void *) 0x16ee4, size_patch);
|
||||
|
||||
// Replace Default CreatorMode Constructor With CreatorMode Or SurvivalMode Constructor
|
||||
|
@ -57,7 +57,7 @@ void init_game_mode() {
|
|||
overwrite_call((void *) 0x16f84, (void *) ServerLevel_constructor);
|
||||
|
||||
// Allocate Correct Size For ServerLevel
|
||||
uint32_t level_size = sizeof(ServerLevel);
|
||||
uint32_t level_size = SERVER_LEVEL_SIZE;
|
||||
patch_address((void *) 0x17004, (void *) level_size);
|
||||
|
||||
// Disable CreatorMode-Specific API Features (Polling Block Hits) In SurvivalMode, This Is Preferable To Crashing
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
// Config Needs To Load First
|
||||
#include <libreborn/libreborn.h>
|
||||
#include "game-mode-internal.h"
|
||||
|
||||
// Game Mode UI Code Is Useless In Headless Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include <mods/text-input-box/TextInputScreen.h>
|
||||
#include <mods/touch/touch.h>
|
||||
#include <mods/misc/misc.h>
|
||||
#include "game-mode-internal.h"
|
||||
|
||||
// Strings
|
||||
#define GAME_MODE_STR(mode) ("Game Mode: " mode)
|
||||
|
@ -32,9 +36,6 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
|
|||
static int inner_padding = 4;
|
||||
static int description_padding = 4;
|
||||
static int title_padding = 8;
|
||||
static int button_height = 24;
|
||||
static int content_y_offset_top = (title_padding * 2) + line_height;
|
||||
static int content_y_offset_bottom = button_height + (bottom_padding * 2);
|
||||
// Init
|
||||
static Screen_init_t original_init = vtable->init;
|
||||
vtable->init = [](Screen *super) {
|
||||
|
@ -70,26 +71,25 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
|
|||
CreateWorldScreen *self = (CreateWorldScreen *) super;
|
||||
delete self->name;
|
||||
delete self->seed;
|
||||
self->game_mode->destructor_deleting();
|
||||
self->back->destructor_deleting();
|
||||
self->create->destructor_deleting();
|
||||
self->game_mode->vtable->destructor_deleting(self->game_mode);
|
||||
self->back->vtable->destructor_deleting(self->back);
|
||||
self->create->vtable->destructor_deleting(self->create);
|
||||
};
|
||||
// Rendering
|
||||
static Screen_render_t original_render = vtable->render;
|
||||
vtable->render = [](Screen *super, int x, int y, float param_1) {
|
||||
// Background
|
||||
misc_render_background(80, super->minecraft, 0, 0, super->width, super->height);
|
||||
misc_render_background(32, super->minecraft, 0, content_y_offset_top, super->width, super->height - content_y_offset_top - content_y_offset_bottom);
|
||||
super->vtable->renderBackground(super);
|
||||
// Call Original Method
|
||||
original_render(super, x, y, param_1);
|
||||
// Title
|
||||
std::string title = "Create world";
|
||||
super->drawCenteredString(super->font, &title, super->width / 2, title_padding, 0xffffffff);
|
||||
Screen_drawCenteredString(super, super->font, &title, super->width / 2, title_padding, 0xffffffff);
|
||||
// Game Mode Description
|
||||
CreateWorldScreen *self = (CreateWorldScreen *) super;
|
||||
bool is_creative = self->game_mode->text == CREATIVE_STR;
|
||||
std::string description = is_creative ? Strings::creative_mode_description : Strings::survival_mode_description;
|
||||
super->drawString(super->font, &description, self->game_mode->x, self->game_mode->y + self->game_mode->height + description_padding, 0xa0a0a0);
|
||||
std::string description = is_creative ? Strings_creative_mode_description : Strings_survival_mode_description;
|
||||
Screen_drawString(super, super->font, &description, self->game_mode->x, self->game_mode->y + self->game_mode->height + description_padding, 0xa0a0a0);
|
||||
};
|
||||
// Positioning
|
||||
static Screen_setupPositions_t original_setupPositions = vtable->setupPositions;
|
||||
|
@ -98,15 +98,15 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
|
|||
CreateWorldScreen *self = (CreateWorldScreen *) super;
|
||||
// Height/Width
|
||||
int width = 120;
|
||||
int height = button_height;
|
||||
int height = 24;
|
||||
self->create->width = self->back->width = self->game_mode->width = width;
|
||||
int seed_width = self->game_mode->width;
|
||||
int name_width = width * 1.5f;
|
||||
self->create->height = self->back->height = self->game_mode->height = height;
|
||||
int text_box_height = self->game_mode->height;
|
||||
// Find Center Y
|
||||
int top = content_y_offset_top;
|
||||
int bottom = super->height - content_y_offset_bottom;
|
||||
int top = (title_padding * 2) + line_height;
|
||||
int bottom = super->height - self->create->height - (bottom_padding * 2);
|
||||
int center_y = ((bottom - top) / 2) + top;
|
||||
center_y -= (description_padding + line_height) / 2;
|
||||
// X/Y
|
||||
|
@ -125,7 +125,7 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
|
|||
// ESC
|
||||
vtable->handleBackEvent = [](Screen *super, bool do_nothing) {
|
||||
if (!do_nothing) {
|
||||
super->minecraft->screen_chooser.setScreen(5);
|
||||
ScreenChooser_setScreen(&super->minecraft->screen_chooser, 5);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
@ -138,7 +138,7 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
|
|||
self->game_mode->text = is_creative ? SURVIVAL_STR : CREATIVE_STR;
|
||||
} else if (button == self->back) {
|
||||
// Back
|
||||
super->handleBackEvent(false);
|
||||
super->vtable->handleBackEvent(super, false);
|
||||
} else if (button == self->create) {
|
||||
// Create
|
||||
create_world(super->minecraft, self->name->getText(), is_creative, self->seed->getText());
|
||||
|
@ -149,7 +149,7 @@ static Screen *create_create_world_screen() {
|
|||
// Construct
|
||||
CreateWorldScreen *screen = new CreateWorldScreen;
|
||||
ALLOC_CHECK(screen);
|
||||
screen->super.super.constructor();
|
||||
Screen_constructor(&screen->super.super);
|
||||
|
||||
// Set VTable
|
||||
screen->super.super.vtable = get_create_world_screen_vtable();
|
||||
|
@ -162,7 +162,7 @@ static Screen *create_create_world_screen() {
|
|||
static std::string getUniqueLevelName(LevelStorageSource *source, const std::string &in) {
|
||||
std::set<std::string> maps;
|
||||
std::vector<LevelSummary> vls;
|
||||
source->getLevelList(&vls);
|
||||
source->vtable->getLevelList(source, &vls);
|
||||
for (int i = 0; i < int(vls.size()); i++) {
|
||||
const LevelSummary &ls = vls[i];
|
||||
maps.insert(ls.folder);
|
||||
|
@ -178,20 +178,20 @@ static std::string getUniqueLevelName(LevelStorageSource *source, const std::str
|
|||
static void create_world(Minecraft *minecraft, std::string name, bool is_creative, std::string seed_str) {
|
||||
// Get Seed
|
||||
int seed;
|
||||
seed_str = Util::stringTrim(&seed_str);
|
||||
seed_str = Util_stringTrim(&seed_str);
|
||||
if (!seed_str.empty()) {
|
||||
int num;
|
||||
if (sscanf(seed_str.c_str(), "%d", &num) > 0) {
|
||||
seed = num;
|
||||
} else {
|
||||
seed = Util::hashCode(&seed_str);
|
||||
seed = Util_hashCode(&seed_str);
|
||||
}
|
||||
} else {
|
||||
seed = Common::getEpochTimeS();
|
||||
seed = Common_getEpochTimeS();
|
||||
}
|
||||
|
||||
// Get Folder Name
|
||||
name = Util::stringTrim(&name);
|
||||
name = Util_stringTrim(&name);
|
||||
std::string folder = "";
|
||||
for (char c : name) {
|
||||
if (
|
||||
|
@ -213,7 +213,7 @@ static void create_world(Minecraft *minecraft, std::string name, bool is_creativ
|
|||
if (folder.empty()) {
|
||||
folder = "World";
|
||||
}
|
||||
folder = getUniqueLevelName(minecraft->getLevelSource(), folder);
|
||||
folder = getUniqueLevelName(Minecraft_getLevelSource(minecraft), folder);
|
||||
|
||||
// Settings
|
||||
LevelSettings settings;
|
||||
|
@ -221,16 +221,16 @@ static void create_world(Minecraft *minecraft, std::string name, bool is_creativ
|
|||
settings.seed = seed;
|
||||
|
||||
// Create World
|
||||
minecraft->selectLevel(&folder, &name, &settings);
|
||||
minecraft->vtable->selectLevel(minecraft, &folder, &name, &settings);
|
||||
|
||||
// Multiplayer
|
||||
minecraft->hostMultiplayer(19132);
|
||||
Minecraft_hostMultiplayer(minecraft, 19132);
|
||||
|
||||
// Open ProgressScreen
|
||||
ProgressScreen *screen = new ProgressScreen;
|
||||
ProgressScreen *screen = alloc_ProgressScreen();
|
||||
ALLOC_CHECK(screen);
|
||||
screen = screen->constructor();
|
||||
minecraft->setScreen((Screen *) screen);
|
||||
screen = ProgressScreen_constructor(screen);
|
||||
Minecraft_setScreen(minecraft, (Screen *) screen);
|
||||
}
|
||||
|
||||
// Redirect Create World Button
|
||||
|
@ -238,7 +238,7 @@ static void create_world(Minecraft *minecraft, std::string name, bool is_creativ
|
|||
static void prefix##SelectWorldScreen_tick_injection(prefix##SelectWorldScreen_tick_t original, prefix##SelectWorldScreen *screen) { \
|
||||
if (screen->should_create_world) { \
|
||||
/* Open Screen */ \
|
||||
screen->minecraft->setScreen(create_create_world_screen()); \
|
||||
Minecraft_setScreen(screen->minecraft, create_create_world_screen()); \
|
||||
/* Finish */ \
|
||||
screen->should_create_world = false; \
|
||||
} else { \
|
||||
|
@ -255,3 +255,8 @@ void _init_game_mode_ui() {
|
|||
overwrite_virtual_calls(SelectWorldScreen_tick, SelectWorldScreen_tick_injection);
|
||||
overwrite_virtual_calls(Touch_SelectWorldScreen_tick, Touch_SelectWorldScreen_tick_injection);
|
||||
}
|
||||
|
||||
#else
|
||||
void _init_game_mode_ui() {
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@ __attribute__((destructor)) static void _free_home() {
|
|||
// Init
|
||||
void init_home() {
|
||||
// Store Data In ~/.minecraft-pi Instead Of ~/.minecraft
|
||||
patch_address((void *) &Strings::default_path, (void *) HOME_SUBDIRECTORY_FOR_GAME_DATA);
|
||||
patch_address((void *) Strings_default_path_pointer, (void *) HOME_SUBDIRECTORY_FOR_GAME_DATA);
|
||||
|
||||
// The override code resolves assets manually,
|
||||
// making changing directory redundant.
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
#include <mods/init/init.h>
|
||||
#include <media-layer/core.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
__attribute__((constructor)) static void init() {
|
||||
__attribute__((constructor)) static void init(int argc, char *argv[]) {
|
||||
media_ensure_loaded();
|
||||
reborn_init_patch();
|
||||
run_tests();
|
||||
init_symbols();
|
||||
init_version();
|
||||
init_compat();
|
||||
#ifdef MCPI_SERVER_MODE
|
||||
|
@ -18,12 +20,12 @@ __attribute__((constructor)) static void init() {
|
|||
init_input();
|
||||
init_sign();
|
||||
init_camera();
|
||||
init_touch();
|
||||
init_atlas();
|
||||
init_title_screen();
|
||||
init_skin();
|
||||
init_fps();
|
||||
#endif
|
||||
init_touch();
|
||||
init_textures();
|
||||
init_creative();
|
||||
init_game_mode();
|
||||
|
@ -35,6 +37,9 @@ __attribute__((constructor)) static void init() {
|
|||
init_cake();
|
||||
init_home();
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
init_benchmark();
|
||||
init_benchmark(argc, argv);
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ static int32_t MouseBuildInput_tickBuild_injection(MouseBuildInput_tickBuild_t o
|
|||
static bool last_player_attack_successful = false;
|
||||
static bool Player_attack_Entity_hurt_injection(Entity *entity, Entity *attacker, int32_t damage) {
|
||||
// Call Original Method
|
||||
last_player_attack_successful = entity->hurt(attacker, damage);
|
||||
last_player_attack_successful = entity->vtable->hurt(entity, attacker, damage);
|
||||
return last_player_attack_successful;
|
||||
}
|
||||
static ItemInstance *Player_attack_Inventory_getSelected_injection(Inventory *inventory) {
|
||||
|
@ -49,7 +49,7 @@ static ItemInstance *Player_attack_Inventory_getSelected_injection(Inventory *in
|
|||
}
|
||||
|
||||
// Call Original Method
|
||||
return inventory->getSelected();
|
||||
return Inventory_getSelected(inventory);
|
||||
}
|
||||
|
||||
// Init
|
||||
|
|
|
@ -19,8 +19,8 @@ static void _handle_bow(Minecraft *minecraft) {
|
|||
if (fix_bow && !is_right_click) {
|
||||
GameMode *game_mode = minecraft->game_mode;
|
||||
LocalPlayer *player = minecraft->player;
|
||||
if (player != nullptr && game_mode != nullptr && player->isUsingItem()) {
|
||||
game_mode->releaseUsingItem((Player *) player);
|
||||
if (player != nullptr && game_mode != nullptr && LocalPlayer_isUsingItem(player)) {
|
||||
game_mode->vtable->releaseUsingItem(game_mode, (Player *) player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@ static void _handle_open_crafting(Minecraft *minecraft) {
|
|||
|
||||
// Set Screen
|
||||
if (!creative_is_restricted() || !Minecraft_isCreativeMode(minecraft)) {
|
||||
WorkbenchScreen *screen = new WorkbenchScreen;
|
||||
WorkbenchScreen *screen = alloc_WorkbenchScreen();
|
||||
ALLOC_CHECK(screen);
|
||||
screen = screen->constructor(0);
|
||||
minecraft->setScreen((Screen *) screen);
|
||||
screen = WorkbenchScreen_constructor(screen, 0);
|
||||
Minecraft_setScreen(minecraft, (Screen *) screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ static void _handle_drop(Minecraft *minecraft) {
|
|||
Inventory *inventory = player->inventory;
|
||||
|
||||
// Get Item
|
||||
ItemInstance *inventory_item = inventory->getItem(selected_slot);
|
||||
ItemInstance *inventory_item = inventory->vtable->getItem(inventory, selected_slot);
|
||||
// Check
|
||||
if (inventory_item != nullptr && inventory_item->count > 0) {
|
||||
// Copy
|
||||
|
@ -59,12 +59,12 @@ static void _handle_drop(Minecraft *minecraft) {
|
|||
|
||||
// Empty Slot If Needed
|
||||
if (inventory_item->count < 1) {
|
||||
inventory->release(selected_slot);
|
||||
inventory->compressLinkedSlotList(selected_slot);
|
||||
Inventory_release(inventory, selected_slot);
|
||||
Inventory_compressLinkedSlotList(inventory, selected_slot);
|
||||
}
|
||||
|
||||
// Drop
|
||||
player->drop(dropped_item, false);
|
||||
player->vtable->drop(player, dropped_item, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__attribute__((visibility("internal"))) void _init_attack();
|
||||
__attribute__((visibility("internal"))) void _init_bow();
|
||||
__attribute__((visibility("internal"))) void _init_misc();
|
||||
__attribute__((visibility("internal"))) void _init_toggle();
|
||||
__attribute__((visibility("internal"))) void _init_drop();
|
||||
__attribute__((visibility("internal"))) void _init_crafting();
|
||||
__attribute__((visibility("internal"))) void _init_crafting();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,7 +29,7 @@ static void _handle_back(Minecraft *minecraft) {
|
|||
}
|
||||
// Send Event
|
||||
for (int i = 0; i < back_button_presses; i++) {
|
||||
minecraft->handleBack(0);
|
||||
minecraft->vtable->handleBack(minecraft, 0);
|
||||
}
|
||||
back_button_presses = 0;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ static void _handle_back(Minecraft *minecraft) {
|
|||
static bool OptionsScreen_handleBackEvent_injection(OptionsScreen *screen, bool do_nothing) {
|
||||
if (!do_nothing) {
|
||||
Minecraft *minecraft = screen->minecraft;
|
||||
minecraft->setScreen(nullptr);
|
||||
Minecraft_setScreen(minecraft, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -48,11 +48,11 @@ static bool InBedScreen_handleBackEvent_injection(InBedScreen *screen, bool do_n
|
|||
if (!do_nothing) {
|
||||
// Close Screen
|
||||
Minecraft *minecraft = screen->minecraft;
|
||||
minecraft->setScreen(nullptr);
|
||||
Minecraft_setScreen(minecraft, nullptr);
|
||||
// Stop Sleeping
|
||||
LocalPlayer *player = minecraft->player;
|
||||
if (player != nullptr) {
|
||||
player->stopSleepInBed(1, 1, 1);
|
||||
player->vtable->stopSleepInBed(player, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -68,10 +68,10 @@ void input_set_mouse_grab_state(int state) {
|
|||
static void _handle_mouse_grab(Minecraft *minecraft) {
|
||||
if (mouse_grab_state == -1) {
|
||||
// Grab
|
||||
minecraft->grabMouse();
|
||||
Minecraft_grabMouse(minecraft);
|
||||
} else if (mouse_grab_state == 1) {
|
||||
// Un-Grab
|
||||
minecraft->releaseMouse();
|
||||
Minecraft_releaseMouse(minecraft);
|
||||
}
|
||||
mouse_grab_state = 0;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(Minecraft *
|
|||
bool is_in_game = minecraft->screen == nullptr || minecraft->screen->vtable == (Screen_vtable *) Touch_IngameBlockSelectionScreen_vtable_base;
|
||||
if (!enable_misc || (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF && is_in_game)) {
|
||||
// Call Original Method
|
||||
return creative_is_restricted() && minecraft->isCreativeMode();
|
||||
return creative_is_restricted() && Minecraft_isCreativeMode(minecraft);
|
||||
} else {
|
||||
// Disable Item Drop Ticking
|
||||
return 1;
|
||||
|
@ -103,9 +103,9 @@ void _init_misc() {
|
|||
enable_misc = feature_has("Miscellaneous Input Fixes", server_disabled);
|
||||
if (enable_misc) {
|
||||
// Fix OptionsScreen Ignoring The Back Button
|
||||
patch_vtable(OptionsScreen_handleBackEvent, OptionsScreen_handleBackEvent_injection);
|
||||
patch_address(OptionsScreen_handleBackEvent_vtable_addr, OptionsScreen_handleBackEvent_injection);
|
||||
// Fix "Sleeping Beauty" Bug
|
||||
patch_vtable(InBedScreen_handleBackEvent, InBedScreen_handleBackEvent_injection);
|
||||
patch_address(InBedScreen_handleBackEvent_vtable_addr, InBedScreen_handleBackEvent_injection);
|
||||
// Disable Opening Inventory Using The Cursor When Cursor Is Hidden
|
||||
overwrite_calls(Gui_handleClick, Gui_handleClick_injection);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#include <GLES/gl.h>
|
||||
#endif
|
||||
|
||||
#include <mods/misc/misc.h>
|
||||
#include "misc-internal.h"
|
||||
|
@ -82,7 +79,7 @@ SETUP_CALLBACK(creative_inventory_setup, FillingContainer);
|
|||
// Handle Custom Creative Inventory Setup Behavior
|
||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container, ItemInstance *item_instance) {
|
||||
// Call Original Method
|
||||
filling_container->addItem(item_instance);
|
||||
FillingContainer_addItem(filling_container, item_instance);
|
||||
|
||||
// Run Functions
|
||||
handle_misc_creative_inventory_setup(filling_container);
|
||||
|
@ -142,28 +139,6 @@ static void Gui_handleKeyPressed_injection(Gui_handleKeyPressed_t original, Gui
|
|||
original(self, key);
|
||||
}
|
||||
|
||||
// Render Fancy Background
|
||||
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height) {
|
||||
// https://github.com/ReMinecraftPE/mcpe/blob/f0d65eaecec1b3fe9c2f2b251e114a890c54ab77/source/client/gui/components/RolledSelectionList.cpp#L169-L179
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
glColor4f(1, 1, 1, 1);
|
||||
#endif
|
||||
std::string texture = "gui/background.png";
|
||||
minecraft->textures->loadAndBindTexture(&texture);
|
||||
Tesselator *t = &Tesselator::instance;
|
||||
t->begin(7);
|
||||
t->color(color, color, color, 255);
|
||||
float x1 = x;
|
||||
float x2 = x + width;
|
||||
float y1 = y;
|
||||
float y2 = y + height;
|
||||
t->vertexUV(x1, y2, 0.0f, x1 / 32.0f, y2 / 32.0f);
|
||||
t->vertexUV(x2, y2, 0.0f, x2 / 32.0f, y2 / 32.0f);
|
||||
t->vertexUV(x2, y1, 0.0f, x2 / 32.0f, y1 / 32.0f);
|
||||
t->vertexUV(x1, y1, 0.0f, x1 / 32.0f, y1 / 32.0f);
|
||||
t->draw();
|
||||
}
|
||||
|
||||
// Init
|
||||
void _init_misc_api() {
|
||||
// Handle Custom Update Behavior
|
||||
|
|
|
@ -43,9 +43,9 @@ static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, std::s
|
|||
static int last_progress = -1;
|
||||
static const char *last_message = nullptr;
|
||||
static void print_progress(Minecraft *minecraft) {
|
||||
const char *message = minecraft->getProgressMessage();
|
||||
const char *message = Minecraft_getProgressMessage(minecraft);
|
||||
int32_t progress = minecraft->progress;
|
||||
if (minecraft->isLevelGenerated()) {
|
||||
if (Minecraft_isLevelGenerated(minecraft)) {
|
||||
message = "Ready";
|
||||
progress = -1;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__attribute__((visibility("internal"))) void _init_misc_logging();
|
||||
__attribute__((visibility("internal"))) void _init_misc_api();
|
||||
__attribute__((visibility("internal"))) void _init_misc_api();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,61 +24,17 @@
|
|||
#include "misc-internal.h"
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
// Classic HUD
|
||||
#define DEFAULT_HUD_PADDING 2
|
||||
#define NEW_HUD_PADDING 1
|
||||
#define HUD_ELEMENT_WIDTH 82
|
||||
#define HUD_ELEMENT_HEIGHT 9
|
||||
#define TOOLBAR_HEIGHT 22
|
||||
#define SLOT_WIDTH 20
|
||||
#define DEFAULT_BUBBLES_PADDING 1
|
||||
#define NUMBER_OF_SLOTS 9
|
||||
static int use_classic_hud = 0;
|
||||
static void Gui_renderHearts_GuiComponent_blit_hearts_injection(GuiComponent *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
|
||||
Minecraft *minecraft = ((Gui *) component)->minecraft;
|
||||
x_dest -= DEFAULT_HUD_PADDING;
|
||||
float width = ((float) minecraft->screen_width) * Gui::InvGuiScale;
|
||||
float height = ((float) minecraft->screen_height) * Gui::InvGuiScale;
|
||||
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
|
||||
y_dest -= DEFAULT_HUD_PADDING;
|
||||
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
|
||||
// Call Original Method
|
||||
component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
||||
}
|
||||
static void Gui_renderHearts_GuiComponent_blit_armor_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
|
||||
Minecraft *minecraft = component->minecraft;
|
||||
x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH;
|
||||
float width = ((float) minecraft->screen_width) * Gui::InvGuiScale;
|
||||
float height = ((float) minecraft->screen_height) * Gui::InvGuiScale;
|
||||
x_dest += width - ((width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2) - HUD_ELEMENT_WIDTH;
|
||||
y_dest -= DEFAULT_HUD_PADDING;
|
||||
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
|
||||
// Call Original Method
|
||||
component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
||||
}
|
||||
static void Gui_renderBubbles_GuiComponent_blit_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
|
||||
Minecraft *minecraft = component->minecraft;
|
||||
x_dest -= DEFAULT_HUD_PADDING;
|
||||
float width = ((float) minecraft->screen_width) * Gui::InvGuiScale;
|
||||
float height = ((float) minecraft->screen_height) * Gui::InvGuiScale;
|
||||
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
|
||||
y_dest -= DEFAULT_HUD_PADDING + DEFAULT_BUBBLES_PADDING + HUD_ELEMENT_HEIGHT;
|
||||
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - HUD_ELEMENT_HEIGHT - NEW_HUD_PADDING;
|
||||
// Call Original Method
|
||||
component->blit(x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
||||
}
|
||||
|
||||
// Heart Food Overlay
|
||||
// Heart food overlay
|
||||
static int heal_amount = 0, heal_amount_drawing = 0;
|
||||
static void Gui_renderHearts_injection(Gui_renderHearts_t original, Gui *gui) {
|
||||
// Get heal_amount
|
||||
heal_amount = heal_amount_drawing = 0;
|
||||
|
||||
Inventory *inventory = gui->minecraft->player->inventory;
|
||||
ItemInstance *held_ii = inventory->getSelected();
|
||||
ItemInstance *held_ii = Inventory_getSelected(inventory);
|
||||
if (held_ii) {
|
||||
Item *held = Item::items[held_ii->id];
|
||||
if (held->isFood() && held_ii->id) {
|
||||
Item *held = Item_items[held_ii->id];
|
||||
if (held->vtable->isFood(held) && held_ii->id) {
|
||||
int nutrition = ((FoodItem *) held)->nutrition;
|
||||
int cur_health = gui->minecraft->player->health;
|
||||
int heal_num = fmin(cur_health + nutrition, 20) - cur_health;
|
||||
|
@ -89,42 +45,86 @@ static void Gui_renderHearts_injection(Gui_renderHearts_t original, Gui *gui) {
|
|||
// Call original
|
||||
original(gui);
|
||||
}
|
||||
static GuiComponent_blit_t get_blit_with_classic_hud_offset() {
|
||||
return use_classic_hud ? Gui_renderHearts_GuiComponent_blit_hearts_injection : GuiComponent_blit;
|
||||
}
|
||||
|
||||
#define PINK_HEART_FULL 70
|
||||
#define PINK_HEART_HALF 79
|
||||
static Gui_blit_t Gui_blit_renderHearts_original = nullptr;
|
||||
static void Gui_renderHearts_GuiComponent_blit_overlay_empty_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) {
|
||||
// Call Original Method
|
||||
get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, x2, y2, w1, h1, w2, h2);
|
||||
// Render The Overlay
|
||||
// Call original
|
||||
Gui_blit_renderHearts_original(gui, x1, y1, x2, y2, w1, h1, w2, h2);
|
||||
// Render the overlay
|
||||
if (heal_amount_drawing == 1) {
|
||||
// Half Heart
|
||||
get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, PINK_HEART_HALF, 0, w1, h1, w2, h2);
|
||||
// Half heart
|
||||
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_HALF, 0, w1, h1, w2, h2);
|
||||
heal_amount_drawing = 0;
|
||||
} else if (heal_amount_drawing > 0) {
|
||||
// Full Heart
|
||||
get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
|
||||
// Full heart
|
||||
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
|
||||
heal_amount_drawing -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) {
|
||||
// Offset the overlay
|
||||
if (x2 == 52) {
|
||||
heal_amount_drawing += 2;
|
||||
} else if (x2 == 61 && heal_amount) {
|
||||
// Half heart, flipped
|
||||
get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
|
||||
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
|
||||
heal_amount_drawing += 1;
|
||||
}
|
||||
// Call Original Method
|
||||
get_blit_with_classic_hud_offset()((GuiComponent *) gui, x1, y1, x2, y2, w1, h1, w2, h2);
|
||||
};
|
||||
// Call original
|
||||
Gui_blit_renderHearts_original(gui, x1, y1, x2, y2, w1, h1, w2, h2);
|
||||
heal_amount_drawing = fmin(heal_amount_drawing, heal_amount);
|
||||
}
|
||||
|
||||
// Classic HUD
|
||||
#define DEFAULT_HUD_PADDING 2
|
||||
#define NEW_HUD_PADDING 1
|
||||
#define HUD_ELEMENT_WIDTH 82
|
||||
#define HUD_ELEMENT_HEIGHT 9
|
||||
#define TOOLBAR_HEIGHT 22
|
||||
#define SLOT_WIDTH 20
|
||||
#define DEFAULT_BUBBLES_PADDING 1
|
||||
#define NUMBER_OF_SLOTS 9
|
||||
static int use_classic_hud = 0;
|
||||
static void Gui_renderHearts_GuiComponent_blit_hearts_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
|
||||
Minecraft *minecraft = component->minecraft;
|
||||
x_dest -= DEFAULT_HUD_PADDING;
|
||||
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
|
||||
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
|
||||
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
|
||||
y_dest -= DEFAULT_HUD_PADDING;
|
||||
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
|
||||
// Call Original Method
|
||||
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
||||
}
|
||||
static void Gui_renderHearts_GuiComponent_blit_armor_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
|
||||
Minecraft *minecraft = component->minecraft;
|
||||
x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH;
|
||||
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
|
||||
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
|
||||
x_dest += width - ((width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2) - HUD_ELEMENT_WIDTH;
|
||||
y_dest -= DEFAULT_HUD_PADDING;
|
||||
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
|
||||
// Call Original Method
|
||||
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
||||
}
|
||||
static void Gui_renderBubbles_GuiComponent_blit_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
|
||||
Minecraft *minecraft = component->minecraft;
|
||||
x_dest -= DEFAULT_HUD_PADDING;
|
||||
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
|
||||
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
|
||||
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
|
||||
y_dest -= DEFAULT_HUD_PADDING + DEFAULT_BUBBLES_PADDING + HUD_ELEMENT_HEIGHT;
|
||||
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - HUD_ELEMENT_HEIGHT - NEW_HUD_PADDING;
|
||||
// Call Original Method
|
||||
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
|
||||
}
|
||||
|
||||
// Additional GUI Rendering
|
||||
static int hide_chat_messages = 0;
|
||||
bool is_in_chat = false;
|
||||
bool is_in_chat = 0;
|
||||
static int render_selected_item_text = 0;
|
||||
static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original, Gui *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, Font *font) {
|
||||
// Handle Classic HUD
|
||||
|
@ -149,9 +149,9 @@ static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original,
|
|||
// Calculate Selected Item Text Scale
|
||||
Minecraft *minecraft = gui->minecraft;
|
||||
int32_t screen_width = minecraft->screen_width;
|
||||
float scale = ((float) screen_width) * Gui::InvGuiScale;
|
||||
float scale = ((float) screen_width) * Gui_InvGuiScale;
|
||||
// Render Selected Item Text
|
||||
gui->renderOnSelectItemNameText((int32_t) scale, font, y_offset - 0x13);
|
||||
Gui_renderOnSelectItemNameText(gui, (int32_t) scale, font, y_offset - 0x13);
|
||||
}
|
||||
}
|
||||
// Reset Selected Item Text Timer On Slot Select
|
||||
|
@ -235,7 +235,7 @@ static void LoginPacket_read_injection(LoginPacket_read_t original, LoginPacket
|
|||
ALLOC_CHECK(new_username);
|
||||
sanitize_string(&new_username, MAX_USERNAME_LENGTH, 0);
|
||||
// Set New Username
|
||||
rak_string->Assign(new_username);
|
||||
RakNet_RakString_Assign(rak_string, new_username);
|
||||
// Free
|
||||
free(new_username);
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ static const char *RAKNET_ERROR_NAMES[] = {
|
|||
#endif
|
||||
static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection(RakNet_RakPeer *rak_peer, unsigned short maxConnections, unsigned char *socketDescriptors, uint32_t socketDescriptorCount, int32_t threadPriority) {
|
||||
// Call Original Method
|
||||
RakNet_StartupResult result = rak_peer->Startup(maxConnections, socketDescriptors, socketDescriptorCount, threadPriority);
|
||||
RakNet_StartupResult result = rak_peer->vtable->Startup(rak_peer, maxConnections, socketDescriptors, socketDescriptorCount, threadPriority);
|
||||
|
||||
// Print Error
|
||||
if (result != RAKNET_STARTED) {
|
||||
|
@ -297,7 +297,7 @@ static RakNetInstance *RakNetInstance_injection(RakNetInstance_constructor_t ori
|
|||
static void LocalPlayer_die_injection(LocalPlayer_die_t original, LocalPlayer *entity, Entity *cause) {
|
||||
// Close Screen
|
||||
Minecraft *minecraft = entity->minecraft;
|
||||
minecraft->setScreen(nullptr);
|
||||
Minecraft_setScreen(minecraft, nullptr);
|
||||
|
||||
// Call Original Method
|
||||
original(entity, cause);
|
||||
|
@ -307,7 +307,7 @@ static void LocalPlayer_die_injection(LocalPlayer_die_t original, LocalPlayer *e
|
|||
static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen_handleAddItem_t original, FurnaceScreen *furnace_screen, int32_t slot, ItemInstance *item) {
|
||||
// Get Existing Item
|
||||
FurnaceTileEntity *tile_entity = furnace_screen->tile_entity;
|
||||
ItemInstance *existing_item = tile_entity->getItem(slot);
|
||||
ItemInstance *existing_item = tile_entity->vtable->getItem(tile_entity, slot);
|
||||
|
||||
// Check Item
|
||||
int valid;
|
||||
|
@ -349,11 +349,11 @@ static void GameRenderer_render_injection(GameRenderer_render_t original, GameRe
|
|||
// Fix GL Mode
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
// Get X And Y
|
||||
float x = Mouse::getX() * Gui::InvGuiScale;
|
||||
float y = Mouse::getY() * Gui::InvGuiScale;
|
||||
float x = Mouse_getX() * Gui_InvGuiScale;
|
||||
float y = Mouse_getY() * Gui_InvGuiScale;
|
||||
// Render Cursor
|
||||
Minecraft *minecraft = game_renderer->minecraft;
|
||||
Common::renderCursor(x, y, minecraft);
|
||||
Common_renderCursor(x, y, minecraft);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -410,14 +410,14 @@ HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) {
|
|||
|
||||
// Change Grass Color
|
||||
static int32_t get_color(LevelSource *level_source, int32_t x, int32_t z) {
|
||||
Biome *biome = level_source->getBiome(x, z);
|
||||
Biome *biome = level_source->vtable->getBiome(level_source, x, z);
|
||||
if (biome == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return biome->color;
|
||||
}
|
||||
#define BIOME_BLEND_SIZE 7
|
||||
static int32_t GrassTile_getColor_injection(__attribute__((unused)) GrassTile *tile, LevelSource *level_source, int32_t x, __attribute__((unused)) int32_t y, int32_t z) {
|
||||
static int32_t GrassTile_getColor_injection(__attribute__((unused)) Tile *tile, LevelSource *level_source, int32_t x, __attribute__((unused)) int32_t y, int32_t z) {
|
||||
int r_sum = 0;
|
||||
int g_sum = 0;
|
||||
int b_sum = 0;
|
||||
|
@ -441,7 +441,7 @@ static int32_t GrassTile_getColor_injection(__attribute__((unused)) GrassTile *t
|
|||
static int32_t TallGrass_getColor_injection(TallGrass_getColor_t original, TallGrass *tile, LevelSource *level_source, int32_t x, int32_t y, int32_t z) {
|
||||
int32_t original_color = original(tile, level_source, x, y, z);
|
||||
if (original_color == 0x339933) {
|
||||
return GrassTile_getColor_injection(nullptr, level_source, x, y, z);
|
||||
return GrassTile_getColor_injection((Tile *) tile, level_source, x, y, z);
|
||||
} else {
|
||||
return original_color;
|
||||
}
|
||||
|
@ -459,27 +459,26 @@ static void RandomLevelSource_buildSurface_injection(RandomLevelSource_buildSurf
|
|||
LargeCaveFeature *cave_feature = &random_level_source->cave_feature;
|
||||
|
||||
// Generate
|
||||
cave_feature->apply((ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0);
|
||||
cave_feature->vtable->apply(cave_feature, (ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0);
|
||||
}
|
||||
|
||||
// No Block Tinting
|
||||
template <typename T, typename S>
|
||||
static int32_t Tile_getColor_injection(__attribute__((unused)) T original, __attribute__((unused)) S *self, __attribute__((unused)) LevelSource *level_source, __attribute__((unused)) int x, __attribute__((unused)) int y, __attribute__((unused)) int z) {
|
||||
static int32_t Tile_getColor_injection() {
|
||||
return 0xffffff;
|
||||
}
|
||||
|
||||
// Disable Hostile AI In Creative Mode
|
||||
static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
|
||||
// Call Original Method
|
||||
Entity *target = mob->findAttackTarget();
|
||||
Entity *target = mob->vtable->findAttackTarget(mob);
|
||||
|
||||
// Only modify the AI of monsters
|
||||
if (mob->getCreatureBaseType() != 1) {
|
||||
if (mob->vtable->getCreatureBaseType(mob) != 1) {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Check If Creative Mode
|
||||
if (target != nullptr && target->isPlayer()) {
|
||||
if (target != nullptr && target->vtable->isPlayer(target)) {
|
||||
Player *player = (Player *) target;
|
||||
Inventory *inventory = player->inventory;
|
||||
bool is_creative = inventory->is_creative;
|
||||
|
@ -494,12 +493,12 @@ static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
|
|||
|
||||
// 3D Chests
|
||||
static int32_t Tile_getRenderShape_injection(Tile *tile) {
|
||||
if (tile == Tile::chest) {
|
||||
if (tile == Tile_chest) {
|
||||
// Don't Render "Simple" Chest Model
|
||||
return -1;
|
||||
} else {
|
||||
// Call Original Method
|
||||
return tile->getRenderShape();
|
||||
return tile->vtable->getRenderShape(tile);
|
||||
}
|
||||
}
|
||||
static ChestTileEntity *ChestTileEntity_injection(ChestTileEntity_constructor_t original, ChestTileEntity *tile_entity) {
|
||||
|
@ -518,7 +517,7 @@ static void ModelPart_render_injection(ModelPart *model_part, float scale) {
|
|||
is_rendering_chest = true;
|
||||
|
||||
// Call Original Method
|
||||
model_part->render(scale);
|
||||
ModelPart_render(model_part, scale);
|
||||
|
||||
// Stop
|
||||
is_rendering_chest = false;
|
||||
|
@ -545,7 +544,7 @@ static ContainerMenu *ContainerMenu_injection(ContainerMenu_constructor_t origin
|
|||
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
|
||||
bool is_client = tile_entity->is_client;
|
||||
if (!is_client) {
|
||||
container->startOpen();
|
||||
container->vtable->startOpen(container);
|
||||
}
|
||||
|
||||
// Return
|
||||
|
@ -557,7 +556,7 @@ static ContainerMenu *ContainerMenu_destructor_injection(ContainerMenu_destructo
|
|||
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
|
||||
bool is_client = tile_entity->is_client;
|
||||
if (!is_client) {
|
||||
container->stopOpen();
|
||||
container->vtable->stopOpen(container);
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
|
@ -578,7 +577,7 @@ static void glColor4f_injection(__attribute__((unused)) GLfloat red, __attribute
|
|||
line_width = strtof(custom_line_width, nullptr);
|
||||
} else {
|
||||
// Guess
|
||||
line_width = 1.5f / Gui::InvGuiScale;
|
||||
line_width = 2 / Gui_InvGuiScale;
|
||||
}
|
||||
// Clamp Line Width
|
||||
float range[2];
|
||||
|
@ -621,7 +620,7 @@ static void Player_stopUsingItem_injection(Player_stopUsingItem_t original, Play
|
|||
}
|
||||
|
||||
// Java Light Ramp
|
||||
static void Dimension_updateLightRamp_injection(__attribute__((unused)) Dimension_updateLightRamp_t original, Dimension *self) {
|
||||
static void Dimension_updateLightRamp_injection(Dimension *self) {
|
||||
// https://github.com/ReMinecraftPE/mcpe/blob/d7a8b6baecf8b3b050538abdbc976f690312aa2d/source/world/level/Dimension.cpp#L92-L105
|
||||
for (int i = 0; i <= 15; i++) {
|
||||
float f1 = 1.0f - (((float) i) / 15.0f);
|
||||
|
@ -633,9 +632,9 @@ static void Dimension_updateLightRamp_injection(__attribute__((unused)) Dimensio
|
|||
}
|
||||
|
||||
// Read Asset File
|
||||
static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injection(__attribute__((unused)) AppPlatform_readAssetFile_t original, __attribute__((unused)) AppPlatform *app_platform, std::string *path) {
|
||||
static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injection(__attribute__((unused)) AppPlatform *app_platform, std::string const& path) {
|
||||
// Open File
|
||||
std::ifstream stream("data/" + *path, std::ios_base::binary | std::ios_base::ate);
|
||||
std::ifstream stream("data/" + path, std::ios_base::binary | std::ios_base::ate);
|
||||
if (!stream) {
|
||||
// Does Not Exist
|
||||
AppPlatform_readAssetFile_return_value ret;
|
||||
|
@ -666,7 +665,7 @@ static void PauseScreen_init_injection(PauseScreen_init_t original, PauseScreen
|
|||
Minecraft *minecraft = screen->minecraft;
|
||||
RakNetInstance *rak_net_instance = minecraft->rak_net_instance;
|
||||
if (rak_net_instance != nullptr) {
|
||||
if (rak_net_instance->isServer()) {
|
||||
if (rak_net_instance->vtable->isServer(rak_net_instance)) {
|
||||
// Add Button
|
||||
std::vector<Button *> *rendered_buttons = &screen->rendered_buttons;
|
||||
std::vector<Button *> *selectable_buttons = &screen->selectable_buttons;
|
||||
|
@ -675,7 +674,7 @@ static void PauseScreen_init_injection(PauseScreen_init_t original, PauseScreen
|
|||
selectable_buttons->push_back(button);
|
||||
|
||||
// Update Button Text
|
||||
screen->updateServerVisibilityText();
|
||||
PauseScreen_updateServerVisibilityText(screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -686,24 +685,24 @@ void PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_inje
|
|||
CItem *item = self->item;
|
||||
for (size_t i = 0; i < item->ingredients.size(); i++) {
|
||||
ItemInstance requested_item_instance = item->ingredients[i].requested_item;
|
||||
Item *requested_item = Item::items[requested_item_instance.id];
|
||||
ItemInstance *craftingRemainingItem = requested_item->getCraftingRemainingItem(&requested_item_instance);
|
||||
Item *requested_item = Item_items[requested_item_instance.id];
|
||||
ItemInstance *craftingRemainingItem = requested_item->vtable->getCraftingRemainingItem(requested_item, &requested_item_instance);
|
||||
if (craftingRemainingItem != nullptr) {
|
||||
// Add or drop remainder
|
||||
LocalPlayer *player = self->minecraft->player;
|
||||
if (!player->inventory->add(craftingRemainingItem)) {
|
||||
if (!player->inventory->vtable->add(player->inventory, craftingRemainingItem)) {
|
||||
// Drop
|
||||
player->drop(craftingRemainingItem, false);
|
||||
player->vtable->drop(player, craftingRemainingItem, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Call Original Method
|
||||
self->recheckRecipes();
|
||||
PaneCraftingScreen_recheckRecipes(self);
|
||||
}
|
||||
|
||||
ItemInstance *Item_getCraftingRemainingItem_injection(__attribute__((unused)) Item_getCraftingRemainingItem_t original, Item *self, ItemInstance *item_instance) {
|
||||
ItemInstance *Item_getCraftingRemainingItem_injection(Item *self, ItemInstance *item_instance) {
|
||||
if (self->craftingRemainingItem != nullptr) {
|
||||
ItemInstance *ret = new ItemInstance;
|
||||
ItemInstance *ret = alloc_ItemInstance();
|
||||
ret->id = self->craftingRemainingItem->id;
|
||||
ret->count = item_instance->count;
|
||||
ret->auxiliary = 0;
|
||||
|
@ -727,7 +726,7 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkS
|
|||
}
|
||||
for (int i = 0; i < chunks_size; i++) {
|
||||
Chunk *chunk = chunks_begin[i];
|
||||
float distance = chunk->distanceToSqr((Entity *) sorter.mob);
|
||||
float distance = Chunk_distanceToSqr(chunk, (Entity *) sorter.mob);
|
||||
if ((1024.0 <= distance) && chunk->y < 0x40) {
|
||||
distance *= 10.0;
|
||||
}
|
||||
|
@ -766,6 +765,7 @@ void init_misc() {
|
|||
}
|
||||
|
||||
// Classic HUD
|
||||
Gui_blit_renderHearts_original = Gui_blit;
|
||||
if (feature_has("Classic HUD", server_disabled)) {
|
||||
use_classic_hud = 1;
|
||||
overwrite_call((void *) 0x26758, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
|
||||
|
@ -773,6 +773,7 @@ void init_misc() {
|
|||
overwrite_call((void *) 0x268c4, (void *) Gui_renderBubbles_GuiComponent_blit_injection);
|
||||
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
|
||||
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
|
||||
Gui_blit_renderHearts_original = Gui_renderHearts_GuiComponent_blit_hearts_injection;
|
||||
}
|
||||
|
||||
// Food overlay
|
||||
|
@ -822,10 +823,10 @@ void init_misc() {
|
|||
|
||||
#ifdef MCPI_HEADLESS_MODE
|
||||
// Don't Render Game In Headless Mode
|
||||
overwrite_manual(GameRenderer_render, nop);
|
||||
overwrite_manual(NinecraftApp_initGLStates, nop);
|
||||
overwrite_manual(Gui_onConfigChanged, nop);
|
||||
overwrite_manual(LevelRenderer_generateSky, nop);
|
||||
overwrite(GameRenderer_render, nop);
|
||||
overwrite(NinecraftApp_initGLStates, nop);
|
||||
overwrite(Gui_onConfigChanged, nop);
|
||||
overwrite(LevelRenderer_generateSky, nop);
|
||||
#else
|
||||
// Improved Cursor Rendering
|
||||
if (feature_has("Improved Cursor Rendering", server_disabled)) {
|
||||
|
@ -849,7 +850,7 @@ void init_misc() {
|
|||
|
||||
// Remove Forced GUI Lag
|
||||
if (feature_has("Remove Forced GUI Lag (Can Break Joining Servers)", server_enabled)) {
|
||||
overwrite_manual(Common_sleepMs, nop);
|
||||
overwrite(Common_sleepMs, nop);
|
||||
}
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
@ -858,7 +859,7 @@ void init_misc() {
|
|||
#endif
|
||||
|
||||
// Fix Graphics Bug When Switching To First-Person While Sneaking
|
||||
patch_vtable(PlayerRenderer_render, PlayerRenderer_render_injection);
|
||||
patch_address(PlayerRenderer_render_vtable_addr, PlayerRenderer_render_injection);
|
||||
|
||||
// Disable Speed Bridging
|
||||
if (feature_has("Disable Speed Bridging", server_disabled)) {
|
||||
|
@ -874,7 +875,7 @@ void init_misc() {
|
|||
|
||||
// Change Grass Color
|
||||
if (feature_has("Add Biome Colors To Grass", server_disabled)) {
|
||||
patch_vtable(GrassTile_getColor, GrassTile_getColor_injection);
|
||||
patch_address(GrassTile_getColor_vtable_addr, GrassTile_getColor_injection);
|
||||
overwrite_virtual_calls(TallGrass_getColor, TallGrass_getColor_injection);
|
||||
}
|
||||
|
||||
|
@ -885,11 +886,11 @@ void init_misc() {
|
|||
|
||||
// Disable Block Tinting
|
||||
if (feature_has("Disable Block Tinting", server_disabled)) {
|
||||
overwrite_virtual_calls(GrassTile_getColor, Tile_getColor_injection);
|
||||
overwrite_virtual_calls(TallGrass_getColor, Tile_getColor_injection);
|
||||
overwrite_virtual_calls(StemTile_getColor, Tile_getColor_injection);
|
||||
overwrite_virtual_calls(LeafTile_getColor, Tile_getColor_injection);
|
||||
overwrite_virtual_calls(LiquidTile_getColor, Tile_getColor_injection);
|
||||
patch_address(GrassTile_getColor_vtable_addr, Tile_getColor_injection);
|
||||
patch_address(TallGrass_getColor_vtable_addr, Tile_getColor_injection);
|
||||
patch_address(StemTile_getColor_vtable_addr, Tile_getColor_injection);
|
||||
patch_address(LeafTile_getColor_vtable_addr, Tile_getColor_injection);
|
||||
overwrite(*LiquidTile_getColor_vtable_addr, Tile_getColor_injection);
|
||||
}
|
||||
|
||||
// Custom GUI Scale
|
||||
|
@ -931,7 +932,7 @@ void init_misc() {
|
|||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Replace Block Highlight With Outline
|
||||
if (feature_has("Replace Block Highlight With Outline", server_disabled)) {
|
||||
overwrite(LevelRenderer_renderHitSelect, LevelRenderer_renderHitOutline);
|
||||
overwrite((void *) LevelRenderer_renderHitSelect, (void *) LevelRenderer_renderHitOutline);
|
||||
unsigned char fix_outline_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
patch((void *) 0x4d830, fix_outline_patch);
|
||||
overwrite_call((void *) 0x4d764, (void *) glColor4f_injection);
|
||||
|
@ -951,7 +952,7 @@ void init_misc() {
|
|||
|
||||
// Java Light Ramp
|
||||
if (feature_has("Use Java Beta 1.3 Light Ramp", server_disabled)) {
|
||||
overwrite_virtual_calls(Dimension_updateLightRamp, Dimension_updateLightRamp_injection);
|
||||
overwrite(*Dimension_updateLightRamp_vtable_addr, Dimension_updateLightRamp_injection);
|
||||
}
|
||||
|
||||
// Fix used items transferring durability
|
||||
|
@ -959,7 +960,7 @@ void init_misc() {
|
|||
overwrite_calls(Player_stopUsingItem, Player_stopUsingItem_injection);
|
||||
|
||||
// Fix invalid ItemInHandRenderer texture cache
|
||||
if (feature_has("Fix Held Item Caching", server_disabled)) {
|
||||
if (feature_has("Disable Buggy Held Item Caching", server_disabled)) {
|
||||
// This works by forcing MCPI to always use the branch that enables using the
|
||||
// cache, but then patches that as well to do the opposite
|
||||
uchar ensure_equal_patch[] = {0x07, 0x00, 0x57, 0xe1}; // "cmp r7, r7"
|
||||
|
@ -970,7 +971,7 @@ void init_misc() {
|
|||
|
||||
// Implement AppPlatform::readAssetFile So Translations Work
|
||||
if (feature_has("Load Language Files", server_enabled)) {
|
||||
overwrite_virtual_calls(AppPlatform_readAssetFile, AppPlatform_readAssetFile_injection);
|
||||
overwrite(*AppPlatform_readAssetFile_vtable_addr, AppPlatform_readAssetFile_injection);
|
||||
}
|
||||
|
||||
// Fix Pause Menu
|
||||
|
@ -981,16 +982,16 @@ void init_misc() {
|
|||
|
||||
// Implement Crafting Remainders
|
||||
overwrite_call((void *) 0x2e230, (void *) PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection);
|
||||
overwrite_virtual_calls(Item_getCraftingRemainingItem, Item_getCraftingRemainingItem_injection);
|
||||
overwrite(*Item_getCraftingRemainingItem_vtable_addr, Item_getCraftingRemainingItem_injection);
|
||||
|
||||
// Replace 2011 std::sort With Optimized(TM) Code
|
||||
if (feature_has("Optimized Chunk Sorting", server_enabled)) {
|
||||
overwrite_manual((void *) 0x51fac, (void *) sort_chunks);
|
||||
overwrite((void *) 0x51fac, (void *) sort_chunks);
|
||||
}
|
||||
|
||||
// Display Date In Select World Screen
|
||||
if (feature_has("Display Date In Select World Screen", server_disabled)) {
|
||||
patch_vtable(AppPlatform_linux_getDateString, AppPlatform_linux_getDateString_injection);
|
||||
patch_address(AppPlatform_linux_getDateString_vtable_addr, AppPlatform_linux_getDateString_injection);
|
||||
}
|
||||
|
||||
// Init Logging
|
||||
|
|
|
@ -122,7 +122,7 @@ static void RakNetInstance_pingForHosts_injection(RakNetInstance_pingForHosts_t
|
|||
|
||||
// Add External Servers
|
||||
iterate_servers([rak_peer](const char *address, int port) {
|
||||
rak_peer->Ping(address, port, 1, 0);
|
||||
rak_peer->vtable->Ping(rak_peer, address, port, 1, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,268 +0,0 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include <mods/touch/touch.h>
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
#include "options-internal.h"
|
||||
|
||||
// Button IDs
|
||||
#define DISCORD_ID 0
|
||||
#define BACK_ID 1
|
||||
#define INFO_ID_START 2
|
||||
|
||||
// Constants
|
||||
static int line_button_padding = 8;
|
||||
static int line_height = 8;
|
||||
static int line_button_height = (line_button_padding * 2) + line_height;
|
||||
static int padding = 4;
|
||||
static int bottom_padding = padding;
|
||||
static int inner_padding = padding;
|
||||
static int title_padding = 8;
|
||||
static int info_text_y_offset = (line_button_height - line_height) / 2;
|
||||
static int content_y_offset_top = (title_padding * 2) + line_height;
|
||||
static int content_y_offset_bottom = (bottom_padding * 2) + line_button_height;
|
||||
|
||||
// Extra Version Info
|
||||
static std::string extra_version_info =
|
||||
#ifdef MCPI_IS_APPIMAGE_BUILD
|
||||
"AppImage"
|
||||
#elif defined(MCPI_IS_FLATPAK_BUILD)
|
||||
"Flatpak"
|
||||
#else
|
||||
""
|
||||
#endif
|
||||
;
|
||||
static std::string extra_version_info_full = !extra_version_info.empty() ? (" (" + extra_version_info + ")") : "";
|
||||
|
||||
// Profile Directory
|
||||
static std::string profile_directory_suffix =
|
||||
#ifdef MCPI_IS_FLATPAK_BUILD
|
||||
"/.var/app/" MCPI_APP_ID
|
||||
#endif
|
||||
HOME_SUBDIRECTORY_FOR_GAME_DATA
|
||||
;
|
||||
static std::string get_profile_directory_url() {
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
return std::string("file://") + home + profile_directory_suffix;
|
||||
}
|
||||
|
||||
// Info Data
|
||||
struct info_line {
|
||||
std::string (*get_text)();
|
||||
std::string button_url;
|
||||
std::string button_text;
|
||||
};
|
||||
std::string info_sound_data_state = "N/A";
|
||||
static info_line info[] = {
|
||||
{
|
||||
.get_text = []() {
|
||||
return std::string("Version: v") + reborn_get_version() + extra_version_info_full;
|
||||
},
|
||||
.button_url = "https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/CHANGELOG.md",
|
||||
.button_text = "Changelog"
|
||||
},
|
||||
{
|
||||
.get_text = []() {
|
||||
return std::string("Profile Directory");
|
||||
},
|
||||
.button_url = get_profile_directory_url(),
|
||||
.button_text = "Open"
|
||||
},
|
||||
{
|
||||
.get_text = []() {
|
||||
return std::string("Sound Data: ") + info_sound_data_state;
|
||||
},
|
||||
.button_url = "https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/SOUND.md",
|
||||
.button_text = "More Info"
|
||||
},
|
||||
};
|
||||
#define info_size int(sizeof(info) / sizeof(info_line))
|
||||
|
||||
// Positioned Info
|
||||
struct info_pos {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
struct info_line_position {
|
||||
info_pos text;
|
||||
info_pos button;
|
||||
};
|
||||
static info_line_position positioned_info[info_size];
|
||||
static int content_height = 0;
|
||||
static int line_button_width = 0;
|
||||
static void position_info(Font *font, int width, int height) {
|
||||
// First Stage (Find Max Text Width)
|
||||
int info_text_width = 0;
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
std::string text = info[i].get_text();
|
||||
int text_width = font->width(&text);
|
||||
if (text_width > info_text_width) {
|
||||
info_text_width = text_width;
|
||||
}
|
||||
}
|
||||
|
||||
// Second Stage (Initial Positioning)
|
||||
int y = 0;
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
// Padding
|
||||
if (i != 0) {
|
||||
y += padding;
|
||||
}
|
||||
// Y
|
||||
positioned_info[i].button.y = y;
|
||||
positioned_info[i].text.y = y + info_text_y_offset;
|
||||
// X
|
||||
positioned_info[i].button.x = info_text_width + padding;
|
||||
positioned_info[i].text.x = 0;
|
||||
// Advance
|
||||
y += line_button_height;
|
||||
}
|
||||
|
||||
// Third Stage (Find Line Button Width)
|
||||
line_button_width = 0;
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
int text_width = font->width(&info[i].button_text);
|
||||
if (text_width > line_button_width) {
|
||||
line_button_width = text_width;
|
||||
}
|
||||
}
|
||||
line_button_width += line_button_padding * 2;
|
||||
|
||||
// Fourth Stage (Centering)
|
||||
int info_height = y;
|
||||
int info_width = info_text_width + padding + line_button_width;
|
||||
content_height = height - content_y_offset_top - content_y_offset_bottom;
|
||||
int info_y_offset = ((content_height - info_height) / 2) + content_y_offset_top;
|
||||
int info_x_offset = (width - info_width) / 2;
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
positioned_info[i].button.x += info_x_offset;
|
||||
positioned_info[i].button.y += info_y_offset;
|
||||
positioned_info[i].text.x += info_x_offset;
|
||||
positioned_info[i].text.y += info_y_offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Open URL
|
||||
static void open_url(const std::string &url) {
|
||||
int return_code;
|
||||
const char *command[] = {"xdg-open", url.c_str(), nullptr};
|
||||
char *output = run_command(command, &return_code, nullptr);
|
||||
if (output != nullptr) {
|
||||
free(output);
|
||||
}
|
||||
if (!is_exit_status_success(return_code)) {
|
||||
WARN("Unable To Open URL: %s", url.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Create VTable
|
||||
CUSTOM_VTABLE(info_screen, Screen) {
|
||||
// Buttons
|
||||
static Button *discord;
|
||||
static Button *back;
|
||||
static Button *info_buttons[info_size];
|
||||
// Init
|
||||
vtable->init = [](Screen *self) {
|
||||
// Info
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
Button *button = touch_create_button(INFO_ID_START + i, info[i].button_text);
|
||||
self->rendered_buttons.push_back(button);
|
||||
self->selectable_buttons.push_back(button);
|
||||
info_buttons[i] = button;
|
||||
}
|
||||
// Discord Button
|
||||
discord = touch_create_button(DISCORD_ID, "Discord");
|
||||
self->rendered_buttons.push_back(discord);
|
||||
self->selectable_buttons.push_back(discord);
|
||||
// Back Button
|
||||
back = touch_create_button(BACK_ID, "Back");
|
||||
self->rendered_buttons.push_back(back);
|
||||
self->selectable_buttons.push_back(back);
|
||||
};
|
||||
// Handle Back
|
||||
vtable->handleBackEvent = [](Screen *self, bool do_nothing) {
|
||||
if (!do_nothing) {
|
||||
OptionsScreen *screen = new OptionsScreen;
|
||||
ALLOC_CHECK(screen);
|
||||
screen->constructor();
|
||||
self->minecraft->setScreen((Screen *) screen);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Rendering
|
||||
static Screen_render_t original_render = vtable->render;
|
||||
vtable->render = [](Screen *self, int x, int y, float param_1) {
|
||||
// Background
|
||||
misc_render_background(80, self->minecraft, 0, 0, self->width, self->height);
|
||||
misc_render_background(32, self->minecraft, 0, content_y_offset_top, self->width, content_height);
|
||||
// Call Original Method
|
||||
original_render(self, x, y, param_1);
|
||||
// Title
|
||||
std::string title = "Reborn Information";
|
||||
self->drawCenteredString(self->font, &title, self->width / 2, title_padding, 0xffffffff);
|
||||
// Info Text
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
std::string text = info[i].get_text();
|
||||
self->drawString(self->font, &text, positioned_info[i].text.x, positioned_info[i].text.y, 0xffffffff);
|
||||
}
|
||||
};
|
||||
// Positioning
|
||||
vtable->setupPositions = [](Screen *self) {
|
||||
// Height/Width
|
||||
int width = 120;
|
||||
discord->width = back->width = width;
|
||||
discord->height = back->height = line_button_height;
|
||||
// X/Y
|
||||
discord->y = back->y = self->height - bottom_padding - line_button_height;
|
||||
discord->x = (self->width / 2) - inner_padding - width;
|
||||
back->x = (self->width / 2) + inner_padding;
|
||||
// Info
|
||||
position_info(self->font, self->width, self->height);
|
||||
for (int i = 0; i < info_size; i++) {
|
||||
Button *button = info_buttons[i];
|
||||
button->width = line_button_width;
|
||||
button->height = line_button_height;
|
||||
button->x = positioned_info[i].button.x;
|
||||
button->y = positioned_info[i].button.y;
|
||||
}
|
||||
};
|
||||
// Cleanup
|
||||
vtable->removed = [](Screen *self) {
|
||||
for (Button *button : self->rendered_buttons) {
|
||||
button->destructor_deleting();
|
||||
}
|
||||
};
|
||||
// Handle Button Click
|
||||
vtable->buttonClicked = [](Screen *self, Button *button) {
|
||||
if (button->id == BACK_ID) {
|
||||
// Back
|
||||
self->handleBackEvent(false);
|
||||
} else if (button->id == DISCORD_ID) {
|
||||
// Open Discord Invite
|
||||
open_url(MCPI_DISCORD_INVITE);
|
||||
} else if (button->id >= INFO_ID_START) {
|
||||
// Open Info URL
|
||||
int i = button->id - INFO_ID_START;
|
||||
open_url(info[i].button_url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Create Screen
|
||||
Screen *_create_options_info_screen() {
|
||||
// Allocate
|
||||
Screen *screen = new Screen;
|
||||
ALLOC_CHECK(screen);
|
||||
screen->constructor();
|
||||
|
||||
// Set VTable
|
||||
screen->vtable = get_info_screen_vtable();
|
||||
|
||||
// Return
|
||||
return screen;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
__attribute__((visibility("internal"))) void _init_options_ui();
|
||||
__attribute__((visibility("internal"))) extern Options *stored_options;
|
||||
__attribute__((visibility("internal"))) Screen *_create_options_info_screen();
|
|
@ -10,10 +10,8 @@
|
|||
#include <mods/init/init.h>
|
||||
#include <mods/home/home.h>
|
||||
|
||||
#include "options-internal.h"
|
||||
|
||||
// Force Mob Spawning
|
||||
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) LevelData *level_data) {
|
||||
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,7 +49,7 @@ __attribute__((destructor)) static void _free_safe_username() {
|
|||
|
||||
static int render_distance;
|
||||
// Configure Options
|
||||
Options *stored_options = nullptr;
|
||||
static Options *stored_options = nullptr;
|
||||
static void Options_initDefaultValue_injection(Options_initDefaultValue_t original, Options *options) {
|
||||
// Call Original Method
|
||||
original(options);
|
||||
|
@ -79,27 +77,40 @@ static void Minecraft_init_injection(Minecraft_init_t original, Minecraft *minec
|
|||
// Smooth Lighting
|
||||
static bool TileRenderer_tesselateBlockInWorld_injection(TileRenderer_tesselateBlockInWorld_t original, TileRenderer *tile_renderer, Tile *tile, int32_t x, int32_t y, int32_t z) {
|
||||
// Set Variable
|
||||
Minecraft::useAmbientOcclusion = stored_options->ambient_occlusion;
|
||||
Minecraft_useAmbientOcclusion = stored_options->ambient_occlusion;
|
||||
|
||||
// Call Original Method
|
||||
return original(tile_renderer, tile, x, y, z);
|
||||
}
|
||||
|
||||
// Fix Initial Option Button Rendering
|
||||
// The calling function doesn't exist in MCPE v0.6.1, so its name is unknown.
|
||||
static OptionButton *OptionsPane_unknown_toggle_creating_function_OptionButton_injection(OptionButton *option_button, Options_Option *option) {
|
||||
// Call Original Method
|
||||
OptionButton *ret = OptionButton_constructor(option_button, option);
|
||||
|
||||
// Setup Image
|
||||
OptionButton_updateImage(option_button, stored_options);
|
||||
|
||||
// Return
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Actually Save options.txt
|
||||
// Hook Last Options::addOptionToSaveOutput Call
|
||||
static void Options_save_Options_addOptionToSaveOutput_injection(Options *options, std::vector<std::string> *data, std::string option, int32_t value) {
|
||||
// Call Original Method
|
||||
options->addOptionToSaveOutput(data, option, value);
|
||||
Options_addOptionToSaveOutput(options, data, option, value);
|
||||
|
||||
// Save Fancy Graphics
|
||||
options->addOptionToSaveOutput(data, "gfx_fancygraphics", options->fancy_graphics);
|
||||
Options_addOptionToSaveOutput(options, data, "gfx_fancygraphics", options->fancy_graphics);
|
||||
|
||||
// Save 3D Anaglyph
|
||||
options->addOptionToSaveOutput(data, "gfx_anaglyph", options->anaglyph_3d);
|
||||
Options_addOptionToSaveOutput(options, data, "gfx_anaglyph", options->anaglyph_3d);
|
||||
|
||||
// Save File
|
||||
OptionsFile *options_file = &options->options_file;
|
||||
options_file->save(data);
|
||||
OptionsFile_save(options_file, data);
|
||||
}
|
||||
|
||||
// MCPI's OptionsFile::getOptionStrings is broken, this is the version in v0.7.0
|
||||
|
@ -154,11 +165,80 @@ static char *get_new_options_txt_path() {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Modify Option Toggles
|
||||
static void OptionsPane_unknown_toggle_creating_function_injection(OptionsPane_unknown_toggle_creating_function_t original, OptionsPane *options_pane, uint32_t group_id, std::string *name_ptr, Options_Option *option) {
|
||||
// Modify
|
||||
std::string name = *name_ptr;
|
||||
std::string new_name = name;
|
||||
if (name == "Fancy Graphics") {
|
||||
option = &Options_Option_GRAPHICS;
|
||||
} else if (name == "Soft shadows") {
|
||||
option = &Options_Option_AMBIENT_OCCLUSION;
|
||||
} else if (name == "Fancy Skies" || name == "Animated water") {
|
||||
// These have no corresponding option, so disable the toggle.
|
||||
return;
|
||||
} else if (name == "Third person camera") {
|
||||
// This isn't saved/loaded, so disable the toggle.
|
||||
return;
|
||||
} else if (name == "Lefty" || name == "Use touch screen" || name == "Split touch controls") {
|
||||
// These toggles require touch support, so disable them.
|
||||
return;
|
||||
} else if (name == "Vibrate on destroy") {
|
||||
// This toggle requires vibration support, so disable it.
|
||||
return;
|
||||
} else if (name == "Invert X-axis") {
|
||||
// Fix Incorrect Name
|
||||
new_name = "Invert Y-axis";
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
original(options_pane, group_id, &new_name, option);
|
||||
|
||||
// Add 3D Anaglyph
|
||||
if (option == &Options_Option_GRAPHICS) {
|
||||
std::string cpp_string = "3D Anaglyph";
|
||||
original(options_pane, group_id, &cpp_string, &Options_Option_ANAGLYPH);
|
||||
}
|
||||
|
||||
// Add Peaceful Mode
|
||||
if (option == &Options_Option_SERVER_VISIBLE) {
|
||||
std::string cpp_string = "Peaceful mode";
|
||||
original(options_pane, group_id, &cpp_string, &Options_Option_DIFFICULTY);
|
||||
}
|
||||
}
|
||||
|
||||
// Add Missing Options To Options::getBooleanValue
|
||||
static bool Options_getBooleanValue_injection(Options_getBooleanValue_t original, Options *options, Options_Option *option) {
|
||||
// Check
|
||||
if (option == &Options_Option_GRAPHICS) {
|
||||
return options->fancy_graphics;
|
||||
} else if (option == &Options_Option_DIFFICULTY) {
|
||||
return options->game_difficulty == 0;
|
||||
} else {
|
||||
// Call Original Method
|
||||
return original(options, option);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix Difficulty When Toggling
|
||||
static void OptionButton_toggle_Options_save_injection(Options *self) {
|
||||
// Fix Value
|
||||
if (self->game_difficulty == 1) {
|
||||
// Disable Peaceful
|
||||
self->game_difficulty = 2;
|
||||
} else if (self->game_difficulty == 3) {
|
||||
// Switch To Peaceful
|
||||
self->game_difficulty = 0;
|
||||
}
|
||||
// Call Original Method
|
||||
Options_save(self);
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_options() {
|
||||
// Force Mob Spawning
|
||||
if (feature_has("Force Mob Spawning", server_auto)) {
|
||||
overwrite(LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection);
|
||||
overwrite((void *) LevelData_getSpawnMobs, (void *) LevelData_getSpawnMobs_injection);
|
||||
}
|
||||
|
||||
// Render Distance
|
||||
|
@ -172,11 +252,11 @@ void init_options() {
|
|||
// Change Username
|
||||
const char *username = get_username();
|
||||
DEBUG("Setting Username: %s", username);
|
||||
if (strcmp(Strings::default_username, "StevePi") != 0) {
|
||||
if (strcmp(Strings_default_username, "StevePi") != 0) {
|
||||
ERR("Default Username Is Invalid");
|
||||
}
|
||||
safe_username = to_cp437(username);
|
||||
patch_address((void *) &Strings::default_username, (void *) safe_username);
|
||||
patch_address((void *) Strings_default_username_pointer, (void *) safe_username);
|
||||
|
||||
// Disable Autojump By Default
|
||||
if (feature_has("Disable Autojump By Default", server_disabled)) {
|
||||
|
@ -197,12 +277,36 @@ void init_options() {
|
|||
// NOP
|
||||
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
|
||||
// Fix Options Screen
|
||||
if (feature_has("Fix Options Screen", server_disabled)) {
|
||||
// Fix Initial Option Button Rendering
|
||||
overwrite_call((void *) 0x24510, (void *) OptionsPane_unknown_toggle_creating_function_OptionButton_injection);
|
||||
|
||||
// "Gui Scale" slider is broken, so disable it.
|
||||
patch((void *) 0x35a10, nop_patch);
|
||||
// "Vibrate on destroy" is disabled, so "Feedback" is empty, so disable it.
|
||||
patch((void *) 0x35960, nop_patch);
|
||||
|
||||
// Disconnect "This works?" Slider From Difficulty
|
||||
unsigned char this_works_slider_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0"
|
||||
patch((void *) 0x3577c, this_works_slider_patch);
|
||||
|
||||
// Modify Option Toggles
|
||||
overwrite_calls(OptionsPane_unknown_toggle_creating_function, OptionsPane_unknown_toggle_creating_function_injection);
|
||||
|
||||
// Add Missing Options To Options::getBooleanValue
|
||||
overwrite_calls(Options_getBooleanValue, Options_getBooleanValue_injection);
|
||||
|
||||
// Fix Difficulty When Toggling
|
||||
overwrite_call((void *) 0x1cd00, (void *) OptionButton_toggle_Options_save_injection);
|
||||
}
|
||||
|
||||
// Actually Save options.txt
|
||||
overwrite_call((void *) 0x197fc, (void *) Options_save_Options_addOptionToSaveOutput_injection);
|
||||
// Fix options.txt Path
|
||||
patch_address((void *) &Strings::options_txt_path, (void *) get_new_options_txt_path());
|
||||
patch_address((void *) Strings_options_txt_path_pointer, (void *) get_new_options_txt_path());
|
||||
// When Loading, options.txt Should Be Opened In Read Mode
|
||||
patch_address((void *) &Strings::options_txt_fopen_mode_when_loading, (void *) "r");
|
||||
patch_address((void *) Strings_options_txt_fopen_mode_when_loading_pointer, (void *) "r");
|
||||
// Fix OptionsFile::getOptionStrings
|
||||
overwrite(OptionsFile_getOptionStrings, OptionsFile_getOptionStrings_injection);
|
||||
|
||||
|
@ -221,7 +325,7 @@ void init_options() {
|
|||
// Replace "feedback_vibration" Loading/Saving With "gfx_ao"
|
||||
{
|
||||
// Replace String
|
||||
patch_address((void *) &Strings::feedback_vibration_options_txt_name, (void *) "gfx_ao");
|
||||
patch_address((void *) Strings_feedback_vibration_options_txt_name_pointer, (void *) "gfx_ao");
|
||||
// Loading
|
||||
unsigned char offset = (unsigned char) offsetof(Options, ambient_occlusion);
|
||||
unsigned char gfx_ao_loading_patch[4] = {offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET"
|
||||
|
@ -234,7 +338,7 @@ void init_options() {
|
|||
// Replace "gfx_lowquality" Loading With "gfx_anaglyph"
|
||||
{
|
||||
// Replace String
|
||||
patch_address((void *) &Strings::gfx_lowquality_options_txt_name, (void *) "gfx_anaglyph");
|
||||
patch_address((void *) Strings_gfx_lowquality_options_txt_name_pointer, (void *) "gfx_anaglyph");
|
||||
// Loading
|
||||
unsigned char offset = (unsigned char) offsetof(Options, anaglyph_3d);
|
||||
unsigned char gfx_anaglyph_loading_patch[4] = {offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET"
|
||||
|
@ -243,7 +347,4 @@ void init_options() {
|
|||
patch((void *) 0x19414, nop_patch);
|
||||
patch((void *) 0x1941c, nop_patch);
|
||||
}
|
||||
|
||||
// UI
|
||||
_init_options_ui();
|
||||
}
|
||||
|
|
|
@ -1,197 +0,0 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/feature/feature.h>
|
||||
|
||||
#include "options-internal.h"
|
||||
|
||||
// Fix Initial Option Button Rendering
|
||||
// The calling function doesn't exist in MCPE v0.6.1, so its name is unknown.
|
||||
static OptionButton *OptionsPane_unknown_toggle_creating_function_OptionButton_injection(OptionButton *option_button, Options_Option *option) {
|
||||
// Call Original Method
|
||||
OptionButton *ret = option_button->constructor(option);
|
||||
|
||||
// Setup Image
|
||||
option_button->updateImage(stored_options);
|
||||
|
||||
// Return
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Modify Option Toggles
|
||||
static void OptionsPane_unknown_toggle_creating_function_injection(OptionsPane_unknown_toggle_creating_function_t original, OptionsPane *options_pane, uint32_t group_id, std::string *name_ptr, Options_Option *option) {
|
||||
// Modify
|
||||
std::string name = *name_ptr;
|
||||
std::string new_name = name;
|
||||
if (name == "Fancy Graphics") {
|
||||
option = &Options_Option::GRAPHICS;
|
||||
} else if (name == "Soft shadows") {
|
||||
option = &Options_Option::AMBIENT_OCCLUSION;
|
||||
} else if (name == "Fancy Skies" || name == "Animated water") {
|
||||
// These have no corresponding option, so disable the toggle.
|
||||
return;
|
||||
} else if (name == "Third person camera") {
|
||||
// This isn't saved/loaded, so disable the toggle.
|
||||
return;
|
||||
} else if (name == "Lefty" || name == "Use touch screen" || name == "Split touch controls") {
|
||||
// These toggles require touch support, so disable them.
|
||||
return;
|
||||
} else if (name == "Vibrate on destroy") {
|
||||
// This toggle requires vibration support, so disable it.
|
||||
return;
|
||||
} else if (name == "Invert X-axis") {
|
||||
// Fix Incorrect Name
|
||||
new_name = "Invert Y-axis";
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
original(options_pane, group_id, &new_name, option);
|
||||
|
||||
// Add 3D Anaglyph
|
||||
if (option == &Options_Option::GRAPHICS) {
|
||||
std::string cpp_string = "3D Anaglyph";
|
||||
original(options_pane, group_id, &cpp_string, &Options_Option::ANAGLYPH);
|
||||
}
|
||||
|
||||
// Add Peaceful Mode
|
||||
if (option == &Options_Option::SERVER_VISIBLE) {
|
||||
std::string cpp_string = "Peaceful mode";
|
||||
original(options_pane, group_id, &cpp_string, &Options_Option::DIFFICULTY);
|
||||
}
|
||||
}
|
||||
|
||||
// Add Missing Options To Options::getBooleanValue
|
||||
static bool Options_getBooleanValue_injection(Options_getBooleanValue_t original, Options *options, Options_Option *option) {
|
||||
// Check
|
||||
if (option == &Options_Option::GRAPHICS) {
|
||||
return options->fancy_graphics;
|
||||
} else if (option == &Options_Option::DIFFICULTY) {
|
||||
return options->game_difficulty == 0;
|
||||
} else {
|
||||
// Call Original Method
|
||||
return original(options, option);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix Difficulty When Toggling
|
||||
static void OptionButton_toggle_Options_save_injection(Options *self) {
|
||||
// Fix Value
|
||||
if (self->game_difficulty == 1) {
|
||||
// Disable Peaceful
|
||||
self->game_difficulty = 2;
|
||||
} else if (self->game_difficulty == 3) {
|
||||
// Switch To Peaceful
|
||||
self->game_difficulty = 0;
|
||||
}
|
||||
// Call Original Method
|
||||
self->save();
|
||||
}
|
||||
|
||||
// Add "Reborn" Info Button
|
||||
#define INFO_BUTTON_ID 99
|
||||
static void OptionsScreen_init_injection(OptionsScreen_init_t original, OptionsScreen *self) {
|
||||
// Call Original Method
|
||||
original(self);
|
||||
|
||||
// Add Button
|
||||
Touch_TButton *button = new Touch_TButton;
|
||||
ALLOC_CHECK(button);
|
||||
std::string name = "Reborn";
|
||||
button->constructor(INFO_BUTTON_ID, &name);
|
||||
self->rendered_buttons.push_back((Button *) button);
|
||||
self->selectable_buttons.push_back((Button *) button);
|
||||
}
|
||||
static void OptionsScreen_setupPositions_injection(OptionsScreen_setupPositions_t original, OptionsScreen *self) {
|
||||
// Call Original Method
|
||||
original(self);
|
||||
|
||||
// Find Button
|
||||
Button *prevButton = nullptr;
|
||||
Button *button = nullptr;
|
||||
for (Button *x : self->selectable_buttons) {
|
||||
if (x->id == INFO_BUTTON_ID) {
|
||||
button = x;
|
||||
break;
|
||||
}
|
||||
prevButton = x;
|
||||
}
|
||||
if (button == nullptr || prevButton == nullptr) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
|
||||
// Setup Button
|
||||
button->width = prevButton->width;
|
||||
button->height = prevButton->height;
|
||||
button->x = prevButton->x;
|
||||
button->y = prevButton->y + prevButton->height;
|
||||
}
|
||||
static void OptionsScreen_buttonClicked_injection(OptionsScreen_buttonClicked_t original, OptionsScreen *self, Button *button) {
|
||||
// Check ID
|
||||
if (button->id == INFO_BUTTON_ID) {
|
||||
// Show Screen
|
||||
self->minecraft->setScreen(_create_options_info_screen());
|
||||
} else {
|
||||
// Call Original Method
|
||||
original(self, button);
|
||||
}
|
||||
}
|
||||
static void OptionsScreen_removed_injection(OptionsScreen_removed_t original, OptionsScreen *self) {
|
||||
// Delete Button
|
||||
Button *button = nullptr;
|
||||
for (Button *x : self->selectable_buttons) {
|
||||
if (x->id == INFO_BUTTON_ID) {
|
||||
button = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (button == nullptr) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
button->destructor_deleting();
|
||||
|
||||
// Call Original Method
|
||||
original(self);
|
||||
}
|
||||
|
||||
// Init
|
||||
void _init_options_ui() {
|
||||
// Fix Options Screen
|
||||
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
if (feature_has("Fix Options Screen", server_disabled)) {
|
||||
// Fix Initial Option Button Rendering
|
||||
overwrite_call((void *) 0x24510, (void *) OptionsPane_unknown_toggle_creating_function_OptionButton_injection);
|
||||
|
||||
// "Gui Scale" slider is broken, so disable it.
|
||||
patch((void *) 0x35a10, nop_patch);
|
||||
// "Vibrate on destroy" is disabled, so "Feedback" is empty, so disable it.
|
||||
patch((void *) 0x35960, nop_patch);
|
||||
|
||||
// Disconnect "This works?" Slider From Difficulty
|
||||
unsigned char this_works_slider_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0"
|
||||
patch((void *) 0x3577c, this_works_slider_patch);
|
||||
|
||||
// Modify Option Toggles
|
||||
overwrite_calls(OptionsPane_unknown_toggle_creating_function, OptionsPane_unknown_toggle_creating_function_injection);
|
||||
|
||||
// Add Missing Options To Options::getBooleanValue
|
||||
overwrite_calls(Options_getBooleanValue, Options_getBooleanValue_injection);
|
||||
|
||||
// Fix Difficulty When Toggling
|
||||
overwrite_call((void *) 0x1cd00, (void *) OptionButton_toggle_Options_save_injection);
|
||||
}
|
||||
|
||||
// Info Button
|
||||
if (feature_has("Add Reborn Info To Options", server_disabled)) {
|
||||
// Add Button
|
||||
overwrite_virtual_calls(OptionsScreen_init, OptionsScreen_init_injection);
|
||||
// Position Button
|
||||
overwrite_virtual_calls(OptionsScreen_setupPositions, OptionsScreen_setupPositions_injection);
|
||||
// Handle Click
|
||||
overwrite_virtual_calls(OptionsScreen_buttonClicked, OptionsScreen_buttonClicked_injection);
|
||||
// Cleanup
|
||||
overwrite_virtual_calls(OptionsScreen_removed, OptionsScreen_removed_injection);
|
||||
}
|
||||
}
|
|
@ -31,8 +31,16 @@
|
|||
|
||||
// --only-generate: Ony Generate World And Then Exit
|
||||
static bool only_generate = false;
|
||||
__attribute__((constructor)) static void _init_only_generate() {
|
||||
only_generate = getenv("_MCPI_ONLY_GENERATE") != nullptr;
|
||||
__attribute__((constructor)) static void _init_only_generate(int argc, char *argv[]) {
|
||||
// Iterate Arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
// Check Argument
|
||||
if (strcmp(argv[i], "--only-generate") == 0) {
|
||||
// Enabled
|
||||
only_generate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Server Properties
|
||||
|
@ -84,21 +92,21 @@ static void start_world(Minecraft *minecraft) {
|
|||
settings.seed = seed;
|
||||
|
||||
// Select Level
|
||||
minecraft->selectLevel(&world_name, &world_name, &settings);
|
||||
minecraft->vtable->selectLevel(minecraft, &world_name, &world_name, &settings);
|
||||
|
||||
// Don't Open Port When Using --only-generate
|
||||
if (!only_generate) {
|
||||
// Open Port
|
||||
int port = get_server_properties().get_int("port", DEFAULT_PORT);
|
||||
INFO("Listening On: %i", port);
|
||||
minecraft->hostMultiplayer(port);
|
||||
Minecraft_hostMultiplayer(minecraft, port);
|
||||
}
|
||||
|
||||
// Open ProgressScreen
|
||||
ProgressScreen *screen = new ProgressScreen;
|
||||
ProgressScreen *screen = alloc_ProgressScreen();
|
||||
ALLOC_CHECK(screen);
|
||||
screen = screen->constructor();
|
||||
minecraft->setScreen((Screen *) screen);
|
||||
screen = ProgressScreen_constructor(screen);
|
||||
Minecraft_setScreen(minecraft, (Screen *) screen);
|
||||
}
|
||||
|
||||
// Check If Running In Whitelist Mode
|
||||
|
@ -156,7 +164,7 @@ static RakNet_RakNetGUID get_rak_net_guid(Player *player) {
|
|||
}
|
||||
static RakNet_SystemAddress get_system_address(RakNet_RakPeer *rak_peer, RakNet_RakNetGUID guid) {
|
||||
// Get SystemAddress
|
||||
return rak_peer->GetSystemAddressFromGuid(guid);
|
||||
return rak_peer->vtable->GetSystemAddressFromGuid(rak_peer, guid);
|
||||
}
|
||||
static RakNet_RakPeer *get_rak_peer(Minecraft *minecraft) {
|
||||
return minecraft->rak_net_instance->peer;
|
||||
|
@ -164,7 +172,7 @@ static RakNet_RakPeer *get_rak_peer(Minecraft *minecraft) {
|
|||
static char *get_rak_net_guid_ip(RakNet_RakPeer *rak_peer, RakNet_RakNetGUID guid) {
|
||||
RakNet_SystemAddress address = get_system_address(rak_peer, guid);
|
||||
// Get IP
|
||||
return address.ToString(false, '|');
|
||||
return RakNet_SystemAddress_ToString(&address, false, '|');
|
||||
}
|
||||
|
||||
// Get IP From Player
|
||||
|
@ -199,7 +207,7 @@ static void ban_callback(Minecraft *minecraft, std::string username, Player *pla
|
|||
|
||||
// Kill Player
|
||||
static void kill_callback(__attribute__((unused)) Minecraft *minecraft, __attribute__((unused)) std::string username, Player *player) {
|
||||
player->hurt(nullptr, INT32_MAX);
|
||||
player->vtable->hurt(player, nullptr, INT32_MAX);
|
||||
INFO("Killed: %s", username.c_str());
|
||||
}
|
||||
|
||||
|
@ -215,9 +223,9 @@ static void handle_server_stop(Minecraft *minecraft) {
|
|||
// Save And Exit
|
||||
Level *level = get_level(minecraft);
|
||||
if (level != nullptr) {
|
||||
level->saveLevelData();
|
||||
Level_saveLevelData_injection(level);
|
||||
}
|
||||
minecraft->leaveGame(false);
|
||||
Minecraft_leaveGame(minecraft, false);
|
||||
// Stop Game
|
||||
SDL_Event event;
|
||||
event.type = SDL_QUIT;
|
||||
|
@ -228,7 +236,7 @@ static void handle_server_stop(Minecraft *minecraft) {
|
|||
// Track TPS
|
||||
#define NANOSECONDS_IN_SECOND 1000000000ll
|
||||
static long long int get_time() {
|
||||
timespec ts = {};
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
long long int a = (long long int) ts.tv_nsec;
|
||||
long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;
|
||||
|
@ -258,7 +266,7 @@ static volatile bool stdin_buffer_complete = false;
|
|||
static volatile char *stdin_buffer = nullptr;
|
||||
static void *read_stdin_thread(__attribute__((unused)) void *data) {
|
||||
// Loop
|
||||
while (true) {
|
||||
while (1) {
|
||||
int bytes_available;
|
||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
|
@ -293,7 +301,7 @@ __attribute__((destructor)) static void _free_stdin_buffer() {
|
|||
// Handle Commands
|
||||
static void handle_commands(Minecraft *minecraft) {
|
||||
// Check If Level Is Generated
|
||||
if (minecraft->isLevelGenerated() && stdin_buffer_complete) {
|
||||
if (Minecraft_isLevelGenerated(minecraft) && stdin_buffer_complete) {
|
||||
// Command Ready; Run It
|
||||
if (stdin_buffer != nullptr) {
|
||||
ServerSideNetworkHandler *server_side_network_handler = get_server_side_network_handler(minecraft);
|
||||
|
@ -325,7 +333,7 @@ static void handle_commands(Minecraft *minecraft) {
|
|||
char *safe_message = to_cp437(message.c_str());
|
||||
std::string cpp_string = safe_message;
|
||||
// Post Message To Chat
|
||||
server_side_network_handler->displayGameMessage(&cpp_string);
|
||||
ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &cpp_string);
|
||||
// Free
|
||||
free(safe_message);
|
||||
} else if (data == list_command) {
|
||||
|
@ -373,7 +381,7 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
|
|||
}
|
||||
|
||||
// Handle --only-generate
|
||||
if (only_generate && minecraft->isLevelGenerated()) {
|
||||
if (only_generate && Minecraft_isLevelGenerated(minecraft)) {
|
||||
// Request Exit
|
||||
compat_request_exit();
|
||||
// Disable Special Behavior After Requesting Exit
|
||||
|
@ -425,7 +433,7 @@ static bool is_ip_in_blacklist(const char *ip) {
|
|||
}
|
||||
|
||||
// Ban Players
|
||||
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) RakNet_RakPeer_IsBanned_t original, __attribute__((unused)) RakNet_RakPeer *rakpeer, const char *ip) {
|
||||
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) RakNet_RakPeer *rakpeer, const char *ip) {
|
||||
// Check List
|
||||
bool ret = is_ip_in_blacklist(ip);
|
||||
if (is_whitelist()) {
|
||||
|
@ -438,7 +446,7 @@ static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) RakNet_Rak
|
|||
// Log IPs
|
||||
static Player *ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection(ServerSideNetworkHandler *server_side_network_handler, RakNet_RakNetGUID *guid) {
|
||||
// Call Original Method
|
||||
Player *player = server_side_network_handler->popPendingPlayer(guid);
|
||||
Player *player = ServerSideNetworkHandler_popPendingPlayer(server_side_network_handler, guid);
|
||||
|
||||
// Check If Player Is Null
|
||||
if (player != nullptr) {
|
||||
|
@ -568,7 +576,7 @@ static void server_init() {
|
|||
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3}; // "mov r3, #MAX_PLAYERS"
|
||||
patch((void *) 0x166d0, max_players_patch);
|
||||
// Custom Banned IP List
|
||||
overwrite_virtual_calls(RakNet_RakPeer_IsBanned, RakNet_RakPeer_IsBanned_injection);
|
||||
patch_address(RakNet_RakPeer_IsBanned_vtable_addr, (void *) RakNet_RakPeer_IsBanned_injection);
|
||||
|
||||
// Show The MineCon Icon Next To MOTD In Server List
|
||||
if (get_server_properties().get_bool("show-minecon-badge", DEFAULT_SHOW_MINECON_BADGE)) {
|
||||
|
|
|
@ -33,23 +33,23 @@ static int32_t sdl_key_to_minecraft_key_injection(Common_sdl_key_to_minecraft_ke
|
|||
static void LocalPlayer_openTextEdit_injection(LocalPlayer *local_player, TileEntity *sign) {
|
||||
if (sign->type == 4) {
|
||||
Minecraft *minecraft = local_player->minecraft;
|
||||
TextEditScreen *screen = new TextEditScreen;
|
||||
TextEditScreen *screen = alloc_TextEditScreen();
|
||||
ALLOC_CHECK(screen);
|
||||
screen = screen->constructor((SignTileEntity *) sign);
|
||||
minecraft->setScreen((Screen *) screen);
|
||||
screen = TextEditScreen_constructor(screen, (SignTileEntity *) sign);
|
||||
Minecraft_setScreen(minecraft, (Screen *) screen);
|
||||
}
|
||||
}
|
||||
|
||||
// Store Text Input
|
||||
void sign_key_press(char key) {
|
||||
Keyboard::_inputText.push_back(key);
|
||||
Keyboard__inputText.push_back(key);
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_sign() {
|
||||
if (feature_has("Fix Sign Placement", server_disabled)) {
|
||||
// Fix Signs
|
||||
patch_vtable(LocalPlayer_openTextEdit, LocalPlayer_openTextEdit_injection);
|
||||
patch_address(LocalPlayer_openTextEdit_vtable_addr, (void *) LocalPlayer_openTextEdit_injection);
|
||||
}
|
||||
|
||||
// Handle Backspace
|
||||
|
|
|
@ -69,12 +69,12 @@ static int32_t Textures_loadAndBindTexture_injection(Textures *textures, __attri
|
|||
// Change Texture
|
||||
static std::string new_texture;
|
||||
if (new_texture.length() == 0) {
|
||||
std::string username = base64_encode(Strings::default_username);
|
||||
std::string username = base64_encode(Strings_default_username);
|
||||
new_texture = '$' + username;
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
return textures->loadAndBindTexture(&new_texture);
|
||||
return Textures_loadAndBindTexture(textures, &new_texture);
|
||||
}
|
||||
|
||||
// Init
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
// Resolve Source File Path
|
||||
#define SOURCE_FILE_BASE "data/libminecraftpe.so"
|
||||
extern std::string info_sound_data_state;
|
||||
std::string _sound_get_source_file() {
|
||||
static bool source_loaded = false;
|
||||
static std::string source;
|
||||
|
@ -39,11 +38,9 @@ std::string _sound_get_source_file() {
|
|||
// Fail
|
||||
WARN("Audio Source File Doesn't Exist: " SOURCE_FILE_BASE " (See: https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/SOUND.md)");
|
||||
source.assign("");
|
||||
info_sound_data_state = "Missing";
|
||||
} else {
|
||||
// Set
|
||||
source.assign(path);
|
||||
info_sound_data_state = "Loaded";
|
||||
}
|
||||
|
||||
// Free
|
||||
|
@ -69,11 +66,11 @@ static void play(std::string name, float x, float y, float z, float volume, floa
|
|||
media_audio_play(source.c_str(), resolved_name.c_str(), x, y, z, pitch, volume, is_ui);
|
||||
}
|
||||
}
|
||||
static void SoundEngine_playUI_injection(__attribute__((unused)) SoundEngine *sound_engine, std::string *name, float volume, float pitch) {
|
||||
play(*name, 0, 0, 0, volume, pitch, true);
|
||||
static void SoundEngine_playUI_injection(__attribute__((unused)) unsigned char *sound_engine, std::string const& name, float volume, float pitch) {
|
||||
play(name, 0, 0, 0, volume, pitch, true);
|
||||
}
|
||||
static void SoundEngine_play_injection(__attribute__((unused)) SoundEngine *sound_engine, std::string *name, float x, float y, float z, float volume, float pitch) {
|
||||
play(*name, x, y, z, volume, pitch, false);
|
||||
static void SoundEngine_play_injection(__attribute__((unused)) unsigned char *sound_engine, std::string const& name, float x, float y, float z, float volume, float pitch) {
|
||||
play(name, x, y, z, volume, pitch, false);
|
||||
}
|
||||
|
||||
// Refresh Data
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
TextInputBox *TextInputBox::create(const std::string &placeholder, const std::string &text) {
|
||||
// Construct
|
||||
TextInputBox *self = new TextInputBox;
|
||||
self->super.constructor();
|
||||
GuiComponent_constructor(&self->super);
|
||||
|
||||
// Setup
|
||||
self->m_xPos = 0;
|
||||
|
@ -111,11 +111,11 @@ void TextInputBox::keyPressed(int key) {
|
|||
|
||||
void TextInputBox::tick() {
|
||||
if (!m_lastFlashed) {
|
||||
m_lastFlashed = Common::getTimeMs();
|
||||
m_lastFlashed = Common_getTimeMs();
|
||||
}
|
||||
|
||||
if (m_bFocused) {
|
||||
if (Common::getTimeMs() > m_lastFlashed + 500) {
|
||||
if (Common_getTimeMs() > m_lastFlashed + 500) {
|
||||
m_lastFlashed += 500;
|
||||
m_bCursorOn ^= 1;
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ void TextInputBox::setFocused(bool b) {
|
|||
|
||||
m_bFocused = b;
|
||||
if (b) {
|
||||
m_lastFlashed = Common::getTimeMs();
|
||||
m_lastFlashed = Common_getTimeMs();
|
||||
m_bCursorOn = true;
|
||||
m_insertHead = int(m_text.size());
|
||||
recalculateScroll();
|
||||
|
@ -167,7 +167,7 @@ void TextInputBox::charPressed(int k) {
|
|||
static std::string get_rendered_text(Font *font, int width, int scroll_pos, std::string text) {
|
||||
std::string rendered_text = text.substr(scroll_pos);
|
||||
int max_width = width - (PADDING * 2);
|
||||
while (font->width(&rendered_text) > max_width) {
|
||||
while (Font_width(font, &rendered_text) > max_width) {
|
||||
rendered_text.pop_back();
|
||||
}
|
||||
return rendered_text;
|
||||
|
@ -176,8 +176,8 @@ static std::string get_rendered_text(Font *font, int width, int scroll_pos, std:
|
|||
static char CURSOR_CHAR = '_';
|
||||
|
||||
void TextInputBox::render() {
|
||||
super.fill(m_xPos, m_yPos, m_xPos + m_width, m_yPos + m_height, 0xFFAAAAAA);
|
||||
super.fill(m_xPos + 1, m_yPos + 1, m_xPos + m_width - 1, m_yPos + m_height - 1, 0xFF000000);
|
||||
GuiComponent_fill(&super, m_xPos, m_yPos, m_xPos + m_width, m_yPos + m_height, 0xFFAAAAAA);
|
||||
GuiComponent_fill(&super, m_xPos + 1, m_yPos + 1, m_xPos + m_width - 1, m_yPos + m_height - 1, 0xFF000000);
|
||||
|
||||
int text_color;
|
||||
int scroll_pos;
|
||||
|
@ -194,17 +194,17 @@ void TextInputBox::render() {
|
|||
rendered_text = get_rendered_text(m_pFont, m_width, scroll_pos, rendered_text);
|
||||
|
||||
int textYPos = (m_height - 8) / 2;
|
||||
super.drawString(m_pFont, &rendered_text, m_xPos + PADDING, m_yPos + textYPos, text_color);
|
||||
GuiComponent_drawString(&super, m_pFont, &rendered_text, m_xPos + PADDING, m_yPos + textYPos, text_color);
|
||||
|
||||
if (m_bCursorOn) {
|
||||
int cursor_pos = m_insertHead - m_scrollPos;
|
||||
if (cursor_pos >= 0 && cursor_pos <= int(rendered_text.length())) {
|
||||
std::string substr = rendered_text.substr(0, cursor_pos);
|
||||
int xPos = PADDING + m_pFont->width(&substr);
|
||||
int xPos = PADDING + Font_width(m_pFont, &substr);
|
||||
|
||||
std::string str;
|
||||
str += CURSOR_CHAR;
|
||||
super.drawString(m_pFont, &str, m_xPos + xPos, m_yPos + textYPos + 2, 0xffffff);
|
||||
GuiComponent_drawString(&super, m_pFont, &str, m_xPos + xPos, m_yPos + textYPos + 2, 0xffffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <mods/init/init.h>
|
||||
|
||||
// Disable Texture Loading
|
||||
static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) AppPlatform_linux_loadTexture_t original, __attribute__((unused)) AppPlatform_linux *app_platform, __attribute__((unused)) std::string *path, __attribute__((unused)) bool b) {
|
||||
static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) AppPlatform_linux *app_platform, __attribute__((unused)) std::string *path, __attribute__((unused)) bool b) {
|
||||
Texture out;
|
||||
out.width = 0;
|
||||
out.height = 0;
|
||||
|
@ -19,5 +19,5 @@ static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) A
|
|||
// Init
|
||||
void init_textures() {
|
||||
// Disable Texture Loading
|
||||
overwrite_virtual_calls(AppPlatform_linux_loadTexture, AppPlatform_linux_loadTexture_injection);
|
||||
overwrite((void *) AppPlatform_linux_loadTexture_non_virtual, (void *) AppPlatform_linux_loadTexture_injection);
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ CUSTOM_VTABLE(lava_texture, DynamicTexture) {
|
|||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
float f = 0.0F;
|
||||
int ax = int(Mth::sin((float(x) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
int ay = int(Mth::sin((float(y) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
int ax = int(Mth_sin((float(x) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
int ay = int(Mth_sin((float(y) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
for (int bx = x - 1; bx <= x + 1; bx++) {
|
||||
for (int by = y - 1; by <= y + 1; by++) {
|
||||
int k2 = (bx + ay) & 0xf;
|
||||
|
@ -57,7 +57,7 @@ CUSTOM_VTABLE(lava_texture, DynamicTexture) {
|
|||
self->m_data3[x + y * 16] = 0.0f;
|
||||
}
|
||||
self->m_data4[x + y * 16] -= 0.06f;
|
||||
if (Mth::random() < 0.005f) {
|
||||
if (Mth_random() < 0.005f) {
|
||||
self->m_data4[x + y * 16] = 1.5f;
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ static DynamicTexture *create_lava_texture() {
|
|||
// Construct
|
||||
LavaTexture *texture = new LavaTexture;
|
||||
ALLOC_CHECK(texture);
|
||||
texture->super.constructor(Tile::lava->texture);
|
||||
DynamicTexture_constructor(&texture->super, Tile_lava->texture);
|
||||
// Set VTable
|
||||
texture->super.vtable = get_lava_texture_vtable();
|
||||
// Setup
|
||||
|
@ -106,8 +106,8 @@ CUSTOM_VTABLE(lava_side_texture, DynamicTexture) {
|
|||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
float f = 0.0F;
|
||||
int ax = int(Mth::sin((float(x) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
int ay = int(Mth::sin((float(y) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
int ax = int(Mth_sin((float(x) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
int ay = int(Mth_sin((float(y) * float(M_PI) * 2) / 16.0f) * 1.2f);
|
||||
for (int bx = x - 1; bx <= x + 1; bx++) {
|
||||
for (int by = y - 1; by <= y + 1; by++) {
|
||||
int k2 = (bx + ay) & 0xf;
|
||||
|
@ -121,7 +121,7 @@ CUSTOM_VTABLE(lava_side_texture, DynamicTexture) {
|
|||
self->m_data3[x + y * 16] = 0.0f;
|
||||
}
|
||||
self->m_data4[x + y * 16] -= 0.06f;
|
||||
if (Mth::random() < 0.005f) {
|
||||
if (Mth_random() < 0.005f) {
|
||||
self->m_data4[x + y * 16] = 1.5f;
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ static DynamicTexture *create_lava_side_texture() {
|
|||
// Construct
|
||||
LavaSideTexture *texture = new LavaSideTexture;
|
||||
ALLOC_CHECK(texture);
|
||||
texture->super.constructor(Tile::lava->texture + 1);
|
||||
DynamicTexture_constructor(&texture->super, Tile_lava->texture + 1);
|
||||
// Set VTable
|
||||
texture->super.vtable = get_lava_side_texture_vtable();
|
||||
// Setup
|
||||
|
@ -189,7 +189,7 @@ CUSTOM_VTABLE(fire_texture, DynamicTexture) {
|
|||
uint32_t x;
|
||||
uint8_t b[4];
|
||||
} a;
|
||||
a.x = self->m_random.genrand_int32();
|
||||
a.x = Random_genrand_int32(&self->m_random);
|
||||
self->m_data2[i + j * 16] = 0.2f + (((a.b[3] / 256.0f) * 0.1f) + ((((a.b[0] / 256.0f) * (a.b[1] / 256.0f)) * (a.b[2] / 256.0f)) * 4.0f));
|
||||
}
|
||||
}
|
||||
|
@ -214,11 +214,11 @@ static DynamicTexture *create_fire_texture(int a2) {
|
|||
// Construct
|
||||
FireTexture *texture = new FireTexture;
|
||||
ALLOC_CHECK(texture);
|
||||
texture->super.constructor(Tile::fire->texture + (16 * a2));
|
||||
DynamicTexture_constructor(&texture->super, Tile_fire->texture + (16 * a2));
|
||||
// Set VTable
|
||||
texture->super.vtable = get_fire_texture_vtable();
|
||||
// Setup Random
|
||||
int seed = Common::getTimeMs();
|
||||
int seed = Common_getTimeMs();
|
||||
texture->m_random.seed = seed;
|
||||
texture->m_random.param_1 = 0x271;
|
||||
texture->m_random.param_2 = false;
|
||||
|
@ -238,17 +238,17 @@ static bool animated_fire = false;
|
|||
static void Textures_addDynamicTexture_injection(Textures *textures, DynamicTexture *dynamic_texture) {
|
||||
// Call Original Method
|
||||
if (animated_water) {
|
||||
textures->addDynamicTexture(dynamic_texture);
|
||||
Textures_addDynamicTexture(textures, dynamic_texture);
|
||||
}
|
||||
|
||||
// Add Lava
|
||||
if (animated_lava) {
|
||||
textures->addDynamicTexture(create_lava_texture());
|
||||
textures->addDynamicTexture(create_lava_side_texture());
|
||||
Textures_addDynamicTexture(textures, create_lava_texture());
|
||||
Textures_addDynamicTexture(textures, create_lava_side_texture());
|
||||
}
|
||||
if (animated_fire) {
|
||||
textures->addDynamicTexture(create_fire_texture(0));
|
||||
textures->addDynamicTexture(create_fire_texture(1));
|
||||
Textures_addDynamicTexture(textures, create_fire_texture(0));
|
||||
Textures_addDynamicTexture(textures, create_fire_texture(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ static void Minecraft_tick_injection(Minecraft *minecraft) {
|
|||
// Tick Dynamic Textures
|
||||
Textures *textures = minecraft->textures;
|
||||
if (textures != nullptr) {
|
||||
textures->tick(true);
|
||||
Textures_tick(textures, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ static void Textures_tick_glTexSubImage2D_injection(GLenum target, GLint level,
|
|||
}
|
||||
|
||||
// Load Textures
|
||||
static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) AppPlatform_linux_loadTexture_t original, __attribute__((unused)) AppPlatform_linux *app_platform, std::string *path, bool b) {
|
||||
static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) AppPlatform_linux *app_platform, std::string *path, bool b) {
|
||||
Texture out;
|
||||
std::string real_path = *path;
|
||||
if (b) {
|
||||
|
@ -234,5 +234,5 @@ void init_textures() {
|
|||
overwrite_call((void *) 0x53274, (void *) Textures_tick_glTexSubImage2D_injection);
|
||||
|
||||
// Load Textures
|
||||
overwrite_virtual_calls(AppPlatform_linux_loadTexture, AppPlatform_linux_loadTexture_injection);
|
||||
overwrite(*AppPlatform_linux_loadTexture_vtable_addr, AppPlatform_linux_loadTexture_injection);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ static void StartMenuScreen_render_Screen_renderBackground_injection(Screen *scr
|
|||
Minecraft *minecraft = screen->minecraft;
|
||||
Textures *textures = minecraft->textures;
|
||||
std::string texture = "gui/titleBG.png";
|
||||
textures->loadAndBindTexture(&texture);
|
||||
screen->blit(0, 0, 0, 0, screen->width, screen->height, 0x100, 0x100);
|
||||
Textures_loadAndBindTexture(textures, &texture);
|
||||
Screen_blit(screen, 0, 0, 0, 0, screen->width, screen->height, 0x100, 0x100);
|
||||
}
|
||||
|
||||
// Add Buttons Back To Classic Start Screen
|
||||
|
@ -88,21 +88,20 @@ static void StartMenuScreen_render_Screen_render_injection(Screen *screen, int x
|
|||
current_splash = splashes[rand() % splashes.size()];
|
||||
}
|
||||
// Choose Position
|
||||
float multiplier = touch_gui ? 0.5f : 1.0f;
|
||||
float multiplier = touch_gui ? 0.5f: 1.0f;
|
||||
float splash_x = (float(screen->width) / 2.0f) + (94.0f * multiplier);
|
||||
float splash_y = 4.0f + (36.0f * multiplier);
|
||||
float max_width = 86;
|
||||
float max_scale = 2.0f;
|
||||
// Draw (From https://github.com/ReMinecraftPE/mcpe/blob/d7a8b6baecf8b3b050538abdbc976f690312aa2d/source/client/gui/screens/StartMenuScreen.cpp#L699-L718)
|
||||
glPushMatrix();
|
||||
// Position
|
||||
glTranslatef(splash_x, splash_y, 0.0f);
|
||||
glRotatef(-20.0f, 0.0f, 0.0f, 1.0f);
|
||||
// Scale
|
||||
int textWidth = screen->font->width(¤t_splash);
|
||||
float timeMS = float(Common::getTimeMs() % 1000) / 1000.0f;
|
||||
float scale = max_scale - Mth::abs(0.1f * Mth::sin(2.0f * float(M_PI) * timeMS));
|
||||
float real_text_width = textWidth * max_scale;
|
||||
int textWidth = Font_width(screen->font, ¤t_splash);
|
||||
float timeMS = float(Common_getTimeMs() % 1000) / 1000.0f;
|
||||
float scale = 2.0f - Mth_abs(0.1f * Mth_sin(2.0f * float(M_PI) * timeMS));
|
||||
float real_text_width = textWidth * scale;
|
||||
if (real_text_width > max_width) {
|
||||
scale *= max_width / real_text_width;
|
||||
}
|
||||
|
@ -110,7 +109,7 @@ static void StartMenuScreen_render_Screen_render_injection(Screen *screen, int x
|
|||
glScalef(scale, scale, scale);
|
||||
// Render
|
||||
static int line_height = 8;
|
||||
screen->drawCenteredString(screen->font, ¤t_splash, 0, -(float(line_height) / 2), 0xffff00);
|
||||
Screen_drawCenteredString(screen, screen->font, ¤t_splash, 0, -(float(line_height) / 2), 0xffff00);
|
||||
// Finish
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -152,7 +151,7 @@ void init_title_screen() {
|
|||
}
|
||||
|
||||
// Rename "Create" Button To "Quit"
|
||||
patch_address((void *) &Strings::classic_create_button_text, (void *) "Quit");
|
||||
patch_address((void *) Strings_classic_create_button_text_pointer, (void *) "Quit");
|
||||
|
||||
// Add Functionality To Quit Button
|
||||
overwrite_virtual_calls(StartMenuScreen_buttonClicked, StartMenuScreen_buttonClicked_injection);
|
||||
|
|
|
@ -13,14 +13,14 @@ static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) Minecra
|
|||
|
||||
// IngameBlockSelectionScreen Memory Allocation Override
|
||||
static unsigned char *operator_new_IngameBlockSelectionScreen_injection(__attribute__((unused)) uint32_t size) {
|
||||
return (unsigned char *) ::operator new(sizeof(Touch_IngameBlockSelectionScreen));
|
||||
return (unsigned char *) ::operator new(TOUCH_INGAME_BLOCK_SELECTION_SCREEN_SIZE);
|
||||
}
|
||||
|
||||
// Improved Button Hover Behavior
|
||||
static int32_t Button_hovered_injection(__attribute__((unused)) Button *button, __attribute__((unused)) Minecraft *minecraft, __attribute__((unused)) int32_t click_x, __attribute__((unused)) int32_t click_y) {
|
||||
// Get Mouse Position
|
||||
int32_t x = Mouse::getX() * Gui::InvGuiScale;
|
||||
int32_t y = Mouse::getY() * Gui::InvGuiScale;
|
||||
int32_t x = Mouse_getX() * Gui_InvGuiScale;
|
||||
int32_t y = Mouse_getY() * Gui_InvGuiScale;
|
||||
|
||||
// Get Button Position
|
||||
int32_t button_x1 = button->x;
|
||||
|
@ -38,24 +38,25 @@ static void LargeImageButton_render_GuiComponent_drawCenteredString_injection(Gu
|
|||
}
|
||||
|
||||
// Call Original Method
|
||||
component->drawCenteredString(font, text, x, y, color);
|
||||
GuiComponent_drawCenteredString(component, font, text, x, y, color);
|
||||
}
|
||||
|
||||
// Create Button
|
||||
int touch_gui = 0;
|
||||
template <typename T>
|
||||
static Button *create_button(int id, std::string text) {
|
||||
T *button = new T;
|
||||
ALLOC_CHECK(button);
|
||||
button->constructor(id, &text);
|
||||
return (Button *) button;
|
||||
}
|
||||
Button *touch_create_button(int id, std::string text) {
|
||||
Button *button = nullptr;
|
||||
if (touch_gui) {
|
||||
return create_button<Touch_TButton>(id, text);
|
||||
button = (Button *) new Touch_TButton;
|
||||
} else {
|
||||
return create_button<Button>(id, text);
|
||||
button = new Button;
|
||||
}
|
||||
ALLOC_CHECK(button);
|
||||
if (touch_gui) {
|
||||
Touch_TButton_constructor((Touch_TButton *) button, id, &text);
|
||||
} else {
|
||||
Button_constructor(button, id, &text);
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
// Init
|
||||
|
@ -64,7 +65,7 @@ void init_touch() {
|
|||
int touch_buttons = touch_gui;
|
||||
if (touch_gui) {
|
||||
// Main UI
|
||||
overwrite(Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection);
|
||||
overwrite((void *) Minecraft_isTouchscreen, (void *) Minecraft_isTouchscreen_injection);
|
||||
|
||||
// Force Correct Toolbar Size
|
||||
unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1"
|
||||
|
@ -97,7 +98,7 @@ void init_touch() {
|
|||
|
||||
// Improved Button Hover Behavior
|
||||
if (touch_buttons && feature_has("Improved Button Hover Behavior", server_disabled)) {
|
||||
overwrite(Button_hovered, Button_hovered_injection);
|
||||
overwrite((void *) Button_hovered, (void *) Button_hovered_injection);
|
||||
overwrite_call((void *) 0x1ebd4, (void *) LargeImageButton_render_GuiComponent_drawCenteredString_injection);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ char *version_get() {
|
|||
static char *version = nullptr;
|
||||
// Load
|
||||
if (version == nullptr) {
|
||||
safe_asprintf(&version, "%s / Reborn v%s", Strings::minecraft_pi_version, reborn_get_version());
|
||||
safe_asprintf(&version, "%s / Reborn v%s", Strings_minecraft_pi_version, reborn_get_version());
|
||||
}
|
||||
// Return
|
||||
return version;
|
||||
|
@ -20,7 +20,7 @@ __attribute__((destructor)) static void _free_version() {
|
|||
}
|
||||
|
||||
// Injection For Touch GUI Version
|
||||
static std::string Common_getGameVersionString_injection(__attribute__((unused)) std::string *version_suffix) {
|
||||
static std::string Common_getGameVersionString_injection(__attribute__((unused)) std::string const& version_suffix) {
|
||||
// Set Version
|
||||
return version_get();
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ static std::string Common_getGameVersionString_injection(__attribute__((unused))
|
|||
// Init
|
||||
void init_version() {
|
||||
// Touch GUI
|
||||
overwrite(Common_getGameVersionString, Common_getGameVersionString_injection);
|
||||
overwrite((void *) Common_getGameVersionString, (void *) Common_getGameVersionString_injection);
|
||||
// Normal GUI
|
||||
patch_address((void *) &Strings::minecraft_pi_version, version_get());
|
||||
patch_address((void *) Strings_minecraft_pi_version_pointer, version_get());
|
||||
|
||||
// Log
|
||||
INFO("Starting Minecraft: Pi Edition (%s)", version_get());
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue