Compare commits

...

4 Commits

Author SHA1 Message Date
1942ae49f3 Add Sign To Expanded Creative Inventory
All checks were successful
minecraft-pi-reborn/pipeline/head This commit looks good
2022-07-20 03:04:03 -04:00
150de0a7a9 Rename Package 2022-07-20 03:04:01 -04:00
0c642a7413 Port To v0.1.0 2022-07-20 03:02:51 -04:00
379da809cd 2.4.1
All checks were successful
minecraft-pi-reborn/pipeline/head This commit looks good
2022-07-20 02:58:14 -04:00
69 changed files with 843 additions and 1216 deletions

View File

@ -34,7 +34,7 @@ if(NOT MCPI_HEADLESS_MODE)
endif()
# App ID
set(DEFAULT_APP_ID "com.thebrokenrail.MCPIReborn")
set(DEFAULT_APP_ID "com.thebrokenrail.MCPIRebornLegacy")
if(MCPI_SERVER_MODE)
string(APPEND DEFAULT_APP_ID "Server")
else()
@ -43,7 +43,7 @@ endif()
set(MCPI_APP_ID "${DEFAULT_APP_ID}" CACHE STRING "App ID")
# App Title
set(DEFAULT_APP_TITLE "Minecraft: Pi Edition: Reborn")
set(DEFAULT_APP_TITLE "Minecraft: Pi Edition: Reborn Legacy")
if(MCPI_SERVER_MODE)
string(APPEND DEFAULT_APP_TITLE " (Server)")
else()
@ -52,7 +52,7 @@ endif()
set(MCPI_APP_TITLE "${DEFAULT_APP_TITLE}" CACHE STRING "App Title")
# Specify Variant Name
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
set(MCPI_VARIANT_NAME "minecraft-pi-reborn-legacy")
if(MCPI_SERVER_MODE)
string(APPEND MCPI_VARIANT_NAME "-server")
else()

View File

@ -16,4 +16,4 @@ WORKDIR /data
# Setup Entrypoint
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/app/usr/bin/minecraft-pi-reborn-server"]
CMD ["/app/usr/bin/minecraft-pi-reborn-legacy-server"]

4
Jenkinsfile vendored
View File

@ -24,11 +24,11 @@ pipeline {
sh 'apt-get update && apt-get install -y docker.io'
sh 'rm -rf ./out/server-amd64'
sh './scripts/build.sh server amd64'
sh 'docker build --no-cache --tag thebrokenrail/minecraft-pi-reborn-server .'
sh 'docker build --no-cache --tag thebrokenrail/minecraft-pi-reborn-legacy-server .'
withCredentials([usernamePassword(credentialsId: 'docker_hub_login', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
sh 'docker login -u "${DOCKER_HUB_USERNAME}" -p "${DOCKER_HUB_PASSWORD}"'
}
sh 'docker push thebrokenrail/minecraft-pi-reborn-server'
sh 'docker push thebrokenrail/minecraft-pi-reborn-legacy-server'
}
}
}

View File

@ -2,7 +2,7 @@
<img alt="Start Screen" src="images/start.png">
</p>
# Minecraft: Pi Edition: Reborn
# Minecraft: Pi Edition: Reborn Legacy
Minecraft: Pi Edition Modding Project
## Documentation

View File

@ -1 +1 @@
2.4.0
2.4.1

View File

@ -56,7 +56,6 @@ if(NOT EXISTS "${sysroot_dir}")
# Delete Unneeded Files
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit")
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/gconv")
# Strip Files
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*")
@ -68,6 +67,13 @@ if(NOT EXISTS "${sysroot_dir}")
file(REMOVE "${file}")
endif()
endforeach()
# Setup gconv
file(
COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/usr/lib/gconv/gconv-modules"
DESTINATION "${sysroot_dir}/usr/lib/gconv"
USE_SOURCE_PERMISSIONS
)
endif()
# Install Sysroot (Skipping Empty Directories)

View File

@ -7,7 +7,7 @@ include(FetchContent)
# Download
FetchContent_Declare(
minecraft-pi
URL "${CMAKE_CURRENT_SOURCE_DIR}/minecraft-pi-0.1.1.tar.gz"
URL "${CMAKE_CURRENT_SOURCE_DIR}/minecraft-pi-0.1.0.tar.gz"
)
FetchContent_Populate(minecraft-pi)

Binary file not shown.

View File

@ -1,5 +1,9 @@
# Changelog
**2.4.1**
* Allow More Characters In Usernames And Chat
* Fix Running On ARMHF Debian Buster
**2.4.0**
* [Modding SDK](../example-mods/README.md)
* Cache Blacklist/Whitelist

View File

@ -1,15 +1,15 @@
# Dedicated Server
The dedicated server is a version of Minecraft: Pi Edition modified to run in a headless environment. It loads settings from a ``server.properties`` file.
This server is also compatible with MCPE Alpha v0.6.1[^1].
This server is also compatible with MCPE Alpha v0.5.0[^1].
## Setup
### Debian Package
To use, install and run ``minecraft-pi-reborn-server``. It will generate the world and ``server.properties`` in the current directory.
To use, install and run ``minecraft-pi-reborn-legacy-server``. It will generate the world and ``server.properties`` in the current directory.
### Docker Image
An official Docker image is also provided: [thebrokenrail/minecraft-pi-reborn-server](https://hub.docker.com/r/thebrokenrail/minecraft-pi-reborn-server).
An official Docker image is also provided: [thebrokenrail/minecraft-pi-reborn-legacy-server](https://hub.docker.com/r/thebrokenrail/minecraft-pi-reborn-legacy-server).
## Server Limitations
* Player data is not saved because of limitations with MCPE LAN worlds

View File

@ -1,7 +1,7 @@
# Installation
## AppImage
Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/).
Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/legacy/lastSuccessfulBuild/artifact/out/).
### System Requirements
* Debian Buster/Ubuntu 18.04 Or Higher

View File

@ -1,7 +1,7 @@
# Sound
One of MCPI-Reborn's main modifications is a sound-engine since MCPI doesn't include one by default[^1]. However, it can't be used out-of-box because MCPI doesn't contain any sound data and MCPI-Reborn can't include it because of copyright.
MCPE's sound data can be extracted from any MCPE v0.6.1[^2] APK file, just place its `libminecraftpe.so` into `~/.minecraft-pi/overrides` and you should have sound!
MCPE's sound data can be extracted from any MCPE v0.5.0[^2] APK file, just place its `libminecraftpe.so` into `~/.minecraft-pi/overrides` and you should have sound!
[^1]: The mute button is just leftover code from MCPE, it doesn't actually do anything in un-modded MCPI, however it is connected to MCPI-Reborn's sound-engine.
[^2]: This isn't a hard limit, an MCPE v0.8.1 APK would probably work, but don't rely on it.

View File

@ -8,12 +8,12 @@ This is an example of a mod that cane be built using the modding SDK.
## The SDK
The modding SDK is a collection of exported CMake targets that allows anyone to create their own MCPI mod!
The SDK is copied to ``~/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake`` whenever MCPI-Reborn is started.
The SDK is copied to ``~/.minecraft-pi/sdk/lib/minecraft-pi-reborn-legacy-client/sdk/sdk.cmake`` whenever MCPI-Reborn is started.
## How do I use this?
```sh
mkdir build
cd build
cmake ..
cp libexpanded-creative.so ~/.minecraft-pi/mods
cp libexpanded-creative.so ~/.minecraft-pi/legacy-mods
```

View File

@ -8,7 +8,7 @@ set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
project(chat-commands)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-legacy-client/sdk/sdk.cmake")
# Build
add_library(chat-commands SHARED chat-commands.cpp)

View File

@ -8,7 +8,7 @@ set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
project(expanded-creative)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-legacy-client/sdk/sdk.cmake")
# Build
add_library(expanded-creative SHARED expanded-creative.cpp)

View File

@ -378,146 +378,6 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
bread_instance->id = 297;
(*FillingContainer_addItem)(filling_container, bread_instance);
ItemInstance *diamondHelm_instance = new ItemInstance;
ALLOC_CHECK(diamondHelm_instance);
diamondHelm_instance->count = 255;
diamondHelm_instance->auxiliary = 0;
diamondHelm_instance->id = 310;
(*FillingContainer_addItem)(filling_container, diamondHelm_instance);
ItemInstance *diamondChest_instance = new ItemInstance;
ALLOC_CHECK(diamondChest_instance);
diamondChest_instance->count = 255;
diamondChest_instance->auxiliary = 0;
diamondChest_instance->id = 311;
(*FillingContainer_addItem)(filling_container, diamondChest_instance);
ItemInstance *diamondLeg_instance = new ItemInstance;
ALLOC_CHECK(diamondLeg_instance);
diamondLeg_instance->count = 255;
diamondLeg_instance->auxiliary = 0;
diamondLeg_instance->id = 312;
(*FillingContainer_addItem)(filling_container, diamondLeg_instance);
ItemInstance *diamondBoot_instance = new ItemInstance;
ALLOC_CHECK(diamondBoot_instance);
diamondBoot_instance->count = 255;
diamondBoot_instance->auxiliary = 0;
diamondBoot_instance->id = 313;
(*FillingContainer_addItem)(filling_container, diamondBoot_instance);
ItemInstance *leatherCap_instance = new ItemInstance;
ALLOC_CHECK(leatherCap_instance);
leatherCap_instance->count = 255;
leatherCap_instance->auxiliary = 0;
leatherCap_instance->id = 298;
(*FillingContainer_addItem)(filling_container, leatherCap_instance);
ItemInstance *leatherShirt_instance = new ItemInstance;
ALLOC_CHECK(leatherShirt_instance);
leatherShirt_instance->count = 255;
leatherShirt_instance->auxiliary = 0;
leatherShirt_instance->id = 299;
(*FillingContainer_addItem)(filling_container, leatherShirt_instance);
ItemInstance *leatherPants_instance = new ItemInstance;
ALLOC_CHECK(leatherPants_instance);
leatherPants_instance->count = 255;
leatherPants_instance->auxiliary = 0;
leatherPants_instance->id = 300;
(*FillingContainer_addItem)(filling_container, leatherPants_instance);
ItemInstance *leatherBoots_instance = new ItemInstance;
ALLOC_CHECK(leatherBoots_instance);
leatherBoots_instance->count = 255;
leatherBoots_instance->auxiliary = 0;
leatherBoots_instance->id = 301;
(*FillingContainer_addItem)(filling_container, leatherBoots_instance);
ItemInstance *chainHelm_instance = new ItemInstance;
ALLOC_CHECK(chainHelm_instance);
chainHelm_instance->count = 255;
chainHelm_instance->auxiliary = 0;
chainHelm_instance->id = 302;
(*FillingContainer_addItem)(filling_container, chainHelm_instance);
ItemInstance *chainShirt_instance = new ItemInstance;
ALLOC_CHECK(chainShirt_instance);
chainShirt_instance->count = 255;
chainShirt_instance->auxiliary = 0;
chainShirt_instance->id = 303;
(*FillingContainer_addItem)(filling_container, chainShirt_instance);
ItemInstance *chainLegs_instance = new ItemInstance;
ALLOC_CHECK(chainLegs_instance);
chainLegs_instance->count = 255;
chainLegs_instance->auxiliary = 0;
chainLegs_instance->id = 304;
(*FillingContainer_addItem)(filling_container, chainLegs_instance);
ItemInstance *chainBoots_instance = new ItemInstance;
ALLOC_CHECK(chainBoots_instance);
chainBoots_instance->count = 255;
chainBoots_instance->auxiliary = 0;
chainBoots_instance->id = 305;
(*FillingContainer_addItem)(filling_container, chainBoots_instance);
ItemInstance *goldHelm_instance = new ItemInstance;
ALLOC_CHECK(goldHelm_instance);
goldHelm_instance->count = 255;
goldHelm_instance->auxiliary = 0;
goldHelm_instance->id = 314;
(*FillingContainer_addItem)(filling_container, goldHelm_instance);
ItemInstance *goldChest_instance = new ItemInstance;
ALLOC_CHECK(goldChest_instance);
goldChest_instance->count = 255;
goldChest_instance->auxiliary = 0;
goldChest_instance->id = 315;
(*FillingContainer_addItem)(filling_container, goldChest_instance);
ItemInstance *goldLegs_instance = new ItemInstance;
ALLOC_CHECK(goldLegs_instance);
goldLegs_instance->count = 255;
goldLegs_instance->auxiliary = 0;
goldLegs_instance->id = 316;
(*FillingContainer_addItem)(filling_container, goldLegs_instance);
ItemInstance *goldBoots_instance = new ItemInstance;
ALLOC_CHECK(goldBoots_instance);
goldBoots_instance->count = 255;
goldBoots_instance->auxiliary = 0;
goldBoots_instance->id = 317;
(*FillingContainer_addItem)(filling_container, goldBoots_instance);
ItemInstance *ironHelm_instance = new ItemInstance;
ALLOC_CHECK(ironHelm_instance);
ironHelm_instance->count = 255;
ironHelm_instance->auxiliary = 0;
ironHelm_instance->id = 306;
(*FillingContainer_addItem)(filling_container, ironHelm_instance);
ItemInstance *ironChest_instance = new ItemInstance;
ALLOC_CHECK(ironChest_instance);
ironChest_instance->count = 255;
ironChest_instance->auxiliary = 0;
ironChest_instance->id = 307;
(*FillingContainer_addItem)(filling_container, ironChest_instance);
ItemInstance *ironLegs_instance = new ItemInstance;
ALLOC_CHECK(ironLegs_instance);
ironLegs_instance->count = 255;
ironLegs_instance->auxiliary = 0;
ironLegs_instance->id = 308;
(*FillingContainer_addItem)(filling_container, ironLegs_instance);
ItemInstance *ironBoots_instance = new ItemInstance;
ALLOC_CHECK(ironBoots_instance);
ironBoots_instance->count = 255;
ironBoots_instance->auxiliary = 0;
ironBoots_instance->id = 309;
(*FillingContainer_addItem)(filling_container, ironBoots_instance);
ItemInstance *flint2_instance = new ItemInstance;
ALLOC_CHECK(flint2_instance);
flint2_instance->count = 255;

