Compare commits

...

4 Commits

Author SHA1 Message Date
Bigjango13
5efbb19bcc Fix invalid ItemInHandRenderer texture cache 2024-02-13 01:29:49 -05:00
8152a4a5ca Also Scan .data.rel.ro 2024-02-13 01:29:49 -05:00
0d3b1e2a4b Bug Fixes & Low-Level Improvements 2024-02-13 01:29:45 -05:00
d5f747107b Small Changes 2024-02-13 01:28:42 -05:00
35 changed files with 433 additions and 77 deletions

View File

@ -87,9 +87,7 @@ jobs:
./out/client/host/usr/bin/minecraft-pi-reborn-client --copy-sdk
# Build Example Mods
- name: Build Example Mods
run: |
cd example-mods
./build.sh
run: ./example-mods/build.sh
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:

View File

@ -44,7 +44,8 @@ include(cmake/options/paths.cmake)
string(CONCAT COMPILE_FLAGS_SETUP
# Optimizations
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n"
" add_compile_options(-O3 -s)\n"
" add_compile_options(-O3)\n"
" add_link_options(-s)\n"
"else()\n"
" add_compile_options(-g)\n"
"endif()\n"
@ -159,6 +160,7 @@ if(BUILD_NATIVE_COMPONENTS)
else()
list(APPEND ARM_OPTIONS "-DMCPI_USE_PREBUILT_ARMHF_TOOLCHAIN:BOOL=TRUE")
endif()
list(APPEND ARM_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}")
# Build
ExternalProject_Add(arm-components
DOWNLOAD_COMMAND ""

View File

@ -11,12 +11,17 @@
* Add `Use Java Beta 1.3 Light Ramp` Feature Flag (Enabled By Default)
* Add `Send Full Level When Hosting Game` Feature Flag (Enabled By Default)
* Add `Food Overlay` Feature Flag (Disabled By Default)
* 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 Milk Buckets
* Implement Crafting Remainders
* Improve Death Messages
* Massive Build System Improvements
* Fix Item Dropping When Killing Players From The Server Console
* Fix Furnace Visual Bug When Using Lava Bucket As Fuel
* Add Splash Text To Start Screen
* `overwrite_calls` Now Scans VTables
**2.5.3**
* Add `Replace Block Highlight With Outline` Feature Flag (Enabled By Default)

View File

@ -3,6 +3,7 @@
set -e
# Create Output Directory
cd "$(dirname "$0")"
ROOT="$(pwd)"
OUT="${ROOT}/out"
rm -rf "${OUT}"

View File

@ -58,3 +58,5 @@ TRUE Use Java Beta 1.3 Light Ramp
TRUE Send Full Level When Hosting Game
FALSE Food Overlay
TRUE Add Splashes
TRUE Display Date In Select World Screen
TRUE Optimized Chunk Sorting

View File

@ -3,6 +3,9 @@
#include <LIEF/ELF.hpp>
#include <dlfcn.h>
#include <link.h>
#include <libreborn/libreborn.h>
#include "patchelf.h"

View File

@ -5,7 +5,7 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn")
configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
# Util
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c src/util/cp437.cpp)
add_library(reborn-util SHARED src/util/exec.c src/util/string.c src/util/util.c src/util/log.c src/util/cp437.cpp)
target_include_directories(
reborn-util
PUBLIC
@ -25,7 +25,7 @@ endif()
# Patch
if(BUILD_ARM_COMPONENTS)
add_library(reborn-patch SHARED src/patch/patch.c)
add_library(reborn-patch SHARED src/patch/patch.cpp src/patch/segments.cpp src/patch/code-block.cpp src/patch/instruction.cpp)
target_link_libraries(reborn-patch dl pthread reborn-util)
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
# Install

View File

@ -1,22 +0,0 @@
#pragma once
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <elf.h>
#include <link.h>
#include "log.h"
#include "exec.h"
#ifdef __cplusplus
extern "C" {
#endif
// Find And Iterate Over All Segments In Current Binary
typedef void (*segment_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
void iterate_segments(segment_callback_t callback, void *data);
#ifdef __cplusplus
}
#endif

View File

@ -5,6 +5,5 @@
#include "util.h"
#include "string.h"
#include "exec.h"
#include "elf.h"
#include "home.h"
#include "patch.h"

View File

@ -8,6 +8,8 @@ extern "C" {
#ifdef REBORN_HAS_PATCH_CODE
void reborn_init_patch();
void _overwrite_call(const char *file, int line, void *start, void *target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);

View File

@ -0,0 +1,46 @@
#include <sys/mman.h>
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Limit To 512 overwrite_calls() Uses
#define CODE_BLOCK_SIZE 4096
static unsigned char *code_block = NULL;
#define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE;
// Create Long Overwrite At Current Position
static void long_overwrite(void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(NULL, -1, start, patch_data);
_patch_address(NULL, -1, (void *) (((unsigned char *) start) + 4), target);
}
void *update_code_block(void *target) {
// BL Instructions can only access a limited portion of memory.
// So this allocates memory closer to the original instruction,
// that when run, will jump into the actual target.
if (code_block == NULL) {
code_block = (unsigned char *) mmap((void *) 0x200000, CODE_BLOCK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (code_block == MAP_FAILED) {
ERR("Unable To Allocate Code Block: %s", strerror(errno));
}
DEBUG("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
// Store Segment
segment_data data;
data.start = code_block;
data.end = (void *) (((uintptr_t) code_block) + CODE_BLOCK_SIZE);
data.is_executable = true;
data.is_writable = true;
add_segment(data);
}
if (code_block_remaining < CODE_SIZE) {
ERR("Maximum Amount Of overwrite_calls() Uses Reached");
}
long_overwrite(code_block, target);
// Return
return code_block;
}
void increment_code_block() {
code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE;
}

View File

@ -0,0 +1,50 @@
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Generate A BL Instruction
#define INSTRUCTION_RANGE 32000000
static uint64_t nice_diff_64(uint64_t a, uint64_t b) {
if (a > b) {
return a - b;
} else {
return b - a;
}
}
uint32_t generate_bl_instruction(void *from, void *to, int use_b_instruction) {
// Check Instruction Range
if (nice_diff_64((uint64_t) to, (uint64_t) from) > INSTRUCTION_RANGE) {
IMPOSSIBLE();
}
// Create New Instruction
uint32_t instruction;
unsigned char *instruction_array = (unsigned char *) &instruction;
instruction_array[3] = use_b_instruction ? B_INSTRUCTION : BL_INSTRUCTION;
// Determine PC
unsigned char *pc = ((unsigned char *) from) + 8;
int32_t offset = (int32_t) to - (int32_t) pc;
int32_t target = offset >> 2;
// Set Instruction Offset
unsigned char *target_array = (unsigned char *) &target;
instruction_array[0] = target_array[0];
instruction_array[1] = target_array[1];
instruction_array[2] = target_array[2];
// Return
return instruction;
}
// Extract Target Address From B(L) Instruction
void *extract_from_bl_instruction(unsigned char *from) {
// Calculate PC
unsigned char *pc = ((unsigned char *) from) + 8;
// Extract Offset From Instruction
int32_t target = *(int32_t *) from;
target = (target << 8) >> 8;
int32_t offset = target << 2;
// Add PC To Offset
return (void *) (pc + offset);
}

View File

@ -0,0 +1,26 @@
#pragma once
#ifndef __arm__
#error "Patching Code Is ARM Only"
#endif
#include <cstdint>
// Segments
struct segment_data {
void *start;
void *end;
bool is_executable;
bool is_writable;
};
__attribute__((visibility("internal"))) segment_data &get_data_for_addr(void *addr);
__attribute__((visibility("internal"))) void add_segment(segment_data data);
// Code Block
__attribute__((visibility("internal"))) void *update_code_block(void *target);
__attribute__((visibility("internal"))) void increment_code_block();
// BL Instruction Magic Number
#define BL_INSTRUCTION 0xeb
#define B_INSTRUCTION 0xea
__attribute__((visibility("internal"))) uint32_t generate_bl_instruction(void *from, void *to, int use_b_instruction);

View File

@ -0,0 +1,170 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/mman.h>
#include <cstdint>
#include <cerrno>
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Overwrite Specific B(L) Instruction
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) {
// Add New Target To Code Block
void *code_block = update_code_block(target);
// Patch
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
_patch(file, line, start, (unsigned char *) &new_instruction);
// Increment Code Block Position
increment_code_block();
}
void _overwrite_call(const char *file, int line, void *start, void *target) {
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
_overwrite_call_internal(file, line, start, target, use_b_instruction);
}
// .rodata Information
#define RODATA_START 0x1020c8
#define RODATA_END 0x11665c
// .data.rel.ro Information
#define DATA_REL_RO_START 0x1352b8
#define DATA_REL_RO_END 0x135638
// Search And Patch VTables Containing Function
#define scan_vtables(section) \
for (uintptr_t i = section##_START; i < section##_END; i = i + 4) { \
uint32_t *addr = (uint32_t *) i; \
if (*addr == (uintptr_t) target) { \
/* Found VTable Entry */ \
_patch_address(file, line, addr, replacement); \
found++; \
} \
}
static int _patch_vtables(const char *file, int line, void *target, void *replacement) {
int found = 0;
scan_vtables(RODATA);
scan_vtables(DATA_REL_RO);
return found;
}
#undef scan_vtables
// Patch Calls Within Range
static int _overwrite_calls_within_internal(const char *file, int line, void *from, void *to, void *target, void *replacement) {
int found = 0;
for (uintptr_t i = (uintptr_t) from; i < (uintptr_t) to; i = i + 4) {
unsigned char *addr = (unsigned char *) i;
int use_b_instruction = addr[3] == B_INSTRUCTION;
// Check If Instruction is B Or BL
if (addr[3] == BL_INSTRUCTION || use_b_instruction) {
uint32_t check_instruction = generate_bl_instruction(addr, target, use_b_instruction);
unsigned char *check_instruction_array = (unsigned char *) &check_instruction;
// Check If Instruction Calls Target
if (addr[0] == check_instruction_array[0] && addr[1] == check_instruction_array[1] && addr[2] == check_instruction_array[2]) {
// Patch Instruction
uint32_t new_instruction = generate_bl_instruction(addr, replacement, use_b_instruction);
_patch(file, line, addr, (unsigned char *) &new_instruction);
found++;
}
}
}
return found;
}
// .text Information
#define TEXT_START 0xde60
#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) {
// Add New Target To Code Block
void *code_block = update_code_block(target);
// Patch Code
int found = _overwrite_calls_within_internal(file, line, (void *) TEXT_START, (void *) TEXT_END, start, code_block);
// Patch VTables
found += _patch_vtables(file, line, start, code_block);
// Increment Code Block Position
increment_code_block();
// Check
if (found < 1) {
ERR(NO_CALLSITE_ERROR, file, line, start);
}
}
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
void *code_block = update_code_block(replacement);
// Patch
int found = _overwrite_calls_within_internal(file, line, from, to, target, code_block);
// Check
if (found < 1) {
ERR(NO_CALLSITE_ERROR, file, line, target);
}
// Increment Code Block Position
increment_code_block();
}
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
// Replace the function's start with a call
// to the replacement function.
_overwrite_call_internal(file, line, start, target, 1);
}
// Print Patch Debug Data
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) DEBUG("(%s:%i): Patching (%p) - " str ": %02x %02x %02x %02x", file, line, start, data[0], data[1], data[2], data[3]);
// Patch Instruction
static void safe_mprotect(void *addr, size_t len, int prot) {
long page_size = sysconf(_SC_PAGESIZE);
long diff = ((uintptr_t) addr) % page_size;
void *aligned_addr = (void *) (((uintptr_t) addr) - diff);
size_t aligned_len = len + diff;
int ret = mprotect(aligned_addr, aligned_len, prot);
if (ret == -1) {
ERR("Unable To Set Permissions: %p: %s", addr, strerror(errno));
}
}
void _patch(const char *file, int line, void *start, unsigned char patch[4]) {
if (((uint32_t) start) % 4 != 0) {
ERR("Invalid Address");
}
// Get Current Permissions
segment_data &segment_data = get_data_for_addr(start);
int prot = PROT_READ;
if (segment_data.is_executable) {
prot |= PROT_EXEC;
}
if (segment_data.is_writable) {
prot |= PROT_WRITE;
}
// Allow Writing To Code Memory
uint32_t size = 4;
safe_mprotect(start, size, prot | PROT_WRITE);
// Patch
unsigned char *data = (unsigned char *) start;
PATCH_PRINTF(file, line, start, "original");
memcpy(data, patch, 4);
PATCH_PRINTF(file, line, start, "result");
// Reset Code Memory Permissions
safe_mprotect(start, size, prot);
// Clear ARM Instruction Cache
__clear_cache(start, (void *) (((uintptr_t) start) + size));
}
// Patch Address
void _patch_address(const char *file, int line, void *start, void *target) {
uint32_t addr = (uint32_t) target;
unsigned char *patch_data = (unsigned char *) &addr;
_patch(file, line, start, patch_data);
}

View File

@ -0,0 +1,50 @@
#include <vector>
#include <elf.h>
#include <dlfcn.h>
#include <link.h>
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Track Segments
static std::vector<segment_data> &get_segments() {
static std::vector<segment_data> data;
return data;
}
// Functions
segment_data &get_data_for_addr(void *addr) {
for (segment_data &data : get_segments()) {
if (addr >= data.start && addr < data.end) {
return data;
}
}
ERR("Address Not Part Of Main Program: %p", addr);
}
void add_segment(segment_data data) {
get_segments().push_back(data);
}
// Init
void reborn_init_patch() {
dl_iterate_phdr([](struct dl_phdr_info *info, __attribute__((unused)) size_t size, __attribute__((unused)) void *user_data) {
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
// Only Loaded Segemnts
if (info->dlpi_phdr[i].p_type == PT_LOAD) {
// Store
segment_data data;
data.start = (void *) (info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
data.end = (void *) (((uintptr_t) data.start) + info->dlpi_phdr[i].p_memsz);
data.is_executable = info->dlpi_phdr[i].p_flags & PF_X;
data.is_writable = info->dlpi_phdr[i].p_flags & PF_W;
add_segment(data);
}
}
}
// Return
return 0;
}, nullptr);
}

