diff --git a/CMakeLists.txt b/CMakeLists.txt index b301179..2ca206e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/Dockerfile b/Dockerfile index 51ff52f..96baa5f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 \ diff --git a/VERSION b/VERSION index ebf14b4..ccbccc3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.8 +2.2.0 diff --git a/debian/client-arm b/debian/client-arm index 392fc8f..7d98f96 100644 --- a/debian/client-arm +++ b/debian/client-arm @@ -4,4 +4,4 @@ Maintainer: TheBrokenRail 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 diff --git a/debian/client-arm64 b/debian/client-arm64 index 95ef9bb..d89a362 100644 --- a/debian/client-arm64 +++ b/debian/client-arm64 @@ -4,4 +4,4 @@ Maintainer: TheBrokenRail 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 diff --git a/debian/client-x86_64 b/debian/client-x86_64 index d10adf8..59d8eaf 100644 --- a/debian/client-x86_64 +++ b/debian/client-x86_64 @@ -4,4 +4,4 @@ Maintainer: TheBrokenRail 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 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4fd3fea..d88e083 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -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) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 640f566..cd80587 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -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 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3fc226b..fef2fc4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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 diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 4a001d2..1d63d43 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -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-_X.Y.Z~_ +minecraft-pi-reborn-_X.Y.Z_ ``` ### 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) diff --git a/docs/README.md b/docs/README.md index 92b055c..a62d74f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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) diff --git a/docs/SOUND.md b/docs/SOUND.md new file mode 100644 index 0000000..f438a1d --- /dev/null +++ b/docs/SOUND.md @@ -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. diff --git a/docs/TERMINOLOGY.md b/docs/TERMINOLOGY.md index c8274d5..cbfd0cb 100644 --- a/docs/TERMINOLOGY.md +++ b/docs/TERMINOLOGY.md @@ -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 | diff --git a/images/start.png b/images/start.png index 7c7cd97..189cbc7 100644 Binary files a/images/start.png and b/images/start.png differ diff --git a/launcher/client-data/opt/minecraft-pi-reborn-client/available-feature-flags b/launcher/client-data/opt/minecraft-pi-reborn-client/available-feature-flags index 440e76b..c961bf6 100644 --- a/launcher/client-data/opt/minecraft-pi-reborn-client/available-feature-flags +++ b/launcher/client-data/opt/minecraft-pi-reborn-client/available-feature-flags @@ -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 diff --git a/launcher/src/bootstrap.c b/launcher/src/bootstrap.c index 813c5ae..4f7f46f 100644 --- a/launcher/src/bootstrap.c +++ b/launcher/src/bootstrap.c @@ -8,7 +8,6 @@ #include #include -#define FORCE_PROC_FOR_ROOT_PATH #include #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 } diff --git a/libreborn/CMakeLists.txt b/libreborn/CMakeLists.txt index 3a2bbcd..8eea982 100644 --- a/libreborn/CMakeLists.txt +++ b/libreborn/CMakeLists.txt @@ -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() diff --git a/libreborn/include/libreborn/elf.h b/libreborn/include/libreborn/elf.h index e6a94af..1a3fd48 100644 --- a/libreborn/include/libreborn/elf.h +++ b/libreborn/include/libreborn/elf.h @@ -4,53 +4,46 @@ #include #include #include +#include #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); } diff --git a/libreborn/include/libreborn/exec.h b/libreborn/include/libreborn/exec.h index 76250b1..85628c0 100644 --- a/libreborn/include/libreborn/exec.h +++ b/libreborn/include/libreborn/exec.h @@ -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; } diff --git a/libreborn/include/libreborn/libreborn.h b/libreborn/include/libreborn/libreborn.h index 6852a8a..93771b2 100644 --- a/libreborn/include/libreborn/libreborn.h +++ b/libreborn/include/libreborn/libreborn.h @@ -10,7 +10,7 @@ extern "C" { #include "exec.h" #include "elf.h" -#ifdef __arm__ +#ifdef REBORN_HAS_COMPILED_CODE // Patching Functions diff --git a/libreborn/include/libreborn/log.h b/libreborn/include/libreborn/log.h index 7350d03..9333b21 100644 --- a/libreborn/include/libreborn/log.h +++ b/libreborn/include/libreborn/log.h @@ -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") diff --git a/libreborn/src/reborn.c b/libreborn/src/reborn.c index 9b2fa65..80efe15 100644 --- a/libreborn/src/reborn.c +++ b/libreborn/src/reborn.c @@ -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]" diff --git a/media-layer/core/CMakeLists.txt b/media-layer/core/CMakeLists.txt index bd70237..bd2f4e7 100644 --- a/media-layer/core/CMakeLists.txt +++ b/media-layer/core/CMakeLists.txt @@ -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() diff --git a/media-layer/core/src/audio/api.cpp b/media-layer/core/src/audio/api.cpp new file mode 100644 index 0000000..9d1f5db --- /dev/null +++ b/media-layer/core/src/audio/api.cpp @@ -0,0 +1,104 @@ +#include +#include + +#include + +#include +#include + +#include "file.h" +#include "engine.h" + +// Store Audio Sources +static std::vector &get_sources() { + static std::vector 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::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); + } +} diff --git a/media-layer/core/src/audio/engine.c b/media-layer/core/src/audio/engine.c new file mode 100644 index 0000000..18ee667 --- /dev/null +++ b/media-layer/core/src/audio/engine.c @@ -0,0 +1,85 @@ +#include +#include +#include + +#include + +#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"); + } +} diff --git a/media-layer/core/src/audio/engine.h b/media-layer/core/src/audio/engine.h new file mode 100644 index 0000000..69e70f0 --- /dev/null +++ b/media-layer/core/src/audio/engine.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#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 diff --git a/media-layer/core/src/audio/file.cpp b/media-layer/core/src/audio/file.cpp new file mode 100644 index 0000000..9bbba33 --- /dev/null +++ b/media-layer/core/src/audio/file.cpp @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "file.h" +#include "engine.h" + +// Load Symbol From ELF File +static void load_symbol(const char *source, const char *name, std::function 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 &get_buffers() { + static std::unordered_map 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(); +} diff --git a/media-layer/core/src/audio/file.h b/media-layer/core/src/audio/file.h new file mode 100644 index 0000000..f68f8cb --- /dev/null +++ b/media-layer/core/src/audio/file.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#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 diff --git a/media-layer/core/src/base.cpp b/media-layer/core/src/base.cpp index 9b17b1d..491d572 100644 --- a/media-layer/core/src/base.cpp +++ b/media-layer/core/src/base.cpp @@ -4,7 +4,7 @@ #include -#include +#include // SDL Is Replaced With GLFW diff --git a/media-layer/core/src/media.c b/media-layer/core/src/media.c index f23c821..e9898ea 100644 --- a/media-layer/core/src/media.c +++ b/media-layer/core/src/media.c @@ -9,10 +9,12 @@ #endif // #ifndef MCPI_HEADLESS_MODE #include -#include -#include +#include +#include -// 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 - glfwDestroyWindow(glfw_window); - glfwTerminate(); + // Terminate GLFW + glfwDestroyWindow(glfw_window); + glfwTerminate(); + + // Cleanup OpenAL + _media_audio_cleanup(); #endif // #ifndef MCPI_HEADLESS_MODE + + // Update State + is_running = 0; + } } // Store Cursor State diff --git a/media-layer/core/src/screenshot.c b/media-layer/core/src/screenshot.c index d388980..22c6c36 100644 --- a/media-layer/core/src/screenshot.c +++ b/media-layer/core/src/screenshot.c @@ -1,4 +1,4 @@ -// Screenshot Code Is Useless In Server Mode +// Screenshot Code Is Useless In Headless Mode #ifndef MCPI_HEADLESS_MODE #include @@ -14,7 +14,7 @@ #include #include -#include +#include // Ensure Screenshots Folder Exists static void ensure_screenshots_folder(char *screenshots) { diff --git a/media-layer/extras/src/SDL.c b/media-layer/extras/src/SDL.c index 8b30236..e7a6b4b 100644 --- a/media-layer/extras/src/SDL.c +++ b/media-layer/extras/src/SDL.c @@ -4,7 +4,7 @@ #include #include -#include +#include // SDL Stub void *SDL_SetVideoMode(__attribute__((unused)) int width, __attribute__((unused)) int height, __attribute__((unused)) int bpp, __attribute__((unused)) uint32_t flags) { diff --git a/media-layer/include/media-layer/audio.h b/media-layer/include/media-layer/audio.h new file mode 100644 index 0000000..264437e --- /dev/null +++ b/media-layer/include/media-layer/audio.h @@ -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 diff --git a/media-layer/include/libreborn/media-layer/core.h b/media-layer/include/media-layer/core.h similarity index 100% rename from media-layer/include/libreborn/media-layer/core.h rename to media-layer/include/media-layer/core.h diff --git a/media-layer/include/libreborn/media-layer/internal.h b/media-layer/include/media-layer/internal.h similarity index 100% rename from media-layer/include/libreborn/media-layer/internal.h rename to media-layer/include/media-layer/internal.h diff --git a/media-layer/proxy/src/common/common.c b/media-layer/proxy/src/common/common.c index 28b7176..2aca691 100644 --- a/media-layer/proxy/src/common/common.c +++ b/media-layer/proxy/src/common/common.c @@ -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) { diff --git a/media-layer/proxy/src/common/common.h b/media-layer/proxy/src/common/common.h index 31ffab0..97a30ed 100644 --- a/media-layer/proxy/src/common/common.h +++ b/media-layer/proxy/src/common/common.h @@ -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); diff --git a/media-layer/proxy/src/media-layer-core.c b/media-layer/proxy/src/media-layer-core.c index 73953a9..850466d 100644 --- a/media-layer/proxy/src/media-layer-core.c +++ b/media-layer/proxy/src/media-layer-core.c @@ -3,8 +3,9 @@ #include #include -#include -#include +#include +#include +#include #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 +} diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index d193e4c..7b3e4f2 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -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) + 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 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 symbols feature media-layer-core) + + add_library(sign SHARED src/sign/sign.cpp) + target_link_libraries(sign reborn symbols feature input) + + add_library(creative SHARED src/creative/creative.cpp) + target_link_libraries(creative reborn symbols feature) + + add_library(touch SHARED src/touch/touch.c) + target_link_libraries(touch reborn symbols feature) + + add_library(override SHARED src/override/override.c) + target_link_libraries(override reborn symbols dl home) + + add_library(textures SHARED src/textures/textures.cpp) + target_link_libraries(textures reborn symbols feature) + + add_library(atlas SHARED src/atlas/atlas.cpp) + target_link_libraries(atlas reborn symbols feature GLESv1_CM) endif() -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) - -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) - -add_library(sign SHARED src/sign/sign.cpp) -target_link_libraries(sign reborn feature input) +target_link_libraries(game-mode reborn symbols feature) add_library(death SHARED src/death/death.cpp) -target_link_libraries(death reborn feature) +target_link_libraries(death reborn symbols 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) -target_link_libraries(creative reborn feature) +target_link_libraries(misc 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) -target_link_libraries(touch reborn feature) - -add_library(override SHARED src/override/override.c) -target_link_libraries(override reborn dl home) - -add_library(textures SHARED src/textures/textures.cpp) -target_link_libraries(textures reborn feature) - -add_library(atlas SHARED src/atlas/atlas.cpp) -target_link_libraries(atlas reborn feature GLESv1_CM) - -add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c) -target_link_libraries(chat reborn feature input pthread) +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() diff --git a/mods/src/atlas/atlas.cpp b/mods/src/atlas/atlas.cpp index bd0b4c3..a9ffd3d 100644 --- a/mods/src/atlas/atlas.cpp +++ b/mods/src/atlas/atlas.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include "../feature/feature.h" #include "../init/init.h" diff --git a/mods/src/camera/camera.cpp b/mods/src/camera/camera.cpp index f4adb91..ba99952 100644 --- a/mods/src/camera/camera.cpp +++ b/mods/src/camera/camera.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include "../feature/feature.h" #include "../home/home.h" diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp index f23aacb..ed17e87 100644 --- a/mods/src/chat/chat.cpp +++ b/mods/src/chat/chat.cpp @@ -5,11 +5,13 @@ #include #include -#include +#include #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 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 } } diff --git a/mods/src/chat/chat.h b/mods/src/chat/chat.h index 0beccbf..07d4e9b 100644 --- a/mods/src/chat/chat.h +++ b/mods/src/chat/chat.h @@ -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 } diff --git a/mods/src/chat/ui.c b/mods/src/chat/ui.c index 6fea101..06187f7 100644 --- a/mods/src/chat/ui.c +++ b/mods/src/chat/ui.c @@ -1,3 +1,4 @@ +#ifndef MCPI_SERVER_MODE #include #include #include @@ -86,3 +87,4 @@ void chat_open() { pthread_create(&thread, NULL, chat_thread, NULL); } } +#endif // #ifndef MCPI_SERVER_MODE diff --git a/mods/src/compat/compat.c b/mods/src/compat/compat.c index 7d2a842..5c2e0e8 100644 --- a/mods/src/compat/compat.c +++ b/mods/src/compat/compat.c @@ -1,17 +1,19 @@ #include #include +#include "compat.h" +#include "../init/init.h" + +#ifndef MCPI_SERVER_MODE #include -#include +#include #include #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) { diff --git a/mods/src/compat/egl.c b/mods/src/compat/egl.c index 6cb5459..42fbf04 100644 --- a/mods/src/compat/egl.c +++ b/mods/src/compat/egl.c @@ -1,7 +1,7 @@ #include #include -#include +#include // 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) { diff --git a/mods/src/compat/x11.c b/mods/src/compat/x11.c index 9beeba4..27dbb73 100644 --- a/mods/src/compat/x11.c +++ b/mods/src/compat/x11.c @@ -1,7 +1,7 @@ #include #include -#include +#include // 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) { diff --git a/mods/src/creative/creative.cpp b/mods/src/creative/creative.cpp index 009f7ee..8f869ae 100644 --- a/mods/src/creative/creative.cpp +++ b/mods/src/creative/creative.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "../init/init.h" #include "../feature/feature.h" diff --git a/mods/src/death/death.cpp b/mods/src/death/death.cpp index 70d603e..5a2e5a4 100644 --- a/mods/src/death/death.cpp +++ b/mods/src/death/death.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include "../init/init.h" #include "../feature/feature.h" diff --git a/mods/src/game-mode/game-mode.c b/mods/src/game-mode/game-mode.c index 833c9ad..9d0b3ce 100644 --- a/mods/src/game-mode/game-mode.c +++ b/mods/src/game-mode/game-mode.c @@ -3,7 +3,7 @@ #include "../feature/feature.h" #include -#include +#include static int is_survival = -1; diff --git a/mods/src/game-mode/game-mode.cpp b/mods/src/game-mode/game-mode.cpp index 1d39e34..0fa98a9 100644 --- a/mods/src/game-mode/game-mode.cpp +++ b/mods/src/game-mode/game-mode.cpp @@ -2,7 +2,7 @@ #include "game-mode.h" -#include +#include // Get Minecraft From Screen static unsigned char *get_minecraft_from_screen(unsigned char *screen) { diff --git a/mods/src/home/home.c b/mods/src/home/home.c index 7105295..5edbafb 100644 --- a/mods/src/home/home.c +++ b/mods/src/home/home.c @@ -1,5 +1,5 @@ #include -#include +#include #include "home.h" #include "../init/init.h" diff --git a/mods/src/init/init.c b/mods/src/init/init.c index be4e30a..a3117c3 100644 --- a/mods/src/init/init.c +++ b/mods/src/init/init.c @@ -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(); diff --git a/mods/src/init/init.h b/mods/src/init/init.h index 062c80f..226e143 100644 --- a/mods/src/init/init.h +++ b/mods/src/init/init.h @@ -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(); diff --git a/mods/src/input/attack.c b/mods/src/input/attack.c index 3060ded..c23c538 100644 --- a/mods/src/input/attack.c +++ b/mods/src/input/attack.c @@ -1,5 +1,5 @@ #include -#include +#include #include "../feature/feature.h" #include "input.h" diff --git a/mods/src/input/bow.c b/mods/src/input/bow.c index deebbdf..80a8f2e 100644 --- a/mods/src/input/bow.c +++ b/mods/src/input/bow.c @@ -1,5 +1,5 @@ #include -#include +#include #include "../feature/feature.h" #include "input.h" diff --git a/mods/src/input/drop.cpp b/mods/src/input/drop.cpp index 411fb42..6803722 100644 --- a/mods/src/input/drop.cpp +++ b/mods/src/input/drop.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "input.h" #include "../feature/feature.h" diff --git a/mods/src/input/input.cpp b/mods/src/input/input.cpp index 4346ca0..d83b4ca 100644 --- a/mods/src/input/input.cpp +++ b/mods/src/input/input.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include "../feature/feature.h" #include "../init/init.h" diff --git a/mods/src/input/misc.c b/mods/src/input/misc.c index 50daf8d..da0a18d 100644 --- a/mods/src/input/misc.c +++ b/mods/src/input/misc.c @@ -1,5 +1,5 @@ #include -#include +#include #include "input.h" #include "../feature/feature.h" diff --git a/mods/src/input/toggle.c b/mods/src/input/toggle.c index 8595a94..2b8f7e6 100644 --- a/mods/src/input/toggle.c +++ b/mods/src/input/toggle.c @@ -1,5 +1,5 @@ #include -#include +#include #include "input.h" #include "../feature/feature.h" diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c index 920b311..3a936cc 100644 --- a/mods/src/misc/misc.c +++ b/mods/src/misc/misc.c @@ -3,7 +3,7 @@ #include #include -#include +#include #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(); } diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp index 3a1daee..7291a07 100644 --- a/mods/src/misc/misc.cpp +++ b/mods/src/misc/misc.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include "../feature/feature.h" #include "misc.h" diff --git a/mods/src/multiplayer/multiplayer.cpp b/mods/src/multiplayer/multiplayer.cpp index 3e6a748..2f2e5f2 100644 --- a/mods/src/multiplayer/multiplayer.cpp +++ b/mods/src/multiplayer/multiplayer.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include "../home/home.h" #include "../init/init.h" @@ -110,8 +110,9 @@ static void iterate_servers(std::function 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 diff --git a/mods/src/options/options.c b/mods/src/options/options.c index 852d96c..6c108e3 100644 --- a/mods/src/options/options.c +++ b/mods/src/options/options.c @@ -1,7 +1,7 @@ #include #include -#include +#include #include "../feature/feature.h" #include "../init/init.h" diff --git a/mods/src/override/override.c b/mods/src/override/override.c index c1301a7..f7930d6 100644 --- a/mods/src/override/override.c +++ b/mods/src/override/override.c @@ -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); diff --git a/mods/src/override/override.h b/mods/src/override/override.h new file mode 100644 index 0000000..331ec46 --- /dev/null +++ b/mods/src/override/override.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +char *override_get_path(const char *filename); + +#ifdef __cplusplus +} +#endif diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index ae187a4..a748c57 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -25,7 +25,7 @@ #include "../compat/compat.h" #include "../version/version.h" -#include +#include // --only-generate: Ony Generate World And Then Exit static bool only_generate = false; diff --git a/mods/src/sign/sign.cpp b/mods/src/sign/sign.cpp index 7fc5b39..23ce255 100644 --- a/mods/src/sign/sign.cpp +++ b/mods/src/sign/sign.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include "../init/init.h" #include "../feature/feature.h" diff --git a/mods/src/sound/README.md b/mods/src/sound/README.md new file mode 100644 index 0000000..7c8d082 --- /dev/null +++ b/mods/src/sound/README.md @@ -0,0 +1,2 @@ +# ``sound`` Mod +This mod implements a sound engine. diff --git a/mods/src/sound/repository.cpp b/mods/src/sound/repository.cpp new file mode 100644 index 0000000..55f1c7f --- /dev/null +++ b/mods/src/sound/repository.cpp @@ -0,0 +1,335 @@ +#include +#include +#include +#include +#include + +#include + +#include "sound.h" + +// Sound Repository Extracted From MCPE 0.6.1 APK +static std::unordered_map> 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 &options = repository[sound]; + return options[rand() % options.size()]; + } else { + // Invalid Sound + ERR("Invalid Sound: %s", sound.c_str()); + } +} diff --git a/mods/src/sound/sound.cpp b/mods/src/sound/sound.cpp new file mode 100644 index 0000000..3060e0b --- /dev/null +++ b/mods/src/sound/sound.cpp @@ -0,0 +1,119 @@ +#include + +#include +#include +#include + +#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); + } +} diff --git a/mods/src/sound/sound.h b/mods/src/sound/sound.h new file mode 100644 index 0000000..f20c1bf --- /dev/null +++ b/mods/src/sound/sound.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +__attribute__((visibility("internal"))) std::string _sound_pick(std::string sound); diff --git a/mods/src/textures/textures.cpp b/mods/src/textures/textures.cpp index 897a7e4..450e2e9 100644 --- a/mods/src/textures/textures.cpp +++ b/mods/src/textures/textures.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "../feature/feature.h" #include "../init/init.h" diff --git a/mods/src/touch/touch.c b/mods/src/touch/touch.c index bc136df..dae8d7d 100644 --- a/mods/src/touch/touch.c +++ b/mods/src/touch/touch.c @@ -3,7 +3,7 @@ #include "../feature/feature.h" #include "../init/init.h" -#include +#include // Enable Touch GUI static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) { diff --git a/mods/src/version/version.cpp b/mods/src/version/version.cpp index ac12b27..4ed14e3 100644 --- a/mods/src/version/version.cpp +++ b/mods/src/version/version.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "version.h" #include "../init/init.h" diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh index 958842f..003b86f 100755 --- a/scripts/install-dependencies.sh +++ b/scripts/install-dependencies.sh @@ -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 diff --git a/scripts/package.sh b/scripts/package.sh index 556e2d2..8541c0a 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -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}" diff --git a/symbols/CMakeLists.txt b/symbols/CMakeLists.txt new file mode 100644 index 0000000..cfa9dc5 --- /dev/null +++ b/symbols/CMakeLists.txt @@ -0,0 +1,4 @@ +project(symbols) + +add_library(symbols INTERFACE) +target_include_directories(symbols INTERFACE include) diff --git a/libreborn/include/libreborn/minecraft.h b/symbols/include/symbols/minecraft.h similarity index 93% rename from libreborn/include/libreborn/minecraft.h rename to symbols/include/symbols/minecraft.h index 4163a75..5e27d2d 100644 --- a/libreborn/include/libreborn/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -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);