View File

@ -8,7 +8,7 @@ set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
project(recipes)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-legacy-client/sdk/sdk.cmake")
# Build
add_library(recipes SHARED recipes.cpp)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -14,38 +14,6 @@
#include "patchelf.h"
#include "crash-report.h"
// Set Environmental Variable
static void trim(char **value) {
// Remove Trailing Colon
int length = strlen(*value);
if ((*value)[length - 1] == ':') {
(*value)[length - 1] = '\0';
}
if ((*value)[0] == ':') {
*value = &(*value)[1];
}
}
void set_and_print_env(const char *name, char *value) {
// Set Variable With No Trailing Colon
static const char *unmodified_name_prefix = "MCPI_";
if (!starts_with(name, unmodified_name_prefix)) {
trim(&value);
}
// Print New Value
DEBUG("Set %s = %s", name, value);
// Set The Value
setenv(name, value, 1);
}
// Get Environmental Variable
static char *get_env_safe(const char *name) {
// Get Variable Or Blank String If Not Set
char *ret = getenv(name);
return ret != NULL ? ret : "";
}
// Get All Mods In Folder
static void load(char **ld_preload, char *folder) {
int folder_name_length = strlen(folder);
@ -133,6 +101,10 @@ void pre_bootstrap(int argc, char *argv[]) {
// Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0);
// 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);
// Print Version
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
@ -178,8 +150,8 @@ void pre_bootstrap(int argc, char *argv[]) {
safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH
{
char *value = get_env_safe("PATH");
if (strlen(value) > 0) {
char *value = getenv("PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&new_path, ":%s", value);
}
}
@ -331,78 +303,121 @@ void bootstrap(int argc, char *argv[]) {
free(resolved_path);
// Configure Library Search Path
char *library_path = NULL;
{
// Log
DEBUG("Setting Linker Search Paths...");
// Prepare
char *new_ld_path = NULL;
char *transitive_ld_path = NULL;
char *mcpi_ld_path = NULL;
// Add Native Library Directory
safe_asprintf(&new_ld_path, "%s/lib/native", binary_directory);
// Add LD_LIBRARY_PATH
// Library Search Path For Native Components
{
char *value = get_env_safe("LD_LIBRARY_PATH");
if (strlen(value) > 0) {
string_append(&new_ld_path, ":%s", value);
// 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);
}
// Set LD_LIBRARY_PATH (Used For Everything Except MCPI)
set_and_print_env("LD_LIBRARY_PATH", new_ld_path);
// Library Search Path For ARM Components
{
// Add ARM Library Directory
// (This Overrides LD_LIBRARY_PATH Using ld.so's --library-path Option)
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
// Add ARM Library Directory
// (This Overrides LD_LIBRARY_PATH Using ld.so's --library-path Option)
safe_asprintf(&library_path, "%s/lib/arm", binary_directory);
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
string_append(&library_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);
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 Remaining LD_LIBRARY_PATH
string_append(&library_path, ":%s", new_ld_path);
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&transitive_ld_path, ":%s", value);
}
}
// Free LD_LIBRARY_PATH
free(new_ld_path);
// Set
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
free(mcpi_ld_path);
}
// Setup iconv
{
// Native Components
char *host_gconv_path = getenv("GCONV_PATH");
set_and_print_env("MCPI_NATIVE_GCONV_PATH", host_gconv_path);
// ARM Components
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
char *gconv_path = NULL;
safe_asprintf(&gconv_path, "%s/sysroot/usr/lib/gconv", binary_directory);
set_and_print_env("MCPI_ARM_GCONV_PATH", gconv_path);
free(gconv_path);
#else
set_and_print_env("MCPI_ARM_GCONV_PATH", host_gconv_path);
#endif
}
}
// Configure MCPI's Preloaded Objects
char *preload = NULL;
// Configure Preloaded Objects
{
// Log
DEBUG("Locating Mods...");
// ~/.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);
}
// Native Components
char *host_ld_preload = getenv("LD_PRELOAD");
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
// Built-In Mods
// ARM Components
{
// 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);
}
// Prepare
char *preload = NULL;
// Add LD_PRELOAD
{
char *value = get_env_safe("LD_PRELOAD");
if (strlen(value) > 0) {
string_append(&preload, ":%s", value);
// ~/.minecraft-pi/mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/legacy-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);
}
}
@ -414,23 +429,17 @@ void bootstrap(int argc, char *argv[]) {
// Arguments
int argv_start = 1; // argv = &new_args[argv_start]
int real_argv_start = argv_start + 5; // ld.so Arguments
const char *new_args[real_argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
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 + real_argv_start] = argv[i];
new_args[i + argv_start] = argv[i];
}
// NULL-Terminator
new_args[real_argv_start + argc] = NULL;
new_args[argv_start + argc] = NULL;
// Set Executable Argument
new_args[argv_start] = patch_get_interpreter(new_mcpi_exe_path);
new_args[argv_start + 1] = "--preload";
new_args[argv_start + 2] = preload;
new_args[argv_start + 3] = "--library-path";
new_args[argv_start + 4] = library_path;
new_args[real_argv_start] = new_mcpi_exe_path;
new_args[argv_start] = new_mcpi_exe_path;
// Non-ARM Systems Need QEMU
#ifndef __ARM_ARCH
@ -438,6 +447,20 @@ void bootstrap(int argc, char *argv[]) {
new_args[argv_start] = QEMU_BINARY;
#endif
// Setup Environment
setup_exec_environment(1);
// Pass LD_* Variables Through QEMU
#ifndef __ARM_ARCH
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);

View File

@ -4,8 +4,6 @@
extern "C" {
#endif
void set_and_print_env(const char *name, char *value);
void pre_bootstrap(int argc, char *argv[]);
void bootstrap(int argc, char *argv[]);

View File

@ -1,16 +1,17 @@
FALSE Full Touch GUI
TRUE Fix Bow & Arrow
TRUE Fix Attacking
FALSE Force Mob Spawning
TRUE Fancy Graphics
TRUE Disable Autojump By Default
TRUE Display Nametags By Default
TRUE Fix Sign Placement
TRUE Show Block Outlines
FALSE Expand Creative Inventory
FALSE Remove Creative Mode Restrictions
FALSE Peaceful Mode
TRUE Animated Water
TRUE Remove Invalid Item Background
TRUE Disable "gui_blocks" Atlas
TRUE Smooth Lighting
FALSE 3D Anaglyph
TRUE Fix Camera Rendering
TRUE Implement Chat
@ -28,9 +29,9 @@ TRUE Implement Sound Engine
TRUE Close Current Screen On Death
FALSE Disable Raw Mouse Motion (Not Recommended)
TRUE Fix Furnace Not Checking Item Auxiliary
FALSE Disable Hosting LAN Worlds
TRUE Improved Cursor Rendering
TRUE Disable V-Sync
TRUE Fix Options Screen
TRUE Force Touch GUI Inventory
TRUE Fix Pause Menu
TRUE Improved Title Background

View File

@ -26,7 +26,7 @@ static void show_report(const char *log_filename) {
"--width", CRASH_REPORT_DIALOG_WIDTH,
"--height", CRASH_REPORT_DIALOG_HEIGHT,
"--text-info",
"--text", "Minecraft: Pi Edition: Reborn has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>!",
"--text", "Minecraft: Pi Edition: Reborn Legacy has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>!",
"--filename", log_filename,
"--no-wrap",
"--font", "Monospace",

View File

@ -1,6 +1,8 @@
#include <stdlib.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "../bootstrap.h"
int main(int argc, char *argv[]) {

View File

@ -16,7 +16,15 @@
extern "C" {
#endif
// Set Environmental Variable
void set_and_print_env(const char *name, const char *value);
// Safe execvpe()
#define for_each_special_environmental_variable(handle) \
handle("LD_LIBRARY_PATH"); \
handle("GCONV_PATH"); \
handle("LD_PRELOAD");
void setup_exec_environment(int is_arm_component);
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
// Chop Off Last Component
@ -24,9 +32,6 @@ void chop_last_component(char **str);
// Get Binary Directory (Remember To Free)
char *get_binary_directory();
// Safe execvpe() Relative To Binary
__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]);
// Run Command And Get Output
char *run_command(const char *const command[], int *exit_status);
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)

View File

@ -3,6 +3,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <stdint.h>
#include "util.h"
@ -33,6 +35,11 @@ extern "C" {
// Sanitize String
void sanitize_string(char **str, int max_length, unsigned int allow_newlines);
// CP437
void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size);
char *to_cp437(const char *input);
char *from_cp437(const char *input);
// Starts With
int starts_with(const char *str, const char *prefix);

View File

@ -2,7 +2,32 @@
#include <libreborn/exec.h>
// Set Environmental Variable
static void setenv_safe(const char *name, const char *value) {
if (value != NULL) {
setenv(name, value, 1);
} else {
unsetenv(name);
}
}
void set_and_print_env(const char *name, const char *value) {
// Print New Value
DEBUG("Set %s = %s", name, value != NULL ? value : "(unset)");
// Set The Value
setenv_safe(name, value);
}
// Safe execvpe()
#define handle_environmental_variable(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) {
for_each_special_environmental_variable(handle_environmental_variable);
}
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
// Log
DEBUG("Running Command:");
@ -45,29 +70,6 @@ char *get_binary_directory() {
return exe;
}
// Safe execvpe() Relative To Binary
__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]) {
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Create Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/%s", binary_directory, argv[0]);
// Free Binary Directory
free(binary_directory);
// Build New argv
int argc;
for (argc = 0; argv[argc] != NULL; argc++);
const char *new_argv[argc + 1];
for (int i = 1; i < argc; i++) {
new_argv[i] = argv[i];
}
new_argv[0] = full_path;
new_argv[argc] = NULL;
// Run
safe_execvpe(new_argv, envp);
}
// Run Command And Get Output
char *run_command(const char *const command[], int *exit_status) {
// Store Output
@ -85,6 +87,9 @@ char *run_command(const char *const command[], int *exit_status) {
close(output_pipe[0]);
close(output_pipe[1]);
// Setup Environment
setup_exec_environment(0);
// Run
safe_execvpe(command, (const char *const *) environ);
} else {

View File

@ -1,8 +1,9 @@
#include <iconv.h>
#include <stdint.h>
#include <libreborn/string.h>
// Sanitize String
#define MINIMUM_SAFE_CHARACTER 32
#define MAXIMUM_SAFE_CHARACTER 126
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
// Store Message Length
int length = strlen(*str);
@ -12,18 +13,135 @@ void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
length = max_length;
}
// Loop Through Message
for (int i = 0; i < length; i++) {
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
continue;
}
unsigned char c = (unsigned char) (*str)[i];
if (c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) {
// Replace Illegal Character
(*str)[i] = '?';
if (!allow_newlines) {
for (int i = 0; i < length; i++) {
if ((*str)[i] == '\n' || (*str)[i] == '\r') {
// Replace Newline
(*str)[i] = ' ';
}
}
}
}
// Minecraft-Flavored CP437
void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size) {
iconv(cd, &input, &input_size, &output, &output_size);
}
#define CP437_CHARACTERS 256
static const char *cp437_characters_map[CP437_CHARACTERS] = {
"\0", "", "", "", "", "", "", "", "", "", "\n", "", "", "\r", "", "",
"", "", "", "", "", "§", "", "", "", "", "", "", "", "", "", "",
" ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
"@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
"`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "",
"Ç", "ü", "é", "â", "ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å",
"É", "æ", "Æ", "ô", "ö", "ò", "û", "ù", "ÿ", "Ö", "Ü", "¢", "£", "¥", "", "ƒ",
"á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "", "¬", "½", "¼", "¡", "«", "»",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"α", "ß", "Γ", "π", "Σ", "σ", "µ", "τ", "Φ", "Θ", "Ω", "δ", "", "φ", "ε", "",
"", "±", "", "", "", "", "÷", "", "°", "", "·", "", "", "²", "", "©"
};
static uint32_t *get_cp437_characters_codepoint_map() {
static uint32_t map[CP437_CHARACTERS];
static int is_setup = 0;
if (!is_setup) {
// Build Map
iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
if (cd != (iconv_t) -1) {
size_t str_size = 4;
uint32_t *str = (uint32_t *) malloc(str_size);
ALLOC_CHECK(str);
for (int i = 0; i < CP437_CHARACTERS; i++) {
// Convert to UTF-32, Then Extract Codepoint
safe_iconv(cd, (char *) cp437_characters_map[i], strlen(cp437_characters_map[i]), (char *) str, str_size);
// Extract
map[i] = str[0];
}
// Free
free(str);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
is_setup = 1;
}
return map;
}
char *to_cp437(const char *input) {
// Convert To UTF-32 For Easier Parsing
size_t in_size = strlen(input);
size_t utf32_str_size = in_size * 4;
size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */;
uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size);
ALLOC_CHECK(utf32_str);
memset(utf32_str, 0, real_utf32_str_size);
iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
if (cd != (iconv_t) -1) {
safe_iconv(cd, (char *) input, in_size, (char *) utf32_str, utf32_str_size);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
// Allocate String
size_t cp437_str_size;
for (cp437_str_size = 0; utf32_str[cp437_str_size] != 0; cp437_str_size++);
size_t real_cp437_str_size = cp437_str_size + 1 /* NULL-terminator */;
char *cp437_str = (char *) malloc(real_cp437_str_size);
ALLOC_CHECK(cp437_str);
memset(cp437_str, 0, real_cp437_str_size);
// Handle Characters
for (size_t i = 0; utf32_str[i] != 0; i++) {
uint32_t codepoint = utf32_str[i];
for (int j = 0; j < CP437_CHARACTERS; j++) {
uint32_t test_codepoint = get_cp437_characters_codepoint_map()[j];
if (codepoint == test_codepoint) {
cp437_str[i] = j;
break;
}
}
if (cp437_str[i] == '\0') {
cp437_str[i] = '?';
}
}
// Free
free(utf32_str);
// Return
return cp437_str;
}
char *from_cp437(const char *input) {
// Convert To UTF-32 For Easier Parsing
size_t in_size = strlen(input);
size_t utf32_str_size = in_size * 4;
size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */;
uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size);
ALLOC_CHECK(utf32_str);
memset(utf32_str, 0, real_utf32_str_size);
// Handle Characters
for (size_t i = 0; input[i] != '\0'; i++) {
utf32_str[i] = get_cp437_characters_codepoint_map()[(uint32_t) input[i]];
}
// Convert To UTF-8
size_t out_size = utf32_str_size;
size_t real_out_size = utf32_str_size + 1 /* NULL-terminator */;
char *output = (char *) malloc(real_out_size);
ALLOC_CHECK(output);
memset(output, 0, real_out_size);
iconv_t cd = iconv_open("UTF-8", "UTF-32LE");
if (cd != (iconv_t) -1) {
safe_iconv(cd, (char *) utf32_str, utf32_str_size, output, out_size);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
// Return
return output;
}
// Starts With
int starts_with(const char *str, const char *prefix) {
return strncmp(prefix, str, strlen(prefix)) == 0;

View File

@ -156,7 +156,7 @@ static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int sc
event.key.keysym.sym = glfw_key_to_sdl_key(key);
SDL_PushEvent(&event);
if (key == GLFW_KEY_BACKSPACE && !up) {
character_event((char) '\b');
character_event('\b');
}
}
}
@ -164,7 +164,25 @@ static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int sc
// Pass Text To Minecraft
static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
if (is_interactable) {
character_event((char) codepoint);
// Signs Only Accepts ASCII Characters
size_t in_size = 4; // 1 UTF-32LE Codepoint
size_t out_size = 4; // 4 ASCII Characters Max
size_t real_out_size = out_size + 1 /* NULL-terminator */;
char *output = (char *) malloc(real_out_size);
ALLOC_CHECK(output);
memset(output, 0, real_out_size);
iconv_t cd = iconv_open("ASCII//TRANSLIT", "UTF-32LE");
if (cd != (iconv_t) -1) {
safe_iconv(cd, (char *) &codepoint, in_size, output, out_size);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
for (size_t i = 0; output[i] != '\0'; i++) {
character_event(output[i]);
}
// Free
free(output);
}
}

View File

@ -71,6 +71,9 @@ static void start_media_layer_proxy_client(int read, int write) {
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 {

View File

@ -20,7 +20,7 @@ if(NOT MCPI_HEADLESS_MODE)
target_link_libraries(compat screenshot)
endif()
if(NOT MCPI_SERVER_MODE)
target_link_libraries(compat input sign chat home dl)
target_link_libraries(compat input chat home dl)
endif()
add_library(readdir SHARED src/readdir/readdir.c)
@ -62,12 +62,9 @@ else()
target_link_libraries(camera screenshot)
endif()
add_library(input SHARED src/input/input.cpp src/input/bow.c src/input/attack.c src/input/toggle.c src/input/misc.c src/input/drop.cpp)
add_library(input SHARED src/input/input.cpp src/input/attack.c src/input/toggle.c src/input/misc.c src/input/drop.cpp)
target_link_libraries(input mods-headers reborn-patch symbols creative feature misc media-layer-core)
add_library(sign SHARED src/sign/sign.cpp)
target_link_libraries(sign mods-headers reborn-patch symbols feature input)
add_library(touch SHARED src/touch/touch.cpp)
target_link_libraries(touch mods-headers reborn-patch symbols feature)
@ -90,8 +87,8 @@ target_link_libraries(death mods-headers reborn-patch symbols feature)
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp src/misc/logging.cpp src/misc/api.cpp)
target_link_libraries(misc mods-headers reborn-patch symbols media-layer-core feature)
add_library(options SHARED src/options/options.c src/options/options.cpp)
target_link_libraries(options mods-headers reborn-patch symbols feature home)
add_library(options SHARED src/options/options.c)
target_link_libraries(options mods-headers reborn-patch symbols feature)
add_library(bucket SHARED src/bucket/bucket.cpp)
target_link_libraries(bucket mods-headers reborn-patch symbols feature misc)
@ -108,11 +105,11 @@ add_library(test SHARED src/test/test.c)
target_link_libraries(test mods-headers reborn-patch home)
add_library(init SHARED src/init/init.c)
target_link_libraries(init mods-headers compat game-mode misc death options chat creative bucket home version test media-layer-core)
target_link_libraries(init mods-headers reborn-util compat game-mode misc death options chat creative bucket home version test media-layer-core)
if(MCPI_SERVER_MODE)
target_link_libraries(init server)
else()
target_link_libraries(init multiplayer sound camera input sign touch textures atlas benchmark)
target_link_libraries(init multiplayer sound camera input touch textures atlas benchmark)
endif()
## Install Mods
@ -120,7 +117,7 @@ set(MODS_TO_INSTALL init compat readdir feature game-mode misc override death op
if(MCPI_SERVER_MODE)
list(APPEND MODS_TO_INSTALL server)
else()
list(APPEND MODS_TO_INSTALL multiplayer sound camera input sign touch textures atlas benchmark)
list(APPEND MODS_TO_INSTALL multiplayer sound camera input touch textures atlas benchmark)
endif()
if(NOT MCPI_HEADLESS_MODE)
list(APPEND MODS_TO_INSTALL screenshot)

View File

@ -15,7 +15,6 @@ void init_server();
void init_multiplayer();
void init_sound();
void init_input();
void init_sign();
void init_creative();
void init_camera();
void init_touch();

View File

@ -7,7 +7,6 @@ extern "C" {
typedef void (*input_tick_function_t)(unsigned char *minecraft);
void input_run_on_tick(input_tick_function_t function);
void input_set_is_right_click(int val);
void input_hide_gui();
void input_third_person();
int input_back();

View File

@ -15,6 +15,7 @@ void misc_run_on_recipes_setup(misc_update_function_t function); // obj == Recip
void misc_run_on_furnace_recipes_setup(misc_update_function_t function); // obj == FurnaceRecipes *
void misc_run_on_creative_inventory_setup(misc_update_function_t function); // obj == FillingContainer *
void misc_run_on_tiles_setup(misc_update_function_t function); // obj == NULL
void misc_run_on_internal_after_tiles_setup(misc_update_function_t function); // obj == NULL
void misc_run_on_items_setup(misc_update_function_t function); // obj == NULL
void Level_saveLevelData_injection(unsigned char *level);

View File

@ -1,11 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void sign_key_press(char key);
#ifdef __cplusplus
}
#endif

View File

@ -57,9 +57,9 @@ static void Tesselator_color_injection(unsigned char *tesselator, int32_t r, int
// Call Original Method
(*Tesselator_color)(tesselator, r, g, b, a);
}
static void Tesselator_begin_injection(unsigned char *tesselator, int32_t mode) {
static void Tesselator_begin_injection(unsigned char *tesselator) {
// Call Original Method
(*Tesselator_begin)(tesselator, mode);
(*Tesselator_begin)(tesselator);
// Fix Furnace UI
if (item_color_fix_mode != 0) {
@ -96,14 +96,14 @@ void init_atlas() {
// Disable The gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory
if (feature_has("Disable \"gui_blocks\" Atlas", server_disabled)) {
unsigned char disable_gui_blocks_atlas_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x63c2c, disable_gui_blocks_atlas_patch);
unsigned char disable_gui_blocks_atlas_patch[4] = {0x45, 0x00, 0x00, 0xea}; // "b 0x7f740"
patch((void *) 0x7f624, disable_gui_blocks_atlas_patch);
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
overwrite_calls((void *) ItemRenderer_renderGuiItemCorrect, (void *) ItemRenderer_renderGuiItemCorrect_injection);
// Fix Furnace UI
overwrite_calls((void *) Tesselator_begin, (void *) Tesselator_begin_injection);
overwrite_calls((void *) Tesselator_color, (void *) Tesselator_color_injection);
overwrite_call((void *) 0x32324, (void *) FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection);
overwrite_call((void *) 0x1e21c, (void *) InventoryPane_renderBatch_Tesselator_color_injection);
overwrite_call((void *) 0x3bff4, (void *) FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection);
overwrite_call((void *) 0x23c0c, (void *) InventoryPane_renderBatch_Tesselator_color_injection);
}
}

View File

@ -144,7 +144,7 @@ static unsigned char *create_bucket(int32_t id, int32_t texture_x, int32_t textu
// Construct
unsigned char *item = (unsigned char *) ::operator new(ITEM_SIZE);
ALLOC_CHECK(item);
(*Item)(item, id);
new ((std::string *) (item + Item_description_id_property_offset)) std::string;
// Set VTable
*(unsigned char **) item = get_bucket_vtable();
@ -157,10 +157,16 @@ static unsigned char *create_bucket(int32_t id, int32_t texture_x, int32_t textu
// Setup
(*Item_setIcon)(item, texture_x, texture_y);
(*Item_setDescriptionId)(item, name);
*(int32_t *) (item + Item_id_property_offset) = id + 0x100;
*(int32_t *) (item + Item_is_stacked_by_data_property_offset) = 1;
*(int32_t *) (item + Item_category_property_offset) = 2;
*(int32_t *) (item + Item_is_hand_equipped_property_offset) = 0;
*(int32_t *) (item + Item_category_property_offset) = 1;
*(int32_t *) (item + Item_max_damage_property_offset) = 0;
*(int32_t *) (item + Item_max_stack_size_property_offset) = 1;
*(int32_t *) (item + Item_max_stack_size_property_offset) = 16;
*(unsigned char **) (item + Item_crafting_remaining_item_property_offset) = NULL;
// Register
Item_items[*(int32_t *) (item + Item_id_property_offset)] = item;
// Return
return item;
@ -171,9 +177,9 @@ static void Item_initItems_injection(__attribute__((unused)) unsigned char *null
// Change Max Stack Size Based On Auxiliary
static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instance) {
if (item_instance->id == *(int32_t *) (bucket + Item_id_property_offset) && item_instance->auxiliary == 0) {
if (item_instance->id == *(int32_t *) (bucket + Item_id_property_offset) && item_instance->auxiliary != 0) {
// Custom Value
return 16;
return 1;
} else {
// Call Original Method
return (*ItemInstance_getMaxStackSize)(item_instance);
@ -297,7 +303,7 @@ void init_bucket() {
// Creative Inventory
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
// Make Liquids Selectable
overwrite_call((void *) 0x7f5b0, (void *) Mob_pick_Level_clip_injection);
overwrite_call((void *) 0xab594, (void *) Mob_pick_Level_clip_injection);
misc_run_on_tick(handle_tick);
// Prevent Breaking Liquid
overwrite_calls((void *) Minecraft_handleMouseDown, (void *) Minecraft_handleMouseDown_injection);
@ -305,6 +311,6 @@ void init_bucket() {
misc_run_on_recipes_setup(Recipes_injection);
// Custom Furnace Fuel
overwrite_calls((void *) FurnaceTileEntity_getBurnDuration, (void *) FurnaceTileEntity_getBurnDuration_injection);
overwrite_call((void *) 0xd351c, (void *) FurnaceTileEntity_tick_ItemInstance_setNull_injection);
overwrite_call((void *) 0x14048c, (void *) FurnaceTileEntity_tick_ItemInstance_setNull_injection);
}
}

View File

@ -43,6 +43,6 @@ void init_camera() {
// Enable TripodCameraRenderer
overwrite_calls((void *) EntityRenderDispatcher, (void *) EntityRenderDispatcher_injection);
// Display Smoke From TripodCamera Higher
overwrite_call((void *) 0x87dc4, (void *) TripodCamera_tick_Level_addParticle_call_injection);
overwrite_call((void *) 0xbcf18, (void *) TripodCamera_tick_Level_addParticle_call_injection);
}
}

View File

@ -87,7 +87,8 @@ static void CommandServer_parse_CommandServer_dispatchPacket_injection(unsigned
// Handle ChatPacket Server-Side
static void ServerSideNetworkHandler_handle_ChatPacket_injection(unsigned char *server_side_network_handler, RakNet_RakNetGUID *rak_net_guid, unsigned char *chat_packet) {
unsigned char *player = (*ServerSideNetworkHandler_getPlayer)(server_side_network_handler, rak_net_guid);
unsigned char *level = *(unsigned char **) (server_side_network_handler + ServerSideNetworkHandler_level_property_offset);
unsigned char *player = (*NetEventCallback_findPlayer)(server_side_network_handler, level, rak_net_guid);
if (player != NULL) {
char *username = *(char **) (player + Player_username_property_offset);
char *message = *(char **) (chat_packet + ChatPacket_message_property_offset);
@ -138,9 +139,9 @@ void init_chat() {
if (_chat_enabled) {
// Disable Original ChatPacket Loopback
unsigned char disable_chat_packet_loopback_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x6b490, disable_chat_packet_loopback_patch);
patch((void *) 0x8c118, disable_chat_packet_loopback_patch);
// Manually Send (And Loopback) ChatPacket
overwrite_call((void *) 0x6b518, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
overwrite_call((void *) 0x8c1a4, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
// Re-Broadcast ChatPacket
patch_address(ServerSideNetworkHandler_handle_ChatPacket_vtable_addr, (void *) ServerSideNetworkHandler_handle_ChatPacket_injection);
// Send Messages On Input Tick

View File

@ -48,7 +48,9 @@ static void *chat_thread(__attribute__((unused)) void *nop) {
// Don't Allow Empty Strings
if (length > 0) {
// Submit
_chat_queue_message(output);
char *safe_output = to_cp437(output);
_chat_queue_message(safe_output);
free(safe_output);
}
}
// Free Output

View File

@ -8,11 +8,11 @@ static void do_nothing() {
// Patch bcm_host Calls
__attribute__((constructor)) static 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
overwrite_call((void *) 0x125a8, (void *) do_nothing); // graphics_get_display_size
overwrite_call((void *) 0x125dc, (void *) do_nothing); // vc_dispmanx_display_open
overwrite_call((void *) 0x125e8, (void *) do_nothing); // vc_dispmanx_update_start
overwrite_call((void *) 0x12618, (void *) do_nothing); // vc_dispmanx_element_add
overwrite_call((void *) 0x12624, (void *) do_nothing); // vc_dispmanx_update_submit_sync
overwrite_call((void *) 0xdbe8, (void *) do_nothing); // bcm_host_init
overwrite_call((void *) 0x11c54, (void *) do_nothing); // bcm_host_deinit
overwrite_call((void *) 0x11de4, (void *) do_nothing); // graphics_get_display_size
overwrite_call((void *) 0x11e18, (void *) do_nothing); // vc_dispmanx_display_open
overwrite_call((void *) 0x11e28, (void *) do_nothing); // vc_dispmanx_update_start
overwrite_call((void *) 0x11e58, (void *) do_nothing); // vc_dispmanx_element_add
overwrite_call((void *) 0x11e64, (void *) do_nothing); // vc_dispmanx_update_submit_sync
}

View File

@ -29,7 +29,6 @@ HOOK(SDL_ShowCursor, int, (int toggle)) {
#include <media-layer/core.h>
#include <mods/input/input.h>
#include <mods/sign/sign.h>
#include <mods/chat/chat.h>
#include <mods/home/home.h>
@ -89,20 +88,12 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
// Track Right-Click State
if (event->button.button == SDL_BUTTON_RIGHT) {
input_set_is_right_click(event->button.state != SDL_RELEASED);
} else if (event->button.button == SDL_BUTTON_LEFT) {
// Track Left-Click State
if (event->button.button == SDL_BUTTON_LEFT) {
input_set_is_left_click(event->button.state != SDL_RELEASED);
}
break;
}
case SDL_USEREVENT: {
// SDL_UserEvent Is Never Used In MCPI, So It Is Repurposed For Character Events
sign_key_press((char) event->user.code);
handled = 1;
break;
}
}
if (handled) {

View File

@ -23,17 +23,17 @@ static EGLBoolean eglSwapBuffers_injection(__attribute__((unused)) EGLDisplay di
__attribute__((constructor)) static void patch_egl_calls() {
// Disable EGL Calls
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x1250c, nop_patch); // eglTerminate
patch((void *) 0x12580, nop_patch); // eglBindAPI
overwrite_call((void *) 0x12638, (void *) eglCreateWindowSurface_injection); // eglCreateWindowSurface
patch((void *) 0x12578, nop_patch); // eglChooseConfig
patch((void *) 0x1255c, nop_patch); // eglInitialize
patch((void *) 0x124f0, nop_patch); // eglMakeCurrent #1
patch((void *) 0x12654, nop_patch); // eglMakeCurrent #2
overwrite_call((void *) 0x124dc, (void *) eglSwapBuffers_injection); // eglSwapBuffers #1
overwrite_call((void *) 0x14b6c, (void *) eglSwapBuffers_injection); // eglSwapBuffers #2
overwrite_call((void *) 0x1254c, (void *) eglGetDisplay_injection); // eglGetDisplay
patch((void *) 0x124fc, nop_patch); // eglDestroySurface #1
patch((void *) 0x12504, nop_patch); // eglDestroySurface #2
overwrite_call((void *) 0x12594, (void *) eglCreateContext_injection); // eglCreateContext
patch((void *) 0x11d3c, nop_patch); // eglTerminate
patch((void *) 0x11dbc, nop_patch); // eglBindAPI
overwrite_call((void *) 0x11e78, (void *) eglCreateWindowSurface_injection); // eglCreateWindowSurface
patch((void *) 0x11db4, nop_patch); // eglChooseConfig
patch((void *) 0x11d98, nop_patch); // eglInitialize
patch((void *) 0x11d20, nop_patch); // eglMakeCurrent #1
patch((void *) 0x11e90, nop_patch); // eglMakeCurrent #2
overwrite_call((void *) 0x11d0c, (void *) eglSwapBuffers_injection); // eglSwapBuffers #1
overwrite_call((void *) 0x14ce4, (void *) eglSwapBuffers_injection); // eglSwapBuffers #2
overwrite_call((void *) 0x11d7c, (void *) eglGetDisplay_injection); // eglGetDisplay
patch((void *) 0x11d2c, nop_patch); // eglDestroySurface #1
patch((void *) 0x11d34, nop_patch); // eglDestroySurface #2
overwrite_call((void *) 0x11dd0, (void *) eglCreateContext_injection); // eglCreateContext
}

View File

@ -23,6 +23,6 @@ static int XGetWindowAttributes_injection(__attribute__((unused)) void *display,
// Patch X11 Calls
__attribute__((constructor)) static void patch_x11_calls() {
// Disable X11 Calls
overwrite_call((void *) 0x132a4, (void *) XGetWindowAttributes_injection); // XGetWindowAttributes
overwrite_call((void *) 0x132d4, (void *) XTranslateCoordinates_injection); // XTranslateCoordinates
overwrite_call((void *) 0x12f2c, (void *) XGetWindowAttributes_injection); // XGetWindowAttributes
overwrite_call((void *) 0x12f64, (void *) XTranslateCoordinates_injection); // XTranslateCoordinates
}

View File

@ -1,3 +1,5 @@
#include <vector>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
@ -18,6 +20,7 @@ static void inventory_add_item(unsigned char *inventory, unsigned char *item, bo
// Expand Creative Inventory
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) {
// Add Items
inventory_add_item(filling_container, *Item_sign, false);
inventory_add_item(filling_container, *Item_flintAndSteel, false);
inventory_add_item(filling_container, *Item_snowball, false);
inventory_add_item(filling_container, *Item_egg, false);
@ -37,7 +40,6 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
// Add Tiles
inventory_add_item(filling_container, *Tile_water, true);
inventory_add_item(filling_container, *Tile_lava, true);
inventory_add_item(filling_container, *Tile_calmWater, true);
inventory_add_item(filling_container, *Tile_calmLava, true);
inventory_add_item(filling_container, *Tile_glowingObsidian, true);
inventory_add_item(filling_container, *Tile_web, true);
@ -79,21 +81,37 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
}
#endif
// Hook Specific TileItem Constructor
static unsigned char *Tile_initTiles_TileItem_injection(unsigned char *tile_item, int32_t id) {
// Store All Default TileItems
static std::vector<unsigned char *> &get_default_tile_items() {
static std::vector<unsigned char *> tile_items;
return tile_items;
}
// Hook Specific TileItem :;operator new
static unsigned char *Tile_initTiles_operator_new_injection(__attribute__((unused)) uint32_t size) {
// Call Original Method
unsigned char *ret = (*TileItem)(tile_item, id);
unsigned char *ret = (unsigned char *) ::operator new(AUX_DATA_TILE_ITEM_SIZE);
// Switch VTable
*(unsigned char **) tile_item = AuxDataTileItem_vtable;
// Configure Item
*(bool *) (tile_item + Item_is_stacked_by_data_property_offset) = true;
*(int32_t *) (tile_item + Item_max_damage_property_offset) = 0;
*(unsigned char **) (tile_item + AuxDataTileItem_icon_tile_property_offset) = Tile_tiles[id + 0x100];
// Store
get_default_tile_items().push_back(ret);
// Return
return ret;
}
// Modify All Default TileItems
static void Tile_initTiles_injection(__attribute__((unused)) unsigned char *null) {
// Loop
for (unsigned char *tile_item : get_default_tile_items()) {
// Get ID
int32_t id = *(int32_t *) (tile_item + Item_id_property_offset);
// Switch VTable
*(unsigned char **) tile_item = AuxDataTileItem_vtable;
// Configure Item
*(bool *) (tile_item + Item_is_stacked_by_data_property_offset) = true;
*(int32_t *) (tile_item + Item_max_damage_property_offset) = 0;
*(unsigned char **) (tile_item + AuxDataTileItem_icon_tile_property_offset) = Tile_tiles[id];
}
get_default_tile_items().clear();
}
// Check Restriction Status
static int is_restricted = 1;
@ -112,11 +130,10 @@ void init_creative() {
// Use AuxDataTileItem by default instead of TileItem, so tiles in the Creative
// Inventory can have arbitrary auxiliary values.
{
// Fix 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);
// Hook TileItem ::operator new To Store TileItems
overwrite_call((void *) 0x1295a4, (void *) Tile_initTiles_operator_new_injection);
// Modify Stored TileItems
misc_run_on_internal_after_tiles_setup(Tile_initTiles_injection);
}
}
@ -124,34 +141,35 @@ void init_creative() {
if (feature_has("Remove Creative Mode Restrictions", server_disabled)) {
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);
patch((void *) 0x59e68, nop_patch);
patch((void *) 0x59ebc, nop_patch);
patch((void *) 0x59f10, nop_patch);
unsigned char allow_eating_patch[4] = {0x02, 0x00, 0x00, 0xea}; // "b 0xddcbc"
patch((void *) 0xddcac, allow_eating_patch);
// Fix UI
patch((void *) 0x341c0, nop_patch);
patch((void *) 0x3adb4, nop_patch);
patch((void *) 0x3b374, nop_patch);
patch((void *) 0x4cb88, nop_patch);
unsigned char fix_ui_patch[4] = {0x05, 0x00, 0x55, 0xe1}; // "cmp r5, r5"
patch((void *) 0x4bf20, fix_ui_patch);
// Fix Inventory
patch((void *) 0xcce90, nop_patch);
patch((void *) 0xd5548, nop_patch);
unsigned char inv_creative_check_r3_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
patch((void *) 0xd497c, inv_creative_check_r3_patch);
unsigned char inv_creative_check_r5_patch[4] = {0x05, 0x00, 0x55, 0xe1}; // "cmp r5, r5"
patch((void *) 0xd4d94, inv_creative_check_r5_patch);
patch((void *) 0xd50ac, nop_patch);
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);
patch((void *) 0x23d4c, nop_patch);
patch((void *) 0x2c570, nop_patch);
patch((void *) 0x3eec0, 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);
unsigned char maximize_stack_patch[4] = {0xff, 0x60, 0xa0, 0xe3}; // "mov r6, 0xff"
patch((void *) 0xccf80, maximize_stack_patch);
// Allow Nether Reactor
patch((void *) 0xc0290, nop_patch);
unsigned char nether_reactor_patch[4] = {0x00, 0x00, 0xa0, 0xe3}; // "mov r0, #0x0"
patch((void *) 0x12283c, nether_reactor_patch);
// Disable Other Restrictions
is_restricted = 0;
}

View File

@ -14,14 +14,14 @@ static void set_is_survival(int new_is_survival) {
// Correct Inventpry UI
unsigned char inventory_patch[4] = {new_is_survival ? 0x00 : 0x01, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0" or "mov r3, #0x1"
patch((void *) 0x16efc, inventory_patch);
patch((void *) 0x178c0, inventory_patch);
// Use Correct Size For GameMode Object
unsigned char size_patch[4] = {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);
patch((void *) 0x178a8, size_patch);
// Replace Default CreatorMode Constructor With CreatorMode Or SurvivalMode Constructor
overwrite_call((void *) 0x16ef4, new_is_survival ? SurvivalMode : CreatorMode);
overwrite_call((void *) 0x178b8, new_is_survival ? SurvivalMode : CreatorMode);
is_survival = new_is_survival;
}
@ -54,11 +54,11 @@ void init_game_mode() {
overwrite_calls((void *) Minecraft_setIsCreativeMode, (void *) Minecraft_setIsCreativeMode_injection);
// Replace CreatorLevel With ServerLevel (This Fixes Beds And Mob Spawning)
overwrite_call((void *) 0x16f84, (void *) ServerLevel);
overwrite_call((void *) 0x17950, (void *) ServerLevel);
// Allocate Correct Size For ServerLevel
uint32_t level_size = SERVER_LEVEL_SIZE;
patch_address((void *) 0x17004, (void *) level_size);
patch_address((void *) 0x17a38, (void *) level_size);
// Disable CreatorMode-Specific API Features (Polling Block Hits) In SurvivalMode, This Is Preferable To Crashing
overwrite_calls((void *) Minecraft_getCreator, (void *) Minecraft_getCreator_injection);
@ -72,7 +72,7 @@ void init_game_mode() {
// Allow Joining Survival Servers
if (feature_has("Allow Joining Survival Servers", server_enabled)) {
unsigned char server_patch[4] = {0x0f, 0x00, 0x00, 0xea}; // "b 0x6dcb4"
patch((void *) 0x6dc70, server_patch);
unsigned char server_patch[4] = {0x16, 0x00, 0x00, 0xea}; // "b 0x8e998"
patch((void *) 0x8e938, server_patch);
}
}

View File

@ -186,7 +186,9 @@ static void *create_world_thread(__attribute__((unused)) void *nop) {
pthread_mutex_lock(&create_world_state_lock);
reset_create_world_state();
create_world_state.dialog_state = DIALOG_SUCCESS;
create_world_state.name = world_name;
char *safe_name = to_cp437(world_name);
create_world_state.name = safe_name;
free(world_name);
create_world_state.game_mode = game_mode;
create_world_state.seed = seed;
pthread_mutex_unlock(&create_world_state_lock);

View File

@ -24,10 +24,8 @@ __attribute__((destructor)) static void _free_home() {
// Init
void init_home() {
// Store Data In ~/.minecraft-pi Instead Of ~/.minecraft
patch_address((void *) default_path, (void *) HOME_SUBDIRECTORY_FOR_GAME_DATA);
patch_address((void *) full_data_path, (void *) home_get());
// The override code resolves assets manually,
// making changing directory redundant.
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0xe0ac, nop_patch);
}

View File

@ -15,7 +15,6 @@ __attribute__((constructor)) static void init() {
init_multiplayer();
init_sound();
init_input();
init_sign();
init_creative();
init_camera();
init_touch();

View File

@ -1,37 +0,0 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/feature/feature.h>
#include "input-internal.h"
#include <mods/input/input.h>
// Store Right-Click Status
static int is_right_click = 0;
void input_set_is_right_click(int val) {
is_right_click = val;
}
// Enable Bow & Arrow Fix
static int fix_bow = 0;
// Handle Bow & Arrow
static void _handle_bow(unsigned char *minecraft) {
if (fix_bow && !is_right_click) {
// GameMode Is Offset From minecraft By 0x160
// Player Is Offset From minecraft By 0x18c
unsigned char *game_mode = *(unsigned char **) (minecraft + Minecraft_game_mode_property_offset);
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
if (player != NULL && game_mode != NULL && (*Player_isUsingItem)(player)) {
unsigned char *game_mode_vtable = *(unsigned char **) game_mode;
GameMode_releaseUsingItem_t GameMode_releaseUsingItem = *(GameMode_releaseUsingItem_t *) (game_mode_vtable + GameMode_releaseUsingItem_vtable_offset);
(*GameMode_releaseUsingItem)(game_mode, player);
}
}
}
// Init
void _init_bow() {
// Enable Bow & Arrow Fix
fix_bow = feature_has("Fix Bow & Arrow", server_disabled);
input_run_on_tick(_handle_bow);
}

View File

@ -5,7 +5,6 @@ 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();

View File

@ -40,9 +40,6 @@ void init_input() {
// Item Dropping
_init_drop();
// Enable Bow & Arrow Fix
_init_bow();
// Loop
overwrite_calls((void *) Minecraft_tickInput, (void *) Minecraft_tickInput_injection);

View File

@ -88,7 +88,7 @@ void _init_misc() {
overwrite_calls((void *) Gui_handleClick, (void *) Gui_handleClick_injection);
}
// Disable Item Dropping Using The Cursor When Cursor Is Hidden
overwrite_call((void *) 0x27800, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection);
overwrite_call((void *) 0x2b130, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection);
input_run_on_tick(_handle_back);
input_run_on_tick(_handle_mouse_grab);

View File

@ -83,6 +83,7 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
// Run Functions On Tiles Setup
SETUP_CALLBACK(tiles_setup);
SETUP_CALLBACK(internal_after_tiles_setup);
// Handle Custom Tiles Setup Behavior
static void Tile_initTiles_injection() {
// Run Functions
@ -90,6 +91,9 @@ static void Tile_initTiles_injection() {
// Call Original Method
(*Tile_initTiles)();
// Run Functions
handle_misc_internal_after_tiles_setup(NULL);
}
// Run Functions On Items Setup
@ -113,7 +117,7 @@ void _init_misc_api() {
overwrite_calls((void *) Recipes, (void *) Recipes_injection);
overwrite_calls((void *) FurnaceRecipes, (void *) FurnaceRecipes_injection);
// Handle Custom Creative Inventory Setup Behavior
overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection);
overwrite_call((void *) 0xcdcf4, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection);
// Handle Custom Item/Tile Init Behavior
overwrite_calls((void *) Tile_initTiles, (void *) Tile_initTiles_injection);
overwrite_calls((void *) Item_initItems, (void *) Item_initItems_injection);

View File

@ -20,7 +20,9 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text
Gui_addMessage_recursing = true;
// Print Log Message
fprintf(stderr, "[CHAT]: %s\n", new_message);
char *safe_message = from_cp437(new_message);
fprintf(stderr, "[CHAT]: %s\n", safe_message);
free(safe_message);
// Call Original Method
(*Gui_addMessage)(gui, std::string(new_message));

View File

@ -36,17 +36,6 @@ static void Gui_renderHearts_GuiComponent_blit_hearts_injection(unsigned char *c
// Call Original Method
(*GuiComponent_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(unsigned char *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) {
unsigned char *minecraft = *(unsigned char **) (component + Gui_minecraft_property_offset);
x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH;
float width = ((float) *(int32_t *) (minecraft + Minecraft_screen_width_property_offset)) * *InvGuiScale;
float height = ((float) *(int32_t *) (minecraft + Minecraft_screen_height_property_offset)) * *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
(*GuiComponent_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(unsigned char *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) {
unsigned char *minecraft = *(unsigned char **) (component + Gui_minecraft_property_offset);
x_dest -= DEFAULT_HUD_PADDING;
@ -297,6 +286,11 @@ int32_t misc_get_real_selected_slot(unsigned char *player) {
return selected_slot;
}
// Stop Checking GL Renderer
static bool AppPlatform_isPowerVR_injection(__attribute__((unused)) unsigned char *app_platform) {
return 0;
}
// Init
static void nop() {
}
@ -304,17 +298,16 @@ void init_misc() {
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
if (feature_has("Remove Invalid Item Background", server_disabled)) {
unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x63c98, invalid_item_background_patch);
patch((void *) 0x7f7e8, invalid_item_background_patch);
}
// Classic HUD
if (feature_has("Classic HUD", server_disabled)) {
use_classic_hud = 1;
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x26758, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x2656c, (void *) Gui_renderHearts_GuiComponent_blit_armor_injection);
overwrite_call((void *) 0x268c4, (void *) Gui_renderBubbles_GuiComponent_blit_injection);
overwrite_call((void *) 0x2b730, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x2b8a4, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x2b788, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x2ba80, (void *) Gui_renderBubbles_GuiComponent_blit_injection);
}
// Render Selected Item Text + Hide Chat Messages
@ -327,7 +320,7 @@ void init_misc() {
// Translucent Toolbar
if (feature_has("Translucent Toolbar", server_disabled)) {
overwrite_calls((void *) Gui_renderToolBar, (void *) Gui_renderToolBar_injection);
overwrite_call((void *) 0x26c5c, (void *) Gui_renderToolBar_glColor4f_injection);
overwrite_call((void *) 0x2c130, (void *) Gui_renderToolBar_glColor4f_injection);
}
// Fix Screen Rendering When GUI is Hidden
@ -340,7 +333,7 @@ void init_misc() {
overwrite_calls((void *) RakNet_RakString, (void *) RakNet_RakString_injection);
// Print Error Message If RakNet Startup Fails
overwrite_call((void *) 0x73778, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection);
overwrite_call((void *) 0x98014, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection);
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
overwrite_calls((void *) RakNetInstance, (void *) RakNetInstance_injection);
@ -359,7 +352,7 @@ void init_misc() {
if (feature_has("Improved Cursor Rendering", server_disabled)) {
// Disable Normal Cursor Rendering
unsigned char disable_cursor_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4a6c0, disable_cursor_patch);
patch((void *) 0x61afc, disable_cursor_patch);
// Add Custom Cursor Rendering
overwrite_calls((void *) GameRenderer_render, (void *) GameRenderer_render_injection);
}
@ -379,6 +372,9 @@ void init_misc() {
overwrite_calls((void *) sleepMs, (void *) nop);
}
// Stop Checking GL Renderer
overwrite((void *) AppPlatform_isPowerVR, (void *) AppPlatform_isPowerVR_injection);
// Init C++ And Logging
_init_misc_cpp();
_init_misc_logging();

View File

@ -75,10 +75,10 @@ void _init_misc_cpp() {
// Improved Title Background
if (feature_has("Improved Title Background", server_disabled)) {
// Switch Background
overwrite_call((void *) 0x39528, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
overwrite_call((void *) 0x3dee0, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
overwrite_call((void *) 0x4a40c, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
overwrite_call((void *) 0x52360, (void *) StartMenuScreen_render_Screen_renderBackground_injection);
// Text Color
patch_address((void *) 0x397ac, (void *) 0xffffffff);
patch_address((void *) 0x3e10c, (void *) 0xffffffff);
patch_address((void *) 0x4a764, (void *) 0xffffffff);
patch_address((void *) 0x525f4, (void *) 0xffffffff);
}
}

View File

@ -1,12 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((visibility("internal"))) void _init_options_cpp();
__attribute__((visibility("internal"))) extern unsigned char *stored_options;
#ifdef __cplusplus
}
#endif

View File

@ -5,7 +5,6 @@
#include <mods/feature/feature.h>
#include <mods/init/init.h>
#include "options-internal.h"
// Force Mob Spawning
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) {
@ -39,44 +38,37 @@ static char *get_username() {
}
return username;
}
static int anaglyph;
static int render_distance;
// Configure Options
unsigned char *stored_options = NULL;
static void Options_initDefaultValue_injection(unsigned char *options) {
// Call Original Method
(*Options_initDefaultValue)(options);
// Default Graphics Settings
#ifndef MCPI_SERVER_MODE
*(options + Options_fancy_graphics_property_offset) = 1;
*(options + Options_ambient_occlusion_property_offset) = 1;
#endif
// Store
stored_options = options;
static char *safe_username = NULL;
__attribute__((destructor)) static void _free_safe_username() {
free(safe_username);
}
static void Minecraft_init_injection(unsigned char *minecraft) {
// Call Original Method
(*Minecraft_init)(minecraft);
unsigned char *options = minecraft + Minecraft_options_property_offset;
static int fancy_graphics;
static int peaceful_mode;
static int anaglyph;
static int smooth_lighting;
static int render_distance;
static int server_visible;
// Configure Options
static void Minecraft_init_injection(unsigned char *this) {
// Call Original Method
(*Minecraft_init)(this);
unsigned char *options = this + Minecraft_options_property_offset;
// Enable Fancy Graphics
*(options + Options_fancy_graphics_property_offset) = fancy_graphics;
// Enable Crosshair In Touch GUI
*(options + Options_split_controls_property_offset) = 1;
// Peaceful Mode
*(int32_t *) (options + Options_game_difficulty_property_offset) = peaceful_mode ? 0 : 2;
// 3D Anaglyph
*(options + Options_3d_anaglyph_property_offset) = anaglyph;
// Smooth Lighting
*(options + Options_ambient_occlusion_property_offset) = smooth_lighting;
// Render Distance
*(int32_t *) (options + Options_render_distance_property_offset) = render_distance;
}
// Smooth Lighting
static void TileRenderer_tesselateBlockInWorld_injection(unsigned char *tile_renderer, unsigned char *tile, int32_t x, int32_t y, int32_t z) {
// Set Variable
*Minecraft_useAmbientOcclusion = *(stored_options + Options_ambient_occlusion_property_offset);
// Call Original Method
(*TileRenderer_tesselateBlockInWorld)(tile_renderer, tile, x, y, z);
// Server Visible
*(options + Options_server_visible_property_offset) = server_visible;
}
// Init
@ -86,14 +78,19 @@ void init_options() {
overwrite((void *) LevelData_getSpawnMobs, (void *) LevelData_getSpawnMobs_injection);
}
// Enable Fancy Graphics
fancy_graphics = feature_has("Fancy Graphics", server_disabled);
// Peaceful Mode
peaceful_mode = feature_has("Peaceful Mode", server_auto);
// 3D Anaglyph
anaglyph = feature_has("3D Anaglyph", server_disabled);
// Render Distance
render_distance = get_render_distance();
DEBUG("Setting Render Distance: %i", render_distance);
// Server Visible
server_visible = !feature_has("Disable Hosting LAN Worlds", server_disabled);
// Set Options
overwrite_calls((void *) Options_initDefaultValue, (void *) Options_initDefaultValue_injection);
overwrite_calls((void *) Minecraft_init, (void *) Minecraft_init_injection);
// Change Username
@ -102,24 +99,28 @@ void init_options() {
if (strcmp(*default_username, "StevePi") != 0) {
ERR("Default Username Is Invalid");
}
patch_address((void *) default_username, (void *) username);
safe_username = to_cp437(username);
patch_address((void *) default_username, (void *) safe_username);
unsigned char username_length_patch[4] = {(unsigned char) strlen(safe_username), 0x20, 0xa0, 0xe3}; // "mov r2, #USERNAME_LENGTH"
patch((void *) 0x1ba2c, username_length_patch);
// Disable Autojump By Default
if (feature_has("Disable Autojump By Default", server_disabled)) {
unsigned char autojump_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0"
patch((void *) 0x44b90, autojump_patch);
unsigned char autojump_patch[4] = {0x00, 0x00, 0xa0, 0xe3}; // "mov r0, #0x0"
patch((void *) 0x5b148, autojump_patch);
}
// Display Nametags By Default
if (feature_has("Display Nametags By Default", server_disabled)) {
// r6 = 0x1
// r5 = 0x0
unsigned char display_nametags_patch[4] = {0x1d, 0x60, 0xc0, 0xe5}; // "strb r6, [r0, #0x1d]"
patch((void *) 0xa6628, display_nametags_patch);
// r12 = 0x0
unsigned char display_nametags_patch[4] = {0x1d, 0x60, 0xc4, 0xe5}; // "strb r6, [r4, #0x1d]"
patch((void *) 0xf2d44, display_nametags_patch);
}
// Smooth Lighting
overwrite_calls((void *) TileRenderer_tesselateBlockInWorld, (void *) TileRenderer_tesselateBlockInWorld_injection);
// Init C++
_init_options_cpp();
// Enable Smooth Lighting
smooth_lighting = feature_has("Smooth Lighting", server_disabled);
if (smooth_lighting) {
unsigned char smooth_lighting_patch[4] = {0x01, 0x00, 0x53, 0xe3}; // "cmp r3, #0x1"
patch((void *) 0x73b74, smooth_lighting_patch);
}
}

View File

@ -1,230 +0,0 @@
#include <string>
#include <vector>
#include <sstream>
#include <string.h>
#include <libreborn/libreborn.h>
#include <mods/feature/feature.h>
#include <mods/home/home.h>
#include "options-internal.h"
#include <symbols/minecraft.h>
// Fix Initial Option Button Rendering
// The calling function doesn't exist in MCPE v0.6.1, so its name is unknown.
static unsigned char *OptionsPane_unknown_toggle_creating_function_OptionButton_injection(unsigned char *option_button, unsigned char *option) {
// Call Original Method
unsigned char *ret = (*OptionButton)(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(unsigned char *options, std::vector<std::string> &data, std::string option, int32_t value) {
// Call Original Method
(*Options_addOptionToSaveOutput)(options, data, option, value);
// Save Fancy Graphics
(*Options_addOptionToSaveOutput)(options, data, "gfx_fancygraphics", *(options + Options_fancy_graphics_property_offset));
// Save File
unsigned char *options_file = options + Options_options_file_property_offset;
(*OptionsFile_save)(options_file, data);
}
// MCPI's OptionsFile::getOptionStrings is broken, this is the version in v0.7.0
static std::vector<std::string> OptionsFile_getOptionStrings_injection(unsigned char *options_file) {
// Get options.txt Path
std::string path = *(std::string *) (options_file + OptionsFile_options_txt_path_property_offset);
// Parse
std::vector<std::string> ret;
FILE *stream = fopen(path.c_str(), "r");
char line[128];
if (stream != NULL) {
while (fgets(line, 0x80, stream) != NULL) {
size_t sVar1 = strlen(line);
if (2 < sVar1) {
std::stringstream string_stream(line);
while (true) {
std::string data;
std::getline(string_stream, data, ':');
int iVar2 = data.find_last_not_of(" \n\r\t");
data.erase(iVar2 + 1);
if (data.length() == 0) {
break;
}
ret.push_back(data);
}
}
}
fclose(stream);
}
return ret;
}
// Get New options.txt Path
#ifndef MCPI_SERVER_MODE
static char *get_new_options_txt_path() {
static char *path = NULL;
// Path
if (path == NULL) {
safe_asprintf(&path, "%s/options.txt", home_get());
}
// Return
return path;
}
// Free
__attribute__((destructor)) static void _free_new_options_txt_path() {
free(get_new_options_txt_path());
}
#else
static char *get_new_options_txt_path() {
// Block options.txt On Servers
return (char *) "/dev/null";
}
#endif
// Modify Option Toggles
static void OptionsPane_unknown_toggle_creating_function_injection(unsigned char *options_pane, uint32_t group_id, std::string const& name, unsigned char *option) {
// Modify
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
(*OptionsPane_unknown_toggle_creating_function)(options_pane, group_id, new_name, option);
}
// Add Missing Options To Options::getBooleanValue
static bool Options_getBooleanValue_injection(unsigned char *options, unsigned char *option) {
// Check
if (option == Options_Option_GRAPHICS) {
return *(options + Options_fancy_graphics_property_offset);
} else {
// Call Original Method
return (*Options_getBooleanValue)(options, option);
}
}
// Add Options Button Back To Classic Start Screen
static void StartMenuScreen_init_injection(unsigned char *screen) {
// Call Original Method
(*StartMenuScreen_init)(screen);
// Add Button
std::vector<unsigned char *> *rendered_buttons = (std::vector<unsigned char *> *) (screen + Screen_rendered_buttons_property_offset);
std::vector<unsigned char *> *selectable_buttons = (std::vector<unsigned char *> *) (screen + Screen_selectable_buttons_property_offset);
unsigned char *options_button = screen + StartMenuScreen_options_button_property_offset;
rendered_buttons->push_back(options_button);
selectable_buttons->push_back(options_button);
}
// Init C++
void _init_options_cpp() {
// NOP
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((void *) OptionsPane_unknown_toggle_creating_function, (void *) OptionsPane_unknown_toggle_creating_function_injection);
// Add Missing Options To Options::getBooleanValue
overwrite_calls((void *) Options_getBooleanValue, (void *) Options_getBooleanValue_injection);
// Add Options Button Back To Classic Start Screen
patch_address(StartMenuScreen_init_vtable_addr, (void *) StartMenuScreen_init_injection);
// Fix Classic UI Options Button Size
unsigned char classic_options_button_width_patch[4] = {0xa0, 0x00, 0xa0, 0xe3}; // "mov r0, #0xa0"
patch((void *) 0x39a98, classic_options_button_width_patch);
unsigned char classic_options_button_height_patch[4] = {0x18, 0x30, 0xa0, 0xe3}; // "mov r3, #0x18"
patch((void *) 0x39a9c, classic_options_button_height_patch);
// Fix Classic UI Buttons Spacing
{
// Join Button
unsigned char classic_join_button_spacing_patch[4] = {0x12, 0x20, 0x83, 0xe2}; // "add r2, r3, #0x12"
patch((void *) 0x39894, classic_join_button_spacing_patch);
// Start Button
unsigned char classic_start_button_spacing_patch[4] = {0x08, 0x20, 0x43, 0xe2}; // "sub r2, r3, #0x08"
patch((void *) 0x3988c, classic_start_button_spacing_patch);
// Options Button
unsigned char classic_options_button_spacing_patch[4] = {0x2c, 0x30, 0x83, 0xe2}; // "add r3, r3, #0x2c"
patch((void *) 0x39898, classic_options_button_spacing_patch);
}
}
// Actually Save options.txt
overwrite_call((void *) 0x197fc, (void *) Options_save_Options_addOptionToSaveOutput_injection);
// Fix options.txt Path
patch_address((void *) options_txt_path, (void *) get_new_options_txt_path());
// When Loading, options.txt Should Be Opened In Read Mode
patch_address((void *) options_txt_fopen_mode_when_loading, (void *) "r");
// Fix OptionsFile::getOptionStrings
overwrite_calls((void *) OptionsFile_getOptionStrings, (void *) OptionsFile_getOptionStrings_injection);
// Sensitivity Loading/Saving Is Broken, Disable It
patch((void *) 0x1931c, nop_patch);
patch((void *) 0x1973c, nop_patch);
// Unsplit Touch Controls Breaks Things, Never Load/Save It
unsigned char cmp_r0_r0_patch[4] = {0x00, 0x00, 0x50, 0xe1}; // "cmp r0, r0"
patch((void *) 0x19378, cmp_r0_r0_patch);
patch((void *) 0x197cc, nop_patch);
// Custom Username Is Loaded Manually, Disable Loading From options.txt
patch((void *) 0x192ac, nop_patch);
// Replace "feedback_vibration" Loading/Saving With "gfx_ao"
{
// Replace String
static const char *new_feedback_vibration_options_txt_nam = "gfx_ao";
patch_address((void *) feedback_vibration_options_txt_name_1, (void *) &new_feedback_vibration_options_txt_nam);
patch_address((void *) feedback_vibration_options_txt_name_2, (void *) &new_feedback_vibration_options_txt_nam);
// Loading
unsigned char gfx_ao_loading_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x10, 0x84, 0xe2}; // "add param_2, r4, #OFFSET"
patch((void *) 0x193b8, gfx_ao_loading_patch);
// Saving
unsigned char gfx_ao_saving_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x30, 0xd4, 0xe5}; // "ldrb r3, [r4, #OFFSET]"
patch((void *) 0x197f8, gfx_ao_saving_patch);
}
// Disable "gfx_lowquality" Loading
patch((void *) 0x19414, nop_patch);
patch((void *) 0x1941c, nop_patch);
}

View File

@ -64,7 +64,11 @@ static ServerProperties &get_server_properties() {
// Get World Name
static std::string get_world_name() {
return get_server_properties().get_string("world-name", DEFAULT_WORLD_NAME);
std::string name = get_server_properties().get_string("world-name", DEFAULT_WORLD_NAME);
char *safe_name_c = to_cp437(name.c_str());
std::string safe_name = safe_name_c;
free(safe_name_c);
return safe_name;
}
// Create/Start World
@ -75,10 +79,6 @@ static void start_world(unsigned char *minecraft) {
// Log
INFO("Loading World: %s", world_name.c_str());
// Peaceful Mode
unsigned char *options = minecraft + Minecraft_options_property_offset;
*(int32_t *) (options + Options_game_difficulty_property_offset) = get_server_properties().get_bool("peaceful-mode", DEFAULT_PEACEFUL_MODE) ? 0 : 2;
// Specify Level Settings
LevelSettings settings;
settings.game_type = get_server_properties().get_int("game-mode", DEFAULT_GAME_MODE);
@ -94,6 +94,7 @@ static void start_world(unsigned char *minecraft) {
// Open Port
int port = get_server_properties().get_int("port", DEFAULT_PORT);
INFO("Listening On: %i", port);
patch_address((void *) 0x16cd8, (void *) port);
(*Minecraft_hostMultiplayer)(minecraft, port);
}
@ -120,8 +121,12 @@ static std::vector<unsigned char *> get_players_in_level(unsigned char *level) {
return *(std::vector<unsigned char *> *) (level + Level_players_property_offset);
}
// Get Player's Username
static std::string *get_player_username(unsigned char *player) {
return (std::string *) (player + Player_username_property_offset);
static std::string get_player_username(unsigned char *player) {
std::string *username = (std::string *) (player + Player_username_property_offset);
char *safe_username_c = from_cp437(username->c_str());
std::string safe_username = safe_username_c;
free(safe_username_c);
return safe_username;
}
// Get Level From Minecraft
static unsigned char *get_level(unsigned char *minecraft) {
@ -137,7 +142,7 @@ static void find_players(unsigned char *minecraft, std::string target_username,
for (std::size_t i = 0; i < players.size(); i++) {
// Iterate Players
unsigned char *player = players[i];
std::string username = *get_player_username(player);
std::string username = get_player_username(player);
if (all_players || username == target_username) {
// Run Callback
(*callback)(minecraft, username, player);
@ -293,6 +298,15 @@ __attribute__((destructor)) static void _free_stdin_buffer() {
stdin_buffer = NULL;
}
}
// Prevent STDIN From Being Closed
HOOK(close, int, (int fd)) {
if (fd != fileno(stdin)) {
ensure_close();
return (*real_close)(fd);
} else {
return 0;
}
}
// Handle Commands
static void handle_commands(unsigned char *minecraft) {
@ -326,8 +340,11 @@ static void handle_commands(unsigned char *minecraft) {
} else if (data.rfind(say_command, 0) == 0) {
// Format Message
std::string message = "[Server] " + data.substr(say_command.length());
char *safe_message = to_cp437(message.c_str());
// Post Message To Chat
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, message);
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, safe_message);
// Free
free(safe_message);
} else if (data == list_command) {
// List Players
INFO("All Players:");
@ -470,6 +487,9 @@ static const char *get_features() {
loaded_features = true;
features.clear();
if (get_server_properties().get_bool("peaceful-mode", DEFAULT_PEACEFUL_MODE)) {
features += "Peaceful Mode|";
}
if (get_server_properties().get_bool("force-mob-spawning", DEFAULT_FORCE_MOB_SPAWNING)) {
features += "Force Mob Spawning|";
}
@ -555,23 +575,23 @@ static void server_init() {
// Prevent Main Player From Loading
unsigned char player_patch[4] = {0x00, 0x20, 0xa0, 0xe3}; // "mov r2, #0x0"
patch((void *) 0x1685c, player_patch);
patch((void *) 0x16ef8, player_patch);
// Start World On Launch
misc_run_on_update(Minecraft_update_injection);
// Set Max Players
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3}; // "mov r3, #MAX_PLAYERS"
patch((void *) 0x166d0, max_players_patch);
patch((void *) 0x16cc0, max_players_patch);
// Custom Banned IP List
overwrite((void *) RakNet_RakPeer_IsBanned, (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)) {
unsigned char minecon_badge_patch[4] = {0x04, 0x1a, 0x9f, 0xe5}; // "ldr r1, [0x741f0]"
patch((void *) 0x737e4, minecon_badge_patch);
unsigned char minecon_badge_patch[4] = {0x5c, 0x1a, 0x9f, 0xe5}; // "ldr r1, [0x98af0]"
patch((void *) 0x9808c, minecon_badge_patch);
}
// Log IPs
overwrite_call((void *) 0x75e54, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection);
overwrite_call((void *) 0x9a63c, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection);
// Track TPS
misc_run_on_tick(Minecraft_tick_injection);
@ -584,7 +604,7 @@ static void server_init() {
// Init Server
void init_server() {
server_init();
setenv("MCPI_FEATURE_FLAGS", get_features(), 1);
setenv("MCPI_RENDER_DISTANCE", "Tiny", 1);
setenv("MCPI_USERNAME", get_motd().c_str(), 1);
set_and_print_env("MCPI_FEATURE_FLAGS", get_features());
set_and_print_env("MCPI_RENDER_DISTANCE", "Tiny");
set_and_print_env("MCPI_USERNAME", get_motd().c_str());
}

View File

@ -1,2 +0,0 @@
# ``sign`` Mod
This mod fixes sign placement.

View File

@ -1,68 +0,0 @@
#include <vector>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/init/init.h>
#include <mods/feature/feature.h>
#include <mods/input/input.h>
#include <mods/sign/sign.h>
// Open Sign Screen
static void LocalPlayer_openTextEdit_injection(unsigned char *local_player, unsigned char *sign) {
if (*(int32_t *) (sign + TileEntity_id_property_offset) == 4) {
unsigned char *minecraft = *(unsigned char **) (local_player + LocalPlayer_minecraft_property_offset);
unsigned char *screen = (unsigned char *) ::operator new(TEXT_EDIT_SCREEN_SIZE);
ALLOC_CHECK(screen);
screen = (*TextEditScreen)(screen, sign);
(*Minecraft_setScreen)(minecraft, screen);
}
}
#define BACKSPACE_KEY 8
static int is_valid_key(char key) {
return (key >= 32 && key <= 126) || key == BACKSPACE_KEY;
}
// Store Text Input
std::vector<char> input;
void sign_key_press(char key) {
if (is_valid_key(key)) {
input.push_back(key);
}
}
static void clear_input(__attribute__((unused)) unsigned char *minecraft) {
input.clear();
}
// Handle Text Input
static void TextEditScreen_updateEvents_injection(unsigned char *screen) {
// Call Original Method
(*Screen_updateEvents)(screen);
if (*(char *)(screen + 4) == '\0') {
unsigned char *vtable = *(unsigned char **) screen;
for (char key : input) {
if (key == BACKSPACE_KEY) {
// Handle Backspace
(*(Screen_keyPressed_t *) (vtable + Screen_keyPressed_vtable_offset))(screen, BACKSPACE_KEY);
} else {
// Handle Normal Key
(*(Screen_keyboardNewChar_t *) (vtable + Screen_keyboardNewChar_vtable_offset))(screen, key);
}
}
}
clear_input(NULL);
}
// Init
void init_sign() {
if (feature_has("Fix Sign Placement", server_disabled)) {
// Fix Signs
patch_address(LocalPlayer_openTextEdit_vtable_addr, (void *) LocalPlayer_openTextEdit_injection);
patch_address(TextEditScreen_updateEvents_vtable_addr, (void *) TextEditScreen_updateEvents_injection);
// Clear input On Input Tick
input_run_on_tick(clear_input);
}
}

View File

@ -170,5 +170,5 @@ void init_textures() {
}
// Scale Animated Textures
overwrite_call((void *) 0x53274, (void *) Textures_tick_glTexSubImage2D_injection);
overwrite_call((void *) 0x6bfd0, (void *) Textures_tick_glTexSubImage2D_injection);
}

View File

@ -30,7 +30,7 @@ static int32_t Button_hovered_injection(__attribute__((unused)) unsigned char *b
// Check
return x >= button_x1 && x <= button_x2 && y >= button_y1 && y <= button_y2;
}
static void LargeImageButton_render_GuiComponent_drawCenteredString_injection(unsigned char *component, unsigned char *font, std::string const& text, int32_t x, int32_t y, int32_t color) {
static void Button_render_GuiComponent_drawCenteredString_injection(unsigned char *component, unsigned char *font, std::string const& text, int32_t x, int32_t y, int32_t color) {
// Change Color On Hover
if (color == 0xe0e0e0 && Button_hovered_injection(component, NULL, 0, 0)) {
color = 0xffffa0;
@ -39,6 +39,15 @@ static void LargeImageButton_render_GuiComponent_drawCenteredString_injection(un
// Call Original Method
(*GuiComponent_drawCenteredString)(component, font, text, x, y, color);
}
static void Button_renderBg_GuiComponent_blit_injection(unsigned char *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) {
// Change Color On Hover
if (y_src == 66 && Button_hovered_injection(component, NULL, 0, 0)) {
y_src += 20;
}
// Call Original Method
(*GuiComponent_blit)(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
// Init
void init_touch() {
@ -50,46 +59,50 @@ void init_touch() {
// Force Correct Toolbar Size
unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1"
patch((void *) 0x257b0, toolbar_patch);
patch((void *) 0x2a6cc, toolbar_patch);
} else {
// Force Touch Inventory
if (feature_has("Force Touch GUI Inventory", server_disabled)) {
overwrite_call((void *) 0x2943c, (void *) operator_new_IngameBlockSelectionScreen_injection);
overwrite_call((void *) 0x29444, (void *) Touch_IngameBlockSelectionScreen);
overwrite_call((void *) 0x2f628, (void *) operator_new_IngameBlockSelectionScreen_injection);
overwrite_call((void *) 0x2f630, (void *) Touch_IngameBlockSelectionScreen);
// Make "Craft" And "Armor" Buttons Use Classic GUI Style (Button And TButton Have The Same Size)
overwrite_call((void *) 0x3b060, (void *) Button);
overwrite_call((void *) 0x3b08c, (void *) Button);
overwrite_call((void *) 0x4c6fc, (void *) Button);
}
// Force Touch Button Behavior
if (feature_has("Force Touch GUI Button Behavior", server_disabled)) {
touch_buttons = 1;
overwrite_call((void *) 0x1baf4, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x1be40, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x1c470, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x1e868, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x290b8, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x29168, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x3e314, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2cbc0, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2ea7c, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x4a438, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2007c, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2020c, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x20674, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2f200, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2fe9c, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x213bc, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x24250, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2f200, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x2f2a8, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x520c4, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x33cac, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x37e7c, (void *) Minecraft_isTouchscreen_injection);
overwrite_call((void *) 0x61a0c, (void *) Minecraft_isTouchscreen_injection);
}
}
// Improved Button Hover Behavior
if (touch_buttons && feature_has("Improved Button Hover Behavior", server_disabled)) {
overwrite((void *) Button_hovered, (void *) Button_hovered_injection);
overwrite_call((void *) 0x1ebd4, (void *) LargeImageButton_render_GuiComponent_drawCenteredString_injection);
overwrite_call((void *) 0x20190, (void *) Button_render_GuiComponent_drawCenteredString_injection);
overwrite_call((void *) 0x24108, (void *) Button_render_GuiComponent_drawCenteredString_injection);
overwrite_call((void *) 0x202d0, (void *) Button_renderBg_GuiComponent_blit_injection);
overwrite_call((void *) 0x20304, (void *) Button_renderBg_GuiComponent_blit_injection);
}
// Show Block Outlines
int block_outlines = feature_has("Show Block Outlines", server_disabled);
unsigned char outline_patch[4] = {(unsigned char) (block_outlines ? !touch_gui : touch_gui), 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" or "cmp r0, #0x0"
patch((void *) 0x4a210, outline_patch);
patch((void *) 0x6183c, outline_patch);
if (block_outlines) {
// Disable Broken Touchscreen-Specific Block Outline Behavior
unsigned char block_highlight_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
patch((void *) 0x494b4, block_highlight_patch);
patch((void *) 0x60bdc, block_highlight_patch);
}
}

View File

@ -31,6 +31,8 @@ void init_version() {
overwrite((void *) Common_getGameVersionString, (void *) Common_getGameVersionString_injection);
// Normal GUI
patch_address((void *) minecraft_pi_version, version_get());
unsigned char normal_gui_version_length_patch[4] = {(unsigned char) strlen(version_get()), 0x20, 0xa0, 0xe3}; // "mov r2, #VERSION_LENGTH"
patch((void *) 0x4b11c, normal_gui_version_length_patch);
// Log
INFO("Starting Minecraft: Pi Edition (%s)", version_get());

View File

@ -3,8 +3,8 @@
set -e
# Prepare
NAME='minecraft-pi-reborn'
BRANCH='master'
NAME='minecraft-pi-reborn-legacy'
BRANCH='legacy'
# Build
./scripts/setup.sh "$1" "$2" -DMCPI_IS_APPIMAGE_BUILD=ON

View File

@ -7,7 +7,7 @@ ARCH="$(dpkg-architecture -qDEB_BUILD_ARCH)"
./scripts/setup.sh server "${ARCH}"
./scripts/build.sh server "${ARCH}"
# Add minecraft-pi-reborn-server To PATH
# Add minecraft-pi-reborn-legacy-server To PATH
export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_BUILD_ARCH)/usr/bin:${PATH}"
# Create Test Directory
@ -16,14 +16,14 @@ mkdir -p build/test
# Run Test
cd build/test
minecraft-pi-reborn-server --only-generate
minecraft-pi-reborn-legacy-server --only-generate
cd ../../
# Build Benchmark
./scripts/setup.sh client "${ARCH}" -DMCPI_HEADLESS_MODE=ON
./scripts/build.sh client "${ARCH}"
# Add minecraft-pi-reborn-client To PATH
# Add minecraft-pi-reborn-legacy-client To PATH
export PATH="$(pwd)/out/client-$(dpkg-architecture -qDEB_BUILD_ARCH)/usr/bin:${PATH}"
# Skip Root Check
@ -31,4 +31,4 @@ export _MCPI_SKIP_ROOT_CHECK=1
# Run Benchmark
export HOME="$(pwd)/build/test"
minecraft-pi-reborn-client --default --benchmark
minecraft-pi-reborn-legacy-client --default --benchmark

File diff suppressed because it is too large Load Diff