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) add_subdirectory(launcher)
endif() endif()
# Include Symbols
if(BUILD_ARM_COMPONENTS)
add_subdirectory(symbols)
endif()
# Build Mods # Build Mods
if(BUILD_ARM_COMPONENTS) if(BUILD_ARM_COMPONENTS)
add_subdirectory(mods) add_subdirectory(mods)

View File

@ -1,7 +1,7 @@
FROM debian:bullseye FROM debian:bullseye-slim
# Copy DEB # Copy DEB
ADD ./out/minecraft-pi-reborn-server_*~bullseye_amd64.deb /root ADD ./out/minecraft-pi-reborn-server_*_amd64.deb /root
# Install # Install
RUN \ 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 Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: armhf 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 Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: arm64 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 Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: amd64 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: The utility functions include:
* Taking Screenshots * Taking Screenshots
* Fullscreen * Fullscreen
* Audio
* Etc * Etc
This is always compiled for the host system's architecture. 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) * Code Patching (ARM Only)
* Logging * Logging
* MCPI Symbols
* Etc * 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). 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 ## Dependencies
MCPI-Reborn has several dependencies: MCPI-Reborn has several dependencies:
* MCPI (Bundled) * MCPI (Bundled)
* GLFW (Only In Client Mode) * GLFW (Only In Client Mode)
* Open GL ES 1.1 * Open GL ES 1.1
* EGL * EGL
* OpenAL (Only In Client Mode)
* ZLib (Required By LibPNG; Bundled) * ZLib (Required By LibPNG; Bundled)
* LibPNG (Bundled) * LibPNG (Bundled)
* FreeImage (Only In Client Mode) * FreeImage (Only In Client Mode)

View File

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

View File

@ -1,5 +1,13 @@
# Changelog # 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** **2.1.8**
* Fix Crash On ARM Systems * Fix Crash On ARM Systems

View File