View File

@ -1,28 +0,0 @@
#include <libreborn/elf.h>
// Find And Iterate Over All Segments In Current Binary
typedef struct {
segment_callback_t callback;
void *data;
} dl_iterate_callback_data;
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
dl_iterate_callback_data *callback_data = (dl_iterate_callback_data *) data;
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
// Only Executable Segemnts
if (info->dlpi_phdr[i].p_type == PT_LOAD && (info->dlpi_phdr[i].p_flags & PF_X) != 0) {
// Callback
(*callback_data->callback)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_memsz, callback_data->data);
}
}
}
return 0;
}
void iterate_segments(segment_callback_t callback, void *data) {
dl_iterate_callback_data callback_data = {
.callback = callback,
.data = data
};
dl_iterate_phdr(dl_iterate_callback, (void *) &callback_data);
}

View File

@ -1,4 +1,5 @@
#include <libreborn/libreborn.h>
#include "compat-internal.h"
// Do Nothing Function
static void do_nothing() {
@ -6,7 +7,7 @@ static void do_nothing() {
}
// Patch bcm_host Calls
__attribute__((constructor)) static void patch_bcm_host_calls() {
void _patch_bcm_host_calls() {
// Disable bcm_host Calls
overwrite_call((void *) 0xdfec, (void *) do_nothing); // bcm_host_init
overwrite_call((void *) 0x12418, (void *) do_nothing); // bcm_host_deinit

View File

@ -0,0 +1,5 @@
#pragma once
__attribute__((visibility("internal"))) void _patch_egl_calls();
__attribute__((visibility("internal"))) void _patch_x11_calls();
__attribute__((visibility("internal"))) void _patch_bcm_host_calls();

View File

@ -5,6 +5,7 @@
#include <mods/compat/compat.h>
#include <mods/screenshot/screenshot.h>
#include <mods/init/init.h>
#include "compat-internal.h"
#include <libreborn/libreborn.h>
@ -120,6 +121,10 @@ void init_compat() {
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
// Patches
_patch_egl_calls();
_patch_x11_calls();
_patch_bcm_host_calls();
}
// Store Exit Requests

View File

@ -2,6 +2,7 @@
#include <libreborn/libreborn.h>
#include <media-layer/core.h>
#include "compat-internal.h"
// Functions That Have Their Return Values Used
static EGLSurface eglCreateWindowSurface_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) {
@ -20,7 +21,7 @@ static EGLBoolean eglSwapBuffers_injection(__attribute__((unused)) EGLDisplay di
}
// Patch EGL Calls
__attribute__((constructor)) static void patch_egl_calls() {
void _patch_egl_calls() {
// Disable EGL Calls
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x1250c, nop_patch); // eglTerminate

View File

@ -2,6 +2,7 @@
#include <libreborn/libreborn.h>
#include <media-layer/core.h>
#include "compat-internal.h"
// Functions That Have Their Return Values Used
static int XTranslateCoordinates_injection(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, __attribute__((unused)) XID *child_return) {
@ -21,7 +22,7 @@ static int XGetWindowAttributes_injection(__attribute__((unused)) void *display,
}
// Patch X11 Calls
__attribute__((constructor)) static void patch_x11_calls() {
void _patch_x11_calls() {
// Disable X11 Calls
overwrite_call((void *) 0x132a4, (void *) XGetWindowAttributes_injection); // XGetWindowAttributes
overwrite_call((void *) 0x132d4, (void *) XTranslateCoordinates_injection); // XTranslateCoordinates

View File

@ -130,13 +130,13 @@ void init_death() {
patch_address(LocalPlayer_die_vtable_addr, (void *) LocalPlayer_die_injection);
patch_address(ServerPlayer_actuallyHurt_vtable_addr, (void *) ServerPlayer_actuallyHurt_injection);
patch_address(LocalPlayer_actuallyHurt_vtable_addr, (void *) LocalPlayer_actuallyHurt_injection);
patch_address(Mob_hurt_vtable_addr, (void *) Mob_hurt_injection);
overwrite_calls((void *) Mob_hurt_non_virtual, (void *) Mob_hurt_injection);
}
// Fix TNT
// This changes PrimedTnt_explode from Level_explode(NULL, x, y, z, 3.1f) to Level_explode(this, x, y, z, 3.1f)
unsigned char cpy_r1_r0_patch[4] = {0x00, 0x10, 0xa0, 0xe1}; // "cpy r1,r0"
// This changes PrimedTnt_explode from Level::explode(NULL, x, y, z, 3.1f) to Level::explode(this, x, y, z, 3.1f)
unsigned char cpy_r1_r0_patch[4] = {0x00, 0x10, 0xa0, 0xe1}; // "cpy r1, r0"
patch((void *) 0x87998, cpy_r1_r0_patch);
unsigned char ldr_r0_24_patch[4] = {0x24, 0x00, 0x90, 0xe5}; // "ldr r0,[r0,#0x24]"
unsigned char ldr_r0_24_patch[4] = {0x24, 0x00, 0x90, 0xe5}; // "ldr r0, [r0, #0x24]"
patch((void *) 0x8799c, ldr_r0_24_patch);
}

View File

@ -5,6 +5,7 @@
__attribute__((constructor)) static void init(int argc, char *argv[]) {
media_ensure_loaded();
reborn_init_patch();
run_tests();
init_symbols();
init_version();

View File

@ -800,7 +800,6 @@ void init_misc() {
// Animation
overwrite_calls((void *) ContainerMenu_constructor, (void *) ContainerMenu_injection);
overwrite_calls((void *) ContainerMenu_destructor_complete_non_virtual, (void *) ContainerMenu_destructor_injection);
patch_address(ContainerMenu_destructor_complete_vtable_addr, (void *) ContainerMenu_destructor_injection);
}
patch_address((void *) 0x115b48, (void *) ChestTileEntity_shouldSave_injection);
@ -834,6 +833,12 @@ void init_misc() {
overwrite_calls((void *) Player_startUsingItem, (void *) Player_startUsingItem_injection);
overwrite_calls((void *) Player_stopUsingItem, (void *) Player_stopUsingItem_injection);
// Fix invalid ItemInHandRenderer texture cache
uchar cmp_r7_patch[] = {0x07, 0x00, 0x57, 0xe1}; // "cmp r7,r7"
patch((void *) 0x4b938, cmp_r7_patch);
uchar moveq_r3_true_patch[] = {0x01, 0x30, 0xa0, 0x03}; // "moveq r3,#0x1"
patch((void *) 0x4b93c, moveq_r3_true_patch);
// Init C++ And Logging
_init_misc_cpp();
_init_misc_logging();

View File

@ -123,6 +123,17 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkS
}
}
// Display Date In Select World Screen
static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, int time) {
// From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84
time_t tt = time;
struct tm t;
gmtime_r(&tt, &t);
char buf[2048];
strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
return std::string(buf);
}
// Init
void _init_misc_cpp() {
// Implement AppPlatform::readAssetFile So Translations Work
@ -136,10 +147,17 @@ void _init_misc_cpp() {
patch_address(PauseScreen_init_vtable_addr, (void *) PauseScreen_init_injection);
}
// Implement crafting remainders
// Implement Crafting Remainders
overwrite_call((void *) 0x2e230, (void *) PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection);
overwrite((void *) Item_getCraftingRemainingItem_non_virtual, (void *) Item_getCraftingRemainingItem_injection);
// Replace 2011 std::sort With Optimized(TM) Code
overwrite((void *) 0x51fac, (void *) sort_chunks);
if (feature_has("Optimized Chunk Sorting", server_enabled)) {
overwrite((void *) 0x51fac, (void *) sort_chunks);
}
// Display Date In Select World Screen
if (feature_has("Display Date In Select World Screen", server_disabled)) {
patch_address(AppPlatform_linux_getDateString_vtable_addr, (void *) AppPlatform_linux_getDateString_injection);
}
}

View File

@ -215,9 +215,7 @@ void _init_options_cpp() {
// Replace "feedback_vibration" Loading/Saving With "gfx_ao"
{
// Replace String
static const char *new_feedback_vibration_options_txt_name = "gfx_ao";
patch_address((void *) Strings_feedback_vibration_options_txt_name_1_pointer, (void *) &new_feedback_vibration_options_txt_name);
patch_address((void *) Strings_feedback_vibration_options_txt_name_2_pointer, (void *) &new_feedback_vibration_options_txt_name);
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"
@ -230,8 +228,7 @@ void _init_options_cpp() {
// Replace "gfx_lowquality" Loading With "gfx_anaglyph"
{
// Replace String
static const char *new_gfx_lowquality_options_txt_name = "gfx_anaglyph";
patch_address((void *) Strings_gfx_lowquality_options_txt_name_pointer, (void *) &new_gfx_lowquality_options_txt_name);
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"

View File

@ -433,7 +433,7 @@ static bool is_ip_in_blacklist(const char *ip) {
}
// Ban Players
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned char *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()) {
@ -576,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((void *) RakNet_RakPeer_IsBanned_non_virtual, (void *) 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)) {

View File

@ -2,5 +2,8 @@
set -e
# Change Directory
cd "$(dirname "$0")/../"
# Run
act push -W '.gitea/workflows/build.yml'

View File

@ -2,6 +2,9 @@
set -e
# Change Directory
cd "$(dirname "$0")/../"
# Variables
MODE="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
ARCH='host'

View File

@ -130,6 +130,7 @@ set(SRC
src/app-platform/AppPlatform_linux.def
src/app-platform/AppPlatform_readAssetFile_return_value.def
src/tile/LeafTile.def
src/tile/DoorTile.def
src/tile/Tile.def
src/tile/LiquidTile.def
src/tile/TallGrass.def

View File

@ -3,3 +3,4 @@ vtable 0x1020d8;
virtual-method void saveScreenshot(std::string *path, int width, int height) = 0x8;
virtual-method AppPlatform_readAssetFile_return_value readAssetFile(std::string *path) = 0x34;
virtual-method Texture loadTexture(std::string *path, bool b) = 0xc;
virtual-method std::string getDateString(int time) = 0x24;

View File

@ -1,3 +1,5 @@
extends Entity;
vtable 0x10c718;
property int fuse = 0xd0;

View File

@ -1 +1,5 @@
vtable 0x102e58;
vtable-size 0x60;
virtual-method void attack(Player *player, Entity *target) = 0x44;
virtual-method void releaseUsingItem(Player *player) = 0x5c;

View File

@ -4,9 +4,8 @@ static-property char *default_username = 0x18fd4; // StevePi
static-property char *minecraft_pi_version = 0x39d94; // v0.1.1 alpha
static-property char *options_txt_path = 0x19bc8; // options.txt
static-property char *options_txt_fopen_mode_when_loading = 0x19d24; // w
static-property char **feedback_vibration_options_txt_name_1 = 0x198a0; // feedback_vibration
static-property char **feedback_vibration_options_txt_name_2 = 0x194bc; // feedback_vibration
static-property char **gfx_lowquality_options_txt_name = 0x194c4; // gfx_lowquality
static-property char *feedback_vibration_options_txt_name = 0x135d70; // feedback_vibration
static-property char *gfx_lowquality_options_txt_name = 0x135d88; // gfx_lowquality
static-property char *classic_create_button_text = 0x39bec; // Create
static-property-array char creative_mode_description = 0x104492; // Unlimited resources and flying
static-property-array char survival_mode_description = 0x104470; // Mobs, health and gather resources

View File

@ -0,0 +1,5 @@
extends Tile;
vtable 0x111220;
static-method uint getCompositeData(LevelSource *level, int x, int y, int z) = 0xbde40;