Compare commits

...

84 Commits

Author SHA1 Message Date
threeoh6000 e2518e734c Fix Arch documentation
pacman -Sy is a bad command and should never be ran as it syncs the repositories but doesn't actually  upgrade the software on the system which could royally screw up an unknowing Arch noob's system.
2022-08-27 15:45:54 +00:00
TheBrokenRail 35cafec1ee Tweaks 2022-08-10 17:21:38 -04:00
TheBrokenRail 4ab6b7aed1 New GCC Is *Still* Broken 2022-08-09 18:48:30 -04:00
TheBrokenRail edd346dd66 Stop Fighting CMake 2022-08-09 18:39:34 -04:00
TheBrokenRail 0d9f498aa7 Fix ZLib In "git status" 2022-08-07 14:14:00 -04:00
TheBrokenRail d761ad8614 Better CMake 2022-08-05 22:07:19 -04:00
TheBrokenRail 4977898bcd Use New Repos 2022-08-05 20:37:11 -04:00
TheBrokenRail 513628d91f More CMake Tweaks 2022-08-05 20:08:13 -04:00
TheBrokenRail 9a521ebca2 Remove Warnings From SDK 2022-08-03 13:08:20 -04:00
TheBrokenRail deae36ed94 Better SDK Setup 2022-08-01 19:56:35 -04:00
TheBrokenRail 00d6ee4f9a 2.4.3 2022-08-01 18:41:08 -04:00
TheBrokenRail 8dd562a20f Fix Signs With CP-437 2022-07-30 23:52:50 -04:00
TheBrokenRail c11c7203ef 2.4.2 2022-07-29 22:13:03 -04:00
TheBrokenRail 379da809cd 2.4.1 2022-07-20 02:58:14 -04:00
TheBrokenRail 96baf9627a Actually Fix Screen Rendering When GUI is Hidden 2022-07-16 00:02:51 -04:00
TheBrokenRail 279b101e46 Hotfix #2 2022-07-15 23:20:31 -04:00
TheBrokenRail b190851d36 Hotfix 2022-07-15 22:08:12 -04:00
TheBrokenRail c3c7d22006 Actually Fix CI 2022-07-15 20:09:51 -04:00
TheBrokenRail 3abbb0cb16 Improve Server Dockerfile 2022-07-15 19:54:58 -04:00
TheBrokenRail dda511f8ff Fix CI (Again) 2022-07-15 19:43:26 -04:00
TheBrokenRail 0ccc1ba6e8 Fix CI 2022-07-15 19:05:59 -04:00
TheBrokenRail 9d3a0964b0 Fix CI Stage Name 2022-07-15 17:54:43 -04:00
TheBrokenRail ed9bef8492 2.4.0 2022-07-15 17:27:21 -04:00
TheBrokenRail c4e26c5be2 Fix Classic HUD 2022-07-15 01:37:12 -04:00
TheBrokenRail 0c82db4116 Diable Broken Touchscreen-Specific Block Outline Behavior 2022-07-15 01:28:51 -04:00
TheBrokenRail ce168c1c16 Add Translucent Toolbar 2022-07-14 19:52:51 -04:00
TheBrokenRail 93eb7807aa Fix Attacking 2022-07-14 18:23:40 -04:00
TheBrokenRail 12074e15d9 Fix Sound 2022-07-14 18:11:44 -04:00
TheBrokenRail 010aaa89e3 Embed Feature Flag Data 2022-07-13 23:35:05 -04:00
TheBrokenRail 0e32fd36c8 Store Temporary Logs In Own Directory 2022-07-13 23:05:59 -04:00
TheBrokenRail 6c89e64f8b Add Classic HUD 2022-07-13 22:11:46 -04:00
TheBrokenRail 9fe6a2fb39 Remove Superfluous Mutexes 2022-07-13 19:32:08 -04:00
TheBrokenRail c87a6fa3c0 Improve Proxy Client 2022-07-13 17:02:18 -04:00
TheBrokenRail 69d3832815 Move Screenshot Code To ARM 2022-07-13 16:46:33 -04:00
TheBrokenRail 67002006f3 Vendor PatchELF 2022-07-13 11:58:35 -04:00
TheBrokenRail eb96d80e5a CMake Restructure 2022-07-11 23:51:27 -04:00
TheBrokenRail 968001897d Build Fixes + Don't Force EGL 2022-07-11 20:47:57 -04:00
TheBrokenRail 68519f06fd Add Buckets 2022-07-10 10:37:19 -04:00
TheBrokenRail b3b935dd1d Logging Changes 2022-07-08 22:40:56 -04:00
TheBrokenRail 006243d02f OpenAL Fixes 2022-07-08 15:00:01 -04:00
TheBrokenRail 3c1bce876c Run Benchmark During CI Test 2022-07-08 13:57:48 -04:00
TheBrokenRail 484d3e7f90 More Miscellaneous Fixes + Fixed GLES v1.1 Support 2022-07-08 00:25:01 -04:00
TheBrokenRail 23df63abb7 CMake Cleanup 2022-07-07 18:55:43 -04:00
TheBrokenRail 126c3d618d No More APT 2022-07-07 18:54:11 -04:00
TheBrokenRail 3937f88084 More Fixes 2022-07-07 00:37:53 -04:00
TheBrokenRail 4bd2fecfa2 Better package.sh 2022-07-04 16:51:56 -04:00
TheBrokenRail b539491713 Treat AppImages As Self-Mounting Tarballs 2022-07-04 16:44:00 -04:00
TheBrokenRail ea4c5c77a1 Cmake Refactor 2022-07-02 18:14:23 -04:00
TheBrokenRail e506dbb1bb GL Fixes 2022-06-30 19:53:32 -04:00
TheBrokenRail 699d83c61b Recipes API 2022-06-27 14:47:55 -04:00
TheBrokenRail 329f92c0a4 Fix Weird Shading 2022-06-26 22:01:31 -04:00
TheBrokenRail bfa0567ac9 Better Examples 2022-06-26 21:17:52 -04:00
TheBrokenRail a94708a1ae More Reliable Jenkins 2022-06-25 23:40:24 -04:00
TheBrokenRail 905a569c09 Better Flathub Badge 2022-06-25 23:38:29 -04:00
TheBrokenRail 53f602403a Cache Blacklist/Whitelist 2022-06-25 23:32:31 -04:00
TheBrokenRail 2f64552926 Fix SDK Bugs 2022-06-25 23:03:46 -04:00
TheBrokenRail 2b920f50ba Improve Example Mod README 2022-06-25 17:49:09 -04:00
TheBrokenRail d859a16b5a Initial SDK Support 2022-06-25 17:30:08 -04:00
TheBrokenRail 78e17d8c18 Block Running As Root 2022-06-24 20:37:52 -04:00
TheBrokenRail 0e7a108a0a Improve Build 2022-06-13 22:53:43 -04:00
TheBrokenRail ca21877000 Ditch FreeImage 2022-06-13 20:49:09 -04:00
TheBrokenRail f1ec29ec86 Build Tweak 2022-06-12 16:23:32 -04:00
TheBrokenRail 13ac816baa Fix Invalid AppStream XML 2022-06-10 23:49:15 -04:00
TheBrokenRail 6ba86b9193 Tiny Docker Fix 2022-06-10 22:02:43 -04:00
TheBrokenRail 49f8da2a80 Fix Build 2022-06-10 21:59:57 -04:00
TheBrokenRail e8faee62fa Improve AppStream 2022-06-09 23:23:37 -04:00
TheBrokenRail a8ff58f0c4 Update Dependency Installation 2022-06-09 23:10:29 -04:00
TheBrokenRail daccf65361 Improve Metadata 2022-06-09 21:31:40 -04:00
TheBrokenRail 3d508d7609 2.3.13 2022-06-05 16:14:03 -04:00
TheBrokenRail 0061edb3b2 2.3.12 2022-06-04 14:36:47 -04:00
TheBrokenRail baeeceeaac Slightly Faster 2022-06-04 14:34:15 -04:00
TheBrokenRail 211bf265ff Optimizations & Fixes 2022-06-03 22:25:22 -04:00
TheBrokenRail 0dd0706f52 2.3.11 2022-05-29 22:54:57 -04:00
TheBrokenRail 1743626113 Sweeping Media Layer Changes (GL ES 2.0 Support) 2022-05-29 18:44:27 -04:00
TheBrokenRail 4ed11b67e7 Add Front-Facing View 2022-05-17 18:31:25 -04:00
TheBrokenRail 365e238c29 Small Fix 2022-05-16 18:56:19 -04:00
TheBrokenRail 36c4ed7e4d Fix Stupid Mistake 2022-05-15 15:16:45 -04:00
TheBrokenRail cf1faf4835 Better Exit Code Messages 2022-05-15 13:51:28 -04:00
TheBrokenRail cb4560a602 Don't Require MCPI_DEBUG For Command Errors 2022-05-15 00:53:46 -04:00
TheBrokenRail b3a96dc3e2 2.3.10 2022-05-14 00:16:25 -04:00
TheBrokenRail be300a2809 Fix Zenity On Wayland 2022-05-13 23:27:06 -04:00
TheBrokenRail 77d7b82a14 Add Crash Report Dialog 2022-05-13 22:36:12 -04:00
TheBrokenRail b59c580f6a Fix Build On Ubuntu 22.04 & Bug Fixes 2022-05-11 18:24:03 -04:00
TheBrokenRail 524a390921 Use Debian Sid As AppImage And ARMHF Sysroot Base 2022-05-04 20:47:15 -04:00
188 changed files with 5734 additions and 2192 deletions

23
.gitignore vendored
View File

@ -1,11 +1,14 @@
out
debian/tmp
.vscode
build
CMakeLists.txt.user
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
AppImageBuilder.yml
appimage-builder-cache
appimage-build
AppDir
*.zsync
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*

12
.gitmodules vendored
View File

@ -1,12 +1,16 @@
[submodule "dependencies/libpng/src"]
path = dependencies/libpng/src
url = https://github.com/glennrp/libpng.git
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/libpng.git
[submodule "dependencies/zlib/src"]
path = dependencies/zlib/src
path = dependencies/libpng/zlib/src
url = https://github.com/madler/zlib.git
ignore = dirty
[submodule "dependencies/glfw/src"]
path = dependencies/glfw/src
path = media-layer/core/dependencies/glfw/src
url = https://github.com/glfw/glfw.git
[submodule "dependencies/zenity/src"]
path = dependencies/zenity/src
url = https://gitea.thebrokenrail.com/TheBrokenRail/zenity.git
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git
[submodule "launcher/dependencies/patchelf/src"]
path = launcher/dependencies/patchelf/src
url = https://github.com/NixOS/patchelf.git

View File