@ -1,25 +1,21 @@
# Manual Installation # Manual Installation
[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/master/lastSuccessfulBuild/artifact/out/)
## Supported Distributions
* Ubuntu 20.04+
* Debian Bullseye+
## Picking A Package ## Picking A Package
### Name Format ### Name Format
``` ```
minecraft-pi-reborn-<Variant>_X.Y.Z~<Distribution>_<Architecture> minecraft-pi-reborn-<Variant>_X.Y.Z_<Architecture>
``` ```
### Picking A Variant ### Picking A Variant
* ``client``: Client mode, use this if you want to play MCPI * ``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 * ``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 ### Picking An Architecture
* ``amd64``: x86_64, use this if you are using a device with an AMD or Intel processor * ``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) * ``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 Architecture](ARCHITECTURE.md)
* [View Command Line Arguments](COMMAND_LINE.md) * [View Command Line Arguments](COMMAND_LINE.md)
* [View Multiplayer](MULTIPLAYER.md) * [View Multiplayer](MULTIPLAYER.md)
* [View Sound](SOUND.md)
* [View Changelog](CHANGELOG.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 | | Name | Description |
| --- | --- | | --- | --- |
| MCPI | Shorthand for Minecraft: Pi Edition | | 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 | | 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 | | Native Component | A component that *can* be compiled for the host architecture |
| ARM Component | A component that *must* be compiled for ARM | | 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 Render Selected Item Text
TRUE External Server Support TRUE External Server Support
TRUE Load Language Files TRUE Load Language Files
TRUE Implement Sound Engine

View File

@ -8,7 +8,6 @@
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#define FORCE_PROC_FOR_ROOT_PATH
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "bootstrap.h" #include "bootstrap.h"
@ -190,14 +189,6 @@ void bootstrap(int argc, char *argv[]) {
setenv("QEMU_LD_PREFIX", "/usr/arm-linux-gnueabihf", 1); setenv("QEMU_LD_PREFIX", "/usr/arm-linux-gnueabihf", 1);
#endif #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 // Create Full Path
char *full_path = NULL; char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_NAME, binary_directory); 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
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 // Create Arguments List
char *new_argv[argc + 2]; char *new_argv[argc + 2];
for (int i = 1; i <= argc; i++) { 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 new_argv[1] = full_path; // Path To MCPI
// Run // Run
safe_execvpe(EXE_INTERPRETER, new_argv, environ); 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) if(BUILD_ARM_COMPONENTS)
add_library(reborn SHARED src/reborn.c) add_library(reborn SHARED src/reborn.c)
target_link_libraries(reborn dl reborn-headers) target_link_libraries(reborn dl reborn-headers)
target_compile_definitions(reborn PUBLIC -DREBORN_HAS_COMPILED_CODE)
# Install # Install
install(TARGETS reborn DESTINATION "${MCPI_LIB_DIR}") install(TARGETS reborn DESTINATION "${MCPI_LIB_DIR}")
endif() endif()

View File

@ -4,53 +4,46 @@
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <elf.h> #include <elf.h>
#include <link.h>
#include "log.h" #include "log.h"
#include "exec.h" #include "exec.h"
// Find And Iterate Over All .text Sections In Current Binary // 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) { 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 // Load Main Binary
FILE *file_obj = fopen(real_path, "rb"); FILE *file_obj = fopen("/proc/self/exe", "rb");
// Verify Binary // Verify Binary
if (!file_obj) { if (!file_obj) {
ERR("Unable To Open Binary: %s", real_path); ERR("%s", "Unable To Open Current Binary");
} }
// Get File Size // Get File Size
fseek(file_obj, 0L, SEEK_END); 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); fseek(file_obj, 0L, SEEK_SET);
// Map File To Pointer // 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 // Parse ELF
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map; ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_map;
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff); ElfW(Shdr) *elf_section_headers = (ElfW(Shdr) *) (file_map + elf_header->e_shoff);
int elf_section_header_count = elf_header->e_shnum; int elf_section_header_count = elf_header->e_shnum;
// Locate Section Names // Locate Section Names
Elf32_Shdr elf_strtab = elf_section_headers[elf_header->e_shstrndx]; ElfW(Shdr) elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_strtab_p = file_map + elf_strtab.sh_offset; unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
// Track .text Sections // Track .text Sections
int text_sections = 0; int text_sections = 0;
// Iterate Sections // Iterate Sections
for (int i = 0; i < elf_section_header_count; ++i) { for (int i = 0; i < elf_section_header_count; ++i) {
Elf32_Shdr header = elf_section_headers[i]; ElfW(Shdr) header = elf_section_headers[i];
char *name = (char *) (elf_strtab_p + header.sh_name); char *name = (char *) (elf_shstrtab_p + header.sh_name);
// Check Section Type // Check Section Type
if (strcmp(name, ".text") == 0) { if (strcmp(name, ".text") == 0) {
// .text Section // .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 // Ensure At Least .text Section Was Scanned
if (text_sections < 1) { 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 // Unmap And Close File
munmap(file_map, size); munmap(file_map, file_size);
fclose(file_obj); 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) // Get Binary Directory (Remember To Free)
static inline char *get_binary_directory() { 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 // Get Path To Current Executable
char *exe = realpath("/proc/self/exe", NULL); char *exe = realpath("/proc/self/exe", NULL);
ALLOC_CHECK(exe); ALLOC_CHECK(exe);
@ -43,9 +34,6 @@ static inline char *get_binary_directory() {
} }
} }
// Set Environment
setenv("MCPI_ROOT_PATH", exe, 1);
// Return // Return
return exe; return exe;
} }

View File

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

View File

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

View File

@ -44,7 +44,7 @@ struct overwrite_data {
void *replacement; void *replacement;
int found; 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; struct overwrite_data *args = (struct overwrite_data *) data;
void *section = (void *) section_addr; 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 Position
increment_code_block(); increment_code_block();
// Check
if (data.found < 1) { if (data.found < 1) {
ERR("(%s:%i) Unable To Find Callsites For 0x%08x", file, line, (uint32_t) start); ERR("(%s:%i) Unable To Find Callsites For 0x%08x", file, line, (uint32_t) start);
} }
} }
// Overwrite Function // Overwrite Function
// NOTE: "start" Must Be At Least 8 Bytes Long
void _overwrite(const char *file, int line, void *start, void *target) { void _overwrite(const char *file, int line, void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]" unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"

View File

@ -2,6 +2,9 @@ project(media-layer-core)
# Configuration # Configuration
set(CORE_SRC src/base.cpp src/media.c src/screenshot.c) # SDL Re-Implementation Using GLFW 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 # Build
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS) 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_package(glfw3 3.3 REQUIRED)
# Find FreeImage # Find FreeImage
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED) find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
# Not Needed In Server Mode # OpenAL
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" GLESv1_CM glfw) find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" "${OPENAL_LIBRARY}" m GLESv1_CM glfw)
endif() endif()
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 <SDL/SDL.h>
#include <libreborn/media-layer/internal.h> #include <media-layer/internal.h>
// SDL Is Replaced With GLFW // SDL Is Replaced With GLFW

