Compare commits

..

No commits in common. "master" and "2.3.11" have entirely different histories.

182 changed files with 1975 additions and 4288 deletions

25
.gitignore vendored
View File

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

12
.gitmodules vendored
View File

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

View File

@ -1,175 +1,135 @@
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.13.0)
# Build Mode # Specify Options
set(MCPI_BUILD_MODE "native" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code") option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE)
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "arm" "native") option(MCPI_BUNDLE_ARMHF_SYSROOT "Whether To Include An ARMHF Sysroot" ${MCPI_IS_MIXED_BUILD})
option(MCPI_SERVER_MODE "Server Mode" FALSE)
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
if(NOT MCPI_HEADLESS_MODE)
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" ${MCPI_IS_MIXED_BUILD})
option(MCPI_USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE)
else()
set(MCPI_USE_MEDIA_LAYER_PROXY FALSE)
set(MCPI_USE_GLES1_COMPATIBILITY_LAYER FALSE)
endif()
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
if(MCPI_BUILD_MODE STREQUAL "arm") if(MCPI_BUILD_MODE STREQUAL "arm")
set(USE_ARM32_TOOLCHAIN TRUE)
set(BUILD_ARM_COMPONENTS TRUE) set(BUILD_ARM_COMPONENTS TRUE)
set(BUILD_NATIVE_COMPONENTS FALSE) set(BUILD_NATIVE_COMPONENTS FALSE)
elseif(MCPI_BUILD_MODE STREQUAL "native") elseif(MCPI_BUILD_MODE STREQUAL "native")
set(USE_ARM32_TOOLCHAIN FALSE)
set(BUILD_ARM_COMPONENTS FALSE) set(BUILD_ARM_COMPONENTS FALSE)
set(BUILD_NATIVE_COMPONENTS TRUE) 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() else()
message(FATAL_ERROR "Invalid Mode") message(FATAL_ERROR "Invalid Mode")
endif() endif()
# Specify Options # Utility Functions
option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE) include(cmake/util.cmake)
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 # Specify Variant Name
set(MCPI_VARIANT_NAME "minecraft-pi-reborn") set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
if(MCPI_SERVER_MODE) if(MCPI_SERVER_MODE)
string(APPEND MCPI_VARIANT_NAME "-server") set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-server")
else() else()
string(APPEND MCPI_VARIANT_NAME "-client") set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-client")
endif() endif()
# Specify Installation Paths # Specify Installation Paths
set(MCPI_INSTALL_DIR "lib/${MCPI_VARIANT_NAME}") set(MCPI_INSTALL_DIR "lib/${MCPI_VARIANT_NAME}")
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") set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
if(BUILD_ARM_COMPONENTS) set(MCPI_BIN_DIR "${MCPI_INSTALL_DIR}/bin")
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 # Build Mode
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release") set(CMAKE_BUILD_TYPE "Release")
endif() 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 # Start Project
project(minecraft-pi-reborn) project(minecraft-pi-reborn)
# Utility Functions # Sanity Check
include(cmake/util.cmake) if(BUILD_NATIVE_COMPONENTS AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND NOT MCPI_IS_MIXED_BUILD)
# 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.") message(FATAL_ERROR "Project is configured as a mixed-buld, but MCPI_IS_MIXED_BUILD is disabled.")
endif() endif()
if(BUILD_ARM_COMPONENTS AND NOT IS_ARM_TARGETING)
# Require ARM Compilation
if(USE_ARM32_TOOLCHAIN AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
message(FATAL_ERROR "ARM-Targeting Compiler Required") message(FATAL_ERROR "ARM-Targeting Compiler Required")
endif() endif()
# Specify Default Installation Prefix # Specify Default Installation Prefix
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(DEFAULT_PREFIX "/usr") set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "" FORCE)
if(MCPI_IS_APPIMAGE_BUILD)
set(DEFAULT_PREFIX "/")
endif()
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
endif() endif()
# Required Compile Flags # Optimizations
string(CONCAT COMPILE_FLAGS_SETUP if(CMAKE_BUILD_TYPE STREQUAL "Release")
# Optimizations add_compile_options(-O3)
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n" else()
" add_compile_options(-O3 -s)\n" add_compile_options(-g)
"else()\n" endif()
" add_compile_options(-g)\n"
"endif()\n"
# PIC # Use LLD When Using Clang
"set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)\n" if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_link_options("-fuse-ld=lld")
endif()
# Warnings # PIC
"add_link_options(-Wl,--no-undefined)\n" set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
# 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 # Fast Math
add_compile_options(-ffast-math) add_compile_options(-ffast-math)
# Warnings
add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
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()
# Buld Dependencies # Buld Dependencies
add_subdirectory(dependencies) add_subdirectory(dependencies)
# Warnings
add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0)
# Prevents False Positives
add_compile_options(-Wno-stringop-overflow)
endif()
add_link_options(-Wl,--no-undefined)
add_definitions(-D_GNU_SOURCE)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
# 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()
if(MCPI_BUNDLE_ARMHF_SYSROOT)
add_definitions(-DMCPI_BUNDLE_ARMHF_SYSROOT)
endif()
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
add_definitions(-DMCPI_USE_GLES1_COMPATIBILITY_LAYER)
endif()
# Version # Version
set_property( set_property(
DIRECTORY DIRECTORY
APPEND APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS VERSION PROPERTY CMAKE_CONFIGURE_DEPENDS VERSION
) )
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION) file(STRINGS VERSION VERSION)
file(TIMESTAMP "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION_DATE "%Y-%m-%d" UTC) add_definitions(-DVERSION="${VERSION}")
# Build libreborn # Build libreborn
add_subdirectory(libreborn) add_subdirectory(libreborn)
@ -196,17 +156,3 @@ endif()
if(BUILD_NATIVE_COMPONENTS) if(BUILD_NATIVE_COMPONENTS)
add_subdirectory(images) add_subdirectory(images)
endif() 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,12 +3,24 @@ FROM debian:bullseye-slim
# Install # Install
RUN \ RUN \
apt-get update && \ apt-get update && \
apt-get install -y tini qemu-user && \ apt-get install -y tini sed && \
apt-get --fix-broken install -y && \ apt-get --fix-broken install -y && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# Copy # Copy AppImage
ADD ./out/server-amd64 /app 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
# Setup Working Directory # Setup Working Directory
RUN mkdir /data RUN mkdir /data
@ -16,4 +28,4 @@ WORKDIR /data
# Setup Entrypoint # Setup Entrypoint
ENTRYPOINT ["/usr/bin/tini", "--"] ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/app/usr/bin/minecraft-pi-reborn-server"] CMD ["/app/squashfs-root/AppRun"]

6
Jenkinsfile vendored
View File

@ -1,11 +1,11 @@
pipeline { pipeline {
agent none agent none
stages { stages {
stage('Debian Buster') { stage('Debian Bullseye') {
agent { agent {
dockerfile { dockerfile {
filename 'scripts/ci/Dockerfile' filename 'scripts/ci/Dockerfile'
args '-v /var/run/docker.sock:/var/run/docker.sock --network host' args '-v /var/run/docker.sock:/var/run/docker.sock'
} }
} }
stages { stages {
@ -22,8 +22,6 @@ pipeline {
stage('Publish') { stage('Publish') {
steps { steps {
sh 'apt-get update && apt-get install -y docker.io' 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 .' 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')]) { 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}"' sh 'docker login -u "${DOCKER_HUB_USERNAME}" -p "${DOCKER_HUB_PASSWORD}"'

View File

@ -1 +1 @@
2.4.3 2.3.11

View File

@ -0,0 +1,11 @@
# 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

@ -1,12 +0,0 @@
# 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

@ -1,77 +0,0 @@
# 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

@ -1,38 +0,0 @@
# 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,26 +1,19 @@
# Symlink Function # Symlink Function
function(install_symlink target link) function(install_symlink target link)
get_filename_component(parent "${link}" DIRECTORY) install(CODE "\
if(parent STREQUAL "") # Prepare\n \
set(parent ".") set(file \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${link}\")\n \
endif() \
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/symlink/${parent}") # Create Directory\n \
file(CREATE_LINK "${target}" "${CMAKE_BINARY_DIR}/symlink/${link}" SYMBOLIC) get_filename_component(dir \"\${file}\" DIRECTORY)\n \
install(FILES "${CMAKE_BINARY_DIR}/symlink/${link}" DESTINATION "${parent}") file(MAKE_DIRECTORY \${dir})\n \
endfunction() \
# Create Symlink\n \
# Embed Resources if(NOT EXISTS \"\${file}\")\n \
set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}") execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink ${target} \"\${file}\")\n \
function(embed_resource target file) message(\"-- Installing: \${file}\")\n \
# Get C Name else()\n \
get_filename_component(name "${file}" NAME) message(\"-- Up-to-date: \${file}\")\n \
string(MAKE_C_IDENTIFIER "${name}" name) endif() \
# 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() endfunction()

View File

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

View File

@ -0,0 +1,114 @@
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")
# Copy To Binary Directory
set(APT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apt")
file(REMOVE_RECURSE "${APT_DIR}")
file(MAKE_DIRECTORY "${APT_DIR}")
# Make Directories
file(MAKE_DIRECTORY "${APT_DIR}/apt.conf.d")
file(MAKE_DIRECTORY "${APT_DIR}/preferences.d")
file(MAKE_DIRECTORY "${APT_DIR}/keys")
file(MAKE_DIRECTORY "${APT_DIR}/dpkg")
file(TOUCH "${APT_DIR}/dpkg/status")
# Create APT Sources
execute_process(
COMMAND "${CMAKE_SOURCE_DIR}/scripts/tools/get-apt-sources.sh"
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE APT_SOURCES
RESULT_VARIABLE APT_SOURCES_RESULT
)
if(NOT APT_SOURCES_RESULT EQUAL 0)
message(FATAL_ERROR "Unable To Get APT Sources For ARMHF Sysroot")
endif()
file(WRITE "${APT_DIR}/sources.list" "${APT_SOURCES}")
# 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 \"True\";\n"
"Acquire::AllowInsecureRepositories \"True\";\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
)

22
dependencies/glfw/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,22 @@
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
dependencies/glfw/src vendored Submodule

@ -0,0 +1 @@
Subproject commit 62e175ef9fae75335575964c845a302447c012c7

View File

@ -1,33 +1,20 @@
project(libpng) project(libpng)
# ZLib (Needed By libpng)
add_subdirectory(zlib)
# Silence Warnings # Silence Warnings
add_compile_options(-w) add_compile_options(-w)
## LibPNG ## 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 # Download
set(ZLIB_LIBRARY zlibstatic) set(ZLIB_LIBRARY zlibstatic)
set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/zlib/src") set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/../zlib/src")
set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning
add_subdirectory(src EXCLUDE_FROM_ALL) add_subdirectory(src EXCLUDE_FROM_ALL)
set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior
# Use Symbol Versioning set_target_properties(png12 PROPERTIES LINK_OPTIONS "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers") # Use Symbol Versioning
set_target_properties(png12 PROPERTIES LINK_OPTIONS "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers") set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode
# Ensure Build # Ensure Build
add_custom_target(png12-build ALL DEPENDS png12) add_custom_target(png12-build ALL DEPENDS png12)
# Install # Install
install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}") 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 6c445538879f9e916f8e62723d2ac7cd77d96191 Subproject commit 5bb5bf345aef1e62adcfe30791f4364730a2aede

View File

@ -14,8 +14,7 @@ FetchContent_Populate(minecraft-pi)
# Install # Install
install( install(
DIRECTORY "${minecraft-pi_SOURCE_DIR}/" DIRECTORY "${minecraft-pi_SOURCE_DIR}/"
DESTINATION "${MCPI_INSTALL_DIR}/game" DESTINATION "${MCPI_INSTALL_DIR}"
USE_SOURCE_PERMISSIONS USE_SOURCE_PERMISSIONS
REGEX "api" EXCLUDE REGEX "api" EXCLUDE
) )
install_symlink("game/minecraft-pi" "${MCPI_INSTALL_DIR}/minecraft-pi")

View File

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

@ -1 +1 @@
Subproject commit 27cd9e88a72538b00d172dee67d94cb4ce6bc9b9 Subproject commit d673e9aab842d7151d92eb9164872dc05e748db2

View File

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

View File

@ -2,11 +2,6 @@
## Launch Sequence ## 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 ### Client
1. The launcher is started by the user 1. The launcher is started by the user
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn 1. The launcher starts several Zenity dialogs to configure MCPI-Reborn
@ -39,11 +34,12 @@ 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. 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: The utility functions include:
* Taking Screenshots
* Fullscreen * Fullscreen
* Audio * Audio
* Etc * Etc
This is always compiled for the host system's architecture unless the Media Layer Proxy is disabled. This is always compiled for the host system's architecture.
This was created because SDL 1.2 has numerous bugs and is in-general unsupported. This was created because SDL 1.2 has numerous bugs and is in-general unsupported.
@ -64,13 +60,21 @@ 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. 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. Using this in server-mode is redundant (and disallowed).
#### Extras #### Extras
This sub-component contains code that must always be linked directly to MCPI. This sub-component contains code that must always be linked directly to MCPI.
This is always compiled for ARM. 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 #### Headers
This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation. This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation.
@ -94,11 +98,12 @@ This component contains all MCPI symbols.
## Dependencies ## Dependencies
MCPI-Reborn has several dependencies: MCPI-Reborn has several dependencies:
* MCPI (Bundled) * MCPI (Bundled)
* GLFW (Only In Client Mode; Bundled) * GLFW (Only In Client Mode)
* Open GL ES 2.0 * Open GL ES 1.1
* EGL * EGL
* OpenAL (Only In Client Mode) * OpenAL (Only In Client Mode)
* ZLib (Required By LibPNG; Bundled) * ZLib (Required By LibPNG; Bundled)
* LibPNG (Bundled) * LibPNG (Bundled)
* FreeImage (Only In Client Mode)
* QEMU User Mode (Only On Non-ARM Hosts; Runtime Only) * QEMU User Mode (Only On Non-ARM Hosts; Runtime Only)
* Zenity (Only In Client Mode; Runtime Only; Bundled) * Zenity (Only In Client Mode; Runtime Only)

View File

@ -1,11 +1,26 @@
# Building # Building
## Dependencies ## Build Dependencies
* Common
* ARM Compiler
* Host Compiler (Clang)
* CMake
* Host Architecture Dependencies
* Client Mode Only
* GLFW
* FreeImage
* OpenAL
### Debian/Ubuntu ## Runtime Dependencies
```sh * Non-ARM Host Architectures
./scripts/install-dependencies.sh * QEMU User-Mode
``` * Host Architecture Dependencies
* Client Mode Only
* OpenGL ES 1.1
* GLFW
* FreeImage
* OpenAL
* Zenity
## Instructions ## Instructions
```sh ```sh
@ -17,6 +32,3 @@
./scripts/setup.sh <client|server> <armhf|arm64|i686|amd64> <Custom CMake Arguments> ./scripts/setup.sh <client|server> <armhf|arm64|i686|amd64> <Custom CMake Arguments>
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64> ./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,39 +1,5 @@
# Changelog # 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** **2.3.11**
* ``--version`` Command Line Option * ``--version`` Command Line Option
* TPS Measured In Benchmark & Server * TPS Measured In Benchmark & Server

View File

@ -14,9 +14,6 @@ TRUE This Flag Is On By Default
FALSE This Flag Is Off 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) ### ``--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. 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.
@ -28,18 +25,18 @@ The world used will always be re-created on start and uses a hard-coded seed.
## Environmental Variables ## Environmental Variables
### ``MCPI_DEBUG`` ### ``MCPI_DEBUG``
This enables debug logging if it is set. This enables debug logging if you set it to any non-zero-length value.
### Client Mode Only ### Client Mode Only
If any of the following variables aren't set, one configuration dialog will open on startup for each unset variable. If a value isn't set for any of the following variables, a GUI will open that allows you to select one.
#### ``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 ``|``. 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*. 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``. This is the render distance. The possible values are: ``Far``, ``Normal``, ``Short``, and ``Tiny``.
#### ``MCPI_USERNAME`` ### ``MCPI_USERNAME``
This is the username. This is the username.

View File

@ -1,7 +1,7 @@
# Dedicated Server # 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. 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[^1]. This server is also compatible with MCPE Alpha v0.6.1.
## Setup ## Setup
@ -15,5 +15,3 @@ An official Docker image is also provided: [thebrokenrail/minecraft-pi-reborn-se
* Player data is not saved because of limitations with MCPE LAN worlds * 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 * An easy workaround is to place your inventory in a chest before logging off
* Survival Mode servers are incompatible with unmodded MCPI * Survival Mode servers are incompatible with unmodded MCPI
[^1]: The exception to this is buckets, those will crash MCPE players.

View File

@ -1,27 +1,21 @@
# Installation # Installation
## AppImage
Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/). Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/).
### System Requirements ## Picking A Package
* 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``
### Running ### 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
Follow [these](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage) instructions. 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``.

View File

@ -1,19 +0,0 @@
# 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
```

View File

@ -1,15 +0,0 @@
/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

@ -1,15 +0,0 @@
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

@ -1,25 +0,0 @@
// 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

@ -1,15 +0,0 @@
/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

@ -1,15 +0,0 @@
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

@ -1,638 +0,0 @@
// 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);
}

View File

@ -1,15 +0,0 @@
/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

@ -1,15 +0,0 @@
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

@ -1,52 +0,0 @@
// 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,23 +1,10 @@
project(images) project(images)
# Title Background # Title Background
if(NOT MCPI_HEADLESS_MODE) if(NOT MCPI_SERVER_MODE)
install( install(
FILES "background.png" FILES "background.png"
DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui" DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui"
RENAME "titleBG.png" RENAME "titleBG.png"
) )
endif() 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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -1,117 +1,32 @@
project(launcher) project(launcher)
# Dependencies
add_subdirectory(dependencies)
# Launcher # Launcher
add_executable(launcher src/bootstrap.c src/patchelf.c src/crash-report.c) if(BUILD_NATIVE_COMPONENTS)
if(MCPI_SERVER_MODE) add_executable(launcher src/bootstrap.c src/patchelf.c src/crash-report.c)
target_sources(launcher PRIVATE src/server/launcher.c) if(MCPI_SERVER_MODE)
else() target_sources(launcher PRIVATE src/server/launcher.c)
embed_resource(launcher src/client/available-feature-flags) else()
target_sources(launcher PRIVATE src/client/launcher.cpp) target_sources(launcher PRIVATE src/client/launcher.cpp)
endif() endif()
target_link_libraries(launcher reborn-util) target_link_libraries(launcher reborn-util)
# RPath # Install
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native") install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
# Install set(ICON_PATH "data/com.thebrokenrail.MCPIReborn.png")
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}") set(ICON_TARGET_PATH "share/icons/hicolor/scalable/apps")
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}") if(NOT MCPI_SERVER_MODE)
install(DIRECTORY "data/client/" DESTINATION ".")
# Install Desktop Entry install(
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop" FILES "${ICON_PATH}"
"[Desktop Entry]\n" DESTINATION "${ICON_TARGET_PATH}"
"Name=${MCPI_APP_TITLE}\n" RENAME "com.thebrokenrail.MCPIRebornClient.png"
"Comment=Fun with Blocks\n" )
"Icon=${MCPI_APP_ID}\n" else()
"Exec=${MCPI_VARIANT_NAME}\n" install(DIRECTORY "data/server/" DESTINATION ".")
"Type=Application\n" install(
"Categories=Game;\n" FILES "${ICON_PATH}"
) DESTINATION "${ICON_TARGET_PATH}"
if(MCPI_HEADLESS_MODE) RENAME "com.thebrokenrail.MCPIRebornServer.png"
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop" )
"Terminal=true\n" endif()
"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() endif()

View File

@ -37,8 +37,3 @@ TRUE Improved Title Background
TRUE Force Touch GUI Button Behavior TRUE Force Touch GUI Button Behavior
TRUE Improved Button Hover Behavior TRUE Improved Button Hover Behavior
TRUE Implement Create World Dialog 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

@ -0,0 +1,10 @@
[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

@ -0,0 +1,43 @@
<?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.

After

Width:  |  Height:  |  Size: 100 KiB

View File

@ -0,0 +1,9 @@
[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

@ -0,0 +1,38 @@
<?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

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

View File

@ -1,17 +0,0 @@
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")

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

View File

@ -14,6 +14,58 @@
#include "patchelf.h" #include "patchelf.h"
#include "crash-report.h" #include "crash-report.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 : "";
}
// Get All Mods In Folder // Get All Mods In Folder
static void load(char **ld_preload, char *folder) { static void load(char **ld_preload, char *folder) {
int folder_name_length = strlen(folder); int folder_name_length = strlen(folder);
@ -46,14 +98,14 @@ static void load(char **ld_preload, char *folder) {
// Add Terminator // Add Terminator
name[total_length] = '\0'; name[total_length] = '\0';
// Check If File Is Accessible // Check If File Is Executable
int result = access(name, R_OK); int result = access(name, R_OK);
if (result == 0) { if (result == 0) {
// Add To LD_PRELOAD // Add To LD_PRELOAD
string_append(ld_preload, "%s%s", *ld_preload == NULL ? "" : ":", name); string_append(ld_preload, ":%s", name);
} else if (result == -1 && errno != 0) { } else if (result == -1 && errno != 0) {
// Fail // Fail
WARN("Unable To Access: %s: %s", name, strerror(errno)); INFO("Unable To Acesss: %s: %s", name, strerror(errno));
errno = 0; errno = 0;
} }
} }
@ -98,18 +150,11 @@ static void exit_handler(__attribute__((unused)) int signal_id) {
// Pre-Bootstrap // Pre-Bootstrap
void pre_bootstrap(int argc, char *argv[]) { 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 // Print Version
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) { if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
// Print // Print
printf("Reborn v%s\n", MCPI_VERSION); printf("Reborn v%s\n", VERSION);
fflush(stdout); fflush(stdout);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -121,14 +166,12 @@ void pre_bootstrap(int argc, char *argv[]) {
#endif #endif
// Debug Zenity // Debug Zenity
#ifndef MCPI_SERVER_MODE
{ {
const char *is_debug = getenv("MCPI_DEBUG"); const char *is_debug = getenv("MCPI_DEBUG");
if (is_debug != NULL && strlen(is_debug) > 0) { if (is_debug != NULL && strlen(is_debug) > 0) {
set_and_print_env("ZENITY_DEBUG", "1"); set_and_print_env("ZENITY_DEBUG", "1");
} }
} }
#endif
// AppImage // AppImage
#ifdef MCPI_IS_APPIMAGE_BUILD #ifdef MCPI_IS_APPIMAGE_BUILD
@ -146,12 +189,12 @@ void pre_bootstrap(int argc, char *argv[]) {
// Configure PATH // Configure PATH
{ {
// Add Library Directory // Add Library Directory
char *new_path = NULL; char *new_path;
safe_asprintf(&new_path, "%s/bin", binary_directory); safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH // Add Existing PATH
{ {
char *value = getenv("PATH"); char *value = get_env_safe("PATH");
if (value != NULL && strlen(value) > 0) { if (strlen(value) > 0) {
string_append(&new_path, ":%s", value); string_append(&new_path, ":%s", value);
} }
} }
@ -179,48 +222,6 @@ void pre_bootstrap(int argc, char *argv[]) {
sigaction(SIGTERM, &act_sigterm, NULL); 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 // Bootstrap
void bootstrap(int argc, char *argv[]) { void bootstrap(int argc, char *argv[]) {
INFO("Configuring Game..."); INFO("Configuring Game...");
@ -228,9 +229,6 @@ void bootstrap(int argc, char *argv[]) {
// Get Binary Directory // Get Binary Directory
char *binary_directory = get_binary_directory(); char *binary_directory = get_binary_directory();
// Copy SDK
copy_sdk(binary_directory);
// Set MCPI_REBORN_ASSETS_PATH // Set MCPI_REBORN_ASSETS_PATH
{ {
char *assets_path = realpath("/proc/self/exe", NULL); char *assets_path = realpath("/proc/self/exe", NULL);
@ -256,7 +254,6 @@ void bootstrap(int argc, char *argv[]) {
} }
// Fix MCPI Dependencies // Fix MCPI Dependencies
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
{ {
// Log // Log
DEBUG("Patching ELF Dependencies..."); DEBUG("Patching ELF Dependencies...");
@ -264,7 +261,7 @@ void bootstrap(int argc, char *argv[]) {
// Find Linker // Find Linker
char *linker = NULL; char *linker = NULL;
// Select Linker // Select Linker
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN #ifdef MCPI_BUNDLE_ARMHF_SYSROOT
// Use ARM Sysroot Linker // Use ARM Sysroot Linker
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory); safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
#else #else
@ -276,7 +273,7 @@ void bootstrap(int argc, char *argv[]) {
#endif #endif
// Patch // Patch
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker); patch_mcpi_elf_dependencies(resolved_path, linker);
// Free Linker Path // Free Linker Path
if (linker != NULL) { if (linker != NULL) {
@ -284,7 +281,7 @@ void bootstrap(int argc, char *argv[]) {
} }
// Verify // Verify
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) { if (!starts_with(getenv("MCPI_EXECUTABLE_PATH"), "/tmp")) {
IMPOSSIBLE(); IMPOSSIBLE();
} }
} }
@ -302,122 +299,78 @@ void bootstrap(int argc, char *argv[]) {
// Free Resolved Path // Free Resolved Path
free(resolved_path); free(resolved_path);
// Configure Library Search Path // Configure LD_LIBRARY_PATH
{ {
// Log // Log
DEBUG("Setting Linker Search Paths..."); DEBUG("Setting Linker Search Paths...");
// Prepare // Preserve
char *transitive_ld_path = NULL; PRESERVE_ENVIRONMENTAL_VARIABLE("LD_LIBRARY_PATH");
char *mcpi_ld_path = NULL; char *new_ld_path = NULL;
// Library Search Path For Native Components // Add Library Directory
{ safe_asprintf(&new_ld_path, "%s/lib", binary_directory);
// Add Native Library Directory
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
// Add Host LD_LIBRARY_PATH // Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
{ #ifdef MCPI_BUNDLE_ARMHF_SYSROOT
char *value = getenv("LD_LIBRARY_PATH"); string_append(&new_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);
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);
}
// 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 #endif
// Add Host LD_LIBRARY_PATH // Add 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 *value = get_env_safe("LD_LIBRARY_PATH");
char *host_gconv_path = getenv("GCONV_PATH"); if (strlen(value) > 0) {
set_and_print_env("MCPI_NATIVE_GCONV_PATH", host_gconv_path); string_append(&new_ld_path, ":%s", value);
}
// 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
} }
// Set And Free
set_and_print_env("LD_LIBRARY_PATH", new_ld_path);
free(new_ld_path);
} }
// Configure Preloaded Objects // Configure LD_PRELOAD
{ {
// Log // Log
DEBUG("Locating Mods..."); DEBUG("Locating Mods...");
// Native Components // Preserve
char *host_ld_preload = getenv("LD_PRELOAD"); PRESERVE_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload); char *new_ld_preload = NULL;
// ARM Components // ~/.minecraft-pi/mods
{ {
// Prepare // Get Mods Folder
char *preload = NULL; char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
// ~/.minecraft-pi/mods // Load Mods From ./mods
{ load(&new_ld_preload, mods_folder);
// Get Mods Folder // Free Mods Folder
char *mods_folder = NULL; free(mods_folder);
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);
}
// 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);
} }
// 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);
}
}
// Set LD_PRELOAD
set_and_print_env("LD_PRELOAD", new_ld_preload);
free(new_ld_preload);
} }
// Free Binary Directory // Free Binary Directory
@ -438,26 +391,16 @@ void bootstrap(int argc, char *argv[]) {
new_args[argv_start + argc] = NULL; new_args[argv_start + argc] = NULL;
// Set Executable Argument // Set Executable Argument
new_args[argv_start] = new_mcpi_exe_path; new_args[argv_start] = getenv("MCPI_EXECUTABLE_PATH");
// Non-ARM Systems Need QEMU // Non-ARM Systems Need QEMU
#ifndef __ARM_ARCH #ifndef __ARM_ARCH
argv_start--; argv_start--;
new_args[argv_start] = QEMU_BINARY; new_args[argv_start] = QEMU_BINARY;
#endif
// Setup Environment // Prevent QEMU From Being Modded
setup_exec_environment(1); PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU("LD_LIBRARY_PATH");
PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU("LD_PRELOAD");
// 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 #endif
// Run // Run

View File

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

View File

@ -1,4 +1,4 @@
#include <sstream> #include <fstream>
#include <cstring> #include <cstring>
#include <cerrno> #include <cerrno>
#include <sys/wait.h> #include <sys/wait.h>
@ -36,44 +36,46 @@ static std::string strip_feature_flag_default(std::string flag, bool *default_re
} }
// Load Available Feature Flags // 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) { static void load_available_feature_flags(std::function<void(std::string)> callback) {
// Get Path // Get Path
char *binary_directory = get_binary_directory(); char *binary_directory = get_binary_directory();
std::string path = std::string(binary_directory) + "/available-feature-flags"; std::string path = std::string(binary_directory) + "/available-feature-flags";
free(binary_directory); free(binary_directory);
// Load File // Load File
std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len); std::ifstream stream(path);
std::stringstream stream(data); if (stream && stream.good()) {
// Store Lines std::vector<std::string> lines;
std::vector<std::string> lines; // Read File
// Read File {
{ std::string line;
std::string line; while (std::getline(stream, line)) {
while (std::getline(stream, line)) { if (line.length() > 0) {
if (line.length() > 0) { // Verify Line
// Verify Line if (line.find('|') == std::string::npos) {
if (line.find('|') == std::string::npos) { lines.push_back(line);
lines.push_back(line); } else {
} else { // Invalid Line
// Invalid Line ERR("Feature Flag Contains Invalid '|'");
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 // Sort
return stripped_a < stripped_b; std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) {
}); // Strip Defaults
// Run Callbacks std::string stripped_a = strip_feature_flag_default(a, NULL);
for (std::string &line : lines) { std::string stripped_b = strip_feature_flag_default(b, NULL);
callback(line); // 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");
} }
} }
@ -104,15 +106,12 @@ static void run_command_and_set_env(const char *env_name, const char *command[])
} }
// Use Zenity To Set Environmental Variable // 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) { static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
// Create Full Command // Create Full Command
std::vector<std::string> full_command; std::vector<std::string> full_command;
full_command.push_back("zenity"); full_command.push_back("zenity");
full_command.push_back("--title");
full_command.push_back(DIALOG_TITLE);
full_command.push_back("--name"); full_command.push_back("--name");
full_command.push_back(MCPI_APP_ID); full_command.push_back(GUI_TITLE);
full_command.insert(full_command.end(), command.begin(), command.end()); full_command.insert(full_command.end(), command.begin(), command.end());
// Convert To C Array // Convert To C Array
const char *full_command_array[full_command.size() + 1]; const char *full_command_array[full_command.size() + 1];
@ -124,28 +123,9 @@ 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); 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 // Launch
#define LIST_DIALOG_SIZE "400" #define LIST_DIALOG_SIZE "400"
int main(int argc, char *argv[]) { 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); pre_bootstrap(argc, argv);
@ -161,37 +141,6 @@ 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 // Create ~/.minecraft-pi If Needed
// Minecraft Folder // Minecraft Folder
{ {
@ -258,11 +207,14 @@ int main(int argc, char *argv[]) {
command.push_back("Selected"); command.push_back("Selected");
command.push_back("--column"); command.push_back("--column");
command.push_back("Name"); command.push_back("Name");
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"}; command.push_back("FALSE");
for (std::string &render_distance : render_distances) { command.push_back("Far");
command.push_back(render_distance.compare(DEFAULT_RENDER_DISTANCE) == 0 ? "TRUE" : "FALSE"); command.push_back("FALSE");
command.push_back(render_distance); command.push_back("Normal");
} command.push_back("TRUE");
command.push_back("Short");
command.push_back("FALSE");
command.push_back("Tiny");
// Run // Run
run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command); run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command);
} }
@ -273,7 +225,7 @@ int main(int argc, char *argv[]) {
command.push_back("--text"); command.push_back("--text");
command.push_back("Enter Minecraft Username:"); command.push_back("Enter Minecraft Username:");
command.push_back("--entry-text"); command.push_back("--entry-text");
command.push_back(DEFAULT_USERNAME); command.push_back("StevePi");
// Run // Run
run_zenity_and_set_env("MCPI_USERNAME", command); run_zenity_and_set_env("MCPI_USERNAME", command);
} }

View File

@ -7,7 +7,6 @@
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
@ -22,7 +21,7 @@ static void show_report(const char *log_filename) {
const char *command[] = { const char *command[] = {
"zenity", "zenity",
"--title", DIALOG_TITLE, "--title", DIALOG_TITLE,
"--name", MCPI_APP_ID, "--name", GUI_TITLE,
"--width", CRASH_REPORT_DIALOG_WIDTH, "--width", CRASH_REPORT_DIALOG_WIDTH,
"--height", CRASH_REPORT_DIALOG_HEIGHT, "--height", CRASH_REPORT_DIALOG_HEIGHT,
"--text-info", "--text-info",
@ -45,7 +44,6 @@ static void exit_handler(__attribute__((unused)) int signal) {
// Setup // Setup
#define PIPE_READ 0 #define PIPE_READ 0
#define PIPE_WRITE 1 #define PIPE_WRITE 1
#define MCPI_LOGS_DIR "/tmp/.minecraft-pi-logs"
void setup_crash_report() { void setup_crash_report() {
// Store Output // Store Output
int output_pipe[2]; int output_pipe[2];
@ -102,21 +100,8 @@ void setup_crash_report() {
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
char buf[BUFFER_SIZE]; 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 // Create Temporary File
char log_filename[] = MCPI_LOGS_DIR "/XXXXXX"; char log_filename[] = "/tmp/.minecraft-pi-log-XXXXXX";
int log_file_fd = mkstemp(log_filename); int log_file_fd = mkstemp(log_filename);
if (log_file_fd == -1) { if (log_file_fd == -1) {
ERR("Unable To Create Log File: %s", strerror(errno)); ERR("Unable To Create Log File: %s", strerror(errno));

View File

@ -8,21 +8,23 @@
#include "patchelf.h" #include "patchelf.h"
// Duplicate MCPI Executable Into /tmp // Duplicate MCPI Executable Into /tmp
static void duplicate_mcpi_executable(const char *original_path, char *new_path) { #define TMP_DIR "/tmp/.minecraft-pi-patched"
static void duplicate_mcpi_executable(const char *original_path) {
// Ensure Temporary Directory // Ensure Temporary Directory
{ {
// Check If It Exists // Check If It Exists
struct stat tmp_stat; struct stat tmp_stat;
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode); int exists = stat(TMP_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) { if (!exists) {
// Doesn't Exist // Doesn't Exist
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) { if (mkdir(TMP_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno)); ERR("Unable To Create Temporary Folder: %s", strerror(errno));
} }
} }
} }
// Generate New File // Generate New File
char new_path[] = TMP_DIR "/XXXXXX";
int new_file_fd = mkstemp(new_path); int new_file_fd = mkstemp(new_path);
if (new_file_fd == -1) { if (new_file_fd == -1) {
ERR("Unable To Create Temporary File: %s", strerror(errno)); ERR("Unable To Create Temporary File: %s", strerror(errno));
@ -31,6 +33,7 @@ static void duplicate_mcpi_executable(const char *original_path, char *new_path)
if (new_file == NULL) { if (new_file == NULL) {
ERR("Unable To Open Temporary File: %s", strerror(errno)); ERR("Unable To Open Temporary File: %s", strerror(errno));
} }
set_and_print_env("MCPI_EXECUTABLE_PATH", new_path);
// Copy Original File // Copy Original File
{ {
@ -72,10 +75,8 @@ static void duplicate_mcpi_executable(const char *original_path, char *new_path)
"--remove-needed", "libbcm_host.so", \ "--remove-needed", "libbcm_host.so", \
"--remove-needed", "libX11.so.6", \ "--remove-needed", "libX11.so.6", \
"--remove-needed", "libEGL.so", \ "--remove-needed", "libEGL.so", \
"--remove-needed", "libGLESv2.so", \ "--replace-needed", "libGLESv2.so", "libGLESv1_CM.so.1", \
"--remove-needed", "libSDL-1.2.so.0", \ exe, \
"--add-needed", "libmedia-layer-core.so", \
new_path, \
NULL \ NULL \
}; \ }; \
int _macro_return_code = 0; \ int _macro_return_code = 0; \
@ -85,9 +86,12 @@ static void duplicate_mcpi_executable(const char *original_path, char *new_path)
} \ } \
_macro_return_code; \ _macro_return_code; \
}) })
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) { void patch_mcpi_elf_dependencies(const char *original_path, const char *linker) {
// Duplicate MCPI executable into /tmp so it can be modified. // Duplicate MCPI executable into /tmp so it can be modified.
duplicate_mcpi_executable(original_path, new_path); duplicate_mcpi_executable(original_path);
// Get Path
char *exe = getenv("MCPI_EXECUTABLE_PATH");
// Run patchelf // Run patchelf
int return_code; int return_code;
@ -103,8 +107,8 @@ void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, cons
} }
// Fix Permissions // Fix Permissions
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) { if (chmod(exe, S_IRUSR | S_IXUSR) != 0) {
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno)); ERR("Unable To Set File Permissions: %s: %s", exe, strerror(errno));
} }
} }

View File

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

View File

@ -1,8 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <libreborn/libreborn.h>
#include "../bootstrap.h" #include "../bootstrap.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

View File

@ -1,34 +1,12 @@
project(libreborn) project(libreborn)
# Config add_library(reborn-util STATIC src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn") target_include_directories(reborn-util PUBLIC include)
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) if(BUILD_ARM_COMPONENTS)
add_library(reborn-patch SHARED src/patch/patch.c) add_library(reborn-patch SHARED src/patch/patch.c)
target_link_libraries(reborn-patch dl pthread reborn-util) target_link_libraries(reborn-patch dl pthread reborn-util)
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE) target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
# Install # Install
install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}") install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}")
# SDK
install(TARGETS reborn-patch EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif() endif()

View File

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

View File

@ -1,11 +0,0 @@
#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

@ -16,15 +16,7 @@
extern "C" { extern "C" {
#endif #endif
// Set Environmental Variable
void set_and_print_env(const char *name, const char *value);
// Safe execvpe() // 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[]); __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
// Chop Off Last Component // Chop Off Last Component
@ -32,6 +24,9 @@ void chop_last_component(char **str);
// Get Binary Directory (Remember To Free) // Get Binary Directory (Remember To Free)
char *get_binary_directory(); 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 // Run Command And Get Output
char *run_command(const char *const command[], int *exit_status); char *run_command(const char *const command[], int *exit_status);
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0) #define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)

View File

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

View File

@ -6,6 +6,6 @@
// Logging // Logging
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); } #define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); } #define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
#define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: " format "\n", ##__VA_ARGS__); } } #define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL && strlen(debug) > 0) { 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 ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("This Should Never Be Called") #define IMPOSSIBLE() ERR("This Should Never Be Called")

View File

@ -14,8 +14,6 @@ void _overwrite_call(const char *file, int line, void *start, void *target);
void _overwrite_calls(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); #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); void _overwrite(const char *file, int line, void *start, void *target);
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target); #define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);

View File

@ -3,8 +3,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <iconv.h>
#include <stdint.h>
#include "util.h" #include "util.h"
@ -35,11 +33,6 @@ extern "C" {
// Sanitize String // Sanitize String
void sanitize_string(char **str, int max_length, unsigned int allow_newlines); 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 // Starts With
int starts_with(const char *str, const char *prefix); int starts_with(const char *str, const char *prefix);

View File

@ -32,6 +32,17 @@
\ \
__attribute__((__used__)) return_type name args __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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -72,12 +72,6 @@ static unsigned char *code_block = NULL;
#define CODE_SIZE 8 #define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE; 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) { 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 // 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) { if (code_block == NULL) {
@ -90,31 +84,28 @@ static void update_code_block(void *target) {
if (code_block_remaining < CODE_SIZE) { if (code_block_remaining < CODE_SIZE) {
ERR("Maximum Amount Of overwrite_calls() Uses Reached"); ERR("Maximum Amount Of overwrite_calls() Uses Reached");
} }
_long_overwrite(code_block, target); _overwrite(NULL, -1, code_block, target);
} }
static void increment_code_block() { static void increment_code_block() {
code_block = code_block + CODE_SIZE; code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE; code_block_remaining = code_block_remaining - CODE_SIZE;
} }
// Overwrite Specific B(L) Instruction // Overwrite Specific BL Instruction
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) { void _overwrite_call(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block // Add New Target To Code Block
update_code_block(target); update_code_block(target);
// Patch // Patch
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction); uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
_patch(file, line, start, (unsigned char *) &new_instruction); _patch(file, line, start, (unsigned char *) &new_instruction);
// Increment Code Block Position // Increment Code Block Position
increment_code_block(); 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 All B(L) Intrusctions That Target The Specified Address // Overwrite Function Calls
void _overwrite_calls(const char *file, int line, void *start, void *target) { void _overwrite_calls(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block // Add New Target To Code Block
update_code_block(target); update_code_block(target);
@ -137,24 +128,13 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
} }
} }
// Extract Target Address From B(L) Instruction
void *extract_from_bl_instruction(unsigned char *from) {
unsigned char *pc = ((unsigned char *) from) + 8;
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 // Overwrite Function
// NOTE: "start" Must Be At Least 8 Bytes Long
void _overwrite(const char *file, int line, void *start, void *target) { void _overwrite(const char *file, int line, void *start, void *target) {
_overwrite_call_internal(file, line, start, target, 1); unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(file, line, start, patch_data);
_patch_address(file, line, (void *) (((unsigned char *) start) + 4), target);
} }
// Print Patch Debug Data // Print Patch Debug Data

View File

@ -2,44 +2,10 @@
#include <libreborn/exec.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() // 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[]) { __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); int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
if (ret == -1) { 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)); ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
} else { } else {
IMPOSSIBLE(); IMPOSSIBLE();
@ -70,6 +36,29 @@ char *get_binary_directory() {
return exe; 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 // Run Command And Get Output
char *run_command(const char *const command[], int *exit_status) { char *run_command(const char *const command[], int *exit_status) {
// Store Output // Store Output
@ -87,9 +76,6 @@ char *run_command(const char *const command[], int *exit_status) {
close(output_pipe[0]); close(output_pipe[0]);
close(output_pipe[1]); close(output_pipe[1]);
// Setup Environment
setup_exec_environment(0);
// Run // Run
safe_execvpe(command, (const char *const *) environ); safe_execvpe(command, (const char *const *) environ);
} else { } else {

View File

@ -1,9 +1,8 @@
#include <iconv.h>
#include <stdint.h>
#include <libreborn/string.h> #include <libreborn/string.h>
// Sanitize String // Sanitize String
#define MINIMUM_SAFE_CHARACTER 32
#define MAXIMUM_SAFE_CHARACTER 126
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) { void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
// Store Message Length // Store Message Length
int length = strlen(*str); int length = strlen(*str);
@ -13,135 +12,18 @@ void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
length = max_length; length = max_length;
} }
// Loop Through Message // Loop Through Message
if (!allow_newlines) { for (int i = 0; i < length; i++) {
for (int i = 0; i < length; i++) { if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
if ((*str)[i] == '\n' || (*str)[i] == '\r') { continue;
// Replace Newline }
(*str)[i] = ' '; unsigned char c = (unsigned char) (*str)[i];
} if (c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) {
// Replace Illegal Character
(*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 // Starts With
int starts_with(const char *str, const char *prefix) { int starts_with(const char *str, const char *prefix) {
return strncmp(prefix, str, strlen(prefix)) == 0; return strncmp(prefix, str, strlen(prefix)) == 0;

View File

@ -1,28 +1,23 @@
project(media-layer) project(media-layer)
# Target Notes:
# media-layer-core-real: Fully Built Media Layer Core
# media-layer-core: Alias Target That Points To The Library MCPI Should Link To
# Add Headers # Add Headers
add_library(media-layer-headers INTERFACE) add_library(media-layer-headers INTERFACE)
target_include_directories( target_include_directories(media-layer-headers INTERFACE include)
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 GLESv1_CM Stubs Or Compatibility Layer
add_subdirectory(extras) add_subdirectory(gles)
# Add Core # Add 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)
add_subdirectory(core)
endif()
# Add Proxy # Add Proxy
if(MCPI_USE_MEDIA_LAYER_PROXY) if(MCPI_USE_MEDIA_LAYER_PROXY)
add_subdirectory(proxy) add_subdirectory(proxy)
endif() endif()
# Add Extras
add_subdirectory(extras)

View File

@ -1,32 +1,41 @@
project(media-layer-core) project(media-layer-core)
# Dependencies
add_subdirectory(dependencies)
# OpenGL
add_subdirectory(gles)
# Configuration # Configuration
set(CORE_SRC src/base.cpp src/media.c $<TARGET_OBJECTS:media-layer-extras>) # SDL Re-Implementation Using GLFW set(CORE_SRC src/base.cpp src/media.c src/screenshot.c) # SDL Re-Implementation Using GLFW
if(NOT MCPI_HEADLESS_MODE) if(NOT MCPI_HEADLESS_MODE)
list(APPEND CORE_SRC src/audio/api.cpp src/audio/engine.c src/audio/file.cpp) 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() endif()
# Build # Build
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
# Install # Build Media Layer Core Natively And Use Proxy
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}") add_library(media-layer-core-real OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
if(BUILD_ARM_COMPONENTS) endif()
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}") if(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
# Directly Link Media Layer Core To MCPI
add_library(media-layer-core-real SHARED ${CORE_SRC}) # Dependencies Are Setup Later
set_target_properties(media-layer-core-real PROPERTIES OUTPUT_NAME "media-layer-core")
# Install
install(TARGETS media-layer-core-real DESTINATION "${MCPI_LIB_DIR}")
# Create Alias Target For Linking
add_library(media-layer-core ALIAS media-layer-core-real)
endif() endif()
# Link # Configure Media Layer Core If Built
target_link_libraries(media-layer-core PUBLIC media-layer-headers PUBLIC reborn-util PUBLIC GLESv1_CM PUBLIC dl) if(TARGET media-layer-core-real)
if(NOT MCPI_HEADLESS_MODE)
# OpenAL
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link # Link
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw) target_link_libraries(media-layer-core-real 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-real "${FREEIMAGE_LIBRARY}" "${OPENAL_LIBRARY}" m GLESv1_CM glfw)
endif()
endif()
# Add Symlinks So MCPI Can Locate Libraries
if(BUILD_ARM_COMPONENTS)
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libSDL-1.2.so.0")
endif() endif()

View File

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

View File

@ -1,31 +0,0 @@
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")

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

View File

@ -1,32 +0,0 @@
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

@ -1,35 +0,0 @@
#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

@ -1,39 +0,0 @@
#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

@ -1,22 +0,0 @@
#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

@ -1,204 +0,0 @@
#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

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

View File

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

View File

@ -6,7 +6,6 @@
#include "engine.h" #include "engine.h"
#include "file.h" #include "file.h"
#include "api.h"
// Store Device // Store Device
static ALCdevice *device = NULL; static ALCdevice *device = NULL;
@ -56,9 +55,6 @@ void _media_audio_init() {
// De-Init // De-Init
void _media_audio_cleanup() { void _media_audio_cleanup() {
if (_media_audio_is_loaded()) { if (_media_audio_is_loaded()) {
// Delete Audio Sources
_media_audio_delete_sources();
// Delete Audio Buffers // Delete Audio Buffers
_media_audio_delete_buffers(); _media_audio_delete_buffers();

View File

@ -229,7 +229,7 @@ ALuint _media_audio_get_buffer(const char *source, const char *name) {
// Delete Buffers // Delete Buffers
void _media_audio_delete_buffers() { void _media_audio_delete_buffers() {
if (_media_audio_is_loaded()) { if (_media_audio_is_loaded()) {
for (auto &it : buffers) { for (auto it : buffers) {
if (it.second && alIsBuffer(it.second)) { if (it.second && alIsBuffer(it.second)) {
alDeleteBuffers(1, &it.second); alDeleteBuffers(1, &it.second);
} }

View File

@ -1,6 +0,0 @@
#include <media-layer/audio.h>
void media_audio_update(__attribute__((unused)) float volume, __attribute__((unused)) float x, __attribute__((unused)) float y, __attribute__((unused)) float z, __attribute__((unused)) float yaw) {
}
void media_audio_play(__attribute__((unused)) const char *source, __attribute__((unused)) const char *name, __attribute__((unused)) float x, __attribute__((unused)) float y, __attribute__((unused)) float z, __attribute__((unused)) float pitch, __attribute__((unused)) float volume, __attribute__((unused)) int is_ui) {
}

View File

@ -1,4 +1,5 @@
#include <cstdlib> #include <cstdlib>
#include <pthread.h>
#include <vector> #include <vector>
#include <SDL/SDL.h> #include <SDL/SDL.h>
@ -14,6 +15,7 @@ int SDL_Init(__attribute__((unused)) uint32_t flags) {
// Event Queue // Event Queue
static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
static std::vector<SDL_Event> queue; static std::vector<SDL_Event> queue;
int SDL_PollEvent(SDL_Event *event) { int SDL_PollEvent(SDL_Event *event) {
@ -21,6 +23,7 @@ int SDL_PollEvent(SDL_Event *event) {
_media_handle_SDL_PollEvent(); _media_handle_SDL_PollEvent();
// Poll Event // Poll Event
pthread_mutex_lock(&queue_mutex);
int ret; int ret;
if (queue.size() > 0) { if (queue.size() > 0) {
*event = queue[0]; *event = queue[0];
@ -29,11 +32,14 @@ int SDL_PollEvent(SDL_Event *event) {
} else { } else {
ret = 0; ret = 0;
} }
pthread_mutex_unlock(&queue_mutex);
return ret; return ret;
} }
int SDL_PushEvent(SDL_Event *event) { int SDL_PushEvent(SDL_Event *event) {
pthread_mutex_lock(&queue_mutex);
queue.push_back(*event); queue.push_back(*event);
pthread_mutex_unlock(&queue_mutex);
return 1; return 1;
} }

View File

@ -1,13 +1,13 @@
#include <unistd.h> #include <unistd.h>
#include <SDL/SDL.h> #include <SDL/SDL.h>
#include <libreborn/libreborn.h>
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#endif #endif
#include <libreborn/libreborn.h>
#include <media-layer/core.h> #include <media-layer/core.h>
#include <media-layer/internal.h> #include <media-layer/internal.h>
@ -155,42 +155,16 @@ static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int sc
event.key.keysym.mod = glfw_modifier_to_sdl_modifier(mods); event.key.keysym.mod = glfw_modifier_to_sdl_modifier(mods);
event.key.keysym.sym = glfw_key_to_sdl_key(key); event.key.keysym.sym = glfw_key_to_sdl_key(key);
SDL_PushEvent(&event); SDL_PushEvent(&event);
if (key == GLFW_KEY_BACKSPACE && !up) {
character_event((char) '\b');
}
} }
} }
// Pass Text To Minecraft // Pass Text To Minecraft
static void codepoint_to_utf8(unsigned char *const buffer, const unsigned int code) {
// https://stackoverflow.com/a/42013433/16198887
if (code <= 0x7f) {
buffer[0] = code;
} else if (code <= 0x7ff) {
buffer[0] = 0xc0 | (code >> 6); // 110xxxxx
buffer[1] = 0x80 | (code & 0x3f); // 10xxxxxx
} else if (code <= 0xffff) {
buffer[0] = 0xe0 | (code >> 12); // 1110xxxx
buffer[1] = 0x80 | ((code >> 6) & 0x3f); // 10xxxxxx
buffer[2] = 0x80 | (code & 0x3f); // 10xxxxxx
} else if (code <= 0x10ffff) {
buffer[0] = 0xf0 | (code >> 18); // 11110xxx
buffer[1] = 0x80 | ((code >> 12) & 0x3f); // 10xxxxxx
buffer[2] = 0x80 | ((code >> 6) & 0x3f); // 10xxxxxx
buffer[3] = 0x80 | (code & 0x3f); // 10xxxxxx
}
}
static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) { static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
if (is_interactable) { if (is_interactable) {
// Convert character_event((char) codepoint);
size_t str_size = 4 /* Maximum UTF-8 character size */ + 1 /* NULL-terminator */;
char str[str_size];
memset(str, 0, str_size);
codepoint_to_utf8((unsigned char *) str, codepoint);
char *cp437_str = to_cp437(str);
// Send Event·
for (int i = 0; cp437_str[i] != '\0'; i++) {
character_event(cp437_str[i]);
}
// Free
free(cp437_str);
} }
} }
@ -277,15 +251,6 @@ void media_disable_vsync() {
#endif #endif
} }
// Force EGL
static int force_egl = 0;
void media_force_egl() {
if (force_egl == -1) {
IMPOSSIBLE();
}
force_egl = 1;
}
// Init Media Layer // Init Media Layer
#define GL_VERSION 0x1f02 #define GL_VERSION 0x1f02
typedef const unsigned char *(*glGetString_t)(unsigned int name); typedef const unsigned char *(*glGetString_t)(unsigned int name);
@ -309,16 +274,10 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif #endif
// Use EGL // Use EGL
if (force_egl) { glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
}
force_egl = -1;
// Extra Settings // Extra Settings
glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE); glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);
glfwWindowHint(GLFW_ALPHA_BITS, 0); // Fix Transparent Window On Wayland glfwWindowHint(GLFW_ALPHA_BITS, 0); // Fix Transparent Window On Wayland
// App ID
glfwWindowHintString(GLFW_X11_CLASS_NAME, MCPI_APP_ID);
glfwWindowHintString(GLFW_WAYLAND_APP_ID, MCPI_APP_ID);
// Create Window // Create Window
glfw_window = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, title, NULL, NULL); glfw_window = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, title, NULL, NULL);

View File

@ -1,3 +1,6 @@
// Screenshot Code Is Useless In Headless Mode
#ifndef MCPI_HEADLESS_MODE
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -6,11 +9,12 @@
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <png.h> #include <FreeImage.h>
#include <GLES/gl.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <GLES/gl.h> #include <media-layer/core.h>
#include <mods/screenshot/screenshot.h>
// Ensure Screenshots Folder Exists // Ensure Screenshots Folder Exists
static void ensure_screenshots_folder(char *screenshots) { static void ensure_screenshots_folder(char *screenshots) {
@ -30,71 +34,7 @@ static void ensure_screenshots_folder(char *screenshots) {
#define TIME_SIZE 20 #define TIME_SIZE 20
// Take Screenshot // Take Screenshot
static int save_png(const char *filename, unsigned char *pixels, int line_size, int width, int height) { void media_take_screenshot(char *home) {
// Return value
int ret = 0;
// Variables
png_structp png = NULL;
png_infop info = NULL;
FILE *file = NULL;
png_colorp palette = NULL;
png_bytep rows[height];
for (int i = 0; i < height; ++i) {
rows[height - i - 1] = (png_bytep) (&pixels[i * line_size]);
}
// Init
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
ret = 1;
goto ret;
}
info = png_create_info_struct(png);
if (!info) {
ret = 1;
goto ret;
}
// Open File
file = fopen(filename, "wb");
if (!file) {
ret = 1;
goto ret;
}
// Prepare To Write
png_init_io(png, file);
png_set_IHDR(png, info, width, height, 8 /* Depth */, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
palette = (png_colorp) png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
if (!palette) {
ret = 1;
goto ret;
}
png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH);
png_write_info(png, info);
png_set_packing(png);
// Write
png_write_image(png, rows);
png_write_end(png, info);
ret:
// Free
if (palette != NULL) {
png_free(png, palette);
}
if (file != NULL) {
fclose(file);
}
if (png != NULL) {
png_destroy_write_struct(&png, &info);
}
// Return
return ret;
}
void screenshot_take(char *home) {
// Get Directory // Get Directory
char *screenshots = NULL; char *screenshots = NULL;
safe_asprintf(&screenshots, "%s/screenshots", home); safe_asprintf(&screenshots, "%s/screenshots", home);
@ -147,14 +87,43 @@ void screenshot_take(char *home) {
unsigned char pixels[size]; unsigned char pixels[size];
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Handle Little Endian Systems
#if __BYTE_ORDER == __LITTLE_ENDIAN
// Swap Red And Blue
for (int j = 0; j < width; j++) {
for (int k = 0; k < height; k++) {
int pixel = (k * line_size) + (j * 4);
// Swap
int red = pixels[pixel];
int blue = pixels[pixel + 2];
pixels[pixel] = blue;
pixels[pixel + 2] = red;
}
}
#endif
// Save Image // Save Image
if (save_png(file, pixels, line_size, width, height)) { FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0);
WARN("Screenshot Failed: %s", file); if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
INFO("Screenshot Failed: %s", file);
} else { } else {
INFO("Screenshot Saved: %s", file); INFO("Screenshot Saved: %s", file);
} }
FreeImage_Unload(image);
// Free // Free
free(file); free(file);
free(screenshots); free(screenshots);
} }
// Init
__attribute__((constructor)) static void init() {
// Init FreeImage
FreeImage_Initialise(0);
}
#else
void media_take_screenshot() {
// NOP
}
#endif

View File

@ -1,5 +1,11 @@
project(media-layer-extras) project(media-layer-extras)
# Build if(BUILD_ARM_COMPONENTS)
add_library(media-layer-extras OBJECT src/SDL.c) # Add Source To Media Core
target_link_libraries(media-layer-extras media-layer-headers reborn-util) if(TARGET media-layer-core-real)
set(TARGET media-layer-core-real)
elseif(TARGET media-layer-proxy-server)
set(TARGET media-layer-proxy-server)
endif()
target_sources("${TARGET}" PRIVATE src/SDL.c)
endif()

View File

@ -0,0 +1,29 @@
project(media-layer-stubs)
# Stubs Only Needed For ARM
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER AND BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
# GLESv1_CM Compatibility Layer
set(GLES1_LINK_MODE "SHARED")
if(MCPI_USE_MEDIA_LAYER_PROXY)
# Link To Media Layer Proxy Client Statically
# (This is so it doesn't interfere with the Media Layer Proxy Server's libGLESv1_CM.so.1 symlink.)
set(GLES1_LINK_MODE "OBJECT")
endif()
add_library(GLESv1_CM "${GLES1_LINK_MODE}" src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c)
target_link_libraries(GLESv1_CM glfw reborn-util dl m)
# Install
if(NOT MCPI_USE_MEDIA_LAYER_PROXY)
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
endif()
else()
# Add GLESv1_CM Stubs For Linking
add_library(GLESv1_CM SHARED src/stubs.c)
# Install Fake GLESv1_CM Stubs In Server Mode
if(MCPI_HEADLESS_MODE AND BUILD_ARM_COMPONENTS)
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
endif()
endif()
# Common
target_link_libraries(GLESv1_CM media-layer-headers)
set_target_properties(GLESv1_CM PROPERTIES SOVERSION "1")

View File

@ -1,5 +1,5 @@
#include "state.h" #include "state.h"
#include "../passthrough.h" #include "passthrough.h"
#include <GLES/gl.h> #include <GLES/gl.h>
@ -54,16 +54,16 @@ static void log_shader(GLuint shader, const char *name) {
ERR("Failed To Compile %s Shader", name); 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) { static GLuint compile_shader(const char *vertex_shader_text, const char *fragment_shader_text) {
// Vertex Shader // Vertex Shader
const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER); const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER);
real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, &vertex_shader_length); real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, NULL);
real_glCompileShader()(vertex_shader); real_glCompileShader()(vertex_shader);
log_shader(vertex_shader, "Vertex"); log_shader(vertex_shader, "Vertex");
// Fragment Shader // Fragment Shader
const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER); const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER);
real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, &fragment_shader_length); real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, NULL);
real_glCompileShader()(fragment_shader); real_glCompileShader()(fragment_shader);
log_shader(fragment_shader, "Fragment"); log_shader(fragment_shader, "Fragment");
@ -78,14 +78,70 @@ static GLuint compile_shader(const char *vertex_shader_text, const int vertex_sh
} }
// Shader // 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 get_shader() {
static GLuint program = 0; static GLuint program = 0;
if (program == 0) { if (program == 0) {
program = compile_shader((const char *) main_vsh, main_vsh_len, (const char *) main_fsh, main_fsh_len); static const char *vertex_shader_text =
"#version 100\n"
"precision mediump float;\n"
// Matrices
"uniform mat4 u_projection;\n"
"uniform mat4 u_model_view;\n"
"uniform mat4 u_texture;\n"
// Texture
"attribute vec3 a_vertex_coords;\n"
"attribute vec2 a_texture_coords;\n"
"varying vec4 v_texture_pos;\n"
// Color
"attribute vec4 a_color;\n"
"varying vec4 v_color;\n"
// Fog
"varying vec4 v_fog_eye_position;\n"
// Main
"void main() {\n"
" v_texture_pos = u_texture * vec4(a_texture_coords.xy, 0.0, 1.0);\n"
" gl_Position = u_projection * u_model_view * vec4(a_vertex_coords.xyz, 1.0);\n"
" v_color = a_color;\n"
" v_fog_eye_position = u_model_view * vec4(a_vertex_coords.xyz, 1.0);\n"
"}";
static const char *fragment_shader_text =
"#version 100\n"
"precision mediump float;\n"
// Texture
"uniform bool u_has_texture;"
"uniform sampler2D u_texture_unit;\n"
// Color
"varying vec4 v_color;\n"
"varying vec4 v_texture_pos;\n"
// Alpha Test
"uniform bool u_alpha_test;\n"
// Fog
"uniform bool u_fog;\n"
"uniform vec4 u_fog_color;\n"
"uniform bool u_fog_is_linear;\n"
"uniform float u_fog_start;\n"
"uniform float u_fog_end;\n"
"varying vec4 v_fog_eye_position;\n"
// Main
"void main(void) {\n"
" gl_FragColor = v_color;\n"
" if (u_has_texture) {\n"
" gl_FragColor *= texture2D(u_texture_unit, v_texture_pos.xy);\n"
" }\n"
" if (u_alpha_test && gl_FragColor.a <= 0.1) {\n"
" discard;\n"
" }\n"
" if (u_fog) {\n"
" float fog_factor;\n"
" if (u_fog_is_linear) {\n"
" fog_factor = (u_fog_end - length(v_fog_eye_position)) / (u_fog_end - u_fog_start);\n"
" } else {\n"
" fog_factor = exp(-u_fog_start * length(v_fog_eye_position));\n"
" }\n"
" gl_FragColor = mix(gl_FragColor, u_fog_color, 1.0 - clamp(fog_factor, 0.0, 1.0));\n"
" }\n"
"}";
program = compile_shader(vertex_shader_text, fragment_shader_text);
} }
return program; return program;
} }
@ -101,11 +157,6 @@ static void use_shader(GLuint program) {
// Array Pointer Drawing // Array Pointer Drawing
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)); 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) { void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
// Verify // Verify
if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) { if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) {
@ -127,30 +178,30 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
use_shader(program); use_shader(program);
// Projection Matrix // Projection Matrix
lazy_uniform(u_projection); GLint u_projection_handle = real_glGetUniformLocation()(program, "u_projection");
matrix_t *p = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i]; 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]); real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Model View Matrix // Model View Matrix
lazy_uniform(u_model_view); GLint u_model_view_handle = real_glGetUniformLocation()(program, "u_model_view");
p = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i]; 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]); real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Has Texture // Has Texture
lazy_uniform(u_has_texture); \ GLint u_has_texture_handle = real_glGetUniformLocation()(program, "u_has_texture"); \
real_glUniform1i()(u_has_texture_handle, use_texture); \ real_glUniform1i()(u_has_texture_handle, use_texture); \
// Texture Matrix // Texture Matrix
lazy_uniform(u_texture); GLint u_texture_handle = real_glGetUniformLocation()(program, "u_texture");
p = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i]; 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]); real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Texture Unit // Texture Unit
lazy_uniform(u_texture_unit); GLint u_texture_unit_handle = real_glGetUniformLocation()(program, "u_texture_unit");
real_glUniform1i()(u_texture_unit_handle, 0); real_glUniform1i()(u_texture_unit_handle, 0);
// Alpha Test // Alpha Test
lazy_uniform(u_alpha_test); GLint u_alpha_test_handle = real_glGetUniformLocation()(program, "u_alpha_test");
real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test); real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test);
// Color // Color
@ -163,16 +214,16 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
} }
// Fog // Fog
lazy_uniform(u_fog); GLint u_fog_handle = real_glGetUniformLocation()(program, "u_fog");
real_glUniform1i()(u_fog_handle, gl_state.fog.enabled); real_glUniform1i()(u_fog_handle, gl_state.fog.enabled);
if (gl_state.fog.enabled) { if (gl_state.fog.enabled) {
lazy_uniform(u_fog_color); GLint u_fog_color_handle = real_glGetUniformLocation()(program, "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]); 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); GLint u_fog_is_linear_handle = real_glGetUniformLocation()(program, "u_fog_is_linear");
real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR); real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR);
lazy_uniform(u_fog_start); GLint u_fog_start_handle = real_glGetUniformLocation()(program, "u_fog_start");
real_glUniform1f()(u_fog_start_handle, gl_state.fog.start); real_glUniform1f()(u_fog_start_handle, gl_state.fog.start);
lazy_uniform(u_fog_end); GLint u_fog_end_handle = real_glGetUniformLocation()(program, "u_fog_end");
real_glUniform1f()(u_fog_end_handle, gl_state.fog.end); real_glUniform1f()(u_fog_end_handle, gl_state.fog.end);
} }

View File

@ -4,6 +4,7 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "state.h" #include "state.h"
#include "passthrough.h"
// Matrix Common // Matrix Common
static void matrix_copy(matrix_t *src, matrix_t *dst) { static void matrix_copy(matrix_t *src, matrix_t *dst) {

View File

@ -1,6 +1,6 @@
#include <GLES/gl.h> #include <GLES/gl.h>
#include "../passthrough.h" #include "passthrough.h"
// Simple v1.1 -> v2.0 Passthrough Functions // Simple v1.1 -> v2.0 Passthrough Functions
GL_FUNC(glLineWidth, void, (GLfloat width)); GL_FUNC(glLineWidth, void, (GLfloat width));
@ -43,6 +43,10 @@ GL_FUNC(glDepthFunc, void, (GLenum func));
void glDepthFunc(GLenum func) { void glDepthFunc(GLenum func) {
real_glDepthFunc()(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)); GL_FUNC(glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
real_glClearColor()(red, green, blue, alpha); real_glClearColor()(red, green, blue, alpha);
@ -57,6 +61,10 @@ void glHint(GLenum target, GLenum mode) {
real_glHint()(target, mode); real_glHint()(target, mode);
} }
} }
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)); GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
real_glColorMask()(red, green, blue, alpha); real_glColorMask()(red, green, blue, alpha);

View File

@ -7,7 +7,7 @@
#define GL_FUNC(name, return_type, args) \ #define GL_FUNC(name, return_type, args) \
typedef return_type (*real_##name##_t)args; \ typedef return_type (*real_##name##_t)args; \
\ \
static real_##name##_t real_##name() { \ __attribute__((__unused__)) static real_##name##_t real_##name() { \
static real_##name##_t func = NULL; \ static real_##name##_t func = NULL; \
if (!func) { \ if (!func) { \
func = (real_##name##_t) glfwGetProcAddress(#name); \ func = (real_##name##_t) glfwGetProcAddress(#name); \

View File

@ -1,7 +1,7 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "state.h" #include "state.h"
#include "../passthrough.h" #include "passthrough.h"
// GL State // GL State
gl_state_t gl_state = { gl_state_t gl_state = {

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