Compare commits
302 Commits
Author | SHA1 | Date |
---|---|---|
TheBrokenRail | 236f7e385d | |
TheBrokenRail | f506b10051 | |
TheBrokenRail | 9b4a9994ba | |
TheBrokenRail | 32cd0c426f | |
TheBrokenRail | 5690df3ebe | |
TheBrokenRail | b4bebfb701 | |
TheBrokenRail | 1fa444f810 | |
TheBrokenRail | f3dc145d4a | |
TheBrokenRail | 5d65b4092f | |
TheBrokenRail | 81aa01daf9 | |
TheBrokenRail | 2edfa62c25 | |
TheBrokenRail | 4870afcc7f | |
TheBrokenRail | c178e5e5eb | |
TheBrokenRail | 57b0bce12c | |
TheBrokenRail | 95345a5f1b | |
TheBrokenRail | 717b4a11a7 | |
TheBrokenRail | 40a527bb23 | |
TheBrokenRail | 2766611878 | |
TheBrokenRail | 8532e7707f | |
TheBrokenRail | 703ced337b | |
TheBrokenRail | bedd5ea53a | |
TheBrokenRail | eb3c5d2e6f | |
TheBrokenRail | ab1dbd2996 | |
TheBrokenRail | 29bc6faf3d | |
TheBrokenRail | 5aae95fd37 | |
TheBrokenRail | 5739c5f999 | |
TheBrokenRail | 34ef2d51aa | |
TheBrokenRail | f328800ce8 | |
TheBrokenRail | 02c73176a5 | |
TheBrokenRail | 16ce586e9c | |
TheBrokenRail | 6378a18494 | |
TheBrokenRail | 6994671c6d | |
TheBrokenRail | 58f329bb4f | |
TheBrokenRail | d03a1a96ff | |
TheBrokenRail | 35cafec1ee | |
TheBrokenRail | 4ab6b7aed1 | |
TheBrokenRail | edd346dd66 | |
TheBrokenRail | 0d9f498aa7 | |
TheBrokenRail | d761ad8614 | |
TheBrokenRail | 4977898bcd | |
TheBrokenRail | 513628d91f | |
TheBrokenRail | 9a521ebca2 | |
TheBrokenRail | deae36ed94 | |
TheBrokenRail | 00d6ee4f9a | |
TheBrokenRail | 8dd562a20f | |
TheBrokenRail | c11c7203ef | |
TheBrokenRail | 379da809cd | |
TheBrokenRail | 96baf9627a | |
TheBrokenRail | 279b101e46 | |
TheBrokenRail | b190851d36 | |
TheBrokenRail | c3c7d22006 | |
TheBrokenRail | 3abbb0cb16 | |
TheBrokenRail | dda511f8ff | |
TheBrokenRail | 0ccc1ba6e8 | |
TheBrokenRail | 9d3a0964b0 | |
TheBrokenRail | ed9bef8492 | |
TheBrokenRail | c4e26c5be2 | |
TheBrokenRail | 0c82db4116 | |
TheBrokenRail | ce168c1c16 | |
TheBrokenRail | 93eb7807aa | |
TheBrokenRail | 12074e15d9 | |
TheBrokenRail | 010aaa89e3 | |
TheBrokenRail | 0e32fd36c8 | |
TheBrokenRail | 6c89e64f8b | |
TheBrokenRail | 9fe6a2fb39 | |
TheBrokenRail | c87a6fa3c0 | |
TheBrokenRail | 69d3832815 | |
TheBrokenRail | 67002006f3 | |
TheBrokenRail | eb96d80e5a | |
TheBrokenRail | 968001897d | |
TheBrokenRail | 68519f06fd | |
TheBrokenRail | b3b935dd1d | |
TheBrokenRail | 006243d02f | |
TheBrokenRail | 3c1bce876c | |
TheBrokenRail | 484d3e7f90 | |
TheBrokenRail | 23df63abb7 | |
TheBrokenRail | 126c3d618d | |
TheBrokenRail | 3937f88084 | |
TheBrokenRail | 4bd2fecfa2 | |
TheBrokenRail | b539491713 | |
TheBrokenRail | ea4c5c77a1 | |
TheBrokenRail | e506dbb1bb | |
TheBrokenRail | 699d83c61b | |
TheBrokenRail | 329f92c0a4 | |
TheBrokenRail | bfa0567ac9 | |
TheBrokenRail | a94708a1ae | |
TheBrokenRail | 905a569c09 | |
TheBrokenRail | 53f602403a | |
TheBrokenRail | 2f64552926 | |
TheBrokenRail | 2b920f50ba | |
TheBrokenRail | d859a16b5a | |
TheBrokenRail | 78e17d8c18 | |
TheBrokenRail | 0e7a108a0a | |
TheBrokenRail | ca21877000 | |
TheBrokenRail | f1ec29ec86 | |
TheBrokenRail | 13ac816baa | |
TheBrokenRail | 6ba86b9193 | |
TheBrokenRail | 49f8da2a80 | |
TheBrokenRail | e8faee62fa | |
TheBrokenRail | a8ff58f0c4 | |
TheBrokenRail | daccf65361 | |
TheBrokenRail | 3d508d7609 | |
TheBrokenRail | 0061edb3b2 | |
TheBrokenRail | baeeceeaac | |
TheBrokenRail | 211bf265ff | |
TheBrokenRail | 0dd0706f52 | |
TheBrokenRail | 1743626113 | |
TheBrokenRail | 4ed11b67e7 | |
TheBrokenRail | 365e238c29 | |
TheBrokenRail | 36c4ed7e4d | |
TheBrokenRail | cf1faf4835 | |
TheBrokenRail | cb4560a602 | |
TheBrokenRail | b3a96dc3e2 | |
TheBrokenRail | be300a2809 | |
TheBrokenRail | 77d7b82a14 | |
TheBrokenRail | b59c580f6a | |
TheBrokenRail | 524a390921 | |
TheBrokenRail | ead7e575f3 | |
TheBrokenRail | f2a9b274d2 | |
TheBrokenRail | dd4972172d | |
TheBrokenRail | 8822a22987 | |
TheBrokenRail | 53cb68beee | |
TheBrokenRail | 47ae13ac51 | |
TheBrokenRail | 492725ed63 | |
TheBrokenRail | 7c2d0d5625 | |
TheBrokenRail | 9449cdf747 | |
TheBrokenRail | d95a9e1871 | |
TheBrokenRail | 8a83702c3c | |
TheBrokenRail | be7e44fd3c | |
TheBrokenRail | 651c49980e | |
TheBrokenRail | 46a53ba3cf | |
TheBrokenRail | 186728ca5f | |
TheBrokenRail | 9412c07c45 | |
TheBrokenRail | 2717e062b3 | |
TheBrokenRail | 0723fb1894 | |
TheBrokenRail | 16f919d147 | |
TheBrokenRail | e18fc9fc63 | |
TheBrokenRail | 3ebdffd396 | |
TheBrokenRail | 82b6252927 | |
TheBrokenRail | 4a35935daf | |
TheBrokenRail | 89c29f14b1 | |
TheBrokenRail | 4edfaeead4 | |
TheBrokenRail | bfcdd3c7e9 | |
TheBrokenRail | 5467b5178f | |
TheBrokenRail | 8f49c550ba | |
TheBrokenRail | 50eb4801a0 | |
TheBrokenRail | a3eef9fc3b | |
TheBrokenRail | f455780833 | |
TheBrokenRail | 0150879d2b | |
TheBrokenRail | 623cf06516 | |
TheBrokenRail | 0b1849a9ad | |
TheBrokenRail | 157d51e6b6 | |
TheBrokenRail | ed58356dd8 | |
TheBrokenRail | fae728061a | |
TheBrokenRail | 353565ce5a | |
TheBrokenRail | efa21bc8a5 | |
TheBrokenRail | 61f9a329ea | |
TheBrokenRail | 3c0c260920 | |
TheBrokenRail | 0592db9bdf | |
TheBrokenRail | 3fee57ce60 | |
TheBrokenRail | b3c32b211b | |
TheBrokenRail | ea92e5188e | |
TheBrokenRail | 9a4b70b5ca | |
TheBrokenRail | b5974f3f46 | |
TheBrokenRail | 709de17558 | |
TheBrokenRail | 3894e98a04 | |
TheBrokenRail | bf890d190b | |
TheBrokenRail | a40da62b70 | |
TheBrokenRail | 59b8fd9f54 | |
TheBrokenRail | 55a815643b | |
TheBrokenRail | aa471fb4ba | |
TheBrokenRail | 4c33b6da9a | |
TheBrokenRail | 3048b3bf50 | |
TheBrokenRail | 03312f44b6 | |
TheBrokenRail | bdeb45eed2 | |
TheBrokenRail | 9f63fa712f | |
TheBrokenRail | e319d46ea0 | |
TheBrokenRail | c88cbd151e | |
TheBrokenRail | 46abc4c4bd | |
TheBrokenRail | 00f8ed4752 | |
TheBrokenRail | 0fd8ba7de9 | |
TheBrokenRail | 07baea7b5a | |
TheBrokenRail | 8792e5749d | |
TheBrokenRail | 53b2c20b8b | |
TheBrokenRail | 244a69d1aa | |
TheBrokenRail | a1f777f632 | |
TheBrokenRail | 5d8a1e4230 | |
TheBrokenRail | 742ead51e1 | |
TheBrokenRail | c33a27b2ea | |
TheBrokenRail | c1377d4f2a | |
TheBrokenRail | e0ebc7fc32 | |
TheBrokenRail | 0fcda17120 | |
TheBrokenRail | e9e9b90bdb | |
TheBrokenRail | 0fd562af40 | |
TheBrokenRail | 1eb06b6b60 | |
TheBrokenRail | c6983ac6c5 | |
TheBrokenRail | 4a69d38e35 | |
TheBrokenRail | 5636abc051 | |
TheBrokenRail | 33c7d025a5 | |
TheBrokenRail | 7f7bc08201 | |
TheBrokenRail | b36df1d8ff | |
TheBrokenRail | bf58129164 | |
TheBrokenRail | 654c719187 | |
TheBrokenRail | e1e2977c29 | |
TheBrokenRail | a85fc1f5fa | |
TheBrokenRail | e3a4cabf61 | |
TheBrokenRail | 4c3fefae89 | |
TheBrokenRail | 729eff232a | |
TheBrokenRail | 560c040416 | |
TheBrokenRail | ea49470450 | |
TheBrokenRail | 5a5fe4c731 | |
TheBrokenRail | 406aa3f9a6 | |
TheBrokenRail | 55679dd54c | |
TheBrokenRail | dbee357ebc | |
TheBrokenRail | bc461d39d5 | |
TheBrokenRail | 21de7487bb | |
TheBrokenRail | 7ad36d0ce1 | |
TheBrokenRail | d17416421a | |
TheBrokenRail | 154adea292 | |
TheBrokenRail | 291e560c8f | |
TheBrokenRail | 472f5d67a5 | |
TheBrokenRail | a79a601c59 | |
TheBrokenRail | e85231bf69 | |
TheBrokenRail | da0aef568d | |
TheBrokenRail | f8b7af1370 | |
TheBrokenRail | 6a7d881258 | |
TheBrokenRail | 2e9ee42d75 | |
TheBrokenRail | 941572063e | |
TheBrokenRail | 43d27e8e11 | |
TheBrokenRail | 7e3cfaa1a8 | |
TheBrokenRail | 320e0c652a | |
TheBrokenRail | e5fc2a61aa | |
TheBrokenRail | 5cf4d7f915 | |
TheBrokenRail | 51d7974ded | |
TheBrokenRail | 16ebea9ed6 | |
TheBrokenRail | 05587efc04 | |
TheBrokenRail | 9ad6cc3906 | |
TheBrokenRail | 12de038f37 | |
TheBrokenRail | 1daede7dba | |
TheBrokenRail | 28a6d59c2d | |
TheBrokenRail | f2bd893241 | |
TheBrokenRail | 28424aa86a | |
TheBrokenRail | 637f1c1132 | |
TheBrokenRail | 74d14ecaa6 | |
TheBrokenRail | f3eaa57041 | |
TheBrokenRail | 015235b889 | |
TheBrokenRail | 8c356dd65c | |
TheBrokenRail | 6a9a22ac25 | |
TheBrokenRail | c45211ad22 | |
TheBrokenRail | 7498c1e932 | |
TheBrokenRail | 734bded289 | |
TheBrokenRail | b7b130e675 | |
TheBrokenRail | 0a65c91d14 | |
TheBrokenRail | 55475a3a0c | |
TheBrokenRail | f9acb08e4f | |
TheBrokenRail | db64afc550 | |
TheBrokenRail | 0465dc75a7 | |
TheBrokenRail | 68a252c3df | |
TheBrokenRail | 866ebfe159 | |
TheBrokenRail | 1f3036c7e1 | |
TheBrokenRail | a338c11f9d | |
TheBrokenRail | 647a482fbd | |
TheBrokenRail | 6c791d6c9d | |
TheBrokenRail | d18afddf1b | |
TheBrokenRail | d851a8f3e1 | |
TheBrokenRail | a762654e35 | |
TheBrokenRail | 4aeb2fd95b | |
TheBrokenRail | c60fb51fae | |
TheBrokenRail | 4597e824bb | |
TheBrokenRail | d372169c79 | |
TheBrokenRail | 99b709fea7 | |
TheBrokenRail | 578bb1c89f | |
TheBrokenRail | 80d5674781 | |
TheBrokenRail | a925463fdf | |
TheBrokenRail | a9830c3bba | |
TheBrokenRail | d114a2d668 | |
TheBrokenRail | 8f782099da | |
TheBrokenRail | 99f33cab61 | |
TheBrokenRail | 4652efcd65 | |
TheBrokenRail | 665fe30a5f | |
TheBrokenRail | e8ae2a9230 | |
TheBrokenRail | 7b4a8a4d4f | |
TheBrokenRail | 6e6537eea1 | |
TheBrokenRail | a196581bbe | |
TheBrokenRail | b32c6013fb | |
TheBrokenRail | 1877996874 | |
TheBrokenRail | bf14e71c87 | |
TheBrokenRail | 07d79b66ea | |
TheBrokenRail | 0bce0d17ac | |
TheBrokenRail | 0c0a61cd23 | |
TheBrokenRail | 989dd7983b | |
TheBrokenRail | 73f900f8b4 | |
TheBrokenRail | 053bf4aa5f | |
TheBrokenRail | 2b0d1d55ff | |
TheBrokenRail | b1d81e860f | |
TheBrokenRail | bf937f8c86 | |
TheBrokenRail | d72c65b7ab | |
TheBrokenRail | 9d1b6aea65 | |
TheBrokenRail | f0439e9683 | |
TheBrokenRail | 6d79beeeb6 | |
TheBrokenRail | 747d2032e6 | |
TheBrokenRail | 0f6c3c2e43 |
|
@ -1,6 +1,14 @@
|
|||
/out
|
||||
/debian/tmp
|
||||
/.vscode
|
||||
/build
|
||||
/build*
|
||||
/CMakeLists.txt.user
|
||||
*.autosave
|
||||
/AppImageBuilder.yml
|
||||
/appimage-builder-cache
|
||||
/appimage-build
|
||||
/AppDir
|
||||
/*.zsync
|
||||
/*.AppImage
|
||||
/core*
|
||||
/qemu_*
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
[submodule "dependencies/libpng/src"]
|
||||
path = dependencies/libpng/src
|
||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/libpng.git
|
||||
[submodule "dependencies/zlib/src"]
|
||||
path = dependencies/libpng/zlib/src
|
||||
url = https://github.com/madler/zlib.git
|
||||
ignore = dirty
|
||||
[submodule "dependencies/glfw/src"]
|
||||
path = media-layer/core/dependencies/glfw/src
|
||||
url = https://github.com/glfw/glfw.git
|
||||
[submodule "dependencies/zenity/src"]
|
||||
path = dependencies/zenity/src
|
||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git
|
||||
[submodule "dependencies/LIEF/src"]
|
||||
path = dependencies/LIEF/src
|
||||
url = https://github.com/lief-project/LIEF.git
|
||||
[submodule "dependencies/qemu/src"]
|
||||
path = dependencies/qemu/src
|
||||
url = https://gitlab.com/qemu-project/qemu.git
|
||||
ignore = dirty
|
210
CMakeLists.txt
210
CMakeLists.txt
|
@ -1,93 +1,183 @@
|
|||
cmake_minimum_required(VERSION 3.13.0)
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
|
||||
# Specify Options
|
||||
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" FALSE)
|
||||
option(MCPI_SERVER_MODE "Server Mode" FALSE)
|
||||
set(MCPI_BUILD_MODE "both" CACHE STRING "\"arm\" = Build Only Code That Must Be ARN; \"native\" = Build Architecture-Independent Code; \"both\" = Build All Code As ARM")
|
||||
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
|
||||
# Avoid Warning About DOWNLOAD_EXTRACT_TIMESTAMP
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24.0)
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
|
||||
# Configure Build Mode
|
||||
# Build Mode
|
||||
set(MCPI_BUILD_MODE "native" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code")
|
||||
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "arm" "native")
|
||||
if(MCPI_BUILD_MODE STREQUAL "arm")
|
||||
set(USE_ARM32_TOOLCHAIN TRUE)
|
||||
set(BUILD_ARM_COMPONENTS TRUE)
|
||||
set(BUILD_NATIVE_COMPONENTS FALSE)
|
||||
elseif(MCPI_BUILD_MODE STREQUAL "native")
|
||||
set(USE_ARM32_TOOLCHAIN FALSE)
|
||||
set(BUILD_ARM_COMPONENTS FALSE)
|
||||
set(BUILD_NATIVE_COMPONENTS TRUE)
|
||||
elseif(MCPI_BUILD_MODE STREQUAL "both")
|
||||
set(USE_ARM32_TOOLCHAIN TRUE)
|
||||
set(BUILD_ARM_COMPONENTS TRUE)
|
||||
set(BUILD_NATIVE_COMPONENTS TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid Mode")
|
||||
endif()
|
||||
|
||||
# Use Clang By Default
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_CXX_COMPILER clang++)
|
||||
# Specify Options
|
||||
option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE)
|
||||
option(MCPI_OPEN_SOURCE_ONLY "Only Install Open-Source Code (Will Result In Broken Install)" FALSE)
|
||||
option(MCPI_IS_APPIMAGE_BUILD "AppImage Build" FALSE)
|
||||
|
||||
# Setup ARM Cross Compilation
|
||||
if(USE_ARM32_TOOLCHAIN)
|
||||
include(cmake/armhf-toolchain.cmake)
|
||||
# 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()
|
||||
|
||||
# Use LLD When Using Clang
|
||||
if(CMAKE_C_COMPILER STREQUAL "clang")
|
||||
add_link_options("-fuse-ld=lld")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld") # Fix try_compile()
|
||||
# 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")
|
||||
|
||||
# Utility Functions
|
||||
include(cmake/util.cmake)
|
||||
# App Title
|
||||
set(MCPI_APP_BASE_TITLE "Minecraft: Pi Edition: Reborn" CACHE STRING "Base App Title")
|
||||
set(DEFAULT_APP_TITLE "${MCPI_APP_BASE_TITLE}")
|
||||
if(MCPI_SERVER_MODE)
|
||||
string(APPEND DEFAULT_APP_TITLE " (Server)")
|
||||
else()
|
||||
string(APPEND DEFAULT_APP_TITLE " (Client)")
|
||||
endif()
|
||||
set(MCPI_APP_TITLE "${DEFAULT_APP_TITLE}" CACHE STRING "App Title")
|
||||
|
||||
# Specify Variant Name
|
||||
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
|
||||
if(MCPI_SERVER_MODE)
|
||||
set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-server")
|
||||
string(APPEND MCPI_VARIANT_NAME "-server")
|
||||
else()
|
||||
set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-client")
|
||||
string(APPEND MCPI_VARIANT_NAME "-client")
|
||||
endif()
|
||||
|
||||
# Specify Installation Paths
|
||||
set(MCPI_INSTALL_DIR "opt/${MCPI_VARIANT_NAME}")
|
||||
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
|
||||
set(MCPI_FALLBACK_LIB_DIR "${MCPI_INSTALL_DIR}/fallback-lib")
|
||||
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")
|
||||
|
||||
# Optimizations
|
||||
# Library Directory
|
||||
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
string(APPEND MCPI_LIB_DIR "/arm")
|
||||
elseif(BUILD_NATIVE_COMPONENTS)
|
||||
string(APPEND MCPI_LIB_DIR "/native")
|
||||
endif()
|
||||
|
||||
# Share Directory
|
||||
set(MCPI_SHARE_DIR "share")
|
||||
if(MCPI_IS_APPIMAGE_BUILD)
|
||||
string(PREPEND MCPI_SHARE_DIR "usr/")
|
||||
endif()
|
||||
|
||||
# Build Mode
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
add_compile_options(-O3)
|
||||
else()
|
||||
add_compile_options(-g)
|
||||
add_definitions(-DDEBUG)
|
||||
|
||||
# Prebuilt ARMHF Toolchain
|
||||
option(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN "Whether To Use A Prebuilt ARMHF Toolchain For Building ARM Components" ${MCPI_IS_MIXED_BUILD})
|
||||
if(BUILD_ARM_COMPONENTS AND MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||
include(cmake/prebuilt-armhf-toolchain.cmake)
|
||||
endif()
|
||||
|
||||
# Start Project
|
||||
project(minecraft-pi-reborn)
|
||||
|
||||
# Utility Functions
|
||||
include(cmake/util.cmake)
|
||||
|
||||
# Sanity Checks
|
||||
set(IS_ARM_TARGETING FALSE)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
|
||||
set(IS_ARM_TARGETING TRUE)
|
||||
endif()
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING AND NOT MCPI_IS_MIXED_BUILD)
|
||||
message(FATAL_ERROR "Project is configured as a mixed-buld, but MCPI_IS_MIXED_BUILD is disabled.")
|
||||
endif()
|
||||
if(BUILD_ARM_COMPONENTS AND NOT IS_ARM_TARGETING)
|
||||
message(FATAL_ERROR "ARM-Targeting Compiler Required")
|
||||
endif()
|
||||
|
||||
# Specify Default Installation Prefix
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "/" CACHE PATH "" FORCE)
|
||||
set(DEFAULT_PREFIX "/usr")
|
||||
if(MCPI_IS_APPIMAGE_BUILD)
|
||||
set(DEFAULT_PREFIX "/")
|
||||
endif()
|
||||
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
|
||||
set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE)
|
||||
endif()
|
||||
|
||||
# Buld LibPNG + ZLib + Download Minecraft: Pi Edition
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(dependencies)
|
||||
endif()
|
||||
# Required Compile Flags
|
||||
string(CONCAT COMPILE_FLAGS_SETUP
|
||||
# Optimizations
|
||||
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n"
|
||||
" add_compile_options(-O3 -s)\n"
|
||||
"else()\n"
|
||||
" add_compile_options(-g)\n"
|
||||
"endif()\n"
|
||||
|
||||
# PIC
|
||||
"set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)\n"
|
||||
|
||||
# Warnings
|
||||
"add_link_options(-Wl,--no-undefined)\n"
|
||||
|
||||
# C Standard
|
||||
"add_definitions(-D_GNU_SOURCE)\n"
|
||||
"set(CMAKE_C_STANDARD 99)\n"
|
||||
"set(CMAKE_CXX_STANDARD 11)\n"
|
||||
|
||||
# Skip RPath
|
||||
"set(CMAKE_SKIP_BUILD_RPATH TRUE)"
|
||||
)
|
||||
cmake_language(EVAL CODE "${COMPILE_FLAGS_SETUP}")
|
||||
|
||||
# Fast Math
|
||||
add_compile_options(-ffast-math)
|
||||
|
||||
# Warnings
|
||||
add_compile_options(-Wall -Wextra -Werror)
|
||||
add_link_options(-Wl,--no-undefined)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
# Specify Constants
|
||||
if(MCPI_SERVER_MODE)
|
||||
add_definitions(-DMCPI_SERVER_MODE)
|
||||
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
|
||||
add_subdirectory(dependencies)
|
||||
|
||||
# Version
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS VERSION
|
||||
)
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION)
|
||||
file(TIMESTAMP "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION_DATE "%Y-%m-%d" UTC)
|
||||
|
||||
# Build libreborn
|
||||
add_subdirectory(libreborn)
|
||||
|
||||
|
@ -99,7 +189,31 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||
add_subdirectory(launcher)
|
||||
endif()
|
||||
|
||||
# Include Symbols
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(symbols)
|
||||
endif()
|
||||
|
||||
# Build Mods
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(mods)
|
||||
endif()
|
||||
|
||||
# Include Images
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
add_subdirectory(images)
|
||||
endif()
|
||||
|
||||
# Install SDK
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(EXPORT sdk DESTINATION "${MCPI_SDK_DIR}" FILE "sdk-targets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES)
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake"
|
||||
# Compile Flags
|
||||
"${COMPILE_FLAGS_SETUP}\n"
|
||||
# Log
|
||||
"message(STATUS \"Using Reborn SDK v${MCPI_VERSION}\")\n"
|
||||
# Include Targets
|
||||
"include(\"\${CMAKE_CURRENT_LIST_DIR}/sdk-targets.cmake\")\n"
|
||||
)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake" DESTINATION "${MCPI_SDK_DIR}")
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
FROM debian:bullseye-slim
|
||||
|
||||
# Install
|
||||
RUN \
|
||||
apt-get update && \
|
||||
apt-get install -y tini qemu-user && \
|
||||
apt-get --fix-broken install -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy
|
||||
ADD ./out/server-amd64 /app
|
||||
|
||||
# Setup Working Directory
|
||||
RUN mkdir /data
|
||||
WORKDIR /data
|
||||
|
||||
# Setup Entrypoint
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
CMD ["/app/usr/bin/minecraft-pi-reborn-server"]
|
|
@ -1,33 +1,35 @@
|
|||
pipeline {
|
||||
agent none
|
||||
stages {
|
||||
stage('Build (Debian Bullseye)') {
|
||||
stage('Debian Buster') {
|
||||
agent {
|
||||
docker {
|
||||
image 'debian:bullseye'
|
||||
dockerfile {
|
||||
filename 'scripts/ci/Dockerfile'
|
||||
args '-v /var/run/docker.sock:/var/run/docker.sock --network host'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
sh './scripts/ci/run.sh'
|
||||
}
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'out/*.deb', fingerprint: true
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './scripts/ci/run.sh'
|
||||
}
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'out/*.AppImage*', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build (Debian Buster)') {
|
||||
agent {
|
||||
docker {
|
||||
image 'debian:buster'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
sh './scripts/ci/run.sh'
|
||||
}
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'out/*.deb', fingerprint: true
|
||||
stage('Publish') {
|
||||
steps {
|
||||
sh 'apt-get update && apt-get install -y docker.io'
|
||||
sh 'rm -rf ./out/server-amd64'
|
||||
sh './scripts/build.sh server amd64'
|
||||
sh 'docker build --no-cache --tag thebrokenrail/minecraft-pi-reborn-server .'
|
||||
withCredentials([usernamePassword(credentialsId: 'docker_hub_login', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
|
||||
sh 'docker login -u "${DOCKER_HUB_USERNAME}" -p "${DOCKER_HUB_PASSWORD}"'
|
||||
}
|
||||
sh 'docker push thebrokenrail/minecraft-pi-reborn-server'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 TheBrokenRail
|
||||
Copyright (c) 2022 TheBrokenRail
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# Compile For ARM
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64_be" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv8b" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv8l")
|
||||
# Force 32-Bit Compile
|
||||
add_compile_options("-m32")
|
||||
elseif(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
|
||||
# Use ARM Cross-Compiler
|
||||
set(TARGET "arm-linux-gnueabihf")
|
||||
set(CMAKE_C_COMPILER "${TARGET}-gcc")
|
||||
set(CMAKE_CXX_COMPILER "${TARGET}-g++")
|
||||
set(CMAKE_FIND_ROOT_PATH "/usr/${TARGET}" "/usr/lib/${TARGET}")
|
||||
endif()
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "arm")
|
|
@ -0,0 +1,12 @@
|
|||
# Read Hex Data
|
||||
file(READ "${EMBED_IN}" data HEX)
|
||||
|
||||
# Convert Hex Data For C Compatibility
|
||||
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${data}")
|
||||
|
||||
# Get C Name
|
||||
get_filename_component(name "${EMBED_IN}" NAME)
|
||||
string(MAKE_C_IDENTIFIER "${name}" name)
|
||||
|
||||
# Write Data
|
||||
file(WRITE "${EMBED_OUT}" "#include <stddef.h>\nconst unsigned char ${name}[] = {${data}};\nconst size_t ${name}_len = sizeof (${name});\n")
|
|
@ -0,0 +1,78 @@
|
|||
# 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_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\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()
|
|
@ -0,0 +1,7 @@
|
|||
# Compile For x86_64
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
|
||||
# Use x86_64 Cross-Compiler
|
||||
setup_toolchain("x86_64-linux-gnu")
|
||||
# Details
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
|
|
@ -0,0 +1,7 @@
|
|||
# Compile For ARM64
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
|
||||
# Use ARM64 Cross-Compiler
|
||||
setup_toolchain("aarch64-linux-gnu")
|
||||
# Details
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
|
|
@ -0,0 +1,7 @@
|
|||
# Compile For ARM
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
|
||||
# Use ARM Cross-Compiler
|
||||
setup_toolchain("arm-linux-gnueabihf")
|
||||
# Details
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "arm")
|
|
@ -0,0 +1,38 @@
|
|||
# Setup Toolchain
|
||||
macro(setup_toolchain target)
|
||||
# Target Variants
|
||||
set(target_variants "${target}")
|
||||
macro(add_target_variant value)
|
||||
string(REPLACE "-linux" "-${value}-linux" target_variant "${target}")
|
||||
list(APPEND target_variants "${target_variant}")
|
||||
endmacro()
|
||||
add_target_variant(unknown)
|
||||
add_target_variant(none)
|
||||
add_target_variant(pc)
|
||||
# Find Compiler
|
||||
macro(find_compiler output name)
|
||||
set(possible_names "")
|
||||
foreach(possible_target IN LISTS target_variants)
|
||||
list(APPEND possible_names "${possible_target}-${name}")
|
||||
endforeach()
|
||||
find_program(
|
||||
"${output}"
|
||||
NAMES ${possible_names}
|
||||
NO_CACHE
|
||||
)
|
||||
if("${${output}}" STREQUAL "${output}-NOTFOUND")
|
||||
message(FATAL_ERROR "Unable To Find ${name}")
|
||||
endif()
|
||||
endmacro()
|
||||
find_compiler(CMAKE_C_COMPILER "gcc")
|
||||
find_compiler(CMAKE_CXX_COMPILER "g++")
|
||||
# Extra
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
# Custom Search Paths
|
||||
if(NOT DEFINED ENV{MCPI_TOOLCHAIN_USE_DEFAULT_SEARCH_PATHS})
|
||||
# Find Root
|
||||
set(CMAKE_FIND_ROOT_PATH "/usr/${target}" "/usr/lib/${target}" "/usr")
|
||||
# pkg-config
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/${target}/pkgconfig:/usr/${target}/lib/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig")
|
||||
endif()
|
||||
endmacro()
|
|
@ -1,20 +1,26 @@
|
|||
# Symlink Function
|
||||
function(install_symlink target link)
|
||||
install(CODE "\
|
||||
# Prepare\n \
|
||||
set(file \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${link}\")\n \
|
||||
\
|
||||
# Create Directory\n \
|
||||
get_filename_component(dir \"\${file}\" DIRECTORY)\n \
|
||||
file(MAKE_DIRECTORY \${dir})\n \
|
||||
\
|
||||
# Create Symlink\n \
|
||||
if(NOT EXISTS \"\${file}\")\n \
|
||||
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink ${target} \"\${file}\")\n \
|
||||
message(\"-- Installing: \${file}\")\n \
|
||||
else()\n \
|
||||
message(\"-- Up-to-date: \${file}\")\n \
|
||||
endif() \
|
||||
")
|
||||
get_filename_component(parent "${link}" DIRECTORY)
|
||||
if(parent STREQUAL "")
|
||||
set(parent ".")
|
||||
endif()
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/symlink/${parent}")
|
||||
file(CREATE_LINK "${target}" "${CMAKE_BINARY_DIR}/symlink/${link}" SYMBOLIC)
|
||||
install(FILES "${CMAKE_BINARY_DIR}/symlink/${link}" DESTINATION "${parent}")
|
||||
endfunction()
|
||||
|
||||
# Embed Resources
|
||||
set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}")
|
||||
function(embed_resource target file)
|
||||
# Get C Name
|
||||
get_filename_component(name "${file}" NAME)
|
||||
string(MAKE_C_IDENTIFIER "${name}" name)
|
||||
# Add Command
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
ARGS "-DEMBED_IN=${CMAKE_CURRENT_SOURCE_DIR}/${file}" "-DEMBED_OUT=${CMAKE_CURRENT_BINARY_DIR}/${name}.c" "-P" "${util_list_dir}/embed-resource.cmake"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${file}" "${util_list_dir}/embed-resource.cmake"
|
||||
)
|
||||
# Add To Target
|
||||
target_sources("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
|
||||
endfunction()
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
Package: minecraft-pi-reborn-client
|
||||
Version: ${VERSION}
|
||||
Maintainer: TheBrokenRail <connor24nolan@live.com>
|
||||
Description: Fun with Blocks
|
||||
Homepage: https://www.minecraft.net/en-us/edition/pi
|
||||
Architecture: armhf
|
||||
Depends: zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3
|
|
@ -1,7 +0,0 @@
|
|||
Package: minecraft-pi-reborn-client
|
||||
Version: ${VERSION}
|
||||
Maintainer: TheBrokenRail <connor24nolan@live.com>
|
||||
Description: Fun with Blocks
|
||||
Homepage: https://www.minecraft.net/en-us/edition/pi
|
||||
Architecture: amd64
|
||||
Depends: zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user-static
|
|
@ -1,6 +0,0 @@
|
|||
Package: minecraft-pi-reborn-server
|
||||
Version: ${VERSION}
|
||||
Maintainer: TheBrokenRail <connor24nolan@live.com>
|
||||
Description: Fun with Blocks
|
||||
Homepage: https://www.minecraft.net/en-us/edition/pi
|
||||
Architecture: armhf
|
|
@ -1,7 +0,0 @@
|
|||
Package: minecraft-pi-reborn-server
|
||||
Version: ${VERSION}
|
||||
Maintainer: TheBrokenRail <connor24nolan@live.com>
|
||||
Description: Fun with Blocks
|
||||
Homepage: https://www.minecraft.net/en-us/edition/pi
|
||||
Architecture: amd64
|
||||
Depends: libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user-static
|
|
@ -1,8 +1,22 @@
|
|||
project(dependencies)
|
||||
|
||||
# ZLib
|
||||
add_subdirectory(zlib)
|
||||
# LibPNG
|
||||
add_subdirectory(libpng)
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(libpng)
|
||||
endif()
|
||||
# Minecraft: Pi Edition
|
||||
add_subdirectory(minecraft-pi)
|
||||
if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
|
||||
add_subdirectory(minecraft-pi)
|
||||
endif()
|
||||
# Zenity (Minimal Build)
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE)
|
||||
add_subdirectory(zenity)
|
||||
endif()
|
||||
# LIEF
|
||||
if(BUILD_NATIVE_COMPONENTS OR (BUILD_ARM_COMPONENTS AND NOT MCPI_SERVER_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY))
|
||||
add_subdirectory(LIEF)
|
||||
endif()
|
||||
# QEMU
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64"))
|
||||
add_subdirectory(qemu)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
project(LIEF)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w -Wno-psabi)
|
||||
|
||||
## LIEF
|
||||
|
||||
# Options
|
||||
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
|
||||
set(LIEF_C_API FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_EXAMPLES FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_PYTHON_API FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_TESTS FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_USE_CCACHE FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_LOGGING FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_LOGGING_DEBUG FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_ENABLE_JSON FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_ELF TRUE CACHE BOOL "" FORCE)
|
||||
set(LIEF_PE FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_MACHO FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_DEX FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_ART FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_OAT FALSE CACHE BOOL "" FORCE)
|
||||
set(LIEF_VDEX FALSE CACHE BOOL "" FORCE)
|
||||
|
||||
# Download
|
||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
||||
|
||||
# Ensure Build
|
||||
add_custom_target(LIEF-build ALL DEPENDS LIB_LIEF)
|
||||
|
||||
# Install
|
||||
install(TARGETS LIB_LIEF DESTINATION "${MCPI_LIB_DIR}")
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS LIB_LIEF EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
# License
|
||||
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/LIEF")
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2169578d46934c973fdbfa2fae23b192e3cac8a0
|
|
@ -1,28 +1,33 @@
|
|||
project(libpng)
|
||||
|
||||
include(FetchContent)
|
||||
# ZLib (Needed By libpng)
|
||||
add_subdirectory(zlib)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w)
|
||||
|
||||
## LibPNG
|
||||
|
||||
# Download
|
||||
set(SKIP_INSTALL_ALL TRUE) # Skip Default LibPNG Installation
|
||||
FetchContent_Declare(
|
||||
libpng
|
||||
GIT_REPOSITORY "https://git.code.sf.net/p/libpng/code"
|
||||
GIT_TAG "v1.2.59"
|
||||
)
|
||||
FetchContent_Populate(libpng)
|
||||
set(ZLIB_LIBRARY zlib)
|
||||
set(ZLIB_INCLUDE_DIR "${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}")
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning
|
||||
add_subdirectory("${libpng_SOURCE_DIR}" "${libpng_BINARY_DIR}")
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior
|
||||
set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers'") # Use Symbol Versioning
|
||||
set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode
|
||||
# Options
|
||||
set(PNG_TESTS FALSE CACHE BOOL "" FORCE)
|
||||
set(PNG_NO_STDIO FALSE CACHE BOOL "" FORCE)
|
||||
set(PNG_BUILD_ZLIB TRUE CACHE BOOL "" FORCE)
|
||||
|
||||
# Download
|
||||
set(ZLIB_LIBRARY zlibstatic)
|
||||
set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/zlib/src")
|
||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
||||
|
||||
# Use Symbol Versioning
|
||||
set_target_properties(png12 PROPERTIES LINK_OPTIONS "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers")
|
||||
|
||||
# Ensure Build
|
||||
add_custom_target(png12-build ALL DEPENDS png12)
|
||||
# Install
|
||||
install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}")
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS png12 zlibstatic EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
# License
|
||||
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/libpng")
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 6c445538879f9e916f8e62723d2ac7cd77d96191
|
|
@ -0,0 +1,16 @@
|
|||
project(zlib)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w)
|
||||
|
||||
## zlib
|
||||
|
||||
# Download
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0022 NEW) # Fix Error
|
||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
||||
|
||||
# Ensure Build
|
||||
add_custom_target(zlib-build ALL DEPENDS zlibstatic)
|
||||
|
||||
# License
|
||||
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/zlib")
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 04f42ceca40f73e2978b50e93806c2a18c1281fc
|
|
@ -7,11 +7,15 @@ include(FetchContent)
|
|||
# Download
|
||||
FetchContent_Declare(
|
||||
minecraft-pi
|
||||
URL "https://www.minecraft.net/content/dam/minecraft/edition-pi/minecraft-pi-0.1.1.tar.gz"
|
||||
URL_HASH "SHA256=e0d68918874cdd403de1fd399380ae2930913fcefdbf60a3fbfebb62e2cfacab"
|
||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/minecraft-pi-0.1.1.tar.gz"
|
||||
)
|
||||
FetchContent_Populate(minecraft-pi)
|
||||
|
||||
# Install
|
||||
install(DIRECTORY "${minecraft-pi_SOURCE_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}" USE_SOURCE_PERMISSIONS)
|
||||
|
||||
install(
|
||||
DIRECTORY "${minecraft-pi_SOURCE_DIR}/"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/game"
|
||||
USE_SOURCE_PERMISSIONS
|
||||
REGEX "api" EXCLUDE
|
||||
)
|
||||
install_symlink("game/minecraft-pi" "${MCPI_INSTALL_DIR}/minecraft-pi")
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,37 @@
|
|||
project(qemu)
|
||||
|
||||
## QEMU
|
||||
|
||||
# Build
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(NPROC)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(qemu
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||
CONFIGURE_COMMAND
|
||||
"${CMAKE_COMMAND}" "-E" "env"
|
||||
"PKG_CONFIG_LIBDIR=$ENV{PKG_CONFIG_LIBDIR}"
|
||||
"CFLAGS=-s"
|
||||
"CXXFLAGS=-s"
|
||||
"<SOURCE_DIR>/configure"
|
||||
"--prefix=${CMAKE_INSTALL_PREFIX}"
|
||||
"--cross-prefix="
|
||||
"--cc=${CMAKE_C_COMPILER}"
|
||||
"--cxx=${CMAKE_CXX_COMPILER}"
|
||||
"--disable-debug-info"
|
||||
"--target-list=arm-linux-user"
|
||||
"--without-default-features"
|
||||
USES_TERMINAL_CONFIGURE TRUE
|
||||
BUILD_COMMAND "make" "-j${NPROC}" "qemu-arm"
|
||||
USES_TERMINAL_BUILD TRUE
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
BUILD_BYPRODUCTS "<BINARY_DIR>/qemu-arm"
|
||||
)
|
||||
|
||||
# Install
|
||||
ExternalProject_Get_property(qemu BINARY_DIR)
|
||||
install(PROGRAMS "${BINARY_DIR}/qemu-arm" DESTINATION "${MCPI_BIN_DIR}")
|
||||
|
||||
# License
|
||||
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/qemu")
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 621da7789083b80d6f1ff1c0fb499334007b4f51
|
|
@ -0,0 +1,18 @@
|
|||
project(zenity)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w)
|
||||
|
||||
## Zenity
|
||||
|
||||
# Download
|
||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
||||
|
||||
# Ensure Build
|
||||
add_custom_target(zenity-build ALL DEPENDS zenity)
|
||||
|
||||
# Install
|
||||
install(TARGETS zenity DESTINATION "${MCPI_BIN_DIR}")
|
||||
|
||||
# License
|
||||
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/zenity")
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a7496461161c917878d58131711425e7c8e59436
|
|
@ -1,23 +0,0 @@
|
|||
project(zlib)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
# Silence Warnings
|
||||
add_compile_options(-w)
|
||||
|
||||
## zlib
|
||||
|
||||
# Download
|
||||
set(SKIP_INSTALL_ALL TRUE) # Skip Default ZLib Installation
|
||||
FetchContent_Declare(
|
||||
zlib
|
||||
GIT_REPOSITORY "https://github.com/madler/zlib.git"
|
||||
GIT_TAG "v1.2.11"
|
||||
)
|
||||
FetchContent_Populate(zlib)
|
||||
include_directories("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") # Fix ZLib Build
|
||||
add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}")
|
||||
|
||||
# Install
|
||||
install(TARGETS zlib DESTINATION "${MCPI_LIB_DIR}")
|
||||
|
|
@ -2,16 +2,24 @@
|
|||
|
||||
## Launch Sequence
|
||||
|
||||
### Common
|
||||
1. The launcher forks itself.
|
||||
1. The child process continues the launch sequence.
|
||||
2. The original process monitors the child process for crashes.
|
||||
|
||||
### Client
|
||||
1. The launcher is started by the user
|
||||
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn
|
||||
2. The launcher replaces itself with MCPI
|
||||
1. MCPI-Reborn components are loaded using ``LD_PRELOAD`` and ``LD_LIBRARY_PATH``
|
||||
2. If the Media Layer Proxy is enabled, the Media Layer Proxy Client is started as a sub-process
|
||||
1. The launcher is started by the user.
|
||||
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn.
|
||||
1. If the corresponding environmental variable for a setting is specified, it will be used instead of the dialog.
|
||||
2. If a setting is cached, then the dialog's default value will be the cached value instead of the normal default.
|
||||
3. When configuration has been completed, the settings specified will be cached.
|
||||
2. The launcher replaces itself with MCPI.
|
||||
1. MCPI-Reborn components are loaded using ``LD_PRELOAD`` and ``LD_LIBRARY_PATH``.
|
||||
2. If the Media Layer Proxy is enabled, then the Media Layer Proxy Client is started as a sub-process.
|
||||
|
||||
### Server
|
||||
1. The launcher is started by the user
|
||||
2. The launcher replaces itself with MCPI
|
||||
1. The launcher is started by the user.
|
||||
2. The launcher replaces itself with MCPI.
|
||||
|
||||
## Components
|
||||
|
||||
|
@ -20,7 +28,8 @@ This component configures the various environmental variables required for MCPI-
|
|||
|
||||
The environmental variables configured by this component includes:
|
||||
* ``LD_PRELOAD``
|
||||
* ``LD_LIBRAR_PATH``
|
||||
* ``LD_LIBRARY_PATH``
|
||||
* ``GCONV_PATH``
|
||||
* ``MCPI_FEATURE_FLAGS``
|
||||
* ``MCPI_RENDER_DISTANCE``
|
||||
* ``MCPI_USERNAME``
|
||||
|
@ -34,11 +43,11 @@ The Media Layer handles MCPI's graphics calls and user input. It replaces MCPI's
|
|||
This sub-component re-implements a subset of SDL 1.2 calls with GLFW. It also provides a few utility functions that are used internally by MCPI-Reborn.
|
||||
|
||||
The utility functions include:
|
||||
* Taking Screenshots
|
||||
* Fullscreen
|
||||
* Audio
|
||||
* Etc
|
||||
|
||||
This is always compiled for the host system's architecture.
|
||||
This is always compiled for the host system's architecture unless the Media Layer Proxy is disabled.
|
||||
|
||||
This was created because SDL 1.2 has numerous bugs and is in-general unsupported.
|
||||
|
||||
|
@ -59,26 +68,18 @@ It is made of two parts:
|
|||
|
||||
While proxying all Media Layer Core API calls across UNIX pipes does hurt performance, it is better than emulating the entire graphics stack.
|
||||
|
||||
Using this in server-mode is redundant (and disallowed).
|
||||
Using this in server-mode is redundant (but is possible).
|
||||
|
||||
#### Extras
|
||||
This sub-component contains code that must always be linked directly to MCPI.
|
||||
|
||||
This is always compiled for ARM.
|
||||
|
||||
#### Stubs
|
||||
This sub-component implements stubs for various redundant libraries used by MCPI to silence linker errors.
|
||||
|
||||
This is always compiled for ARM.
|
||||
|
||||
##### What To Stub And What To Patch?
|
||||
Most libraries (like ``bcm_host``) can just be replaced with stubs, because they don't need to do anything and aren't used by anything else. However, some libraries (like EGL) might be used by some of MCPI-Reborn's dependencies (like GLFW) so instead of being replaced by a stub, each call is manually patched out from MCPI. A stub is still generated just in case that library isn't present on the system to silence linker errors, but it is only loaded if no other version is available.
|
||||
|
||||
#### Headers
|
||||
This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation.
|
||||
|
||||
### Mods
|
||||
This component links directly to MCPI and patches it to modify its behavior.
|
||||
This component patches MCPI to modify its behavior. It's loaded using ``LD_PRELOAD``.
|
||||
|
||||
This is always compiled for ARM.
|
||||
|
||||
|
@ -87,17 +88,20 @@ This component contains various utility functions including:
|
|||
|
||||
* Code Patching (ARM Only)
|
||||
* Logging
|
||||
* MCPI Symbols
|
||||
* Etc
|
||||
|
||||
The code patching is ARM only because it relies on hard-coded ARM instructions. However, this is irrelevant since code patching is only needed in ARM code (to patch MCPI).
|
||||
|
||||
### ``symbols``
|
||||
This component contains all MCPI symbols.
|
||||
|
||||
## Dependencies
|
||||
MCPI-Reborn has several dependencies:
|
||||
* MCPI (Bundled)
|
||||
* GLFW (Only In Client Mode)
|
||||
* GLFW (Only In Client Mode; Bundled)
|
||||
* OpenGL ES 2.0
|
||||
* OpenAL (Only In Client Mode)
|
||||
* ZLib (Required By LibPNG; Bundled)
|
||||
* LibPNG (Bundled)
|
||||
* FreeImage (Only In Client Mode)
|
||||
* QEMU User Mode (Only On Non-ARM Hosts; Runtime Only)
|
||||
* Zenity (Only In Client Mode; Runtime Only)
|
||||
* Zenity (Only In Client Mode; Runtime Only; Bundled)
|
||||
|
|
|
@ -1,63 +1,22 @@
|
|||
# Building
|
||||
|
||||
## Build Options
|
||||
* ``MCPI_BUILD_MODE``
|
||||
* ``arm``: Only Build ARM Components
|
||||
* ``native``: Only Build Native Components
|
||||
* ``both`` (Default): Build Both ARM And Native Components For ARM
|
||||
* ``MCPI_SERVER_MODE``
|
||||
* ``ON``: Enable Server Mode
|
||||
* ``OFF`` (Default): Disable Server Mode
|
||||
* ``MCPI_USE_MEDIA_LAYER_PROXY``
|
||||
* ``ON``: Enable The Media Layer Proxy
|
||||
* ``OFF`` (Default): Disable The Media Layer Proxy
|
||||
|
||||
## Build Dependencies
|
||||
* Common
|
||||
* ARM Compiler
|
||||
* Host Compiler (Clang)
|
||||
* CMake
|
||||
* Host Architecture Dependencies
|
||||
* Client Mode Only
|
||||
* GLFW
|
||||
* FreeImage
|
||||
|
||||
## Runtime Dependencies
|
||||
* Non-ARM Host Architectures
|
||||
* QEMU User-Mode Static
|
||||
* Host Architecture Dependencies
|
||||
* CLient Mode Only
|
||||
* OpenGL ES 1.1
|
||||
* GLFW
|
||||
* FreeImage
|
||||
* Zenity
|
||||
|
||||
## Two-Step Build
|
||||
Use this when the host architecture is not ARM.
|
||||
## Dependencies
|
||||
|
||||
### Debian/Ubuntu
|
||||
```sh
|
||||
# Create Build Directory
|
||||
mkdir build && cd build
|
||||
|
||||
# Build ARM Components
|
||||
mkdir arm && cd arm
|
||||
cmake -DMCPI_BUILD_MODE=arm ../..
|
||||
make -j$(nproc) && sudo make install
|
||||
|
||||
# Build Native Components
|
||||
mkdir native && cd native
|
||||
cmake -DMCPI_BUILD_MODE=native ../..
|
||||
make -j$(nproc) && sudo make install
|
||||
./scripts/install-dependencies.sh
|
||||
```
|
||||
|
||||
## One-Step Build
|
||||
Use this when the host architecture is ARM.
|
||||
|
||||
## Instructions
|
||||
```sh
|
||||
# Create Build Directory
|
||||
mkdir build && cd build
|
||||
|
||||
# Build
|
||||
cmake ..
|
||||
make -j$(nproc) && sudo make install
|
||||
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
|
||||
```
|
||||
|
||||
### Custom CMake Arguments
|
||||
```sh
|
||||
./scripts/setup.sh <client|server> <armhf|arm64|i686|amd64> <Custom CMake Arguments>
|
||||
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
* ``MCPI_TOOLCHAIN_USE_DEFAULT_SEARCH_PATHS``: Use Default CMake Search Paths Rather Than Guessing
|
||||
|
|
|
@ -1,5 +1,269 @@
|
|||
# Changelog
|
||||
|
||||
**2.4.6**
|
||||
* [Minimal Controller Support](CONTROLS.md)
|
||||
* Fix Holding Left-Click When Attacking
|
||||
* Fix Crashing On ARMHF
|
||||
* Heavily Improved Crash Report Dialog
|
||||
|
||||
**2.4.5**
|
||||
* Bundle QEMU
|
||||
|
||||
**2.4.4**
|
||||
* Cache Previous Launcher Configuration
|
||||
* Add ``MCPI_API_PORT`` Environmental Variable
|
||||
* Fix Particles In Front-Facing View
|
||||
* Fixed Launch Crash On Ubuntu ARM64
|
||||
* PatchELF Replaced With LIEF
|
||||
* Moved ``3D Anaglyph`` Feature Flag To Options Screen
|
||||
* Add ``Improved Classic Title Screen`` Feature Flag (Enabled By Default)
|
||||
* Add Quit button
|
||||
* Add Options Button (Moved From ``Fix Options Screen`` Feature Flag)
|
||||
* Add ``Disable Speed Bridging`` Feature Flag (Disabled By Default)
|
||||
* Add ``Disable Creative Mode Mining Delay`` Feature Flag (Disabled By Default)
|
||||
* Improved Feature Flag Names
|
||||
* Miscellaneous Bug Fixes
|
||||
* Improved Build System
|
||||
|
||||
**2.4.3**
|
||||
* Fix Signs With CP-437
|
||||
|
||||
**2.4.2**
|
||||
* Fix Picking Up Lava
|
||||
* Fix Wayland App ID
|
||||
|
||||
**2.4.1**
|
||||
* Allow More Characters In Usernames And Chat
|
||||
* Fix Running On ARMHF Debian Buster
|
||||
|
||||
**2.4.0**
|
||||
* [Modding SDK](../example-mods/README.md)
|
||||
* Cache Blacklist/Whitelist
|
||||
* More Reliable AppImages
|
||||
* CMake Refactors
|
||||
* Disable Broken Touchscreen-Specific Block Outline Behavior
|
||||
* Add ``Remove Forced GUI Lag (Can Break Joining Servers)`` Feature Flag (Disabled By Default)
|
||||
* Add ``Add Buckets`` Feature Flag (Enabled By Default)
|
||||
* Add ``Classic HUD`` Feature Flag (Enabled By Default)
|
||||
* Add ``Translucent Toolbar`` Feature Flag (Enabled By Default)
|
||||
* Add ``Force EGL`` Feature Flag (Disabled By Default)
|
||||
* Fix Sound Pitch/Volume/Attenuation
|
||||
* Fix Holding Left-Click When Attacking
|
||||
* Don't Force EGL (Should Fix Some NVIDIA Systems)
|
||||
* Performance Fixes
|
||||
|
||||
**2.3.13**
|
||||
* Fix Texture Bug
|
||||
|
||||
**2.3.12**
|
||||
* Media Layer Proxy Optimizations
|
||||
* Bug Fixes
|
||||
|
||||
**2.3.11**
|
||||
* ``--version`` Command Line Option
|
||||
* TPS Measured In Benchmark & Server
|
||||
* Front-Facing Third-Person
|
||||
* GLESv1 Comparability Layer
|
||||
* Miscellaneous Bug Fixes
|
||||
|
||||
**2.3.10**
|
||||
* Add Crash Report Dialog
|
||||
* Disable V-Sync By Default
|
||||
* Refactor Child Process Management
|
||||
* Improve Build System
|
||||
* Support For Building On Ubuntu 22.04
|
||||
|
||||
**2.3.9**
|
||||
* Bundle An ARM Sysroot
|
||||
* Not Used On ARM32 Systems
|
||||
* Based On Debian Bullseye
|
||||
* Colored Log Output
|
||||
|
||||
**2.3.8**
|
||||
* Switch Up Mod Loading Order
|
||||
|
||||
**2.3.7**
|
||||
* Don't Append Hyphens To New World Name, Only Folder Names
|
||||
|
||||
**2.3.6**
|
||||
* Fix ``Invert Y-axis`` Option Name
|
||||
* Improve Touch GUI Inventory In Non-Touch GUI
|
||||
* New Create World Dialog
|
||||
* Controlled By ``Implement Create World Dialog`` Feature Flag (Enabled By Default)
|
||||
* Custom World Names
|
||||
* Game-Mode Selection
|
||||
* Custom Seeds
|
||||
|
||||
**2.3.5**
|
||||
* Renamed Some Feature Flags
|
||||
* Add ``Improved Title Background`` Feature Flag (Enabled By Default)
|
||||
* Non-Touch GUI Rework
|
||||
* Make ``Full Touch GUI`` Feature Flag Disabled By Default
|
||||
* Add ``Force Touch GUI Button Behavior`` Feature Flag (Enabled By Default)
|
||||
* Add ``Improved Button Hover Behavior`` Feature Flag (Enabled By Default)
|
||||
|
||||
**2.3.4**
|
||||
* AppImage Fixes
|
||||
* Make Death Messages Customizable Server-Side
|
||||
* Fix Q-Key Behavior Behavior When Editing Signs
|
||||
* Add ``Force Touch Inventory`` Feature Flag (Disabled By Default)
|
||||
* Add ``Fix Pause Menu`` Feature Flag (Enabled By Default)
|
||||
* Enables Server Visibility Toggle Button
|
||||
* Options Changes (Not Supported On Legacy)
|
||||
* Add ``Fix Options Screen`` Feature Flag (Enabled By Default)
|
||||
* Adds Options Button To Classic UI Start Screen
|
||||
* Removes Useless Options Toggles
|
||||
* Fixes Options Toggles' Default Position
|
||||
* Store Multiple Settings In `options.txt`
|
||||
* ``Peaceful Mode`` Feature Flag Moved To ``game_difficulty``
|
||||
* ``Smooth Lighting`` Feature Flag Moved To ``gfx_ao``
|
||||
* ``Fancy Graphics`` Feature Flag Moved To ``gfx_fancygraphics``
|
||||
* ``Disable Hosting LAN Worlds`` Feature Flag Moved To ``mp_server_visible_default``
|
||||
|
||||
**2.3.3**
|
||||
* Add More Blocks To Expanded Creative Inventory
|
||||
* Add AppStream Metadata
|
||||
|
||||
**2.3.2**
|
||||
* Simplify Launch Sequence
|
||||
* Add More Blocks To Expanded Creative Inventory
|
||||
* Fix Nether Reactor With Creative Restrictions Disabled
|
||||
* Alphabetize Feature Flags
|
||||
* Add ``Disable V-Sync`` Feature Flag (Disabled By Default)
|
||||
|
||||
**2.3.1**
|
||||
* Internal Refactor Of ``libreborn``
|
||||
* Remove Use Of ``/bin/sh``
|
||||
* Load Custom Mods First
|
||||
* Use Zenity Dark Mode
|
||||
* Add ``Improved Cursor Rendering`` Feature Flag (Enabled By Default)
|
||||
|
||||
**2.3.0**
|
||||
* Switch To AppImage For Packaging
|
||||
* Prevent OpenAL From Crashing When Out Of Memory
|
||||
* Vendor GLFW & Zenity
|
||||
* Seamless Wayland Support
|
||||
* Add ``MCPI_DEBUG`` Environmental Variable
|
||||
* Add ``Disable Hosting LAN Worlds`` Feature Flag (Disabled By Default)
|
||||
* Add ``Fix Furnace Not Checking Item Auxiliary`` Feature Flag (Enabled By Default)
|
||||
* Add ``Disable Raw Mouse Motion (Not Recommended)`` Feature Flag (Disabled By Default) For Broken X11 Setups
|
||||
* Added Back `~/.minecraft-pi/mods`
|
||||
* Improve Build System
|
||||
* Improve Documentation
|
||||
|
||||
**2.2.11**
|
||||
* Add ``Close Current Screen On Death`` Feature Flag (Enabled By Default) To Prevent Bugs
|
||||
* Fix More Furnace UI Bugs When Using "Disable 'gui_blocks' Atlas"
|
||||
|
||||
**2.2.10**
|
||||
* Fix Bug With Picking Up Items In "Remove Creative Mode Restrictions" Mode
|
||||
|
||||
**2.2.9**
|
||||
* Fix String Sanitization
|
||||
* Store Files In `/usr/lib`
|
||||
|
||||
**2.2.8**
|
||||
* Add ``Hide Chat Messages`` Optional Feature Flag
|
||||
* Add ``Remove Creative Mode Restrictions`` Optional Feature Flag
|
||||
* Improve GLFW->SDL Mouse Motion Event Conversion
|
||||
* Performance Optimizations
|
||||
* Make Majority Of Server-Specific Logging Code Also Apply To The Client
|
||||
* Simple Benchmark Mode
|
||||
* Fix Typo When Audio Source File Doesn't Exist
|
||||
* Improve Build System
|
||||
|
||||
**2.2.7**
|
||||
* Fix Crash When OpenAL Is Unavailable
|
||||
* Fix Command Input In Server
|
||||
|
||||
**2.2.5**
|
||||
* Fix Bug In Texture Scaling Code
|
||||
|
||||
**2.2.5**
|
||||
* Scale Animated Textures
|
||||
* Add More Blocks To Expanded Creative Inventory
|
||||
* Reduce Unnecessary Logging
|
||||
* Log IPs In Server Mode
|
||||
|
||||
**2.2.4**
|
||||
* Instead Of Crashing, Disable Polling Block Hits In Survival Mode Using The API
|
||||
|
||||
**2.2.3**
|
||||
* Fix Crash When Taking Odd-Sized Screenshots
|
||||
|
||||
**2.2.2**
|
||||
* Add More Missing Sound Events
|
||||
* Make Missing Sound Event Cause Warning Rather Than Crash
|
||||
|
||||
**2.2.1**
|
||||
* Prevent ``random.burp`` Sound From Crashing Game
|
||||
* Always Cleanup Media Layer, Even On Crash
|
||||
* Resolve All Sounds On Startup
|
||||
|
||||
**2.2.0**
|
||||
* Sound Support
|
||||
* Split Off ``Allow Joining Survival Servers`` From Game-Mode Mod
|
||||
* Separate Headless Code From Server Code
|
||||
* Fix Bug Where ``RakNetInstance`` Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
|
||||
* Clean-Up Code
|
||||
* Remove Support For Debian Buster
|
||||
|
||||
**2.1.8**
|
||||
* Fix Crash On ARM Systems
|
||||
|
||||
**2.1.7**
|
||||
* Fix On 64-Bit ARM Systems
|
||||
|
||||
**2.1.6**
|
||||
* Optimize Media Layer Proxy
|
||||
|
||||
**2.1.5**
|
||||
* Print Error Message If RakNet Fails To Start
|
||||
|
||||
**2.1.4**
|
||||
* Fix ``RakNet::RakString`` Security Bug
|
||||
|
||||
**2.1.3**
|
||||
* Workaround Broken Library Search Path On Some ARM 32-Bit Systems
|
||||
|
||||
**2.1.2**
|
||||
* Fix Library Loading On ARM 32-Bit Systems
|
||||
|
||||
**2.1.1**
|
||||
* Fix Symlink Code
|
||||
|
||||
**2.1.0**
|
||||
* Allow Binding ``Q`` Key To Item Dropping
|
||||
* Expose More Feature Flags
|
||||
* Replace ``Mob Spawning`` Feature Flag With ``Force Mob Spawning``
|
||||
* Fix ``ESC`` Key In Options Menu When ``Miscellaneous Input Fixes`` Is Enabled
|
||||
|
||||
**2.0.9**
|
||||
* Fix Translucent Preview Items In Furnace UI Being Fully Opaque When The ``gui_blocks`` Atlas Is Disabled
|
||||
|
||||
**2.0.8**
|
||||
* Use Default Port In ``servers.txt`` If Not Specified
|
||||
|
||||
**2.0.7**
|
||||
* Fix Sign Text Not Updating In Multiplayer When Exiting Editing UI Using Escape Button
|
||||
* Fix Item Dropping Not Working
|
||||
|
||||
**2.0.6**
|
||||
* Fix Toolbar Size In Normal GUI
|
||||
|
||||
**2.0.5**
|
||||
* Show Reborn Version In Start Screen
|
||||
* External Server Support
|
||||
|
||||
**2.0.4**
|
||||
* Optimize Media Layer Proxy
|
||||
|
||||
**2.0.3**
|
||||
* Make ``kill`` Admin Command Print Death Message
|
||||
|
||||
**2.0.2**
|
||||
* Fix Mouse Cursor Bugs
|
||||
|
||||
**2.0.1**
|
||||
* Fix Blank Screen On Twister OS
|
||||
|
||||
|
|
|
@ -1,11 +1,61 @@
|
|||
# Command Line Arguments
|
||||
# Command Line Usage
|
||||
|
||||
## ``--print-available-feature-flags`` (Client Mode Only)
|
||||
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags and then immediately exit. The feature flags are printed in the following format:
|
||||
## Command Line Arguments
|
||||
|
||||
### ``--version`` (Or ``-v``)
|
||||
If you run MCPI-Reborn with ``--version`` it will print its version to ``stdout``.
|
||||
|
||||
### ``--debug``
|
||||
This sets ``MCPI_DEBUG``.
|
||||
|
||||
### Client Mode Only
|
||||
|
||||
#### ``--print-available-feature-flags``
|
||||
This print the available feature flags (and their default values) to ``stdout`` and then immediately exit.
|
||||
|
||||
The feature flags are printed in the following format:
|
||||
```
|
||||
TRUE This Flag Is On By Default
|
||||
FALSE This Flag Is Off By Default
|
||||
```
|
||||
|
||||
## ``--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.
|
||||
#### ``--default``
|
||||
This will skip the startup configuration dialogs and just use the default values. This will use the cached configuration unless ``--no-cache`` is used.
|
||||
|
||||
#### ``--benchmark``
|
||||
This will make MCPI-Reborn enter a simple benchmark mode. This means automatically loading a newly generated world, then rotating the camera for a period of time. When it has finished, it will then exit and print the average FPS while the world was loaded. In this mode, all user input is blocked. However you can still modify rendering settings by changing feature flags.
|
||||
|
||||
The world used will always be re-created on start and uses a hard-coded seed.
|
||||
|
||||
#### ``--no-cache``
|
||||
This will skip loading and saving the cached launcher configuration.
|
||||
|
||||
#### ``--wipe-cache``
|
||||
This will wipe the cached launcher configuration.
|
||||
|
||||
### Server Mode Only
|
||||
|
||||
#### ``--only-generate``
|
||||
This will make MCPI-Reborn immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
|
||||
|
||||
## Environmental Variables
|
||||
|
||||
### ``MCPI_DEBUG``
|
||||
This enables debug logging if it is set.
|
||||
|
||||
### ``MCPI_API_PORT``
|
||||
This configures the API to use a different port (the default is 4711).
|
||||
|
||||
### Client Mode Only
|
||||
If any of the following variables aren't set, one configuration dialog will open on startup for each unset variable.
|
||||
|
||||
#### ``MCPI_FEATURE_FLAGS``
|
||||
This corresponds to ``--print-available-feature-flags``. This is just a list of all enabled feature flags separated by ``|``.
|
||||
|
||||
For instance, the string ``Feature A|Feature B`` would enable both ``Feature A`` and ``Feature B`` and *disable every other available feature flag*.
|
||||
|
||||
#### ``MCPI_RENDER_DISTANCE``
|
||||
This is the render distance. The possible values are: ``Far``, ``Normal``, ``Short``, and ``Tiny``.
|
||||
|
||||
#### ``MCPI_USERNAME``
|
||||
This is the username.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# In-Game Controls
|
||||
|
||||
## Keyboard & Mouse
|
||||
| Action | Function |
|
||||
| --- | --- |
|
||||
| W | Move Forward |
|
||||
| A | Move Left |
|
||||
| S | Move Backward |
|
||||
| D | Move Right |
|
||||
| Space | Jump |
|
||||
| Shift | Sneak |
|
||||
| E | Open Inventory |
|
||||
| Q | Drop Item |
|
||||
| Ctrl+Q | Drop Item Stack |
|
||||
| 1-9 | Select Item In Toolbar/Hotbar |
|
||||
| Escape | Pause |
|
||||
| Tab | Lock/Unlock Mouse |
|
||||
| F11 | Fullscreen |
|
||||
| F2 | Screenshot |
|
||||
| F1 | Hide GUI |
|
||||
| F5 | Change Perspective |
|
||||
| T | Open Chat |
|
||||
| Mouse Movement | Camera Control |
|
||||
| Scroll Wheel | Cycle Selected Item In Toolbar |
|
||||
| Left-CLick | Attack/Destroy |
|
||||
| Right-Click | Use Item/Place Block |
|
||||
|
||||
## Game Controller
|
||||
| Action | Function |
|
||||
| --- | --- |
|
||||
| A | Jump |
|
||||
| Y | Open Inventory |
|
||||
| B | Sneak[^1] |
|
||||
| X | Open Crafting |
|
||||
| D-Pad Up | Change Perspective |
|
||||
| D-Pad Down | Drop Item |
|
||||
| D-Pad Right | Open Chat |
|
||||
| Left/Right Bumper | Cycle Selected Item In Toolbar |
|
||||
| Left Trigger | Use Item/Place Block |
|
||||
| Right Trigger | Attack/Destroy |
|
||||
| Start/Back | Pause |
|
||||
| Left Stick | Movement |
|
||||
| Right Stick | Camera Control |
|
||||
|
||||
[^1]: Unlike Minecraft: Bedrock Edition, this *is not* a toggle.
|
|
@ -1,14 +1,19 @@
|
|||
# Dedicated Server
|
||||
The dedicated server is a version of Minecraft: Pi Edition modified to run in a headless environment. It loads settings from a ``server.properties`` file.
|
||||
|
||||
This server is also compatible with MCPE Alpha v0.6.1.
|
||||
This server is also compatible with MCPE Alpha v0.6.1[^1].
|
||||
|
||||
## Setup
|
||||
|
||||
### Debian Package
|
||||
To use, install and run ``minecraft-pi-reborn-server``. It will generate the world and ``server.properties`` in the current directory.
|
||||
|
||||
### Docker Image
|
||||
An official Docker image is also provided: [thebrokenrail/minecraft-pi-reborn-server](https://hub.docker.com/r/thebrokenrail/minecraft-pi-reborn-server).
|
||||
|
||||
## Server Limitations
|
||||
* Player data is not saved because of limitations with MCPE LAN worlds
|
||||
* An easy workaround is to place your inventory in a chest before logging off
|
||||
* Survival Mode servers are incompatible with unmodded MCPI
|
||||
|
||||
[^1]: The exception to this is buckets, those will crash MCPE players.
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
# Manual Installation
|
||||
[Download Packages Here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/)
|
||||
# Installation
|
||||
|
||||
## Picking A Package
|
||||
## AppImage
|
||||
Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/).
|
||||
|
||||
### Name Format
|
||||
```
|
||||
minecraft-pi-reborn-<Variant>_X.Y.Z~<Distribution>_<Architecture>
|
||||
```
|
||||
### System Requirements
|
||||
* Debian Buster/Ubuntu 18.04 Or Higher
|
||||
* 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``
|
||||
|
||||
### 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
|
||||
### Running
|
||||
Follow [these](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage) instructions.
|
||||
|
||||
### Picking A Distribution
|
||||
This specifies which version of Debian MCPI-Reborn was built against. Which one you should use depends on your current distribution. If your distribution supports it, you should use ``bullseye`` for better mouse sensitivity.
|
||||
## 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>
|
||||
|
||||
* Ubuntu 20.04+: ``bullseye``
|
||||
* Ubuntu 18.04: ``buster``
|
||||
* Raspberry Pi OS Buster: ``buster``
|
||||
* Debian Bullseye+: ``bullseye``
|
||||
* Debian Buster: ``buster``
|
||||
|
||||
### Picking An Architecture
|
||||
* ``amd64``: x86_64, use this if you are using a device with an AMD or Intel processor
|
||||
* ``armhf``: ARM, use this if you are using an ARM device (like a Raspberry Pi)
|
||||
### Note
|
||||
Game data is stored in ``~/.var/app/com.thebrokenrail.MCPIReborn/.minecraft-pi`` instead of ``~/.minecraft-pi``.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# Multiplayer
|
||||
MCPI-Reborn supports two ways to play multiplayer.
|
||||
|
||||
## Local Network (LAN)
|
||||
This is also supported by vanilla MCPI. Just load a world in MCPI and other devices on the network can join.
|
||||
|
||||
## External Servers
|
||||
Unlike vanilla MCPI, MCPI-Reborn allows you to natively join a server outside of the local network. Just modify ``~/.minecraft-pi/servers.txt`` and it should show up in MCPI's server list.
|
||||
|
||||
### Example ``~/.minecraft-pi/servers.txt``
|
||||
```
|
||||
# Default Port Is 19132
|
||||
example.com
|
||||
# Custom Port
|
||||
example.com:19133
|
||||
```
|
|
@ -1,5 +1,5 @@
|
|||
# Documentation
|
||||
* [View Manual Installation](INSTALL.md)
|
||||
* [View Installation](INSTALL.md)
|
||||
* [View Overriding Assets](OVERRIDING_ASSETS.md)
|
||||
* [View Dedicated Server](DEDICATED_SERVER.md)
|
||||
* [View Credits](CREDITS.md)
|
||||
|
@ -7,4 +7,7 @@
|
|||
* [View Building](BUILDING.md)
|
||||
* [View Architecture](ARCHITECTURE.md)
|
||||
* [View Command Line Arguments](COMMAND_LINE.md)
|
||||
* [View Multiplayer](MULTIPLAYER.md)
|
||||
* [View Sound](SOUND.md)
|
||||
* [View In-Game Controls](CONTROLS.md)
|
||||
* [View Changelog](CHANGELOG.md)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Sound
|
||||
One of MCPI-Reborn's main modifications is a sound-engine since MCPI doesn't include one by default[^1]. However, it can't be used out-of-box because MCPI doesn't contain any sound data and MCPI-Reborn can't include it because of copyright.
|
||||
|
||||
MCPE's sound data can be extracted from any MCPE v0.6.1[^2] APK file, just place its `libminecraftpe.so` into `~/.minecraft-pi/overrides` and you should have sound!
|
||||
|
||||
[^1]: The mute button is just leftover code from MCPE, it doesn't actually do anything in un-modded MCPI, however it is connected to MCPI-Reborn's sound-engine.
|
||||
[^2]: This isn't a hard limit, an MCPE v0.8.1 APK would probably work, but don't rely on it.
|
|
@ -2,6 +2,7 @@
|
|||
| Name | Description |
|
||||
| --- | --- |
|
||||
| MCPI | Shorthand for Minecraft: Pi Edition |
|
||||
| MCPE | Shorthand for Minecraft: Pocket Edition |
|
||||
| Host Architecture | The native architecture of the CPU that MCPi-Reborn will be running on |
|
||||
| Native Component | A component that *can* be compiled for the host architecture |
|
||||
| ARM Component | A component that *must* be compiled for ARM |
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Example Mods
|
||||
This is an example of a mod that can be built using the modding SDK.
|
||||
|
||||
* **Expanded Creative Mod**: This specific mod adds even more items and blocks to the Creative Inventory. It was originally by [@Bigjango13](https://github.com/bigjango13).
|
||||
* **Chat Commands Mod**: This specific mod makes an chat message starting with a ``/`` handled by the MCPI API.
|
||||
* **Recipes Mod**: This specific mod demos custom recipes.
|
||||
|
||||
## The SDK
|
||||
The modding SDK is a collection of exported CMake targets that allows anyone to create their own MCPI mod!
|
||||
|
||||
The SDK is copied to ``~/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake`` whenever MCPI-Reborn is started.
|
||||
|
||||
## How do I use this?
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cp libexpanded-creative.so ~/.minecraft-pi/mods
|
||||
```
|
|
@ -0,0 +1,15 @@
|
|||
/out
|
||||
/debian/tmp
|
||||
/.vscode
|
||||
/build*
|
||||
/CMakeLists.txt.user
|
||||
*.autosave
|
||||
/AppImageBuilder.yml
|
||||
/appimage-builder-cache
|
||||
/appimage-build
|
||||
/AppDir
|
||||
/*.zsync
|
||||
/*.AppImage
|
||||
/core*
|
||||
/qemu_*
|
||||
/cmake/.prebuilt-armhf-toolchain
|
|
@ -0,0 +1,15 @@
|
|||
cmake_minimum_required(VERSION 3.16.0)
|
||||
|
||||
# Build For ARM
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
|
||||
|
||||
# Start Project
|
||||
project(chat-commands)
|
||||
|
||||
# Include SDK
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
|
||||
|
||||
# Build
|
||||
add_library(chat-commands SHARED chat-commands.cpp)
|
||||
target_link_libraries(chat-commands mods-headers reborn-patch symbols chat misc)
|
|
@ -0,0 +1,25 @@
|
|||
// Headers
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#include <mods/chat/chat.h>
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
// The Actual Mod
|
||||
HOOK(chat_handle_packet_send, void, (unsigned char *minecraft, unsigned char *packet)) {
|
||||
// Get Message
|
||||
char *message = *(char **) (packet + ChatPacket_message_property_offset);
|
||||
if (message[0] == '/') {
|
||||
// API Command
|
||||
unsigned char *gui = minecraft + Minecraft_gui_property_offset;
|
||||
std::string out = chat_send_api_command(minecraft, &message[1]);
|
||||
if (out.length() > 0 && out[out.length() - 1] == '\n') {
|
||||
out[out.length() - 1] = '\0';
|
||||
}
|
||||
misc_add_message(gui, out.c_str());
|
||||
} else {
|
||||
// Call Original Method
|
||||
ensure_chat_handle_packet_send();
|
||||
(*real_chat_handle_packet_send)(minecraft, packet);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/out
|
||||
/debian/tmp
|
||||
/.vscode
|
||||
/build*
|
||||
/CMakeLists.txt.user
|
||||
*.autosave
|
||||
/AppImageBuilder.yml
|
||||
/appimage-builder-cache
|
||||
/appimage-build
|
||||
/AppDir
|
||||
/*.zsync
|
||||
/*.AppImage
|
||||
/core*
|
||||
/qemu_*
|
||||
/cmake/.prebuilt-armhf-toolchain
|
|
@ -0,0 +1,15 @@
|
|||
cmake_minimum_required(VERSION 3.16.0)
|
||||
|
||||
# Build For ARM
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
|
||||
|
||||
# Start Project
|
||||
project(expanded-creative)
|
||||
|
||||
# Include SDK
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
|
||||
|
||||
# Build
|
||||
add_library(expanded-creative SHARED expanded-creative.cpp)
|
||||
target_link_libraries(expanded-creative mods-headers reborn-patch symbols misc)
|
|
@ -0,0 +1,638 @@
|
|||
// Headers
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
// The Actual Mod
|
||||
|
||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) {
|
||||
ItemInstance *fire_instance = new ItemInstance;
|
||||
ALLOC_CHECK(fire_instance);
|
||||
fire_instance->count = 255;
|
||||
fire_instance->auxiliary = 0;
|
||||
fire_instance->id = 51;
|
||||
(*FillingContainer_addItem)(filling_container, fire_instance);
|
||||
|
||||
ItemInstance *mushroomStew_instance = new ItemInstance;
|
||||
ALLOC_CHECK(mushroomStew_instance);
|
||||
mushroomStew_instance->count = 255;
|
||||
mushroomStew_instance->auxiliary = 0;
|
||||
mushroomStew_instance->id = 282;
|
||||
(*FillingContainer_addItem)(filling_container, mushroomStew_instance);
|
||||
|
||||
ItemInstance *steak_instance = new ItemInstance;
|
||||
ALLOC_CHECK(steak_instance);
|
||||
steak_instance->count = 255;
|
||||
steak_instance->auxiliary = 0;
|
||||
steak_instance->id = 364;
|
||||
(*FillingContainer_addItem)(filling_container, steak_instance);
|
||||
|
||||
ItemInstance *cookedChicken_instance = new ItemInstance;
|
||||
ALLOC_CHECK(cookedChicken_instance);
|
||||
cookedChicken_instance->count = 255;
|
||||
cookedChicken_instance->auxiliary = 0;
|
||||
cookedChicken_instance->id = 366;
|
||||
(*FillingContainer_addItem)(filling_container, cookedChicken_instance);
|
||||
|
||||
ItemInstance *porkCooked_instance = new ItemInstance;
|
||||
ALLOC_CHECK(porkCooked_instance);
|
||||
porkCooked_instance->count = 255;
|
||||
porkCooked_instance->auxiliary = 0;
|
||||
porkCooked_instance->id = 320;
|
||||
(*FillingContainer_addItem)(filling_container, porkCooked_instance);
|
||||
|
||||
ItemInstance *apple_instance = new ItemInstance;
|
||||
ALLOC_CHECK(apple_instance);
|
||||
apple_instance->count = 255;
|
||||
apple_instance->auxiliary = 0;
|
||||
apple_instance->id = 260;
|
||||
(*FillingContainer_addItem)(filling_container, apple_instance);
|
||||
|
||||
ItemInstance *tallGrass_instance = new ItemInstance;
|
||||
ALLOC_CHECK(tallGrass_instance);
|
||||
tallGrass_instance->count = 255;
|
||||
tallGrass_instance->auxiliary = 0;
|
||||
tallGrass_instance->id = 31;
|
||||
(*FillingContainer_addItem)(filling_container, tallGrass_instance);
|
||||
|
||||
ItemInstance *crops_instance = new ItemInstance;
|
||||
ALLOC_CHECK(crops_instance);
|
||||
crops_instance->count = 255;
|
||||
crops_instance->auxiliary = 0;
|
||||
crops_instance->id = 59;
|
||||
(*FillingContainer_addItem)(filling_container, crops_instance);
|
||||
|
||||
ItemInstance *farmland_instance = new ItemInstance;
|
||||
ALLOC_CHECK(farmland_instance);
|
||||
farmland_instance->count = 255;
|
||||
farmland_instance->auxiliary = 0;
|
||||
farmland_instance->id = 60;
|
||||
(*FillingContainer_addItem)(filling_container, farmland_instance);
|
||||
|
||||
ItemInstance *activeFurnace_instance = new ItemInstance;
|
||||
ALLOC_CHECK(activeFurnace_instance);
|
||||
activeFurnace_instance->count = 255;
|
||||
activeFurnace_instance->auxiliary = 0;
|
||||
activeFurnace_instance->id = 62;
|
||||
(*FillingContainer_addItem)(filling_container, activeFurnace_instance);
|
||||
|
||||
ItemInstance *ironDoor_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironDoor_instance);
|
||||
ironDoor_instance->count = 255;
|
||||
ironDoor_instance->auxiliary = 0;
|
||||
ironDoor_instance->id = 330;
|
||||
(*FillingContainer_addItem)(filling_container, ironDoor_instance);
|
||||
|
||||
ItemInstance *activeRedstoneOre_instance = new ItemInstance;
|
||||
ALLOC_CHECK(activeRedstoneOre_instance);
|
||||
activeRedstoneOre_instance->count = 255;
|
||||
activeRedstoneOre_instance->auxiliary = 0;
|
||||
activeRedstoneOre_instance->id = 74;
|
||||
(*FillingContainer_addItem)(filling_container, activeRedstoneOre_instance);
|
||||
|
||||
ItemInstance *pumkinStem_instance = new ItemInstance;
|
||||
ALLOC_CHECK(pumkinStem_instance);
|
||||
pumkinStem_instance->count = 255;
|
||||
pumkinStem_instance->auxiliary = 0;
|
||||
pumkinStem_instance->id = 105;
|
||||
(*FillingContainer_addItem)(filling_container, pumkinStem_instance);
|
||||
|
||||
ItemInstance *newGrass_instance = new ItemInstance;
|
||||
ALLOC_CHECK(newGrass_instance);
|
||||
newGrass_instance->count = 255;
|
||||
newGrass_instance->auxiliary = 0;
|
||||
newGrass_instance->id = 253;
|
||||
(*FillingContainer_addItem)(filling_container, newGrass_instance);
|
||||
|
||||
ItemInstance *reserved6_instance = new ItemInstance;
|
||||
ALLOC_CHECK(reserved6_instance);
|
||||
reserved6_instance->count = 255;
|
||||
reserved6_instance->auxiliary = 0;
|
||||
reserved6_instance->id = 1;
|
||||
(*FillingContainer_addItem)(filling_container, reserved6_instance);
|
||||
|
||||
ItemInstance *doubleStoneSlab_instance = new ItemInstance;
|
||||
ALLOC_CHECK(doubleStoneSlab_instance);
|
||||
doubleStoneSlab_instance->count = 255;
|
||||
doubleStoneSlab_instance->auxiliary = 0;
|
||||
doubleStoneSlab_instance->id = 43;
|
||||
(*FillingContainer_addItem)(filling_container, doubleStoneSlab_instance);
|
||||
|
||||
ItemInstance *arrow_instance = new ItemInstance;
|
||||
ALLOC_CHECK(arrow_instance);
|
||||
arrow_instance->count = 255;
|
||||
arrow_instance->auxiliary = 0;
|
||||
arrow_instance->id = 262;
|
||||
(*FillingContainer_addItem)(filling_container, arrow_instance);
|
||||
|
||||
ItemInstance *coal_instance = new ItemInstance;
|
||||
ALLOC_CHECK(coal_instance);
|
||||
coal_instance->count = 255;
|
||||
coal_instance->auxiliary = 0;
|
||||
coal_instance->id = 263;
|
||||
(*FillingContainer_addItem)(filling_container, coal_instance);
|
||||
|
||||
ItemInstance *diamond_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamond_instance);
|
||||
diamond_instance->count = 255;
|
||||
diamond_instance->auxiliary = 0;
|
||||
diamond_instance->id = 264;
|
||||
(*FillingContainer_addItem)(filling_container, diamond_instance);
|
||||
|
||||
ItemInstance *ironIngot_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironIngot_instance);
|
||||
ironIngot_instance->count = 255;
|
||||
ironIngot_instance->auxiliary = 0;
|
||||
ironIngot_instance->id = 265;
|
||||
(*FillingContainer_addItem)(filling_container, ironIngot_instance);
|
||||
|
||||
ItemInstance *goldIngot_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldIngot_instance);
|
||||
goldIngot_instance->count = 255;
|
||||
goldIngot_instance->auxiliary = 0;
|
||||
goldIngot_instance->id = 266;
|
||||
(*FillingContainer_addItem)(filling_container, goldIngot_instance);
|
||||
|
||||
ItemInstance *woodSword_instance = new ItemInstance;
|
||||
ALLOC_CHECK(woodSword_instance);
|
||||
woodSword_instance->count = 255;
|
||||
woodSword_instance->auxiliary = 0;
|
||||
woodSword_instance->id = 268;
|
||||
(*FillingContainer_addItem)(filling_container, woodSword_instance);
|
||||
|
||||
ItemInstance *woodShovel_instance = new ItemInstance;
|
||||
ALLOC_CHECK(woodShovel_instance);
|
||||
woodShovel_instance->count = 255;
|
||||
woodShovel_instance->auxiliary = 0;
|
||||
woodShovel_instance->id = 269;
|
||||
(*FillingContainer_addItem)(filling_container, woodShovel_instance);
|
||||
|
||||
ItemInstance *woodPickaxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(woodPickaxe_instance);
|
||||
woodPickaxe_instance->count = 255;
|
||||
woodPickaxe_instance->auxiliary = 0;
|
||||
woodPickaxe_instance->id = 270;
|
||||
(*FillingContainer_addItem)(filling_container, woodPickaxe_instance);
|
||||
|
||||
ItemInstance *woodAxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(woodAxe_instance);
|
||||
woodAxe_instance->count = 255;
|
||||
woodAxe_instance->auxiliary = 0;
|
||||
woodAxe_instance->id = 271;
|
||||
(*FillingContainer_addItem)(filling_container, woodAxe_instance);
|
||||
|
||||
ItemInstance *stoneSword_instance = new ItemInstance;
|
||||
ALLOC_CHECK(stoneSword_instance);
|
||||
stoneSword_instance->count = 255;
|
||||
stoneSword_instance->auxiliary = 0;
|
||||
stoneSword_instance->id = 272;
|
||||
(*FillingContainer_addItem)(filling_container, stoneSword_instance);
|
||||
|
||||
ItemInstance *stoneShovel_instance = new ItemInstance;
|
||||
ALLOC_CHECK(stoneShovel_instance);
|
||||
stoneShovel_instance->count = 255;
|
||||
stoneShovel_instance->auxiliary = 0;
|
||||
stoneShovel_instance->id = 273;
|
||||
(*FillingContainer_addItem)(filling_container, stoneShovel_instance);
|
||||
|
||||
ItemInstance *stonePickaxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(stonePickaxe_instance);
|
||||
stonePickaxe_instance->count = 255;
|
||||
stonePickaxe_instance->auxiliary = 0;
|
||||
stonePickaxe_instance->id = 274;
|
||||
(*FillingContainer_addItem)(filling_container, stonePickaxe_instance);
|
||||
|
||||
ItemInstance *stoneAxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(stoneAxe_instance);
|
||||
stoneAxe_instance->count = 255;
|
||||
stoneAxe_instance->auxiliary = 0;
|
||||
stoneAxe_instance->id = 275;
|
||||
(*FillingContainer_addItem)(filling_container, stoneAxe_instance);
|
||||
|
||||
ItemInstance *shovelIron_instance = new ItemInstance;
|
||||
ALLOC_CHECK(shovelIron_instance);
|
||||
shovelIron_instance->count = 255;
|
||||
shovelIron_instance->auxiliary = 0;
|
||||
shovelIron_instance->id = 256;
|
||||
(*FillingContainer_addItem)(filling_container, shovelIron_instance);
|
||||
|
||||
ItemInstance *ironPick_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironPick_instance);
|
||||
ironPick_instance->count = 255;
|
||||
ironPick_instance->auxiliary = 0;
|
||||
ironPick_instance->id = 257;
|
||||
(*FillingContainer_addItem)(filling_container, ironPick_instance);
|
||||
|
||||
ItemInstance *ironAxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironAxe_instance);
|
||||
ironAxe_instance->count = 255;
|
||||
ironAxe_instance->auxiliary = 0;
|
||||
ironAxe_instance->id = 258;
|
||||
(*FillingContainer_addItem)(filling_container, ironAxe_instance);
|
||||
|
||||
ItemInstance *diamondSword_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondSword_instance);
|
||||
diamondSword_instance->count = 255;
|
||||
diamondSword_instance->auxiliary = 0;
|
||||
diamondSword_instance->id = 276;
|
||||
(*FillingContainer_addItem)(filling_container, diamondSword_instance);
|
||||
|
||||
ItemInstance *diamondShovel_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondShovel_instance);
|
||||
diamondShovel_instance->count = 255;
|
||||
diamondShovel_instance->auxiliary = 0;
|
||||
diamondShovel_instance->id = 277;
|
||||
(*FillingContainer_addItem)(filling_container, diamondShovel_instance);
|
||||
|
||||
ItemInstance *diamondPickaxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondPickaxe_instance);
|
||||
diamondPickaxe_instance->count = 255;
|
||||
diamondPickaxe_instance->auxiliary = 0;
|
||||
diamondPickaxe_instance->id = 278;
|
||||
(*FillingContainer_addItem)(filling_container, diamondPickaxe_instance);
|
||||
|
||||
ItemInstance *diamondAxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondAxe_instance);
|
||||
diamondAxe_instance->count = 255;
|
||||
diamondAxe_instance->auxiliary = 0;
|
||||
diamondAxe_instance->id = 279;
|
||||
(*FillingContainer_addItem)(filling_container, diamondAxe_instance);
|
||||
|
||||
ItemInstance *magicWand_instance = new ItemInstance;
|
||||
ALLOC_CHECK(magicWand_instance);
|
||||
magicWand_instance->count = 255;
|
||||
magicWand_instance->auxiliary = 0;
|
||||
magicWand_instance->id = 280;
|
||||
(*FillingContainer_addItem)(filling_container, magicWand_instance);
|
||||
|
||||
ItemInstance *bowl_instance = new ItemInstance;
|
||||
ALLOC_CHECK(bowl_instance);
|
||||
bowl_instance->count = 255;
|
||||
bowl_instance->auxiliary = 0;
|
||||
bowl_instance->id = 281;
|
||||
(*FillingContainer_addItem)(filling_container, bowl_instance);
|
||||
|
||||
ItemInstance *goldSword_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldSword_instance);
|
||||
goldSword_instance->count = 255;
|
||||
goldSword_instance->auxiliary = 0;
|
||||
goldSword_instance->id = 283;
|
||||
(*FillingContainer_addItem)(filling_container, goldSword_instance);
|
||||
|
||||
ItemInstance *goldShovel_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldShovel_instance);
|
||||
goldShovel_instance->count = 255;
|
||||
goldShovel_instance->auxiliary = 0;
|
||||
goldShovel_instance->id = 284;
|
||||
(*FillingContainer_addItem)(filling_container, goldShovel_instance);
|
||||
|
||||
ItemInstance *goldPickaxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldPickaxe_instance);
|
||||
goldPickaxe_instance->count = 255;
|
||||
goldPickaxe_instance->auxiliary = 0;
|
||||
goldPickaxe_instance->id = 285;
|
||||
(*FillingContainer_addItem)(filling_container, goldPickaxe_instance);
|
||||
|
||||
ItemInstance *goldAxe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldAxe_instance);
|
||||
goldAxe_instance->count = 255;
|
||||
goldAxe_instance->auxiliary = 0;
|
||||
goldAxe_instance->id = 286;
|
||||
(*FillingContainer_addItem)(filling_container, goldAxe_instance);
|
||||
|
||||
ItemInstance *string_instance = new ItemInstance;
|
||||
ALLOC_CHECK(string_instance);
|
||||
string_instance->count = 255;
|
||||
string_instance->auxiliary = 0;
|
||||
string_instance->id = 287;
|
||||
(*FillingContainer_addItem)(filling_container, string_instance);
|
||||
|
||||
ItemInstance *feather_instance = new ItemInstance;
|
||||
ALLOC_CHECK(feather_instance);
|
||||
feather_instance->count = 255;
|
||||
feather_instance->auxiliary = 0;
|
||||
feather_instance->id = 288;
|
||||
(*FillingContainer_addItem)(filling_container, feather_instance);
|
||||
|
||||
ItemInstance *gunpowder_instance = new ItemInstance;
|
||||
ALLOC_CHECK(gunpowder_instance);
|
||||
gunpowder_instance->count = 255;
|
||||
gunpowder_instance->auxiliary = 0;
|
||||
gunpowder_instance->id = 289;
|
||||
(*FillingContainer_addItem)(filling_container, gunpowder_instance);
|
||||
|
||||
ItemInstance *woodHoe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(woodHoe_instance);
|
||||
woodHoe_instance->count = 255;
|
||||
woodHoe_instance->auxiliary = 0;
|
||||
woodHoe_instance->id = 290;
|
||||
(*FillingContainer_addItem)(filling_container, woodHoe_instance);
|
||||
|
||||
ItemInstance *stoneHoe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(stoneHoe_instance);
|
||||
stoneHoe_instance->count = 255;
|
||||
stoneHoe_instance->auxiliary = 0;
|
||||
stoneHoe_instance->id = 291;
|
||||
(*FillingContainer_addItem)(filling_container, stoneHoe_instance);
|
||||
|
||||
ItemInstance *flint1_instance = new ItemInstance;
|
||||
ALLOC_CHECK(flint1_instance);
|
||||
flint1_instance->count = 255;
|
||||
flint1_instance->auxiliary = 0;
|
||||
flint1_instance->id = 292;
|
||||
(*FillingContainer_addItem)(filling_container, flint1_instance);
|
||||
|
||||
ItemInstance *diamondHoe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondHoe_instance);
|
||||
diamondHoe_instance->count = 255;
|
||||
diamondHoe_instance->auxiliary = 0;
|
||||
diamondHoe_instance->id = 293;
|
||||
(*FillingContainer_addItem)(filling_container, diamondHoe_instance);
|
||||
|
||||
ItemInstance *goldHoe_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldHoe_instance);
|
||||
goldHoe_instance->count = 255;
|
||||
goldHoe_instance->auxiliary = 0;
|
||||
goldHoe_instance->id = 294;
|
||||
(*FillingContainer_addItem)(filling_container, goldHoe_instance);
|
||||
|
||||
ItemInstance *seeds_instance = new ItemInstance;
|
||||
ALLOC_CHECK(seeds_instance);
|
||||
seeds_instance->count = 255;
|
||||
seeds_instance->auxiliary = 0;
|
||||
seeds_instance->id = 295;
|
||||
(*FillingContainer_addItem)(filling_container, seeds_instance);
|
||||
|
||||
ItemInstance *wheat_instance = new ItemInstance;
|
||||
ALLOC_CHECK(wheat_instance);
|
||||
wheat_instance->count = 255;
|
||||
wheat_instance->auxiliary = 0;
|
||||
wheat_instance->id = 296;
|
||||
(*FillingContainer_addItem)(filling_container, wheat_instance);
|
||||
|
||||
ItemInstance *bread_instance = new ItemInstance;
|
||||
ALLOC_CHECK(bread_instance);
|
||||
bread_instance->count = 255;
|
||||
bread_instance->auxiliary = 0;
|
||||
bread_instance->id = 297;
|
||||
(*FillingContainer_addItem)(filling_container, bread_instance);
|
||||
|
||||
ItemInstance *diamondHelm_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondHelm_instance);
|
||||
diamondHelm_instance->count = 255;
|
||||
diamondHelm_instance->auxiliary = 0;
|
||||
diamondHelm_instance->id = 310;
|
||||
(*FillingContainer_addItem)(filling_container, diamondHelm_instance);
|
||||
|
||||
ItemInstance *diamondChest_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondChest_instance);
|
||||
diamondChest_instance->count = 255;
|
||||
diamondChest_instance->auxiliary = 0;
|
||||
diamondChest_instance->id = 311;
|
||||
(*FillingContainer_addItem)(filling_container, diamondChest_instance);
|
||||
|
||||
ItemInstance *diamondLeg_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondLeg_instance);
|
||||
diamondLeg_instance->count = 255;
|
||||
diamondLeg_instance->auxiliary = 0;
|
||||
diamondLeg_instance->id = 312;
|
||||
(*FillingContainer_addItem)(filling_container, diamondLeg_instance);
|
||||
|
||||
ItemInstance *diamondBoot_instance = new ItemInstance;
|
||||
ALLOC_CHECK(diamondBoot_instance);
|
||||
diamondBoot_instance->count = 255;
|
||||
diamondBoot_instance->auxiliary = 0;
|
||||
diamondBoot_instance->id = 313;
|
||||
(*FillingContainer_addItem)(filling_container, diamondBoot_instance);
|
||||
|
||||
ItemInstance *leatherCap_instance = new ItemInstance;
|
||||
ALLOC_CHECK(leatherCap_instance);
|
||||
leatherCap_instance->count = 255;
|
||||
leatherCap_instance->auxiliary = 0;
|
||||
leatherCap_instance->id = 298;
|
||||
(*FillingContainer_addItem)(filling_container, leatherCap_instance);
|
||||
|
||||
ItemInstance *leatherShirt_instance = new ItemInstance;
|
||||
ALLOC_CHECK(leatherShirt_instance);
|
||||
leatherShirt_instance->count = 255;
|
||||
leatherShirt_instance->auxiliary = 0;
|
||||
leatherShirt_instance->id = 299;
|
||||
(*FillingContainer_addItem)(filling_container, leatherShirt_instance);
|
||||
|
||||
ItemInstance *leatherPants_instance = new ItemInstance;
|
||||
ALLOC_CHECK(leatherPants_instance);
|
||||
leatherPants_instance->count = 255;
|
||||
leatherPants_instance->auxiliary = 0;
|
||||
leatherPants_instance->id = 300;
|
||||
(*FillingContainer_addItem)(filling_container, leatherPants_instance);
|
||||
|
||||
ItemInstance *leatherBoots_instance = new ItemInstance;
|
||||
ALLOC_CHECK(leatherBoots_instance);
|
||||
leatherBoots_instance->count = 255;
|
||||
leatherBoots_instance->auxiliary = 0;
|
||||
leatherBoots_instance->id = 301;
|
||||
(*FillingContainer_addItem)(filling_container, leatherBoots_instance);
|
||||
|
||||
ItemInstance *chainHelm_instance = new ItemInstance;
|
||||
ALLOC_CHECK(chainHelm_instance);
|
||||
chainHelm_instance->count = 255;
|
||||
chainHelm_instance->auxiliary = 0;
|
||||
chainHelm_instance->id = 302;
|
||||
(*FillingContainer_addItem)(filling_container, chainHelm_instance);
|
||||
|
||||
ItemInstance *chainShirt_instance = new ItemInstance;
|
||||
ALLOC_CHECK(chainShirt_instance);
|
||||
chainShirt_instance->count = 255;
|
||||
chainShirt_instance->auxiliary = 0;
|
||||
chainShirt_instance->id = 303;
|
||||
(*FillingContainer_addItem)(filling_container, chainShirt_instance);
|
||||
|
||||
ItemInstance *chainLegs_instance = new ItemInstance;
|
||||
ALLOC_CHECK(chainLegs_instance);
|
||||
chainLegs_instance->count = 255;
|
||||
chainLegs_instance->auxiliary = 0;
|
||||
chainLegs_instance->id = 304;
|
||||
(*FillingContainer_addItem)(filling_container, chainLegs_instance);
|
||||
|
||||
ItemInstance *chainBoots_instance = new ItemInstance;
|
||||
ALLOC_CHECK(chainBoots_instance);
|
||||
chainBoots_instance->count = 255;
|
||||
chainBoots_instance->auxiliary = 0;
|
||||
chainBoots_instance->id = 305;
|
||||
(*FillingContainer_addItem)(filling_container, chainBoots_instance);
|
||||
|
||||
ItemInstance *goldHelm_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldHelm_instance);
|
||||
goldHelm_instance->count = 255;
|
||||
goldHelm_instance->auxiliary = 0;
|
||||
goldHelm_instance->id = 314;
|
||||
(*FillingContainer_addItem)(filling_container, goldHelm_instance);
|
||||
|
||||
ItemInstance *goldChest_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldChest_instance);
|
||||
goldChest_instance->count = 255;
|
||||
goldChest_instance->auxiliary = 0;
|
||||
goldChest_instance->id = 315;
|
||||
(*FillingContainer_addItem)(filling_container, goldChest_instance);
|
||||
|
||||
ItemInstance *goldLegs_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldLegs_instance);
|
||||
goldLegs_instance->count = 255;
|
||||
goldLegs_instance->auxiliary = 0;
|
||||
goldLegs_instance->id = 316;
|
||||
(*FillingContainer_addItem)(filling_container, goldLegs_instance);
|
||||
|
||||
ItemInstance *goldBoots_instance = new ItemInstance;
|
||||
ALLOC_CHECK(goldBoots_instance);
|
||||
goldBoots_instance->count = 255;
|
||||
goldBoots_instance->auxiliary = 0;
|
||||
goldBoots_instance->id = 317;
|
||||
(*FillingContainer_addItem)(filling_container, goldBoots_instance);
|
||||
|
||||
ItemInstance *ironHelm_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironHelm_instance);
|
||||
ironHelm_instance->count = 255;
|
||||
ironHelm_instance->auxiliary = 0;
|
||||
ironHelm_instance->id = 306;
|
||||
(*FillingContainer_addItem)(filling_container, ironHelm_instance);
|
||||
|
||||
ItemInstance *ironChest_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironChest_instance);
|
||||
ironChest_instance->count = 255;
|
||||
ironChest_instance->auxiliary = 0;
|
||||
ironChest_instance->id = 307;
|
||||
(*FillingContainer_addItem)(filling_container, ironChest_instance);
|
||||
|
||||
ItemInstance *ironLegs_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironLegs_instance);
|
||||
ironLegs_instance->count = 255;
|
||||
ironLegs_instance->auxiliary = 0;
|
||||
ironLegs_instance->id = 308;
|
||||
(*FillingContainer_addItem)(filling_container, ironLegs_instance);
|
||||
|
||||
ItemInstance *ironBoots_instance = new ItemInstance;
|
||||
ALLOC_CHECK(ironBoots_instance);
|
||||
ironBoots_instance->count = 255;
|
||||
ironBoots_instance->auxiliary = 0;
|
||||
ironBoots_instance->id = 309;
|
||||
(*FillingContainer_addItem)(filling_container, ironBoots_instance);
|
||||
|
||||
ItemInstance *flint2_instance = new ItemInstance;
|
||||
ALLOC_CHECK(flint2_instance);
|
||||
flint2_instance->count = 255;
|
||||
flint2_instance->auxiliary = 0;
|
||||
flint2_instance->id = 318;
|
||||
(*FillingContainer_addItem)(filling_container, flint2_instance);
|
||||
|
||||
ItemInstance *porkRaw_instance = new ItemInstance;
|
||||
ALLOC_CHECK(porkRaw_instance);
|
||||
porkRaw_instance->count = 255;
|
||||
porkRaw_instance->auxiliary = 0;
|
||||
porkRaw_instance->id = 319;
|
||||
(*FillingContainer_addItem)(filling_container, porkRaw_instance);
|
||||
|
||||
ItemInstance *leather_instance = new ItemInstance;
|
||||
ALLOC_CHECK(leather_instance);
|
||||
leather_instance->count = 255;
|
||||
leather_instance->auxiliary = 0;
|
||||
leather_instance->id = 334;
|
||||
(*FillingContainer_addItem)(filling_container, leather_instance);
|
||||
|
||||
ItemInstance *clayBrick_instance = new ItemInstance;
|
||||
ALLOC_CHECK(clayBrick_instance);
|
||||
clayBrick_instance->count = 255;
|
||||
clayBrick_instance->auxiliary = 0;
|
||||
clayBrick_instance->id = 336;
|
||||
(*FillingContainer_addItem)(filling_container, clayBrick_instance);
|
||||
|
||||
ItemInstance *clay_instance = new ItemInstance;
|
||||
ALLOC_CHECK(clay_instance);
|
||||
clay_instance->count = 255;
|
||||
clay_instance->auxiliary = 0;
|
||||
clay_instance->id = 337;
|
||||
(*FillingContainer_addItem)(filling_container, clay_instance);
|
||||
|
||||
ItemInstance *notepad_instance = new ItemInstance;
|
||||
ALLOC_CHECK(notepad_instance);
|
||||
notepad_instance->count = 255;
|
||||
notepad_instance->auxiliary = 0;
|
||||
notepad_instance->id = 339;
|
||||
(*FillingContainer_addItem)(filling_container, notepad_instance);
|
||||
|
||||
ItemInstance *book_instance = new ItemInstance;
|
||||
ALLOC_CHECK(book_instance);
|
||||
book_instance->count = 255;
|
||||
book_instance->auxiliary = 0;
|
||||
book_instance->id = 340;
|
||||
(*FillingContainer_addItem)(filling_container, book_instance);
|
||||
|
||||
ItemInstance *slimeball_instance = new ItemInstance;
|
||||
ALLOC_CHECK(slimeball_instance);
|
||||
slimeball_instance->count = 255;
|
||||
slimeball_instance->auxiliary = 0;
|
||||
slimeball_instance->id = 341;
|
||||
(*FillingContainer_addItem)(filling_container, slimeball_instance);
|
||||
|
||||
ItemInstance *compass_instance = new ItemInstance;
|
||||
ALLOC_CHECK(compass_instance);
|
||||
compass_instance->count = 255;
|
||||
compass_instance->auxiliary = 0;
|
||||
compass_instance->id = 345;
|
||||
(*FillingContainer_addItem)(filling_container, compass_instance);
|
||||
|
||||
ItemInstance *clock_instance = new ItemInstance;
|
||||
ALLOC_CHECK(clock_instance);
|
||||
clock_instance->count = 255;
|
||||
clock_instance->auxiliary = 0;
|
||||
clock_instance->id = 347;
|
||||
(*FillingContainer_addItem)(filling_container, clock_instance);
|
||||
|
||||
ItemInstance *glowDust_instance = new ItemInstance;
|
||||
ALLOC_CHECK(glowDust_instance);
|
||||
glowDust_instance->count = 255;
|
||||
glowDust_instance->auxiliary = 0;
|
||||
glowDust_instance->id = 348;
|
||||
(*FillingContainer_addItem)(filling_container, glowDust_instance);
|
||||
|
||||
ItemInstance *bone_instance = new ItemInstance;
|
||||
ALLOC_CHECK(bone_instance);
|
||||
bone_instance->count = 255;
|
||||
bone_instance->auxiliary = 0;
|
||||
bone_instance->id = 352;
|
||||
(*FillingContainer_addItem)(filling_container, bone_instance);
|
||||
|
||||
ItemInstance *sugar_instance = new ItemInstance;
|
||||
ALLOC_CHECK(sugar_instance);
|
||||
sugar_instance->count = 255;
|
||||
sugar_instance->auxiliary = 0;
|
||||
sugar_instance->id = 353;
|
||||
(*FillingContainer_addItem)(filling_container, sugar_instance);
|
||||
|
||||
ItemInstance *melon_instance = new ItemInstance;
|
||||
ALLOC_CHECK(melon_instance);
|
||||
melon_instance->count = 255;
|
||||
melon_instance->auxiliary = 0;
|
||||
melon_instance->id = 360;
|
||||
(*FillingContainer_addItem)(filling_container, melon_instance);
|
||||
|
||||
ItemInstance *beefRaw_instance = new ItemInstance;
|
||||
ALLOC_CHECK(beefRaw_instance);
|
||||
beefRaw_instance->count = 255;
|
||||
beefRaw_instance->auxiliary = 0;
|
||||
beefRaw_instance->id = 363;
|
||||
(*FillingContainer_addItem)(filling_container, beefRaw_instance);
|
||||
|
||||
ItemInstance *chickenRaw_instance = new ItemInstance;
|
||||
ALLOC_CHECK(chickenRaw_instance);
|
||||
chickenRaw_instance->count = 255;
|
||||
chickenRaw_instance->auxiliary = 0;
|
||||
chickenRaw_instance->id = 365;
|
||||
(*FillingContainer_addItem)(filling_container, chickenRaw_instance);
|
||||
}
|
||||
|
||||
// Init
|
||||
__attribute__((constructor)) static void init_expanded_creative() {
|
||||
INFO("Loading Expanded Creative Mod");
|
||||
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/out
|
||||
/debian/tmp
|
||||
/.vscode
|
||||
/build*
|
||||
/CMakeLists.txt.user
|
||||
*.autosave
|
||||
/AppImageBuilder.yml
|
||||
/appimage-builder-cache
|
||||
/appimage-build
|
||||
/AppDir
|
||||
/*.zsync
|
||||
/*.AppImage
|
||||
/core*
|
||||
/qemu_*
|
||||
/cmake/.prebuilt-armhf-toolchain
|
|
@ -0,0 +1,15 @@
|
|||
cmake_minimum_required(VERSION 3.16.0)
|
||||
|
||||
# Build For ARM
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
|
||||
|
||||
# Start Project
|
||||
project(recipes)
|
||||
|
||||
# Include SDK
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
|
||||
|
||||
# Build
|
||||
add_library(recipes SHARED recipes.cpp)
|
||||
target_link_libraries(recipes mods-headers reborn-util symbols misc)
|
|
@ -0,0 +1,52 @@
|
|||
// Headers
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
// Custom Crafting Recipes
|
||||
static void Recipes_injection(unsigned char *recipes) {
|
||||
// Add
|
||||
Recipes_Type type1 = {
|
||||
.item = 0,
|
||||
.tile = 0,
|
||||
.instance = {
|
||||
.count = 1,
|
||||
.id = 12,
|
||||
.auxiliary = 0
|
||||
},
|
||||
.letter = 'a'
|
||||
};
|
||||
Recipes_Type type2 = {
|
||||
.item = 0,
|
||||
.tile = 0,
|
||||
.instance = {
|
||||
.count = 1,
|
||||
.id = 13,
|
||||
.auxiliary = 0
|
||||
},
|
||||
.letter = 'b'
|
||||
};
|
||||
ItemInstance result = {
|
||||
.count = 1,
|
||||
.id = 344,
|
||||
.auxiliary = 0
|
||||
};
|
||||
(*Recipes_addShapelessRecipe)(recipes, result, {type1, type2});
|
||||
}
|
||||
|
||||
// Custom Furnace Recipes
|
||||
static void FurnaceRecipes_injection(unsigned char *recipes) {
|
||||
// Add
|
||||
(*FurnaceRecipes_addFurnaceRecipe)(recipes, 49, {.count = 1, .id = 246, .auxiliary = 0});
|
||||
}
|
||||
|
||||
// Init
|
||||
__attribute__((constructor)) static void init_recipes() {
|
||||
// Log
|
||||
INFO("Loading Custom Recipes");
|
||||
|
||||
// Setup
|
||||
misc_run_on_recipes_setup(Recipes_injection);
|
||||
misc_run_on_furnace_recipes_setup(FurnaceRecipes_injection);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
project(images)
|
||||
|
||||
# Title Background
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
install(
|
||||
FILES "background.png"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui"
|
||||
RENAME "titleBG.png"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Icon
|
||||
install(
|
||||
FILES "icon.png"
|
||||
DESTINATION "${MCPI_SHARE_DIR}/icons/hicolor/scalable/apps"
|
||||
RENAME "${MCPI_APP_ID}.png"
|
||||
)
|
||||
|
||||
# AppImage
|
||||
if(MCPI_IS_APPIMAGE_BUILD)
|
||||
install_symlink("${MCPI_SHARE_DIR}/icons/hicolor/scalable/apps/${MCPI_APP_ID}.png" "${MCPI_APP_ID}.png")
|
||||
install_symlink("${MCPI_APP_ID}.png" ".DirIcon")
|
||||
endif()
|
Binary file not shown.
After Width: | Height: | Size: 283 KiB |
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
BIN
images/start.png
BIN
images/start.png
Binary file not shown.
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 155 KiB |
|
@ -1,18 +1,114 @@
|
|||
project(launcher)
|
||||
|
||||
# Launcher
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
add_executable(launcher src/bootstrap.c src/ldconfig.cpp)
|
||||
if(MCPI_SERVER_MODE)
|
||||
target_sources(launcher PRIVATE src/server/launcher.c)
|
||||
else()
|
||||
target_sources(launcher PRIVATE src/client/launcher.cpp)
|
||||
endif()
|
||||
target_link_libraries(launcher reborn-headers)
|
||||
# Install
|
||||
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
install_symlink("../../${MCPI_INSTALL_DIR}/launcher" "usr/bin/${MCPI_VARIANT_NAME}")
|
||||
if(NOT MCPI_SERVER_MODE)
|
||||
install(DIRECTORY "client-data/" DESTINATION ".")
|
||||
endif()
|
||||
add_executable(launcher src/bootstrap.c src/patchelf.cpp src/crash-report.c)
|
||||
if(MCPI_SERVER_MODE)
|
||||
target_sources(launcher PRIVATE src/server/launcher.c)
|
||||
else()
|
||||
embed_resource(launcher src/client/available-feature-flags)
|
||||
target_sources(launcher PRIVATE src/client/launcher.cpp src/client/cache.cpp)
|
||||
endif()
|
||||
target_link_libraries(launcher reborn-util LIB_LIEF)
|
||||
# RPath
|
||||
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
||||
|
||||
# Install
|
||||
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
|
||||
|
||||
# Install Desktop Entry
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"[Desktop Entry]\n"
|
||||
"Name=${MCPI_APP_TITLE}\n"
|
||||
"Comment=Fun with Blocks\n"
|
||||
"Icon=${MCPI_APP_ID}\n"
|
||||
"Exec=${MCPI_VARIANT_NAME}\n"
|
||||
"Type=Application\n"
|
||||
"Categories=Game;\n"
|
||||
)
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"Terminal=true\n"
|
||||
"NoDisplay=true\n"
|
||||
)
|
||||
else()
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"Terminal=false\n"
|
||||
"StartupNotify=false\n"
|
||||
"StartupWMClass=${MCPI_APP_ID}\n"
|
||||
)
|
||||
endif()
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
DESTINATION "${MCPI_SHARE_DIR}/applications"
|
||||
RENAME "${MCPI_APP_ID}.desktop"
|
||||
)
|
||||
|
||||
# Install AppStream Metadata
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<component type=\"desktop\">\n"
|
||||
" <id>${MCPI_APP_ID}</id>\n"
|
||||
" <name>${MCPI_APP_TITLE}</name>\n"
|
||||
" <metadata_license>CC0-1.0</metadata_license>\n"
|
||||
" <summary>Fun with Blocks</summary>\n"
|
||||
" <description>\n"
|
||||
" <p>Minecraft: Pi Edition Modding Project.</p>\n"
|
||||
" <p>NOTE: This is not verified by, affiliated with, or supported by Mojang or Microsoft.</p>\n"
|
||||
" </description>\n"
|
||||
" <url type=\"homepage\">https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn</url>\n"
|
||||
" <launchable type=\"desktop-id\">${MCPI_APP_ID}.desktop</launchable>\n"
|
||||
" <provides>\n"
|
||||
" <id>com.thebrokenrail.MCPIRebornClient.desktop</id>\n"
|
||||
" </provides>\n"
|
||||
" <project_license>LicenseRef-proprietary</project_license>\n"
|
||||
" <developer_name>TheBrokenRail & 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()
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
TRUE Touch GUI
|
||||
TRUE Fix Bow & Arrow
|
||||
TRUE Fix Attacking
|
||||
TRUE Mob Spawning
|
||||
TRUE Fancy Graphics
|
||||
TRUE Disable Autojump By Default
|
||||
TRUE Display Nametags By Default
|
||||
TRUE Fix Sign Placement
|
||||
TRUE Show Block Outlines
|
||||
FALSE Expand Creative Inventory
|
||||
FALSE Peaceful Mode
|
||||
TRUE Animated Water
|
||||
TRUE Remove Invalid Item Background
|
||||
TRUE Disable gui_blocks Atlas
|
||||
TRUE Smooth Lighting
|
||||
FALSE 3D Anaglyph
|
|
@ -1,10 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=Minecraft: Pi Edition: Reborn
|
||||
Comment=Fun with Blocks
|
||||
Icon=/usr/share/pixmaps/minecraft-pi-reborn-client.png
|
||||
StartupNotify=false
|
||||
StartupWMClass=Minecraft - Pi edition
|
||||
Exec=/usr/bin/minecraft-pi-reborn-client
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Application;Game;
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
|
@ -11,44 +11,8 @@
|
|||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "ldconfig.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];
|
||||
}
|
||||
}
|
||||
static void set_and_print_env(const char *name, char *value) {
|
||||
// Set Variable With No Trailing Colon
|
||||
trim(&value);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Print New Value
|
||||
INFO("Set %s = %s", name, value);
|
||||
#endif
|
||||
// Set The Value
|
||||
setenv(name, value, 1);
|
||||
}
|
||||
|
||||
// Get Environmental Variable
|
||||
static char *get_env_safe(const char *name) {
|
||||
// Get Variable Or Blank String If Not Set
|
||||
char *ret = getenv(name);
|
||||
return ret != NULL ? ret : "";
|
||||
}
|
||||
#include "patchelf.h"
|
||||
#include "crash-report.h"
|
||||
|
||||
// Get All Mods In Folder
|
||||
static void load(char **ld_preload, char *folder) {
|
||||
|
@ -82,14 +46,14 @@ static void load(char **ld_preload, char *folder) {
|
|||
// Add Terminator
|
||||
name[total_length] = '\0';
|
||||
|
||||
// Check If File Is Executable
|
||||
// Check If File Is Accessible
|
||||
int result = access(name, R_OK);
|
||||
if (result == 0) {
|
||||
// Add To LD_PRELOAD
|
||||
string_append(ld_preload, ":%s", name);
|
||||
string_append(ld_preload, "%s%s", *ld_preload == NULL ? "" : ":", name);
|
||||
} else if (result == -1 && errno != 0) {
|
||||
// Fail
|
||||
INFO("Unable To Acesss: %s: %s", name, strerror(errno));
|
||||
WARN("Unable To Access: %s: %s", name, strerror(errno));
|
||||
errno = 0;
|
||||
}
|
||||
}
|
||||
|
@ -121,102 +85,401 @@ static void load(char **ld_preload, char *folder) {
|
|||
}
|
||||
}
|
||||
|
||||
#define MCPI_NAME "minecraft-pi"
|
||||
#define MCPI_BINARY "minecraft-pi"
|
||||
#define QEMU_BINARY "qemu-arm"
|
||||
|
||||
// Bootstrap
|
||||
void bootstrap(int argc, char *argv[]) {
|
||||
INFO("%s", "Configuring Game...");
|
||||
// Exit Handler
|
||||
static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
// Pass Signal To Child
|
||||
murder_children();
|
||||
while (wait(NULL) > 0) {}
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Pre-Bootstrap
|
||||
void pre_bootstrap(int argc, char *argv[]) {
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Launcher) ";
|
||||
|
||||
// Disable stdout Buffering
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
// Print Version
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
|
||||
// Print
|
||||
printf("Reborn v%s\n", MCPI_VERSION);
|
||||
fflush(stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Logging
|
||||
setup_log_file();
|
||||
|
||||
// --debug
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--debug") == 0) {
|
||||
set_and_print_env("MCPI_DEBUG", "1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// GTK Dark Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
set_and_print_env("GTK_THEME", "Adwaita:dark");
|
||||
#endif
|
||||
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
|
||||
// Configure LD_LIBRARY_PATH
|
||||
// Configure PATH
|
||||
{
|
||||
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_LIBRARY_PATH");
|
||||
// Add Library Directory
|
||||
char *new_ld_path;
|
||||
safe_asprintf(&new_ld_path, "%s/lib", binary_directory);
|
||||
// Add Existing LD_LIBRAR_PATH
|
||||
char *new_path = NULL;
|
||||
safe_asprintf(&new_path, "%s/bin", binary_directory);
|
||||
// Add Existing PATH
|
||||
{
|
||||
char *value = get_env_safe("LD_LIBRARY_PATH");
|
||||
if (strlen(value) > 0) {
|
||||
string_append(&new_ld_path, ":%s", value);
|
||||
char *value = getenv("PATH");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&new_path, ":%s", value);
|
||||
}
|
||||
}
|
||||
// Load ARM Libraries
|
||||
#ifdef __ARM_ARCH
|
||||
string_append(&new_ld_path, "%s", ":/usr/lib/arm-linux-gnueabihf:/usr/arm-linux-gnueabihf/lib");
|
||||
#endif
|
||||
// Add Full Library Search Path
|
||||
{
|
||||
char *value = get_full_library_search_path();
|
||||
if (strlen(value) > 0) {
|
||||
string_append(&new_ld_path, ":%s", value);
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
// Add Fallback Library Directory
|
||||
string_append(&new_ld_path, ":%s/fallback-lib", binary_directory);
|
||||
// Set And Free
|
||||
set_and_print_env("LD_LIBRARY_PATH", new_ld_path);
|
||||
free(new_ld_path);
|
||||
set_and_print_env("PATH", new_path);
|
||||
free(new_path);
|
||||
}
|
||||
|
||||
// Configure LD_PRELOAD
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
|
||||
// Setup Crash Reports
|
||||
setup_crash_report();
|
||||
|
||||
// AppImage
|
||||
#ifdef MCPI_IS_APPIMAGE_BUILD
|
||||
{
|
||||
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
|
||||
char *new_ld_preload = NULL;
|
||||
safe_asprintf(&new_ld_preload, "%s", get_env_safe("LD_PRELOAD"));
|
||||
char *owd = getenv("OWD");
|
||||
if (owd != NULL && chdir(owd) != 0) {
|
||||
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
// Install Signal Handlers
|
||||
struct sigaction act_sigint;
|
||||
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, NULL);
|
||||
struct sigaction act_sigterm;
|
||||
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, NULL);
|
||||
}
|
||||
|
||||
// Set LD_PRELOAD
|
||||
set_and_print_env("LD_PRELOAD", new_ld_preload);
|
||||
free(new_ld_preload);
|
||||
// Copy SDK Into ~/.minecraft-pi
|
||||
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);
|
||||
}
|
||||
}
|
||||
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
|
||||
static void copy_sdk(char *binary_directory) {
|
||||
// Ensure SDK Directory
|
||||
{
|
||||
char *sdk_path = NULL;
|
||||
safe_asprintf(&sdk_path, "%s" HOME_SUBDIRECTORY_FOR_SDK, getenv("HOME"));
|
||||
const char *const command[] = {"mkdir", "-p", sdk_path, NULL};
|
||||
run_simple_command(command, "Unable To Create SDK Directory");
|
||||
}
|
||||
|
||||
// Lock File
|
||||
char *lock_file_path = NULL;
|
||||
safe_asprintf(&lock_file_path, "%s" HOME_SUBDIRECTORY_FOR_SDK "/.lock", getenv("HOME"));
|
||||
int lock_file_fd = lock_file(lock_file_path);
|
||||
|
||||
// Output Directory
|
||||
char *output = NULL;
|
||||
safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_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);
|
||||
|
||||
// Unlock File
|
||||
unlock_file(lock_file_path, lock_file_fd);
|
||||
free(lock_file_path);
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
void bootstrap(int argc, char *argv[]) {
|
||||
INFO("Configuring Game...");
|
||||
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
|
||||
// Copy SDK
|
||||
copy_sdk(binary_directory);
|
||||
|
||||
// Set MCPI_REBORN_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = realpath("/proc/self/exe", NULL);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_REBORN_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
||||
char *resolved_path = NULL;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Resolving File Paths...");
|
||||
|
||||
// Resolve Full Binary Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
|
||||
resolved_path = realpath(full_path, NULL);
|
||||
ALLOC_CHECK(resolved_path);
|
||||
free(full_path);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
||||
{
|
||||
// Log
|
||||
DEBUG("Patching ELF Dependencies...");
|
||||
|
||||
// Find Linker
|
||||
char *linker = NULL;
|
||||
// Select Linker
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
// Use ARM Sysroot Linker
|
||||
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
|
||||
#else
|
||||
// Use Current Linker
|
||||
linker = patch_get_interpreter();
|
||||
#endif
|
||||
|
||||
// Patch
|
||||
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
|
||||
|
||||
// Free Linker Path
|
||||
if (linker != NULL) {
|
||||
free(linker);
|
||||
}
|
||||
|
||||
// Verify
|
||||
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Set MCPI_VANILLA_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = strdup(resolved_path);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Free Resolved Path
|
||||
free(resolved_path);
|
||||
|
||||
// Configure Library Search Path
|
||||
{
|
||||
// Log
|
||||
DEBUG("Setting Linker Search Paths...");
|
||||
|
||||
// Prepare
|
||||
char *transitive_ld_path = NULL;
|
||||
char *mcpi_ld_path = NULL;
|
||||
|
||||
// Library Search Path For Native Components
|
||||
{
|
||||
// Add Native Library Directory
|
||||
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
|
||||
|
||||
// Add Host LD_LIBRARY_PATH
|
||||
{
|
||||
char *value = getenv("LD_LIBRARY_PATH");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&transitive_ld_path, ":%s", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path);
|
||||
free(transitive_ld_path);
|
||||
}
|
||||
|
||||
// Library Search Path For ARM Components
|
||||
{
|
||||
// Add ARM Library Directory
|
||||
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
|
||||
|
||||
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory);
|
||||
#endif
|
||||
|
||||
// Add Host LD_LIBRARY_PATH
|
||||
{
|
||||
char *value = getenv("LD_LIBRARY_PATH");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&mcpi_ld_path, ":%s", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
|
||||
free(mcpi_ld_path);
|
||||
}
|
||||
|
||||
// Setup iconv
|
||||
{
|
||||
// Native Components
|
||||
char *host_gconv_path = getenv("GCONV_PATH");
|
||||
set_and_print_env("MCPI_NATIVE_GCONV_PATH", host_gconv_path);
|
||||
|
||||
// ARM Components
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
char *gconv_path = NULL;
|
||||
safe_asprintf(&gconv_path, "%s/sysroot/usr/lib/gconv", binary_directory);
|
||||
set_and_print_env("MCPI_ARM_GCONV_PATH", gconv_path);
|
||||
free(gconv_path);
|
||||
#else
|
||||
set_and_print_env("MCPI_ARM_GCONV_PATH", host_gconv_path);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Configure Preloaded Objects
|
||||
{
|
||||
// Log
|
||||
DEBUG("Locating Mods...");
|
||||
|
||||
// Native Components
|
||||
char *host_ld_preload = getenv("LD_PRELOAD");
|
||||
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
|
||||
|
||||
// ARM Components
|
||||
{
|
||||
// Prepare
|
||||
char *preload = NULL;
|
||||
|
||||
// ~/.minecraft-pi/mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
char *mods_folder = NULL;
|
||||
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
|
||||
// Load Mods From ./mods
|
||||
load(&preload, mods_folder);
|
||||
// Free Mods Folder
|
||||
free(mods_folder);
|
||||
}
|
||||
|
||||
// Built-In Mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
char *mods_folder = NULL;
|
||||
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
|
||||
// Load Mods From ./mods
|
||||
load(&preload, mods_folder);
|
||||
// Free Mods Folder
|
||||
free(mods_folder);
|
||||
}
|
||||
|
||||
// Add LD_PRELOAD
|
||||
{
|
||||
char *value = getenv("LD_PRELOAD");
|
||||
if (value != NULL && strlen(value) > 0) {
|
||||
string_append(&preload, ":%s", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set
|
||||
set_and_print_env("MCPI_ARM_LD_PRELOAD", preload);
|
||||
free(preload);
|
||||
}
|
||||
}
|
||||
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
|
||||
// Start Game
|
||||
INFO("%s", "Starting Game...");
|
||||
#ifdef __ARM_ARCH
|
||||
// Create Arguments List
|
||||
char *new_argv[argc + 1];
|
||||
for (int i = 1; i <= argc; i++) {
|
||||
new_argv[i] = argv[i];
|
||||
}
|
||||
new_argv[0] = NULL; // Updated By safe_execvpe()
|
||||
// Run
|
||||
safe_execvpe_relative_to_binary(MCPI_NAME, new_argv, environ);
|
||||
#else
|
||||
// Use Static QEMU So It Isn't Affected By LD_* Variables
|
||||
#define QEMU_NAME "qemu-arm-static"
|
||||
// Use Correct LibC
|
||||
setenv("QEMU_LD_PREFIX", "/usr/arm-linux-gnueabihf", 1);
|
||||
INFO("Starting Game...");
|
||||
|
||||
// Get Binary Directory
|
||||
binary_directory = get_binary_directory();
|
||||
// Create Full Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/" MCPI_NAME, binary_directory);
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
// Arguments
|
||||
int argv_start = 1; // argv = &new_args[argv_start]
|
||||
const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
|
||||
|
||||
// Create Arguments List
|
||||
char *new_argv[argc + 2];
|
||||
for (int i = 1; i <= argc; i++) {
|
||||
new_argv[i + 1] = argv[i];
|
||||
// Copy Existing Arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
new_args[i + argv_start] = argv[i];
|
||||
}
|
||||
new_argv[0] = NULL; // Updated By safe_execvpe()
|
||||
new_argv[1] = full_path; // Path To MCPI
|
||||
// Run
|
||||
safe_execvpe(QEMU_NAME, new_argv, environ);
|
||||
// NULL-Terminator
|
||||
new_args[argv_start + argc] = NULL;
|
||||
|
||||
// Set Executable Argument
|
||||
new_args[argv_start] = new_mcpi_exe_path;
|
||||
|
||||
// Non-ARM Systems Need QEMU
|
||||
#ifndef __ARM_ARCH
|
||||
argv_start--;
|
||||
new_args[argv_start] = QEMU_BINARY;
|
||||
#endif
|
||||
|
||||
// Setup Environment
|
||||
setup_exec_environment(1);
|
||||
|
||||
// Pass LD_* Variables Through QEMU
|
||||
#ifndef __ARM_ARCH
|
||||
char *qemu_set_env = NULL;
|
||||
#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name));
|
||||
for_each_special_environmental_variable(pass_variable_through_qemu);
|
||||
set_and_print_env("QEMU_SET_ENV", qemu_set_env);
|
||||
free(qemu_set_env);
|
||||
// Treat QEMU Itself As A Native Component
|
||||
setup_exec_environment(0);
|
||||
#endif
|
||||
|
||||
// Run
|
||||
const char **new_argv = &new_args[argv_start];
|
||||
safe_execvpe(new_argv, (const char *const *) environ);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void run_simple_command(const char *const command[], const char *error);
|
||||
|
||||
void pre_bootstrap(int argc, char *argv[]);
|
||||
void bootstrap(int argc, char *argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
FALSE Full Touch GUI
|
||||
TRUE Fix Bow & Arrow
|
||||
TRUE Fix Attacking
|
||||
FALSE Force Mob Spawning
|
||||
TRUE Disable Autojump By Default
|
||||
TRUE Display Nametags By Default
|
||||
TRUE Fix Sign Placement
|
||||
TRUE Show Block Outlines
|
||||
FALSE Expand Creative Mode Inventory
|
||||
FALSE Remove Creative Mode Restrictions
|
||||
TRUE Animated Water
|
||||
TRUE Remove Invalid Item Background
|
||||
TRUE Disable "gui_blocks" Atlas
|
||||
TRUE Fix Camera Rendering
|
||||
TRUE Implement Chat
|
||||
FALSE Hide Chat Messages
|
||||
TRUE Implement Death Messages
|
||||
TRUE Implement Game-Mode Switching
|
||||
TRUE Allow Joining Survival Mode Servers
|
||||
TRUE Miscellaneous Input Fixes
|
||||
TRUE Bind "Q" Key To Item Dropping
|
||||
TRUE Bind Common Toggleable Options To Function Keys
|
||||
TRUE Render Selected Item Text
|
||||
TRUE External Server Support
|
||||
TRUE Load Language Files
|
||||
TRUE Implement Sound Engine
|
||||
TRUE Close Current Screen On Death
|
||||
FALSE Disable Raw Mouse Motion (Not Recommended)
|
||||
TRUE Fix Furnace Not Checking Item Auxiliary
|
||||
TRUE Improved Cursor Rendering
|
||||
TRUE Disable V-Sync
|
||||
TRUE Fix Options Screen
|
||||
TRUE Force Touch GUI Inventory
|
||||
TRUE Fix Pause Menu
|
||||
TRUE Add Title Screen Background
|
||||
TRUE Force Touch GUI Button Behavior
|
||||
TRUE Improved Button Hover Behavior
|
||||
TRUE Implement Create World Dialog
|
||||
FALSE Remove Forced GUI Lag (Can Break Joining Servers)
|
||||
TRUE Add Buckets
|
||||
TRUE Classic HUD
|
||||
TRUE Translucent Toolbar
|
||||
FALSE Force EGL
|
||||
TRUE Improved Classic Title Screen
|
||||
FALSE Disable Speed Bridging
|
||||
FALSE Disable Creative Mode Mining Delay
|
|
@ -0,0 +1,171 @@
|
|||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "launcher.h"
|
||||
#include "cache.h"
|
||||
|
||||
// Get Cache Path
|
||||
static std::string get_cache_path() {
|
||||
const char *home = getenv("HOME");
|
||||
if (home == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
return std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA "/.launcher-cache";
|
||||
}
|
||||
|
||||
// Load
|
||||
launcher_cache empty_cache = {
|
||||
.username = DEFAULT_USERNAME,
|
||||
.render_distance = DEFAULT_RENDER_DISTANCE,
|
||||
.feature_flags = {}
|
||||
};
|
||||
launcher_cache load_cache() {
|
||||
// Log
|
||||
DEBUG("Loading Launcher Cache...");
|
||||
|
||||
// Return Value
|
||||
launcher_cache ret = empty_cache;
|
||||
|
||||
// Open File
|
||||
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
|
||||
if (!stream) {
|
||||
// Fail
|
||||
struct stat s;
|
||||
// No Warning If File Doesn't Exist
|
||||
if (stat(get_cache_path().c_str(), &s) == 0) {
|
||||
WARN("Unable To Open Launcher Cache For Loading");
|
||||
}
|
||||
} else {
|
||||
// Lock File
|
||||
int lock_fd = lock_file(get_cache_path().c_str());
|
||||
|
||||
// Check Version
|
||||
unsigned char cache_version;
|
||||
stream.read((char *) &cache_version, 1);
|
||||
if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) {
|
||||
// Fail
|
||||
if (!stream.eof()) {
|
||||
WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", (int) CACHE_VERSION, (int) cache_version);
|
||||
} else {
|
||||
WARN("Unable To Read Launcher Cache Version");
|
||||
}
|
||||
stream.close();
|
||||
} else {
|
||||
// Load Username And Render Distance
|
||||
launcher_cache cache;
|
||||
std::getline(stream, cache.username, '\0');
|
||||
std::getline(stream, cache.render_distance, '\0');
|
||||
|
||||
// Load Feature Flags
|
||||
std::string flag;
|
||||
while (!stream.eof() && std::getline(stream, flag, '\0')) {
|
||||
if (flag.length() > 0) {
|
||||
unsigned char is_enabled = 0;
|
||||
stream.read((char *) &is_enabled, 1);
|
||||
cache.feature_flags[flag] = is_enabled != (unsigned char) 0;
|
||||
}
|
||||
stream.peek();
|
||||
}
|
||||
|
||||
// Finish
|
||||
stream.close();
|
||||
if (!stream) {
|
||||
// Fail
|
||||
WARN("Failure While Loading Launcher Cache");
|
||||
} else {
|
||||
// Success
|
||||
ret = cache;
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock File
|
||||
unlock_file(get_cache_path().c_str(), lock_fd);
|
||||
}
|
||||
|
||||
// Return
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Save
|
||||
#define write_env_to_stream(stream, env) \
|
||||
{ \
|
||||
const char *env_value = getenv(env); \
|
||||
if (env == NULL) { \
|
||||
IMPOSSIBLE(); \
|
||||
} \
|
||||
stream.write(env_value, strlen(env_value) + 1); \
|
||||
}
|
||||
void save_cache() {
|
||||
// Log
|
||||
DEBUG("Saving Launcher Cache...");
|
||||
|
||||
// Open File
|
||||
std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary);
|
||||
if (!stream) {
|
||||
// Fail
|
||||
WARN("Unable To Open Launcher Cache For Saving");
|
||||
} else {
|
||||
// Lock File
|
||||
int lock_fd = lock_file(get_cache_path().c_str());
|
||||
|
||||
// Save Cache Version
|
||||
unsigned char cache_version = (unsigned char) CACHE_VERSION;
|
||||
stream.write((const char *) &cache_version, 1);
|
||||
|
||||
// Save Username And Render Distance
|
||||
write_env_to_stream(stream, "MCPI_USERNAME");
|
||||
write_env_to_stream(stream, "MCPI_RENDER_DISTANCE");
|
||||
|
||||
// Save Feature Flags
|
||||
std::unordered_map<std::string, bool> flags;
|
||||
load_available_feature_flags([&flags](std::string flag) {
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, NULL);
|
||||
flags[stripped_flag] = false;
|
||||
});
|
||||
{
|
||||
const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS");
|
||||
if (enabled_flags == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
std::istringstream enabled_flags_stream(enabled_flags);
|
||||
std::string flag;
|
||||
while (std::getline(enabled_flags_stream, flag, '|')) {
|
||||
if (flag.length() > 0) {
|
||||
flags[flag] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &it : flags) {
|
||||
stream.write(it.first.c_str(), it.first.size() + 1);
|
||||
unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0;
|
||||
stream.write((const char *) &val, 1);
|
||||
}
|
||||
|
||||
// Finish
|
||||
stream.close();
|
||||
if (!stream.good()) {
|
||||
WARN("Failure While Saving Launcher Cache");
|
||||
}
|
||||
|
||||
// Unlock File
|
||||
unlock_file(get_cache_path().c_str(), lock_fd);
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe Cache
|
||||
void wipe_cache() {
|
||||
// Log
|
||||
INFO("Wiping Launcher Cache...");
|
||||
|
||||
// Unlink File
|
||||
if (unlink(get_cache_path().c_str()) != 0) {
|
||||
WARN("Failure While Wiping Cache: %s", strerror(errno));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// Cache Version
|
||||
#define CACHE_VERSION 0
|
||||
|
||||
// Load Cache
|
||||
typedef struct {
|
||||
std::string username;
|
||||
std::string render_distance;
|
||||
std::unordered_map<std::string, bool> feature_flags;
|
||||
} launcher_cache;
|
||||
extern launcher_cache empty_cache;
|
||||
launcher_cache load_cache();
|
||||
|
||||
// Save Cache
|
||||
void save_cache();
|
||||
|
||||
// Wipe Cache
|
||||
void wipe_cache();
|
|
@ -1,84 +1,86 @@
|
|||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../bootstrap.h"
|
||||
#include "launcher.h"
|
||||
#include "cache.h"
|
||||
|
||||
// Strip Feature Flag Default
|
||||
std::string strip_feature_flag_default(std::string flag, bool *default_ret) {
|
||||
// Valid Values
|
||||
std::string true_str = "TRUE ";
|
||||
std::string false_str = "FALSE ";
|
||||
// Test
|
||||
if (flag.rfind(true_str, 0) == 0) {
|
||||
// Enabled By Default
|
||||
if (default_ret != NULL) {
|
||||
*default_ret = true;
|
||||
}
|
||||
return flag.substr(true_str.length(), std::string::npos);
|
||||
} else if (flag.rfind(false_str, 0) == 0) {
|
||||
// Disabled By Default
|
||||
if (default_ret != NULL) {
|
||||
*default_ret = false;
|
||||
}
|
||||
return flag.substr(false_str.length(), std::string::npos);
|
||||
} else {
|
||||
// Invalid
|
||||
ERR("Invalid Feature Flag Default");
|
||||
}
|
||||
}
|
||||
|
||||
// Load Available Feature Flags
|
||||
static void load_available_feature_flags(std::function<void(std::string)> callback) {
|
||||
extern unsigned char available_feature_flags[];
|
||||
extern size_t available_feature_flags_len;
|
||||
void load_available_feature_flags(std::function<void(std::string)> callback) {
|
||||
// Get Path
|
||||
char *binary_directory = get_binary_directory();
|
||||
std::string path = std::string(binary_directory) + "/available-feature-flags";
|
||||
free(binary_directory);
|
||||
// Load File
|
||||
std::ifstream stream(path);
|
||||
if (stream && stream.good()) {
|
||||
std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len);
|
||||
std::stringstream stream(data);
|
||||
// Store Lines
|
||||
std::vector<std::string> lines;
|
||||
// Read File
|
||||
{
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) {
|
||||
if (line.length() > 0) {
|
||||
// Verify Line
|
||||
if (line.find('|') == std::string::npos) {
|
||||
callback(line);
|
||||
lines.push_back(line);
|
||||
} else {
|
||||
// Invalid Line
|
||||
ERR("%s", "Feature Flag Contains Invalid '|'");
|
||||
ERR("Feature Flag Contains Invalid '|'");
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.close();
|
||||
} else {
|
||||
ERR("%s", "Unable To Load Available Feature Flags");
|
||||
}
|
||||
// Sort
|
||||
std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) {
|
||||
// Strip Defaults
|
||||
std::string stripped_a = strip_feature_flag_default(a, NULL);
|
||||
std::string stripped_b = strip_feature_flag_default(b, NULL);
|
||||
// Sort
|
||||
return stripped_a < stripped_b;
|
||||
});
|
||||
// Run Callbacks
|
||||
for (std::string &line : lines) {
|
||||
callback(line);
|
||||
}
|
||||
}
|
||||
|
||||
// Run Command And Get Output
|
||||
static char *run_command(char *command[], int *return_code) {
|
||||
// Store Output
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
// Run
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Run Command: %s", strerror(errno));
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Pipe stdout
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
close(output_pipe[0]);
|
||||
close(output_pipe[1]);
|
||||
|
||||
// Run
|
||||
safe_execvpe(command[0], command, environ);
|
||||
} else {
|
||||
// Parent Process
|
||||
|
||||
// Read stdout
|
||||
close(output_pipe[1]);
|
||||
char *output = NULL;
|
||||
char c;
|
||||
int bytes_read = 0;
|
||||
while ((bytes_read = read(output_pipe[0], (void *) &c, 1)) > 0) {
|
||||
string_append(&output, "%c", c);
|
||||
}
|
||||
close(output_pipe[0]);
|
||||
|
||||
// Get Return Code
|
||||
int status;
|
||||
waitpid(ret, &status, 0);
|
||||
*return_code = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
|
||||
|
||||
// Return
|
||||
return output;
|
||||
}
|
||||
}
|
||||
// Run Command And Set Environmental Variable
|
||||
static void run_command_and_set_env(const char *env_name, char *command[]) {
|
||||
static void run_command_and_set_env(const char *env_name, const char *command[]) {
|
||||
// Only Run If Environmental Variable Is NULL
|
||||
if (getenv(env_name) == NULL) {
|
||||
// Run
|
||||
|
@ -91,22 +93,28 @@ static void run_command_and_set_env(const char *env_name, char *command[]) {
|
|||
output[length - 1] = '\0';
|
||||
}
|
||||
// Set
|
||||
setenv(env_name, output, 1);
|
||||
set_and_print_env(env_name, output);
|
||||
// Free
|
||||
free(output);
|
||||
}
|
||||
// Check Return Code
|
||||
if (return_code != 0) {
|
||||
ERR("%s", "Launch Interrupted");
|
||||
if (!is_exit_status_success(return_code)) {
|
||||
// Launch Interrupted
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use Zenity To Set Environmental Variable
|
||||
#define DIALOG_TITLE "Launcher"
|
||||
static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
|
||||
// Create Full Command
|
||||
std::vector<std::string> full_command;
|
||||
full_command.push_back("zenity");
|
||||
full_command.push_back("--class");
|
||||
full_command.push_back("Minecraft - Pi edition");
|
||||
full_command.push_back("--title");
|
||||
full_command.push_back(DIALOG_TITLE);
|
||||
full_command.push_back("--name");
|
||||
full_command.push_back(MCPI_APP_ID);
|
||||
full_command.insert(full_command.end(), command.begin(), command.end());
|
||||
// Convert To C Array
|
||||
const char *full_command_array[full_command.size() + 1];
|
||||
|
@ -115,11 +123,32 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
|
|||
}
|
||||
full_command_array[full_command.size()] = NULL;
|
||||
// Run
|
||||
run_command_and_set_env(env_name, (char **) 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Launch
|
||||
#define LIST_DIALOG_SIZE "400"
|
||||
int main(int argc, char *argv[]) {
|
||||
// Don't Run As Root
|
||||
if (getenv("_MCPI_SKIP_ROOT_CHECK") == NULL && (getuid() == 0 || geteuid() == 0)) {
|
||||
ERR("Don't Run As Root");
|
||||
}
|
||||
|
||||
// Ensure HOME
|
||||
if (getenv("HOME") == NULL) {
|
||||
ERR("$HOME Isn't Set");
|
||||
}
|
||||
|
||||
// Print Features
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--print-available-feature-flags") == 0) {
|
||||
|
@ -132,52 +161,103 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap(argc, argv);
|
||||
|
||||
// Create ~/.minecraft-pi If Needed
|
||||
// Minecraft Folder
|
||||
{
|
||||
char *minecraft_folder = NULL;
|
||||
asprintf(&minecraft_folder, "%s/.minecraft-pi", getenv("HOME"));
|
||||
ALLOC_CHECK(minecraft_folder);
|
||||
{
|
||||
// Check Minecraft Folder
|
||||
struct stat obj;
|
||||
if (stat(minecraft_folder, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
|
||||
// Create Minecraft Folder
|
||||
int ret = mkdir(minecraft_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
if (ret != 0) {
|
||||
// Unable To Create Folder
|
||||
ERR("Error Creating Directory: %s: %s", minecraft_folder, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_asprintf(&minecraft_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA, getenv("HOME"));
|
||||
const char *const command[] = {"mkdir", "-p", minecraft_folder, NULL};
|
||||
run_simple_command(command, "Unable To Create Data Directory");
|
||||
free(minecraft_folder);
|
||||
}
|
||||
|
||||
// --wipe-cache
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--wipe-cache") == 0) {
|
||||
wipe_cache();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --no-cache
|
||||
bool no_cache = false;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--no-cache") == 0) {
|
||||
no_cache = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Load Cache
|
||||
launcher_cache cache = no_cache ? empty_cache : load_cache();
|
||||
|
||||
// --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", [&cache]() {
|
||||
std::string feature_flags = "";
|
||||
load_available_feature_flags([&feature_flags, &cache](std::string flag) {
|
||||
bool value;
|
||||
// Strip Default Value
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &value);
|
||||
// Use Cache
|
||||
if (cache.feature_flags.count(stripped_flag) > 0) {
|
||||
value = cache.feature_flags[stripped_flag];
|
||||
}
|
||||
// Specify Default Value
|
||||
if (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", [&cache]() {
|
||||
return cache.render_distance;
|
||||
});
|
||||
set_env_if_unset("MCPI_USERNAME", [&cache]() {
|
||||
return cache.username;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup MCPI_FEATURE_FLAGS
|
||||
{
|
||||
std::vector<std::string> command;
|
||||
command.push_back("--list");
|
||||
command.push_back("--checklist");
|
||||
command.push_back("--width");
|
||||
command.push_back("400");
|
||||
command.push_back(LIST_DIALOG_SIZE);
|
||||
command.push_back("--height");
|
||||
command.push_back("400");
|
||||
command.push_back(LIST_DIALOG_SIZE);
|
||||
command.push_back("--column");
|
||||
command.push_back("Enabled");
|
||||
command.push_back("--column");
|
||||
command.push_back("Feature");
|
||||
load_available_feature_flags([&command](std::string line) {
|
||||
if (line.rfind("TRUE ", 0) == 0) {
|
||||
load_available_feature_flags([&command, &cache](std::string flag) {
|
||||
bool value;
|
||||
// Strip Default Value
|
||||
std::string stripped_flag = strip_feature_flag_default(flag, &value);
|
||||
// Use Cache
|
||||
if (cache.feature_flags.count(stripped_flag) > 0) {
|
||||
value = cache.feature_flags[stripped_flag];
|
||||
}
|
||||
// Specify Default Value
|
||||
if (value) {
|
||||
// Enabled By Default
|
||||
command.push_back("TRUE");
|
||||
command.push_back(line.substr(5, std::string::npos));
|
||||
} else if (line.rfind("FALSE ", 0) == 0) {
|
||||
} else {
|
||||
// Disabled By Default
|
||||
command.push_back("FALSE");
|
||||
command.push_back(line.substr(6, std::string::npos));
|
||||
} else {
|
||||
ERR("%s", "Invalid Feature Flag Default");
|
||||
}
|
||||
// Specify Name
|
||||
command.push_back(stripped_flag);
|
||||
});
|
||||
// Run
|
||||
run_zenity_and_set_env("MCPI_FEATURE_FLAGS", command);
|
||||
|
@ -188,23 +268,20 @@ int main(int argc, char *argv[]) {
|
|||
command.push_back("--list");
|
||||
command.push_back("--radiolist");
|
||||
command.push_back("--width");
|
||||
command.push_back("400");
|
||||
command.push_back(LIST_DIALOG_SIZE);
|
||||
command.push_back("--height");
|
||||
command.push_back("400");
|
||||
command.push_back(LIST_DIALOG_SIZE);
|
||||
command.push_back("--text");
|
||||
command.push_back("Minecraft Render Distance:");
|
||||
command.push_back("Select Minecraft Render Distance:");
|
||||
command.push_back("--column");
|
||||
command.push_back("Selected");
|
||||
command.push_back("--column");
|
||||
command.push_back("Name");
|
||||
command.push_back("FALSE");
|
||||
command.push_back("Far");
|
||||
command.push_back("FALSE");
|
||||
command.push_back("Normal");
|
||||
command.push_back("TRUE");
|
||||
command.push_back("Short");
|
||||
command.push_back("FALSE");
|
||||
command.push_back("Tiny");
|
||||
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
|
||||
for (std::string &render_distance : render_distances) {
|
||||
command.push_back(render_distance.compare(cache.render_distance) == 0 ? "TRUE" : "FALSE");
|
||||
command.push_back(render_distance);
|
||||
}
|
||||
// Run
|
||||
run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command);
|
||||
}
|
||||
|
@ -213,13 +290,18 @@ int main(int argc, char *argv[]) {
|
|||
std::vector<std::string> command;
|
||||
command.push_back("--entry");
|
||||
command.push_back("--text");
|
||||
command.push_back("Minecraft Username:");
|
||||
command.push_back("Enter Minecraft Username:");
|
||||
command.push_back("--entry-text");
|
||||
command.push_back("StevePi");
|
||||
command.push_back(cache.username);
|
||||
// Run
|
||||
run_zenity_and_set_env("MCPI_USERNAME", command);
|
||||
}
|
||||
|
||||
// Save Cache
|
||||
if (!no_cache) {
|
||||
save_cache();
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
bootstrap(argc, argv);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
// Defaults
|
||||
#define DEFAULT_USERNAME "StevePi"
|
||||
#define DEFAULT_RENDER_DISTANCE "Short"
|
||||
|
||||
// Feature Flags
|
||||
std::string strip_feature_flag_default(std::string flag, bool *default_ret);
|
||||
void load_available_feature_flags(std::function<void(std::string)> callback);
|
|
@ -0,0 +1,260 @@
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "crash-report.h"
|
||||
|
||||
// Show Crash Report Dialog
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#define DIALOG_TITLE "Crash Report"
|
||||
#define CRASH_REPORT_DIALOG_WIDTH "640"
|
||||
#define CRASH_REPORT_DIALOG_HEIGHT "480"
|
||||
static void show_report(const char *log_filename) {
|
||||
// Fork
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// Child
|
||||
setsid();
|
||||
ALLOC_CHECK(freopen("/dev/null", "w", stdout));
|
||||
ALLOC_CHECK(freopen("/dev/null", "w", stderr));
|
||||
ALLOC_CHECK(freopen("/dev/null", "r", stdin));
|
||||
const char *command[] = {
|
||||
"zenity",
|
||||
"--title", DIALOG_TITLE,
|
||||
"--name", MCPI_APP_ID,
|
||||
"--width", CRASH_REPORT_DIALOG_WIDTH,
|
||||
"--height", CRASH_REPORT_DIALOG_HEIGHT,
|
||||
"--text-info",
|
||||
"--text", MCPI_APP_BASE_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_BASE_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
|
||||
"--filename", log_filename,
|
||||
"--no-wrap",
|
||||
"--font", "Monospace",
|
||||
"--save-filename", MCPI_VARIANT_NAME "-crash-report.log",
|
||||
"--ok-label", "Exit",
|
||||
NULL
|
||||
};
|
||||
safe_execvpe(command, (const char *const *) environ);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exit Handler
|
||||
static void exit_handler(__attribute__((unused)) int signal) {
|
||||
// Murder
|
||||
murder_children();
|
||||
}
|
||||
|
||||
// Setup
|
||||
#define PIPE_READ 0
|
||||
#define PIPE_WRITE 1
|
||||
#define MCPI_LOGS_DIR "/tmp/.minecraft-pi-logs"
|
||||
static char log_filename[] = MCPI_LOGS_DIR "/XXXXXX";
|
||||
static int log_file_fd = -1;
|
||||
void setup_log_file() {
|
||||
// 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
|
||||
log_file_fd = mkstemp(log_filename);
|
||||
if (log_file_fd == -1) {
|
||||
ERR("Unable To Create Log File: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Setup Environment
|
||||
char *log_file_fd_env = NULL;
|
||||
safe_asprintf(&log_file_fd_env, "%i", log_file_fd);
|
||||
set_and_print_env("MCPI_LOG_FILE_FD", log_file_fd_env);
|
||||
free(log_file_fd_env);
|
||||
}
|
||||
void setup_crash_report() {
|
||||
// Store Output
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
int error_pipe[2];
|
||||
safe_pipe2(error_pipe, 0);
|
||||
int input_pipe[2];
|
||||
safe_pipe2(input_pipe, 0);
|
||||
|
||||
// Fork
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Fork: %s", strerror(errno));
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Pipe stdio
|
||||
dup2(output_pipe[PIPE_WRITE], STDOUT_FILENO);
|
||||
close(output_pipe[PIPE_READ]);
|
||||
close(output_pipe[PIPE_WRITE]);
|
||||
dup2(error_pipe[PIPE_WRITE], STDERR_FILENO);
|
||||
close(error_pipe[PIPE_READ]);
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
dup2(input_pipe[PIPE_READ], STDIN_FILENO);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
close(input_pipe[PIPE_WRITE]);
|
||||
|
||||
// Create New Process Group
|
||||
setpgid(0, 0);
|
||||
|
||||
// Continue Execution
|
||||
} else {
|
||||
// Parent Process
|
||||
track_child(ret);
|
||||
|
||||
// Install Signal Handlers
|
||||
struct sigaction act_sigint;
|
||||
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, NULL);
|
||||
struct sigaction act_sigterm;
|
||||
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, NULL);
|
||||
atexit(murder_children);
|
||||
|
||||
// Close Unneeded File Descriptors
|
||||
close(output_pipe[PIPE_WRITE]);
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Crash Reporter) ";
|
||||
|
||||
// Setup Logging
|
||||
#define BUFFER_SIZE 1024
|
||||
char buf[BUFFER_SIZE];
|
||||
|
||||
// Setup Polling
|
||||
int number_fds = 3;
|
||||
struct pollfd poll_fds[number_fds];
|
||||
poll_fds[0].fd = output_pipe[PIPE_READ];
|
||||
poll_fds[1].fd = error_pipe[PIPE_READ];
|
||||
poll_fds[2].fd = STDIN_FILENO;
|
||||
for (int i = 0; i < number_fds; i++) {
|
||||
poll_fds[i].events = POLLIN;
|
||||
}
|
||||
|
||||
// Poll Data
|
||||
int status;
|
||||
while (waitpid(ret, &status, WNOHANG) != ret) {
|
||||
int poll_ret = poll(poll_fds, number_fds, -1);
|
||||
if (poll_ret == -1) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
ERR("Unable To Poll Data: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Data
|
||||
for (int i = 0; i < number_fds; i++) {
|
||||
if (poll_fds[i].revents != 0) {
|
||||
if (poll_fds[i].revents & POLLIN) {
|
||||
if (poll_fds[i].fd == STDIN_FILENO) {
|
||||
// Data Available From stdin
|
||||
int bytes_available;
|
||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
}
|
||||
// Read
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
// Write To Child
|
||||
if (write(input_pipe[PIPE_WRITE], (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Input To Child: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
// Data Available From Child's stdout/stderr
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Print To Terminal
|
||||
buf[bytes_read] = '\0';
|
||||
fprintf(poll_fds[i].fd == output_pipe[PIPE_READ] ? stdout : stderr, "%s", buf);
|
||||
|
||||
// Write To log
|
||||
if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Log Data: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// File Descriptor No Longer Accessible
|
||||
poll_fds[i].events = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Untrack Process
|
||||
untrack_child(ret);
|
||||
|
||||
// Close Pipes
|
||||
close(output_pipe[PIPE_READ]);
|
||||
close(error_pipe[PIPE_READ]);
|
||||
close(input_pipe[PIPE_WRITE]);
|
||||
|
||||
// Check If Is Crash
|
||||
int is_crash = !is_exit_status_success(status);
|
||||
|
||||
// Log Exit Code To log If Crash
|
||||
if (is_crash) {
|
||||
// Create Exit Code Log Line
|
||||
char *exit_status = NULL;
|
||||
get_exit_status_string(status, &exit_status);
|
||||
char *exit_code_line = NULL;
|
||||
safe_asprintf(&exit_code_line, "[CRASH]: Terminated%s\n", exit_status);
|
||||
free(exit_status);
|
||||
|
||||
// Print Exit Code Log Line
|
||||
fprintf(stderr, "%s", exit_code_line);
|
||||
|
||||
// Write Exit Code Log Line
|
||||
if (write(log_file_fd, (void *) exit_code_line, strlen(exit_code_line)) == -1) {
|
||||
ERR("Unable To Write Exit Code To Log: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Free Exit Code Log Line
|
||||
free(exit_code_line);
|
||||
}
|
||||
|
||||
// Close Log File FD
|
||||
if (close(log_file_fd) == -1) {
|
||||
ERR("Unable To Close Log File Descriptor: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Show Crash Log
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (is_crash) {
|
||||
show_report(log_filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exit
|
||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
char *get_full_library_search_path(); // Remember To free()
|
||||
void setup_log_file();
|
||||
void setup_crash_report();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "ldconfig.h"
|
||||
|
||||
char *get_full_library_search_path() {
|
||||
std::string output;
|
||||
// Run
|
||||
FILE *file = popen("ldconfig -NXv 2> /dev/null", "r");
|
||||
// Read
|
||||
int running = 1;
|
||||
while (running) {
|
||||
char *line = NULL;
|
||||
size_t length = 0;
|
||||
if (getline(&line, &length, file) != -1) {
|
||||
// Convert to C++ String
|
||||
std::string str(line);
|
||||
// Remove Newline
|
||||
if (str.size() > 0 && str[str.size() - 1] == '\n') {
|
||||
str.pop_back();
|
||||
}
|
||||
// Interpret
|
||||
if (str.size() >= 2 && str[0] != '\t' && str[str.size() - 1] == ':') {
|
||||
output.append(str);
|
||||
}
|
||||
} else {
|
||||
running = 0;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
// Remove Colon
|
||||
if (output.size() > 0 && output[output.size() - 1] == ':') {
|
||||
output.pop_back();
|
||||
}
|
||||
// Close Process
|
||||
pclose(file);
|
||||
// Return
|
||||
char *output_str = strdup(output.c_str());
|
||||
ALLOC_CHECK(output_str);
|
||||
return output_str;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#include <cstdlib>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <LIEF/ELF.hpp>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "patchelf.h"
|
||||
|
||||
// Duplicate MCPI Executable Into /tmp
|
||||
static void duplicate_mcpi_executable(char *new_path) {
|
||||
// Ensure Temporary Directory
|
||||
{
|
||||
// Check If It Exists
|
||||
struct stat tmp_stat;
|
||||
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
|
||||
if (!exists) {
|
||||
// Doesn't Exist
|
||||
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate New File
|
||||
int new_file_fd = mkstemp(new_path);
|
||||
if (new_file_fd == -1) {
|
||||
ERR("Unable To Create Temporary File: %s", strerror(errno));
|
||||
}
|
||||
close(new_file_fd);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
static const char *libraries_to_remove[] = {
|
||||
"libbcm_host.so",
|
||||
"libX11.so.6",
|
||||
"libEGL.so",
|
||||
"libGLESv2.so",
|
||||
"libSDL-1.2.so.0"
|
||||
};
|
||||
static const char *libraries_to_add[] = {
|
||||
"libmedia-layer-core.so"
|
||||
};
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
|
||||
// Duplicate MCPI executable into /tmp so it can be modified.
|
||||
duplicate_mcpi_executable(new_path);
|
||||
|
||||
// Patch File
|
||||
{
|
||||
std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
|
||||
if (linker != NULL) {
|
||||
binary->interpreter(linker);
|
||||
}
|
||||
for (size_t i = 0; i < (sizeof (libraries_to_remove) / sizeof (const char *)); i++) {
|
||||
binary->remove_library(libraries_to_remove[i]);
|
||||
}
|
||||
for (size_t i = 0; i < (sizeof (libraries_to_add) / sizeof (const char *)); i++) {
|
||||
binary->add_library(libraries_to_add[i]);
|
||||
}
|
||||
LIEF::ELF::Builder builder{*binary};
|
||||
builder.build();
|
||||
builder.write(new_path);
|
||||
}
|
||||
|
||||
// Fix Permissions
|
||||
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Get Interpreter
|
||||
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
|
||||
// Only Search Current Program
|
||||
if (strcmp(info->dlpi_name, "") == 0) {
|
||||
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||
if (info->dlpi_phdr[i].p_type == PT_INTERP) {
|
||||
// Callback
|
||||
*(char **) data = (char *) (info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
char *patch_get_interpreter() {
|
||||
char *interpreter = NULL;
|
||||
dl_iterate_phdr(dl_iterate_callback, &interpreter);
|
||||
if (interpreter != NULL) {
|
||||
interpreter = strdup(interpreter);
|
||||
}
|
||||
return interpreter;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
|
||||
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker);
|
||||
char *patch_get_interpreter();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,6 +1,19 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../bootstrap.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap(argc, argv);
|
||||
|
||||
// Set Home To Current Directory, So World Data Is Stored There
|
||||
char *launch_directory = getcwd(NULL, 0);
|
||||
set_and_print_env("HOME", launch_directory);
|
||||
free(launch_directory);
|
||||
|
||||
// Bootstrap
|
||||
bootstrap(argc, argv);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,34 @@
|
|||
project(libreborn)
|
||||
|
||||
add_library(reborn-headers INTERFACE)
|
||||
target_include_directories(reborn-headers INTERFACE include)
|
||||
# Config
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn")
|
||||
configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
|
||||
|
||||
# Util
|
||||
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.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)
|
||||
add_library(reborn SHARED src/libreborn.c)
|
||||
target_link_libraries(reborn dl reborn-headers)
|
||||
# Install
|
||||
install(TARGETS reborn DESTINATION "${MCPI_LIB_DIR}")
|
||||
install(TARGETS reborn-util EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
|
||||
endif()
|
||||
|
||||
# Patch
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_library(reborn-patch SHARED src/patch/patch.c)
|
||||
target_link_libraries(reborn-patch dl pthread reborn-util)
|
||||
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
|
||||
# Install
|
||||
install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}")
|
||||
# SDK
|
||||
install(TARGETS reborn-patch EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#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_BASE_TITLE "@MCPI_APP_BASE_TITLE@"
|
||||
#cmakedefine MCPI_APP_TITLE "@MCPI_APP_TITLE@"
|
||||
#cmakedefine MCPI_APP_ID "@MCPI_APP_ID@"
|
||||
#cmakedefine MCPI_VERSION "@MCPI_VERSION@"
|
||||
#cmakedefine MCPI_VARIANT_NAME "@MCPI_VARIANT_NAME@"
|
||||
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"
|
|
@ -1,67 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __arm__
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "exec.h"
|
||||
|
||||
// Find And Iterate Over All .text Sections In Current Binary
|
||||
typedef void (*text_section_callback_t)(void *section, Elf32_Word size, void *data);
|
||||
static inline void iterate_text_sections(text_section_callback_t callback, void *data) {
|
||||
// Load Main Binary
|
||||
char *real_path = realpath("/proc/self/exe", NULL);
|
||||
FILE *file_obj = fopen(real_path, "rb");
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Verify Binary
|
||||
if (!file_obj) {
|
||||
ERR("Unable To Open Binary: %s", real_path);
|
||||
}
|
||||
// Find And Iterate Over All Segments In Current Binary
|
||||
typedef void (*segment_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
|
||||
void iterate_segments(segment_callback_t callback, void *data);
|
||||
|
||||
// Get File Size
|
||||
fseek(file_obj, 0L, SEEK_END);
|
||||
long int size = ftell(file_obj);
|
||||
fseek(file_obj, 0L, SEEK_SET);
|
||||
|
||||
// Map File To Pointer
|
||||
unsigned char *file_map = (unsigned char *) mmap(0, size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
|
||||
|
||||
// Parse ELF
|
||||
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map;
|
||||
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff);
|
||||
int elf_section_header_count = elf_header->e_shnum;
|
||||
|
||||
// Locate Section Names
|
||||
Elf32_Shdr elf_strtab = elf_section_headers[elf_header->e_shstrndx];
|
||||
unsigned char *elf_strtab_p = file_map + elf_strtab.sh_offset;
|
||||
|
||||
// Track .text Sections
|
||||
int text_sections = 0;
|
||||
|
||||
// Iterate Sections
|
||||
for (int i = 0; i < elf_section_header_count; ++i) {
|
||||
Elf32_Shdr header = elf_section_headers[i];
|
||||
char *name = (char *) (elf_strtab_p + header.sh_name);
|
||||
// Check Section Type
|
||||
if (strcmp(name, ".text") == 0) {
|
||||
// .text Section
|
||||
(*callback)((void *) header.sh_addr, header.sh_size, data);
|
||||
text_sections++;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure At Least .text Section Was Scanned
|
||||
if (text_sections < 1) {
|
||||
ERR("Unable To Find .text Sectons On: %s", real_path);
|
||||
}
|
||||
|
||||
// Free Binary Path
|
||||
free(real_path);
|
||||
|
||||
// Unmap And Close File
|
||||
munmap(file_map, size);
|
||||
fclose(file_obj);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // #ifdef __arm__
|
||||
#endif
|
||||
|
|
|
@ -3,69 +3,50 @@
|
|||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "string.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Set Environmental Variable
|
||||
void set_and_print_env(const char *name, const char *value);
|
||||
|
||||
// Safe execvpe()
|
||||
__attribute__((noreturn)) static inline void safe_execvpe(const char *pathname, char *argv[], char *const envp[]) {
|
||||
argv[0] = (char *) pathname;
|
||||
int ret = execvpe(pathname, argv, envp);
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Execute Program: %s: %s", pathname, strerror(errno));
|
||||
} else {
|
||||
ERR("%s", "Unknown execvpe() Error");
|
||||
}
|
||||
}
|
||||
#define for_each_special_environmental_variable(handle) \
|
||||
handle("LD_LIBRARY_PATH"); \
|
||||
handle("GCONV_PATH"); \
|
||||
handle("LD_PRELOAD");
|
||||
void setup_exec_environment(int is_arm_component);
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
|
||||
|
||||
// Chop Off Last Component
|
||||
void chop_last_component(char **str);
|
||||
// Get Binary Directory (Remember To Free)
|
||||
#define EXE_PATH "/proc/self/exe"
|
||||
static inline char *get_binary_directory() {
|
||||
// Get Path To Current Executable
|
||||
// Get Symlink Path Size
|
||||
struct stat sb;
|
||||
if (lstat(EXE_PATH, &sb) == -1) {
|
||||
ERR("Unable To Get " EXE_PATH " Symlink Size: %s", strerror(errno));
|
||||
}
|
||||
ssize_t path_size = sb.st_size + 1;
|
||||
if (sb.st_size == 0) {
|
||||
path_size = PATH_MAX;
|
||||
}
|
||||
char *exe = (char *) malloc(path_size);
|
||||
ALLOC_CHECK(exe);
|
||||
// Read Link
|
||||
ssize_t r = readlink(EXE_PATH, exe, path_size);
|
||||
if (r < 0) {
|
||||
ERR("Unable To Read " EXE_PATH " Symlink: %s", strerror(errno));
|
||||
}
|
||||
if (r > path_size) {
|
||||
ERR("%s", "Size Of Symlink " EXE_PATH " Changed");
|
||||
}
|
||||
exe[path_size] = '\0';
|
||||
char *get_binary_directory();
|
||||
|
||||
// Chop Off Last Component
|
||||
for (int i = path_size - 1; i >= 0; i--) {
|
||||
if (exe[i] == '/') {
|
||||
exe[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Debug Tag
|
||||
#define CHILD_PROCESS_TAG "(Child Process) "
|
||||
|
||||
// Return
|
||||
return exe;
|
||||
}
|
||||
// Safe execvpe() Relative To Binary
|
||||
__attribute__((noreturn)) static inline void safe_execvpe_relative_to_binary(const char *pathname, char *argv[], 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, pathname);
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
// Run
|
||||
safe_execvpe(full_path, argv, envp);
|
||||
// Run Command And Get Output
|
||||
char *run_command(const char *const command[], int *exit_status);
|
||||
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||
|
||||
// Get Exit Status String
|
||||
void get_exit_status_string(int status, char **out);
|
||||
|
||||
// Track Children
|
||||
void track_child(pid_t pid);
|
||||
void untrack_child(pid_t pid);
|
||||
void murder_children();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
// Minecraft Pi Game Data Root
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
// Store Game Data In "~/.minecraft-pi" Instead Of "~/.minecraft" To Avoid Conflicts
|
||||
#define HOME_SUBDIRECTORY_FOR_GAME_DATA "/.minecraft-pi"
|
||||
#else
|
||||
// Store Game Data In $HOME Root (In Server Mode, $HOME Is Changed To The Launch Directory)
|
||||
#define HOME_SUBDIRECTORY_FOR_GAME_DATA ""
|
||||
#endif
|
|
@ -1,36 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libreborn/config.h>
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "string.h"
|
||||
#include "exec.h"
|
||||
#include "elf.h"
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
// Patching Functions
|
||||
|
||||
void _overwrite_call(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);
|
||||
|
||||
void _overwrite_calls(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_calls(start, target) _overwrite_calls(__FILE__, __LINE__, start, target);
|
||||
|
||||
void _overwrite(const char *file, int line, void *start, void *target);
|
||||
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);
|
||||
|
||||
void _patch(const char *file, int line, void *start, unsigned char patch[]);
|
||||
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch);
|
||||
|
||||
void _patch_address(const char *file, int line, void *start, void *target);
|
||||
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, start, target);
|
||||
|
||||
#endif // #ifdef __arm__
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include "home.h"
|
||||
#include "patch.h"
|
||||
|
|
|
@ -3,7 +3,22 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Debug
|
||||
extern const char *reborn_debug_tag;
|
||||
int reborn_get_debug_fd();
|
||||
|
||||
// Logging
|
||||
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", __VA_ARGS__); }
|
||||
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", __VA_ARGS__); }
|
||||
#define ERR(format, ...) { fprintf(stderr, "[ERR]: " format "\n", __VA_ARGS__); exit(EXIT_FAILURE); }
|
||||
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
|
||||
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
|
||||
#define RAW_DEBUG(tag, format, ...) { int debug_fd = reborn_get_debug_fd(); if (debug_fd != -1) { dprintf(debug_fd, "[DEBUG]: %s" format "\n", tag, ##__VA_ARGS__); } }
|
||||
#define DEBUG(format, ...) RAW_DEBUG(reborn_debug_tag, format, ##__VA_ARGS__)
|
||||
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
|
||||
#define IMPOSSIBLE() ERR("This Should Never Be Called")
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,456 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
|
||||
// bool In C
|
||||
#ifndef __cplusplus
|
||||
typedef uint32_t bool;
|
||||
#endif
|
||||
|
||||
// Globals
|
||||
|
||||
static char **default_path = (char **) 0xe264; // /.minecraft/
|
||||
static char **default_username = (char **) 0x18fd4; // StevePi
|
||||
|
||||
static unsigned char **Item_flintAndSteel = (unsigned char **) 0x17ba70;
|
||||
static unsigned char **Item_snowball = (unsigned char **) 0x17bbb0;
|
||||
static unsigned char **Item_shears = (unsigned char **) 0x17bbf0;
|
||||
static unsigned char **Item_egg = (unsigned char **) 0x17bbd0;
|
||||
static unsigned char **Item_dye_powder = (unsigned char **) 0x17bbe0;
|
||||
static unsigned char **Item_camera = (unsigned char **) 0x17bc14;
|
||||
|
||||
static unsigned char **Tile_water = (unsigned char **) 0x181b3c;
|
||||
static unsigned char **Tile_lava = (unsigned char **) 0x181cc8;
|
||||
static unsigned char **Tile_calmWater = (unsigned char **) 0x181b40;
|
||||
static unsigned char **Tile_calmLava = (unsigned char **) 0x181ccc;
|
||||
static unsigned char **Tile_glowingObsidian = (unsigned char **) 0x181dcc;
|
||||
static unsigned char **Tile_web = (unsigned char **) 0x181d08;
|
||||
static unsigned char **Tile_topSnow = (unsigned char **) 0x181b30;
|
||||
static unsigned char **Tile_ice = (unsigned char **) 0x181d80;
|
||||
static unsigned char **Tile_invisible_bedrock = (unsigned char **) 0x181d94;
|
||||
|
||||
static unsigned char **Tile_leaves = (unsigned char **) 0x18120c;
|
||||
static unsigned char **Tile_leaves_carried = (unsigned char **) 0x181dd8;
|
||||
static unsigned char **Tile_grass = (unsigned char **) 0x181b14;
|
||||
static unsigned char **Tile_grass_carried = (unsigned char **) 0x181dd4;
|
||||
|
||||
static float *InvGuiScale = (float *) 0x135d98;
|
||||
|
||||
// Tile
|
||||
|
||||
static uint32_t Tile_id_property_offset = 0x8;
|
||||
|
||||
// Structures
|
||||
|
||||
struct LevelSettings {
|
||||
unsigned long seed;
|
||||
int32_t game_type;
|
||||
};
|
||||
|
||||
struct RakNet_RakNetGUID {
|
||||
unsigned char data[10];
|
||||
};
|
||||
struct RakNet_SystemAddress {
|
||||
unsigned char data[20];
|
||||
};
|
||||
|
||||
// GameMode
|
||||
|
||||
typedef void (*GameMode_releaseUsingItem_t)(unsigned char *game_mode, unsigned char *player);
|
||||
static uint32_t GameMode_releaseUsingItem_vtable_offset = 0x5c;
|
||||
|
||||
// Minecraft
|
||||
|
||||
typedef void (*Minecraft_init_t)(unsigned char *minecraft);
|
||||
static Minecraft_init_t Minecraft_init = (Minecraft_init_t) 0x1700c;
|
||||
|
||||
typedef void (*Minecraft_tickInput_t)(unsigned char *minecraft);
|
||||
static Minecraft_tickInput_t Minecraft_tickInput = (Minecraft_tickInput_t) 0x15ffc;
|
||||
|
||||
typedef void (*Minecraft_setIsCreativeMode_t)(unsigned char *, int32_t);
|
||||
static Minecraft_setIsCreativeMode_t Minecraft_setIsCreativeMode = (Minecraft_setIsCreativeMode_t) 0x16ec4;
|
||||
|
||||
typedef int32_t (*Minecraft_isTouchscreen_t)(unsigned char *minecraft);
|
||||
static Minecraft_isTouchscreen_t Minecraft_isTouchscreen = (Minecraft_isTouchscreen_t) 0x1639c;
|
||||
|
||||
typedef void (*Minecraft_setScreen_t)(unsigned char *minecraft, unsigned char *screen);
|
||||
static Minecraft_setScreen_t Minecraft_setScreen = (Minecraft_setScreen_t) 0x15d6c;
|
||||
|
||||
typedef void (*Minecraft_tick_t)(unsigned char *minecraft, int32_t param_1, int32_t param_2);
|
||||
static Minecraft_tick_t Minecraft_tick = (Minecraft_tick_t) 0x16934;
|
||||
|
||||
typedef void (*Minecraft_update_t)(unsigned char *minecraft);
|
||||
static Minecraft_update_t Minecraft_update = (Minecraft_update_t) 0x16b74;
|
||||
|
||||
typedef void (*Minecraft_hostMultiplayer_t)(unsigned char *minecraft, int32_t port);
|
||||
static Minecraft_hostMultiplayer_t Minecraft_hostMultiplayer = (Minecraft_hostMultiplayer_t) 0x16664;
|
||||
|
||||
typedef const char *(*Minecraft_getProgressMessage_t)(unsigned char *minecraft);
|
||||
static Minecraft_getProgressMessage_t Minecraft_getProgressMessage = (Minecraft_getProgressMessage_t) 0x16e58;
|
||||
|
||||
typedef uint32_t (*Minecraft_isLevelGenerated_t)(unsigned char *minecraft);
|
||||
static Minecraft_isLevelGenerated_t Minecraft_isLevelGenerated = (Minecraft_isLevelGenerated_t) 0x16e6c;
|
||||
|
||||
typedef bool (*Minecraft_isCreativeMode_t)(unsigned char *minecraft);
|
||||
static Minecraft_isCreativeMode_t Minecraft_isCreativeMode = (Minecraft_isCreativeMode_t) 0x17270;
|
||||
|
||||
typedef void (*Minecraft_releaseMouse_t)(unsigned char *minecraft);
|
||||
static Minecraft_releaseMouse_t Minecraft_releaseMouse = (Minecraft_releaseMouse_t) 0x15d30;
|
||||
|
||||
typedef void (*Minecraft_grabMouse_t)(unsigned char *minecraft);
|
||||
static Minecraft_grabMouse_t Minecraft_grabMouse = (Minecraft_grabMouse_t) 0x15d10;
|
||||
|
||||
typedef void (*Minecraft_leaveGame_t)(unsigned char *minecraft, bool save_remote_level);
|
||||
static Minecraft_leaveGame_t Minecraft_leaveGame = (Minecraft_leaveGame_t) 0x15ea0;
|
||||
|
||||
static uint32_t Minecraft_screen_width_property_offset = 0x20; // int32_t
|
||||
static uint32_t Minecraft_network_handler_property_offset = 0x174; // NetEventCallback *
|
||||
static uint32_t Minecraft_rak_net_instance_property_offset = 0x170; // RakNetInstance *
|
||||
static uint32_t Minecraft_level_property_offset = 0x188; // Level *
|
||||
static uint32_t Minecraft_textures_property_offset = 0x164; // Textures *
|
||||
static uint32_t Minecraft_game_mode_property_offset = 0x160; // GameMode *
|
||||
static uint32_t Minecraft_player_property_offset = 0x18c; // LocalPlayer *
|
||||
static uint32_t Minecraft_options_property_offset = 0x3c; // Options
|
||||
static uint32_t Minecraft_hit_result_property_offset = 0xc38; // HitResult
|
||||
static uint32_t Minecraft_progress_property_offset = 0xc60; // int32_t
|
||||
static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServer *
|
||||
static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen *
|
||||
static uint32_t Minecraft_gui_property_offset = 0x198; // Gui
|
||||
|
||||
// CommandServer
|
||||
|
||||
static uint32_t CommandServer_minecraft_property_offset = 0x18; // Minecraft *
|
||||
|
||||
// ServerLevel
|
||||
|
||||
#define SERVER_LEVEL_SIZE 0xb80
|
||||
|
||||
// Packet
|
||||
|
||||
typedef void (*Packet_read_t)(unsigned char *packet, unsigned char *bit_stream);
|
||||
|
||||
// LoginPacket
|
||||
|
||||
static Packet_read_t LoginPacket_read = (Packet_read_t) 0x6e5f8;
|
||||
static void *LoginPacket_read_vtable_addr = (void *) 0x108dcc;
|
||||
|
||||
static uint32_t LoginPacket_username_property_offset = 0xc; // RakString
|
||||
|
||||
// ChatPacket
|
||||
|
||||
static uint32_t ChatPacket_message_property_offset = 0xc; // char *
|
||||
|
||||
// HitResult
|
||||
|
||||
static uint32_t HitResult_type_property_offset = 0x0;
|
||||
|
||||
// Options
|
||||
|
||||
static uint32_t Options_fancy_graphics_property_offset = 0x17; // unsigned char / bool
|
||||
static uint32_t Options_split_controls_property_offset = 0x105; // int32_t
|
||||
static uint32_t Options_peaceful_mode_property_offset = 0xe8; // unsigned char / bool
|
||||
static uint32_t Options_3d_anaglyph_property_offset = 0x15; // unsigned char / bool
|
||||
static uint32_t Options_ambient_occlusion_property_offset = 0x18; // unsigned char / bool
|
||||
static uint32_t Options_hide_gui_property_offset = 0xec; // unsigned char / bool
|
||||
static uint32_t Options_third_person_property_offset = 0xed; // unsigned char / bool
|
||||
static uint32_t Options_render_distance_property_offset = 0x10; // int32_t
|
||||
|
||||
// MouseBuildInput
|
||||
|
||||
typedef int32_t (*MouseBuildInput_tickBuild_t)(unsigned char *mouse_build_input, unsigned char *player, uint32_t *build_action_intention_return);
|
||||
static MouseBuildInput_tickBuild_t MouseBuildInput_tickBuild = (MouseBuildInput_tickBuild_t) 0x17c98;
|
||||
static void *MouseBuildInput_tickBuild_vtable_addr = (void *) 0x102564;
|
||||
|
||||
// Player
|
||||
|
||||
typedef int (*Player_isUsingItem_t)(unsigned char *player);
|
||||
static Player_isUsingItem_t Player_isUsingItem = (Player_isUsingItem_t) 0x8f15c;
|
||||
|
||||
static uint32_t Player_username_property_offset = 0xbf4; // char *
|
||||
|
||||
// Entity
|
||||
|
||||
typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
|
||||
static uint32_t Entity_die_vtable_offset = 0x130;
|
||||
|
||||
// Mob
|
||||
|
||||
typedef void (*Mob_actuallyHurt_t)(unsigned char *entity, int32_t damage);
|
||||
static Mob_actuallyHurt_t Mob_actuallyHurt = (Mob_actuallyHurt_t) 0x7f11c;
|
||||
|
||||
static uint32_t Mob_health_property_offset = 0xec; // int32_t
|
||||
|
||||
// LocalPlayer
|
||||
|
||||
static Mob_actuallyHurt_t LocalPlayer_actuallyHurt = (Mob_actuallyHurt_t) 0x44010;
|
||||
static void *LocalPlayer_actuallyHurt_vtable_addr = (void *) 0x10639c;
|
||||
|
||||
static void *LocalPlayer_openTextEdit_vtable_addr = (void *) 0x106460;
|
||||
|
||||
static uint32_t LocalPlayer_minecraft_property_offset = 0xc90; // Minecraft *
|
||||
|
||||
// ServerPlayer
|
||||
|
||||
static void *ServerPlayer_actuallyHurt_vtable_addr = (void *) 0x109fa4;
|
||||
|
||||
static uint32_t ServerPlayer_minecraft_property_offset = 0xc8c; // Minecraft *
|
||||
static uint32_t ServerPlayer_guid_property_offset = 0xc08; // RakNetGUID
|
||||
|
||||
// Gui
|
||||
|
||||
typedef void (*Gui_tick_t)(unsigned char *gui);
|
||||
static Gui_tick_t Gui_tick = (Gui_tick_t) 0x27778;
|
||||
|
||||
typedef void (*Gui_handleClick_t)(unsigned char *gui, int32_t param_2, int32_t param_3, int32_t param_4);
|
||||
static Gui_handleClick_t Gui_handleClick = (Gui_handleClick_t) 0x2599c;
|
||||
|
||||
typedef void (*Gui_renderOnSelectItemNameText_t)(unsigned char *gui, int32_t param_1, unsigned char *font, int32_t param_2);
|
||||
static Gui_renderOnSelectItemNameText_t Gui_renderOnSelectItemNameText = (Gui_renderOnSelectItemNameText_t) 0x26aec;
|
||||
|
||||
typedef void (*Gui_renderChatMessages_t)(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font);
|
||||
static Gui_renderChatMessages_t Gui_renderChatMessages = (Gui_renderChatMessages_t) 0x273d8;
|
||||
|
||||
static uint32_t Gui_minecraft_property_offset = 0x9f4; // Minecraft *
|
||||
static uint32_t Gui_selected_item_text_timer_property_offset = 0x9fc; // float
|
||||
|
||||
// Textures
|
||||
|
||||
typedef void (*Textures_tick_t)(unsigned char *textures, bool param_1);
|
||||
static Textures_tick_t Textures_tick = (Textures_tick_t) 0x531c4;
|
||||
|
||||
// GameMode Constructors
|
||||
|
||||
#define CREATOR_MODE_SIZE 0x18
|
||||
static void *CreatorMode = (void *) 0x1a044;
|
||||
#define SURVIVAL_MODE_SIZE 0x24
|
||||
static void *SurvivalMode = (void *) 0x1b7d8;
|
||||
|
||||
// LevelData
|
||||
|
||||
typedef uint32_t (*LevelData_getSpawnMobs_t)(unsigned char *level_data);
|
||||
static LevelData_getSpawnMobs_t LevelData_getSpawnMobs = (LevelData_getSpawnMobs_t) 0xbabec;
|
||||
|
||||
// Level
|
||||
|
||||
typedef void (*Level_saveLevelData_t)(unsigned char *level);
|
||||
static Level_saveLevelData_t Level_saveLevelData = (Level_saveLevelData_t) 0xa2e94;
|
||||
|
||||
static uint32_t Level_players_property_offset = 0x60; // std::vector<ServerPlayer *>
|
||||
|
||||
// TextEditScreen
|
||||
|
||||
#define TEXT_EDIT_SCREEN_SIZE 0xd0
|
||||
|
||||
typedef unsigned char *(*TextEditScreen_t)(unsigned char *text_edit_screen, unsigned char *sign);
|
||||
static TextEditScreen_t TextEditScreen = (TextEditScreen_t) 0x3a840;
|
||||
|
||||
static void *TextEditScreen_updateEvents_vtable_addr = (void *) 0x10531c;
|
||||
|
||||
// ProgressScreen
|
||||
|
||||
#define PROGRESS_SCREEN_SIZE 0x4c
|
||||
|
||||
typedef void *(*ProgressScreen_t)(unsigned char *obj);
|
||||
static ProgressScreen_t ProgressScreen = (ProgressScreen_t) 0x37044;
|
||||
|
||||
// Screen
|
||||
|
||||
typedef void (*Screen_updateEvents_t)(unsigned char *screen);
|
||||
static Screen_updateEvents_t Screen_updateEvents = (Screen_updateEvents_t) 0x28eb8;
|
||||
|
||||
typedef void (*Screen_keyboardNewChar_t)(unsigned char *screen, char key);
|
||||
static uint32_t Screen_keyboardNewChar_vtable_offset = 0x70;
|
||||
|
||||
typedef void (*Screen_keyPressed_t)(unsigned char *screen, int32_t key);
|
||||
static uint32_t Screen_keyPressed_vtable_offset = 0x6c;
|
||||
|
||||
typedef void (*Screen_tick_t)(unsigned char *screen);
|
||||
|
||||
static uint32_t Screen_minecraft_property_offset = 0x14; // Minecraft *
|
||||
|
||||
// SelectWorldScreen
|
||||
|
||||
static Screen_tick_t SelectWorldScreen_tick = (Screen_tick_t) 0x38a2c;
|
||||
static void *SelectWorldScreen_tick_vtable_addr = (void *) 0x104f78;
|
||||
|
||||
static uint32_t SelectWorldScreen_should_create_world_property_offset = 0xfc; // bool
|
||||
static uint32_t SelectWorldScreen_world_created_property_offset = 0xf9; // bool
|
||||
|
||||
// Touch::SelectWorldScreen
|
||||
|
||||
static Screen_tick_t Touch_SelectWorldScreen_tick = (Screen_tick_t) 0x3d96c;
|
||||
static void *Touch_SelectWorldScreen_tick_vtable_addr = (void *) 0x105780;
|
||||
|
||||
static uint32_t Touch_SelectWorldScreen_should_create_world_property_offset = 0x154; // bool
|
||||
static uint32_t Touch_SelectWorldScreen_world_created_property_offset = 0x151; // bool
|
||||
|
||||
// ItemInstance
|
||||
|
||||
#define ITEM_INSTANCE_SIZE 0xc
|
||||
|
||||
typedef unsigned char *(*ItemInstance_constructor_t)(unsigned char *item_instance, unsigned char *item);
|
||||
static ItemInstance_constructor_t ItemInstance_constructor_item = (ItemInstance_constructor_t) 0x9992c;
|
||||
static ItemInstance_constructor_t ItemInstance_constructor_tile = (ItemInstance_constructor_t) 0x998e4;
|
||||
|
||||
typedef unsigned char *(*ItemInstance_constructor_extra_t)(unsigned char *item_instance, unsigned char *item, int32_t count, int32_t auxilary);
|
||||
static ItemInstance_constructor_extra_t ItemInstance_constructor_tile_extra = (ItemInstance_constructor_extra_t) 0x99918;
|
||||
static ItemInstance_constructor_extra_t ItemInstance_constructor_item_extra = (ItemInstance_constructor_extra_t) 0x99960;
|
||||
|
||||
static uint32_t ItemInstance_count_property_offset = 0x0;
|
||||
static uint32_t ItemInstance_id_property_offset = 0x4;
|
||||
static uint32_t ItemInstance_auxilary_property_offset = 0x8;
|
||||
|
||||
// FillingContainer
|
||||
|
||||
typedef int32_t (*FillingContainer_addItem_t)(unsigned char *filling_container, unsigned char *item_instance);
|
||||
static FillingContainer_addItem_t FillingContainer_addItem = (FillingContainer_addItem_t) 0x92aa0;
|
||||
|
||||
// RakNet::RakString
|
||||
|
||||
typedef void (*RakNet_RakString_Assign_t)(unsigned char *rak_string, const char *str);
|
||||
static RakNet_RakString_Assign_t RakNet_RakString_Assign = (RakNet_RakString_Assign_t) 0xe9e34;
|
||||
|
||||
static uint32_t RakNet_RakString_sharedString_property_offset = 0x0; // RakNet::RakString::SharedString *
|
||||
|
||||
// RakNet::RakString::SharedString
|
||||
|
||||
static uint32_t RakNet_RakString_SharedString_c_str_property_offset = 0x10; // char *
|
||||
|
||||
// RakNetInstance
|
||||
|
||||
typedef void (*RakNetInstance_send_t)(unsigned char *rak_net_instance, unsigned char *packet);
|
||||
static uint32_t RakNetInstance_send_vtable_offset = 0x38;
|
||||
|
||||
typedef uint32_t (*RakNetInstance_isServer_t)(unsigned char *rak_net_instance);
|
||||
static uint32_t RakNetInstance_isServer_vtable_offset = 0x48;
|
||||
|
||||
static uint32_t RakNetInstance_peer_property_offset = 0x4; // RakNet::RakPeer *
|
||||
|
||||
// RakNet::RakPeer
|
||||
|
||||
typedef struct RakNet_SystemAddress (*RakNet_RakPeer_GetSystemAddressFromGuid_t)(unsigned char *rak_peer, struct RakNet_RakNetGUID guid);
|
||||
static uint32_t RakNet_RakPeer_GetSystemAddressFromGuid_vtable_offset = 0xd0;
|
||||
|
||||
typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rak_peer, const char *ip);
|
||||
static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4;
|
||||
|
||||
// RakNet::SystemAddress
|
||||
|
||||
typedef char *(*RakNet_SystemAddress_ToString_t)(struct RakNet_SystemAddress *system_address, bool print_delimiter, char delimiter);
|
||||
static RakNet_SystemAddress_ToString_t RakNet_SystemAddress_ToString = (RakNet_SystemAddress_ToString_t) 0xd6198;
|
||||
|
||||
// ServerSideNetworkHandler
|
||||
|
||||
typedef void (*ServerSideNetworkHandler_onDisconnect_t)(unsigned char *server_side_network_handler, unsigned char *guid);
|
||||
static ServerSideNetworkHandler_onDisconnect_t ServerSideNetworkHandler_onDisconnect = (ServerSideNetworkHandler_onDisconnect_t) 0x75164;
|
||||
static void *ServerSideNetworkHandler_onDisconnect_vtable_addr = (void *) 0x109bb0;
|
||||
|
||||
typedef unsigned char *(*ServerSideNetworkHandler_getPlayer_t)(unsigned char *server_side_network_handler, unsigned char *guid);
|
||||
static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464;
|
||||
|
||||
typedef void (*ServerSideNetworkHandler_handle_t)(unsigned char *server_side_network_handler, unsigned char *rak_net_guid, unsigned char *packet);
|
||||
|
||||
static void *ServerSideNetworkHandler_handle_ChatPacket_vtable_addr = (void *) 0x109c60;
|
||||
|
||||
// Inventory
|
||||
|
||||
typedef void (*Inventory_selectSlot_t)(unsigned char *inventory, int32_t slot);
|
||||
static Inventory_selectSlot_t Inventory_selectSlot = (Inventory_selectSlot_t) 0x8d13c;
|
||||
|
||||
// TripodCameraRenderer
|
||||
|
||||
#define TRIPOD_CAMERA_RENDERER_SIZE 0x193
|
||||
|
||||
typedef unsigned char *(*TripodCameraRenderer_t)(unsigned char *renderer);
|
||||
static TripodCameraRenderer_t TripodCameraRenderer = (TripodCameraRenderer_t) 0x6583c;
|
||||
|
||||
// EntityRenderDispatcher
|
||||
|
||||
typedef unsigned char *(*EntityRenderDispatcher_t)(unsigned char *dispatcher);
|
||||
static EntityRenderDispatcher_t EntityRenderDispatcher = (EntityRenderDispatcher_t) 0x6096c;
|
||||
|
||||
typedef void (*EntityRenderDispatcher_assign_t)(unsigned char *dispatcher, unsigned char entity_id, unsigned char *renderer);
|
||||
static EntityRenderDispatcher_assign_t EntityRenderDispatcher_assign = (EntityRenderDispatcher_assign_t) 0x6094c;
|
||||
|
||||
// TileEntity
|
||||
|
||||
static uint32_t TileEntity_id_property_offset = 0x18; // int32_t
|
||||
|
||||
// ItemRenderer
|
||||
|
||||
typedef float (*ItemRenderer_renderGuiItemCorrect_t)(unsigned char *font, unsigned char *textures, unsigned char *item_instance, int32_t param_1, int32_t param_2);
|
||||
static ItemRenderer_renderGuiItemCorrect_t ItemRenderer_renderGuiItemCorrect = (ItemRenderer_renderGuiItemCorrect_t) 0x639a0;
|
||||
|
||||
// Method That Require C++ Types
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
|
||||
// Structures
|
||||
|
||||
struct AppPlatform_readAssetFile_return_value {
|
||||
char *data;
|
||||
int32_t length;
|
||||
};
|
||||
|
||||
struct ConnectedClient {
|
||||
uint32_t sock;
|
||||
std::string str;
|
||||
long time;
|
||||
};
|
||||
|
||||
// AppPlatform
|
||||
|
||||
typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& path, int32_t width, int32_t height);
|
||||
static void *AppPlatform_linux_saveScreenshot_vtable_addr = (void *) 0x102160;
|
||||
|
||||
typedef AppPlatform_readAssetFile_return_value (*AppPlatform_readAssetFile_t)(unsigned char *app_platform, std::string const& path);
|
||||
static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_readAssetFile_t) 0x12b10;
|
||||
|
||||
// Minecraft
|
||||
|
||||
typedef void (*Minecraft_selectLevel_t)(unsigned char *minecraft, std::string const& level_dir, std::string const& level_name, LevelSettings const& vsettings);
|
||||
static Minecraft_selectLevel_t Minecraft_selectLevel = (Minecraft_selectLevel_t) 0x16f38;
|
||||
|
||||
// CommandServer
|
||||
|
||||
typedef std::string (*CommandServer_parse_t)(unsigned char *command_server, struct ConnectedClient &client, std::string const& command);
|
||||
static CommandServer_parse_t CommandServer_parse = (CommandServer_parse_t) 0x6aa8c;
|
||||
|
||||
// Level
|
||||
|
||||
typedef void (*Level_addParticle_t)(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count);
|
||||
static Level_addParticle_t Level_addParticle = (Level_addParticle_t) 0xa449c;
|
||||
|
||||
// Gui
|
||||
|
||||
typedef void (*Gui_addMessage_t)(unsigned char *gui, std::string const& text);
|
||||
static Gui_addMessage_t Gui_addMessage = (Gui_addMessage_t) 0x27820;
|
||||
|
||||
// ServerSideNetworkHandler
|
||||
|
||||
typedef void (*ServerSideNetworkHandler_displayGameMessage_t)(unsigned char *server_side_network_handler, std::string const& message);
|
||||
static ServerSideNetworkHandler_displayGameMessage_t ServerSideNetworkHandler_displayGameMessage = (ServerSideNetworkHandler_displayGameMessage_t) 0x750c4;
|
||||
|
||||
// SimpleChooseLevelScreen
|
||||
|
||||
#define SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE 0x68
|
||||
|
||||
typedef unsigned char *(*SimpleChooseLevelScreen_t)(unsigned char *simple_choose_level_screen, std::string const& world_name);
|
||||
static SimpleChooseLevelScreen_t SimpleChooseLevelScreen = (SimpleChooseLevelScreen_t) 0x31404;
|
||||
|
||||
// SelectWorldScreen
|
||||
|
||||
typedef std::string (*SelectWorldScreen_getUniqueLevelName_t)(unsigned char *screen, std::string const& name);
|
||||
static SelectWorldScreen_getUniqueLevelName_t SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x388ec;
|
||||
|
||||
// Touch::SelectWorldScreen
|
||||
|
||||
static SelectWorldScreen_getUniqueLevelName_t Touch_SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x3d82c;
|
||||
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic pop
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Patching Functions
|
||||
|
||||
#ifdef REBORN_HAS_PATCH_CODE
|
||||
|
||||
void _overwrite_call(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);
|
||||
|
||||
void _overwrite_calls(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_calls(start, target) _overwrite_calls(__FILE__, __LINE__, start, target);
|
||||
|
||||
void *extract_from_bl_instruction(unsigned char *from);
|
||||
|
||||
void _overwrite(const char *file, int line, void *start, void *target);
|
||||
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);
|
||||
|
||||
void _patch(const char *file, int line, void *start, unsigned char patch[4]);
|
||||
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch);
|
||||
|
||||
void _patch_address(const char *file, int line, void *start, void *target);
|
||||
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, start, target);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -3,6 +3,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <iconv.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
@ -19,34 +21,28 @@
|
|||
#define string_append(str, format, ...) \
|
||||
{ \
|
||||
char *old = *str; \
|
||||
safe_asprintf(str, "%s" format, *str == NULL ? "" : *str, __VA_ARGS__); \
|
||||
safe_asprintf(str, "%s" format, *str == NULL ? "" : *str, ##__VA_ARGS__); \
|
||||
ALLOC_CHECK(*str); \
|
||||
if (old != NULL && old != *str) { \
|
||||
free(old); \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Sanitize String
|
||||
#define MINIMUM_SAFE_CHARACTER 32
|
||||
#define MAXIMUM_SAFE_CHARACTER 126
|
||||
#define MINIMUM_EXTENDED_SAFE_CHARACTER 128
|
||||
static inline void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
|
||||
// Store Message Length
|
||||
int length = strlen(*str);
|
||||
// Truncate Message
|
||||
if (max_length != -1 && length > max_length) {
|
||||
(*str)[max_length] = '\0';
|
||||
length = max_length;
|
||||
}
|
||||
// Loop Through Message
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
|
||||
continue;
|
||||
}
|
||||
unsigned char c = (unsigned char) (*str)[i];
|
||||
if ((c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) && c < MINIMUM_EXTENDED_SAFE_CHARACTER) {
|
||||
// Replace Illegal Character
|
||||
(*str)[i] = '?';
|
||||
}
|
||||
}
|
||||
void sanitize_string(char **str, int max_length, unsigned int allow_newlines);
|
||||
|
||||
// CP437
|
||||
void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size);
|
||||
char *to_cp437(const char *input);
|
||||
char *from_cp437(const char *input);
|
||||
|
||||
// Starts With
|
||||
int starts_with(const char *str, const char *prefix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#define ALLOC_CHECK(obj) \
|
||||
{ \
|
||||
if (obj == NULL) { \
|
||||
ERR("(%s:%i) Memory Allocation Failed", __FILE__, __LINE__); \
|
||||
ERR("Memory Allocation Failed"); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -25,27 +25,26 @@
|
|||
dlerror(); \
|
||||
real_##name = (name##_t) dlsym(RTLD_NEXT, #name); \
|
||||
if (!real_##name) { \
|
||||
ERR("Error Resolving Symbol: "#name": %s", dlerror()); \
|
||||
ERR("Error Resolving Symbol: " #name ": %s", dlerror()); \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
\
|
||||
__attribute__((__used__)) return_type name args
|
||||
|
||||
// Macro To Reset Environmental Variables To Pre-MCPI State
|
||||
#define RESET_ENVIRONMENTAL_VARIABLE(name) \
|
||||
{ \
|
||||
char *original_env_value = getenv("ORIGINAL_" name); \
|
||||
if (original_env_value != NULL) { \
|
||||
setenv(name, original_env_value, 1); \
|
||||
} else { \
|
||||
unsetenv(name); \
|
||||
} \
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Safe Version Of pipe()
|
||||
static inline void safe_pipe2(int pipefd[2], int flags) {
|
||||
if (pipe2(pipefd, flags) != 0) {
|
||||
ERR("Unable To Create Pipe: %s", strerror(errno));
|
||||
}
|
||||
void safe_pipe2(int pipefd[2], int flags);
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
int is_progress_difference_significant(int32_t new_val, int32_t old_val);
|
||||
|
||||
// Lock File
|
||||
int lock_file(const char *file);
|
||||
void unlock_file(const char *file, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -5,23 +5,23 @@
|
|||
#include <sys/mman.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#ifndef __arm__
|
||||
#error "Patching Code Is ARM Only"
|
||||
#endif // #ifndef __arm__
|
||||
#endif
|
||||
|
||||
// BL Instruction Magic Number
|
||||
#define BL_INSTRUCTION 0xeb
|
||||
#define B_INSTRUCTION 0xea
|
||||
|
||||
// Generate A BL Instruction
|
||||
static uint32_t generate_bl_instruction(void *from, void *to) {
|
||||
static uint32_t generate_bl_instruction(void *from, void *to, int use_b_instruction) {
|
||||
uint32_t instruction;
|
||||
unsigned char *instruction_array = (unsigned char *) &instruction;
|
||||
|
||||
instruction_array[3] = BL_INSTRUCTION;
|
||||
instruction_array[3] = use_b_instruction ? B_INSTRUCTION : BL_INSTRUCTION;
|
||||
|
||||
unsigned char *pc = ((unsigned char *) from) + 8;
|
||||
int32_t offset = (int32_t) to - (int32_t) pc;
|
||||
|
@ -43,16 +43,21 @@ struct overwrite_data {
|
|||
void *replacement;
|
||||
int found;
|
||||
};
|
||||
static void overwrite_calls_callback(void *section, Elf32_Word size, void *data) {
|
||||
static void overwrite_calls_callback(ElfW(Addr) section_addr, ElfW(Word) size, void *data) {
|
||||
struct overwrite_data *args = (struct overwrite_data *) data;
|
||||
void *section = (void *) section_addr;
|
||||
|
||||
for (uint32_t i = 0; i < size; i = i + 4) {
|
||||
unsigned char *addr = ((unsigned char *) section) + i;
|
||||
if (addr[3] == BL_INSTRUCTION) {
|
||||
uint32_t check_instruction = generate_bl_instruction(addr, args->target);
|
||||
int use_b_instruction = addr[3] == B_INSTRUCTION;
|
||||
// Check If Instruction is B Or BL
|
||||
if (addr[3] == BL_INSTRUCTION || use_b_instruction) {
|
||||
uint32_t check_instruction = generate_bl_instruction(addr, args->target, use_b_instruction);
|
||||
unsigned char *check_instruction_array = (unsigned char *) &check_instruction;
|
||||
// Check If Instruction Calls Target
|
||||
if (addr[0] == check_instruction_array[0] && addr[1] == check_instruction_array[1] && addr[2] == check_instruction_array[2]) {
|
||||
uint32_t new_instruction = generate_bl_instruction(addr, args->replacement);
|
||||
// Patch Instruction
|
||||
uint32_t new_instruction = generate_bl_instruction(addr, args->replacement, use_b_instruction);
|
||||
_patch(args->file, args->line, addr, (unsigned char *) &new_instruction);
|
||||
args->found++;
|
||||
}
|
||||
|
@ -66,6 +71,12 @@ static unsigned char *code_block = NULL;
|
|||
#define CODE_SIZE 8
|
||||
static int code_block_remaining = CODE_BLOCK_SIZE;
|
||||
|
||||
static void _long_overwrite(void *start, void *target) {
|
||||
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
|
||||
|
||||
_patch(NULL, -1, start, patch_data);
|
||||
_patch_address(NULL, -1, (void *) (((unsigned char *) start) + 4), target);
|
||||
}
|
||||
static void update_code_block(void *target) {
|
||||
// BL Instructions Can Only Access A Limited Portion of Memory, So This Allocates Memory Closer To The Original Instruction, That When Run, Will Jump Into The Actual Target
|
||||
if (code_block == NULL) {
|
||||
|
@ -73,33 +84,36 @@ static void update_code_block(void *target) {
|
|||
if (code_block == MAP_FAILED) {
|
||||
ERR("Unable To Allocate Code Block: %s", strerror(errno));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
INFO("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
|
||||
#endif
|
||||
DEBUG("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
|
||||
}
|
||||
if (code_block_remaining < CODE_SIZE) {
|
||||
ERR("%s", "Maximum Amount Of overwrite_calls() Uses Reached");
|
||||
ERR("Maximum Amount Of overwrite_calls() Uses Reached");
|
||||
}
|
||||
_overwrite(NULL, -1, code_block, target);
|
||||
_long_overwrite(code_block, target);
|
||||
}
|
||||
static void increment_code_block() {
|
||||
code_block = code_block + CODE_SIZE;
|
||||
code_block_remaining = code_block_remaining - CODE_SIZE;
|
||||
}
|
||||
|
||||
// Overwrite Specific BL Instruction
|
||||
void _overwrite_call(const char *file, int line, void *start, void *target) {
|
||||
// Overwrite Specific B(L) Instruction
|
||||
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) {
|
||||
// Add New Target To Code Block
|
||||
update_code_block(target);
|
||||
|
||||
uint32_t new_instruction = generate_bl_instruction(start, code_block);
|
||||
// Patch
|
||||
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
|
||||
_patch(file, line, start, (unsigned char *) &new_instruction);
|
||||
|
||||
// Increment Code Block Position
|
||||
increment_code_block();
|
||||
}
|
||||
void _overwrite_call(const char *file, int line, void *start, void *target) {
|
||||
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
|
||||
_overwrite_call_internal(file, line, start, target, use_b_instruction);
|
||||
}
|
||||
|
||||
// Overwrite Function Calls
|
||||
// Overwrite All B(L) Intrusctions That Target The Specified Address
|
||||
void _overwrite_calls(const char *file, int line, void *start, void *target) {
|
||||
// Add New Target To Code Block
|
||||
update_code_block(target);
|
||||
|
@ -111,35 +125,44 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
|
|||
data.replacement = code_block;
|
||||
data.found = 0;
|
||||
|
||||
iterate_text_sections(overwrite_calls_callback, &data);
|
||||
iterate_segments(overwrite_calls_callback, &data);
|
||||
|
||||
// Increment Code Block Position
|
||||
increment_code_block();
|
||||
|
||||
// Check
|
||||
if (data.found < 1) {
|
||||
ERR("(%s:%i) Unable To Find Callsites For 0x%08x", file, line, (uint32_t) start);
|
||||
}
|
||||
}
|
||||
|
||||
// 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_array[0] = from[0];
|
||||
target_array[1] = from[1];
|
||||
target_array[2] = from[2];
|
||||
|
||||
int32_t offset = target << 2;
|
||||
|
||||
return (void *) (pc + offset);
|
||||
}
|
||||
|
||||
// Overwrite Function
|
||||
void _overwrite(const char *file, int line, void *start, void *target) {
|
||||
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
|
||||
|
||||
_patch(file, line, start, patch_data);
|
||||
_patch_address(file, line, start + 4, target);
|
||||
_overwrite_call_internal(file, line, start, target, 1);
|
||||
}
|
||||
|
||||
// Print Patch Debug Data
|
||||
#ifdef DEBUG
|
||||
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) fprintf(stderr, "[PATCH]: (%s:%i) Patching (0x%08x) - "str": 0x%02x 0x%02x 0x%02x 0x%02x\n", file, line, (uint32_t) start, data[0], data[1], data[2], data[3]);
|
||||
#else
|
||||
#define PATCH_PRINTF(file, line, start, str) { (void) file; (void) line; (void) start; (void) str; } // Mark As Used
|
||||
#endif
|
||||
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) DEBUG("(%s:%i): Patching (0x%08x) - " str ": 0x%02x 0x%02x 0x%02x 0x%02x", file, line, (uint32_t) start, data[0], data[1], data[2], data[3]);
|
||||
|
||||
// Patch Instruction
|
||||
void _patch(const char *file, int line, void *start, unsigned char patch[]) {
|
||||
void _patch(const char *file, int line, void *start, unsigned char patch[4]) {
|
||||
if (((uint32_t) start) % 4 != 0) {
|
||||
ERR("%s", "Invalid Address");
|
||||
ERR("Invalid Address");
|
||||
}
|
||||
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
|
@ -166,6 +189,6 @@ void _patch(const char *file, int line, void *start, unsigned char patch[]) {
|
|||
// Patch Address
|
||||
void _patch_address(const char *file, int line, void *start, void *target) {
|
||||
uint32_t addr = (uint32_t) target;
|
||||
unsigned char patch_data[4] = {addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff};
|
||||
unsigned char *patch_data = (unsigned char *) &addr;
|
||||
_patch(file, line, start, patch_data);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include <libreborn/elf.h>
|
||||
|
||||
// Find And Iterate Over All Segments In Current Binary
|
||||
typedef struct {
|
||||
segment_callback_t callback;
|
||||
void *data;
|
||||
} dl_iterate_callback_data;
|
||||
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
|
||||
dl_iterate_callback_data *callback_data = (dl_iterate_callback_data *) data;
|
||||
// Only Search Current Program
|
||||
if (strcmp(info->dlpi_name, "") == 0) {
|
||||
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||
// Only Executable Segemnts
|
||||
if (info->dlpi_phdr[i].p_type == PT_LOAD && (info->dlpi_phdr[i].p_flags & PF_X) != 0) {
|
||||
// Callback
|
||||
(*callback_data->callback)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_memsz, callback_data->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void iterate_segments(segment_callback_t callback, void *data) {
|
||||
dl_iterate_callback_data callback_data = {
|
||||
.callback = callback,
|
||||
.data = data
|
||||
};
|
||||
dl_iterate_phdr(dl_iterate_callback, (void *) &callback_data);
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
#include <pthread.h>
|
||||
|
||||
#include <libreborn/exec.h>
|
||||
|
||||
// Set Environmental Variable
|
||||
static void setenv_safe(const char *name, const char *value) {
|
||||
if (value != NULL) {
|
||||
setenv(name, value, 1);
|
||||
} else {
|
||||
unsetenv(name);
|
||||
}
|
||||
}
|
||||
void set_and_print_env(const char *name, const char *value) {
|
||||
// Set The Value
|
||||
setenv_safe(name, value);
|
||||
|
||||
// Print New Value
|
||||
DEBUG("Set %s = %s", name, value != NULL ? value : "(unset)");
|
||||
}
|
||||
|
||||
// Safe execvpe()
|
||||
#define handle_environmental_variable(var) \
|
||||
{ \
|
||||
const char *full_var = is_arm_component ? "MCPI_ARM_" var : "MCPI_NATIVE_" var; \
|
||||
const char *var_value = getenv(full_var); \
|
||||
set_and_print_env(var, var_value); \
|
||||
}
|
||||
void setup_exec_environment(int is_arm_component) {
|
||||
for_each_special_environmental_variable(handle_environmental_variable);
|
||||
}
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
|
||||
// Log
|
||||
DEBUG("Running Command:");
|
||||
for (int i = 0; argv[i] != NULL; i++) {
|
||||
DEBUG(" %s", argv[i]);
|
||||
}
|
||||
// Run
|
||||
int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
|
||||
} else {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Chop Off Last Component
|
||||
void chop_last_component(char **str) {
|
||||
size_t length = strlen(*str);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
size_t j = length - i - 1;
|
||||
if ((*str)[j] == '/') {
|
||||
(*str)[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get Binary Directory (Remember To Free)
|
||||
char *get_binary_directory() {
|
||||
// Get Path To Current Executable
|
||||
char *exe = realpath("/proc/self/exe", NULL);
|
||||
ALLOC_CHECK(exe);
|
||||
|
||||
// Chop Off Last Component
|
||||
chop_last_component(&exe);
|
||||
|
||||
// Return
|
||||
return exe;
|
||||
}
|
||||
|
||||
// Run Command And Get Output
|
||||
char *run_command(const char *const command[], int *exit_status) {
|
||||
// Store Output
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
// Run
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Run Command: %s", strerror(errno));
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = CHILD_PROCESS_TAG;
|
||||
|
||||
// Pipe stdout
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
close(output_pipe[0]);
|
||||
close(output_pipe[1]);
|
||||
|
||||
// Setup stderr
|
||||
if (getenv("MCPI_DEBUG") == NULL) {
|
||||
const char *log_file_fd_env = getenv("MCPI_LOG_FILE_FD");
|
||||
if (log_file_fd_env == NULL) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
dup2(atoi(log_file_fd_env), STDERR_FILENO);
|
||||
}
|
||||
|
||||
// Setup Environment
|
||||
setup_exec_environment(0);
|
||||
|
||||
// Run
|
||||
safe_execvpe(command, (const char *const *) environ);
|
||||
} else {
|
||||
// Parent Process
|
||||
track_child(ret);
|
||||
|
||||
// Read stdout
|
||||
close(output_pipe[1]);
|
||||
char *output = NULL;
|
||||
#define BUFFER_SIZE 1024
|
||||
char buf[BUFFER_SIZE];
|
||||
ssize_t bytes_read = 0;
|
||||
while ((bytes_read = read(output_pipe[0], (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */)) > 0) {
|
||||
buf[bytes_read] = '\0';
|
||||
string_append(&output, "%s", buf);
|
||||
}
|
||||
close(output_pipe[0]);
|
||||
|
||||
// Get Return Code
|
||||
int status;
|
||||
waitpid(ret, &status, 0);
|
||||
untrack_child(ret);
|
||||
if (exit_status != NULL) {
|
||||
*exit_status = status;
|
||||
}
|
||||
|
||||
// Return
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
// Get Exit Status String
|
||||
void get_exit_status_string(int status, char **out) {
|
||||
if (out != NULL) {
|
||||
*out =NULL;
|
||||
if (WIFEXITED(status)) {
|
||||
safe_asprintf(out, ": Exit Code: %i", WEXITSTATUS(status));
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
safe_asprintf(out, ": Signal: %i%s", WTERMSIG(status), WCOREDUMP(status) ? " (Core Dumped)" : "");
|
||||
} else {
|
||||
safe_asprintf(out, ": Terminated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Track Children
|
||||
#define MAX_CHILDREN 128
|
||||
static pid_t children[MAX_CHILDREN] = { 0 };
|
||||
static pthread_mutex_t children_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
void track_child(pid_t pid) {
|
||||
pthread_mutex_lock(&children_lock);
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
if (children[i] == 0) {
|
||||
children[i] = pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&children_lock);
|
||||
}
|
||||
void untrack_child(pid_t pid) {
|
||||
pthread_mutex_lock(&children_lock);
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
if (children[i] == pid) {
|
||||
children[i] = 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&children_lock);
|
||||
}
|
||||
void murder_children() {
|
||||
pthread_mutex_lock(&children_lock);
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
if (children[i] != 0) {
|
||||
kill(children[i], SIGTERM);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&children_lock);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <libreborn/log.h>
|
||||
|
||||
// Debug Tag
|
||||
const char *reborn_debug_tag = "";
|
||||
|
||||
// Debug FD
|
||||
int reborn_get_debug_fd() {
|
||||
if (getenv("MCPI_DEBUG") != NULL) {
|
||||
return STDERR_FILENO;
|
||||
} else {
|
||||
static int debug_fd = -1;
|
||||
if (debug_fd == -1) {
|
||||
const char *log_file_fd_env = getenv("MCPI_LOG_FILE_FD");
|
||||
if (log_file_fd_env == NULL) {
|
||||
return -1;
|
||||
}
|
||||
debug_fd = atoi(log_file_fd_env);
|
||||
}
|
||||
return debug_fd;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
#include <iconv.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libreborn/string.h>
|
||||
|
||||
// Sanitize String
|
||||
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
|
||||
// Store Message Length
|
||||
int length = strlen(*str);
|
||||
// Truncate Message
|
||||
if (max_length != -1 && length > max_length) {
|
||||
(*str)[max_length] = '\0';
|
||||
length = max_length;
|
||||
}
|
||||
// Loop Through Message
|
||||
if (!allow_newlines) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if ((*str)[i] == '\n' || (*str)[i] == '\r') {
|
||||
// Replace Newline
|
||||
(*str)[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Minecraft-Flavored CP437
|
||||
void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size) {
|
||||
iconv(cd, &input, &input_size, &output, &output_size);
|
||||
}
|
||||
#define CP437_CHARACTERS 256
|
||||
static const char *cp437_characters_map[CP437_CHARACTERS] = {
|
||||
"\0", "☺", "☻", "♥", "♦", "♣", "♠", "•", "◘", "○", "\n", "♂", "♀", "\r", "♫", "☼",
|
||||
"►", "◄", "↕", "‼", "¶", "§", "▬", "↨", "↑", "↓", "→", "←", "∟", "↔", "▲", "▼",
|
||||
" ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
|
||||
"@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
|
||||
"P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
|
||||
"`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
|
||||
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "⌂",
|
||||
"Ç", "ü", "é", "â", "ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å",
|
||||
"É", "æ", "Æ", "ô", "ö", "ò", "û", "ù", "ÿ", "Ö", "Ü", "¢", "£", "¥", "₧", "ƒ",
|
||||
"á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "⌐", "¬", "½", "¼", "¡", "«", "»",
|
||||
"░", "▒", "▓", "│", "┤", "╡", "╢", "╖", "╕", "╣", "║", "╗", "╝", "╜", "╛", "┐",
|
||||
"└", "┴", "┬", "├", "─", "┼", "╞", "╟", "╚", "╔", "╩", "╦", "╠", "═", "╬", "╧",
|
||||
"╨", "╤", "╥", "╙", "╘", "╒", "╓", "╫", "╪", "┘", "┌", "█", "▄", "▌", "▐", "▀",
|
||||
"α", "ß", "Γ", "π", "Σ", "σ", "µ", "τ", "Φ", "Θ", "Ω", "δ", "∞", "φ", "ε", "∩",
|
||||
"≡", "±", "≥", "≤", "⌠", "⌡", "÷", "≈", "°", "∙", "·", "√", "ⁿ", "²", "■", "©"
|
||||
};
|
||||
static uint32_t *get_cp437_characters_codepoint_map() {
|
||||
static uint32_t map[CP437_CHARACTERS];
|
||||
static int is_setup = 0;
|
||||
if (!is_setup) {
|
||||
// Build Map
|
||||
iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
|
||||
if (cd != (iconv_t) -1) {
|
||||
size_t str_size = 4;
|
||||
uint32_t *str = (uint32_t *) malloc(str_size);
|
||||
ALLOC_CHECK(str);
|
||||
for (int i = 0; i < CP437_CHARACTERS; i++) {
|
||||
// Convert to UTF-32, Then Extract Codepoint
|
||||
safe_iconv(cd, (char *) cp437_characters_map[i], strlen(cp437_characters_map[i]), (char *) str, str_size);
|
||||
// Extract
|
||||
map[i] = str[0];
|
||||
}
|
||||
// Free
|
||||
free(str);
|
||||
iconv_close(cd);
|
||||
} else {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
is_setup = 1;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
char *to_cp437(const char *input) {
|
||||
// Convert To UTF-32 For Easier Parsing
|
||||
size_t in_size = strlen(input);
|
||||
size_t utf32_str_size = in_size * 4;
|
||||
size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */;
|
||||
uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size);
|
||||
ALLOC_CHECK(utf32_str);
|
||||
memset(utf32_str, 0, real_utf32_str_size);
|
||||
iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
|
||||
if (cd != (iconv_t) -1) {
|
||||
safe_iconv(cd, (char *) input, in_size, (char *) utf32_str, utf32_str_size);
|
||||
iconv_close(cd);
|
||||
} else {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
// Allocate String
|
||||
size_t cp437_str_size;
|
||||
for (cp437_str_size = 0; utf32_str[cp437_str_size] != 0; cp437_str_size++);
|
||||
size_t real_cp437_str_size = cp437_str_size + 1 /* NULL-terminator */;
|
||||
char *cp437_str = (char *) malloc(real_cp437_str_size);
|
||||
ALLOC_CHECK(cp437_str);
|
||||
memset(cp437_str, 0, real_cp437_str_size);
|
||||
// Handle Characters
|
||||
for (size_t i = 0; utf32_str[i] != 0; i++) {
|
||||
uint32_t codepoint = utf32_str[i];
|
||||
for (int j = 0; j < CP437_CHARACTERS; j++) {
|
||||
uint32_t test_codepoint = get_cp437_characters_codepoint_map()[j];
|
||||
if (codepoint == test_codepoint) {
|
||||
cp437_str[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cp437_str[i] == '\0') {
|
||||
cp437_str[i] = '?';
|
||||
}
|
||||
}
|
||||
// Free
|
||||
free(utf32_str);
|
||||
// Return
|
||||
return cp437_str;
|
||||
}
|
||||
char *from_cp437(const char *input) {
|
||||
// Convert To UTF-32 For Easier Parsing
|
||||
size_t in_size = strlen(input);
|
||||
size_t utf32_str_size = in_size * 4;
|
||||
size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */;
|
||||
uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size);
|
||||
ALLOC_CHECK(utf32_str);
|
||||
memset(utf32_str, 0, real_utf32_str_size);
|
||||
// Handle Characters
|
||||
for (size_t i = 0; input[i] != '\0'; i++) {
|
||||
utf32_str[i] = get_cp437_characters_codepoint_map()[(uint32_t) input[i]];
|
||||
}
|
||||
// Convert To UTF-8
|
||||
size_t out_size = utf32_str_size;
|
||||
size_t real_out_size = utf32_str_size + 1 /* NULL-terminator */;
|
||||
char *output = (char *) malloc(real_out_size);
|
||||
ALLOC_CHECK(output);
|
||||
memset(output, 0, real_out_size);
|
||||
iconv_t cd = iconv_open("UTF-8", "UTF-32LE");
|
||||
if (cd != (iconv_t) -1) {
|
||||
safe_iconv(cd, (char *) utf32_str, utf32_str_size, output, out_size);
|
||||
iconv_close(cd);
|
||||
} else {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
// Return
|
||||
return output;
|
||||
}
|
||||
|
||||
// Starts With
|
||||
int starts_with(const char *str, const char *prefix) {
|
||||
return strncmp(prefix, str, strlen(prefix)) == 0;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <libreborn/util.h>
|
||||
|
||||
// Safe Version Of pipe()
|
||||
void safe_pipe2(int pipefd[2], int flags) {
|
||||
if (pipe2(pipefd, flags) != 0) {
|
||||
ERR("Unable To Create Pipe: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
#define SIGNIFICANT_PROGRESS 5
|
||||
int is_progress_difference_significant(int32_t new_val, int32_t old_val) {
|
||||
if (new_val != old_val) {
|
||||
if (new_val == -1 || old_val == -1) {
|
||||
return 1;
|
||||
} else if (new_val == 0 || new_val == 100) {
|
||||
return 1;
|
||||
} else {
|
||||
return new_val - old_val >= SIGNIFICANT_PROGRESS;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Lock File
|
||||
int lock_file(const char *file) {
|
||||
int fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (fd == -1) {
|
||||
ERR("Unable To Open Lock File: %s: %s", file, strerror(errno));
|
||||
}
|
||||
if (flock(fd, LOCK_EX) == -1) {
|
||||
ERR("Unable To Lock File: %s: %s", file, strerror(errno));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
void unlock_file(const char *file, int fd) {
|
||||
if (flock(fd, LOCK_UN) == -1) {
|
||||
ERR("Unable To Unlock File: %s: %s", file, strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
}
|
|
@ -1,40 +1,28 @@
|
|||
project(media-layer)
|
||||
|
||||
# Check Options
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
if(MCPI_SERVER_MODE)
|
||||
message(FATAL_ERROR "Server Mode With Media Layer Proxy Configuration Is Redundant")
|
||||
endif()
|
||||
if(MCPI_BUILD_MODE STREQUAL "both")
|
||||
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add Headers
|
||||
add_library(media-layer-headers INTERFACE)
|
||||
target_include_directories(media-layer-headers INTERFACE include)
|
||||
target_include_directories(
|
||||
media-layer-headers
|
||||
INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/media-layer>"
|
||||
)
|
||||
# SDK
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS media-layer-headers EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/media-layer")
|
||||
endif()
|
||||
|
||||
# Add Extras
|
||||
add_subdirectory(extras)
|
||||
|
||||
# Add Core
|
||||
add_subdirectory(core)
|
||||
if((BUILD_NATIVE_COMPONENTS AND MCPI_USE_MEDIA_LAYER_PROXY) OR (BUILD_ARM_COMPONENTS AND NOT MCPI_USE_MEDIA_LAYER_PROXY))
|
||||
add_subdirectory(core)
|
||||
endif()
|
||||
|
||||
# Add Proxy
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
add_subdirectory(proxy)
|
||||
endif()
|
||||
|
||||
# Add Stubs
|
||||
add_subdirectory(stubs)
|
||||
|
||||
# Add Extras
|
||||
add_subdirectory(extras)
|
||||
|
||||
# Add Symlinks So MCPI Can Locate Libraries
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
if(MCPI_SERVER_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libX11.so.6")
|
||||
else()
|
||||
# When Loading In Client Mode On An ARM Host, Use Native X11 By Default
|
||||
install_symlink("../lib/libmedia-layer-core.so" "${MCPI_FALLBACK_LIB_DIR}/libX11.so.6")
|
||||
endif()
|
||||
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libSDL-1.2.so.0")
|
||||
endif()
|
||||
|
|
|
@ -1,29 +1,32 @@
|
|||
project(media-layer-core)
|
||||
|
||||
# Dependencies
|
||||
add_subdirectory(dependencies)
|
||||
|
||||
# OpenGL
|
||||
add_subdirectory(gles)
|
||||
|
||||
# Configuration
|
||||
set(CORE_SRC src/base.cpp src/media.c src/screenshot.c) # SDL Re-Implementation Using GLFW
|
||||
set(CORE_SRC src/base.cpp src/media.c $<TARGET_OBJECTS:media-layer-extras>) # SDL Re-Implementation Using GLFW
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
list(APPEND CORE_SRC src/audio/api.cpp src/audio/engine.c src/audio/file.cpp)
|
||||
else()
|
||||
list(APPEND CORE_SRC src/audio/stubs.c)
|
||||
endif()
|
||||
|
||||
# Build
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
|
||||
# Building Native Components
|
||||
add_library(media-layer-core OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
elseif(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
|
||||
# Building ARM Components
|
||||
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
# Install
|
||||
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
|
||||
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
# Install
|
||||
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
# Configure Media Layer Core If Built
|
||||
if(TARGET media-layer-core)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core PUBLIC media-layer-headers PUBLIC reborn-util PUBLIC GLESv1_CM PUBLIC dl)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
# OpenAL
|
||||
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-headers pthread dl)
|
||||
if(NOT MCPI_SERVER_MODE)
|
||||
# Find GLFW
|
||||
find_package(glfw3 3.2 REQUIRED)
|
||||
# Find FreeImage
|
||||
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
|
||||
# Not Needed In Server Mode
|
||||
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" GLESv1_CM glfw)
|
||||
endif()
|
||||
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw PRIVATE LIB_LIEF)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
project(media-layer-core-dependencies)
|
||||
|
||||
# GLFW
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
add_subdirectory(glfw)
|
||||
endif()
|
|
@ -0,0 +1,40 @@
|
|||
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)
|
||||
|
||||
# Remove When glfw/glfw#2192 Is Merged
|
||||
target_compile_definitions(glfw PRIVATE -D_GLFW_LINUX_JOYSTICK)
|
||||
# Remove When glfw/glfw#2198 Is Merged
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/publicize-glfw-symbol.h"
|
||||
"#pragma once\n"
|
||||
"extern __attribute__((visibility(\"default\"))) void _glfwDetectJoystickConnectionLinux(void);\n"
|
||||
)
|
||||
target_compile_options(glfw PRIVATE -include PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/publicize-glfw-symbol.h")
|
||||
|
||||
# Install
|
||||
install(TARGETS glfw DESTINATION "${MCPI_LIB_DIR}")
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS glfw EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
# License
|
||||
install(FILES src/LICENSE.md DESTINATION "${MCPI_LEGAL_DIR}/glfw")
|
|
@ -0,0 +1 @@
|
|||
Subproject commit dd8a678a66f1967372e5a5e3deac41ebf65ee127
|
|
@ -0,0 +1,32 @@
|
|||
project(media-layer-gles)
|
||||
|
||||
# Build
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
# Stubs For Headless Mode
|
||||
set(GLES_SRC src/stubs.c)
|
||||
elseif(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
|
||||
# GLESv1_CM Compatibility Layer
|
||||
set(GLES_SRC src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c)
|
||||
else()
|
||||
# Passthrough To glfwGetProcAddress()
|
||||
set(GLES_SRC src/passthrough.c)
|
||||
endif()
|
||||
add_library(GLESv1_CM OBJECT ${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()
|
|
@ -0,0 +1,204 @@
|
|||
#include "state.h"
|
||||
#include "../passthrough.h"
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// Shaders
|
||||
#define REAL_GL_FRAGMENT_SHADER 0x8b30
|
||||
#define REAL_GL_VERTEX_SHADER 0x8b31
|
||||
#define REAL_GL_INFO_LOG_LENGTH 0x8b84
|
||||
#define REAL_GL_COMPILE_STATUS 0x8b81
|
||||
GL_FUNC(glUseProgram, void, (GLuint program));
|
||||
GL_FUNC(glGetUniformLocation, GLint, (GLuint program, const GLchar *name));
|
||||
GL_FUNC(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
|
||||
GL_FUNC(glUniform1i, void, (GLint location, GLint v0));
|
||||
GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0));
|
||||
GL_FUNC(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
|
||||
GL_FUNC(glGetAttribLocation, GLint, (GLuint program, const GLchar *name));
|
||||
GL_FUNC(glEnableVertexAttribArray, void, (GLuint index));
|
||||
GL_FUNC(glDisableVertexAttribArray, void, (GLuint index));
|
||||
GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
|
||||
GL_FUNC(glVertexAttrib3f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2));
|
||||
GL_FUNC(glVertexAttrib4f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
|
||||
GL_FUNC(glCreateShader, GLuint, (GLenum type));
|
||||
GL_FUNC(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length));
|
||||
GL_FUNC(glCompileShader, void, (GLuint shader));
|
||||
GL_FUNC(glCreateProgram, GLuint, ());
|
||||
GL_FUNC(glAttachShader, void, (GLuint program, GLuint shader));
|
||||
GL_FUNC(glLinkProgram, void, (GLuint program));
|
||||
GL_FUNC(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params));
|
||||
GL_FUNC(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
|
||||
|
||||
// Compile Shader
|
||||
static void log_shader(GLuint shader, const char *name) {
|
||||
// Log
|
||||
GLint log_length = 0;
|
||||
real_glGetShaderiv()(shader, REAL_GL_INFO_LOG_LENGTH, &log_length);
|
||||
GLchar *log = malloc(log_length * sizeof (GLchar));
|
||||
ALLOC_CHECK(log);
|
||||
real_glGetShaderInfoLog()(shader, log_length, &log_length, log);
|
||||
if (log_length > 0) {
|
||||
if (log_length > 1 && log[log_length - 1] == '\n') {
|
||||
log[log_length - 1] = '\0';
|
||||
}
|
||||
DEBUG("%s Shader Compile Log: %s", name, log);
|
||||
}
|
||||
free(log);
|
||||
|
||||
// Check Status
|
||||
GLint is_compiled = 0;
|
||||
real_glGetShaderiv()(shader, REAL_GL_COMPILE_STATUS, &is_compiled);
|
||||
if (!is_compiled) {
|
||||
ERR("Failed To Compile %s Shader", name);
|
||||
}
|
||||
}
|
||||
static GLuint compile_shader(const char *vertex_shader_text, const int vertex_shader_length, const char *fragment_shader_text, const int fragment_shader_length) {
|
||||
// Vertex Shader
|
||||
const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER);
|
||||
real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, &vertex_shader_length);
|
||||
real_glCompileShader()(vertex_shader);
|
||||
log_shader(vertex_shader, "Vertex");
|
||||
|
||||
// Fragment Shader
|
||||
const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER);
|
||||
real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, &fragment_shader_length);
|
||||
real_glCompileShader()(fragment_shader);
|
||||
log_shader(fragment_shader, "Fragment");
|
||||
|
||||
// Link
|
||||
GLuint program = real_glCreateProgram()();
|
||||
real_glAttachShader()(program, vertex_shader);
|
||||
real_glAttachShader()(program, fragment_shader);
|
||||
real_glLinkProgram()(program);
|
||||
|
||||
// Return
|
||||
return program;
|
||||
}
|
||||
|
||||
// Shader
|
||||
extern unsigned char main_vsh[];
|
||||
extern size_t main_vsh_len;
|
||||
extern unsigned char main_fsh[];
|
||||
extern size_t main_fsh_len;
|
||||
static GLuint get_shader() {
|
||||
static GLuint program = 0;
|
||||
if (program == 0) {
|
||||
program = compile_shader((const char *) main_vsh, main_vsh_len, (const char *) main_fsh, main_fsh_len);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
// Shader Switching
|
||||
static void use_shader(GLuint program) {
|
||||
static GLuint current_program = 0;
|
||||
if (current_program != program) {
|
||||
real_glUseProgram()(program);
|
||||
current_program = program;
|
||||
}
|
||||
}
|
||||
|
||||
// Array Pointer Drawing
|
||||
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count));
|
||||
#define lazy_uniform(name) \
|
||||
static GLint name##_handle = -1; \
|
||||
if (name##_handle == -1) { \
|
||||
name##_handle = real_glGetUniformLocation()(program, #name); \
|
||||
}
|
||||
void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
// Verify
|
||||
if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) {
|
||||
ERR("Unsupported Vertex Conifguration");
|
||||
}
|
||||
|
||||
// Check Mode
|
||||
int use_color_pointer = gl_state.array_pointers.color.enabled;
|
||||
if (use_color_pointer && (gl_state.array_pointers.color.size != 4 || gl_state.array_pointers.color.type != GL_UNSIGNED_BYTE)) {
|
||||
ERR("Unsupported Color Conifguration");
|
||||
}
|
||||
int use_texture = gl_state.texture_2d && gl_state.array_pointers.tex_coord.enabled;
|
||||
if (use_texture && (gl_state.array_pointers.tex_coord.size != 2 || gl_state.array_pointers.tex_coord.type != GL_FLOAT)) {
|
||||
ERR("Unsupported Texture Conifguration");
|
||||
}
|
||||
|
||||
// Load Shader
|
||||
GLuint program = get_shader();
|
||||
use_shader(program);
|
||||
|
||||
// Projection Matrix
|
||||
lazy_uniform(u_projection);
|
||||
matrix_t *p = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i];
|
||||
real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
||||
|
||||
// Model View Matrix
|
||||
lazy_uniform(u_model_view);
|
||||
p = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i];
|
||||
real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
||||
|
||||
// Has Texture
|
||||
lazy_uniform(u_has_texture); \
|
||||
real_glUniform1i()(u_has_texture_handle, use_texture); \
|
||||
|
||||
// Texture Matrix
|
||||
lazy_uniform(u_texture);
|
||||
p = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i];
|
||||
real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
||||
|
||||
// Texture Unit
|
||||
lazy_uniform(u_texture_unit);
|
||||
real_glUniform1i()(u_texture_unit_handle, 0);
|
||||
|
||||
// Alpha Test
|
||||
lazy_uniform(u_alpha_test);
|
||||
real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test);
|
||||
|
||||
// Color
|
||||
GLint a_color_handle = real_glGetAttribLocation()(program, "a_color");
|
||||
if (use_color_pointer) {
|
||||
real_glVertexAttribPointer()(a_color_handle, gl_state.array_pointers.color.size, gl_state.array_pointers.color.type, 1, gl_state.array_pointers.color.stride, gl_state.array_pointers.color.pointer);
|
||||
real_glEnableVertexAttribArray()(a_color_handle);
|
||||
} else {
|
||||
real_glVertexAttrib4f()(a_color_handle, gl_state.color.red, gl_state.color.green, gl_state.color.blue, gl_state.color.alpha);
|
||||
}
|
||||
|
||||
// Fog
|
||||
lazy_uniform(u_fog);
|
||||
real_glUniform1i()(u_fog_handle, gl_state.fog.enabled);
|
||||
if (gl_state.fog.enabled) {
|
||||
lazy_uniform(u_fog_color);
|
||||
real_glUniform4f()(u_fog_color_handle, gl_state.fog.color[0], gl_state.fog.color[1], gl_state.fog.color[2], gl_state.fog.color[3]);
|
||||
lazy_uniform(u_fog_is_linear);
|
||||
real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR);
|
||||
lazy_uniform(u_fog_start);
|
||||
real_glUniform1f()(u_fog_start_handle, gl_state.fog.start);
|
||||
lazy_uniform(u_fog_end);
|
||||
real_glUniform1f()(u_fog_end_handle, gl_state.fog.end);
|
||||
}
|
||||
|
||||
// Vertices
|
||||
GLint a_vertex_coords_handle = real_glGetAttribLocation()(program, "a_vertex_coords");
|
||||
real_glVertexAttribPointer()(a_vertex_coords_handle, gl_state.array_pointers.vertex.size, gl_state.array_pointers.vertex.type, 0, gl_state.array_pointers.vertex.stride, gl_state.array_pointers.vertex.pointer);
|
||||
real_glEnableVertexAttribArray()(a_vertex_coords_handle);
|
||||
|
||||
// Texture Coordinates
|
||||
GLint a_texture_coords_handle = real_glGetAttribLocation()(program, "a_texture_coords");
|
||||
if (use_texture) {
|
||||
real_glVertexAttribPointer()(a_texture_coords_handle, gl_state.array_pointers.tex_coord.size, gl_state.array_pointers.tex_coord.type, 0, gl_state.array_pointers.tex_coord.stride, gl_state.array_pointers.tex_coord.pointer);
|
||||
real_glEnableVertexAttribArray()(a_texture_coords_handle);
|
||||
} else {
|
||||
real_glVertexAttrib3f()(a_texture_coords_handle, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Draw
|
||||
real_glDrawArrays()(mode, first, count);
|
||||
|
||||
// Cleanup
|
||||
if (use_color_pointer) {
|
||||
real_glDisableVertexAttribArray()(a_color_handle);
|
||||
}
|
||||
real_glDisableVertexAttribArray()(a_vertex_coords_handle);
|
||||
if (use_texture) {
|
||||
real_glDisableVertexAttribArray()(a_texture_coords_handle);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "state.h"
|
||||
|
||||
// Matrix Common
|
||||
static void matrix_copy(matrix_t *src, matrix_t *dst) {
|
||||
memcpy((void *) dst->data, (void *) src->data, MATRIX_DATA_SIZE);
|
||||
}
|
||||
|
||||
// Identity Matrix
|
||||
static matrix_t identity_matrix = {
|
||||
.data = {
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1}
|
||||
}
|
||||
};
|
||||
static void init_matrix_stack(matrix_stack_t *stack) {
|
||||
matrix_copy(&identity_matrix, &stack->stack[0]);
|
||||
}
|
||||
__attribute__((constructor)) static void init_matrix_stacks() {
|
||||
init_matrix_stack(&gl_state.matrix_stacks.model_view);
|
||||
init_matrix_stack(&gl_state.matrix_stacks.projection);
|
||||
init_matrix_stack(&gl_state.matrix_stacks.texture);
|
||||
}
|
||||
|
||||
// Matrix Mode
|
||||
static matrix_stack_t *get_matrix_stack() {
|
||||
switch (gl_state.matrix_stacks.mode) {
|
||||
case GL_MODELVIEW: {
|
||||
return &gl_state.matrix_stacks.model_view;
|
||||
}
|
||||
case GL_PROJECTION: {
|
||||
return &gl_state.matrix_stacks.projection;
|
||||
}
|
||||
case GL_TEXTURE: {
|
||||
return &gl_state.matrix_stacks.texture;
|
||||
}
|
||||
default: {
|
||||
ERR("Unsupported Matrix Mode: %i", gl_state.matrix_stacks.mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Matrix Functions
|
||||
void glMatrixMode(GLenum mode) {
|
||||
gl_state.matrix_stacks.mode = mode;
|
||||
}
|
||||
void glPopMatrix() {
|
||||
get_matrix_stack()->i--;
|
||||
}
|
||||
void glLoadIdentity() {
|
||||
matrix_stack_t *stack = get_matrix_stack();
|
||||
matrix_copy(&identity_matrix, &stack->stack[stack->i]);
|
||||
}
|
||||
void glPushMatrix() {
|
||||
matrix_stack_t *stack = get_matrix_stack();
|
||||
matrix_copy(&stack->stack[stack->i], &stack->stack[stack->i + 1]);
|
||||
stack->i++;
|
||||
}
|
||||
void glMultMatrixf(const GLfloat *m) {
|
||||
matrix_t new_matrix;
|
||||
matrix_stack_t *stack = get_matrix_stack();
|
||||
matrix_t *current_matrix = &stack->stack[stack->i];
|
||||
for (int x = 0; x < MATRIX_SIZE; x++) {
|
||||
for (int y = 0; y < MATRIX_SIZE; y++) {
|
||||
GLfloat result = 0;
|
||||
for (int i = 0; i < MATRIX_SIZE; i++) {
|
||||
result += (current_matrix->data[i][y] * m[(x * MATRIX_SIZE) + i]);
|
||||
}
|
||||
new_matrix.data[x][y] = result;
|
||||
}
|
||||
}
|
||||
matrix_copy(&new_matrix, current_matrix);
|
||||
}
|
||||
void glScalef(GLfloat x, GLfloat y, GLfloat z) {
|
||||
GLfloat m[] = {
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0,
|
||||
0, 0, 0, 1
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
|
||||
GLfloat m[] = {
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
x, y, z, 1
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) {
|
||||
GLfloat m[] = {
|
||||
(2.f / (right - left)), 0, 0, 0,
|
||||
0, (2.f / (top - bottom)), 0, 0,
|
||||
0, 0, (-2.f / (far - near)), 0,
|
||||
-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), 1
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
#define DEG2RAD (M_PI / 180.f)
|
||||
void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
|
||||
// Normalize
|
||||
GLfloat length = sqrtf((x * x) + (y * y) + (z * z));
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
|
||||
// Values
|
||||
GLfloat angle_radians = angle * DEG2RAD;
|
||||
GLfloat c = cosf(angle_radians);
|
||||
GLfloat s = sinf(angle_radians);
|
||||
GLfloat x2 = x * x;
|
||||
GLfloat y2 = y * y;
|
||||
GLfloat z2 = z * z;
|
||||
|
||||
// Multiply
|
||||
GLfloat m[] = {
|
||||
x2 * (1.f - c) + c, (x * y) * (1.f - c) + (z * s), (x * z) * (1.f - c) - (y * s), 0,
|
||||
(x * y) * (1.f - c) - (z * s), y2 * (1.f - c) + c, (y * z) * (1.f - c) + (x * s), 0,
|
||||
(x * z) * (1.f - c) + (y * s), (y * z) * (1.f - c) - (x * s), z2 * (1.f - c) + c, 0,
|
||||
0, 0, 0, 1.f
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue