This commit is contained in:
TheBrokenRail 2021-09-11 23:18:12 -04:00
parent a762654e35
commit d851a8f3e1
79 changed files with 1307 additions and 180 deletions

View File

@ -115,6 +115,11 @@ if(BUILD_NATIVE_COMPONENTS)
add_subdirectory(launcher)
endif()
# Include Symbols
if(BUILD_ARM_COMPONENTS)
add_subdirectory(symbols)
endif()
# Build Mods
if(BUILD_ARM_COMPONENTS)
add_subdirectory(mods)

View File

@ -1,7 +1,7 @@
FROM debian:bullseye
FROM debian:bullseye-slim
# Copy DEB
ADD ./out/minecraft-pi-reborn-server_*~bullseye_amd64.deb /root
ADD ./out/minecraft-pi-reborn-server_*_amd64.deb /root
# Install
RUN \

View File

@ -1 +1 @@
2.1.8
2.2.0

2
debian/client-arm vendored
View File

@ -4,4 +4,4 @@ Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: armhf
Depends: libc6, libstdc++6, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3
Depends: libc6, libstdc++6, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1

2
debian/client-arm64 vendored
View File

@ -4,4 +4,4 @@ Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: arm64
Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3
Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1

View File

@ -4,4 +4,4 @@ Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: amd64
Depends: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, qemu-user-static
Depends: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1, qemu-user-static

View File

@ -36,6 +36,7 @@ This sub-component re-implements a subset of SDL 1.2 calls with GLFW. It also pr
The utility functions include:
* Taking Screenshots
* Fullscreen
* Audio
* Etc
This is always compiled for the host system's architecture.
@ -87,17 +88,20 @@ This component contains various utility functions including:
* Code Patching (ARM Only)
* Logging
* MCPI Symbols
* Etc
The code patching is ARM only because it relies on hard-coded ARM instructions. However, this is irrelevant since code patching is only needed in ARM code (to patch MCPI).
### ``symbols``
This component contains all MCPI symbols.
## Dependencies
MCPI-Reborn has several dependencies:
* MCPI (Bundled)
* GLFW (Only In Client Mode)
* Open GL ES 1.1
* EGL
* OpenAL (Only In Client Mode)
* ZLib (Required By LibPNG; Bundled)
* LibPNG (Bundled)
* FreeImage (Only In Client Mode)

View File

@ -24,6 +24,7 @@
* Client Mode Only
* GLFW
* FreeImage
* OpenAL
## Runtime Dependencies
* Non-ARM Host Architectures
@ -33,6 +34,7 @@
* OpenGL ES 1.1
* GLFW
* FreeImage
* OpenAL
* Zenity
## Two-Step Build

View File

@ -1,5 +1,13 @@
# Changelog
**2.2.0**
* Sound Support
* Split Off "Allow Joining Survival Servers" From Game-Mode Mod
* Separate Headless Code From Server Code
* Fix Bug Where `RakNetInstance` Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
* Clean-Up Code
* Remove Support For Debian Buster
**2.1.8**
* Fix Crash On ARM Systems

View File

@ -1,25 +1,21 @@
# Manual Installation
[Download Packages Here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/)
## Supported Distributions
* Ubuntu 20.04+
* Debian Bullseye+
## Picking A Package
### Name Format
```
minecraft-pi-reborn-<Variant>_X.Y.Z~<Distribution>_<Architecture>
minecraft-pi-reborn-<Variant>_X.Y.Z_<Architecture>
```
### Picking A Variant
* ``client``: Client mode, use this if you want to play MCPI
* ``server``: Server mode, use this if you want to host a dedicated MCPI server
### Picking A Distribution
This specifies which version of Debian MCPI-Reborn was built against. Which one you should use depends on your current distribution. If your distribution supports it, you should use ``bullseye`` for better mouse sensitivity.
* Ubuntu 20.04+: ``bullseye``
* Raspberry Pi OS Buster: ``buster``
* Debian Bullseye+: ``bullseye``
* Debian Buster: ``buster``
### Picking An Architecture
* ``amd64``: x86_64, use this if you are using a device with an AMD or Intel processor
* ``armhf``: ARM 32-Bit, use this if you are using an ARM device (like a Raspberry Pi)

View File

@ -8,4 +8,5 @@
* [View Architecture](ARCHITECTURE.md)
* [View Command Line Arguments](COMMAND_LINE.md)
* [View Multiplayer](MULTIPLAYER.md)
* [View Sound](SOUND.md)
* [View Changelog](CHANGELOG.md)

7
docs/SOUND.md Normal file
View File

