2.2.0
All checks were successful
minecraft-pi-reborn/pipeline/head This commit looks good

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

View File

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

View File

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

View File

@ -1 +1 @@
2.1.8
2.2.0

2
debian/client-arm vendored
View File

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

2
debian/client-arm64 vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

7
docs/SOUND.md Normal file
View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
## Mods
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c)
target_link_libraries(compat feature input chat sign media-layer-core home dl)
target_link_libraries(compat reborn media-layer-core)
add_library(readdir SHARED src/readdir/readdir.c)
@ -16,73 +16,80 @@ add_library(feature SHARED src/feature/feature.c)
target_link_libraries(feature reborn)
add_library(version SHARED src/version/version.cpp)
target_link_libraries(version reborn)
target_link_libraries(version reborn symbols)
add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c)
target_link_libraries(chat reborn symbols feature pthread)
if(MCPI_SERVER_MODE)
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp)
target_link_libraries(server reborn feature home compat version dl media-layer-core pthread)
target_link_libraries(server reborn symbols feature home compat version dl media-layer-core pthread)
else()
target_link_libraries(compat input sign chat home dl)
target_link_libraries(chat input)
add_library(multiplayer SHARED src/multiplayer/multiplayer.cpp)
target_link_libraries(multiplayer reborn home feature)
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)