View File

@ -9,10 +9,12 @@
#endif // #ifndef MCPI_HEADLESS_MODE #endif // #ifndef MCPI_HEADLESS_MODE
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h> #include <media-layer/core.h>
#include <libreborn/media-layer/internal.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 #ifndef MCPI_HEADLESS_MODE
static GLFWwindow *glfw_window; static GLFWwindow *glfw_window;
@ -196,10 +198,14 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
#endif // #ifndef MCPI_HEADLESS_MODE #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) { 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 #ifndef MCPI_HEADLESS_MODE
// Init GLFW
glfwSetErrorCallback(glfw_error); glfwSetErrorCallback(glfw_error);
if (!glfwInit()) { 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"); 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); glfwSetKeyCallback(glfw_window, glfw_key);
glfwSetCharCallback(glfw_window, glfw_char); glfwSetCharCallback(glfw_window, glfw_char);
glfwSetCursorPosCallback(glfw_window, glfw_motion); 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); glfwSetScrollCallback(glfw_window, glfw_scroll);
glfwMakeContextCurrent(glfw_window); glfwMakeContextCurrent(glfw_window);
// Init OpenAL
_media_audio_init();
#else // #ifndef MCPI_HEADLESS_MODE #else // #ifndef MCPI_HEADLESS_MODE
(void) title; // Mark As Used (void) title; // Mark As Used
#endif // #ifndef MCPI_HEADLESS_MODE #endif // #ifndef MCPI_HEADLESS_MODE
// Set State
is_running = 1;
} }
void media_swap_buffers() { void media_swap_buffers() {
@ -241,7 +253,7 @@ void media_swap_buffers() {
#endif // #ifndef MCPI_HEADLESS_MODE #endif // #ifndef MCPI_HEADLESS_MODE
} }
// Fullscreen Not Needed In Server Mode // Fullscreen Not Needed In Headless Mode
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
static int is_fullscreen = 0; static int is_fullscreen = 0;
@ -278,7 +290,7 @@ void media_toggle_fullscreen() {
// Intercept SDL Events // Intercept SDL Events
void _media_handle_SDL_PollEvent() { void _media_handle_SDL_PollEvent() {
// GLFW Is Disabled In Server Mode // GLFW And Audio Are Disabled Disabled In Headless Mode
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
// Process GLFW Events // Process GLFW Events
glfwPollEvents(); glfwPollEvents();
@ -293,13 +305,22 @@ void _media_handle_SDL_PollEvent() {
#endif // #ifndef MCPI_HEADLESS_MODE #endif // #ifndef MCPI_HEADLESS_MODE
} }
// Terminate GLFW // Cleanup Media Layer
void media_cleanup() { void media_cleanup() {
// GLFW Is Disabled In Server Mode if (is_running) {
// GLFW And Audio Are Disabled In Headless Mode
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
// Terminate GLFW
glfwDestroyWindow(glfw_window); glfwDestroyWindow(glfw_window);
glfwTerminate(); glfwTerminate();
// Cleanup OpenAL
_media_audio_cleanup();
#endif // #ifndef MCPI_HEADLESS_MODE #endif // #ifndef MCPI_HEADLESS_MODE
// Update State
is_running = 0;
}
} }
// Store Cursor State // 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 #ifndef MCPI_HEADLESS_MODE
#include <stdlib.h> #include <stdlib.h>
@ -14,7 +14,7 @@
#include <GLES/gl.h> #include <GLES/gl.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h> #include <media-layer/core.h>
// Ensure Screenshots Folder Exists // Ensure Screenshots Folder Exists
static void ensure_screenshots_folder(char *screenshots) { static void ensure_screenshots_folder(char *screenshots) {

View File

@ -4,7 +4,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h> #include <media-layer/core.h>
// SDL Stub // SDL Stub
void *SDL_SetVideoMode(__attribute__((unused)) int width, __attribute__((unused)) int height, __attribute__((unused)) int bpp, __attribute__((unused)) uint32_t flags) { 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); return strdup(str);
} }
#define MAX_STRING_SIZE 256 #define MAX_STRING_SIZE 256
void write_string(char *str) { void write_string(const char *str) {
unsigned char is_null = str == NULL; unsigned char is_null = str == NULL;
write_byte(is_null); write_byte(is_null);
if (!is_null) { if (!is_null) {

View File

@ -44,7 +44,7 @@ __attribute__((visibility("internal"))) void write_float(float x);
// Read/Write Strings // Read/Write Strings
__attribute__((visibility("internal"))) char *read_string(); // Remember To free() __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 // Manipulate Connection
__attribute__((visibility("internal"))) void set_connection(int read, int write); __attribute__((visibility("internal"))) void set_connection(int read, int write);

View File

@ -3,8 +3,9 @@
#include <SDL/SDL.h> #include <SDL/SDL.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h> #include <media-layer/core.h>
#include <libreborn/media-layer/internal.h> #include <media-layer/audio.h>
#include <media-layer/internal.h>
#include "common/common.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); write_int((uint32_t) height);
#endif #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 ## Mods
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c) 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) 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) target_link_libraries(feature reborn)
add_library(version SHARED src/version/version.cpp) 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) if(MCPI_SERVER_MODE)
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp) 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() else()
target_link_libraries(compat input sign chat home dl)
target_link_libraries(chat input)
add_library(multiplayer SHARED src/multiplayer/multiplayer.cpp) add_library(multiplayer SHARED src/multiplayer/multiplayer.cpp)
target_link_libraries(multiplayer reborn home feature) target_link_libraries(multiplayer reborn symbols home feature)
endif()
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) add_library(camera SHARED src/camera/camera.cpp)
target_link_libraries(camera reborn media-layer-core feature home) target_link_libraries(camera reborn symbols 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)
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/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) add_library(sign SHARED src/sign/sign.cpp)
target_link_libraries(sign reborn feature input) target_link_libraries(sign reborn symbols 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)
add_library(creative SHARED src/creative/creative.cpp) add_library(creative SHARED src/creative/creative.cpp)
target_link_libraries(creative reborn feature) target_link_libraries(creative reborn symbols feature)
add_library(options SHARED src/options/options.c)
target_link_libraries(options reborn feature)
add_library(touch SHARED src/touch/touch.c) 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) 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) 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) 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) add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
target_link_libraries(chat reborn feature input pthread) 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) 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) add_library(test SHARED src/test/test.c)
target_link_libraries(test reborn home) target_link_libraries(test reborn home)
add_library(init SHARED src/init/init.c) 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) if(MCPI_SERVER_MODE)
target_link_libraries(init server) target_link_libraries(init server)
else() else()
target_link_libraries(init multiplayer) target_link_libraries(init multiplayer sound camera input sign creative touch textures atlas)
endif() endif()
## Install Mods ## 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) if(MCPI_SERVER_MODE)
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods") install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
else() 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() endif()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h> #include <media-layer/core.h>
// Functions That Have Their Return Values Used // 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) { 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 <X11/Xlib.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h> #include <media-layer/core.h>
// Functions That Have Their Return Values Used // 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) { 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/libreborn.h>
#include <libreborn/minecraft.h> #include <symbols/minecraft.h>
#include "../init/init.h" #include "../init/init.h"
#include "../feature/feature.h" #include "../feature/feature.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
#include <unistd.h> #include <unistd.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/minecraft.h> #include <symbols/minecraft.h>
#include "../init/init.h" #include "../init/init.h"
#include "../feature/feature.h" #include "../feature/feature.h"
@ -107,6 +107,16 @@ static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection
return result; 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 // Init
void init_misc() { void init_misc() {
if (feature_has("Remove Invalid Item Background", 0)) { if (feature_has("Remove Invalid Item Background", 0)) {
@ -131,6 +141,9 @@ void init_misc() {
// Print Error Message If RakNet Startup Fails // Print Error Message If RakNet Startup Fails
overwrite_call((void *) 0x73778, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection); 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 C++
_init_misc_cpp(); _init_misc_cpp();
} }

View File

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

View File

@ -8,7 +8,7 @@
#include <vector> #include <vector>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/minecraft.h> #include <symbols/minecraft.h>
#include "../home/home.h" #include "../home/home.h"
#include "../init/init.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) { 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); (*RakNetInstance_pingForHosts)(rak_net_instance, base_port);
// Get RakNet::RakPeer // Get RakNet::RakPeer

View File

@ -1,7 +1,7 @@
#include <string.h> #include <string.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <libreborn/minecraft.h> #include <symbols/minecraft.h>
#include "../feature/feature.h" #include "../feature/feature.h"
#include "../init/init.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; 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 // Get MCPI Home Path
char *home_path = home_get(); char *home_path = home_get();
// Get Asset Override Path // Get Asset Override Path
char *overrides = NULL; char *overrides = NULL;
safe_asprintf(&overrides, "%s/overrides", home_path); safe_asprintf(&overrides, "%s/overrides", home_path);
// Get Data Path // Get Data Path
char *data = NULL; char *data = NULL;
char *cwd = getcwd(NULL, 0); char *binary_directory = get_binary_directory();
safe_asprintf(&data, "%s/data", cwd); safe_asprintf(&data, "%s/data", binary_directory);
free(cwd); free(binary_directory);
int data_length = strlen(data);
// Get Full Path // 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 *new_path = NULL;
char *full_path = realpath(filename, NULL);
if (full_path != NULL) { if (full_path != NULL) {
if (starts_with(full_path, data)) { 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) { if (access(new_path, F_OK) == -1) {
free(new_path); free(new_path);
new_path = NULL; new_path = NULL;
@ -38,15 +50,17 @@ static char *get_override_path(const char *filename) {
} }
free(full_path); free(full_path);
} }
// Free Variables // Free Variables
free(overrides); free(overrides);
free(data); free(data);
// Return // Return
return new_path; return new_path;
} }
HOOK(fopen, FILE *, (const char *filename, const char *mode)) { 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 // Open File
ensure_fopen(); ensure_fopen();
FILE *file = (*real_fopen)(new_path != NULL ? new_path : filename, mode); 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)) { 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 // Open File
ensure_fopen64(); ensure_fopen64();
FILE *file = (*real_fopen64)(new_path != NULL ? new_path : filename, mode); 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 "../compat/compat.h"
#include "../version/version.h" #include "../version/version.h"
#include <libreborn/minecraft.h> #include <symbols/minecraft.h>
// --only-generate: Ony Generate World And Then Exit // --only-generate: Ony Generate World And Then Exit
static bool only_generate = false; static bool only_generate = false;

View File

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

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ package() {
cp "debian/$1" "${dir}/DEBIAN/control" cp "debian/$1" "${dir}/DEBIAN/control"
# Format 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 # Fix Permissions On Jenkins
chmod -R g-s "${dir}" 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 // bool In C
#ifndef __cplusplus #ifndef __cplusplus
typedef uint32_t bool; typedef unsigned char bool;
#endif #endif
// Globals // 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_hide_gui_property_offset = 0xec; // unsigned char / bool
static uint32_t Options_third_person_property_offset = 0xed; // 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_render_distance_property_offset = 0x10; // int32_t
static uint32_t Options_sound_property_offset = 0x4; // int32_t
// MouseBuildInput // 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); typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
static uint32_t Entity_die_vtable_offset = 0x130; 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 // Mob
typedef void (*Mob_actuallyHurt_t)(unsigned char *entity, int32_t damage); 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 uint32_t RakNetInstance_pingForHosts_vtable_offset = 0x14;
static void *RakNetInstance_pingForHosts_vtable_addr = (void *) 0x109afc; 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_peer_property_offset = 0x4; // RakNet::RakPeer *
static uint32_t RakNetInstance_pinging_for_hosts_property_offset = 0x24; // unsigned char
// RakNet::RakPeer // 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); 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; 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 // Method That Require C++ Types
#ifdef __cplusplus #ifdef __cplusplus
@ -550,6 +575,14 @@ static SelectWorldScreen_getUniqueLevelName_t SelectWorldScreen_getUniqueLevelNa
static SelectWorldScreen_getUniqueLevelName_t Touch_SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x3d82c; 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 // Common
typedef std::string (*Common_getGameVersionString_t)(std::string const& version_suffix); typedef std::string (*Common_getGameVersionString_t)(std::string const& version_suffix);