@ -0,0 +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!
[^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

@ -2,6 +2,7 @@
| Name | Description |
| --- | --- |
| MCPI | Shorthand for Minecraft: Pi Edition |
| MCPE | Shorthand for Minecraft: Pocket Edition |
| Host Architecture | The native architecture of the CPU that MCPi-Reborn will be running on |
| Native Component | A component that *can* be compiled for the host architecture |
| ARM Component | A component that *must* be compiled for ARM |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -25,3 +25,4 @@ TRUE Bind Common Toggleable Options To Function Keys
TRUE Render Selected Item Text
TRUE External Server Support
TRUE Load Language Files
TRUE Implement Sound Engine

View File

@ -8,7 +8,6 @@
#include <errno.h>
#include <sys/stat.h>
#define FORCE_PROC_FOR_ROOT_PATH
#include <libreborn/libreborn.h>
#include "bootstrap.h"
@ -190,14 +189,6 @@ void bootstrap(int argc, char *argv[]) {
setenv("QEMU_LD_PREFIX", "/usr/arm-linux-gnueabihf", 1);
#endif
// Select Executable Interpreter
#ifdef __ARM_ARCH
#define EXE_INTERPRETER "/lib/ld-linux-armhf.so.3"
#else
// Use Static QEMU So It Isn't Affected By LD_* Variables
#define EXE_INTERPRETER "qemu-arm-static"
#endif
// Create Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_NAME, binary_directory);
@ -205,6 +196,14 @@ void bootstrap(int argc, char *argv[]) {
// Free Binary Directory
free(binary_directory);
#ifdef __ARM_ARCH
// Mark argc As Used
(void) argc;
// Run
safe_execvpe(full_path, argv, environ);
#else
// Use Static QEMU So It Isn't Affected By LD_* Variables
#define EXE_INTERPRETER "qemu-arm-static"
// Create Arguments List
char *new_argv[argc + 2];
for (int i = 1; i <= argc; i++) {
@ -214,4 +213,5 @@ void bootstrap(int argc, char *argv[]) {
new_argv[1] = full_path; // Path To MCPI
// Run
safe_execvpe(EXE_INTERPRETER, new_argv, environ);
#endif
}

View File

@ -6,6 +6,7 @@ target_include_directories(reborn-headers INTERFACE include)
if(BUILD_ARM_COMPONENTS)
add_library(reborn SHARED src/reborn.c)
target_link_libraries(reborn dl reborn-headers)
target_compile_definitions(reborn PUBLIC -DREBORN_HAS_COMPILED_CODE)
# Install
install(TARGETS reborn DESTINATION "${MCPI_LIB_DIR}")
endif()

View File

@ -4,53 +4,46 @@
#include <string.h>
#include <sys/mman.h>
#include <elf.h>
#include <link.h>
#include "log.h"
#include "exec.h"
// Find And Iterate Over All .text Sections In Current Binary
typedef void (*text_section_callback_t)(Elf32_Addr section, Elf32_Word size, void *data);
typedef void (*text_section_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
static inline void iterate_text_sections(text_section_callback_t callback, void *data) {
// Find Main Binary
char *real_path = NULL;
{
char *binary_directory = get_binary_directory();
safe_asprintf(&real_path, "%s/minecraft-pi", binary_directory);
free(binary_directory);
}
// Load Main Binary
FILE *file_obj = fopen(real_path, "rb");
FILE *file_obj = fopen("/proc/self/exe", "rb");
// Verify Binary
if (!file_obj) {
ERR("Unable To Open Binary: %s", real_path);
ERR("%s", "Unable To Open Current Binary");
}
// Get File Size
fseek(file_obj, 0L, SEEK_END);
long int size = ftell(file_obj);
long int file_size = ftell(file_obj);
fseek(file_obj, 0L, SEEK_SET);
// Map File To Pointer
unsigned char *file_map = (unsigned char *) mmap(0, size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
unsigned char *file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
// Parse ELF
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map;
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff);
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_map;
ElfW(Shdr) *elf_section_headers = (ElfW(Shdr) *) (file_map + elf_header->e_shoff);
int elf_section_header_count = elf_header->e_shnum;
// Locate Section Names
Elf32_Shdr elf_strtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_strtab_p = file_map + elf_strtab.sh_offset;
ElfW(Shdr) elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
// Track .text Sections
int text_sections = 0;
// Iterate Sections
for (int i = 0; i < elf_section_header_count; ++i) {
Elf32_Shdr header = elf_section_headers[i];
char *name = (char *) (elf_strtab_p + header.sh_name);
ElfW(Shdr) header = elf_section_headers[i];
char *name = (char *) (elf_shstrtab_p + header.sh_name);
// Check Section Type
if (strcmp(name, ".text") == 0) {
// .text Section
@ -61,13 +54,10 @@ static inline void iterate_text_sections(text_section_callback_t callback, void
// Ensure At Least .text Section Was Scanned
if (text_sections < 1) {
ERR("Unable To Find .text Sectons On: %s", real_path);
ERR("%s", "Unable To Find .text Sectons");
}
// Free Binary Path
free(real_path);
// Unmap And Close File
munmap(file_map, size);
munmap(file_map, file_size);
fclose(file_obj);
}

View File

@ -21,15 +21,6 @@ __attribute__((noreturn)) static inline void safe_execvpe(const char *pathname,
}
// Get Binary Directory (Remember To Free)
static inline char *get_binary_directory() {
#ifndef FORCE_PROC_FOR_ROOT_PATH
{
// Check Environment
char *specified_root = getenv("MCPI_ROOT_PATH");
if (specified_root != NULL) {
return strdup(specified_root);
}
}
#endif
// Get Path To Current Executable
char *exe = realpath("/proc/self/exe", NULL);
ALLOC_CHECK(exe);
@ -43,9 +34,6 @@ static inline char *get_binary_directory() {
}
}
// Set Environment
setenv("MCPI_ROOT_PATH", exe, 1);
// Return
return exe;
}

View File

@ -10,7 +10,7 @@ extern "C" {
#include "exec.h"
#include "elf.h"
#ifdef __arm__
#ifdef REBORN_HAS_COMPILED_CODE
// Patching Functions

View File

@ -6,5 +6,5 @@
// Logging
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", __VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", __VA_ARGS__); }
#define ERR(format, ...) { fprintf(stderr, "[ERR]: " format "\n", __VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, __VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("%s", "This Should Never Be Called")

View File

@ -44,7 +44,7 @@ struct overwrite_data {
void *replacement;
int found;
};
static void overwrite_calls_callback(Elf32_Addr section_addr, Elf32_Word size, void *data) {
static void overwrite_calls_callback(ElfW(Addr) section_addr, ElfW(Word) size, void *data) {
struct overwrite_data *args = (struct overwrite_data *) data;
void *section = (void *) section_addr;
@ -122,12 +122,14 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
// Increment Code Block Position
increment_code_block();
// Check
if (data.found < 1) {
ERR("(%s:%i) Unable To Find Callsites For 0x%08x", file, line, (uint32_t) start);
}
}
// Overwrite Function
// NOTE: "start" Must Be At Least 8 Bytes Long
void _overwrite(const char *file, int line, void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"

View File

@ -2,6 +2,9 @@ project(media-layer-core)
# Configuration
set(CORE_SRC src/base.cpp src/media.c src/screenshot.c) # SDL Re-Implementation Using GLFW
if(NOT MCPI_HEADLESS_MODE)
list(APPEND CORE_SRC src/audio/api.cpp src/audio/engine.c src/audio/file.cpp)
endif()
# Build
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
@ -23,8 +26,10 @@ if(TARGET media-layer-core)
find_package(glfw3 3.3 REQUIRED)
# Find FreeImage
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
# Not Needed In Server Mode
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" GLESv1_CM glfw)
# OpenAL
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" "${OPENAL_LIBRARY}" m GLESv1_CM glfw)
endif()
endif()

View File

@ -0,0 +1,104 @@
#include <vector>
#include <cmath>
#include <AL/al.h>
#include <media-layer/audio.h>
#include <libreborn/libreborn.h>
#include "file.h"
#include "engine.h"
// Store Audio Sources
static std::vector<ALuint> &get_sources() {
static std::vector<ALuint> sources;
return sources;
}
#define AL_ERROR_CHECK() \
{ \
ALenum err = alGetError(); \
if (err != AL_NO_ERROR) { \
ERR("OpenAL Error: %s", alGetString(err)); \
} \
}
// Update Listener
void media_audio_update(float volume, float x, float y, float z, float yaw) {
// Update Listener Volume
alListenerf(AL_GAIN, volume);
AL_ERROR_CHECK();
// Update Listener Position
alListener3f(AL_POSITION, x, y, z);
AL_ERROR_CHECK();
// Update Listener Orientation
float radian_yaw = yaw * (M_PI / 180);
ALfloat orientation[] = {-sinf(radian_yaw), 0.0f, cosf(radian_yaw), 0.0f, 1.0f, 0.0f};
alListenerfv(AL_ORIENTATION, orientation);
AL_ERROR_CHECK();
// Clear Finished Sources
std::vector<ALuint>::iterator it = get_sources().begin();
while (it != get_sources().end()) {
ALuint source = *it;
// Check
ALint source_state;
alGetSourcei(source, AL_SOURCE_STATE, &source_state);
AL_ERROR_CHECK();
if (source_state != AL_PLAYING) {
// Finished
it = get_sources().erase(it);
alDeleteSources(1, &source);
AL_ERROR_CHECK();
} else {
// Still Playing
++it;
}
}
}
void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui) {
// Load Sound
ALuint buffer = _media_audio_get_buffer(source, name);
if (buffer) {
// Create Source
ALuint al_source;
alGenSources(1, &al_source);
AL_ERROR_CHECK();
// Set Properties
alSourcef(al_source, AL_PITCH, pitch);
AL_ERROR_CHECK();
alSourcef(al_source, AL_GAIN, volume);
AL_ERROR_CHECK();
alSource3f(al_source, AL_POSITION, x, y, z);
AL_ERROR_CHECK();
alSource3f(al_source, AL_VELOCITY, 0, 0, 0);
AL_ERROR_CHECK();
alSourcei(al_source, AL_LOOPING, AL_FALSE);
AL_ERROR_CHECK();
alSourcei(al_source, AL_SOURCE_RELATIVE, is_ui ? AL_TRUE : AL_FALSE);
AL_ERROR_CHECK();
// Set Attenuation
alSourcei(al_source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE);
AL_ERROR_CHECK();
alSourcef(al_source, AL_MAX_DISTANCE, 16.0f);
AL_ERROR_CHECK();
alSourcef(al_source, AL_ROLLOFF_FACTOR, 1.0f);
AL_ERROR_CHECK();
alSourcef(al_source, AL_REFERENCE_DISTANCE, 0.0f);
AL_ERROR_CHECK();
// Set Buffer
alSourcei(al_source, AL_BUFFER, buffer);
AL_ERROR_CHECK();
// Play
alSourcePlay(al_source);
AL_ERROR_CHECK();
get_sources().push_back(al_source);
}
}

View File

@ -0,0 +1,85 @@
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alext.h>
#include <libreborn/libreborn.h>
#include "engine.h"
#include "file.h"
// Store Device
static ALCdevice *device = NULL;
static ALCcontext *context = NULL;
// Store State
static int is_loaded = 0;
int _media_audio_is_loaded() {
return is_loaded;
}
// Init
void _media_audio_init() {
// Open Device
device = alcOpenDevice(NULL);
if (!device) {
WARN("%s", "Unable To Load Audio Engine");
return;
}
// Create Context
context = alcCreateContext(device, NULL);
ALCenum err = alcGetError(device);
if (err != ALC_NO_ERROR) {
ERR("Unable To Open Audio Context: %s", alcGetString(device, err));
}
// Select Context
alcMakeContextCurrent(context);
err = alcGetError(device);
if (err != ALC_NO_ERROR) {
ERR("Unable To Select Audio Context: %s", alcGetString(device, err));
}
// Enable AL_SOURCE_DISTANCE_MODEL
alEnable(AL_SOURCE_DISTANCE_MODEL);
ALenum al_err = alGetError();
if (al_err != AL_NO_ERROR) {
ERR("Unable To Enable AL_SOURCE_DISTANCE_MODEL: %s", alGetString(al_err));
}
// Log
INFO("%s", "Loaded Audio Engine");
is_loaded = 1;
}
// De-Init
void _media_audio_cleanup() {
if (_media_audio_is_loaded()) {
// Delete Audio Buffers
_media_audio_delete_buffers();
// Deselect Context
alcMakeContextCurrent(NULL);
ALCenum err = alcGetError(device);
if (err != ALC_NO_ERROR) {
ERR("Unable To Deselect Audio Context: %s", alcGetString(device, err));
}
// Destroy Context
alcDestroyContext(context);
err = alcGetError(device);
if (err != ALC_NO_ERROR) {
ERR("Unable To Destroy Audio Context: %s", alcGetString(device, err));
}
// Close Device
alcCloseDevice(device);
err = alcGetError(device);
if (err != ALC_NO_ERROR) {
ERR("Unable To Close Audio Device: %s", alcGetString(device, err));
}
// Log
INFO("%s", "Unloaded Audio Engine");
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <AL/al.h>
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((visibility("internal"))) void _media_audio_init();
__attribute__((visibility("internal"))) void _media_audio_cleanup();
__attribute__((visibility("internal"))) int _media_audio_is_loaded();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,241 @@
#include <unordered_map>
#include <string>
#include <functional>
#include <cstdint>
#include <unistd.h>
#include <sys/mman.h>
#include <elf.h>
#include <AL/al.h>
#include <libreborn/libreborn.h>
#include "file.h"
#include "engine.h"
// Load Symbol From ELF File
static void load_symbol(const char *source, const char *name, std::function<void(unsigned char *, uint32_t)> callback) {
// File Data
FILE *file_obj = NULL;
unsigned char *file_map = NULL;
long int file_size = 0;
// Code
{
// Load Main Binary
file_obj = fopen(source, "rb");
// Verify Binary
if (!file_obj) {
WARN("Unable To Open: %s", source);
goto end;
}
// Get File Size
fseek(file_obj, 0L, SEEK_END);
file_size = ftell(file_obj);
fseek(file_obj, 0L, SEEK_SET);
// Map File To Pointer
file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
// Check ELF Magic
if (file_map[EI_MAG0] != ELFMAG0 || file_map[EI_MAG1] != ELFMAG1 || file_map[EI_MAG2] != ELFMAG2 || file_map[EI_MAG3] != ELFMAG3) {
WARN("Not An ELF File: %s", source);
goto end;
}
if (file_map[EI_CLASS] != ELFCLASS32) {
WARN("ELF File Isn't 32-Bit: %s", source);
goto end;
}
if (file_map[EI_DATA] != ELFDATA2LSB) {
WARN("ELF File Isn't Little-Endian: %s", source);
goto end;
}
// Parse ELF
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map;
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff);
int elf_section_header_count = elf_header->e_shnum;
// Locate Section Names
Elf32_Shdr elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
// Locate String Table
unsigned char *elf_strtab_p = NULL;
for (int i = 0; i < elf_section_header_count; ++i) {
Elf32_Shdr header = elf_section_headers[i];
// Check Section Type
if (header.sh_type == SHT_STRTAB) {
// Check Section Name
char *section_name = (char *) (elf_shstrtab_p + header.sh_name);
if (strcmp(section_name, ".dynstr") == 0) {
// Found
elf_strtab_p = file_map + header.sh_offset;
break;
}
}
}
if (elf_strtab_p == NULL) {
WARN("Unable To Find String Table In: %s", source);
goto end;
}
// Locate Symbol Tables
Elf32_Sym *symbol = NULL;
for (int i = 0; i < elf_section_header_count; ++i) {
// Exit Loop If Finished
if (symbol != NULL) {
break;
}
// Get Section Header
Elf32_Shdr header = elf_section_headers[i];
// Check Section Type
if (header.sh_type == SHT_DYNSYM) {
// Symbol Table
Elf32_Sym *table = (Elf32_Sym *) (file_map + header.sh_offset);
for (int j = 0; (j * sizeof (Elf32_Sym)) < header.sh_size; j++) {
// Check Symbol Name
char *symbol_name = (char *) (elf_strtab_p + table[j].st_name);
if (strcmp(symbol_name, name) == 0) {
// Found
symbol = &table[j];
break;
}
}
}
}
// Check Symbol
if (symbol != NULL) {
// Convert Virtual Address To File Offset
Elf32_Shdr symbol_section_header = elf_section_headers[symbol->st_shndx];
int vaddr_to_offset = -symbol_section_header.sh_addr + symbol_section_header.sh_offset;
Elf32_Off symbol_offset = symbol->st_value + vaddr_to_offset;
// Access Symbol
unsigned char *value = file_map + symbol_offset;
uint32_t size = symbol->st_size;
callback(value, size);
} else {
// Unable To Find Symbol
WARN("Unable To Find Symbol: %s", name);
}
}
end:
// Unmap And Close File
if (file_map != NULL) {
munmap(file_map, file_size);
}
if (file_obj != NULL) {
fclose(file_obj);
}
}
// Audio Metadata
struct audio_metadata {
int32_t channels;
int32_t frame_size;
int32_t sample_rate;
int32_t frames;
};
// Load Sound Symbol Into ALunit
static ALuint load_sound(const char *source, const char *name) {
// Check OpenAL
if (!_media_audio_is_loaded()) {
return 0;
}
// Store Result
ALuint buffer = 0;
// Load Symbol
load_symbol(source, name, [name, &buffer](unsigned char *symbol, uint32_t size) {
// Load Metadata
if (size < sizeof (audio_metadata)) {
WARN("Symbol Too Small To Contain Audio Metadata: %s", name);
return;
}
audio_metadata *meta = (audio_metadata *) symbol;
// Check Frame Size
if (meta->frame_size != 1 && meta->frame_size != 2) {
WARN("Unsupported Frame Size: %s: %i", name, meta->frame_size);
return;
}
// Get Audio Format
ALenum format = AL_NONE;
if (meta->channels == 1) {
format = meta->frame_size == 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8;
} else if (meta->channels == 2) {
format = meta->frame_size == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8;
} else {
WARN("Unsupported Channel Count: %s: %i", name, meta->channels);
return;
}
// Load Data
int remaining_size = size - sizeof (audio_metadata);
int data_size = meta->channels * meta->frames * meta->frame_size;
if (remaining_size < data_size) {
WARN("Symbol Too Small To Contain Specified Audio Data: %s", name);
return;
}
unsigned char *data = symbol + sizeof (audio_metadata);
// Create Buffer
alGenBuffers(1, &buffer);
alBufferData(buffer, format, data, data_size, meta->sample_rate);
// Check OpenAL Error
ALenum err = alGetError();
if (err != AL_NO_ERROR) {
WARN("Unable To Store Audio Buffer: %s", alGetString(err));
if (buffer && alIsBuffer(buffer)) {
alDeleteBuffers(1, &buffer);
}
buffer = 0;
}
});
// Return
return buffer;
}
// Store Buffers
static std::unordered_map<std::string, ALuint> &get_buffers() {
static std::unordered_map<std::string, ALuint> buffers;
return buffers;
}
// Get Buffer For Sound
ALuint _media_audio_get_buffer(const char *source, const char *name) {
// Check
if (_media_audio_is_loaded()) {
if (get_buffers().count(name) > 0) {
// Return
return get_buffers()[name];
} else {
// Load And Return
get_buffers()[name] = load_sound(source, name);
return _media_audio_get_buffer(source, name);
}
} else {
return 0;
}
}
// Delete Buffers
void _media_audio_delete_buffers() {
if (_media_audio_is_loaded()) {
for (auto it : get_buffers()) {
if (it.second && alIsBuffer(it.second)) {
alDeleteBuffers(1, &it.second);
}
}
}
get_buffers().clear();
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <AL/al.h>
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((visibility("internal"))) ALuint _media_audio_get_buffer(const char *source, const char *name);
__attribute__((visibility("internal"))) void _media_audio_delete_buffers();
#ifdef __cplusplus
}
#endif

View File

@ -4,7 +4,7 @@
#include <SDL/SDL.h>
#include <libreborn/media-layer/internal.h>
#include <media-layer/internal.h>
// SDL Is Replaced With GLFW

View File

@ -9,10 +9,12 @@
#endif // #ifndef MCPI_HEADLESS_MODE
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <libreborn/media-layer/internal.h>
#include <media-layer/core.h>
#include <media-layer/internal.h>
// GLFW Code Not Needed In Server Mode
#include "audio/engine.h"
// GLFW Code Not Needed In Headless Mode
#ifndef MCPI_HEADLESS_MODE
static GLFWwindow *glfw_window;
@ -196,10 +198,14 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
#endif // #ifndef MCPI_HEADLESS_MODE
// Init GLFW
// Track Media Layer State
static int is_running = 0;
// Init Media Layer
void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *icon) {
// Don't Enable GLFW In Server Mode
// Don't Enable GLFW In Headless Mode
#ifndef MCPI_HEADLESS_MODE
// Init GLFW
glfwSetErrorCallback(glfw_error);
if (!glfwInit()) {
@ -221,7 +227,7 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
ERR("%s", "Unable To Create GLFW Window");
}
// Don't Process Events In Server Mode
// Don't Process Events In Headless Mode
glfwSetKeyCallback(glfw_window, glfw_key);
glfwSetCharCallback(glfw_window, glfw_char);
glfwSetCursorPosCallback(glfw_window, glfw_motion);
@ -229,9 +235,15 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
glfwSetScrollCallback(glfw_window, glfw_scroll);
glfwMakeContextCurrent(glfw_window);
// Init OpenAL
_media_audio_init();
#else // #ifndef MCPI_HEADLESS_MODE
(void) title; // Mark As Used
#endif // #ifndef MCPI_HEADLESS_MODE
// Set State
is_running = 1;
}
void media_swap_buffers() {
@ -241,7 +253,7 @@ void media_swap_buffers() {
#endif // #ifndef MCPI_HEADLESS_MODE
}
// Fullscreen Not Needed In Server Mode
// Fullscreen Not Needed In Headless Mode
#ifndef MCPI_HEADLESS_MODE
static int is_fullscreen = 0;
@ -278,7 +290,7 @@ void media_toggle_fullscreen() {
// Intercept SDL Events
void _media_handle_SDL_PollEvent() {
// GLFW Is Disabled In Server Mode
// GLFW And Audio Are Disabled Disabled In Headless Mode
#ifndef MCPI_HEADLESS_MODE
// Process GLFW Events
glfwPollEvents();
@ -293,13 +305,22 @@ void _media_handle_SDL_PollEvent() {
#endif // #ifndef MCPI_HEADLESS_MODE
}
// Terminate GLFW
// Cleanup Media Layer
void media_cleanup() {
// GLFW Is Disabled In Server Mode
if (is_running) {
// GLFW And Audio Are Disabled In Headless Mode
#ifndef MCPI_HEADLESS_MODE
// Terminate GLFW
glfwDestroyWindow(glfw_window);
glfwTerminate();
// Cleanup OpenAL
_media_audio_cleanup();
#endif // #ifndef MCPI_HEADLESS_MODE
// Update State
is_running = 0;
}
}
// Store Cursor State

View File

@ -1,4 +1,4 @@
// Screenshot Code Is Useless In Server Mode
// Screenshot Code Is Useless In Headless Mode
#ifndef MCPI_HEADLESS_MODE
#include <stdlib.h>
@ -14,7 +14,7 @@
#include <GLES/gl.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <media-layer/core.h>
// Ensure Screenshots Folder Exists
static void ensure_screenshots_folder(char *screenshots) {

View File

@ -4,7 +4,7 @@
#include <sys/wait.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <media-layer/core.h>
// SDL Stub
void *SDL_SetVideoMode(__attribute__((unused)) int width, __attribute__((unused)) int height, __attribute__((unused)) int bpp, __attribute__((unused)) uint32_t flags) {

View File

@ -0,0 +1,12 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void media_audio_update(float volume, float x, float y, float z, float yaw);
void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui);
#ifdef __cplusplus
}
#endif

View File

@ -135,7 +135,7 @@ char *read_string() {
return strdup(str);
}
#define MAX_STRING_SIZE 256
void write_string(char *str) {
void write_string(const char *str) {
unsigned char is_null = str == NULL;
write_byte(is_null);
if (!is_null) {

View File

@ -44,7 +44,7 @@ __attribute__((visibility("internal"))) void write_float(float x);
// Read/Write Strings
__attribute__((visibility("internal"))) char *read_string(); // Remember To free()
__attribute__((visibility("internal"))) void write_string(char *str);
__attribute__((visibility("internal"))) void write_string(const char *str);
// Manipulate Connection
__attribute__((visibility("internal"))) void set_connection(int read, int write);

View File

@ -3,8 +3,9 @@
#include <SDL/SDL.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <libreborn/media-layer/internal.h>
#include <media-layer/core.h>
#include <media-layer/audio.h>
#include <media-layer/internal.h>
#include "common/common.h"
@ -356,3 +357,62 @@ CALL(10, media_get_framebuffer_size, void, (int *width, int *height)) {
write_int((uint32_t) height);
#endif
}
CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_float(volume);
write_float(x);
write_float(y);
write_float(z);
write_float(yaw);
// Release Proxy
end_proxy_call();
#else
float volume = read_float();
float x = read_float();
float y = read_float();
float z = read_float();
float yaw = read_float();
// Run
media_audio_update(volume, x, y, z, yaw);
#endif
}
CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_string(source);
write_string(name);
write_float(x);
write_float(y);
write_float(z);
write_float(pitch);
write_float(volume);
write_int(is_ui);
// Release Proxy
end_proxy_call();
#else
char *source = read_string();
char *name = read_string();
float x = read_float();
float y = read_float();
float z = read_float();
float pitch = read_float();
float volume = read_float();
int is_ui = read_int();
// Run
media_audio_play(source, name, x, y, z, pitch, volume, is_ui);
// Free
free(source);
free(name);
#endif
}

View File

@ -8,7 +8,7 @@ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
## Mods
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c)
target_link_libraries(compat feature input chat sign media-layer-core home dl)
target_link_libraries(compat reborn media-layer-core)
add_library(readdir SHARED src/readdir/readdir.c)
@ -16,73 +16,80 @@ add_library(feature SHARED src/feature/feature.c)
target_link_libraries(feature reborn)
add_library(version SHARED src/version/version.cpp)
target_link_libraries(version reborn)
target_link_libraries(version reborn symbols)
add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c)
target_link_libraries(chat reborn symbols feature pthread)
if(MCPI_SERVER_MODE)
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp)
target_link_libraries(server reborn feature home compat version dl media-layer-core pthread)
target_link_libraries(server reborn symbols feature home compat version dl media-layer-core pthread)
else()
target_link_libraries(compat input sign chat home dl)
target_link_libraries(chat input)
add_library(multiplayer SHARED src/multiplayer/multiplayer.cpp)
target_link_libraries(multiplayer reborn home feature)
endif()
target_link_libraries(multiplayer reborn symbols home feature)
add_library(sound SHARED src/sound/sound.cpp src/sound/repository.cpp)
target_link_libraries(sound reborn symbols feature override media-layer-core)
add_library(camera SHARED src/camera/camera.cpp)
target_link_libraries(camera reborn media-layer-core feature home)
add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
target_link_libraries(game-mode reborn feature)
target_link_libraries(camera reborn symbols media-layer-core feature home)
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)
target_link_libraries(input reborn feature media-layer-core)
target_link_libraries(input reborn symbols feature media-layer-core)
add_library(sign SHARED src/sign/sign.cpp)
target_link_libraries(sign reborn feature input)
add_library(death SHARED src/death/death.cpp)
target_link_libraries(death reborn feature)
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp)
target_link_libraries(misc reborn feature)
target_link_libraries(sign reborn symbols feature input)
add_library(creative SHARED src/creative/creative.cpp)
target_link_libraries(creative reborn feature)
add_library(options SHARED src/options/options.c)
target_link_libraries(options reborn feature)
target_link_libraries(creative reborn symbols feature)
add_library(touch SHARED src/touch/touch.c)
target_link_libraries(touch reborn feature)
target_link_libraries(touch reborn symbols feature)
add_library(override SHARED src/override/override.c)
target_link_libraries(override reborn dl home)
target_link_libraries(override reborn symbols dl home)
add_library(textures SHARED src/textures/textures.cpp)
target_link_libraries(textures reborn feature)
target_link_libraries(textures reborn symbols feature)
add_library(atlas SHARED src/atlas/atlas.cpp)
target_link_libraries(atlas reborn feature GLESv1_CM)
target_link_libraries(atlas reborn symbols feature GLESv1_CM)
endif()
add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c)
target_link_libraries(chat reborn feature input pthread)
add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
target_link_libraries(game-mode reborn symbols feature)
add_library(death SHARED src/death/death.cpp)
target_link_libraries(death reborn symbols feature)
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp)
target_link_libraries(misc reborn symbols feature)
add_library(options SHARED src/options/options.c)
target_link_libraries(options reborn symbols feature)
add_library(home SHARED src/home/home.c)
target_link_libraries(home reborn)
target_link_libraries(home reborn symbols)
add_library(test SHARED src/test/test.c)
target_link_libraries(test reborn home)
add_library(init SHARED src/init/init.c)
target_link_libraries(init compat game-mode camera input sign misc creative death options touch textures atlas chat home version test)
target_link_libraries(init compat game-mode misc death options chat home version test)
if(MCPI_SERVER_MODE)
target_link_libraries(init server)
else()
target_link_libraries(init multiplayer)
target_link_libraries(init multiplayer sound camera input sign creative touch textures atlas)
endif()
## Install Mods
install(TARGETS init compat readdir feature override game-mode camera input sign misc creative death options touch textures atlas chat home version test DESTINATION "${MCPI_INSTALL_DIR}/mods")
install(TARGETS init compat readdir feature game-mode misc death options chat home version test DESTINATION "${MCPI_INSTALL_DIR}/mods")
if(MCPI_SERVER_MODE)
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
else()
install(TARGETS multiplayer DESTINATION "${MCPI_INSTALL_DIR}/mods")
install(TARGETS multiplayer sound override camera input sign creative touch textures atlas DESTINATION "${MCPI_INSTALL_DIR}/mods")
endif()

View File

@ -1,7 +1,7 @@
#include <GLES/gl.h>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "../init/init.h"

View File

@ -1,6 +1,6 @@
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <libreborn/minecraft.h>
#include <media-layer/core.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "../home/home.h"

View File

@ -5,11 +5,13 @@
#include <pthread.h>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../init/init.h"
#include "../feature/feature.h"
#ifndef MCPI_SERVER_MODE
#include "../input/input.h"
#endif // #ifndef MCPI_SERVER_MODE
#include "chat.h"
// Store If Chat is Enabled
@ -19,6 +21,7 @@ int _chat_enabled = 0;
#define MAX_CHAT_MESSAGE_LENGTH 512
// Send API Command
#ifndef MCPI_SERVER_MODE
static void send_api_command(unsigned char *minecraft, char *str) {
struct ConnectedClient client;
client.sock = -1;
@ -36,6 +39,7 @@ static void send_api_chat_command(unsigned char *minecraft, char *str) {
send_api_command(minecraft, command);
free(command);
}
#endif // #ifndef MCPI_SERVER_MODE
// Send Message To Players
static void send_message(unsigned char *server_side_network_handler, char *username, char *message) {
@ -76,6 +80,7 @@ static void ServerSideNetworkHandler_handle_ChatPacket_injection(unsigned char *
}
}
#ifndef MCPI_SERVER_MODE
// Message Queue
static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
static std::vector<std::string> queue;
@ -110,6 +115,7 @@ static void send_queued_messages(unsigned char *minecraft) {
// Unlock
pthread_mutex_unlock(&queue_mutex);
}
#endif // #ifndef MCPI_SERVER_MODE
// Init
void init_chat() {
@ -123,6 +129,8 @@ void init_chat() {
// Re-Broadcast ChatPacket
patch_address(ServerSideNetworkHandler_handle_ChatPacket_vtable_addr, (void *) ServerSideNetworkHandler_handle_ChatPacket_injection);
// Send Messages On Input Tick
#ifndef MCPI_SERVER_MODE
input_run_on_tick(send_queued_messages);
#endif // #ifndef MCPI_SERVER_MODE
}
}

View File

@ -4,11 +4,15 @@
extern "C" {
#endif
#ifndef MCPI_SERVER_MODE
void chat_open();
unsigned int chat_get_counter();
#endif // #ifndef MCPI_SERVER_MODE
__attribute__((visibility("internal"))) extern int _chat_enabled;
#ifndef MCPI_SERVER_MODE
__attribute__((visibility("internal"))) void _chat_queue_message(char *message);
#endif // #ifndef MCPI_SERVER_MODE
#ifdef __cplusplus
}

View File

@ -1,3 +1,4 @@
#ifndef MCPI_SERVER_MODE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
@ -86,3 +87,4 @@ void chat_open() {
pthread_create(&thread, NULL, chat_thread, NULL);
}
}
#endif // #ifndef MCPI_SERVER_MODE

View File

@ -1,17 +1,19 @@
#include <unistd.h>
#include <signal.h>
#include "compat.h"
#include "../init/init.h"
#ifndef MCPI_SERVER_MODE
#include <SDL/SDL.h>
#include <libreborn/media-layer/core.h>
#include <media-layer/core.h>
#include <libreborn/libreborn.h>
#include "../input/input.h"
#include "../sign/sign.h"
#include "../chat/chat.h"
#include "../home/home.h"
#include "../init/init.h"
#include "compat.h"
// Custom Title
HOOK(SDL_WM_SetCaption, void, (__attribute__((unused)) const char *title, const char *icon)) {
@ -29,7 +31,6 @@ HOOK(SDL_ShowCursor, int, (int toggle)) {
// Intercept SDL Events
HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// In Server Mode, Exit Requests Are Handled In src/server/server.cpp
#ifndef MCPI_SERVER_MODE
// Check If Exit Is Requested
if (compat_check_exit_requested()) {
// Send SDL_QUIT
@ -37,7 +38,6 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
new_event.type = SDL_QUIT;
SDL_PushEvent(&new_event);
}
#endif // #ifndef MCPI_SERVER_MODE
// Poll Events
ensure_SDL_PollEvent();
@ -106,6 +106,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
return ret;
}
#endif // #ifndef MCPI_SERVER_MODE
// Exit Handler
static void exit_handler(__attribute__((unused)) int data) {

View File

@ -1,7 +1,7 @@
#include <EGL/egl.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <media-layer/core.h>
// Functions That Have Their Return Values Used
static EGLSurface eglCreateWindowSurface_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) {

View File

@ -1,7 +1,7 @@
#include <X11/Xlib.h>
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <media-layer/core.h>
// Functions That Have Their Return Values Used
static int XTranslateCoordinates_injection(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, __attribute__((unused)) XID *child_return) {

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../init/init.h"
#include "../feature/feature.h"

View File

@ -1,7 +1,7 @@
#include <string>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../init/init.h"
#include "../feature/feature.h"

View File

@ -3,7 +3,7 @@
#include "../feature/feature.h"
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
static int is_survival = -1;

View File

@ -2,7 +2,7 @@
#include "game-mode.h"
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
// Get Minecraft From Screen
static unsigned char *get_minecraft_from_screen(unsigned char *screen) {

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "home.h"
#include "../init/init.h"

View File

@ -7,18 +7,19 @@ __attribute__((constructor)) static void init() {
init_server();
#else
init_multiplayer();
#endif
init_game_mode();
init_sound();
init_input();
init_sign();
init_misc();
init_creative();
init_death();
init_camera();
init_options();
init_touch();
init_textures();
init_atlas();
#endif
init_game_mode();
init_misc();
init_death();
init_options();
init_chat();
init_home();
init_version();

View File

@ -10,18 +10,19 @@ void init_compat();
void init_server();
#else
void init_multiplayer();
#endif
void init_game_mode();
void init_sound();
void init_input();
void init_sign();
void init_misc();
void init_creative();
void init_death();
void init_camera();
void init_options();
void init_touch();
void init_textures();
void init_atlas();
#endif
void init_game_mode();
void init_misc();
void init_death();
void init_options();
void init_chat();
void init_home();
void init_version();

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "input.h"

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "input.h"

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "input.h"
#include "../feature/feature.h"

View File

@ -1,7 +1,7 @@
#include <vector>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "../init/init.h"

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "input.h"
#include "../feature/feature.h"

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "input.h"
#include "../feature/feature.h"

View File

@ -3,7 +3,7 @@
#include <unistd.h>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../init/init.h"
#include "../feature/feature.h"
@ -107,6 +107,16 @@ static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection
return result;
}
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
static unsigned char *RakNetInstance_injection(unsigned char *rak_net_instance) {
// Call Original Method
unsigned char *result = (*RakNetInstance)(rak_net_instance);
// Fix
*(unsigned char *) (rak_net_instance + RakNetInstance_pinging_for_hosts_property_offset) = 0;
// Return
return result;
}
// Init
void init_misc() {
if (feature_has("Remove Invalid Item Background", 0)) {
@ -131,6 +141,9 @@ void init_misc() {
// Print Error Message If RakNet Startup Fails
overwrite_call((void *) 0x73778, (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);
// Init C++
_init_misc_cpp();
}

View File

@ -5,7 +5,7 @@
#include <cstring>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "misc.h"

View File

@ -8,7 +8,7 @@
#include <vector>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../home/home.h"
#include "../init/init.h"
@ -110,8 +110,9 @@ static void iterate_servers(std::function<void(const char *address, int port)> c
}
}
// Ping External Servers
static void RakNetInstance_pingForHosts_injection(unsigned char *rak_net_instance, int32_t base_port) {
// Call Original
// Call Original Method
(*RakNetInstance_pingForHosts)(rak_net_instance, base_port);
// Get RakNet::RakPeer

View File

@ -1,7 +1,7 @@
#include <string.h>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "../init/init.h"

View File

@ -14,23 +14,35 @@ static int starts_with(const char *s, const char *t) {
return strncmp(s, t, strlen(t)) == 0;
}
static char *get_override_path(const char *filename) {
char *override_get_path(const char *filename) {
// Get MCPI Home Path
char *home_path = home_get();
// Get Asset Override Path
char *overrides = NULL;
safe_asprintf(&overrides, "%s/overrides", home_path);
// Get Data Path
char *data = NULL;
char *cwd = getcwd(NULL, 0);
safe_asprintf(&data, "%s/data", cwd);
free(cwd);
char *binary_directory = get_binary_directory();
safe_asprintf(&data, "%s/data", binary_directory);
free(binary_directory);
int data_length = strlen(data);
// Get Full Path
char *full_path;
if (strlen(filename) > 0 && filename[0] == '/') {
// Absolute Path
full_path = strdup(filename);
} else {
// Relative Path
full_path = realpath(filename, NULL);
}
// Check For Override
char *new_path = NULL;
char *full_path = realpath(filename, NULL);
if (full_path != NULL) {
if (starts_with(full_path, data)) {
safe_asprintf(&new_path, "%s%s", overrides, &full_path[strlen(data)]);
safe_asprintf(&new_path, "%s%s", overrides, &full_path[data_length]);
if (access(new_path, F_OK) == -1) {
free(new_path);
new_path = NULL;
@ -38,15 +50,17 @@ static char *get_override_path(const char *filename) {
}
free(full_path);
}
// Free Variables
free(overrides);
free(data);
// Return
return new_path;
}
HOOK(fopen, FILE *, (const char *filename, const char *mode)) {
char *new_path = get_override_path(filename);
char *new_path = override_get_path(filename);
// Open File
ensure_fopen();
FILE *file = (*real_fopen)(new_path != NULL ? new_path : filename, mode);
@ -59,7 +73,7 @@ HOOK(fopen, FILE *, (const char *filename, const char *mode)) {
}
HOOK(fopen64, FILE *, (const char *filename, const char *mode)) {
char *new_path = get_override_path(filename);
char *new_path = override_get_path(filename);
// Open File
ensure_fopen64();
FILE *file = (*real_fopen64)(new_path != NULL ? new_path : filename, mode);

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
char *override_get_path(const char *filename);
#ifdef __cplusplus
}
#endif

View File

@ -25,7 +25,7 @@
#include "../compat/compat.h"
#include "../version/version.h"
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
// --only-generate: Ony Generate World And Then Exit
static bool only_generate = false;

View File

@ -1,7 +1,7 @@
#include <vector>
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../init/init.h"
#include "../feature/feature.h"

2
mods/src/sound/README.md Normal file
View File

@ -0,0 +1,2 @@
# ``sound`` Mod
This mod implements a sound engine.

View File

@ -0,0 +1,335 @@
#include <unordered_map>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <libreborn/libreborn.h>
#include "sound.h"
// Sound Repository Extracted From MCPE 0.6.1 APK
static std::unordered_map<std::string, std::vector<std::string>> repository = {
{
{
"step.cloth",
{
"PCM_cloth1",
"PCM_cloth2",
"PCM_cloth3",
"PCM_cloth4"
}
},
{
"step.grass",
{
"PCM_grass1",
"PCM_grass2",
"PCM_grass3",
"PCM_grass4"
}
},
{
"step.gravel",
{
"PCM_gravel1",
"PCM_gravel2",
"PCM_gravel3",
"PCM_gravel4"
}
},
{
"step.sand",
{
"PCM_sand1",
"PCM_sand2",
"PCM_sand3",
"PCM_sand4"
}
},
{
"step.stone",
{
"PCM_stone1",
"PCM_stone2",
"PCM_stone3",
"PCM_stone4"
}
},
{
"step.wood",
{
"PCM_wood1",
"PCM_wood2",
"PCM_wood3",
"PCM_wood4"
}
},
{
"random.splash",
{
"PCM_splash"
}
},
{
"random.explode",
{
"PCM_explode"
}
},
{
"random.click",
{
"PCM_click"
}
},
{
"random.door_open",
{
"PCM_door_open"
}
},
{
"random.door_close",
{
"PCM_door_close"
}
},
{
"random.pop",
{
"PCM_pop"
}
},
{
"random.pop2",
{
"PCM_pop2"
}
},
{
"random.hurt",
{
"PCM_hurt"
}
},
{
"random.glass",
{
"PCM_glass1",
"PCM_glass2",
"PCM_glass3"
}
},
{
"mob.sheep",
{
"PCM_sheep1",
"PCM_sheep2",
"PCM_sheep3"
}
},
{
"mob.pig",
{
"PCM_pig1",
"PCM_pig2",
"PCM_pig3"
}
},
{
"mob.pigdeath",
{
"PCM_pigdeath"
}
},
{
"mob.cow",
{
"PCM_cow1",
"PCM_cow2",
"PCM_cow3",
"PCM_cow4"
}
},
{
"mob.cowhurt",
{
"PCM_cowhurt1",
"PCM_cowhurt2",
"PCM_cowhurt3"
}
},
{
"mob.chicken",
{
"PCM_chicken2",
"PCM_chicken3"
}
},
{
"mob.chickenhurt",
{
"PCM_chickenhurt1",
"PCM_chickenhurt2"
}
},
{
"mob.zombie",
{
"PCM_zombie1",
"PCM_zombie2",
"PCM_zombie3"
}
},
{
"mob.zombiedeath",
{
"PCM_zombiedeath"
}
},
{
"mob.zombiehurt",
{
"PCM_zombiehurt1",
"PCM_zombiehurt2"
}
},
{
"mob.skeleton",
{
"PCM_skeleton1",
"PCM_skeleton2",
"PCM_skeleton3"
}
},
{
"mob.skeletonhurt",
{
"PCM_skeletonhurt1",
"PCM_skeletonhurt2",
"PCM_skeletonhurt3",
"PCM_skeletonhurt4"
}
},
{
"mob.spider",
{
"PCM_spider1",
"PCM_spider2",
"PCM_spider3",
"PCM_spider4"
}
},
{
"mob.spiderdeath",
{
"PCM_spiderdeath"
}
},
{
"mob.zombiepig.zpig",
{
"PCM_zpig1",
"PCM_zpig2",
"PCM_zpig3",
"PCM_zpig4"
}
},
{
"mob.zombiepig.zpigangry",
{
"PCM_zpigangry1",
"PCM_zpigangry2",
"PCM_zpigangry3",
"PCM_zpigangry4"
}
},
{
"mob.zombiepig.zpigdeath",
{
"PCM_zpigdeath"
}
},
{
"mob.zombiepig.zpighurt",
{
"PCM_zpighurt1",
"PCM_zpighurt2"
}
},
{
"damage.fallbig",
{
"PCM_fallbig1",
"PCM_fallbig2"
}
},
{
"damage.fallsmall",
{
"PCM_fallsmall"
}
},
{
"random.bow",
{
"PCM_bow"
}
},
{
"random.bowhit",
{
"PCM_bowhit1",
"PCM_bowhit2",
"PCM_bowhit3",
"PCM_bowhit4"
}
},
{
"mob.creeper",
{
"PCM_creeper1",
"PCM_creeper2",
"PCM_creeper3",
"PCM_creeper4"
}
},
{
"mob.creeperdeath",
{
"PCM_creeperdeath"
}
},
{
"random.eat",
{
"PCM_eat1",
"PCM_eat2",
"PCM_eat3"
}
},
{
"random.fuse",
{
"PCM_fuse"
}
}
}
};
// Set rand() Seed
__attribute__((constructor)) static void init_rand_seed() {
srand(time(NULL));
}
// Pick Sound
std::string _sound_pick(std::string sound) {
if (repository.count(sound) > 0) {
// Sound Exists
std::vector<std::string> &options = repository[sound];
return options[rand() % options.size()];
} else {
// Invalid Sound
ERR("Invalid Sound: %s", sound.c_str());
}
}

119
mods/src/sound/sound.cpp Normal file
View File

@ -0,0 +1,119 @@
#include <string>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <media-layer/audio.h>
#include "sound.h"
#include "../feature/feature.h"
#include "../override/override.h"
#include "../init/init.h"
// Resolve Source File Path
#define SOURCE_FILE_BASE "data/libminecraftpe.so"
static std::string get_source_file() {
static bool source_loaded = false;
static std::string source;
// Check
if (source_loaded) {
// Already Resolved
return source;
} else {
// Resolve
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Get Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" SOURCE_FILE_BASE, binary_directory);
// Free Binary Directory
free(binary_directory);
// Handle Overrides
char *overridden_full_path = override_get_path(full_path);
if (overridden_full_path != NULL) {
free(full_path);
full_path = overridden_full_path;
}
// Check If Sound Exists
if (access(full_path, F_OK) == -1) {
// Fail
WARN("%s", "Audio Source File Doesn't Exists: " SOURCE_FILE_BASE);
source.assign("");
} else {
// Set
source.assign(full_path);
}
// Free
free(full_path);
// Mark As Loaded
source_loaded = true;
// Return
return get_source_file();
}
}
// Resolve On Startup
__attribute__((constructor)) static void resolve_source_file() {
get_source_file();
}
// Play Sound
// The pitch value is unsued because it causes glitchy sounds, it is seemingly unused in MCPE as well.
static void SoundEngine_playUI_injection(__attribute__((unused)) unsigned char *sound_engine, std::string const& name, __attribute__((unused)) float pitch, float volume) {
std::string source = get_source_file();
if (source.size() > 0) {
media_audio_play(source.c_str(), _sound_pick(name).c_str(), 0.0f, 0.0f, 0.0f, 1.0f, volume, 1);
}
}
static void SoundEngine_play_injection(__attribute__((unused)) unsigned char *sound_engine, std::string const& name, float x, float y, float z, __attribute__((unused)) float pitch, float volume) {
std::string source = get_source_file();
if (source.size() > 0) {
media_audio_play(source.c_str(), _sound_pick(name).c_str(), x, y, z, 1.0f, volume, 0);
}
}
// Refresh Data
static void SoundEngine_update_injection(unsigned char *sound_engine, unsigned char *listener_mob, __attribute__((unused)) float listener_angle) {
// Variables
static float volume = 0;
static float x = 0;
static float y = 0;
static float z = 0;
static float yaw = 0;
// SoundEngine Properties
unsigned char *options = *(unsigned char **) (sound_engine + SoundEngine_options_property_offset);
// Volume
int32_t sound_enabled = *(int32_t *) (options + Options_sound_property_offset);
volume = sound_enabled ? 1 : 0;
// Position And Rotation
if (listener_mob != NULL) {
// Values
x = *(float *) (listener_mob + Entity_x_property_offset);
y = *(float *) (listener_mob + Entity_y_property_offset);
z = *(float *) (listener_mob + Entity_z_property_offset);
yaw = *(float *) (listener_mob + Entity_yaw_property_offset);
}
// Log
media_audio_update(volume, x, y, z, yaw);
}
// Init
void init_sound() {
// Implement Sound Engine
if (feature_has("Implement Sound Engine", 0)) {
overwrite_calls((void *) SoundEngine_playUI, (void *) SoundEngine_playUI_injection);
overwrite_calls((void *) SoundEngine_play, (void *) SoundEngine_play_injection);
overwrite_calls((void *) SoundEngine_update, (void *) SoundEngine_update_injection);
}
}

5
mods/src/sound/sound.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
__attribute__((visibility("internal"))) std::string _sound_pick(std::string sound);

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "../feature/feature.h"
#include "../init/init.h"

View File

@ -3,7 +3,7 @@
#include "../feature/feature.h"
#include "../init/init.h"
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
// Enable Touch GUI
static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) {

View File

@ -1,5 +1,5 @@
#include <libreborn/libreborn.h>
#include <libreborn/minecraft.h>
#include <symbols/minecraft.h>
#include "version.h"
#include "../init/init.h"

View File

@ -31,6 +31,7 @@ sudo apt-get install --no-install-recommends -y \
libfreeimage3 libfreeimage-dev \
crossbuild-essential-armhf \
crossbuild-essential-arm64 \
libopenal-dev \
qemu-user-static
# Install ARM Dependencies
@ -38,7 +39,9 @@ if [ ! -z "${ARM_PACKAGES_SUPPORTED}" ]; then
sudo apt-get install --no-install-recommends -y \
libglfw3:armhf libglfw3-dev:armhf \
libfreeimage3:armhf \
libopenal-dev:armhf \
libglfw3:arm64 libglfw3-dev:arm64 \
libfreeimage3:arm64
libfreeimage3:arm64 \
libopenal-dev:arm64
fi

View File

@ -15,7 +15,7 @@ package() {
cp "debian/$1" "${dir}/DEBIAN/control"
# Format DEBIAN/control
sed -i "s/\${VERSION}/${VERSION}~$(lsb_release -cs)/g" "${dir}/DEBIAN/control"
sed -i "s/\${VERSION}/${VERSION}/g" "${dir}/DEBIAN/control"
# Fix Permissions On Jenkins
chmod -R g-s "${dir}"

4
symbols/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
project(symbols)
add_library(symbols INTERFACE)
target_include_directories(symbols INTERFACE include)

View File

@ -7,7 +7,7 @@
// bool In C
#ifndef __cplusplus
typedef uint32_t bool;
typedef unsigned char bool;
#endif
// Globals
@ -182,6 +182,7 @@ static uint32_t Options_ambient_occlusion_property_offset = 0x18; // unsigned ch
static uint32_t Options_hide_gui_property_offset = 0xec; // unsigned char / bool
static uint32_t Options_third_person_property_offset = 0xed; // unsigned char / bool
static uint32_t Options_render_distance_property_offset = 0x10; // int32_t
static uint32_t Options_sound_property_offset = 0x4; // int32_t
// MouseBuildInput
@ -221,6 +222,15 @@ static uint32_t Player_inventory_property_offset = 0xbe0; // Inventory *
typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
static uint32_t Entity_die_vtable_offset = 0x130;
static uint32_t Entity_x_property_offset = 0x4; // float
static uint32_t Entity_y_property_offset = 0x8; // float
static uint32_t Entity_z_property_offset = 0xc; // float
static uint32_t Entity_yaw_property_offset = 0x40; // float
static uint32_t Entity_old_x_property_offset = 0x28; // float
static uint32_t Entity_old_y_property_offset = 0x2c; // float
static uint32_t Entity_old_z_property_offset = 0x30; // float
static uint32_t Entity_old_yaw_property_offset = 0x48; // float
// Mob
typedef void (*Mob_actuallyHurt_t)(unsigned char *entity, int32_t damage);
@ -389,7 +399,11 @@ static RakNetInstance_pingForHosts_t RakNetInstance_pingForHosts = (RakNetInstan
static uint32_t RakNetInstance_pingForHosts_vtable_offset = 0x14;
static void *RakNetInstance_pingForHosts_vtable_addr = (void *) 0x109afc;
typedef unsigned char *(*RakNetInstance_t)(unsigned char *rak_net_instance);
static RakNetInstance_t RakNetInstance = (RakNetInstance_t) 0x73b20;
static uint32_t RakNetInstance_peer_property_offset = 0x4; // RakNet::RakPeer *
static uint32_t RakNetInstance_pinging_for_hosts_property_offset = 0x24; // unsigned char
// RakNet::RakPeer
@ -483,6 +497,17 @@ static Tesselator_colorABGR_t Tesselator_colorABGR = (Tesselator_colorABGR_t) 0x
typedef void (*Tesselator_color_t)(unsigned char *tesselator, int32_t r, int32_t g, int32_t b, int32_t a);
static Tesselator_color_t Tesselator_color = (Tesselator_color_t) 0x52a48;
// SoundEngine
typedef void (*SoundEngine_enable_t)(unsigned char *sound_engine, bool state);
static SoundEngine_enable_t SoundEngine_enable = (SoundEngine_enable_t) 0x6776c;
typedef void (*SoundEngine_update_t)(unsigned char *sound_engine, unsigned char *listener_mob, float listener_angle);
static SoundEngine_update_t SoundEngine_update = (SoundEngine_update_t) 0x67778;
static uint32_t SoundEngine_minecraft_property_offset = 0xa08; // Minecraft *
static uint32_t SoundEngine_options_property_offset = 0x4; // Options *
// Method That Require C++ Types
#ifdef __cplusplus
@ -550,6 +575,14 @@ static SelectWorldScreen_getUniqueLevelName_t SelectWorldScreen_getUniqueLevelNa
static SelectWorldScreen_getUniqueLevelName_t Touch_SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x3d82c;
// SoundEngine
typedef void (*SoundEngine_playUI_t)(unsigned char *sound_engine, std::string const& name, float pitch, float volume);
static SoundEngine_playUI_t SoundEngine_playUI = (SoundEngine_playUI_t) 0x67864;
typedef void (*SoundEngine_play_t)(unsigned char *sound_engine, std::string const& name, float x, float y, float z, float pitch, float volume);
static SoundEngine_play_t SoundEngine_play = (SoundEngine_play_t) 0x67860;
// Common
typedef std::string (*Common_getGameVersionString_t)(std::string const& version_suffix);