@ -1,103 +1,166 @@
cmake_minimum_required(VERSION 3.13.0)
cmake_minimum_required(VERSION 3.16.0)
# Specify Options
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" FALSE)
option(MCPI_SERVER_MODE "Server Mode" FALSE)
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
set(MCPI_BUILD_MODE "both" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code; \"both\" = Build All Code As ARM")
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
option(MCPI_OPEN_SOURCE_ONLY "Only Install Open-Source Code (Will Result In Broken Install)" FALSE)
option(MCPI_IS_APPIMAGE_BUILD "AppImage Build" FALSE)
# Configure Build Mode
# Build Mode
set(MCPI_BUILD_MODE "native" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code")
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "arm" "native")
if(MCPI_BUILD_MODE STREQUAL "arm")
set(USE_ARM32_TOOLCHAIN TRUE)
set(BUILD_ARM_COMPONENTS TRUE)
set(BUILD_NATIVE_COMPONENTS FALSE)
elseif(MCPI_BUILD_MODE STREQUAL "native")
set(USE_ARM32_TOOLCHAIN FALSE)
set(BUILD_ARM_COMPONENTS FALSE)
set(BUILD_NATIVE_COMPONENTS TRUE)
elseif(MCPI_BUILD_MODE STREQUAL "both")
set(USE_ARM32_TOOLCHAIN TRUE)
set(BUILD_ARM_COMPONENTS TRUE)
set(BUILD_NATIVE_COMPONENTS TRUE)
else()
message(FATAL_ERROR "Invalid Mode")
endif()
# Utility Functions
include(cmake/util.cmake)
# Specify Options
option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE)
option(MCPI_OPEN_SOURCE_ONLY "Only Install Open-Source Code (Will Result In Broken Install)" FALSE)
option(MCPI_IS_APPIMAGE_BUILD "AppImage Build" FALSE)
# Server/Headless Builds
option(MCPI_SERVER_MODE "Server Mode" FALSE)
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
# Media Layer
if(MCPI_HEADLESS_MODE)
set(DEFAULT_USE_MEDIA_LAYER_PROXY FALSE)
else()
set(DEFAULT_USE_MEDIA_LAYER_PROXY ${MCPI_IS_MIXED_BUILD})
endif()
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" ${DEFAULT_USE_MEDIA_LAYER_PROXY})
if(NOT MCPI_HEADLESS_MODE)
option(MCPI_USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE)
endif()
# App ID
set(DEFAULT_APP_ID "com.thebrokenrail.MCPIReborn")
if(MCPI_SERVER_MODE)
string(APPEND DEFAULT_APP_ID "Server")
else()
string(APPEND DEFAULT_APP_ID "Client")
endif()
set(MCPI_APP_ID "${DEFAULT_APP_ID}" CACHE STRING "App ID")
# App Title
set(DEFAULT_APP_TITLE "Minecraft: Pi Edition: Reborn")
if(MCPI_SERVER_MODE)
string(APPEND DEFAULT_APP_TITLE " (Server)")
else()
string(APPEND DEFAULT_APP_TITLE " (Client)")
endif()
set(MCPI_APP_TITLE "${DEFAULT_APP_TITLE}" CACHE STRING "App Title")
# Specify Variant Name
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
if(MCPI_SERVER_MODE)
set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-server")
string(APPEND MCPI_VARIANT_NAME "-server")
else()
set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-client")
string(APPEND MCPI_VARIANT_NAME "-client")
endif()
# Specify Installation Paths
set(MCPI_INSTALL_DIR "lib/${MCPI_VARIANT_NAME}")
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
set(MCPI_BIN_DIR "${MCPI_INSTALL_DIR}/bin")
set(MCPI_LEGAL_DIR "${MCPI_INSTALL_DIR}/legal") # For Software Licenses
set(MCPI_SDK_DIR "${MCPI_INSTALL_DIR}/sdk")
set(MCPI_SDK_LIB_DIR "${MCPI_SDK_DIR}/lib")
set(MCPI_SDK_INCLUDE_DIR "${MCPI_SDK_DIR}/include")
# Library Directory
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
if(BUILD_ARM_COMPONENTS)
string(APPEND MCPI_LIB_DIR "/arm")
elseif(BUILD_NATIVE_COMPONENTS)
string(APPEND MCPI_LIB_DIR "/native")
endif()
# Share Directory
set(MCPI_SHARE_DIR "share")
if(MCPI_IS_APPIMAGE_BUILD)
string(PREPEND MCPI_SHARE_DIR "usr/")
endif()
# Build Mode
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
# Prebuilt ARMHF Toolchain
option(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN "Whether To Use A Prebuilt ARMHF Toolchain For Building ARM Components" ${MCPI_IS_MIXED_BUILD})
if(BUILD_ARM_COMPONENTS AND MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
include(cmake/prebuilt-armhf-toolchain.cmake)
endif()
# Start Project
project(minecraft-pi-reborn)
# Require ARM Compilation
if(USE_ARM32_TOOLCHAIN AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
# Utility Functions
include(cmake/util.cmake)
# Sanity Checks
set(IS_ARM_TARGETING FALSE)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(IS_ARM_TARGETING TRUE)
endif()
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING AND NOT MCPI_IS_MIXED_BUILD)
message(FATAL_ERROR "Project is configured as a mixed-buld, but MCPI_IS_MIXED_BUILD is disabled.")
endif()
if(BUILD_ARM_COMPONENTS AND NOT IS_ARM_TARGETING)
message(FATAL_ERROR "ARM-Targeting Compiler Required")
endif()
# Specify Default Installation Prefix
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "" FORCE)
set(DEFAULT_PREFIX "/usr")
if(MCPI_IS_APPIMAGE_BUILD)
set(DEFAULT_PREFIX "/")
endif()
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
endif()
# Optimizations
if(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-O3)
else()
add_compile_options(-g)
endif()
# Required Compile Flags
string(CONCAT COMPILE_FLAGS_SETUP
# Optimizations
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n"
" add_compile_options(-O3 -s)\n"
"else()\n"
" add_compile_options(-g)\n"
"endif()\n"
# Use LLD When Using Clang
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_link_options("-fuse-ld=lld")
endif()
# PIC
"set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)\n"
# PIC
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
# Warnings
"add_link_options(-Wl,--no-undefined)\n"
# C Standard
"add_definitions(-D_GNU_SOURCE)\n"
"set(CMAKE_C_STANDARD 99)\n"
"set(CMAKE_CXX_STANDARD 11)\n"
# Skip RPath
"set(CMAKE_SKIP_BUILD_RPATH TRUE)"
)
cmake_language(EVAL CODE "${COMPILE_FLAGS_SETUP}")
# Fast Math
add_compile_options(-ffast-math)
# Buld Dependencies
add_subdirectory(dependencies)
# Warnings
add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
add_link_options(-Wl,--no-undefined)
add_definitions(-D_GNU_SOURCE)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
if(CMAKE_C_COMPILER_ID STREQUAL \"GNU\")
# Prevents False Positives
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 10.0)
add_compile_options(-Wno-stringop-overflow)
endif()
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 11.0)
add_compile_options(-Wno-array-bounds -Wno-stringop-overread)
endif()
endif()
# Specify Constants
if(MCPI_SERVER_MODE)
add_definitions(-DMCPI_SERVER_MODE)
endif()
if(MCPI_HEADLESS_MODE)
add_definitions(-DMCPI_HEADLESS_MODE)
endif()
if(MCPI_IS_APPIMAGE_BUILD)
add_definitions(-DMCPI_IS_APPIMAGE_BUILD)
endif()
# Buld Dependencies
add_subdirectory(dependencies)
# Version
set_property(
@ -105,8 +168,8 @@ set_property(
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS VERSION
)
file(STRINGS VERSION VERSION)
add_definitions(-DVERSION="${VERSION}")
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION)
file(TIMESTAMP "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION_DATE "%Y-%m-%d" UTC)
# Build libreborn
add_subdirectory(libreborn)
@ -133,3 +196,17 @@ endif()
if(BUILD_NATIVE_COMPONENTS)
add_subdirectory(images)
endif()
# Install SDK
if(BUILD_ARM_COMPONENTS)
install(EXPORT sdk DESTINATION "${MCPI_SDK_DIR}" FILE "sdk-targets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake"
# Compile Flags
"${COMPILE_FLAGS_SETUP}\n"
# Log
"message(STATUS \"Using Reborn SDK v${MCPI_VERSION}\")\n"
# Include Targets
"include(\"\${CMAKE_CURRENT_LIST_DIR}/sdk-targets.cmake\")\n"
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake" DESTINATION "${MCPI_SDK_DIR}")
endif()

View File

@ -3,24 +3,12 @@ FROM debian:bullseye-slim
# Install
RUN \
apt-get update && \
apt-get install -y tini sed && \
apt-get install -y tini qemu-user && \
apt-get --fix-broken install -y && \
rm -rf /var/lib/apt/lists/*
# Copy AppImage
RUN mkdir /app
ADD ./out/minecraft-pi-reborn-server-*-amd64.AppImage /app
# Extract AppImage
WORKDIR /app
RUN \
sed -i '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' ./*.AppImage && \
./*.AppImage --appimage-extract && \
rm -f ./*.AppImage
# Setup AppImage
ENV OWD=/data
ENV APPDIR=/app/squashfs-root
# Copy
ADD ./out/server-amd64 /app
# Setup Working Directory
RUN mkdir /data
@ -28,4 +16,4 @@ WORKDIR /data
# Setup Entrypoint
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/app/squashfs-root/AppRun"]
CMD ["/app/usr/bin/minecraft-pi-reborn-server"]

6
Jenkinsfile vendored
View File

@ -1,11 +1,11 @@
pipeline {
agent none
stages {
stage('Debian Bullseye') {
stage('Debian Buster') {
agent {
dockerfile {
filename 'scripts/ci/Dockerfile'
args '-v /var/run/docker.sock:/var/run/docker.sock'
args '-v /var/run/docker.sock:/var/run/docker.sock --network host'
}
}
stages {
@ -22,6 +22,8 @@ pipeline {
stage('Publish') {
steps {
sh 'apt-get update && apt-get install -y docker.io'
sh 'rm -rf ./out/server-amd64'
sh './scripts/build.sh server amd64'
sh 'docker build --no-cache --tag thebrokenrail/minecraft-pi-reborn-server .'
withCredentials([usernamePassword(credentialsId: 'docker_hub_login', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
sh 'docker login -u "${DOCKER_HUB_USERNAME}" -p "${DOCKER_HUB_PASSWORD}"'

View File

@ -1 +1 @@
2.3.9
2.4.3

View File

@ -1,11 +0,0 @@
# Setup Toolchain
macro(setup_toolchain target)
# Use ARM Cross-Compiler
set(CMAKE_C_COMPILER "${target}-gcc")
set(CMAKE_CXX_COMPILER "${target}-g++")
set(CMAKE_FIND_ROOT_PATH "/usr/${target}" "/usr/lib/${target}")
# Extra
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# pkg-config
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/${target}/pkgconfig:/usr/${target}/lib/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig")
endmacro()

View File

@ -0,0 +1,12 @@
# Read Hex Data
file(READ "${EMBED_IN}" data HEX)
# Convert Hex Data For C Compatibility
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${data}")
# Get C Name
get_filename_component(name "${EMBED_IN}" NAME)
string(MAKE_C_IDENTIFIER "${name}" name)
# Write Data
file(WRITE "${EMBED_OUT}" "#include <stddef.h>\nconst unsigned char ${name}[] = {${data}};\nconst size_t ${name}_len = sizeof (${name});\n")

View File

@ -0,0 +1,77 @@
# Pick URL
execute_process(COMMAND uname -m OUTPUT_VARIABLE arch OUTPUT_STRIP_TRAILING_WHITESPACE)
if(arch STREQUAL "x86_64")
set(toolchain_url "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz")
set(toolchain_sha256 "aa074fa8371a4f73fecbd16bd62c8b1945f23289e26414794f130d6ccdf8e39c")
elseif(arch STREQUAL "aarch64" OR arch STREQUAL "armv8b" OR arch STREQUAL "armv8l")
set(toolchain_url "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-aarch64-arm-none-linux-gnueabihf.tar.xz")
set(toolchain_sha256 "fccd7af76988da2b077f939eb2a78baa9935810918d2bf3f837bc74f52efa825")
else()
message(FATAL_ERROR "Unable To Download Prebuilt ARMHF Toolchain")
endif()
# Download If Needed
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
FetchContent_Declare(
prebuilt-armhf-toolchain
URL "${toolchain_url}"
URL_HASH "SHA256=${toolchain_sha256}"
)
FetchContent_MakeAvailable(prebuilt-armhf-toolchain)
set(FETCHCONTENT_QUIET TRUE)
set(toolchain_dir "${prebuilt-armhf-toolchain_SOURCE_DIR}")
# Force Toolchain
file(WRITE "${toolchain_dir}/toolchain.cmake"
"set(CMAKE_C_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-gcc\")\n"
"set(CMAKE_CXX_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-g++\")\n"
"set(CMAKE_SYSTEM_NAME \"Linux\")\n"
"set(CMAKE_SYSTEM_PROCESSOR \"arm\")\n"
)
set(CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" CACHE STRING "" FORCE)
# Build Sysroot
set(sysroot_dir "${CMAKE_CURRENT_BINARY_DIR}/bundled-armhf-sysroot")
if("${toolchain_dir}/bin/arm-none-linux-gnueabihf-gcc" IS_NEWER_THAN "${sysroot_dir}")
# Create Directory
file(REMOVE_RECURSE "${sysroot_dir}")
file(MAKE_DIRECTORY "${sysroot_dir}")
# Copy Files From Toolchain
file(
COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/"
DESTINATION "${sysroot_dir}"
USE_SOURCE_PERMISSIONS
FILES_MATCHING
PATTERN "*.so*"
)
# Delete Unneeded Files
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit")
# Strip Files
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*")
foreach(file IN LISTS files)
execute_process(COMMAND "${toolchain_dir}/bin/arm-none-linux-gnueabihf-strip" "${file}" RESULT_VARIABLE ret)
# Check Result
if(NOT ret EQUAL 0)
# Delete Invalid Files
file(REMOVE "${file}")
endif()
endforeach()
# Setup gconv
file(
COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/usr/lib/gconv/gconv-modules"
DESTINATION "${sysroot_dir}/usr/lib/gconv"
USE_SOURCE_PERMISSIONS
)
endif()
# Install Sysroot (Skipping Empty Directories)
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE RELATIVE "${sysroot_dir}" "${sysroot_dir}/*")
foreach(file IN LISTS files)
get_filename_component(parent "${file}" DIRECTORY)
install(PROGRAMS "${sysroot_dir}/${file}" DESTINATION "${MCPI_INSTALL_DIR}/sysroot/${parent}")
endforeach()

View File

@ -0,0 +1,38 @@
# Setup Toolchain
macro(setup_toolchain target)
# Target Variants
set(target_variants "${target}")
macro(add_target_variant value)
string(REPLACE "-linux" "-${value}-linux" target_variant "${target}")
list(APPEND target_variants "${target_variant}")
endmacro()
add_target_variant(unknown)
add_target_variant(none)
add_target_variant(pc)
# Find Compiler
macro(find_compiler output name)
set(possible_names "")
foreach(possible_target IN LISTS target_variants)
list(APPEND possible_names "${possible_target}-${name}")
endforeach()
find_program(
"${output}"
NAMES ${possible_names}
NO_CACHE
)
if("${${output}}" STREQUAL "${output}-NOTFOUND")
message(FATAL_ERROR "Unable To Find ${name}")
endif()
endmacro()
find_compiler(CMAKE_C_COMPILER "gcc")
find_compiler(CMAKE_CXX_COMPILER "g++")
# Extra
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Custom Search Paths
if(NOT DEFINED ENV{MCPI_TOOLCHAIN_USE_DEFAULT_SEARCH_PATHS})
# Find Root
set(CMAKE_FIND_ROOT_PATH "/usr/${target}" "/usr/lib/${target}" "/usr")
# pkg-config
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/${target}/pkgconfig:/usr/${target}/lib/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig")
endif()
endmacro()

View File

@ -1,19 +1,26 @@
# Symlink Function
function(install_symlink target link)
install(CODE "\
# Prepare\n \
set(file \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${link}\")\n \
\
# Create Directory\n \
get_filename_component(dir \"\${file}\" DIRECTORY)\n \
file(MAKE_DIRECTORY \${dir})\n \
\
# Create Symlink\n \
if(NOT EXISTS \"\${file}\")\n \
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink ${target} \"\${file}\")\n \
message(\"-- Installing: \${file}\")\n \
else()\n \
message(\"-- Up-to-date: \${file}\")\n \
endif() \
")
get_filename_component(parent "${link}" DIRECTORY)
if(parent STREQUAL "")
set(parent ".")
endif()
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/symlink/${parent}")
file(CREATE_LINK "${target}" "${CMAKE_BINARY_DIR}/symlink/${link}" SYMBOLIC)
install(FILES "${CMAKE_BINARY_DIR}/symlink/${link}" DESTINATION "${parent}")
endfunction()
# Embed Resources
set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}")
function(embed_resource target file)
# Get C Name
get_filename_component(name "${file}" NAME)
string(MAKE_C_IDENTIFIER "${name}" name)
# Add Command
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
COMMAND "${CMAKE_COMMAND}"
ARGS "-DEMBED_IN=${CMAKE_CURRENT_SOURCE_DIR}/${file}" "-DEMBED_OUT=${CMAKE_CURRENT_BINARY_DIR}/${name}.c" "-P" "${util_list_dir}/embed-resource.cmake"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${file}" "${util_list_dir}/embed-resource.cmake"
)
# Add To Target
target_sources("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
endfunction()

View File

@ -1,9 +1,5 @@
project(dependencies)
# ZLib
if(BUILD_ARM_COMPONENTS)
add_subdirectory(zlib)
endif()
# LibPNG
if(BUILD_ARM_COMPONENTS)
add_subdirectory(libpng)
@ -12,15 +8,7 @@ endif()
if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
add_subdirectory(minecraft-pi)
endif()
# GLFW
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
add_subdirectory(glfw)
endif()
# Zenity (Minimal Build)
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE)
add_subdirectory(zenity)
endif()
# Sysroot
if(BUILD_NATIVE_COMPONENTS AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
add_subdirectory(armhf-sysroot)
endif()

View File

@ -1,111 +0,0 @@
project(armhf-sysroot)
# Allow Custom Sysroot
set(MCPI_CUSTOM_BUNDLED_ARMHF_SYSROOT "" CACHE PATH "Custom Bundled ARMHF Sysroot")
if(MCPI_CUSTOM_BUNDLED_ARMHF_SYSROOT)
# Custom Sysroot
set(SYSROOT_DIR "${MCPI_CUSTOM_BUNDLED_ARMHF_SYSROOT}")
else()
# Download From APT
set(APT_PACKAGES "libc6" "libstdc++6")
# Reconfigure CMake If APT Data Is Changed
file(GLOB_RECURSE APT_FILES "apt/*")
foreach(APT_FILE IN LISTS APT_FILES)
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS "${APT_FILE}"
)
endforeach()
# Copy To Binary Directory
set(APT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apt-build")
file(REMOVE_RECURSE "${APT_DIR}")
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/apt/." DESTINATION "${APT_DIR}")
# Make Directories
file(MAKE_DIRECTORY "${APT_DIR}/apt.conf.d")
file(MAKE_DIRECTORY "${APT_DIR}/preferences.d")
file(MAKE_DIRECTORY "${APT_DIR}/dpkg")
file(TOUCH "${APT_DIR}/dpkg/status")
# Create APT Config
string(CONCAT APT_CONFIG
"Dir \"${APT_DIR}\";\n"
"Dir::State \"${APT_DIR}\";\n"
"Dir::Cache \"${APT_DIR}\";\n"
"Dir::Etc::Main \"${APT_DIR}/apt.conf\";\n"
"Dir::Etc::Parts \"${APT_DIR}/apt.conf.d\";\n"
"Dir::Etc::SourceList \"${APT_DIR}/sources.list\";\n"
"Dir::Etc::SourceListParts \"${APT_DIR}/sources.list.d\";\n"
"Dir::Etc::PreferencesParts \"${APT_DIR}/preferences.d\";\n"
"Dir::Etc::TrustedParts \"${APT_DIR}/keys\";\n"
"Dir::State::status \"${APT_DIR}/dpkg/status\";\n"
"Dir::Ignore-Files-Silently \"False\";\n"
"APT::Install-Recommends \"False\";\n"
"APT::Install-Suggests \"False\";\n"
"APT::Immediate-Configure \"False\";\n"
"APT::Architecture \"armhf\";\n"
"APT::Architectures { \"armhf\"; }\n"
"Acquire::Languages \"none\";\n"
"APT::Get::AllowUnauthenticated \"False\";\n"
"Acquire::AllowInsecureRepositories \"False\";\n"
)
file(WRITE "${APT_DIR}/apt.conf" "${APT_CONFIG}")
# Environment
set(APT_ENV
"${CMAKE_COMMAND}"
-E env
"DEBIAN_FRONTEND=noninteractive"
"APT_CONFIG=${APT_DIR}/apt.conf"
)
# Create Sysroot Directory
set(SYSROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/sysroot")
file(REMOVE_RECURSE "${SYSROOT_DIR}")
file(MAKE_DIRECTORY "${SYSROOT_DIR}")
# Download
add_custom_command(
OUTPUT "${APT_DIR}/.update-stamp"
COMMAND ${APT_ENV} apt-get update
COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.update-stamp"
VERBATIM
)
add_custom_command(
OUTPUT "${APT_DIR}/.download-stamp"
DEPENDS "${APT_DIR}/.update-stamp"
COMMAND ${APT_ENV} apt-get install -y --no-install-recommends --download-only ${APT_PACKAGES}
COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.download-stamp"
VERBATIM
)
add_custom_command(
OUTPUT "${APT_DIR}/.extract-stamp"
DEPENDS "${APT_DIR}/.download-stamp"
COMMAND ${APT_ENV} find "${APT_DIR}/archives" -maxdepth 1 -type f -name "*.deb" -exec dpkg -x {} "${SYSROOT_DIR}" ";"
COMMAND "${CMAKE_COMMAND}" -E touch "${APT_DIR}/.extract-stamp"
VERBATIM
)
add_custom_target(armhf-sysroot ALL DEPENDS "${APT_DIR}/.extract-stamp")
endif()
# Install
install(
DIRECTORY "${SYSROOT_DIR}/"
DESTINATION "${MCPI_INSTALL_DIR}/sysroot"
USE_SOURCE_PERMISSIONS
REGEX "usr/lib/arm-linux-gnueabihf/gconv" EXCLUDE
REGEX "usr/lib/arm-linux-gnueabihf/audit" EXCLUDE
REGEX "usr/share/man" EXCLUDE
REGEX "usr/share/doc/.*/README\..*" EXCLUDE
REGEX "usr/share/doc/.*/changelog\..*" EXCLUDE
REGEX "usr/share/doc/.*/NEWS\..*" EXCLUDE
REGEX "usr/share/doc/.*/TODO\..*" EXCLUDE
REGEX "usr/share/lintian" EXCLUDE
REGEX "usr/share/gcc" EXCLUDE
REGEX "usr/share/gdb" EXCLUDE
REGEX "usr/share/locale" EXCLUDE
REGEX "usr/share/help" EXCLUDE
REGEX "etc" EXCLUDE
)

View File

@ -1,186 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
1UKhwK2BVhqTmCWb
=svWP
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,2 +0,0 @@
deb http://deb.debian.org/debian/ bullseye main
deb http://deb.debian.org/debian/ bullseye-updates main

View File

@ -1,22 +0,0 @@
project(glfw)
# Silence Warnings
add_compile_options(-w)
## GLFW
# Download
set(BUILD_SHARED_LIBS FALSE)
set(GLFW_BUILD_EXAMPLES FALSE)
set(GLFW_BUILD_TESTS FALSE)
set(GLFW_BUILD_DOCS FALSE)
set(GLFW_INSTALL FALSE)
set(GLFW_BUILD_WIN32 FALSE)
set(GLFW_BUILD_COCOA FALSE)
set(GLFW_BUILD_X11 TRUE)
set(GLFW_BUILD_WAYLAND TRUE)
set(GLFW_LIBRARY_TYPE "STATIC")
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(glfw-build ALL DEPENDS glfw)

@ -1 +0,0 @@
Subproject commit 7dfd84c458dfa12b351c932b8281b13faf7b50b9

View File

@ -1,20 +1,33 @@
project(libpng)
# ZLib (Needed By libpng)
add_subdirectory(zlib)
# Silence Warnings
add_compile_options(-w)
## LibPNG
# Options
set(PNG_TESTS FALSE CACHE BOOL "" FORCE)
set(PNG_NO_STDIO FALSE CACHE BOOL "" FORCE)
set(PNG_BUILD_ZLIB TRUE CACHE BOOL "" FORCE)
# Download
set(ZLIB_LIBRARY zlibstatic)
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/../zlib/src")
set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning
set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/zlib/src")
add_subdirectory(src EXCLUDE_FROM_ALL)
set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior
set_target_properties(png12 PROPERTIES LINK_OPTIONS "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers") # Use Symbol Versioning
set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode
# Use Symbol Versioning
set_target_properties(png12 PROPERTIES LINK_OPTIONS "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers")
# Ensure Build
add_custom_target(png12-build ALL DEPENDS png12)
# Install
install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install(TARGETS png12 zlibstatic EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# License
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/libpng")

@ -1 +1 @@
Subproject commit 5bb5bf345aef1e62adcfe30791f4364730a2aede
Subproject commit 6c445538879f9e916f8e62723d2ac7cd77d96191

View File

@ -6,7 +6,11 @@ add_compile_options(-w)
## zlib
# Download
set(CMAKE_POLICY_DEFAULT_CMP0022 NEW) # Fix Error
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(zlib-build ALL DEPENDS zlibstatic)
# License
install(FILES src/README DESTINATION "${MCPI_LEGAL_DIR}/zlib")

View File

@ -12,4 +12,10 @@ FetchContent_Declare(
FetchContent_Populate(minecraft-pi)
# Install
install(DIRECTORY "${minecraft-pi_SOURCE_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}" USE_SOURCE_PERMISSIONS)
install(
DIRECTORY "${minecraft-pi_SOURCE_DIR}/"
DESTINATION "${MCPI_INSTALL_DIR}/game"
USE_SOURCE_PERMISSIONS
REGEX "api" EXCLUDE
)
install_symlink("game/minecraft-pi" "${MCPI_INSTALL_DIR}/minecraft-pi")

View File

@ -13,3 +13,6 @@ add_custom_target(zenity-build ALL DEPENDS zenity)
# Install
install(TARGETS zenity DESTINATION "${MCPI_BIN_DIR}")
# License
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/zenity")

@ -1 +1 @@
Subproject commit 3dbcdbb34a0c92297155de48ed491ea3e587b208
Subproject commit 27cd9e88a72538b00d172dee67d94cb4ce6bc9b9

View File

@ -2,6 +2,11 @@
## Launch Sequence
### Common
1. The launcher forks itself
1. The child process continues the launch sequence.
2. The original process monitors the child process for crashes.
### Client
1. The launcher is started by the user
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn
@ -34,12 +39,11 @@ The Media Layer handles MCPI's graphics calls and user input. It replaces MCPI's
This sub-component re-implements a subset of SDL 1.2 calls with GLFW. It also provides a few utility functions that are used internally by MCPI-Reborn.
The utility functions include:
* Taking Screenshots
* Fullscreen
* Audio
* Etc
This is always compiled for the host system's architecture.
This is always compiled for the host system's architecture unless the Media Layer Proxy is disabled.
This was created because SDL 1.2 has numerous bugs and is in-general unsupported.
@ -60,21 +64,13 @@ It is made of two parts:
While proxying all Media Layer Core API calls across UNIX pipes does hurt performance, it is better than emulating the entire graphics stack.
Using this in server-mode is redundant (and disallowed).
Using this in server-mode is redundant.
#### Extras
This sub-component contains code that must always be linked directly to MCPI.
This is always compiled for ARM.
#### Stubs
This sub-component implements stubs for various redundant libraries used by MCPI to silence linker errors.
This is always compiled for ARM.
##### What To Stub And What To Patch?
Most libraries (like ``bcm_host``) can just be replaced with stubs, because they don't need to do anything and aren't used by anything else. However, some libraries (like EGL and X11) might be used by some of MCPI-Reborn's dependencies (like GLFW) so instead of being replaced by a stub, each call is manually patched out from MCPI. A stub is still generated just in case that library isn't present on the system to silence linker errors, but it is only loaded if no other version is available.
#### Headers
This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation.
@ -98,12 +94,11 @@ This component contains all MCPI symbols.
## Dependencies
MCPI-Reborn has several dependencies:
* MCPI (Bundled)
* GLFW (Only In Client Mode)
* Open GL ES 1.1
* GLFW (Only In Client Mode; Bundled)
* Open GL ES 2.0
* EGL
* OpenAL (Only In Client Mode)
* ZLib (Required By LibPNG; Bundled)
* LibPNG (Bundled)
* FreeImage (Only In Client Mode)
* QEMU User Mode (Only On Non-ARM Hosts; Runtime Only)
* Zenity (Only In Client Mode; Runtime Only)
* Zenity (Only In Client Mode; Runtime Only; Bundled)

View File

@ -1,26 +1,11 @@
# Building
## Build Dependencies
* Common
* ARM Compiler
* Host Compiler (Clang)
* CMake
* Host Architecture Dependencies
* Client Mode Only
* GLFW
* FreeImage
* OpenAL
## Dependencies
## Runtime Dependencies
* Non-ARM Host Architectures
* QEMU User-Mode
* Host Architecture Dependencies
* Client Mode Only
* OpenGL ES 1.1
* GLFW
* FreeImage
* OpenAL
* Zenity
### Debian/Ubuntu
```sh
./scripts/install-dependencies.sh
```
## Instructions
```sh
@ -32,3 +17,6 @@
./scripts/setup.sh <client|server> <armhf|arm64|i686|amd64> <Custom CMake Arguments>
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
```
### Environment Variables
* ``MCPI_TOOLCHAIN_USE_DEFAULT_SEARCH_PATHS``: Use Default CMake Search Paths Rather Than Guessing

View File

@ -1,5 +1,53 @@
# Changelog
**2.4.3**
* Fix Signs With CP-437
**2.4.2**
* Fix Picking Up Lava
* Fix Wayland App ID
**2.4.1**
* Allow More Characters In Usernames And Chat
* Fix Running On ARMHF Debian Buster
**2.4.0**
* [Modding SDK](../example-mods/README.md)
* Cache Blacklist/Whitelist
* More Reliable AppImages
* CMake Refactors
* Disable Broken Touchscreen-Specific Block Outline Behavior
* Add ``Remove Forced GUI Lag (Can Break Joining Servers)`` Feature Flag (Disabled By Default)
* Add ``Add Buckets`` Feature Flag (Enabled By Default)
* Add ``Classic HUD`` Feature Flag (Enabled By Default)
* Add ``Translucent Toolbar`` Feature Flag (Enabled By Default)
* Add ``Force EGL`` Feature Flag (Disabled By Default)
* Fix Sound Pitch/Volume/Attenuation
* Fix Holding Left-Click When Attacking
* Don't Force EGL (Should Fix Some NVIDIA Systems)
* Performance Fixes
**2.3.13**
* Fix Texture Bug
**2.3.12**
* Media Layer Proxy Optimizations
* Bug Fixes
**2.3.11**
* ``--version`` Command Line Option
* TPS Measured In Benchmark & Server
* Front-Facing Third-Person
* GLESv1 Comparability Layer
* Miscellaneous Bug Fixes
**2.3.10**
* Add Crash Report Dialog
* Disable V-Sync By Default
* Refactor Child Process Management
* Improve Build System
* Support For Building On Ubuntu 22.04
**2.3.9**
* Bundle An ARM Sysroot
* Not Used On ARM32 Systems

View File

@ -2,8 +2,11 @@
## Command Line Arguments
### ``--version`` (Or ``-v``)
If you run MCPI-Reborn with ``--version`` it will print its version to ``stdout``.
### ``--print-available-feature-flags`` (Client Mode Only)
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags and then immediately exit.
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags to ``stdout`` and then immediately exit.
The feature flags are printed in the following format:
```
@ -11,6 +14,9 @@ TRUE This Flag Is On By Default
FALSE This Flag Is Off By Default
```
### ``--default`` (Client Mode Only)
If you run MCPI-Reborn with ``--default``, it will skip the startup configuration dialogs and just use the default values.
### ``--only-generate`` (Server Mode Only)
If you run MCPI-Reborn with ``--only-generate``, it will immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
@ -22,18 +28,18 @@ The world used will always be re-created on start and uses a hard-coded seed.
## Environmental Variables
### ``MCPI_DEBUG``
This enables debug logging if you set it to any non-zero-length value.
This enables debug logging if it is set.
### Client Mode Only
If a value isn't set for any of the following variables, a GUI will open that allows you to select one.
If any of the following variables aren't set, one configuration dialog will open on startup for each unset variable.
### ``MCPI_FEATURE_FLAGS``
#### ``MCPI_FEATURE_FLAGS``
This corresponds to ``--print-available-feature-flags``. This is just a list of all enabled feature flags separated by ``|``.
For instance, the string ``Feature A|Feature B`` would enable both ``Feature A`` and ``Feature B`` and *disable every other available feature flag*.
### ``MCPI_RENDER_DISTANCE``
#### ``MCPI_RENDER_DISTANCE``
This is the render distance. The possible values are: ``Far``, ``Normal``, ``Short``, and ``Tiny``.
### ``MCPI_USERNAME``
#### ``MCPI_USERNAME``
This is the username.

View File

@ -1,7 +1,7 @@
# Dedicated Server
The dedicated server is a version of Minecraft: Pi Edition modified to run in a headless environment. It loads settings from a ``server.properties`` file.
This server is also compatible with MCPE Alpha v0.6.1.
This server is also compatible with MCPE Alpha v0.6.1[^1].
## Setup
@ -15,3 +15,5 @@ An official Docker image is also provided: [thebrokenrail/minecraft-pi-reborn-se
* Player data is not saved because of limitations with MCPE LAN worlds
* An easy workaround is to place your inventory in a chest before logging off
* Survival Mode servers are incompatible with unmodded MCPI
[^1]: The exception to this is buckets, those will crash MCPE players.

View File

@ -1,21 +1,27 @@
# Installation
## AppImage
Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/).
## Picking A Package
### System Requirements
* Debian Buster/Ubuntu 18.04 Or Higher
* QEMU User-Mode
* Debian/Ubuntu: ``sudo apt install qemu-user``
* Arch: ``sudo pacman -S qemu-user``
* Client-Only Dependencies
* Graphics Drivers
* GTK+ 3
* Debian/Ubuntu: ``sudo apt install libgtk-3-0``
* Arch: ``sudo pacman -S gtk3``
* OpenAL
* Debian/Ubuntu: ``sudo apt install libopenal1``
* Arch: ``sudo pacman -S openal``
### Name Format
```
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 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).
* ``arm64``: ARM 64-Bit, ``armhf`` but for 64-bit devices.
## Running
### Running
Follow [these](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage) instructions.
## Flatpak
<a href="https://flathub.org/apps/details/com.thebrokenrail.MCPIReborn"><img width="240" alt="Download On Flathub" src="https://flathub.org/assets/badges/flathub-badge-en.svg" /></a>
### Note
Game data is stored in ``~/.var/app/com.thebrokenrail.MCPIReborn/.minecraft-pi`` instead of ``~/.minecraft-pi``.

19
example-mods/README.md Normal file
View File

@ -0,0 +1,19 @@
# Example Mods
This is an example of a mod that can be built using the modding SDK.
* **Expanded Creative Mod**: This specific mod adds even more items and blocks to the Creative Inventory. It was originally by [@Bigjango13](https://github.com/bigjango13).
* **Chat Commands Mod**: This specific mod makes an chat message starting with a ``/`` handled by the MCPI API.
* **Recipes Mod**: This specific mod demos custom recipes.
## The SDK
The modding SDK is a collection of exported CMake targets that allows anyone to create their own MCPI mod!
The SDK is copied to ``~/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake`` whenever MCPI-Reborn is started.
## How do I use this?
```sh
mkdir build
cd build
cmake ..
cp libexpanded-creative.so ~/.minecraft-pi/mods
```

15
example-mods/chat-commands/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*
/cmake/.prebuilt-armhf-toolchain

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16.0)
# Build For ARM
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Start Project
project(chat-commands)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
# Build
add_library(chat-commands SHARED chat-commands.cpp)
target_link_libraries(chat-commands mods-headers reborn-patch symbols chat misc)

View File

@ -0,0 +1,25 @@
// Headers
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/chat/chat.h>
#include <mods/misc/misc.h>
// The Actual Mod
HOOK(chat_handle_packet_send, void, (unsigned char *minecraft, unsigned char *packet)) {
// Get Message
char *message = *(char **) (packet + ChatPacket_message_property_offset);
if (message[0] == '/') {
// API Command
unsigned char *gui = minecraft + Minecraft_gui_property_offset;
std::string out = chat_send_api_command(minecraft, &message[1]);
if (out.length() > 0 && out[out.length() - 1] == '\n') {
out[out.length() - 1] = '\0';
}
misc_add_message(gui, out.c_str());
} else {
// Call Original Method
ensure_chat_handle_packet_send();
(*real_chat_handle_packet_send)(minecraft, packet);
}
}

View File

@ -0,0 +1,15 @@
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*
/cmake/.prebuilt-armhf-toolchain

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16.0)
# Build For ARM
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Start Project
project(expanded-creative)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
# Build
add_library(expanded-creative SHARED expanded-creative.cpp)
target_link_libraries(expanded-creative mods-headers reborn-patch symbols misc)

View File

@ -0,0 +1,638 @@
// Headers
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/misc/misc.h>
// The Actual Mod
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) {
ItemInstance *fire_instance = new ItemInstance;
ALLOC_CHECK(fire_instance);
fire_instance->count = 255;
fire_instance->auxiliary = 0;
fire_instance->id = 51;
(*FillingContainer_addItem)(filling_container, fire_instance);
ItemInstance *mushroomStew_instance = new ItemInstance;
ALLOC_CHECK(mushroomStew_instance);
mushroomStew_instance->count = 255;
mushroomStew_instance->auxiliary = 0;
mushroomStew_instance->id = 282;
(*FillingContainer_addItem)(filling_container, mushroomStew_instance);
ItemInstance *steak_instance = new ItemInstance;
ALLOC_CHECK(steak_instance);
steak_instance->count = 255;
steak_instance->auxiliary = 0;
steak_instance->id = 364;
(*FillingContainer_addItem)(filling_container, steak_instance);
ItemInstance *cookedChicken_instance = new ItemInstance;
ALLOC_CHECK(cookedChicken_instance);
cookedChicken_instance->count = 255;
cookedChicken_instance->auxiliary = 0;
cookedChicken_instance->id = 366;
(*FillingContainer_addItem)(filling_container, cookedChicken_instance);
ItemInstance *porkCooked_instance = new ItemInstance;
ALLOC_CHECK(porkCooked_instance);
porkCooked_instance->count = 255;
porkCooked_instance->auxiliary = 0;
porkCooked_instance->id = 320;
(*FillingContainer_addItem)(filling_container, porkCooked_instance);
ItemInstance *apple_instance = new ItemInstance;
ALLOC_CHECK(apple_instance);
apple_instance->count = 255;
apple_instance->auxiliary = 0;
apple_instance->id = 260;
(*FillingContainer_addItem)(filling_container, apple_instance);
ItemInstance *tallGrass_instance = new ItemInstance;
ALLOC_CHECK(tallGrass_instance);
tallGrass_instance->count = 255;
tallGrass_instance->auxiliary = 0;
tallGrass_instance->id = 31;
(*FillingContainer_addItem)(filling_container, tallGrass_instance);
ItemInstance *crops_instance = new ItemInstance;
ALLOC_CHECK(crops_instance);
crops_instance->count = 255;
crops_instance->auxiliary = 0;
crops_instance->id = 59;
(*FillingContainer_addItem)(filling_container, crops_instance);
ItemInstance *farmland_instance = new ItemInstance;
ALLOC_CHECK(farmland_instance);
farmland_instance->count = 255;
farmland_instance->auxiliary = 0;
farmland_instance->id = 60;
(*FillingContainer_addItem)(filling_container, farmland_instance);
ItemInstance *activeFurnace_instance = new ItemInstance;
ALLOC_CHECK(activeFurnace_instance);
activeFurnace_instance->count = 255;
activeFurnace_instance->auxiliary = 0;
activeFurnace_instance->id = 62;
(*FillingContainer_addItem)(filling_container, activeFurnace_instance);
ItemInstance *ironDoor_instance = new ItemInstance;
ALLOC_CHECK(ironDoor_instance);
ironDoor_instance->count = 255;
ironDoor_instance->auxiliary = 0;
ironDoor_instance->id = 330;
(*FillingContainer_addItem)(filling_container, ironDoor_instance);
ItemInstance *activeRedstoneOre_instance = new ItemInstance;
ALLOC_CHECK(activeRedstoneOre_instance);
activeRedstoneOre_instance->count = 255;
activeRedstoneOre_instance->auxiliary = 0;
activeRedstoneOre_instance->id = 74;
(*FillingContainer_addItem)(filling_container, activeRedstoneOre_instance);
ItemInstance *pumkinStem_instance = new ItemInstance;
ALLOC_CHECK(pumkinStem_instance);
pumkinStem_instance->count = 255;
pumkinStem_instance->auxiliary = 0;
pumkinStem_instance->id = 105;
(*FillingContainer_addItem)(filling_container, pumkinStem_instance);
ItemInstance *newGrass_instance = new ItemInstance;
ALLOC_CHECK(newGrass_instance);
newGrass_instance->count = 255;
newGrass_instance->auxiliary = 0;
newGrass_instance->id = 253;
(*FillingContainer_addItem)(filling_container, newGrass_instance);
ItemInstance *reserved6_instance = new ItemInstance;
ALLOC_CHECK(reserved6_instance);
reserved6_instance->count = 255;
reserved6_instance->auxiliary = 0;
reserved6_instance->id = 1;
(*FillingContainer_addItem)(filling_container, reserved6_instance);
ItemInstance *doubleStoneSlab_instance = new ItemInstance;
ALLOC_CHECK(doubleStoneSlab_instance);
doubleStoneSlab_instance->count = 255;
doubleStoneSlab_instance->auxiliary = 0;
doubleStoneSlab_instance->id = 43;
(*FillingContainer_addItem)(filling_container, doubleStoneSlab_instance);
ItemInstance *arrow_instance = new ItemInstance;
ALLOC_CHECK(arrow_instance);
arrow_instance->count = 255;
arrow_instance->auxiliary = 0;
arrow_instance->id = 262;
(*FillingContainer_addItem)(filling_container, arrow_instance);
ItemInstance *coal_instance = new ItemInstance;
ALLOC_CHECK(coal_instance);
coal_instance->count = 255;
coal_instance->auxiliary = 0;
coal_instance->id = 263;
(*FillingContainer_addItem)(filling_container, coal_instance);
ItemInstance *diamond_instance = new ItemInstance;
ALLOC_CHECK(diamond_instance);
diamond_instance->count = 255;
diamond_instance->auxiliary = 0;
diamond_instance->id = 264;
(*FillingContainer_addItem)(filling_container, diamond_instance);
ItemInstance *ironIngot_instance = new ItemInstance;
ALLOC_CHECK(ironIngot_instance);
ironIngot_instance->count = 255;
ironIngot_instance->auxiliary = 0;
ironIngot_instance->id = 265;
(*FillingContainer_addItem)(filling_container, ironIngot_instance);
ItemInstance *goldIngot_instance = new ItemInstance;
ALLOC_CHECK(goldIngot_instance);
goldIngot_instance->count = 255;
goldIngot_instance->auxiliary = 0;
goldIngot_instance->id = 266;
(*FillingContainer_addItem)(filling_container, goldIngot_instance);
ItemInstance *woodSword_instance = new ItemInstance;
ALLOC_CHECK(woodSword_instance);
woodSword_instance->count = 255;
woodSword_instance->auxiliary = 0;
woodSword_instance->id = 268;
(*FillingContainer_addItem)(filling_container, woodSword_instance);
ItemInstance *woodShovel_instance = new ItemInstance;
ALLOC_CHECK(woodShovel_instance);
woodShovel_instance->count = 255;
woodShovel_instance->auxiliary = 0;
woodShovel_instance->id = 269;
(*FillingContainer_addItem)(filling_container, woodShovel_instance);
ItemInstance *woodPickaxe_instance = new ItemInstance;
ALLOC_CHECK(woodPickaxe_instance);
woodPickaxe_instance->count = 255;
woodPickaxe_instance->auxiliary = 0;
woodPickaxe_instance->id = 270;
(*FillingContainer_addItem)(filling_container, woodPickaxe_instance);
ItemInstance *woodAxe_instance = new ItemInstance;
ALLOC_CHECK(woodAxe_instance);
woodAxe_instance->count = 255;
woodAxe_instance->auxiliary = 0;
woodAxe_instance->id = 271;
(*FillingContainer_addItem)(filling_container, woodAxe_instance);
ItemInstance *stoneSword_instance = new ItemInstance;
ALLOC_CHECK(stoneSword_instance);
stoneSword_instance->count = 255;
stoneSword_instance->auxiliary = 0;
stoneSword_instance->id = 272;
(*FillingContainer_addItem)(filling_container, stoneSword_instance);
ItemInstance *stoneShovel_instance = new ItemInstance;
ALLOC_CHECK(stoneShovel_instance);
stoneShovel_instance->count = 255;
stoneShovel_instance->auxiliary = 0;
stoneShovel_instance->id = 273;
(*FillingContainer_addItem)(filling_container, stoneShovel_instance);
ItemInstance *stonePickaxe_instance = new ItemInstance;
ALLOC_CHECK(stonePickaxe_instance);
stonePickaxe_instance->count = 255;
stonePickaxe_instance->auxiliary = 0;
stonePickaxe_instance->id = 274;
(*FillingContainer_addItem)(filling_container, stonePickaxe_instance);
ItemInstance *stoneAxe_instance = new ItemInstance;
ALLOC_CHECK(stoneAxe_instance);
stoneAxe_instance->count = 255;
stoneAxe_instance->auxiliary = 0;
stoneAxe_instance->id = 275;
(*FillingContainer_addItem)(filling_container, stoneAxe_instance);
ItemInstance *shovelIron_instance = new ItemInstance;
ALLOC_CHECK(shovelIron_instance);
shovelIron_instance->count = 255;
shovelIron_instance->auxiliary = 0;
shovelIron_instance->id = 256;
(*FillingContainer_addItem)(filling_container, shovelIron_instance);
ItemInstance *ironPick_instance = new ItemInstance;
ALLOC_CHECK(ironPick_instance);
ironPick_instance->count = 255;
ironPick_instance->auxiliary = 0;
ironPick_instance->id = 257;
(*FillingContainer_addItem)(filling_container, ironPick_instance);
ItemInstance *ironAxe_instance = new ItemInstance;
ALLOC_CHECK(ironAxe_instance);
ironAxe_instance->count = 255;
ironAxe_instance->auxiliary = 0;
ironAxe_instance->id = 258;
(*FillingContainer_addItem)(filling_container, ironAxe_instance);
ItemInstance *diamondSword_instance = new ItemInstance;
ALLOC_CHECK(diamondSword_instance);
diamondSword_instance->count = 255;
diamondSword_instance->auxiliary = 0;
diamondSword_instance->id = 276;
(*FillingContainer_addItem)(filling_container, diamondSword_instance);
ItemInstance *diamondShovel_instance = new ItemInstance;
ALLOC_CHECK(diamondShovel_instance);
diamondShovel_instance->count = 255;
diamondShovel_instance->auxiliary = 0;
diamondShovel_instance->id = 277;
(*FillingContainer_addItem)(filling_container, diamondShovel_instance);
ItemInstance *diamondPickaxe_instance = new ItemInstance;
ALLOC_CHECK(diamondPickaxe_instance);
diamondPickaxe_instance->count = 255;
diamondPickaxe_instance->auxiliary = 0;
diamondPickaxe_instance->id = 278;
(*FillingContainer_addItem)(filling_container, diamondPickaxe_instance);
ItemInstance *diamondAxe_instance = new ItemInstance;
ALLOC_CHECK(diamondAxe_instance);
diamondAxe_instance->count = 255;
diamondAxe_instance->auxiliary = 0;
diamondAxe_instance->id = 279;
(*FillingContainer_addItem)(filling_container, diamondAxe_instance);
ItemInstance *magicWand_instance = new ItemInstance;
ALLOC_CHECK(magicWand_instance);
magicWand_instance->count = 255;
magicWand_instance->auxiliary = 0;
magicWand_instance->id = 280;
(*FillingContainer_addItem)(filling_container, magicWand_instance);
ItemInstance *bowl_instance = new ItemInstance;
ALLOC_CHECK(bowl_instance);
bowl_instance->count = 255;
bowl_instance->auxiliary = 0;
bowl_instance->id = 281;
(*FillingContainer_addItem)(filling_container, bowl_instance);
ItemInstance *goldSword_instance = new ItemInstance;
ALLOC_CHECK(goldSword_instance);
goldSword_instance->count = 255;
goldSword_instance->auxiliary = 0;
goldSword_instance->id = 283;
(*FillingContainer_addItem)(filling_container, goldSword_instance);
ItemInstance *goldShovel_instance = new ItemInstance;
ALLOC_CHECK(goldShovel_instance);
goldShovel_instance->count = 255;
goldShovel_instance->auxiliary = 0;
goldShovel_instance->id = 284;
(*FillingContainer_addItem)(filling_container, goldShovel_instance);
ItemInstance *goldPickaxe_instance = new ItemInstance;
ALLOC_CHECK(goldPickaxe_instance);
goldPickaxe_instance->count = 255;
goldPickaxe_instance->auxiliary = 0;
goldPickaxe_instance->id = 285;
(*FillingContainer_addItem)(filling_container, goldPickaxe_instance);
ItemInstance *goldAxe_instance = new ItemInstance;
ALLOC_CHECK(goldAxe_instance);
goldAxe_instance->count = 255;
goldAxe_instance->auxiliary = 0;
goldAxe_instance->id = 286;
(*FillingContainer_addItem)(filling_container, goldAxe_instance);
ItemInstance *string_instance = new ItemInstance;
ALLOC_CHECK(string_instance);
string_instance->count = 255;
string_instance->auxiliary = 0;
string_instance->id = 287;
(*FillingContainer_addItem)(filling_container, string_instance);
ItemInstance *feather_instance = new ItemInstance;
ALLOC_CHECK(feather_instance);
feather_instance->count = 255;
feather_instance->auxiliary = 0;
feather_instance->id = 288;
(*FillingContainer_addItem)(filling_container, feather_instance);
ItemInstance *gunpowder_instance = new ItemInstance;
ALLOC_CHECK(gunpowder_instance);
gunpowder_instance->count = 255;
gunpowder_instance->auxiliary = 0;
gunpowder_instance->id = 289;
(*FillingContainer_addItem)(filling_container, gunpowder_instance);
ItemInstance *woodHoe_instance = new ItemInstance;
ALLOC_CHECK(woodHoe_instance);
woodHoe_instance->count = 255;
woodHoe_instance->auxiliary = 0;
woodHoe_instance->id = 290;
(*FillingContainer_addItem)(filling_container, woodHoe_instance);
ItemInstance *stoneHoe_instance = new ItemInstance;
ALLOC_CHECK(stoneHoe_instance);
stoneHoe_instance->count = 255;
stoneHoe_instance->auxiliary = 0;
stoneHoe_instance->id = 291;
(*FillingContainer_addItem)(filling_container, stoneHoe_instance);
ItemInstance *flint1_instance = new ItemInstance;
ALLOC_CHECK(flint1_instance);
flint1_instance->count = 255;
flint1_instance->auxiliary = 0;
flint1_instance->id = 292;
(*FillingContainer_addItem)(filling_container, flint1_instance);
ItemInstance *diamondHoe_instance = new ItemInstance;
ALLOC_CHECK(diamondHoe_instance);
diamondHoe_instance->count = 255;
diamondHoe_instance->auxiliary = 0;
diamondHoe_instance->id = 293;
(*FillingContainer_addItem)(filling_container, diamondHoe_instance);
ItemInstance *goldHoe_instance = new ItemInstance;
ALLOC_CHECK(goldHoe_instance);
goldHoe_instance->count = 255;
goldHoe_instance->auxiliary = 0;
goldHoe_instance->id = 294;
(*FillingContainer_addItem)(filling_container, goldHoe_instance);
ItemInstance *seeds_instance = new ItemInstance;
ALLOC_CHECK(seeds_instance);
seeds_instance->count = 255;
seeds_instance->auxiliary = 0;
seeds_instance->id = 295;
(*FillingContainer_addItem)(filling_container, seeds_instance);
ItemInstance *wheat_instance = new ItemInstance;
ALLOC_CHECK(wheat_instance);
wheat_instance->count = 255;
wheat_instance->auxiliary = 0;
wheat_instance->id = 296;
(*FillingContainer_addItem)(filling_container, wheat_instance);
ItemInstance *bread_instance = new ItemInstance;
ALLOC_CHECK(bread_instance);
bread_instance->count = 255;
bread_instance->auxiliary = 0;
bread_instance->id = 297;
(*FillingContainer_addItem)(filling_container, bread_instance);
ItemInstance *diamondHelm_instance = new ItemInstance;
ALLOC_CHECK(diamondHelm_instance);
diamondHelm_instance->count = 255;
diamondHelm_instance->auxiliary = 0;
diamondHelm_instance->id = 310;
(*FillingContainer_addItem)(filling_container, diamondHelm_instance);
ItemInstance *diamondChest_instance = new ItemInstance;
ALLOC_CHECK(diamondChest_instance);
diamondChest_instance->count = 255;
diamondChest_instance->auxiliary = 0;
diamondChest_instance->id = 311;
(*FillingContainer_addItem)(filling_container, diamondChest_instance);
ItemInstance *diamondLeg_instance = new ItemInstance;
ALLOC_CHECK(diamondLeg_instance);
diamondLeg_instance->count = 255;
diamondLeg_instance->auxiliary = 0;
diamondLeg_instance->id = 312;
(*FillingContainer_addItem)(filling_container, diamondLeg_instance);
ItemInstance *diamondBoot_instance = new ItemInstance;
ALLOC_CHECK(diamondBoot_instance);
diamondBoot_instance->count = 255;
diamondBoot_instance->auxiliary = 0;
diamondBoot_instance->id = 313;
(*FillingContainer_addItem)(filling_container, diamondBoot_instance);
ItemInstance *leatherCap_instance = new ItemInstance;
ALLOC_CHECK(leatherCap_instance);
leatherCap_instance->count = 255;
leatherCap_instance->auxiliary = 0;
leatherCap_instance->id = 298;
(*FillingContainer_addItem)(filling_container, leatherCap_instance);
ItemInstance *leatherShirt_instance = new ItemInstance;
ALLOC_CHECK(leatherShirt_instance);
leatherShirt_instance->count = 255;
leatherShirt_instance->auxiliary = 0;
leatherShirt_instance->id = 299;
(*FillingContainer_addItem)(filling_container, leatherShirt_instance);
ItemInstance *leatherPants_instance = new ItemInstance;
ALLOC_CHECK(leatherPants_instance);
leatherPants_instance->count = 255;
leatherPants_instance->auxiliary = 0;
leatherPants_instance->id = 300;
(*FillingContainer_addItem)(filling_container, leatherPants_instance);
ItemInstance *leatherBoots_instance = new ItemInstance;
ALLOC_CHECK(leatherBoots_instance);
leatherBoots_instance->count = 255;
leatherBoots_instance->auxiliary = 0;
leatherBoots_instance->id = 301;
(*FillingContainer_addItem)(filling_container, leatherBoots_instance);
ItemInstance *chainHelm_instance = new ItemInstance;
ALLOC_CHECK(chainHelm_instance);
chainHelm_instance->count = 255;
chainHelm_instance->auxiliary = 0;
chainHelm_instance->id = 302;
(*FillingContainer_addItem)(filling_container, chainHelm_instance);
ItemInstance *chainShirt_instance = new ItemInstance;
ALLOC_CHECK(chainShirt_instance);
chainShirt_instance->count = 255;
chainShirt_instance->auxiliary = 0;
chainShirt_instance->id = 303;
(*FillingContainer_addItem)(filling_container, chainShirt_instance);
ItemInstance *chainLegs_instance = new ItemInstance;
ALLOC_CHECK(chainLegs_instance);
chainLegs_instance->count = 255;
chainLegs_instance->auxiliary = 0;
chainLegs_instance->id = 304;
(*FillingContainer_addItem)(filling_container, chainLegs_instance);
ItemInstance *chainBoots_instance = new ItemInstance;
ALLOC_CHECK(chainBoots_instance);
chainBoots_instance->count = 255;
chainBoots_instance->auxiliary = 0;
chainBoots_instance->id = 305;
(*FillingContainer_addItem)(filling_container, chainBoots_instance);
ItemInstance *goldHelm_instance = new ItemInstance;
ALLOC_CHECK(goldHelm_instance);
goldHelm_instance->count = 255;
goldHelm_instance->auxiliary = 0;
goldHelm_instance->id = 314;
(*FillingContainer_addItem)(filling_container, goldHelm_instance);
ItemInstance *goldChest_instance = new ItemInstance;
ALLOC_CHECK(goldChest_instance);
goldChest_instance->count = 255;
goldChest_instance->auxiliary = 0;
goldChest_instance->id = 315;
(*FillingContainer_addItem)(filling_container, goldChest_instance);
ItemInstance *goldLegs_instance = new ItemInstance;
ALLOC_CHECK(goldLegs_instance);
goldLegs_instance->count = 255;
goldLegs_instance->auxiliary = 0;
goldLegs_instance->id = 316;
(*FillingContainer_addItem)(filling_container, goldLegs_instance);
ItemInstance *goldBoots_instance = new ItemInstance;
ALLOC_CHECK(goldBoots_instance);
goldBoots_instance->count = 255;
goldBoots_instance->auxiliary = 0;
goldBoots_instance->id = 317;
(*FillingContainer_addItem)(filling_container, goldBoots_instance);
ItemInstance *ironHelm_instance = new ItemInstance;
ALLOC_CHECK(ironHelm_instance);
ironHelm_instance->count = 255;
ironHelm_instance->auxiliary = 0;
ironHelm_instance->id = 306;
(*FillingContainer_addItem)(filling_container, ironHelm_instance);
ItemInstance *ironChest_instance = new ItemInstance;
ALLOC_CHECK(ironChest_instance);
ironChest_instance->count = 255;
ironChest_instance->auxiliary = 0;
ironChest_instance->id = 307;
(*FillingContainer_addItem)(filling_container, ironChest_instance);
ItemInstance *ironLegs_instance = new ItemInstance;
ALLOC_CHECK(ironLegs_instance);
ironLegs_instance->count = 255;
ironLegs_instance->auxiliary = 0;
ironLegs_instance->id = 308;
(*FillingContainer_addItem)(filling_container, ironLegs_instance);
ItemInstance *ironBoots_instance = new ItemInstance;
ALLOC_CHECK(ironBoots_instance);
ironBoots_instance->count = 255;
ironBoots_instance->auxiliary = 0;
ironBoots_instance->id = 309;
(*FillingContainer_addItem)(filling_container, ironBoots_instance);
ItemInstance *flint2_instance = new ItemInstance;
ALLOC_CHECK(flint2_instance);
flint2_instance->count = 255;
flint2_instance->auxiliary = 0;
flint2_instance->id = 318;
(*FillingContainer_addItem)(filling_container, flint2_instance);
ItemInstance *porkRaw_instance = new ItemInstance;
ALLOC_CHECK(porkRaw_instance);
porkRaw_instance->count = 255;
porkRaw_instance->auxiliary = 0;
porkRaw_instance->id = 319;
(*FillingContainer_addItem)(filling_container, porkRaw_instance);
ItemInstance *leather_instance = new ItemInstance;
ALLOC_CHECK(leather_instance);
leather_instance->count = 255;
leather_instance->auxiliary = 0;
leather_instance->id = 334;
(*FillingContainer_addItem)(filling_container, leather_instance);
ItemInstance *clayBrick_instance = new ItemInstance;
ALLOC_CHECK(clayBrick_instance);
clayBrick_instance->count = 255;
clayBrick_instance->auxiliary = 0;
clayBrick_instance->id = 336;
(*FillingContainer_addItem)(filling_container, clayBrick_instance);
ItemInstance *clay_instance = new ItemInstance;
ALLOC_CHECK(clay_instance);
clay_instance->count = 255;
clay_instance->auxiliary = 0;
clay_instance->id = 337;
(*FillingContainer_addItem)(filling_container, clay_instance);
ItemInstance *notepad_instance = new ItemInstance;
ALLOC_CHECK(notepad_instance);
notepad_instance->count = 255;
notepad_instance->auxiliary = 0;
notepad_instance->id = 339;
(*FillingContainer_addItem)(filling_container, notepad_instance);
ItemInstance *book_instance = new ItemInstance;
ALLOC_CHECK(book_instance);
book_instance->count = 255;
book_instance->auxiliary = 0;
book_instance->id = 340;
(*FillingContainer_addItem)(filling_container, book_instance);
ItemInstance *slimeball_instance = new ItemInstance;
ALLOC_CHECK(slimeball_instance);
slimeball_instance->count = 255;
slimeball_instance->auxiliary = 0;
slimeball_instance->id = 341;
(*FillingContainer_addItem)(filling_container, slimeball_instance);
ItemInstance *compass_instance = new ItemInstance;
ALLOC_CHECK(compass_instance);
compass_instance->count = 255;
compass_instance->auxiliary = 0;
compass_instance->id = 345;
(*FillingContainer_addItem)(filling_container, compass_instance);
ItemInstance *clock_instance = new ItemInstance;
ALLOC_CHECK(clock_instance);
clock_instance->count = 255;
clock_instance->auxiliary = 0;
clock_instance->id = 347;
(*FillingContainer_addItem)(filling_container, clock_instance);
ItemInstance *glowDust_instance = new ItemInstance;
ALLOC_CHECK(glowDust_instance);
glowDust_instance->count = 255;
glowDust_instance->auxiliary = 0;
glowDust_instance->id = 348;
(*FillingContainer_addItem)(filling_container, glowDust_instance);
ItemInstance *bone_instance = new ItemInstance;
ALLOC_CHECK(bone_instance);
bone_instance->count = 255;
bone_instance->auxiliary = 0;
bone_instance->id = 352;
(*FillingContainer_addItem)(filling_container, bone_instance);
ItemInstance *sugar_instance = new ItemInstance;
ALLOC_CHECK(sugar_instance);
sugar_instance->count = 255;
sugar_instance->auxiliary = 0;
sugar_instance->id = 353;
(*FillingContainer_addItem)(filling_container, sugar_instance);
ItemInstance *melon_instance = new ItemInstance;
ALLOC_CHECK(melon_instance);
melon_instance->count = 255;
melon_instance->auxiliary = 0;
melon_instance->id = 360;
(*FillingContainer_addItem)(filling_container, melon_instance);
ItemInstance *beefRaw_instance = new ItemInstance;
ALLOC_CHECK(beefRaw_instance);
beefRaw_instance->count = 255;
beefRaw_instance->auxiliary = 0;
beefRaw_instance->id = 363;
(*FillingContainer_addItem)(filling_container, beefRaw_instance);
ItemInstance *chickenRaw_instance = new ItemInstance;
ALLOC_CHECK(chickenRaw_instance);
chickenRaw_instance->count = 255;
chickenRaw_instance->auxiliary = 0;
chickenRaw_instance->id = 365;
(*FillingContainer_addItem)(filling_container, chickenRaw_instance);
}
// Init
__attribute__((constructor)) static void init_expanded_creative() {
INFO("Loading Expanded Creative Mod");
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
}

15
example-mods/recipes/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*
/cmake/.prebuilt-armhf-toolchain

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16.0)
# Build For ARM
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Start Project
project(recipes)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
# Build
add_library(recipes SHARED recipes.cpp)
target_link_libraries(recipes mods-headers reborn-util symbols misc)

View File

@ -0,0 +1,52 @@
// Headers
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/misc/misc.h>
// Custom Crafting Recipes
static void Recipes_injection(unsigned char *recipes) {
// Add
Recipes_Type type1 = {
.item = 0,
.tile = 0,
.instance = {
.count = 1,
.id = 12,
.auxiliary = 0
},
.letter = 'a'
};
Recipes_Type type2 = {
.item = 0,
.tile = 0,
.instance = {
.count = 1,
.id = 13,
.auxiliary = 0
},
.letter = 'b'
};
ItemInstance result = {
.count = 1,
.id = 344,
.auxiliary = 0
};
(*Recipes_addShapelessRecipe)(recipes, result, {type1, type2});
}
// Custom Furnace Recipes
static void FurnaceRecipes_injection(unsigned char *recipes) {
// Add
(*FurnaceRecipes_addFurnaceRecipe)(recipes, 49, {.count = 1, .id = 246, .auxiliary = 0});
}
// Init
__attribute__((constructor)) static void init_recipes() {
// Log
INFO("Loading Custom Recipes");
// Setup
misc_run_on_recipes_setup(Recipes_injection);
misc_run_on_furnace_recipes_setup(FurnaceRecipes_injection);
}

View File

@ -1,10 +1,23 @@
project(images)
# Title Background
if(NOT MCPI_SERVER_MODE)
if(NOT MCPI_HEADLESS_MODE)
install(
FILES "background.png"
DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui"
RENAME "titleBG.png"
)
endif()
# Icon
install(
FILES "icon.png"
DESTINATION "${MCPI_SHARE_DIR}/icons/hicolor/scalable/apps"
RENAME "${MCPI_APP_ID}.png"
)
# AppImage
if(MCPI_IS_APPIMAGE_BUILD)
install_symlink("${MCPI_SHARE_DIR}/icons/hicolor/scalable/apps/${MCPI_APP_ID}.png" "${MCPI_APP_ID}.png")
install_symlink("${MCPI_APP_ID}.png" ".DirIcon")
endif()

BIN
images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -1,32 +1,117 @@
project(launcher)
# Dependencies
add_subdirectory(dependencies)
# Launcher
if(BUILD_NATIVE_COMPONENTS)
add_executable(launcher src/bootstrap.c src/patchelf.c)
if(MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c)
else()
target_sources(launcher PRIVATE src/client/launcher.cpp)
endif()
target_link_libraries(launcher reborn-util)
# Install
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
set(ICON_PATH "data/com.thebrokenrail.MCPIReborn.png")
set(ICON_TARGET_PATH "share/icons/hicolor/scalable/apps")
if(NOT MCPI_SERVER_MODE)
install(DIRECTORY "data/client/" DESTINATION ".")
install(
FILES "${ICON_PATH}"
DESTINATION "${ICON_TARGET_PATH}"
RENAME "com.thebrokenrail.MCPIRebornClient.png"
)
else()
install(DIRECTORY "data/server/" DESTINATION ".")
install(
FILES "${ICON_PATH}"
DESTINATION "${ICON_TARGET_PATH}"
RENAME "com.thebrokenrail.MCPIRebornServer.png"
)
endif()
add_executable(launcher src/bootstrap.c src/patchelf.c src/crash-report.c)
if(MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c)
else()
embed_resource(launcher src/client/available-feature-flags)
target_sources(launcher PRIVATE src/client/launcher.cpp)
endif()
target_link_libraries(launcher reborn-util)
# RPath
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
# Install
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
# Install Desktop Entry
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
"[Desktop Entry]\n"
"Name=${MCPI_APP_TITLE}\n"
"Comment=Fun with Blocks\n"
"Icon=${MCPI_APP_ID}\n"
"Exec=${MCPI_VARIANT_NAME}\n"
"Type=Application\n"
"Categories=Game;\n"
)
if(MCPI_HEADLESS_MODE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
"Terminal=true\n"
"NoDisplay=true\n"
)
else()
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
"Terminal=false\n"
"StartupNotify=false\n"
"StartupWMClass=${MCPI_APP_ID}\n"
)
endif()
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
DESTINATION "${MCPI_SHARE_DIR}/applications"
RENAME "${MCPI_APP_ID}.desktop"
)
# Install AppStream Metadata
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<component type=\"desktop\">\n"
" <id>${MCPI_APP_ID}</id>\n"
" <name>${MCPI_APP_TITLE}</name>\n"
" <metadata_license>CC0-1.0</metadata_license>\n"
" <summary>Fun with Blocks</summary>\n"
" <description>\n"
" <p>Minecraft: Pi Edition Modding Project.</p>\n"
" <p>NOTE: This is not verified by, affiliated with, or supported by Mojang or Microsoft.</p>\n"
" </description>\n"
" <url type=\"homepage\">https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn</url>\n"
" <launchable type=\"desktop-id\">${MCPI_APP_ID}.desktop</launchable>\n"
" <provides>\n"
" <id>com.thebrokenrail.MCPIRebornClient.desktop</id>\n"
" </provides>\n"
" <project_license>LicenseRef-proprietary</project_license>\n"
" <developer_name>TheBrokenRail &amp; Mojang AB</developer_name>\n"
" <content_rating type=\"oars-1.0\">\n"
" <content_attribute id=\"violence-cartoon\">moderate</content_attribute>\n"
" <content_attribute id=\"violence-fantasy\">none</content_attribute>\n"
" <content_attribute id=\"violence-realistic\">none</content_attribute>\n"
" <content_attribute id=\"violence-bloodshed\">none</content_attribute>\n"
" <content_attribute id=\"violence-sexual\">none</content_attribute>\n"
" <content_attribute id=\"drugs-alcohol\">none</content_attribute>\n"
" <content_attribute id=\"drugs-narcotics\">none</content_attribute>\n"
" <content_attribute id=\"drugs-tobacco\">none</content_attribute>\n"
" <content_attribute id=\"sex-nudity\">none</content_attribute>\n"
" <content_attribute id=\"sex-themes\">none</content_attribute>\n"
" <content_attribute id=\"language-profanity\">none</content_attribute>\n"
" <content_attribute id=\"language-humor\">none</content_attribute>\n"
" <content_attribute id=\"language-discrimination\">none</content_attribute>\n"
" <content_attribute id=\"social-chat\">intense</content_attribute>\n"
" <content_attribute id=\"social-info\">none</content_attribute>\n"
" <content_attribute id=\"social-audio\">none</content_attribute>\n"
" <content_attribute id=\"social-location\">none</content_attribute>\n"
" <content_attribute id=\"social-contacts\">none</content_attribute>\n"
" <content_attribute id=\"money-purchasing\">none</content_attribute>\n"
" <content_attribute id=\"money-gambling\">none</content_attribute>\n"
" </content_rating>\n"
" <releases>\n"
" <release version=\"${MCPI_VERSION}\" date=\"${MCPI_VERSION_DATE}\"></release>\n"
" </releases>\n"
)
if(NOT MCPI_HEADLESS_MODE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
" <screenshots>\n"
" <screenshot type=\"default\">\n"
" <image>https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn/raw/branch/master/images/start.png</image>\n"
" </screenshot>\n"
" </screenshots>\n"
)
endif()
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
"</component>\n"
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
DESTINATION "${MCPI_SHARE_DIR}/metainfo"
RENAME "${MCPI_APP_ID}.appdata.xml"
)
# AppImage
if(MCPI_IS_APPIMAGE_BUILD)
install_symlink("bin/${MCPI_VARIANT_NAME}" "AppRun")
install_symlink("${MCPI_SHARE_DIR}/applications/${MCPI_APP_ID}.desktop" "${MCPI_APP_ID}.desktop")
endif()

View File

@ -1,10 +0,0 @@
[Desktop Entry]
Name=Minecraft: Pi Edition: Reborn (Client)
Comment=Fun with Blocks
Icon=com.thebrokenrail.MCPIRebornClient
StartupNotify=false
StartupWMClass=Minecraft: Pi Edition: Reborn
Exec=minecraft-pi-reborn-client
Terminal=false
Type=Application
Categories=Game;

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>com.thebrokenrail.MCPIRebornClient</id>
<name>Minecraft: Pi Edition: Reborn (Client)</name>
<metadata_license>CC0-1.0</metadata_license>
<summary>Fun with Blocks</summary>
<description><p>Minecraft: Pi Edition Modding Project.</p><p>NOTE: This is not verified by, affiliated with, or supported by Mojang or Microsoft.</p></description>
<url type="homepage">https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn</url>
<screenshots>
<screenshot type="default">
<image>https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn/raw/branch/master/images/start.png</image>
</screenshot>
</screenshots>
<launchable type="desktop-id">com.thebrokenrail.MCPIRebornClient.desktop</launchable>
<provides>
<id>com.thebrokenrail.MCPIRebornClient.desktop</id>
</provides>
<project_license>LicenseRef-proprietary</project_license>
<developer_name>TheBrokenRail &amp; Mojang AB</developer_name>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">moderate</content_attribute>
<content_attribute id="violence-fantasy">none</content_attribute>
<content_attribute id="violence-realistic">none</content_attribute>
<content_attribute id="violence-bloodshed">none</content_attribute>
<content_attribute id="violence-sexual">none</content_attribute>
<content_attribute id="drugs-alcohol">none</content_attribute>
<content_attribute id="drugs-narcotics">none</content_attribute>
<content_attribute id="drugs-tobacco">none</content_attribute>
<content_attribute id="sex-nudity">none</content_attribute>
<content_attribute id="sex-themes">none</content_attribute>
<content_attribute id="language-profanity">none</content_attribute>
<content_attribute id="language-humor">none</content_attribute>
<content_attribute id="language-discrimination">none</content_attribute>
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-info">none</content_attribute>
<content_attribute id="social-audio">none</content_attribute>
<content_attribute id="social-location">none</content_attribute>
<content_attribute id="social-contacts">none</content_attribute>
<content_attribute id="money-purchasing">none</content_attribute>
<content_attribute id="money-gambling">none</content_attribute>
</content_rating>
</component>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

View File

@ -1,9 +0,0 @@
[Desktop Entry]
Name=Minecraft: Pi Edition: Reborn (Server)
Comment=Fun with Blocks
Icon=com.thebrokenrail.MCPIRebornServer
Exec=minecraft-pi-reborn-server
Terminal=true
Type=Application
Categories=Game;
NoDisplay=true

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>com.thebrokenrail.MCPIRebornServer</id>
<name>Minecraft: Pi Edition: Reborn (Server)</name>
<metadata_license>CC0-1.0</metadata_license>
<summary>Fun with Blocks</summary>
<description><p>Minecraft: Pi Edition Modding Project.</p><p>NOTE: This is not verified by, affiliated with, or supported by Mojang or Microsoft.</p></description>
<url type="homepage">https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn</url>
<launchable type="desktop-id">com.thebrokenrail.MCPIRebornServer.desktop</launchable>
<provides>
<id>com.thebrokenrail.MCPIRebornServer.desktop</id>
</provides>
<project_license>LicenseRef-proprietary</project_license>
<developer_name>TheBrokenRail &amp; Mojang AB</developer_name>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">moderate</content_attribute>
<content_attribute id="violence-fantasy">none</content_attribute>
<content_attribute id="violence-realistic">none</content_attribute>
<content_attribute id="violence-bloodshed">none</content_attribute>
<content_attribute id="violence-sexual">none</content_attribute>
<content_attribute id="drugs-alcohol">none</content_attribute>
<content_attribute id="drugs-narcotics">none</content_attribute>
<content_attribute id="drugs-tobacco">none</content_attribute>
<content_attribute id="sex-nudity">none</content_attribute>
<content_attribute id="sex-themes">none</content_attribute>
<content_attribute id="language-profanity">none</content_attribute>
<content_attribute id="language-humor">none</content_attribute>
<content_attribute id="language-discrimination">none</content_attribute>
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-info">none</content_attribute>
<content_attribute id="social-audio">none</content_attribute>
<content_attribute id="social-location">none</content_attribute>
<content_attribute id="social-contacts">none</content_attribute>
<content_attribute id="money-purchasing">none</content_attribute>
<content_attribute id="money-gambling">none</content_attribute>
</content_rating>
</component>

View File

@ -0,0 +1,4 @@
project(launcher-dependencies)
# PatchELF
add_subdirectory(patchelf)

View File

@ -0,0 +1,17 @@
project(patchelf)
# Silence Warnings
add_compile_options(-w)
## PatchELF
# Build
add_executable(patchelf src/src/patchelf.cc)
target_compile_definitions(patchelf PRIVATE -D_FILE_OFFSET_BITS=64)
set_target_properties(patchelf PROPERTIES CXX_STANDARD 17)
# Install
install(TARGETS patchelf DESTINATION "${MCPI_BIN_DIR}")
# License
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/patchelf")

@ -0,0 +1 @@
Subproject commit c2b419dc2a0d6095eaa69b65ad5854ce847bdd01

View File

@ -12,58 +12,7 @@
#include "bootstrap.h"
#include "patchelf.h"
// Set Environmental Variable
#define PRESERVE_ENVIRONMENTAL_VARIABLE(name) \
{ \
char *original_env_value = getenv(name); \
if (original_env_value != NULL) { \
setenv("ORIGINAL_" name, original_env_value, 1); \
} \
}
static void trim(char **value) {
// Remove Trailing Colon
int length = strlen(*value);
if ((*value)[length - 1] == ':') {
(*value)[length - 1] = '\0';
}
if ((*value)[0] == ':') {
*value = &(*value)[1];
}
}
void set_and_print_env(const char *name, char *value) {
// Set Variable With No Trailing Colon
static const char *unmodified_name_prefix = "MCPI_";
if (!starts_with(name, unmodified_name_prefix)) {
trim(&value);
}
// Print New Value
DEBUG("Set %s = %s", name, value);
// Set The Value
setenv(name, value, 1);
}
#ifndef __ARM_ARCH
#define PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU(name) \
{ \
char *old_value = getenv("QEMU_SET_ENV"); \
char *new_value = NULL; \
/* Pass Variable */ \
safe_asprintf(&new_value, "%s%s%s=%s", old_value == NULL ? "" : old_value, old_value == NULL ? "" : ",", name, getenv(name)); \
setenv("QEMU_SET_ENV", new_value, 1); \
free(new_value); \
/* Reset Variable */ \
RESET_ENVIRONMENTAL_VARIABLE(name); \
}
#endif
// Get Environmental Variable
static char *get_env_safe(const char *name) {
// Get Variable Or Blank String If Not Set
char *ret = getenv(name);
return ret != NULL ? ret : "";
}
#include "crash-report.h"
// Get All Mods In Folder
static void load(char **ld_preload, char *folder) {
@ -97,14 +46,14 @@ static void load(char **ld_preload, char *folder) {
// Add Terminator
name[total_length] = '\0';
// Check If File Is Executable
// Check If File Is Accessible
int result = access(name, R_OK);
if (result == 0) {
// Add To LD_PRELOAD
string_append(ld_preload, ":%s", name);
string_append(ld_preload, "%s%s", *ld_preload == NULL ? "" : ":", name);
} else if (result == -1 && errno != 0) {
// Fail
INFO("Unable To Acesss: %s: %s", name, strerror(errno));
WARN("Unable To Access: %s: %s", name, strerror(errno));
errno = 0;
}
}
@ -139,18 +88,55 @@ static void load(char **ld_preload, char *folder) {
#define MCPI_BINARY "minecraft-pi"
#define QEMU_BINARY "qemu-arm"
// Exit Handler
static void exit_handler(__attribute__((unused)) int signal_id) {
// Pass Signal To Child
murder_children();
while (wait(NULL) > 0) {}
_exit(EXIT_SUCCESS);
}
// Pre-Bootstrap
void pre_bootstrap() {
void pre_bootstrap(int argc, char *argv[]) {
// Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0);
// Set Default Native Component Environment
#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name));
for_each_special_environmental_variable(set_variable_default);
// Print Version
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
// Print
printf("Reborn v%s\n", MCPI_VERSION);
fflush(stdout);
exit(EXIT_SUCCESS);
}
}
// GTK Dark Mode
#ifndef MCPI_HEADLESS_MODE
#ifndef MCPI_SERVER_MODE
set_and_print_env("GTK_THEME", "Adwaita:dark");
#endif
// Debug Zenity
#ifndef MCPI_SERVER_MODE
{
const char *is_debug = getenv("MCPI_DEBUG");
if (is_debug != NULL && strlen(is_debug) > 0) {
set_and_print_env("ZENITY_DEBUG", "1");
}
}
#endif
// AppImage
#ifdef MCPI_IS_APPIMAGE_BUILD
char *owd = getenv("OWD");
if (owd != NULL && chdir(owd) != 0) {
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
{
char *owd = getenv("OWD");
if (owd != NULL && chdir(owd) != 0) {
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
}
}
#endif
@ -160,12 +146,12 @@ void pre_bootstrap() {
// Configure PATH
{
// Add Library Directory
char *new_path;
char *new_path = NULL;
safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH
{
char *value = get_env_safe("PATH");
if (strlen(value) > 0) {
char *value = getenv("PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&new_path, ":%s", value);
}
}
@ -176,6 +162,63 @@ void pre_bootstrap() {
// Free Binary Directory
free(binary_directory);
// Setup Crash Reports
setup_crash_report();
// Install Signal Handlers
struct sigaction act_sigint;
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
}
// Copy SDK Into ~/.minecraft-pi
static void run_simple_command(const char *const command[], const char *error) {
int status = 0;
char *output = run_command(command, &status);
if (output != NULL) {
free(output);
}
if (!is_exit_status_success(status)) {
ERR("%s", error);
}
}
static void copy_sdk(char *binary_directory) {
// Output Directory
char *output = NULL;
safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk/" MCPI_SDK_DIR, getenv("HOME"));
// Source Directory
char *source = NULL;
safe_asprintf(&source, "%s/sdk/.", binary_directory);
// Clean
{
const char *const command[] = {"rm", "-rf", output, NULL};
run_simple_command(command, "Unable To Clean SDK Output Directory");
}
// Make Directory
{
const char *const command[] = {"mkdir", "-p", output, NULL};
run_simple_command(command, "Unable To Create SDK Output Directory");
}
// Copy
{
const char *const command[] = {"cp", "-ar", source, output, NULL};
run_simple_command(command, "Unable To Copy SDK");
}
// Free
free(output);
free(source);
}
// Bootstrap
@ -185,29 +228,8 @@ void bootstrap(int argc, char *argv[]) {
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Resolve Binary Path & Set MCPI_DIRECTORY
{
// Log
DEBUG("Resolving File Paths...");
// Resolve Full Binary Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
char *resolved_path = realpath(full_path, NULL);
ALLOC_CHECK(resolved_path);
free(full_path);
// Set MCPI_EXECUTABLE_PATH
set_and_print_env("MCPI_EXECUTABLE_PATH", resolved_path);
// Set MCPI_VANILLA_ASSETS_PATH
{
chop_last_component(&resolved_path);
string_append(&resolved_path, "/data");
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", resolved_path);
free(resolved_path);
}
}
// Copy SDK
copy_sdk(binary_directory);
// Set MCPI_REBORN_ASSETS_PATH
{
@ -219,7 +241,22 @@ void bootstrap(int argc, char *argv[]) {
free(assets_path);
}
// Resolve Binary Path & Set MCPI_DIRECTORY
char *resolved_path = NULL;
{
// Log
DEBUG("Resolving File Paths...");
// Resolve Full Binary Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
resolved_path = realpath(full_path, NULL);
ALLOC_CHECK(resolved_path);
free(full_path);
}
// Fix MCPI Dependencies
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
{
// Log
DEBUG("Patching ELF Dependencies...");
@ -227,7 +264,7 @@ void bootstrap(int argc, char *argv[]) {
// Find Linker
char *linker = NULL;
// Select Linker
#ifndef __arm__
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
// Use ARM Sysroot Linker
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
#else
@ -239,7 +276,7 @@ void bootstrap(int argc, char *argv[]) {
#endif
// Patch
patch_mcpi_elf_dependencies(linker);
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
// Free Linker Path
if (linker != NULL) {
@ -247,83 +284,140 @@ void bootstrap(int argc, char *argv[]) {
}
// Verify
if (!starts_with(getenv("MCPI_EXECUTABLE_PATH"), "/tmp")) {
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
IMPOSSIBLE();
}
}
// Configure LD_LIBRARY_PATH
// Set MCPI_VANILLA_ASSETS_PATH
{
char *assets_path = strdup(resolved_path);
ALLOC_CHECK(assets_path);
chop_last_component(&assets_path);
string_append(&assets_path, "/data");
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
free(assets_path);
}
// Free Resolved Path
free(resolved_path);
// Configure Library Search Path
{
// Log
DEBUG("Setting Linker Search Paths...");
// Preserve
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_LIBRARY_PATH");
char *new_ld_path = NULL;
// Prepare
char *transitive_ld_path = NULL;
char *mcpi_ld_path = NULL;
// Add Library Directory
safe_asprintf(&new_ld_path, "%s/lib", binary_directory);
// Add ARM Sysroot Libraries (Ensure Priority) (Ignroe On Actual ARM System)
#ifndef __arm__
string_append(&new_ld_path, ":%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory);
#endif
// Add LD_LIBRARY_PATH
// Library Search Path For Native Components
{
char *value = get_env_safe("LD_LIBRARY_PATH");
if (strlen(value) > 0) {
string_append(&new_ld_path, ":%s", value);
// Add Native Library Directory
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&transitive_ld_path, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path);
free(transitive_ld_path);
}
// Set And Free
set_and_print_env("LD_LIBRARY_PATH", new_ld_path);
free(new_ld_path);
// Library Search Path For ARM Components
{
// Add ARM Library Directory
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory);
#endif
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&mcpi_ld_path, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
free(mcpi_ld_path);
}
// Setup iconv
{
// Native Components
char *host_gconv_path = getenv("GCONV_PATH");
set_and_print_env("MCPI_NATIVE_GCONV_PATH", host_gconv_path);
// ARM Components
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
char *gconv_path = NULL;
safe_asprintf(&gconv_path, "%s/sysroot/usr/lib/gconv", binary_directory);
set_and_print_env("MCPI_ARM_GCONV_PATH", gconv_path);
free(gconv_path);
#else
set_and_print_env("MCPI_ARM_GCONV_PATH", host_gconv_path);
#endif
}
}
// Configure LD_PRELOAD
// Configure Preloaded Objects
{
// Log
DEBUG("Locating Mods...");
// Preserve
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
char *new_ld_preload = NULL;
// Native Components
char *host_ld_preload = getenv("LD_PRELOAD");
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
// ~/.minecraft-pi/mods
// ARM Components
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
// Load Mods From ./mods
load(&new_ld_preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Prepare
char *preload = NULL;
// Built-In Mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
// Load Mods From ./mods
load(&new_ld_preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Add LD_PRELOAD
{
char *value = get_env_safe("LD_PRELOAD");
if (strlen(value) > 0) {
string_append(&new_ld_preload, ":%s", value);
// ~/.minecraft-pi/mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
// Load Mods From ./mods
load(&preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
}
// Set LD_PRELOAD
set_and_print_env("LD_PRELOAD", new_ld_preload);
free(new_ld_preload);
// Built-In Mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
// Load Mods From ./mods
load(&preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Add LD_PRELOAD
{
char *value = getenv("LD_PRELOAD");
if (value != NULL && strlen(value) > 0) {
string_append(&preload, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_ARM_LD_PRELOAD", preload);
free(preload);
}
}
// Free Binary Directory
@ -344,16 +438,26 @@ void bootstrap(int argc, char *argv[]) {
new_args[argv_start + argc] = NULL;
// Set Executable Argument
new_args[argv_start] = getenv("MCPI_EXECUTABLE_PATH");
new_args[argv_start] = new_mcpi_exe_path;
// Non-ARM Systems Need QEMU
#ifndef __ARM_ARCH
argv_start--;
new_args[argv_start] = QEMU_BINARY;
#endif
// Prevent QEMU From Being Modded
PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU("LD_LIBRARY_PATH");
PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU("LD_PRELOAD");
// Setup Environment
setup_exec_environment(1);
// Pass LD_* Variables Through QEMU
#ifndef __ARM_ARCH
char *qemu_set_env = NULL;
#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name));
for_each_special_environmental_variable(pass_variable_through_qemu);
set_and_print_env("QEMU_SET_ENV", qemu_set_env);
free(qemu_set_env);
// Treat QEMU Itself As A Native Component
setup_exec_environment(0);
#endif
// Run

View File

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

View File

@ -29,7 +29,7 @@ TRUE Close Current Screen On Death
FALSE Disable Raw Mouse Motion (Not Recommended)
TRUE Fix Furnace Not Checking Item Auxiliary
TRUE Improved Cursor Rendering
FALSE Disable V-Sync
TRUE Disable V-Sync
TRUE Fix Options Screen
TRUE Force Touch GUI Inventory
TRUE Fix Pause Menu
@ -37,3 +37,8 @@ TRUE Improved Title Background
TRUE Force Touch GUI Button Behavior
TRUE Improved Button Hover Behavior
TRUE Implement Create World Dialog
FALSE Remove Forced GUI Lag (Can Break Joining Servers)
TRUE Add Buckets
TRUE Classic HUD
TRUE Translucent Toolbar
FALSE Force EGL

View File

@ -1,4 +1,4 @@
#include <fstream>
#include <sstream>
#include <cstring>
#include <cerrno>
#include <sys/wait.h>
@ -36,46 +36,44 @@ static std::string strip_feature_flag_default(std::string flag, bool *default_re
}
// Load Available Feature Flags
extern unsigned char available_feature_flags[];
extern size_t available_feature_flags_len;
static void load_available_feature_flags(std::function<void(std::string)> callback) {
// Get Path
char *binary_directory = get_binary_directory();
std::string path = std::string(binary_directory) + "/available-feature-flags";
free(binary_directory);
// Load File
std::ifstream stream(path);
if (stream && stream.good()) {
std::vector<std::string> lines;
// Read File
{
std::string line;
while (std::getline(stream, line)) {
if (line.length() > 0) {
// Verify Line
if (line.find('|') == std::string::npos) {
lines.push_back(line);
} else {
// Invalid Line
ERR("Feature Flag Contains Invalid '|'");
}
std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len);
std::stringstream stream(data);
// Store Lines
std::vector<std::string> lines;
// Read File
{
std::string line;
while (std::getline(stream, line)) {
if (line.length() > 0) {
// Verify Line
if (line.find('|') == std::string::npos) {
lines.push_back(line);
} else {
// Invalid Line
ERR("Feature Flag Contains Invalid '|'");
}
}
}
}
// Sort
std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) {
// Strip Defaults
std::string stripped_a = strip_feature_flag_default(a, NULL);
std::string stripped_b = strip_feature_flag_default(b, NULL);
// Sort
std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) {
// Strip Defaults
std::string stripped_a = strip_feature_flag_default(a, NULL);
std::string stripped_b = strip_feature_flag_default(b, NULL);
// Sort
return stripped_a < stripped_b;
});
// Run Callbacks
for (std::string line : lines) {
callback(line);
}
// Close File
stream.close();
} else {
ERR("Unable To Load Available Feature Flags");
return stripped_a < stripped_b;
});
// Run Callbacks
for (std::string &line : lines) {
callback(line);
}
}
@ -98,19 +96,23 @@ static void run_command_and_set_env(const char *env_name, const char *command[])
free(output);
}
// Check Return Code
if (return_code != 0) {
ERR("Launch Interrupted");
if (!is_exit_status_success(return_code)) {
INFO("Launch Interrupted");
exit(EXIT_SUCCESS);
}
}
}
// Use Zenity To Set Environmental Variable
#define DIALOG_TITLE "Launcher"
static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
// Create Full Command
std::vector<std::string> full_command;
full_command.push_back("zenity");
full_command.push_back("--class");
full_command.push_back(GUI_TITLE);
full_command.push_back("--title");
full_command.push_back(DIALOG_TITLE);
full_command.push_back("--name");
full_command.push_back(MCPI_APP_ID);
full_command.insert(full_command.end(), command.begin(), command.end());
// Convert To C Array
const char *full_command_array[full_command.size() + 1];
@ -122,11 +124,30 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
run_command_and_set_env(env_name, full_command_array);
}
// Set Variable If Not Already Set
static void set_env_if_unset(const char *env_name, std::function<std::string()> callback) {
if (getenv(env_name) == NULL) {
char *value = strdup(callback().c_str());
ALLOC_CHECK(value);
set_and_print_env(env_name, value);
free(value);
}
}
// Defaults
#define DEFAULT_USERNAME "StevePi"
#define DEFAULT_RENDER_DISTANCE "Short"
// Launch
#define LIST_DIALOG_SIZE "400"
int main(int argc, char *argv[]) {
// Don't Run As Root
if (getenv("_MCPI_SKIP_ROOT_CHECK") == NULL && (getuid() == 0 || geteuid() == 0)) {
ERR("Don't Run As Root");
}
// Pre-Bootstrap
pre_bootstrap();
pre_bootstrap(argc, argv);
// Print Features
for (int i = 1; i < argc; i++) {
@ -140,6 +161,37 @@ int main(int argc, char *argv[]) {
}
}
// --default
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--default") == 0) {
// Use Default Feature Flags
set_env_if_unset("MCPI_FEATURE_FLAGS", []() {
std::string feature_flags = "";
load_available_feature_flags([&feature_flags](std::string flag) {
bool default_value;
// Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &default_value);
// Specify Default Value
if (default_value) {
// Enabled By Default
feature_flags += stripped_flag + '|';
}
});
if (feature_flags.length() > 0 && feature_flags[feature_flags.length() - 1] == '|') {
feature_flags.pop_back();
}
return feature_flags;
});
set_env_if_unset("MCPI_RENDER_DISTANCE", []() {
return DEFAULT_RENDER_DISTANCE;
});
set_env_if_unset("MCPI_USERNAME", []() {
return DEFAULT_USERNAME;
});
break;
}
}
// Create ~/.minecraft-pi If Needed
// Minecraft Folder
{
@ -206,14 +258,11 @@ int main(int argc, char *argv[]) {
command.push_back("Selected");
command.push_back("--column");
command.push_back("Name");
command.push_back("FALSE");
command.push_back("Far");
command.push_back("FALSE");
command.push_back("Normal");
command.push_back("TRUE");
command.push_back("Short");
command.push_back("FALSE");
command.push_back("Tiny");
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
for (std::string &render_distance : render_distances) {
command.push_back(render_distance.compare(DEFAULT_RENDER_DISTANCE) == 0 ? "TRUE" : "FALSE");
command.push_back(render_distance);
}
// Run
run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command);
}
@ -224,7 +273,7 @@ int main(int argc, char *argv[]) {
command.push_back("--text");
command.push_back("Enter Minecraft Username:");
command.push_back("--entry-text");
command.push_back("StevePi");
command.push_back(DEFAULT_USERNAME);
// Run
run_zenity_and_set_env("MCPI_USERNAME", command);
}

246
launcher/src/crash-report.c Normal file
View File

@ -0,0 +1,246 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <libreborn/libreborn.h>
#include "crash-report.h"
// Show Crash Report Dialog
#ifndef MCPI_HEADLESS_MODE
#define DIALOG_TITLE "Crash Report"
#define CRASH_REPORT_DIALOG_WIDTH "640"
#define CRASH_REPORT_DIALOG_HEIGHT "480"
static void show_report(const char *log_filename) {
const char *command[] = {
"zenity",
"--title", DIALOG_TITLE,
"--name", MCPI_APP_ID,
"--width", CRASH_REPORT_DIALOG_WIDTH,
"--height", CRASH_REPORT_DIALOG_HEIGHT,
"--text-info",
"--text", "Minecraft: Pi Edition: Reborn has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>!",
"--filename", log_filename,
"--no-wrap",
"--font", "Monospace",
NULL
};
free(run_command(command, NULL));
}
#endif
// Exit Handler
static void exit_handler(__attribute__((unused)) int signal) {
// Murder
murder_children();
}
// Setup
#define PIPE_READ 0
#define PIPE_WRITE 1
#define MCPI_LOGS_DIR "/tmp/.minecraft-pi-logs"
void setup_crash_report() {
// Store Output
int output_pipe[2];
safe_pipe2(output_pipe, 0);
int error_pipe[2];
safe_pipe2(error_pipe, 0);
int input_pipe[2];
safe_pipe2(input_pipe, 0);
// Fork
pid_t ret = fork();
if (ret == -1) {
ERR("Unable To Fork: %s", strerror(errno));
} else if (ret == 0) {
// Child Process
// Pipe stdio
dup2(output_pipe[PIPE_WRITE], STDOUT_FILENO);
close(output_pipe[PIPE_READ]);
close(output_pipe[PIPE_WRITE]);
dup2(error_pipe[PIPE_WRITE], STDERR_FILENO);
close(error_pipe[PIPE_READ]);
close(error_pipe[PIPE_WRITE]);
dup2(input_pipe[PIPE_READ], STDIN_FILENO);
close(input_pipe[PIPE_READ]);
close(input_pipe[PIPE_WRITE]);
// Create New Process Group
setpgid(0, 0);
// Continue Execution
} else {
// Parent Process
track_child(ret);
// Install Signal Handlers
struct sigaction act_sigint;
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
// Close Unneeded File Descriptors
close(output_pipe[PIPE_WRITE]);
close(error_pipe[PIPE_WRITE]);
close(input_pipe[PIPE_READ]);
// Setup Logging
#define BUFFER_SIZE 1024
char buf[BUFFER_SIZE];
// Ensure Temporary Directory
{
// Check If It Exists
struct stat tmp_stat;
int exists = stat(MCPI_LOGS_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) {
// Doesn't Exist
if (mkdir(MCPI_LOGS_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
}
}
}
// Create Temporary File
char log_filename[] = MCPI_LOGS_DIR "/XXXXXX";
int log_file_fd = mkstemp(log_filename);
if (log_file_fd == -1) {
ERR("Unable To Create Log File: %s", strerror(errno));
}
// Setup Polling
int number_fds = 3;
struct pollfd poll_fds[number_fds];
poll_fds[0].fd = output_pipe[PIPE_READ];
poll_fds[1].fd = error_pipe[PIPE_READ];
poll_fds[2].fd = STDIN_FILENO;
for (int i = 0; i < number_fds; i++) {
poll_fds[i].events = POLLIN;
}
// Poll Data
int number_open_fds = number_fds;
while (number_open_fds > 0) {
int poll_ret = poll(poll_fds, number_fds, -1);
if (poll_ret == -1) {
if (errno == EINTR) {
continue;
} else {
ERR("Unable To Poll Data: %s", strerror(errno));
}
}
// Handle Data
for (int i = 0; i < number_fds; i++) {
if (poll_fds[i].revents != 0) {
if (poll_fds[i].revents & POLLIN) {
if (poll_fds[i].fd == STDIN_FILENO) {
// Data Available From stdin
int bytes_available;
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
bytes_available = 0;
}
// Read
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE);
if (bytes_read == -1) {
ERR("Unable To Read Log Data: %s", strerror(errno));
}
// Write To Child
if (write(input_pipe[PIPE_WRITE], (void *) buf, bytes_read) == -1) {
ERR("Unable To Write Input To Child: %s", strerror(errno));
}
} else {
// Data Available From Child's stdout/stderr
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
if (bytes_read == -1) {
ERR("Unable To Read Log Data: %s", strerror(errno));
}
// Print To Terminal
buf[bytes_read] = '\0';
fprintf(i == 0 ? stdout : stderr, "%s", buf);
// Write To log
if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
ERR("Unable To Write Log Data: %s", strerror(errno));
}
}
} else {
// File Descriptor No Longer Accessible
if (poll_fds[i].events != 0 && close(poll_fds[i].fd) == -1) {
ERR("Unable To Close File Descriptor: %s", strerror(errno));
}
poll_fds[i].events = 0;
number_open_fds--;
}
}
}
}
// Close Input Pipe
close(input_pipe[PIPE_WRITE]);
// Get Return Code
int status;
waitpid(ret, &status, 0);
untrack_child(ret);
// Check If Is Crash
int is_crash = !is_exit_status_success(status);
// Log Exit Code To log If Crash
if (is_crash) {
// Create Exit Code Log Line
char *exit_status = NULL;
get_exit_status_string(status, &exit_status);
char *exit_code_line = NULL;
safe_asprintf(&exit_code_line, "[CRASH]: Terminated%s\n", exit_status);
free(exit_status);
// Print Exit Code Log Line
fprintf(stderr, "%s", exit_code_line);
// Write Exit Code Log Line
if (write(log_file_fd, (void *) exit_code_line, strlen(exit_code_line)) == -1) {
ERR("Unable To Write Exit Code To Log: %s", strerror(errno));
}
// Free Exit Code Log Line
free(exit_code_line);
}
// Close Log File FD
if (close(log_file_fd) == -1) {
ERR("Unable To Close Log File Descriptor: %s", strerror(errno));
}
// Show Crash Log
#ifndef MCPI_HEADLESS_MODE
if (is_crash) {
show_report(log_filename);
}
#endif
// Delete Log File
if (unlink(log_filename) == -1) {
ERR("Unable To Delete Log File: %s", strerror(errno));
}
// Exit
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
}
}

View File

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

View File

@ -8,26 +8,21 @@
#include "patchelf.h"
// Duplicate MCPI Executable Into /tmp
#define TMP_DIR "/tmp/.minecraft-pi-tmp"
static void duplicate_mcpi_executable() {
// Get Original Path
const char *original_path = getenv("MCPI_EXECUTABLE_PATH");
static void duplicate_mcpi_executable(const char *original_path, char *new_path) {
// Ensure Temporary Directory
{
// Check If It Exists
struct stat tmp_stat;
int exists = stat(TMP_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) {
// Doesn't Exist
if (mkdir(TMP_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
}
}
}
// Generate New File
char new_path[] = TMP_DIR "/XXXXXX";
int new_file_fd = mkstemp(new_path);
if (new_file_fd == -1) {
ERR("Unable To Create Temporary File: %s", strerror(errno));
@ -36,7 +31,6 @@ static void duplicate_mcpi_executable() {
if (new_file == NULL) {
ERR("Unable To Open Temporary File: %s", strerror(errno));
}
set_and_print_env("MCPI_EXECUTABLE_PATH", new_path);
// Copy Original File
{
@ -78,8 +72,10 @@ static void duplicate_mcpi_executable() {
"--remove-needed", "libbcm_host.so", \
"--remove-needed", "libX11.so.6", \
"--remove-needed", "libEGL.so", \
"--replace-needed", "libGLESv2.so", "libGLESv1_CM.so.1", \
exe, \
"--remove-needed", "libGLESv2.so", \
"--remove-needed", "libSDL-1.2.so.0", \
"--add-needed", "libmedia-layer-core.so", \
new_path, \
NULL \
}; \
int _macro_return_code = 0; \
@ -89,12 +85,9 @@ static void duplicate_mcpi_executable() {
} \
_macro_return_code; \
})
void patch_mcpi_elf_dependencies(const char *linker) {
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
// Duplicate MCPI executable into /tmp so it can be modified.
duplicate_mcpi_executable();
// Get Path
char *exe = getenv("MCPI_EXECUTABLE_PATH");
duplicate_mcpi_executable(original_path, new_path);
// Run patchelf
int return_code;
@ -103,13 +96,15 @@ void patch_mcpi_elf_dependencies(const char *linker) {
} else {
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args("--set-interpreter", linker);
}
if (return_code != 0) {
ERR("patchelf Failed: Exit Code: %i", return_code);
if (!is_exit_status_success(return_code)) {
char *exit_status_line = NULL;
get_exit_status_string(return_code, &exit_status_line);
ERR("patchelf Failed%s", exit_status_line);
}
// Fix Permissions
if (chmod(exe, S_IRUSR | S_IXUSR) != 0) {
ERR("Unable To Set File Permissions: %s: %s", exe, strerror(errno));
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
}
}
@ -122,7 +117,13 @@ char *patch_get_interpreter(const char *file) {
file,
NULL
};
char *output = run_command(command, NULL);
int return_code;
char *output = run_command(command, &return_code);
if (!is_exit_status_success(return_code)) {
char *exit_status_line = NULL;
get_exit_status_string(return_code, &exit_status_line);
ERR("patchelf Failed%s", exit_status_line);
}
if (output != NULL) {
// Trim
int length = strlen(output);

View File

@ -4,7 +4,9 @@
extern "C" {
#endif
void patch_mcpi_elf_dependencies(const char *linker);
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker);
char *patch_get_interpreter(const char *file);
#ifdef __cplusplus

View File

@ -1,11 +1,13 @@
#include <stdlib.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "../bootstrap.h"
int main(int argc, char *argv[]) {
// Pre-Bootstrap
pre_bootstrap();
pre_bootstrap(argc, argv);
// Set Home To Current Directory, So World Data Is Stored There
char *launch_directory = getcwd(NULL, 0);

View File

@ -1,12 +1,34 @@
project(libreborn)
add_library(reborn-util STATIC src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c)
target_include_directories(reborn-util PUBLIC include)
# Config
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn")
configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
# Util
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c)
target_include_directories(
reborn-util
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/libreborn>"
)
# Install
install(TARGETS reborn-util DESTINATION "${MCPI_LIB_DIR}")
# SDK
if(BUILD_ARM_COMPONENTS)
install(TARGETS reborn-util EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
endif()
# Patch
if(BUILD_ARM_COMPONENTS)
add_library(reborn-patch SHARED src/patch/patch.c)
target_link_libraries(reborn-patch dl reborn-util)
target_link_libraries(reborn-patch dl pthread reborn-util)
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
# Install
install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}")
# SDK
install(TARGETS reborn-patch EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()

View File

@ -1,3 +0,0 @@
#pragma once
#define GUI_TITLE "Minecraft: Pi Edition: Reborn"

View File

@ -0,0 +1,11 @@
#pragma once
#cmakedefine MCPI_SERVER_MODE
#cmakedefine MCPI_HEADLESS_MODE
#cmakedefine MCPI_IS_APPIMAGE_BUILD
#cmakedefine MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
#cmakedefine MCPI_USE_GLES1_COMPATIBILITY_LAYER
#cmakedefine MCPI_APP_TITLE "@MCPI_APP_TITLE@"
#cmakedefine MCPI_APP_ID "@MCPI_APP_ID@"
#cmakedefine MCPI_VERSION "@MCPI_VERSION@"
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"

View File

@ -13,9 +13,9 @@
extern "C" {
#endif
// Find And Iterate Over All .text Sections In Current Binary
typedef void (*text_section_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
void iterate_text_sections(const char *exe, text_section_callback_t callback, void *data);
// Find And Iterate Over All Segments In Current Binary
typedef void (*segment_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
void iterate_segments(segment_callback_t callback, void *data);
#ifdef __cplusplus
}

View File

@ -6,6 +6,7 @@
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include "log.h"
#include "string.h"
@ -15,7 +16,15 @@
extern "C" {
#endif
// Set Environmental Variable
void set_and_print_env(const char *name, const char *value);
// Safe execvpe()
#define for_each_special_environmental_variable(handle) \
handle("LD_LIBRARY_PATH"); \
handle("GCONV_PATH"); \
handle("LD_PRELOAD");
void setup_exec_environment(int is_arm_component);
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
// Chop Off Last Component
@ -23,11 +32,17 @@ void chop_last_component(char **str);
// Get Binary Directory (Remember To Free)
char *get_binary_directory();
// Safe execvpe() Relative To Binary
__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]);
// Run Command And Get Output
char *run_command(const char *const command[], int *return_code);
char *run_command(const char *const command[], int *exit_status);
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)
// Get Exit Status String
void get_exit_status_string(int status, char **out);
// Track Children
void track_child(pid_t pid);
void untrack_child(pid_t pid);
void murder_children();
#ifdef __cplusplus
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "config.h"
#include <libreborn/config.h>
#include "log.h"
#include "util.h"
#include "string.h"

View File

@ -3,23 +3,9 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
// Colors
char *color_reset();
char *color_yellow();
char *color_faint();
char *color_red();
// Logging
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "%s[WARN]: " format "%s\n", color_yellow(), ##__VA_ARGS__, color_reset()); }
#define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL && strlen(debug) > 0) { fprintf(stderr, "%s[DEBUG]: " format "%s\n", color_faint(), ##__VA_ARGS__, color_reset()); } }
#define ERR(format, ...) { fprintf(stderr, "%s[ERR]: (%s:%i): " format "%s\n", color_red(), __FILE__, __LINE__, ##__VA_ARGS__, color_reset()); exit(EXIT_FAILURE); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
#define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: " format "\n", ##__VA_ARGS__); } }
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("This Should Never Be Called")
#ifdef __cplusplus
}
#endif

View File

@ -14,6 +14,8 @@ void _overwrite_call(const char *file, int line, void *start, void *target);
void _overwrite_calls(const char *file, int line, void *start, void *target);
#define overwrite_calls(start, target) _overwrite_calls(__FILE__, __LINE__, start, target);
void *extract_from_bl_instruction(unsigned char *from);
void _overwrite(const char *file, int line, void *start, void *target);
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);

View File

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

View File

@ -25,30 +25,21 @@
dlerror(); \
real_##name = (name##_t) dlsym(RTLD_NEXT, #name); \
if (!real_##name) { \
ERR("Error Resolving Symbol: "#name": %s", dlerror()); \
ERR("Error Resolving Symbol: " #name ": %s", dlerror()); \
} \
} \
} \
\
__attribute__((__used__)) return_type name args
// Macro To Reset Environmental Variables To Pre-MCPI State
#define RESET_ENVIRONMENTAL_VARIABLE(name) \
{ \
char *original_env_value = getenv("ORIGINAL_" name); \
if (original_env_value != NULL) { \
setenv(name, original_env_value, 1); \
} else { \
unsetenv(name); \
} \
}
#ifdef __cplusplus
extern "C" {
#endif
// Safe Version Of pipe()
void safe_pipe2(int pipefd[2], int flags);
// Check If Two Percentages Are Different Enough To Be Logged
int is_progress_difference_significant(int32_t new_val, int32_t old_val);
#ifdef __cplusplus
}

View File

@ -72,6 +72,12 @@ static unsigned char *code_block = NULL;
#define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE;
static void _long_overwrite(void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(NULL, -1, start, patch_data);
_patch_address(NULL, -1, (void *) (((unsigned char *) start) + 4), target);
}
static void update_code_block(void *target) {
// BL Instructions Can Only Access A Limited Portion of Memory, So This Allocates Memory Closer To The Original Instruction, That When Run, Will Jump Into The Actual Target
if (code_block == NULL) {
@ -84,26 +90,31 @@ static void update_code_block(void *target) {
if (code_block_remaining < CODE_SIZE) {
ERR("Maximum Amount Of overwrite_calls() Uses Reached");
}
_overwrite(NULL, -1, code_block, target);
_long_overwrite(code_block, target);
}
static void increment_code_block() {
code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE;
}
// Overwrite Specific BL Instruction
void _overwrite_call(const char *file, int line, void *start, void *target) {
// Overwrite Specific B(L) Instruction
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) {
// Add New Target To Code Block
update_code_block(target);
uint32_t new_instruction = generate_bl_instruction(start, code_block, 0);
// Patch
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
_patch(file, line, start, (unsigned char *) &new_instruction);
// Increment Code Block Position
increment_code_block();
}
void _overwrite_call(const char *file, int line, void *start, void *target) {
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
_overwrite_call_internal(file, line, start, target, use_b_instruction);
}
// Overwrite Function Calls
// Overwrite All B(L) Intrusctions That Target The Specified Address
void _overwrite_calls(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block
update_code_block(target);
@ -115,7 +126,7 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
data.replacement = code_block;
data.found = 0;
iterate_text_sections(getenv("MCPI_EXECUTABLE_PATH"), overwrite_calls_callback, &data);
iterate_segments(overwrite_calls_callback, &data);
// Increment Code Block Position
increment_code_block();
@ -126,13 +137,24 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
}
}
// 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]"
// Extract Target Address From B(L) Instruction
void *extract_from_bl_instruction(unsigned char *from) {
unsigned char *pc = ((unsigned char *) from) + 8;
_patch(file, line, start, patch_data);
_patch_address(file, line, (void *) (((unsigned char *) start) + 4), target);
int32_t target = 0;
unsigned char *target_array = (unsigned char *) &target;
target_array[0] = from[0];
target_array[1] = from[1];
target_array[2] = from[2];
int32_t offset = target << 2;
return (void *) (pc + offset);
}
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
_overwrite_call_internal(file, line, start, target, 1);
}
// Print Patch Debug Data

View File

@ -1,53 +1,28 @@
#include <libreborn/elf.h>
// Find And Iterate Over All .text Sections In Current Binary
void iterate_text_sections(const char *exe, text_section_callback_t callback, void *data) {
// Load Main Binary
FILE *file_obj = fopen(exe, "rb");
// Verify Binary
if (!file_obj) {
ERR("Unable To Open Binary");
}
// Get File Size
fseek(file_obj, 0L, SEEK_END);
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, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
// Parse ELF
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
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) {
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
(*callback)(header.sh_addr, header.sh_size, data);
text_sections++;
// Find And Iterate Over All Segments In Current Binary
typedef struct {
segment_callback_t callback;
void *data;
} dl_iterate_callback_data;
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
dl_iterate_callback_data *callback_data = (dl_iterate_callback_data *) data;
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
// Only Executable Segemnts
if (info->dlpi_phdr[i].p_type == PT_LOAD && (info->dlpi_phdr[i].p_flags & PF_X) != 0) {
// Callback
(*callback_data->callback)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_memsz, callback_data->data);
}
}
}
// Ensure At Least .text Section Was Scanned
if (text_sections < 1) {
ERR("Unable To Find .text Sectons");
}
// Unmap And Close File
munmap(file_map, file_size);
fclose(file_obj);
return 0;
}
void iterate_segments(segment_callback_t callback, void *data) {
dl_iterate_callback_data callback_data = {
.callback = callback,
.data = data
};
dl_iterate_phdr(dl_iterate_callback, (void *) &callback_data);
}

View File

@ -1,9 +1,45 @@
#include <pthread.h>
#include <libreborn/exec.h>
// Set Environmental Variable
static void setenv_safe(const char *name, const char *value) {
if (value != NULL) {
setenv(name, value, 1);
} else {
unsetenv(name);
}
}
void set_and_print_env(const char *name, const char *value) {
// Print New Value
DEBUG("Set %s = %s", name, value != NULL ? value : "(unset)");
// Set The Value
setenv_safe(name, value);
}
// Safe execvpe()
#define handle_environmental_variable(var) \
{ \
const char *full_var = is_arm_component ? "MCPI_ARM_" var : "MCPI_NATIVE_" var; \
const char *var_value = getenv(full_var); \
set_and_print_env(var, var_value); \
}
void setup_exec_environment(int is_arm_component) {
for_each_special_environmental_variable(handle_environmental_variable);
}
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
// Log
DEBUG("Running Command:");
for (int i = 0; argv[i] != NULL; i++) {
DEBUG(" %s", argv[i]);
}
// Run
int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
if (ret == -1) {
if (errno == ENOENT && strcmp(argv[0], "qemu-qrm")) {
ERR("Unable to find QEMU! To install on Ubuntu/Debian, run \"sudo apt install qemu-user\". To install on Arch Linux, run \"sudo pacman -Sy qemu-user\".");
}
ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
} else {
IMPOSSIBLE();
@ -34,31 +70,8 @@ char *get_binary_directory() {
return exe;
}
// Safe execvpe() Relative To Binary
__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]) {
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Create Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/%s", binary_directory, argv[0]);
// Free Binary Directory
free(binary_directory);
// Build New argv
int argc;
for (argc = 0; argv[argc] != NULL; argc++);
const char *new_argv[argc + 1];
for (int i = 1; i < argc; i++) {
new_argv[i] = argv[i];
}
new_argv[0] = full_path;
new_argv[argc] = NULL;
// Run
safe_execvpe(new_argv, envp);
}
// Run Command And Get Output
char *run_command(const char *const command[], int *return_code) {
char *run_command(const char *const command[], int *exit_status) {
// Store Output
int output_pipe[2];
safe_pipe2(output_pipe, 0);
@ -74,25 +87,21 @@ char *run_command(const char *const command[], int *return_code) {
close(output_pipe[0]);
close(output_pipe[1]);
// Close stderr (But Not In Debug Mode)
const char *is_debug = getenv("MCPI_DEBUG");
if (is_debug == NULL || strlen(is_debug) < 1) {
int null_fd = open("/dev/null", O_WRONLY);
dup2(null_fd, STDERR_FILENO);
close(null_fd);
}
// Setup Environment
setup_exec_environment(0);
// Run
safe_execvpe(command, (const char *const *) environ);
} else {
// Parent Process
track_child(ret);
// Read stdout
close(output_pipe[1]);
char *output = NULL;
#define BUFFER_SIZE 1024
char buf[BUFFER_SIZE];
size_t bytes_read = 0;
ssize_t bytes_read = 0;
while ((bytes_read = read(output_pipe[0], (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */)) > 0) {
buf[bytes_read] = '\0';
string_append(&output, "%s", buf);
@ -102,11 +111,59 @@ char *run_command(const char *const command[], int *return_code) {
// Get Return Code
int status;
waitpid(ret, &status, 0);
if (return_code != NULL) {
*return_code = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
untrack_child(ret);
if (exit_status != NULL) {
*exit_status = status;
}
// Return
return output;
}
}
// Get Exit Status String
void get_exit_status_string(int status, char **out) {
if (out != NULL) {
*out =NULL;
if (WIFEXITED(status)) {
safe_asprintf(out, ": Exit Code: %i", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
safe_asprintf(out, ": Signal: %i%s", WTERMSIG(status), WCOREDUMP(status) ? " (Core Dumped)" : "");
} else {
safe_asprintf(out, ": Terminated");
}
}
}
// Track Children
#define MAX_CHILDREN 128
static pid_t children[MAX_CHILDREN] = { 0 };
static pthread_mutex_t children_lock = PTHREAD_MUTEX_INITIALIZER;
void track_child(pid_t pid) {
pthread_mutex_lock(&children_lock);
for (int i = 0; i < MAX_CHILDREN; i++) {
if (children[i] == 0) {
children[i] = pid;
break;
}
}
pthread_mutex_unlock(&children_lock);
}
void untrack_child(pid_t pid) {
pthread_mutex_lock(&children_lock);
for (int i = 0; i < MAX_CHILDREN; i++) {
if (children[i] == pid) {
children[i] = 0;
}
}
pthread_mutex_unlock(&children_lock);
}
void murder_children() {
pthread_mutex_lock(&children_lock);
for (int i = 0; i < MAX_CHILDREN; i++) {
if (children[i] != 0) {
kill(children[i], SIGTERM);
}
}
pthread_mutex_unlock(&children_lock);
}

View File

@ -1,16 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#define COLOR(name, value) \
char *color_##name() { \
static char *out = NULL; \
if (out == NULL) { \
out = isatty(fileno(stderr)) ? "\x1b[" value "m" : ""; \
} \
return out; \
}
COLOR(reset, "0")
COLOR(yellow, "93")
COLOR(faint, "2")
COLOR(red, "91")

View File

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

View File

@ -6,3 +6,19 @@ void safe_pipe2(int pipefd[2], int flags) {
ERR("Unable To Create Pipe: %s", strerror(errno));
}
}
// Check If Two Percentages Are Different Enough To Be Logged
#define SIGNIFICANT_PROGRESS 5
int is_progress_difference_significant(int32_t new_val, int32_t old_val) {
if (new_val != old_val) {
if (new_val == -1 || old_val == -1) {
return 1;
} else if (new_val == 0 || new_val == 100) {
return 1;
} else {
return new_val - old_val >= SIGNIFICANT_PROGRESS;
}
} else {
return 0;
}
}

View File

@ -1,29 +1,28 @@
project(media-layer)
# Check Options
if(MCPI_USE_MEDIA_LAYER_PROXY)
if(MCPI_HEADLESS_MODE)
message(FATAL_ERROR "Headless Mode With Media Layer Proxy Configuration Is Redundant")
endif()
if(MCPI_BUILD_MODE STREQUAL "both")
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build")
endif()
endif()
# Add Headers
add_library(media-layer-headers INTERFACE)
target_include_directories(media-layer-headers INTERFACE include)
target_include_directories(
media-layer-headers
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/media-layer>"
)
# SDK
if(BUILD_ARM_COMPONENTS)
install(TARGETS media-layer-headers EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/media-layer")
endif()
# Add Extras
add_subdirectory(extras)
# Add Core
add_subdirectory(core)
if((BUILD_NATIVE_COMPONENTS AND MCPI_USE_MEDIA_LAYER_PROXY) OR (BUILD_ARM_COMPONENTS AND NOT MCPI_USE_MEDIA_LAYER_PROXY))
add_subdirectory(core)
endif()
# Add Proxy
if(MCPI_USE_MEDIA_LAYER_PROXY)
add_subdirectory(proxy)
endif()
# Add Stubs
add_subdirectory(stubs)
# Add Extras
add_subdirectory(extras)

View File

@ -1,37 +1,32 @@
project(media-layer-core)
# Dependencies
add_subdirectory(dependencies)
# OpenGL
add_subdirectory(gles)
# Configuration
set(CORE_SRC src/base.cpp src/media.c src/screenshot.c) # SDL Re-Implementation Using GLFW
set(CORE_SRC src/base.cpp src/media.c $<TARGET_OBJECTS:media-layer-extras>) # 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)
else()
list(APPEND CORE_SRC src/audio/stubs.c)
endif()
# Build
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
# Building Native Components
add_library(media-layer-core OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
elseif(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
# Building ARM Components
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
# Install
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
endif()
# Configure Media Layer Core If Built
if(TARGET media-layer-core)
# Link
target_link_libraries(media-layer-core media-layer-headers reborn-util pthread dl)
if(NOT MCPI_HEADLESS_MODE)
# Find FreeImage
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
# 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()
# Add Symlinks So MCPI Can Locate Libraries
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
# Install
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libSDL-1.2.so.0")
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# Link
target_link_libraries(media-layer-core PUBLIC media-layer-headers PUBLIC reborn-util PUBLIC GLESv1_CM PUBLIC dl)
if(NOT MCPI_HEADLESS_MODE)
# OpenAL
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw)
endif()

View File

@ -0,0 +1,6 @@
project(media-layer-core-dependencies)
# GLFW
if(NOT MCPI_HEADLESS_MODE)
add_subdirectory(glfw)
endif()

View File

@ -0,0 +1,31 @@
project(glfw)
# Silence Warnings
add_compile_options(-w)
## GLFW
# Download
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_DOCS FALSE CACHE BOOL "" FORCE)
set(GLFW_INSTALL FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_WIN32 FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_COCOA FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_X11 TRUE CACHE BOOL "" FORCE)
set(GLFW_BUILD_WAYLAND TRUE CACHE BOOL "" FORCE)
set(GLFW_LIBRARY_TYPE "SHARED" CACHE BOOL "" FORCE)
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(glfw-build ALL DEPENDS glfw)
# Install
install(TARGETS glfw DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install(TARGETS glfw EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# License
install(FILES src/LICENSE.md DESTINATION "${MCPI_LEGAL_DIR}/glfw")

@ -0,0 +1 @@
Subproject commit c18851f52ec9704eb06464058a600845ec1eada1

View File

@ -0,0 +1,32 @@
project(media-layer-gles)
# Build
if(MCPI_HEADLESS_MODE)
# Stubs For Headless Mode
set(GLES_SRC src/stubs.c)
elseif(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
# GLESv1_CM Compatibility Layer
set(GLES_SRC src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c src/compatibility-layer/buffer.cpp)
else()
# Passthrough To glfwGetProcAddress()
set(GLES_SRC src/passthrough.c)
endif()
add_library(GLESv1_CM SHARED ${GLES_SRC})
if(NOT MCPI_HEADLESS_MODE)
target_link_libraries(GLESv1_CM PRIVATE glfw PUBLIC reborn-util PRIVATE dl PRIVATE m)
# Shaders
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
embed_resource(GLESv1_CM src/compatibility-layer/shaders/main.vsh)
embed_resource(GLESv1_CM src/compatibility-layer/shaders/main.fsh)
endif()
endif()
# Common
target_link_libraries(GLESv1_CM PUBLIC media-layer-headers)
set_target_properties(GLESv1_CM PROPERTIES SOVERSION "1")
# Install
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
# SDK
if(BUILD_ARM_COMPONENTS)
install(TARGETS GLESv1_CM EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()

View File

@ -0,0 +1,35 @@
#include <unordered_map>
#include <GLES/gl.h>
#include "../passthrough.h"
// Store Buffers
static std::unordered_map<GLuint, GLuint> buffers_map;
// Get Buffer
GL_FUNC(glGenBuffers, void, (GLsizei n, GLuint *buffers));
static GLuint get_real_buffer(GLuint fake_buffer) {
if (buffers_map.count(fake_buffer) > 0) {
return buffers_map[fake_buffer];
} else {
GLuint new_buffer;
real_glGenBuffers()(1, &new_buffer);
buffers_map[fake_buffer] = new_buffer;
return get_real_buffer(fake_buffer);
}
}
// Convert Fake Buffers To Real Buffers When Calling GL
GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer));
void glBindBuffer(GLenum target, GLuint buffer) {
real_glBindBuffer()(target, get_real_buffer(buffer));
}
GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers));
void glDeleteBuffers(GLsizei n, const GLuint *buffers) {
for (int i = 0; i < n; i++) {
if (buffers_map.count(buffers[i]) > 0) {
real_glDeleteBuffers()(1, &buffers_map[i]);
buffers_map.erase(buffers[i]);
}
}
}

View File

@ -0,0 +1,204 @@
#include "state.h"
#include "../passthrough.h"
#include <GLES/gl.h>
#include <libreborn/libreborn.h>
// Shaders
#define REAL_GL_FRAGMENT_SHADER 0x8b30
#define REAL_GL_VERTEX_SHADER 0x8b31
#define REAL_GL_INFO_LOG_LENGTH 0x8b84
#define REAL_GL_COMPILE_STATUS 0x8b81
GL_FUNC(glUseProgram, void, (GLuint program));
GL_FUNC(glGetUniformLocation, GLint, (GLuint program, const GLchar *name));
GL_FUNC(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
GL_FUNC(glUniform1i, void, (GLint location, GLint v0));
GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0));
GL_FUNC(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
GL_FUNC(glGetAttribLocation, GLint, (GLuint program, const GLchar *name));
GL_FUNC(glEnableVertexAttribArray, void, (GLuint index));
GL_FUNC(glDisableVertexAttribArray, void, (GLuint index));
GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
GL_FUNC(glVertexAttrib3f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2));
GL_FUNC(glVertexAttrib4f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
GL_FUNC(glCreateShader, GLuint, (GLenum type));
GL_FUNC(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length));
GL_FUNC(glCompileShader, void, (GLuint shader));
GL_FUNC(glCreateProgram, GLuint, ());
GL_FUNC(glAttachShader, void, (GLuint program, GLuint shader));
GL_FUNC(glLinkProgram, void, (GLuint program));
GL_FUNC(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params));
GL_FUNC(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
// Compile Shader
static void log_shader(GLuint shader, const char *name) {
// Log
GLint log_length = 0;
real_glGetShaderiv()(shader, REAL_GL_INFO_LOG_LENGTH, &log_length);
GLchar *log = malloc(log_length * sizeof (GLchar));
ALLOC_CHECK(log);
real_glGetShaderInfoLog()(shader, log_length, &log_length, log);
if (log_length > 0) {
if (log_length > 1 && log[log_length - 1] == '\n') {
log[log_length - 1] = '\0';
}
DEBUG("%s Shader Compile Log: %s", name, log);
}
free(log);
// Check Status
GLint is_compiled = 0;
real_glGetShaderiv()(shader, REAL_GL_COMPILE_STATUS, &is_compiled);
if (!is_compiled) {
ERR("Failed To Compile %s Shader", name);
}
}
static GLuint compile_shader(const char *vertex_shader_text, const int vertex_shader_length, const char *fragment_shader_text, const int fragment_shader_length) {
// Vertex Shader
const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER);
real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, &vertex_shader_length);
real_glCompileShader()(vertex_shader);
log_shader(vertex_shader, "Vertex");
// Fragment Shader
const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER);
real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, &fragment_shader_length);
real_glCompileShader()(fragment_shader);
log_shader(fragment_shader, "Fragment");
// Link
GLuint program = real_glCreateProgram()();
real_glAttachShader()(program, vertex_shader);
real_glAttachShader()(program, fragment_shader);
real_glLinkProgram()(program);
// Return
return program;
}
// Shader
extern unsigned char main_vsh[];
extern size_t main_vsh_len;
extern unsigned char main_fsh[];
extern size_t main_fsh_len;
static GLuint get_shader() {
static GLuint program = 0;
if (program == 0) {
program = compile_shader((const char *) main_vsh, main_vsh_len, (const char *) main_fsh, main_fsh_len);
}
return program;
}
// Shader Switching
static void use_shader(GLuint program) {
static GLuint current_program = 0;
if (current_program != program) {
real_glUseProgram()(program);
current_program = program;
}
}
// Array Pointer Drawing
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count));
#define lazy_uniform(name) \
static GLint name##_handle = -1; \
if (name##_handle == -1) { \
name##_handle = real_glGetUniformLocation()(program, #name); \
}
void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
// Verify
if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) {
ERR("Unsupported Vertex Conifguration");
}
// Check Mode
int use_color_pointer = gl_state.array_pointers.color.enabled;
if (use_color_pointer && (gl_state.array_pointers.color.size != 4 || gl_state.array_pointers.color.type != GL_UNSIGNED_BYTE)) {
ERR("Unsupported Color Conifguration");
}
int use_texture = gl_state.texture_2d && gl_state.array_pointers.tex_coord.enabled;
if (use_texture && (gl_state.array_pointers.tex_coord.size != 2 || gl_state.array_pointers.tex_coord.type != GL_FLOAT)) {
ERR("Unsupported Texture Conifguration");
}
// Load Shader
GLuint program = get_shader();
use_shader(program);
// Projection Matrix
lazy_uniform(u_projection);
matrix_t *p = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i];
real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Model View Matrix
lazy_uniform(u_model_view);
p = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i];
real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Has Texture
lazy_uniform(u_has_texture); \
real_glUniform1i()(u_has_texture_handle, use_texture); \
// Texture Matrix
lazy_uniform(u_texture);
p = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i];
real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Texture Unit
lazy_uniform(u_texture_unit);
real_glUniform1i()(u_texture_unit_handle, 0);
// Alpha Test
lazy_uniform(u_alpha_test);
real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test);
// Color
GLint a_color_handle = real_glGetAttribLocation()(program, "a_color");
if (use_color_pointer) {
real_glVertexAttribPointer()(a_color_handle, gl_state.array_pointers.color.size, gl_state.array_pointers.color.type, 1, gl_state.array_pointers.color.stride, gl_state.array_pointers.color.pointer);
real_glEnableVertexAttribArray()(a_color_handle);
} else {
real_glVertexAttrib4f()(a_color_handle, gl_state.color.red, gl_state.color.green, gl_state.color.blue, gl_state.color.alpha);
}
// Fog
lazy_uniform(u_fog);
real_glUniform1i()(u_fog_handle, gl_state.fog.enabled);
if (gl_state.fog.enabled) {
lazy_uniform(u_fog_color);
real_glUniform4f()(u_fog_color_handle, gl_state.fog.color[0], gl_state.fog.color[1], gl_state.fog.color[2], gl_state.fog.color[3]);
lazy_uniform(u_fog_is_linear);
real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR);
lazy_uniform(u_fog_start);
real_glUniform1f()(u_fog_start_handle, gl_state.fog.start);
lazy_uniform(u_fog_end);
real_glUniform1f()(u_fog_end_handle, gl_state.fog.end);
}
// Vertices
GLint a_vertex_coords_handle = real_glGetAttribLocation()(program, "a_vertex_coords");
real_glVertexAttribPointer()(a_vertex_coords_handle, gl_state.array_pointers.vertex.size, gl_state.array_pointers.vertex.type, 0, gl_state.array_pointers.vertex.stride, gl_state.array_pointers.vertex.pointer);
real_glEnableVertexAttribArray()(a_vertex_coords_handle);
// Texture Coordinates
GLint a_texture_coords_handle = real_glGetAttribLocation()(program, "a_texture_coords");
if (use_texture) {
real_glVertexAttribPointer()(a_texture_coords_handle, gl_state.array_pointers.tex_coord.size, gl_state.array_pointers.tex_coord.type, 0, gl_state.array_pointers.tex_coord.stride, gl_state.array_pointers.tex_coord.pointer);
real_glEnableVertexAttribArray()(a_texture_coords_handle);
} else {
real_glVertexAttrib3f()(a_texture_coords_handle, 0, 0, 0);
}
// Draw
real_glDrawArrays()(mode, first, count);
// Cleanup
if (use_color_pointer) {
real_glDisableVertexAttribArray()(a_color_handle);
}
real_glDisableVertexAttribArray()(a_vertex_coords_handle);
if (use_texture) {
real_glDisableVertexAttribArray()(a_texture_coords_handle);
}
}

View File

@ -0,0 +1,131 @@
#include <math.h>
#include <string.h>
#include <libreborn/libreborn.h>
#include "state.h"
// Matrix Common
static void matrix_copy(matrix_t *src, matrix_t *dst) {
memcpy((void *) dst->data, (void *) src->data, MATRIX_DATA_SIZE);
}
// Identity Matrix
static matrix_t identity_matrix = {
.data = {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
}
};
static void init_matrix_stack(matrix_stack_t *stack) {
matrix_copy(&identity_matrix, &stack->stack[0]);
}
__attribute__((constructor)) static void init_matrix_stacks() {
init_matrix_stack(&gl_state.matrix_stacks.model_view);
init_matrix_stack(&gl_state.matrix_stacks.projection);
init_matrix_stack(&gl_state.matrix_stacks.texture);
}
// Matrix Mode
static matrix_stack_t *get_matrix_stack() {
switch (gl_state.matrix_stacks.mode) {
case GL_MODELVIEW: {
return &gl_state.matrix_stacks.model_view;
}
case GL_PROJECTION: {
return &gl_state.matrix_stacks.projection;
}
case GL_TEXTURE: {
return &gl_state.matrix_stacks.texture;
}
default: {
ERR("Unsupported Matrix Mode: %i", gl_state.matrix_stacks.mode);
}
}
}
// Matrix Functions
void glMatrixMode(GLenum mode) {
gl_state.matrix_stacks.mode = mode;
}
void glPopMatrix() {
get_matrix_stack()->i--;
}
void glLoadIdentity() {
matrix_stack_t *stack = get_matrix_stack();
matrix_copy(&identity_matrix, &stack->stack[stack->i]);
}
void glPushMatrix() {
matrix_stack_t *stack = get_matrix_stack();
matrix_copy(&stack->stack[stack->i], &stack->stack[stack->i + 1]);
stack->i++;
}
void glMultMatrixf(const GLfloat *m) {
matrix_t new_matrix;
matrix_stack_t *stack = get_matrix_stack();
matrix_t *current_matrix = &stack->stack[stack->i];
for (int x = 0; x < MATRIX_SIZE; x++) {
for (int y = 0; y < MATRIX_SIZE; y++) {
GLfloat result = 0;
for (int i = 0; i < MATRIX_SIZE; i++) {
result += (current_matrix->data[i][y] * m[(x * MATRIX_SIZE) + i]);
}
new_matrix.data[x][y] = result;
}
}
matrix_copy(&new_matrix, current_matrix);
}
void glScalef(GLfloat x, GLfloat y, GLfloat z) {
GLfloat m[] = {
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
};
glMultMatrixf(m);
}
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
GLfloat m[] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1
};
glMultMatrixf(m);
}
void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) {
GLfloat m[] = {
(2.f / (right - left)), 0, 0, 0,
0, (2.f / (top - bottom)), 0, 0,
0, 0, (-2.f / (far - near)), 0,
-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), 1
};
glMultMatrixf(m);
}
#define DEG2RAD (M_PI / 180.f)
void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
// Normalize
GLfloat length = sqrtf((x * x) + (y * y) + (z * z));
x /= length;
y /= length;
z /= length;
// Values
GLfloat angle_radians = angle * DEG2RAD;
GLfloat c = cosf(angle_radians);
GLfloat s = sinf(angle_radians);
GLfloat x2 = x * x;
GLfloat y2 = y * y;
GLfloat z2 = z * z;
// Multiply
GLfloat m[] = {
x2 * (1.f - c) + c, (x * y) * (1.f - c) + (z * s), (x * z) * (1.f - c) - (y * s), 0,
(x * y) * (1.f - c) - (z * s), y2 * (1.f - c) + c, (y * z) * (1.f - c) + (x * s), 0,
(x * z) * (1.f - c) + (y * s), (y * z) * (1.f - c) - (x * s), z2 * (1.f - c) + c, 0,
0, 0, 0, 1.f
};
glMultMatrixf(m);
}

View File

@ -0,0 +1,9 @@
#include <GLES/gl.h>
// Matrix Common
#define MATRIX_SIZE 4
#define MATRIX_DATA_SIZE (sizeof (float) * MATRIX_SIZE * MATRIX_SIZE)
// OpenGL Matricies Are Column-Major
typedef struct {
GLfloat data[MATRIX_SIZE][MATRIX_SIZE];
} matrix_t;

View File

@ -0,0 +1,105 @@
#include <GLES/gl.h>
#include "../passthrough.h"
// Simple v1.1 -> v2.0 Passthrough Functions
GL_FUNC(glLineWidth, void, (GLfloat width));
void glLineWidth(GLfloat width) {
real_glLineWidth()(width);
}
GL_FUNC(glBlendFunc, void, (GLenum sfactor, GLenum dfactor));
void glBlendFunc(GLenum sfactor, GLenum dfactor) {
real_glBlendFunc()(sfactor, dfactor);
}
GL_FUNC(glClear, void, (GLbitfield mask));
void glClear(GLbitfield mask) {
real_glClear()(mask);
}
GL_FUNC(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage));
void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
real_glBufferData()(target, size, data, usage);
}
GL_FUNC(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height));
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
real_glScissor()(x, y, width, height);
}
GL_FUNC(glTexParameteri, void, (GLenum target, GLenum pname, GLint param));
void glTexParameteri(GLenum target, GLenum pname, GLint param) {
real_glTexParameteri()(target, pname, param);
}
GL_FUNC(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels));
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {
real_glTexImage2D()(target, level, internalformat, width, height, border, format, type, pixels);
}
GL_FUNC(glPolygonOffset, void, (GLfloat factor, GLfloat units));
void glPolygonOffset(GLfloat factor, GLfloat units) {
real_glPolygonOffset()(factor, units);
}
GL_FUNC(glDepthRangef, void, (GLclampf near, GLclampf far));
void glDepthRangef(GLclampf near, GLclampf far) {
real_glDepthRangef()(near, far);
}
GL_FUNC(glDepthFunc, void, (GLenum func));
void glDepthFunc(GLenum func) {
real_glDepthFunc()(func);
}
GL_FUNC(glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
real_glClearColor()(red, green, blue, alpha);
}
GL_FUNC(glDepthMask, void, (GLboolean flag));
void glDepthMask(GLboolean flag) {
real_glDepthMask()(flag);
}
GL_FUNC(glHint, void, (GLenum target, GLenum mode));
void glHint(GLenum target, GLenum mode) {
if (target != GL_PERSPECTIVE_CORRECTION_HINT) {
real_glHint()(target, mode);
}
}
GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
real_glColorMask()(red, green, blue, alpha);
}
GL_FUNC(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels));
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
real_glTexSubImage2D()(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
GL_FUNC(glGenTextures, void, (GLsizei n, GLuint *textures));
void glGenTextures(GLsizei n, GLuint *textures) {
real_glGenTextures()(n, textures);
}
GL_FUNC(glDeleteTextures, void, (GLsizei n, const GLuint *textures));
void glDeleteTextures(GLsizei n, const GLuint *textures) {
real_glDeleteTextures()(n, textures);
}
GL_FUNC(glBindTexture, void, (GLenum target, GLuint texture));
void glBindTexture(GLenum target, GLuint texture) {
real_glBindTexture()(target, texture);
}
GL_FUNC(glCullFace, void, (GLenum mode));
void glCullFace(GLenum mode) {
real_glCullFace()(mode);
}
GL_FUNC(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height));
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
real_glViewport()(x, y, width, height);
}
GL_FUNC(glIsEnabled, GLboolean, (GLenum cap));
GLboolean glIsEnabled(GLenum cap) {
return real_glIsEnabled()(cap);
}
GL_FUNC(glGetIntegerv, void, (GLenum pname, GLint *data));
void glGetIntegerv(GLenum pname, GLint *data) {
real_glGetIntegerv()(pname, data);
}
GL_FUNC(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data));
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
real_glReadPixels()(x, y, width, height, format, type, data);
}
void glShadeModel(__attribute__((unused)) GLenum mode) {
// Do Nothing
}
void glNormal3f(__attribute__((unused)) GLfloat nx, __attribute__((unused)) GLfloat ny, __attribute__((unused)) GLfloat nz) {
// Do Nothing
}

View File

@ -0,0 +1,39 @@
#version 100
precision mediump float;
// Texture
uniform bool u_has_texture;
uniform sampler2D u_texture_unit;
// Color
varying vec4 v_color;
varying vec4 v_texture_pos;
// Alpha Test
uniform bool u_alpha_test;
// Fog
uniform bool u_fog;
uniform vec4 u_fog_color;
uniform bool u_fog_is_linear;
uniform float u_fog_start;
uniform float u_fog_end;
varying vec4 v_fog_eye_position;
// Main
void main(void) {
gl_FragColor = v_color;
// Texture
if (u_has_texture) {
gl_FragColor *= texture2D(u_texture_unit, v_texture_pos.xy);
}
// Alpha Test
if (u_alpha_test && gl_FragColor.a <= 0.1) {
discard;
}
// Fog
if (u_fog) {
float fog_factor;
if (u_fog_is_linear) {
fog_factor = (u_fog_end - length(v_fog_eye_position)) / (u_fog_end - u_fog_start);
} else {
fog_factor = exp(-u_fog_start * length(v_fog_eye_position));
}
gl_FragColor = mix(gl_FragColor, u_fog_color, 1.0 - clamp(fog_factor, 0.0, 1.0));
}
}

View File

@ -0,0 +1,22 @@
#version 100
precision mediump float;
// Matrices
uniform mat4 u_projection;
uniform mat4 u_model_view;
uniform mat4 u_texture;
// Texture
attribute vec3 a_vertex_coords;
attribute vec2 a_texture_coords;
varying vec4 v_texture_pos;
// Color
attribute vec4 a_color;
varying vec4 v_color;
// Fog
varying vec4 v_fog_eye_position;
// Main
void main(void) {
v_texture_pos = u_texture * vec4(a_texture_coords.xy, 0.0, 1.0);
gl_Position = u_projection * u_model_view * vec4(a_vertex_coords.xyz, 1.0);
v_color = a_color;
v_fog_eye_position = u_model_view * vec4(a_vertex_coords.xyz, 1.0);
}

View File

@ -0,0 +1,178 @@
#include <libreborn/libreborn.h>
#include "state.h"
#include "../passthrough.h"
// GL State
gl_state_t gl_state = {
.color = {
.red = 1,
.green = 1,
.blue = 1,
.alpha = 1
},
.matrix_stacks = {
.mode = GL_MODELVIEW
},
.alpha_test = 0,
.texture_2d = 0,
.fog = {
.enabled = 0,
.mode = GL_LINEAR,
.color = {0, 0, 0, 0},
.start = 0,
.end = 1
}
};
// Change Color
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
gl_state.color.red = red;
gl_state.color.green = green;
gl_state.color.blue = blue;
gl_state.color.alpha = alpha;
}
// Array Pointer Storage
#define ARRAY_POINTER_FUNC(func, name) \
void func(GLint size, GLenum type, GLsizei stride, const void *pointer) { \
gl_state.array_pointers.name.size = size; \
gl_state.array_pointers.name.type = type; \
gl_state.array_pointers.name.stride = stride; \
gl_state.array_pointers.name.pointer = pointer; \
}
ARRAY_POINTER_FUNC(glVertexPointer, vertex)
ARRAY_POINTER_FUNC(glColorPointer, color)
ARRAY_POINTER_FUNC(glTexCoordPointer, tex_coord)
static array_pointer_t *get_array_pointer(GLenum array) {
switch (array) {
case GL_VERTEX_ARRAY: {
return &gl_state.array_pointers.vertex;
}
case GL_COLOR_ARRAY: {
return &gl_state.array_pointers.color;
}
case GL_TEXTURE_COORD_ARRAY: {
return &gl_state.array_pointers.tex_coord;
}
default: {
ERR("Unsupported Array Pointer: %i", array);
}
}
}
void glEnableClientState(GLenum array) {
get_array_pointer(array)->enabled = 1;
}
void glDisableClientState(GLenum array) {
get_array_pointer(array)->enabled = 0;
}
// Enable/Disable State
GL_FUNC(glEnable, void, (GLenum cap));
void glEnable(GLenum cap) {
switch (cap) {
case GL_ALPHA_TEST: {
gl_state.alpha_test = 1;
break;
}
case GL_TEXTURE_2D: {
gl_state.texture_2d = 1;
break;
}
case GL_COLOR_MATERIAL: {
// Ignore
break;
}
case GL_FOG: {
gl_state.fog.enabled = 1;
break;
}
default: {
real_glEnable()(cap);
break;
}
}
}
GL_FUNC(glDisable, void, (GLenum cap));
void glDisable(GLenum cap) {
switch (cap) {
case GL_ALPHA_TEST: {
gl_state.alpha_test = 0;
break;
}
case GL_TEXTURE_2D: {
gl_state.texture_2d = 0;
break;
}
case GL_COLOR_MATERIAL: {
// Ignore
break;
}
case GL_FOG: {
gl_state.fog.enabled = 0;
break;
}
default: {
real_glDisable()(cap);
break;
}
}
}
void glAlphaFunc(GLenum func, GLclampf ref) {
if (func != GL_GREATER && ref != 0.1f) {
ERR("Unsupported Alpha Function");
}
}
// Fog
#define UNSUPPORTED_FOG() ERR("Unsupported Fog Configuration")
void glFogfv(GLenum pname, const GLfloat *params) {
if (pname == GL_FOG_COLOR) {
memcpy((void *) gl_state.fog.color, params, sizeof (gl_state.fog.color));
} else {
UNSUPPORTED_FOG();
}
}
void glFogx(GLenum pname, GLfixed param) {
if (pname == GL_FOG_MODE && (param == GL_LINEAR || param == GL_EXP)) {
gl_state.fog.mode = param;
} else {
UNSUPPORTED_FOG();
}
}
void glFogf(GLenum pname, GLfloat param) {
switch (pname) {
case GL_FOG_DENSITY:
case GL_FOG_START: {
gl_state.fog.start = param;
break;
}
case GL_FOG_END: {
gl_state.fog.end = param;
break;
}
default: {
UNSUPPORTED_FOG();
break;
}
}
}
// Get Matrix Data
GL_FUNC(glGetFloatv, void, (GLenum pname, GLfloat *params));
void glGetFloatv(GLenum pname, GLfloat *params) {
switch (pname) {
case GL_MODELVIEW_MATRIX: {
memcpy((void *) params, gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i].data, MATRIX_DATA_SIZE);
break;
}
case GL_PROJECTION_MATRIX: {
memcpy((void *) params, gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i].data, MATRIX_DATA_SIZE);
break;
}
default: {
real_glGetFloatv()(pname, params);
break;
}
}
}

View File

@ -0,0 +1,50 @@
#include <GLES/gl.h>
#include "matrix.h"
// Matrix Data
#define MATRIX_STACK_DEPTH 256
typedef struct {
matrix_t stack[MATRIX_STACK_DEPTH];
unsigned int i;
} matrix_stack_t;
// Array Pointer Storage
typedef struct {
GLboolean enabled;
GLint size;
GLenum type;
GLsizei stride;
const void *pointer;
} array_pointer_t;
// GL State
typedef struct {
struct {
GLfloat red;
GLfloat green;
GLfloat blue;
GLfloat alpha;
} color;
struct {
GLenum mode;
matrix_stack_t model_view;
matrix_stack_t projection;
matrix_stack_t texture;
} matrix_stacks;
struct {
array_pointer_t vertex;
array_pointer_t color;
array_pointer_t tex_coord;
} array_pointers;
GLboolean alpha_test;
GLboolean texture_2d;
struct {
GLboolean enabled;
GLfixed mode;
GLfloat color[4];
GLfloat start;
GLfloat end;
} fog;
} gl_state_t;
extern gl_state_t gl_state;

View File

@ -0,0 +1,204 @@
#include <GLES/gl.h>
#include "passthrough.h"
GL_FUNC(glFogfv, void, (GLenum pname, const GLfloat *params));
void glFogfv(GLenum pname, const GLfloat *params) {
real_glFogfv()(pname, params);
}
GL_FUNC(glVertexPointer, void, (GLint size, GLenum type, GLsizei stride, const void *pointer));
void glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) {
real_glVertexPointer()(size, type, stride, pointer);
}
GL_FUNC(glLineWidth, void, (GLfloat width));
void glLineWidth(GLfloat width) {
real_glLineWidth()(width);
}
GL_FUNC(glBlendFunc, void, (GLenum sfactor, GLenum dfactor));
void glBlendFunc(GLenum sfactor, GLenum dfactor) {
real_glBlendFunc()(sfactor, dfactor);
}
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count));
void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
real_glDrawArrays()(mode, first, count);
}
GL_FUNC(glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha));
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
real_glColor4f()(red, green, blue, alpha);
}
GL_FUNC(glClear, void, (GLbitfield mask));
void glClear(GLbitfield mask) {
real_glClear()(mask);
}
GL_FUNC(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage));
void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
real_glBufferData()(target, size, data, usage);
}
GL_FUNC(glFogx, void, (GLenum pname, GLfixed param));
void glFogx(GLenum pname, GLfixed param) {
real_glFogx()(pname, param);
}
GL_FUNC(glFogf, void, (GLenum pname, GLfloat param));
void glFogf(GLenum pname, GLfloat param) {
real_glFogf()(pname, param);
}
GL_FUNC(glMatrixMode, void, (GLenum mode));
void glMatrixMode(GLenum mode) {
real_glMatrixMode()(mode);
}
GL_FUNC(glColorPointer, void, (GLint size, GLenum type, GLsizei stride, const void *pointer));
void glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) {
real_glColorPointer()(size, type, stride, pointer);
}
GL_FUNC(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height));
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
real_glScissor()(x, y, width, height);
}
GL_FUNC(glTexParameteri, void, (GLenum target, GLenum pname, GLint param));
void glTexParameteri(GLenum target, GLenum pname, GLint param) {
real_glTexParameteri()(target, pname, param);
}
GL_FUNC(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels));
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {
real_glTexImage2D()(target, level, internalformat, width, height, border, format, type, pixels);
}
GL_FUNC(glEnable, void, (GLenum cap));
void glEnable(GLenum cap) {
real_glEnable()(cap);
}
GL_FUNC(glEnableClientState, void, (GLenum array));
void glEnableClientState(GLenum array) {
real_glEnableClientState()(array);
}
GL_FUNC(glPolygonOffset, void, (GLfloat factor, GLfloat units));
void glPolygonOffset(GLfloat factor, GLfloat units) {
real_glPolygonOffset()(factor, units);
}
GL_FUNC(glDisableClientState, void, (GLenum array));
void glDisableClientState(GLenum array) {
real_glDisableClientState()(array);
}
GL_FUNC(glDepthRangef, void, (GLclampf near, GLclampf far));
void glDepthRangef(GLclampf near, GLclampf far) {
real_glDepthRangef()(near, far);
}
GL_FUNC(glDepthFunc, void, (GLenum func));
void glDepthFunc(GLenum func) {
real_glDepthFunc()(func);
}
GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer));
void glBindBuffer(GLenum target, GLuint buffer) {
real_glBindBuffer()(target, buffer);
}
GL_FUNC(glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
real_glClearColor()(red, green, blue, alpha);
}
GL_FUNC(glPopMatrix, void, ());
void glPopMatrix() {
real_glPopMatrix()();
}
GL_FUNC(glLoadIdentity, void, ());
void glLoadIdentity() {
real_glLoadIdentity()();
}
GL_FUNC(glScalef, void, (GLfloat x, GLfloat y, GLfloat z));
void glScalef(GLfloat x, GLfloat y, GLfloat z) {
real_glScalef()(x, y, z);
}
GL_FUNC(glPushMatrix, void, ());
void glPushMatrix() {
real_glPushMatrix()();
}
GL_FUNC(glDepthMask, void, (GLboolean flag));
void glDepthMask(GLboolean flag) {
real_glDepthMask()(flag);
}
GL_FUNC(glHint, void, (GLenum target, GLenum mode));
void glHint(GLenum target, GLenum mode) {
real_glHint()(target, mode);
}
GL_FUNC(glMultMatrixf, void, (const GLfloat *m));
void glMultMatrixf(const GLfloat *m) {
real_glMultMatrixf()(m);
}
GL_FUNC(glTexCoordPointer, void, (GLint size, GLenum type, GLsizei stride, const void *pointer));
void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) {
real_glTexCoordPointer()(size, type, stride, pointer);
}
GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers));
void glDeleteBuffers(GLsizei n, const GLuint *buffers) {
real_glDeleteBuffers()(n, buffers);
}
GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
real_glColorMask()(red, green, blue, alpha);
}
GL_FUNC(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels));
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
real_glTexSubImage2D()(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
GL_FUNC(glGenTextures, void, (GLsizei n, GLuint *textures));
void glGenTextures(GLsizei n, GLuint *textures) {
real_glGenTextures()(n, textures);
}
GL_FUNC(glDeleteTextures, void, (GLsizei n, const GLuint *textures));
void glDeleteTextures(GLsizei n, const GLuint *textures) {
real_glDeleteTextures()(n, textures);
}
GL_FUNC(glAlphaFunc, void, (GLenum func, GLclampf ref));
void glAlphaFunc(GLenum func, GLclampf ref) {
real_glAlphaFunc()(func, ref);
}
GL_FUNC(glGetFloatv, void, (GLenum pname, GLfloat *params));
void glGetFloatv(GLenum pname, GLfloat *params) {
real_glGetFloatv()(pname, params);
}
GL_FUNC(glBindTexture, void, (GLenum target, GLuint texture));
void glBindTexture(GLenum target, GLuint texture) {
real_glBindTexture()(target, texture);
}
GL_FUNC(glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z));
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
real_glTranslatef()(x, y, z);
}
GL_FUNC(glShadeModel, void, (GLenum mode));
void glShadeModel(GLenum mode) {
real_glShadeModel()(mode);
}
GL_FUNC(glOrthof, void, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far));
void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) {
real_glOrthof()(left, right, bottom, top, near, far);
}
GL_FUNC(glDisable, void, (GLenum cap));
void glDisable(GLenum cap) {
real_glDisable()(cap);
}
GL_FUNC(glCullFace, void, (GLenum mode));
void glCullFace(GLenum mode) {
real_glCullFace()(mode);
}
GL_FUNC(glRotatef, void, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z));
void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
real_glRotatef()(angle, x, y, z);
}
GL_FUNC(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height));
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
real_glViewport()(x, y, width, height);
}
GL_FUNC(glNormal3f, void, (GLfloat nx, GLfloat ny, GLfloat nz));
void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) {
real_glNormal3f()(nx, ny, nz);
}
GL_FUNC(glIsEnabled, GLboolean, (GLenum cap));
GLboolean glIsEnabled(GLenum cap) {
return real_glIsEnabled()(cap);
}
GL_FUNC(glGetIntegerv, void, (GLenum pname, GLint *data));
void glGetIntegerv(GLenum pname, GLint *data) {
real_glGetIntegerv()(pname, data);
}
GL_FUNC(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data));
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
real_glReadPixels()(x, y, width, height, format, type, data);
}

View File

@ -0,0 +1,19 @@
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <libreborn/libreborn.h>
// Load GL Function
#define GL_FUNC(name, return_type, args) \
typedef return_type (*real_##name##_t)args; \
\
static real_##name##_t real_##name() { \
static real_##name##_t func = NULL; \
if (!func) { \
func = (real_##name##_t) glfwGetProcAddress(#name); \
if (!func) { \
ERR("Error Resolving GL Symbol: " #name ": %s", dlerror()); \
} \
} \
return func; \
}

View File

@ -45,7 +45,11 @@ void glDepthRangef(GLclampf near, GLclampf far) {
}
void glDepthFunc(GLenum func) {
}
static GLuint current_buffer = 0;
void glBindBuffer(GLenum target, GLuint buffer) {
if (target == GL_ARRAY_BUFFER) {
current_buffer = buffer;
}
}
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
}
@ -72,14 +76,48 @@ void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
}
void glGenTextures(GLsizei n, GLuint *textures) {
static int i = 0;
for (int j = 0; j < n; j++) {
textures[j] = i++;
}
}
void glDeleteTextures(GLsizei n, const GLuint *textures) {
}
void glAlphaFunc(GLenum func, GLclampf ref) {
}
void glGetFloatv(GLenum pname, GLfloat *params) {
switch (pname) {
case GL_MODELVIEW_MATRIX:
case GL_PROJECTION_MATRIX: {
params[0] = 1;
params[1] = 0;
params[2] = 0;
params[3] = 0;
params[4] = 0;
params[5] = 1;
params[6] = 0;
params[7] = 0;
params[8] = 0;
params[9] = 0;
params[10] = 1;
params[11] = 0;
params[12] = 0;
params[13] = 0;
params[14] = 0;
params[15] = 1;
break;
}
default: {
params[0] = 0;
break;
}
}
}
static GLuint current_texture = 0;
void glBindTexture(GLenum target, GLuint texture) {
if (target == GL_TEXTURE_2D) {
current_texture = texture;
}
}
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
}
@ -101,6 +139,24 @@ GLboolean glIsEnabled(GLenum cap) {
return GL_FALSE;
}
void glGetIntegerv(GLenum pname, GLint *data) {
switch (pname) {
case GL_TEXTURE_BINDING_2D: {
data[0] = current_texture;
break;
}
case GL_ARRAY_BUFFER_BINDING: {
data[0] = current_buffer;
break;
}
case GL_UNPACK_ALIGNMENT: {
data[0] = 1;
break;
}
default: {
data[0] = 0;
break;
}
}
}
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
}

View File

@ -8,13 +8,16 @@
#include "file.h"
#include "engine.h"
#include "api.h"
// Store Audio Sources
static std::vector<ALuint> &get_sources() {
static std::vector<ALuint> sources;
return sources;
}
static std::vector<ALuint> sources;
// Store Idle Audio Sources
#define MAX_IDLE_SOURCES 50
static std::vector<ALuint> idle_sources;
// Error Checking
#define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError())
#define AL_ERROR_CHECK_MANUAL(val) \
{ \
@ -24,6 +27,22 @@ static std::vector<ALuint> &get_sources() {
} \
}
// Delete Sources
void _media_audio_delete_sources() {
if (_media_audio_is_loaded()) {
for (ALuint source : idle_sources) {
alDeleteSources(1, &source);
AL_ERROR_CHECK();
}
for (ALuint source : sources) {
alDeleteSources(1, &source);
AL_ERROR_CHECK();
}
}
idle_sources.clear();
sources.clear();
}
// Update Listener
void media_audio_update(float volume, float x, float y, float z, float yaw) {
// Check
@ -43,8 +62,8 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) {
AL_ERROR_CHECK();
// Clear Finished Sources
std::vector<ALuint>::iterator it = get_sources().begin();
while (it != get_sources().end()) {
std::vector<ALuint>::iterator it = sources.begin();
while (it != sources.end()) {
ALuint source = *it;
bool remove = false;
// Check
@ -56,8 +75,12 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) {
if (source_state != AL_PLAYING) {
// Finished Playing
remove = true;
alDeleteSources(1, &source);
AL_ERROR_CHECK();
if (idle_sources.size() < MAX_IDLE_SOURCES) {
idle_sources.push_back(source);
} else {
alDeleteSources(1, &source);
AL_ERROR_CHECK();
}
}
} else {
// Not A Source
@ -65,7 +88,7 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) {
}
// Remove If Needed
if (remove) {
it = get_sources().erase(it);
it = sources.erase(it);
} else {
++it;
}
@ -73,22 +96,30 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) {
}
}
// Play
void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui) {
// Check
if (_media_audio_is_loaded()) {
// Load Sound
ALuint buffer = _media_audio_get_buffer(source, name);
if (volume > 0.0f && buffer) {
// Create Source
// Get Source
ALuint al_source;
alGenSources(1, &al_source);
// Special Out-Of-Memory Handling
{
ALenum err = alGetError();
if (err == AL_OUT_OF_MEMORY) {
return;
} else {
AL_ERROR_CHECK_MANUAL(err);
if (idle_sources.size() > 0) {
// Use Idle Source
al_source = idle_sources.back();
idle_sources.pop_back();
} else {
// Create Source
alGenSources(1, &al_source);
// Special Out-Of-Memory Handling
{
ALenum err = alGetError();
if (err == AL_OUT_OF_MEMORY) {
return;
} else {
AL_ERROR_CHECK_MANUAL(err);
}
}
}
@ -107,13 +138,13 @@ void media_audio_play(const char *source, const char *name, float x, float y, fl
AL_ERROR_CHECK();
// Set Attenuation
alSourcei(al_source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE);
alSourcei(al_source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE_CLAMPED);
AL_ERROR_CHECK();
alSourcef(al_source, AL_MAX_DISTANCE, 16.0f);
alSourcef(al_source, AL_MAX_DISTANCE, 22.0f);
AL_ERROR_CHECK();
alSourcef(al_source, AL_ROLLOFF_FACTOR, 1.0f);
AL_ERROR_CHECK();
alSourcef(al_source, AL_REFERENCE_DISTANCE, 0.0f);
alSourcef(al_source, AL_REFERENCE_DISTANCE, 2.0f);
AL_ERROR_CHECK();
// Set Buffer
@ -123,7 +154,7 @@ void media_audio_play(const char *source, const char *name, float x, float y, fl
// Play
alSourcePlay(al_source);
AL_ERROR_CHECK();
get_sources().push_back(al_source);
sources.push_back(al_source);
}
}
}

Some files were not shown because too many files have changed in this diff Show More