From e1ddc78d31c6326d91ef7e8a2bf2a1a41989122e Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 1 Oct 2020 11:08:46 -0400 Subject: [PATCH] Add Survival Mode --- Dockerfile | 8 +- Jenkinsfile | 2 +- core/include/libcore/libcore.h | 3 +- core/src/core.c | 46 ++++++-- debian/DEBIAN/control | 2 +- debian/usr/bin/minecraft-pi | 2 + .../usr/share/minecraft-pi/docker-compose.yml | 1 + mods/CMakeLists.txt | 4 +- mods/src/compat.c | 1 - mods/src/extra.c | 104 ++++++++++++++++++ mods/src/touch.c | 6 - scripts/build.sh | 2 +- 12 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 mods/src/extra.c delete mode 100644 mods/src/touch.c diff --git a/Dockerfile b/Dockerfile index 1c84b265d..bc322d523 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,16 +10,18 @@ RUN apt-get install -y libglvnd-dev:armhf libsdl1.2-dev:armhf libx11-dev:armhf b RUN ln -s /usr/lib/arm-linux-gnueabihf/libGLESv2.so.2 /usr/lib/libGLESv2.so RUN ln -s /usr/lib/arm-linux-gnueabihf/libEGL.so.1 /usr/lib/libEGL.so -ADD . /app +ADD ./build /app/build WORKDIR /app RUN ./build/download-minecraft-pi.sh -RUN ./build/build-mods.sh - RUN ./build/build-libpng12.sh +ADD . /app + +RUN ./build/build-mods.sh + WORKDIR ./minecraft-pi ENTRYPOINT ./launcher diff --git a/Jenkinsfile b/Jenkinsfile index ee3c213f6..924f38866 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,7 +13,7 @@ pipeline { } stage('Build') { steps { - sh './scripts/build.sh' + sh 'DOCKER_BUILD_OPTIONS="--no-cache" ./scripts/build.sh' } } stage('Publish') { diff --git a/core/include/libcore/libcore.h b/core/include/libcore/libcore.h index bfeff27f0..3e3cf94ab 100644 --- a/core/include/libcore/libcore.h +++ b/core/include/libcore/libcore.h @@ -27,7 +27,8 @@ extern "C" { \ __attribute__((__used__)) return_type name args -void overwrite(void *start, void *target); +void *overwrite(void *start, void *target); +void revert_overwrite(void *start, void *original); void patch(void *start, unsigned char patch[]); #ifdef __cplusplus diff --git a/core/src/core.c b/core/src/core.c index 0ea3da141..34638f5d8 100644 --- a/core/src/core.c +++ b/core/src/core.c @@ -6,9 +6,11 @@ #include -#define PREPARE_PATCH(start) \ +#define PATCH_PRINTF(print, start, str) if (print) fprintf(stderr, "Patching (0x%04x) - "str": 0x%02x 0x%02x 0x%02x 0x%02x\n", (uint32_t) start, data[0], data[1], data[2], data[3]); + +#define PREPARE_PATCH(print, count) \ size_t page_size = sysconf(_SC_PAGESIZE); \ - uintptr_t end = ((uintptr_t) start) + 1; \ + uintptr_t end = ((uintptr_t) start) + (4 * count); \ uintptr_t page_start = ((uintptr_t) start) & -page_size; \ mprotect((void *) page_start, end - page_start, PROT_READ | PROT_WRITE); \ \ @@ -17,15 +19,22 @@ if (thumb) { \ data--; \ } \ - fprintf(stderr, "Patching - original: %i %i %i %i %i\n", data[0], data[1], data[2], data[3], data[4]); + PATCH_PRINTF(print, start, "original"); -#define END_PATCH() \ - fprintf(stderr, "Patching - result: %i %i %i %i %i\n", data[0], data[1], data[2], data[3], data[4]); \ +#define END_PATCH(print) \ + PATCH_PRINTF(print, start, "result"); \ \ - mprotect((void *) page_start, end - page_start, PROT_READ | PROT_EXEC); + mprotect((void *) page_start, end - page_start, PROT_READ | PROT_EXEC); \ + __clear_cache(start, (void *) end); + +#define ORIGINAL_SIZE 4 + sizeof (int) + +void *overwrite(void *start, void *target) { + PREPARE_PATCH(1, 2); + + void *original = malloc(ORIGINAL_SIZE); + memcpy(original, start, ORIGINAL_SIZE); -void overwrite(void *start, void *target) { - PREPARE_PATCH(start); if (thumb) { unsigned char patch[4] = {0xdf, 0xf8, 0x00, 0xf0}; memcpy(data, patch, 4); @@ -34,11 +43,26 @@ void overwrite(void *start, void *target) { memcpy(data, patch, 4); } memcpy(&data[4], &target, sizeof (int)); - END_PATCH(); + + END_PATCH(1); + + return original; +} + +void revert_overwrite(void *start, void *original) { + PREPARE_PATCH(0, 2); + + void *temp = malloc(ORIGINAL_SIZE); + memcpy(temp, data, ORIGINAL_SIZE); + memcpy(data, original, ORIGINAL_SIZE); + memcpy(original, temp, ORIGINAL_SIZE); + free(temp); + + END_PATCH(0); } void patch(void *start, unsigned char patch[]) { - PREPARE_PATCH(start); + PREPARE_PATCH(1, 1); memcpy(data, patch, 4); - END_PATCH(); + END_PATCH(1); } diff --git a/debian/DEBIAN/control b/debian/DEBIAN/control index bcdac30a9..4da80c9fa 100644 --- a/debian/DEBIAN/control +++ b/debian/DEBIAN/control @@ -4,4 +4,4 @@ Maintainer: TheBrokenRail Description: Fun with Blocks Homepage: https://www.minecraft.net/en-us/edition/pi Architecture: amd64 -Depends: docker.io, docker-compose, virgl-server +Depends: docker.io, docker-compose, virgl-server, zenity diff --git a/debian/usr/bin/minecraft-pi b/debian/usr/bin/minecraft-pi index a8463ed4f..063b4d259 100755 --- a/debian/usr/bin/minecraft-pi +++ b/debian/usr/bin/minecraft-pi @@ -2,6 +2,8 @@ set -e +export FEATURES="$(zenity --class minecraft-pi --list --checklist --column 'Enabled' --column 'Feature' FALSE 'Touch GUI' FALSE 'Survival Mode' FALSE 'Fix Bow & Arrow' FALSE 'Fix Attacking' FALSE 'Mob Spawning')" + virgl_test_server & PID="$!" diff --git a/debian/usr/share/minecraft-pi/docker-compose.yml b/debian/usr/share/minecraft-pi/docker-compose.yml index 60d834dc9..53ee669d7 100644 --- a/debian/usr/share/minecraft-pi/docker-compose.yml +++ b/debian/usr/share/minecraft-pi/docker-compose.yml @@ -9,3 +9,4 @@ services: - '~/.minecraft-pi:/root/.minecraft' environment: - 'DISPLAY=unix${DISPLAY}' + - 'FEATURES=${FEATURES}' diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 2288d7c25..37b55a4e6 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -12,8 +12,8 @@ target_link_libraries(compat core SDL EGL GLESv1_CM GLESv2 X11 dl) # Force GLESv1 Link target_link_options(compat PRIVATE "-Wl,--no-as-needed") -add_library(touch SHARED src/touch.c) -target_link_libraries(touch core dl) +add_library(extra SHARED src/extra.c) +target_link_libraries(extra core dl) add_library(readdir SHARED src/readdir.c) target_link_libraries(readdir core) diff --git a/mods/src/compat.c b/mods/src/compat.c index 1b67172b6..7483503d8 100644 --- a/mods/src/compat.c +++ b/mods/src/compat.c @@ -144,7 +144,6 @@ HOOK(eglSwapBuffers, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __ } static void resize(int width, int height, int fullscreen) { - fprintf(stderr, "W: %i H: %i FS: %i\n", width, height, fullscreen); Uint32 flags = fullscreen ? FULLSCREEN_VIDEO_FLAGS : WINDOW_VIDEO_FLAGS; ensure_SDL_SetVideoMode(); diff --git a/mods/src/extra.c b/mods/src/extra.c new file mode 100644 index 000000000..efe86eb33 --- /dev/null +++ b/mods/src/extra.c @@ -0,0 +1,104 @@ +#include +#include + +#include + +static int32_t get_game_type(__attribute__((unused)) int32_t level_data) { + return 0; +} + +static uint32_t can_spawn_mobs(__attribute__((unused)) int32_t obj) { + return 1; +} + +#include + +typedef void (*releaseUsingItem_t)(unsigned char *t, unsigned char *player); +static releaseUsingItem_t survival_releaseUsingItem = (releaseUsingItem_t) 0x1a598; +static releaseUsingItem_t creative_releaseUsingItem = (releaseUsingItem_t) 0x1b1a0; + +typedef void (*handle_input_t)(unsigned char *, unsigned char *, unsigned char *, unsigned char *); +static handle_input_t handle_input = (handle_input_t) 0x15ffc; +static void *handle_input_original = NULL; + +static int is_survival = 0; + +static void handle_input_injection(unsigned char *param_1, unsigned char *param_2, unsigned char *param_3, unsigned char *param_4) { + // Call Original Method + revert_overwrite((void *) handle_input, handle_input_original); + (*handle_input)(param_1, param_2, param_3, param_4); + revert_overwrite((void *) handle_input, handle_input_original); + + // GameMode Is Offset From param_1 By 0x160 + // Player Is Offset From param_1 By 0x18c + int using_item = SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_RIGHT); + if (!using_item) { + unsigned char *game_mode = *(unsigned char **) (param_1 + 0x160); + unsigned char *player = *(unsigned char **) (param_1 + 0x18c); + if (player != NULL && game_mode != NULL) { + (*(is_survival ? survival_releaseUsingItem : creative_releaseUsingItem))(game_mode, player); + } + } +} + +static int has_feature(const char *name) { + char *env = getenv("FEATURES"); + char *features = strdup(env != NULL ? env : ""); + char *tok = strtok(features, "|"); + int ret = 0; + while (tok != NULL) { + if (strcmp(tok, name) == 0) { + ret = 1; + break; + } + tok = strtok(NULL, "|"); + } + free(features); + fprintf(stderr, "Feature: %s: %s\n", name, ret ? "Enabled" : "Disabled"); + return ret; +} + +__attribute__((constructor)) static void init() { + if (has_feature("Touch GUI")) { + // Use Touch UI + unsigned char patch_data[4] = {0x01, 0x00, 0x50, 0xe3}; + patch((void *) 0x292fc, patch_data); + } + + is_survival = has_feature("Survival Mode"); + if (is_survival) { + // Survival Mode Inventpry UI + unsigned char patch_data_2[4] = {0x00, 0x30, 0xa0, 0xe3}; + patch((void *) 0x16efc, patch_data_2); + + // Replace Creative Mode VTable With Survival Mode VTable + patch((void *) 0x1a0d8, (unsigned char *) 0x1b804); + + // Use Correct Size For Survival Mode Object + unsigned char patch_data_3[4] = {0x24, 0x00, 0xa0, 0xe3}; + patch((void *) 0x1a054, patch_data_3); + + // Force GameType To 0 (Required For Day-Night Cycle) + overwrite((void *) 0xbabdc, get_game_type); + } + + if (has_feature("Fix Bow & Arrow")) { + // Fix Bow + handle_input_original = overwrite((void *) handle_input, handle_input_injection); + } + + if (has_feature("Fix Attacking")) { + // Allow Attacking Mobs + unsigned char patch_data_5[4] = {0x00, 0xf0, 0x20, 0xe3}; + patch((void *) 0x162d4, patch_data_5); + } + + if (has_feature("Mob Spawning")) { + // Enable Mob Spawning + overwrite((void *) 0xbabec, can_spawn_mobs); + + // Replace CreatorLevel With Level + unsigned char patch_data_4[4] = {0x96, 0x3d, 0x02, 0xeb}; + patch((void *) 0x16f84, patch_data_4); + } +} diff --git a/mods/src/touch.c b/mods/src/touch.c deleted file mode 100644 index 06099eb0a..000000000 --- a/mods/src/touch.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -__attribute__((constructor)) static void init() { - unsigned char patch_data[4] = {0x01, 0x00, 0x50, 0xe3}; - patch((void *) 0x292fc, patch_data); -} diff --git a/scripts/build.sh b/scripts/build.sh index bcc301a65..4d05a8908 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,4 +2,4 @@ set -e -docker build --no-cache --tag thebrokenrail/minecraft-pi:latest . +docker build ${DOCKER_BUILD_OPTIONS} --tag thebrokenrail/minecraft-pi:latest .