Compare commits

...

17 Commits

Author SHA1 Message Date
00f8ed4752 2.3.0
Some checks failed
minecraft-pi-reborn/pipeline/head There was a failure building this commit
2022-03-11 20:34:50 -05:00
0fd8ba7de9 Improve AppImages & Safer OpenAL 2022-03-11 20:02:38 -05:00
07baea7b5a Vendor Zenity For AppImages 2022-03-11 00:00:13 -05:00
8792e5749d Remove Broken WebKit Exclusion 2022-03-10 21:05:33 -05:00
53b2c20b8b Fix More AppImage Bugs 2022-03-09 23:29:37 -05:00
244a69d1aa Move CI Dockerfile 2022-03-09 22:54:30 -05:00
a1f777f632 Add MCPI_DEBUG & Improve Documentation 2022-03-09 22:40:21 -05:00
5d8a1e4230 Small Debug Fixes 2022-03-09 22:08:47 -05:00
742ead51e1 Vendor GLFW 2022-03-09 21:23:41 -05:00
c33a27b2ea AppImage! 2022-03-09 18:47:31 -05:00
c1377d4f2a Add "Disable Hosting LAN Worlds" 2022-03-07 17:03:03 -05:00
e0ebc7fc32 Fix Furnace Not Checking Item Auxiliary 2022-03-06 22:43:42 -05:00
0fcda17120 (Hopefully) Improve CI Speed 2022-03-06 20:46:18 -05:00
e9e9b90bdb Use Ninja 2022-03-06 20:13:41 -05:00
0fd562af40 Allow Disabling Raw Mouse Motion 2022-03-06 20:07:49 -05:00
1eb06b6b60 Add Back ~/.minecraft-pi/mods & Fix Segmentation Fault With Media Layer Proxy 2022-03-06 18:22:28 -05:00
c6983ac6c5 Improve Build System + Use GCC (Clang Is Just Too Broken) 2022-03-06 15:53:27 -05:00
72 changed files with 1014 additions and 590 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@ debian/tmp
build
CMakeLists.txt.user
*.autosave
AppImageBuilder.yml
appimage-builder-cache
AppDir
*.zsync

8
.gitmodules vendored
View File

@ -6,3 +6,11 @@
path = dependencies/zlib/src
url = https://github.com/madler/zlib.git
shallow = true
[submodule "dependencies/glfw/src"]
path = dependencies/glfw/src
url = https://github.com/glfw/glfw.git
shallow = true
[submodule "dependencies/zenity/src"]
path = dependencies/zenity/src
url = https://gitea.thebrokenrail.com/TheBrokenRail/zenity.git
shallow = true

View File

@ -7,6 +7,7 @@ option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
set(MCPI_BUILD_MODE "both" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code; \"both\" = Build All Code As ARM")
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
option(MCPI_OPEN_SOURCE_ONLY "Only Install Open-Source Code (Will Result In Broken Install)" FALSE)
option(MCPI_IS_APPIMAGE_BUILD "AppImage Build" FALSE)
# Configure Build Mode
if(MCPI_BUILD_MODE STREQUAL "arm")
@ -25,14 +26,6 @@ else()
message(FATAL_ERROR "Invalid Mode")
endif()
# Use Clang By Default
if(NOT DEFINED CMAKE_C_COMPILER)
set(CMAKE_C_COMPILER "clang")
endif()
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_CXX_COMPILER "clang++")
endif()
# Utility Functions
include(cmake/util.cmake)
@ -47,18 +40,13 @@ endif()
# Specify Installation Paths
set(MCPI_INSTALL_DIR "lib/${MCPI_VARIANT_NAME}")
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
set(MCPI_BIN_DIR "${MCPI_INSTALL_DIR}/bin")
set(MCPI_FALLBACK_LIB_DIR "${MCPI_INSTALL_DIR}/fallback-lib")
# Optimizations
# 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)
endif()
# Start Project
project(minecraft-pi-reborn)
@ -73,6 +61,13 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "" FORCE)
endif()
# Optimizations
if(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-O3)
else()
add_compile_options(-g)
endif()
# Use LLD When Using Clang
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_link_options("-fuse-ld=lld")
@ -81,10 +76,11 @@ endif()
# PIC
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
# Buld LibPNG + ZLib + Download Minecraft: Pi Edition
if(BUILD_ARM_COMPONENTS)
add_subdirectory(dependencies)
endif()
# Fast Math
add_compile_options(-ffast-math)
# Buld Dependencies
add_subdirectory(dependencies)
# Warnings
add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
@ -93,9 +89,6 @@ add_definitions(-D_GNU_SOURCE)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
# Fast Math
add_compile_options(-ffast-math)
# Specify Constants
if(MCPI_SERVER_MODE)
add_definitions(-DMCPI_SERVER_MODE)
@ -103,6 +96,9 @@ endif()
if(MCPI_HEADLESS_MODE)
add_definitions(-DMCPI_HEADLESS_MODE)
endif()
if(MCPI_IS_APPIMAGE_BUILD)
add_definitions(-DMCPI_IS_APPIMAGE_BUILD)
endif()
# Version
file(STRINGS VERSION VERSION)

View File

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

4
Jenkinsfile vendored
View File

@ -4,7 +4,7 @@ pipeline {
stage('Debian Bullseye') {
agent {
docker {
image 'debian:bullseye'
filename 'scripts/ci/Dockerfile'
args '-v /var/run/docker.sock:/var/run/docker.sock'
}
}
@ -15,7 +15,7 @@ pipeline {
}
post {
success {
archiveArtifacts artifacts: 'out/*.deb', fingerprint: true
archiveArtifacts artifacts: 'out/*.AppImage*', fingerprint: true
}
}
}

View File

@ -1 +1 @@
2.2.11
2.3.0

View File

@ -1,122 +1,11 @@
# Sanity Check Return
function(sanity_check_return ret)
if(NOT ret EQUAL "0")
message(FATAL_ERROR "Process Failed")
endif()
endfunction()
# Get Host Architecture
find_program(UNAME uname /bin /usr/bin /usr/local/bin REQUIRED)
execute_process(
COMMAND "${UNAME}" "-m"
OUTPUT_VARIABLE HOST_ARCHITECTURE
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE ret
)
sanity_check_return("${ret}")
# Get Include Directories
function(get_include_dirs target compiler result)
# Get Tool Name
set(tool "cc1")
if(compiler MATCHES "^.*g\\+\\+$")
set(tool "cc1plus")
endif()
# Get Tool Path
execute_process(
COMMAND "${compiler}" "-print-prog-name=${tool}"
ERROR_QUIET
OUTPUT_VARIABLE tool
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE ret
)
sanity_check_return("${ret}")
# Run Tool To Get Include Path
set(tool_output "")
execute_process(
COMMAND "${tool}" "-quiet" "-v" "-imultiarch" "${target}"
OUTPUT_QUIET
ERROR_VARIABLE tool_output
ERROR_STRIP_TRAILING_WHITESPACE
INPUT_FILE "/dev/null"
RESULT_VARIABLE ret
)
sanity_check_return("${ret}")
string(REPLACE "\n" ";" tool_output "${tool_output}")
# Loop
set(parsing_include_section FALSE)
foreach(line IN LISTS tool_output)
# Check Include Section Status
if(parsing_include_section)
# Check If Include Section Is Over
if(line MATCHES "^End of search list.$")
# Starting Include Section
set(parsing_include_section FALSE)
break()
else()
# Parsing Include Section
if(line MATCHES "^ .*$")
# Strip Line
string(STRIP "${line}" line)
# Add To List
list(APPEND "${result}" "${line}")
endif()
endif()
else()
# Check If Include Section Is Starting
if(line MATCHES "^#include <\\.\\.\\.> search starts here:$")
# Starting Include Section
set(parsing_include_section TRUE)
endif()
endif()
endforeach()
# Return
set("${result}" "${${result}}" PARENT_SCOPE)
endfunction()
# Setup Include Directories
function(setup_include_dirs compiler target result)
# Get Full Compiler
set(full_compiler "${target}-${compiler}")
# Get Include Directories
set(include_dirs "")
get_include_dirs("${target}" "${full_compiler}" include_dirs)
# Loop
set(flags "")
foreach(include_dir IN LISTS include_dirs)
set(flags "${flags} -isystem ${include_dir}")
endforeach()
# Return
set("${result}" "${${result}} ${flags}" PARENT_SCOPE)
endfunction()
# Setup Toolchain
macro(setup_toolchain target)
# Use ARM Cross-Compiler
set(CMAKE_C_COMPILER "clang")
set(CMAKE_C_COMPILER_TARGET "${target}")
set(CMAKE_CXX_COMPILER "clang++")
set(CMAKE_CXX_COMPILER_TARGET "${target}")
set(CMAKE_C_COMPILER "${target}-gcc")
set(CMAKE_CXX_COMPILER "${target}-g++")
set(CMAKE_FIND_ROOT_PATH "/usr/${target}" "/usr/lib/${target}")
# Flags
string(CONCAT NEW_FLAGS
"-nostdinc "
"-nostdinc++ "
"-Wno-unused-command-line-argument"
)
set(CMAKE_C_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} ${NEW_FLAGS}")
set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} ${NEW_FLAGS}")
# Include Directories
setup_include_dirs("gcc" "${target}" CMAKE_C_FLAGS_INIT)
setup_include_dirs("g++" "${target}" CMAKE_CXX_FLAGS_INIT)
# Extra
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# pkg-config
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/${target}/pkgconfig:/usr/${target}/lib/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig")
endmacro()

7
debian/client-amd64 vendored
View File

@ -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: libc6, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1, qemu-user

7
debian/client-arm64 vendored
View File

@ -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: arm64
Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1

7
debian/client-armhf vendored
View File

@ -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: libc6, libstdc++6, zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libopenal1

7
debian/server-amd64 vendored
View File

@ -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, libstdc++6, libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user

7
debian/server-arm64 vendored
View File

@ -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: arm64
Depends: libc6, libstdc++6, libc6:armhf, libstdc++6:armhf

7
debian/server-armhf vendored
View File

@ -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: armhf
Depends: libc6, libstdc++6

View File

@ -1,10 +1,22 @@
project(dependencies)
# ZLib
add_subdirectory(zlib)
if(BUILD_ARM_COMPONENTS)
add_subdirectory(zlib)
endif()
# LibPNG
add_subdirectory(libpng)
if(BUILD_ARM_COMPONENTS)
add_subdirectory(libpng)
endif()
# Minecraft: Pi Edition
if(NOT MCPI_OPEN_SOURCE_ONLY)
if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
add_subdirectory(minecraft-pi)
endif()
# GLFW
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
add_subdirectory(glfw)
endif()
# Zenity (Minimal Build)
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
add_subdirectory(zenity)
endif()

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

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

1
dependencies/glfw/src vendored Submodule

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

15
dependencies/zenity/CMakeLists.txt vendored Normal file
View File

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

1
dependencies/zenity/src vendored Submodule

@ -0,0 +1 @@
Subproject commit 4663a8656d8c12be00286ee10aae2ff55ff589af

View File

@ -1,23 +1,5 @@
# 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_HEADLESS_MODE``
* ``ON`` (Default In Server Mode): Enable Headless Mode
* ``OFF`` (Default In Client Mode): Disable Headless Mode
* ``MCPI_USE_MEDIA_LAYER_PROXY``
* ``ON``: Enable The Media Layer Proxy
* ``OFF`` (Default): Disable The Media Layer Proxy
* ``MCPI_OPEN_SOURCE_ONLY``
* ``ON``: Only Install Open-Source Code (Will Result In Broken Install)
* ``OFF`` (Default): Install All Code
## Build Dependencies
* Common
* ARM Compiler
@ -40,37 +22,13 @@
* OpenAL
* Zenity
## Two-Step Build
Use this when the host architecture is not ARM.
## Instructions
```sh
# Create Build Directory
mkdir build && cd build
# Build ARM Components
mkdir arm && cd arm
cmake -DCMAKE_TOOLCHAIN_FILE=../../cmake/armhf-toolchain.cmake -DMCPI_BUILD_MODE=arm ../..
make -j$(nproc) && sudo make install
cd ../
# Build Native Components
mkdir native && cd native
cmake -DMCPI_BUILD_MODE=native ../..
make -j$(nproc) && sudo make install
cd ../../
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
```
This will most likely not compile by itself. You will want to enable either server mode or the Media Layer Proxy.
## One-Step Build
Use this when the host architecture is ARM.
### Custom CMake Arguments
```sh
# Create Build Directory
mkdir build && cd build
# Build
cmake ..
make -j$(nproc) && sudo make install
cd ../
./scripts/setup.sh <client|server> <armhf|arm64|i686|amd64> <Custom CMake Arguments>
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
```

View File

@ -1,7 +1,19 @@
# Changelog
**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
* Improve Build System
* Improve Documentation
**2.2.11**
* Add "Close Current Screen On Death" Feature Flag (Enabled By Default) To Prevent Bugs
* 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**
@ -12,8 +24,8 @@
* Store Files In `/usr/lib`
**2.2.8**
* Add "Hide Chat Messages" Optional Feature Flag
* Add "Remove Creative Mode Restrictions" Optional Feature Flag
* 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
@ -51,7 +63,7 @@
**2.2.0**
* Sound Support
* Split Off "Allow Joining Survival Servers" From Game-Mode Mod
* 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

View File

@ -1,16 +1,39 @@
# 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
### ``--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:
```
TRUE This Flag Is On By Default
FALSE This Flag Is Off By Default
```
## ``--only-generate`` (Server Mode Only)
### ``--only-generate`` (Server Mode Only)
If you run MCPI-Reborn with ``--only-generate``, it will immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
## ``--benchmark`` (Client Mode Only)
### ``--benchmark`` (Client Mode Only)
If you run MCPI-Reborn with ``--benchmark``, it will 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.
## Environmental Variables
### ``MCPI_DEBUG``
This enables debug logging if you set it to any non-zero-length value.
### Client Mode Only
If a value isn't set for any of the following variables, a GUI will open that allows you to select one.
### ``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.

View File

@ -1,10 +1,6 @@
# Manual Installation
[Download Packages Here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/)
## Supported Distributions
* Ubuntu 20.04+
* Debian Bullseye+
## Picking A Package
### Name Format

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -14,5 +14,12 @@ if(BUILD_NATIVE_COMPONENTS)
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
if(NOT MCPI_SERVER_MODE)
install(DIRECTORY "client-data/" DESTINATION ".")
else()
set(ICON_PATH "share/icons/hicolor/scalable/apps")
install(
FILES "client-data/${ICON_PATH}/com.thebrokenrail.MCPIReborn.png"
DESTINATION "${ICON_PATH}"
RENAME "com.thebrokenrail.MCPIRebornServer.png"
)
endif()
endif()

View File

@ -29,3 +29,6 @@ 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
FALSE Disable Hosting LAN Worlds

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Name=Minecraft: Pi Edition: Reborn
Comment=Fun with Blocks
Icon=minecraft-pi-reborn-client
Icon=com.thebrokenrail.MCPIReborn
StartupNotify=false
StartupWMClass=Minecraft: Pi Edition: Reborn
Exec=minecraft-pi-reborn-client

View File

@ -31,14 +31,16 @@ static void trim(char **value) {
*value = &(*value)[1];
}
}
static void set_and_print_env(const char *name, char *value) {
void set_and_print_env(const char *name, char *value) {
// Set Variable With No Trailing Colon
trim(&value);
static const char *unmodified_name_prefix = "MCPI_";
if (strncmp(unmodified_name_prefix, name, strlen(unmodified_name_prefix)) != 0) {
trim(&value);
}
#ifdef DEBUG
// Print New Value
INFO("Set %s = %s", name, value);
#endif
DEBUG("Set %s = %s", name, value);
// Set The Value
setenv(name, value, 1);
}
@ -134,71 +136,27 @@ 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...");
// Pre-Bootstrap
void pre_bootstrap() {
// AppImage
#ifdef MCPI_IS_APPIMAGE_BUILD
char *owd = getenv("OWD");
if (owd != NULL && chdir(owd) != 0) {
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
}
#endif
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Configure LD_LIBRARY_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_LIBRARY_PATH
{
char *value = get_env_safe("LD_LIBRARY_PATH");
if (strlen(value) > 0) {
string_append(&new_ld_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);
}
// Configure LD_PRELOAD
{
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
char *new_ld_preload = NULL;
safe_asprintf(&new_ld_preload, "%s", get_env_safe("LD_PRELOAD"));
// 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);
// Set LD_PRELOAD
set_and_print_env("LD_PRELOAD", new_ld_preload);
free(new_ld_preload);
}
// Configure PATH
{
// Add Library Directory
char *new_path;
safe_asprintf(&new_path, "%s/lib", binary_directory);
safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH
{
char *value = get_env_safe("PATH");
@ -211,40 +169,181 @@ void bootstrap(int argc, char *argv[]) {
free(new_path);
}
// Start Game
INFO("%s", "Starting Game...");
// Free Binary Directory
free(binary_directory);
}
// Use Correct LibC
#ifndef __ARM_ARCH
setenv("QEMU_LD_PREFIX", "/usr/arm-linux-gnueabihf", 1);
// Bootstrap
void bootstrap(int argc, char *argv[]) {
INFO("%s", "Configuring Game...");
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Handle AppImage
char *usr_prefix = NULL;
#ifdef MCPI_IS_APPIMAGE_BUILD
usr_prefix = getenv("APPDIR");
#endif
if (usr_prefix == NULL) {
usr_prefix = "";
}
// Configure LD_LIBRARY_PATH
{
// Preserve
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_LIBRARY_PATH");
char *new_ld_path = NULL;
// Add Library Directory
safe_asprintf(&new_ld_path, "%s/lib", binary_directory);
// Add MCPI_LD_LIBRARY_PATH
{
char *value = get_env_safe("MCPI_LD_LIBRARY_PATH");
if (strlen(value) > 0) {
string_append(&new_ld_path, ":%s", value);
}
}
// Add LD_LIBRARY_PATH (ARM32 Only)
#ifdef __arm__
{
char *value = get_env_safe("LD_LIBRARY_PATH");
if (strlen(value) > 0) {
string_append(&new_ld_path, ":%s", value);
}
}
#endif
// Create Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_NAME, binary_directory);
// Load ARM Libraries (Ensure Priority)
string_append(&new_ld_path, ":%s/usr/lib/arm-linux-gnueabihf:%s/usr/arm-linux-gnueabihf/lib", usr_prefix, usr_prefix);
// 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);
}
// Configure LD_PRELOAD
{
// Preserve
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
char *new_ld_preload = NULL;
// Built-In Mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
// Load Mods From ./mods
load(&new_ld_preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// ~/.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(&new_ld_preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Add MCPI_LD_PRELOAD
{
char *value = get_env_safe("MCPI_LD_PRELOAD");
if (strlen(value) > 0) {
string_append(&new_ld_preload, ":%s", value);
}
}
// Add LD_PRELOAD (ARM32 Only)
#ifdef __arm__
{
char *value = get_env_safe("MCPI_LD_PRELOAD");
if (strlen(value) > 0) {
string_append(&new_ld_preload, ":%s", value);
}
}
#endif
// Set LD_PRELOAD
set_and_print_env("LD_PRELOAD", new_ld_preload);
free(new_ld_preload);
}
// Resolve Binary Path & Set MCPI_DIRECTORY
{
// Resolve Full Binary Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
char *resolved_path = realpath(full_path, NULL);
ALLOC_CHECK(resolved_path);
free(full_path);
// Set MCPI_EXECUTABLE_PATH
set_and_print_env("MCPI_EXECUTABLE_PATH", resolved_path);
// Set MCPI_DIRECTORY
chop_last_component(&resolved_path);
set_and_print_env("MCPI_DIRECTORY", resolved_path);
free(resolved_path);
}
// Free Binary Directory
free(binary_directory);
#ifdef __ARM_ARCH
// Mark argc As Used
(void) argc;
// Run
safe_execvpe(full_path, argv, environ);
#else
// Start Game
INFO("%s", "Starting Game...");
// Arguments
int argv_start = 2; // argv = &new_args[argv_start]
char *new_args[argv_start /* 2 Potential Prefix Arguments (QEMU And Linker) */ + argc + 1 /* NULL-Terminator */]; //
// Copy Existing Arguments
for (int i = 1; i < argc; i++) {
new_args[i + argv_start] = argv[i];
}
// NULL-Terminator
new_args[argv_start + argc] = NULL;
// Set Executable Argument
new_args[argv_start] = getenv("MCPI_EXECUTABLE_PATH");
// Non-ARM32 Systems Need Manually Specified Linker
#ifndef __arm__
argv_start--;
char *linker = NULL;
safe_asprintf(&linker, "%s/usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3", usr_prefix);
new_args[argv_start] = linker;
// Non-ARM Systems Need QEMU
#ifndef __ARM_ARCH
argv_start--;
new_args[argv_start] = QEMU_BINARY;
// Prevent QEMU From Being Modded
PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU("LD_LIBRARY_PATH");
PASS_ENVIRONMENTAL_VARIABLE_TO_QEMU("LD_PRELOAD");
// Use QEMU
#define EXE_INTERPRETER "qemu-arm"
// Create Arguments List
char *new_argv[argc + 2];
for (int i = 1; i <= argc; i++) {
new_argv[i + 1] = argv[i];
}
new_argv[0] = NULL; // Updated By safe_execvpe()
new_argv[1] = full_path; // Path To MCPI
// Run
safe_execvpe(EXE_INTERPRETER, new_argv, environ);
#endif
#endif
// Run
char **new_argv = &new_args[argv_start];
safe_execvpe(new_argv[0], new_argv, environ);
}

View File

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

View File

@ -92,7 +92,7 @@ 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);
}
// Check Return Code
if (return_code != 0) {
@ -121,6 +121,9 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
// Launch
int main(int argc, char *argv[]) {
// Pre-Bootstrap
pre_bootstrap();
// Print Features
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--print-available-feature-flags") == 0) {

View File

@ -37,7 +37,10 @@ char *get_full_library_search_path() {
output.pop_back();
}
// Close Process
pclose(file);
int ret = WEXITSTATUS(pclose(file));
if (ret != 0) {
ERR("ldconfig Failed: Exit Code: %i", ret);
}
// Return
char *output_str = strdup(output.c_str());
ALLOC_CHECK(output_str);

View File

@ -1,6 +1,17 @@
#include <stdlib.h>
#include <unistd.h>
#include "../bootstrap.h"
int main(int argc, char *argv[]) {
// Pre-Bootstrap
pre_bootstrap();
// 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);
}

View File

@ -4,7 +4,7 @@ add_library(reborn-headers INTERFACE)
target_include_directories(reborn-headers INTERFACE include)
if(BUILD_ARM_COMPONENTS)
add_library(reborn SHARED src/reborn.c)
add_library(reborn SHARED src/patch.c)
target_link_libraries(reborn dl reborn-headers)
target_compile_definitions(reborn PUBLIC -DREBORN_HAS_COMPILED_CODE)
# Install

View File

@ -13,7 +13,7 @@
typedef void (*text_section_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
static inline void iterate_text_sections(text_section_callback_t callback, void *data) {
// Load Main Binary
FILE *file_obj = fopen("/proc/self/exe", "rb");
FILE *file_obj = fopen(getenv("MCPI_EXECUTABLE_PATH"), "rb");
// Verify Binary
if (!file_obj) {

View File

@ -19,6 +19,18 @@ __attribute__((noreturn)) static inline void safe_execvpe(const char *pathname,
ERR("%s", "Unknown execvpe() Error");
}
}
// Chop Off Last Component
static inline 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)
static inline char *get_binary_directory() {
// Get Path To Current Executable
@ -26,17 +38,12 @@ static inline char *get_binary_directory() {
ALLOC_CHECK(exe);
// Chop Off Last Component
int length = strlen(exe);
for (int i = length - 1; i >= 0; i--) {
if (exe[i] == '/') {
exe[i] = '\0';
break;
}
}
chop_last_component(&exe);
// 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
@ -49,3 +56,8 @@ __attribute__((noreturn)) static inline void safe_execvpe_relative_to_binary(con
// Run
safe_execvpe(full_path, argv, envp);
}
// Get MCPI Directory
static inline char *get_mcpi_directory() {
return getenv("MCPI_DIRECTORY");
}

View File

@ -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

View File

@ -1,36 +1,9 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "log.h"
#include "util.h"
#include "string.h"
#include "exec.h"
#include "elf.h"
#ifdef REBORN_HAS_COMPILED_CODE
// 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[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 __arm__
#ifdef __cplusplus
}
#endif
#include "home.h"
#include "patch.h"

View File

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

View File

@ -0,0 +1,30 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Patching Functions
#ifdef REBORN_HAS_COMPILED_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 _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 REBORN_HAS_COMPILED_CODE
#ifdef __cplusplus
}
#endif

View File

@ -79,9 +79,7 @@ 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");
@ -138,11 +136,7 @@ void _overwrite(const char *file, int line, void *start, void *target) {
}
// 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[4]) {

View File

@ -22,8 +22,6 @@ if(TARGET media-layer-core)
# Link
target_link_libraries(media-layer-core media-layer-headers reborn-headers pthread dl)
if(NOT MCPI_HEADLESS_MODE)
# Find GLFW
find_package(glfw3 3.3 REQUIRED)
# Find FreeImage
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
# OpenAL

View File

@ -15,11 +15,12 @@ static std::vector<ALuint> &get_sources() {
return sources;
}
#define AL_ERROR_CHECK() \
#define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError())
#define AL_ERROR_CHECK_MANUAL(val) \
{ \
ALenum err = alGetError(); \
if (err != AL_NO_ERROR) { \
ERR("OpenAL Error: %s", alGetString(err)); \
ALenum __err = val; \
if (__err != AL_NO_ERROR) { \
ERR("OpenAL Error: %s", alGetString(__err)); \
} \
}
@ -81,7 +82,15 @@ void media_audio_play(const char *source, const char *name, float x, float y, fl
// Create Source
ALuint al_source;
alGenSources(1, &al_source);
AL_ERROR_CHECK();
// Special Out-Of-Memory Handling
{
ALenum err = alGetError();
if (err == AL_OUT_OF_MEMORY) {
return;
} else {
AL_ERROR_CHECK_MANUAL(err);
}
}
// Set Properties
alSourcef(al_source, AL_PITCH, pitch);

View File

@ -27,7 +27,7 @@ void media_set_interactable(int toggle) {
// GLFW Code Not Needed In Headless Mode
#ifndef MCPI_HEADLESS_MODE
static GLFWwindow *glfw_window;
static GLFWwindow *glfw_window = NULL;
// Handle GLFW Error
static void glfw_error(__attribute__((unused)) int error, const char *description) {
@ -146,7 +146,7 @@ static SDLMod glfw_modifier_to_sdl_modifier(int mods) {
}
// Pass Key Presses To SDL
static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int scancode, int action, __attribute__((unused)) int mods) {
static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int scancode, int action, int mods) {
if (is_interactable) {
SDL_Event event;
int up = action == GLFW_RELEASE;
@ -227,6 +227,20 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
// Track Media Layer State
static int is_running = 0;
// Track If Raw Mouse Motion Is Enabled
static int raw_mouse_motion_enabled = 1;
void media_set_raw_mouse_motion_enabled(int enabled) {
raw_mouse_motion_enabled = enabled;
#ifndef MCPI_HEADLESS_MODE
if (is_running) {
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE);
}
#endif // #ifndef MCPI_HEADLESS_MODE
if (!raw_mouse_motion_enabled) {
WARN("%s", "Raw mouse motion has been DISABLED, this IS NOT recommended, and should only ever be used on systems that don't support or have broken raw mouse motion.");
}
}
// Disable V-Sync
static int disable_vsync = 0;
void media_disable_vsync() {
@ -409,7 +423,7 @@ static void update_cursor() {
glfwSetInputMode(glfw_window, GLFW_CURSOR, new_mode);
// Handle Cursor Lock/Unlock
if ((new_mode == GLFW_CURSOR_DISABLED && old_mode != GLFW_CURSOR_DISABLED) || (new_mode != GLFW_CURSOR_DISABLED && old_mode == GLFW_CURSOR_DISABLED)) {
if (raw_mouse_motion_enabled && ((new_mode == GLFW_CURSOR_DISABLED && old_mode != GLFW_CURSOR_DISABLED) || (new_mode != GLFW_CURSOR_DISABLED && old_mode == GLFW_CURSOR_DISABLED))) {
// Use Raw Mouse Motion
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, new_mode == GLFW_CURSOR_DISABLED ? GLFW_TRUE : GLFW_FALSE);
}

View File

@ -17,6 +17,7 @@ void media_cleanup();
void media_get_framebuffer_size(int *width, int *height);
void media_set_interactable(int is_interactable);
void media_disable_vsync();
void media_set_raw_mouse_motion_enabled(int enabled);
#ifdef __cplusplus
}

View File

@ -12,7 +12,7 @@ if(BUILD_NATIVE_COMPONENTS)
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-headers ${MEDIA_LAYER_PROXY_LIBS})
target_compile_definitions(media-layer-proxy-client PRIVATE -DMEDIA_LAYER_PROXY_CLIENT)
# Install
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_LIB_DIR}")
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}")
endif()
if(BUILD_ARM_COMPONENTS)

View File

@ -32,6 +32,7 @@ static void sigusr1_handler(__attribute__((unused)) int sig) {
void _check_proxy_state() {
// Check Server State
if (!parent_is_alive) {
void_write_cache(); // Parent Is Dead, No Reason To Send A Dead Process Data
PROXY_ERR("%s", "Server Terminated");
}
}

View File

@ -10,8 +10,6 @@
_check_proxy_state(); \
if (!is_connection_open()) { \
PROXY_ERR("%s", "Attempting To Access Closed Connection"); \
} else { \
_check_proxy_state(); \
} \
}
void safe_read(void *buf, size_t len) {
@ -63,27 +61,30 @@ void safe_write(void *buf, size_t len) {
}
// Flush Write Cache
void flush_write_cache() {
// Check Connection
if (!is_connection_open()) {
// Connection Closed
return;
}
// Check Cache
if (_write_cache == NULL || _write_cache_position < 1) {
// Nothing To Write
return;
}
// Write
// Check Connection
if (!is_connection_open()) {
// Connection Closed
return;
}
// Write & Reset
size_t to_write = _write_cache_position;
size_t old_write_cache_position = _write_cache_position;
_write_cache_position = 0;
while (to_write > 0) {
CHECK_CONNECTION();
ssize_t x = write(get_connection_write(), (void *) (((unsigned char *) _write_cache) + (_write_cache_position - to_write)), to_write);
ssize_t x = write(get_connection_write(), (void *) (((unsigned char *) _write_cache) + (old_write_cache_position - to_write)), to_write);
if (x == -1 && errno != EINTR) {
PROXY_ERR("Failed Writing Data To Connection: %s", strerror(errno));
}
to_write -= x;
}
// Reset
}
void void_write_cache() {
_write_cache_position = 0;
}

View File

@ -29,6 +29,7 @@ extern "C" {
__attribute__((visibility("internal"))) void safe_read(void *buf, size_t len);
__attribute__((visibility("internal"))) void safe_write(void *buf, size_t len);
__attribute__((visibility("internal"))) void flush_write_cache();
__attribute__((visibility("internal"))) void void_write_cache();
// Read/Write 32-Bit Integers
__attribute__((visibility("internal"))) uint32_t read_int();

View File

@ -336,3 +336,20 @@ CALL(63, media_disable_vsync, void, ()) {
media_disable_vsync();
#endif
}
CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_int(enabled);
// Release Proxy
end_proxy_call();
#else
int enabled = read_int();
// Run
media_set_raw_mouse_motion_enabled(enabled);
#endif
}

View File

@ -25,6 +25,7 @@ static void update_client_state(int is_alive, int status) {
void _check_proxy_state() {
// Check Client State
if (!_client_is_alive) {
void_write_cache(); // Child Is Dead, No Reason To Send A Dead Process Data
if (WIFEXITED(_client_status)) {
PROXY_ERR("Client Terminated: Exit Code: %i", WEXITSTATUS(_client_status));
} else if (WIFSIGNALED(_client_status)) {

View File

@ -34,7 +34,7 @@ if(BUILD_ARM_COMPONENTS)
# MCPI Depends On GLESv2, But Uses GLESv1_CM
install_symlink("libGLESv1_CM.so.1" "${MCPI_LIB_DIR}/libGLESv2.so")
# Prevent MCPI From Linking To The Legacy GL Driver When Directly Linking To GL
# Prevent MCPI From Linking To The Legacy GL Driver When Directly Linking To GL (RPI-Specific)
if(NOT MCPI_HEADLESS_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY)
# Symlinks
install_symlink("/usr/lib/arm-linux-gnueabihf/libEGL.so.1" "${MCPI_LIB_DIR}/libEGL.so")

View File

@ -29,7 +29,7 @@ static char *run_command(char *command, int *return_code) {
}
// Return
*return_code = pclose(out);
*return_code = WEXITSTATUS(pclose(out));
return output;
}

View File

@ -29,8 +29,10 @@ int feature_has(const char *name, int server_default) {
tok = strtok(NULL, "|");
}
free(features);
#ifdef DEBUG
INFO("Feature: %s: %s", name, ret ? "Enabled" : "Disabled");
#endif
// Log
DEBUG("Feature: %s: %s", name, ret ? "Enabled" : "Disabled");
// Return
return ret;
}

View File

@ -1,46 +1,17 @@
#include <errno.h>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include "home.h"
#include "../init/init.h"
// Minecraft Pi User Data Root
#ifndef MCPI_SERVER_MODE
// Store Game Data In "~/.minecraft-pi" Instead Of "~/.minecraft" To Avoid Conflicts
#define NEW_PATH "/.minecraft-pi"
#else
// Store Game Data In Launch Directory
#define NEW_PATH ""
// Store Launch Directory
__attribute__((constructor)) static char *get_launch_directory() {
static char *launch_directory = NULL;
if (launch_directory == NULL) {
launch_directory = getcwd(NULL, 0);
}
return launch_directory;
}
__attribute__((destructor)) static void free_launch_directory() {
free(get_launch_directory());
}
// Pretend $HOME Is Launch Directory
HOOK(getenv, char *, (const char *name)) {
if (strcmp(name, "HOME") == 0) {
return get_launch_directory();
} else {
ensure_getenv();
return (*real_getenv)(name);
}
}
#endif
// Get MCPI Home Directory
char *home_get() {
static char *dir = NULL;
// Load
if (dir == NULL) {
safe_asprintf(&dir, "%s" NEW_PATH, getenv("HOME"));
safe_asprintf(&dir, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA, getenv("HOME"));
}
// Return
return dir;
@ -53,12 +24,13 @@ __attribute__((destructor)) static void _free_home() {
// Init
void init_home() {
// Store Data In ~/.minecraft-pi Instead Of ~/.minecraft
patch_address((void *) default_path, (void *) NEW_PATH);
patch_address((void *) default_path, (void *) HOME_SUBDIRECTORY_FOR_GAME_DATA);
// Change Directory To Binary Directory Manually
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0xe0ac, nop_patch);
char *binary_directory = get_binary_directory();
chdir(binary_directory);
free(binary_directory);
char *binary_directory = get_mcpi_directory();
if (chdir(binary_directory) != 0) {
ERR("Unable To Change Directory: %s", strerror(errno));
}
}

View File

@ -2,6 +2,7 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <media-layer/core.h>
#include "../feature/feature.h"
#include "../init/init.h"
@ -46,4 +47,9 @@ void init_input() {
// Allow Attacking Mobs
_init_attack();
// Disable Raw Mouse Motion
if (feature_has("Disable Raw Mouse Motion (Not Recommended)", 9)) {
media_set_raw_mouse_motion_enabled(0);
}
}

View File

@ -145,6 +145,40 @@ static void LocalPlayer_die_injection(unsigned char *entity, unsigned char *caus
(*LocalPlayer_die)(entity, cause);
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
static int32_t FurnaceScreen_handleAddItem_injection(unsigned char *furnace_screen, int32_t slot, ItemInstance const *item) {
// Get Existing Item
unsigned char *tile_entity = *(unsigned char **) (furnace_screen + FurnaceScreen_tile_entity_property_offset);
unsigned char *tile_entity_vtable = *(unsigned char **) tile_entity;
FurnaceTileEntity_getItem_t FurnaceTileEntity_getItem = *(FurnaceTileEntity_getItem_t *) (tile_entity_vtable + FurnaceTileEntity_getItem_vtable_offset);
ItemInstance *existing_item = (*FurnaceTileEntity_getItem)(tile_entity, slot);
// Check Item
int valid;
if (item->id == existing_item->id && item->auxiliary == existing_item->auxiliary) {
// Item Matches, Is Valid
valid = 1;
} else {
// Item Doesn't Match, Check If Existing Item Is Empty
if ((existing_item->id | existing_item->count | existing_item->auxiliary) == 0) {
// Existing Item Is Empty, Is Valid
valid = 1;
} else {
// Existing Item Isn't Empty, Isn't Valid
valid = 0;
}
}
// Call Original Method
if (valid) {
// Valid
return (*FurnaceScreen_handleAddItem)(furnace_screen, slot, item);
} else {
// Invalid
return 0;
}
}
// Init
void init_misc() {
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
@ -177,6 +211,11 @@ void init_misc() {
patch_address(LocalPlayer_die_vtable_addr, (void *) LocalPlayer_die_injection);
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
if (feature_has("Fix Furnace Not Checking Item Auxiliary", 0)) {
overwrite_calls((void *) FurnaceScreen_handleAddItem, (void *) FurnaceScreen_handleAddItem_injection);
}
// Init C++ And Logging
_init_misc_cpp();
_init_misc_logging();

View File

@ -46,6 +46,7 @@ static int peaceful_mode;
static int anaglyph;
static int smooth_lighting;
static int render_distance;
static int server_visible;
// Configure Options
static void Minecraft_init_injection(unsigned char *this) {
// Call Original Method
@ -64,6 +65,8 @@ static void Minecraft_init_injection(unsigned char *this) {
*(options + Options_ambient_occlusion_property_offset) = smooth_lighting;
// Render Distance
*(int32_t *) (options + Options_render_distance_property_offset) = render_distance;
// Server Visible
*(options + Options_server_visible_property_offset) = server_visible;
}
// Init
@ -86,6 +89,8 @@ void init_options() {
#else // #ifndef MCPI_SERVER_MODE
render_distance = 3;
#endif // #ifndef MCPI_SERVER_MODE
// Server Visible
server_visible = !feature_has("Disable Hosting LAN Worlds", 0);
// Set Options
overwrite_calls((void *) Minecraft_init, (void *) Minecraft_init_injection);

View File

@ -10,10 +10,12 @@
#include "../home/home.h"
// Check If String Starts With Prefix
static int starts_with(const char *s, const char *t) {
return strncmp(s, t, strlen(t)) == 0;
}
// Get Override Path For File (If It Exists)
char *override_get_path(const char *filename) {
// Get MCPI Home Path
char *home_path = home_get();
@ -23,9 +25,8 @@ char *override_get_path(const char *filename) {
// Get Data Path
char *data = NULL;
char *binary_directory = get_binary_directory();
char *binary_directory = get_mcpi_directory();
safe_asprintf(&data, "%s/data", binary_directory);
free(binary_directory);
int data_length = strlen(data);
// Get Full Path

View File

@ -23,15 +23,11 @@ std::string _sound_get_source_file() {
// Resolve
// Get Binary Directory
char *binary_directory = get_binary_directory();
char *binary_directory = get_mcpi_directory();
// Get Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" SOURCE_FILE_BASE, binary_directory);
// Free Binary Directory
free(binary_directory);
// Handle Overrides
char *overridden_full_path = override_get_path(full_path);
if (overridden_full_path != NULL) {

View File

@ -1,14 +0,0 @@
#!/bin/sh
set -e
# Clean Prefix
rm -rf out
# Build
./scripts/build.sh client amd64
./scripts/build.sh server amd64
./scripts/build.sh client arm64
./scripts/build.sh server arm64
./scripts/build.sh client armhf
./scripts/build.sh server armhf

View File

@ -2,48 +2,29 @@
set -e
# ARM Toolchain File
ARM_TOOLCHAIN_FILE="$(pwd)/cmake/armhf-toolchain.cmake"
# Build
build() {
# Find Toolchain
local toolchain_file="$(pwd)/cmake/$2-toolchain.cmake"
if [ ! -f "${toolchain_file}" ]; then
echo "Invalid Architecture: $2" > /dev/stderr
exit 1
# Use Build Dir
if [ ! -d "build/${MODE}-${ARCH}" ]; then
./scripts/setup.sh "${MODE}" "${ARCH}"
fi
# Create Build Dir
rm -rf "build/$1-$2"
mkdir -p "build/$1-$2"
cd "build/$1-$2"
cd "build/${MODE}-${ARCH}"
# Create Prefix
local prefix="$(cd ../../; pwd)/out/$1-$2"
local prefix="$(cd ../../; pwd)/out/${MODE}-${ARCH}"
rm -rf "${prefix}"
mkdir -p "${prefix}"
# Prepare
local extra_arg='-DMCPI_USE_MEDIA_LAYER_PROXY=ON'
if [ "$1" = "server" ]; then
extra_arg='-DMCPI_SERVER_MODE=ON'
fi
# Build ARM Components
mkdir arm
cd arm
cmake -DCMAKE_TOOLCHAIN_FILE="${ARM_TOOLCHAIN_FILE}" -DMCPI_BUILD_MODE=arm "${extra_arg}" ../../..
make -j$(nproc)
make install DESTDIR="${prefix}"
cmake --build .
DESTDIR="${prefix}" cmake --install .
cd ../
# Build Native Components
mkdir native
cd native
cmake -DCMAKE_TOOLCHAIN_FILE="${toolchain_file}" -DMCPI_BUILD_MODE=native "${extra_arg}" ../../..
make -j$(nproc)
make install DESTDIR="${prefix}"
cmake --build .
DESTDIR="${prefix}" cmake --install .
cd ../
# Exit
@ -52,40 +33,33 @@ build() {
# Build For ARM
armhf_build() {
# Create Build Dir
rm -rf "build/$1-armhf"
mkdir -p "build/$1-armhf"
cd "build/$1-armhf"
# Use Build Dir
if [ ! -d "build/${MODE}-armhf" ]; then
./scripts/setup.sh "${MODE}" armhf
fi
cd "build/${MODE}-armhf"
# Create Prefix
local prefix="$(cd ../../; pwd)/out/$1-armhf"
local prefix="$(cd ../../; pwd)/out/${MODE}-armhf"
rm -rf "${prefix}"
mkdir -p "${prefix}"
# Prepare
local server_mode='OFF'
if [ "$1" = "server" ]; then
server_mode='ON'
fi
# Build All Components
cmake -DCMAKE_TOOLCHAIN_FILE="${ARM_TOOLCHAIN_FILE}" -DMCPI_BUILD_MODE=both -DMCPI_SERVER_MODE="${server_mode}" ../..
make -j$(nproc)
make install DESTDIR="${prefix}"
cmake --build .
DESTDIR="${prefix}" cmake --install .
# Exit
cd ../../
}
# Verify Mode
if [ "$1" != "client" ] && [ "$1" != "server" ]; then
echo "Invalid Mode: $1" > /dev/stderr
exit 1
fi
# Variables
MODE="$1"
ARCH="$2"
shift 2
# Build
if [ "$2" = "armhf" ]; then
armhf_build "$1"
if [ "${ARCH}" = "armhf" ]; then
armhf_build "${MODE}"
else
build "$1" "$2"
build "${MODE}" "${ARCH}"
fi

12
scripts/ci/Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM buildpack-deps:bullseye
# Setup
ENV ARM_PACKAGES_SUPPORTED=1
# Install
ADD ./scripts/install-dependencies.sh /
RUN \
apt-get update && \
apt-get install --no-install-recommends -y sudo && \
/install-dependencies.sh && \
rm -rf /var/lib/apt/lists/*

View File

@ -2,25 +2,10 @@
set -e
# Install sudo
apt-get update
apt-get install -y sudo
# Prepare
export ARM_PACKAGES_SUPPORTED=1
# Install Dependencies
echo '==== Installing Dependencies ===='
./scripts/install-dependencies.sh
# Build
echo '==== Building ===='
./scripts/build-all.sh
# Build/Package
echo '==== Building & Packaging ===='
./scripts/package-all.sh
# Test
echo '==== Testing ===='
./scripts/test.sh
# Package
echo '==== Packaging ===='
./scripts/package.sh

View File

@ -2,5 +2,8 @@
set -e
# Build Docker Image
docker build -f scripts/ci/Dockerfile -t minecraft-pi-reborn-build .
# Run
docker run --rm -v "$(pwd):/data" debian:bullseye sh -c "cd /data; ./scripts/ci/run.sh"
docker run --rm -v "$(pwd):/data" -w '/data' -u '1000:1000' minecraft-pi-reborn-build ./scripts/ci/run.sh

View File

@ -0,0 +1,190 @@
#!/usr/bin/env node
// Arguments
if (process.argv.length < 4) {
throw new Error('Invalid Arguments');
}
const mode = process.argv[2];
const arch = process.argv[3];
// Data
const id = `com.thebrokenrail.MCPIReborn${mode === 'server' ? 'Server' : ''}`;
const name = `minecraft-pi-reborn-${mode}`;
const updateURL = `https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/${name}-latest-${arch}.AppImage.zsync`;
// APT Data
const apt_distribution = 'bullseye';
const apt_key_url = 'https://ftp-master.debian.org/keys/archive-key-11.asc';
// Version
const fs = require('fs');
const version = fs.readFileSync('VERSION', 'utf8').trim();
// Packages/Dependencies
const packages = [
'libc6',
'libc-bin',
'libstdc++6'
];
if (mode === 'client') {
// GLFW's Dependencies Aren't Included As They Should Be Provided By The Host System
packages.push(
'libgtk-3-0',
'libglib2.0-0',
'libgdk-pixbuf2.0-0',
'shared-mime-info',
'libfreeimage3',
'libopenal1'
);
}
if (arch !== 'armhf') {
packages.push(
'libc6-armhf-cross',
'libstdc++6-armhf-cross'
);
if (arch !== 'arm64') {
packages.push('qemu-user');
}
}
// Package Exclusions
const packageExclusions = [
// Exclude Unneeded Packages
'humanity-icon-theme',
'adwaita-icon-theme',
'libxml2',
'*systemd*',
'dconf-service',
'dconf-gsettings-backend',
'libgnutls*',
'librest-*',
'libcups2',
'libcolord2',
'libmount1'
];
// APT
const apt = {
arch: arch,
sources: [
{
sourceline: `deb [arch=${arch}] http://deb.debian.org/debian/ ${apt_distribution} main`,
key_url: apt_key_url
},
{
sourceline: `deb [arch=${arch}] http://deb.debian.org/debian/ ${apt_distribution}-updates main`,
key_url: apt_key_url
}
],
include: packages,
exclude: packageExclusions
};
// Get Architecture Triplet
const triplet = {
'amd64': 'x86_64-linux-gnu',
'i386': 'i386-linux-gnu',
'arm64': 'aarch64-linux-gnu',
'armhf': 'arm-linux-gnueabihf'
}[arch];
if (!triplet) {
throw new Error();
}
// Files
const files = {
exclude: [
// Exclude Unused Files
`usr/lib/${triplet}/gconv`,
'usr/share/man',
'usr/share/doc/*/README.*',
'usr/share/doc/*/changelog.*',
'usr/share/doc/*/NEWS.*',
'usr/share/doc/*/TODO.*',
'usr/include',
'usr/share/locale',
'usr/share/help',
'usr/bin/update-mime-database'
]
};
// Script After Bundling Dependencies
const afterBundle = [
// Remove Unused QEMU Binaries
'find ./AppDir/usr/bin -maxdepth 1 -name \'qemu-*\' -a ! -name \'qemu-arm\' -delete'
];
// Runtime
const runtime = {
env: mode === 'client' ? {
// Make GTK Work (Zenity Uses GTK)
GTK_EXE_PREFIX: '${APPDIR}/usr',
GTK_PATH: `\${APPDIR}/usr/lib/${triplet}/gtk-3.0`,
GTK_DATA_PREFIX: '${APPDIR}',
GTK_THEME: 'Default',
XDG_DATA_DIRS: '${APPDIR}/share:${APPDIR}/usr/share',
APPDIR_LIBRARY_PATH: `\${APPDIR}/usr/lib/${triplet}:\${APPDIR}/usr/${triplet}/lib:\${APPDIR}/lib/${triplet}:\${APPDIR}/usr/lib:\${APPDIR}/usr/lib/${triplet}/gdk-pixbuf-2.0/2.10.0/loaders`
} : undefined,
preserve: arch !== 'armhf' ? [
// On non-ARM32 systems, an ARM32 linker is embedded, this
// prevents AppImage-Builder from modifying ARM32 binaries
// to use a (usually non-existent) system linker.
`usr/lib/${name}/minecraft-pi`,
`usr/lib/${name}/**/*.so`,
'usr/arm-linux-gnueabihf/lib'
] : undefined
};
// AppDir
const appDir = {
path: `./AppDir`,
app_info: {
id: id,
name: `${name}`,
icon: id,
version: version,
exec: `usr/bin/${name}`,
exec_args: '$@'
},
apt: apt,
files: files,
after_bundle: afterBundle,
runtime: runtime
};
// Build Script
const script = [
`rm -rf ./build/${mode}-${arch}`,
`./scripts/setup.sh ${mode} ${arch} -DMCPI_IS_APPIMAGE_BUILD=ON`,
`rm -rf ./out/${mode}-${arch}`,
`./scripts/build.sh ${mode} ${arch}`,
'rm -rf ./AppDir',
`cp -ar ./out/${mode}-${arch} ./AppDir`
];
// AppImage
const appImageArch = {
'amd64': 'x86_64',
'i386': 'i686',
'arm64': 'aarch64',
'armhf': 'armhf'
}[arch];
if (!appImageArch) {
throw new Error();
}
const appImage = {
arch: appImageArch,
file_name: `./out/${name}-${version}-${arch}.AppImage`,
'update-information': `zsync|${updateURL}`
};
// Root
const root = {
version: 1,
AppDir: appDir,
script: script,
AppImage: appImage
};
// Write
fs.writeFileSync(`AppImageBuilder.yml`, JSON.stringify(root, null, 4));

View File

@ -18,32 +18,102 @@ fi
sudo apt-get update
sudo apt-get dist-upgrade -y
# Install
sudo apt-get install --no-install-recommends -y \
ca-certificates \
lsb-release \
dpkg-dev \
# Install Everything In One Go
PKG_QUEUE=''
queue_pkg() {
PKG_QUEUE="${PKG_QUEUE} $@"
}
# Build Tools
queue_pkg \
git \
clang \
lld \
cmake \
make \
libglfw3 libglfw3-dev \
libfreeimage3 libfreeimage-dev \
ninja-build \
crossbuild-essential-armhf \
gcc g++ \
nodejs
# Dependencies
queue_pkg \
libfreeimage3 libfreeimage-dev \
libopenal-dev \
qemu-user
# Install ARM Dependencies
# GLFW Dependencies
queue_pkg \
libwayland-dev \
libxkbcommon-dev \
wayland-protocols \
libx11-dev \
libxcursor-dev \
libxi-dev \
libxinerama-dev \
libxrandr-dev \
libxext-dev
# Zenity Dependencies
queue_pkg \
libgtk-3-dev \
libglib2.0-dev
# ARM Packages
if [ ! -z "${ARM_PACKAGES_SUPPORTED}" ]; then
sudo apt-get install --no-install-recommends -y \
libglfw3:armhf libglfw3-dev:armhf \
libfreeimage3:armhf \
libopenal-dev:armhf \
libglfw3:arm64 libglfw3-dev:arm64 \
libfreeimage3:arm64 \
libopenal-dev:arm64 \
# Build Tools
queue_pkg \
crossbuild-essential-arm64
# Dependencies
queue_pkg \
libfreeimage3:armhf libfreeimage3:arm64 \
libopenal-dev:armhf libopenal-dev:arm64
# GLFW Dependencies
queue_pkg \
libwayland-dev:armhf libwayland-dev:arm64 \
libxkbcommon-dev:armhf libxkbcommon-dev:arm64 \
libx11-dev:armhf libx11-dev:arm64 \
libxcursor-dev:armhf libxcursor-dev:arm64 \
libxi-dev:armhf libxi-dev:arm64 \
libxinerama-dev:armhf libxinerama-dev:arm64 \
libxrandr-dev:armhf libxrandr-dev:arm64 \
libxext-dev:armhf libxext-dev:arm64
# Zenity Dependencies
queue_pkg \
libgtk-3-dev:armhf libgtk-3-dev:arm64 \
libglib2.0-dev:armhf libglib2.0-dev:arm64
fi
# Install appimagetool & appimage-builder Dependencies
queue_pkg \
python3-pip \
python3-setuptools \
patchelf \
desktop-file-utils \
libgdk-pixbuf2.0-dev \
fakeroot \
strace \
fuse \
gtk-update-icon-cache \
shared-mime-info \
sed
# Install Queue
sudo apt-get install --no-install-recommends -y ${PKG_QUEUE}
# Download appimagetool
sudo mkdir -p /opt
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /opt/appimagetool
sudo chmod +x /opt/appimagetool
# Workaround AppImage Issues With Docker
cd /opt
sudo sed -i '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' ./appimagetool
sudo rm -rf /opt/squashfs-root /opt/appimagetool.AppDir
sudo ./appimagetool --appimage-extract
sudo rm -f ./appimagetool
sudo mv /opt/squashfs-root /opt/appimagetool.AppDir
sudo rm -f /usr/local/bin/appimagetool
sudo ln -s /opt/appimagetool.AppDir/AppRun /usr/local/bin/appimagetool
# Install appimage-builder
sudo pip3 install 'git+https://github.com/TheBrokenRail/appimage-builder.git@combined'

14
scripts/package-all.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
set -e
# Clean Prefix
rm -rf out
# Build
./scripts/package.sh client amd64
./scripts/package.sh server amd64
./scripts/package.sh client arm64
./scripts/package.sh server arm64
./scripts/package.sh client armhf
./scripts/package.sh server armhf

View File

@ -2,36 +2,11 @@
set -e
# Prepare
VERSION="$(cat VERSION)"
# Generate
./scripts/generate-appimage-builder-yaml.js "$1" "$2"
# Common
package() {
local dir="out/$1"
# Create DEBIAN Dir
rm -rf "${dir}/DEBIAN"
mkdir -p "${dir}/DEBIAN"
cp "debian/$1" "${dir}/DEBIAN/control"
# Format DEBIAN/control
sed -i "s/\${VERSION}/${VERSION}/g" "${dir}/DEBIAN/control"
# Fix Permissions On Jenkins
chmod -R g-s "${dir}"
# Package
dpkg-deb --root-owner-group --build "${dir}" out
}
# Build/Package
appimage-builder --recipe AppImageBuilder.yml
# Find And Package
for dir in out/*; do
# Check If Directory Exists
if [ -d "${dir}" ]; then
# Check If Debian Package Exists
pkg="$(basename ${dir})"
if [ -f "debian/${pkg}" ]; then
package "${pkg}"
fi
fi
done
# Move ZSync
mv "./minecraft-pi-reborn-$1-$(cat VERSION)-$2.AppImage.zsync" "./out/minecraft-pi-reborn-$1-latest-$2.AppImage.zsync"

80
scripts/setup.sh Executable file
View File

@ -0,0 +1,80 @@
#!/bin/sh
set -e
# ARM Toolchain File
ARM_TOOLCHAIN_FILE="$(pwd)/cmake/armhf-toolchain.cmake"
# Setup
setup() {
# Find Toolchain
local toolchain_file="$(pwd)/cmake/${ARCH}-toolchain.cmake"
if [ ! -f "${toolchain_file}" ]; then
echo "Invalid Architecture: ${ARCH}" > /dev/stderr
exit 1
fi
# Create Build Dir
rm -rf "build/${MODE}-${ARCH}"
mkdir -p "build/${MODE}-${ARCH}"
cd "build/${MODE}-${ARCH}"
# Prepare
local extra_arg='-DMCPI_USE_MEDIA_LAYER_PROXY=ON'
if [ "${MODE}" = "server" ]; then
extra_arg='-DMCPI_SERVER_MODE=ON'
fi
# Build ARM Components
mkdir arm
cd arm
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE="${ARM_TOOLCHAIN_FILE}" -DMCPI_BUILD_MODE=arm "${extra_arg}" "$@" ../../..
cd ../
# Build Native Components
mkdir native
cd native
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE="${toolchain_file}" -DMCPI_BUILD_MODE=native "${extra_arg}" "$@" ../../..
cd ../
# Exit
cd ../../
}
# Setup For ARM
armhf_setup() {
# Create Build Dir
rm -rf "build/${MODE}-armhf"
mkdir -p "build/${MODE}-armhf"
cd "build/${MODE}-armhf"
# Prepare
local server_mode='OFF'
if [ "${MODE}" = "server" ]; then
server_mode='ON'
fi
# Build All Components
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE="${ARM_TOOLCHAIN_FILE}" -DMCPI_BUILD_MODE=both -DMCPI_SERVER_MODE="${server_mode}" "$@" ../..
# Exit
cd ../../
}
# Variables
MODE="$1"
ARCH="$2"
shift 2
# Verify Mode
if [ "${MODE}" != "client" ] && [ "${MODE}" != "server" ]; then
echo "Invalid Mode: ${MODE}" > /dev/stderr
exit 1
fi
# Setup
if [ "${ARCH}" = "armhf" ]; then
armhf_setup "$@"
else
setup "$@"
fi

View File

@ -2,6 +2,10 @@
set -e
# Build Test
./scripts/setup.sh server "$(dpkg-architecture -qDEB_BUILD_ARCH)"
./scripts/build.sh server "$(dpkg-architecture -qDEB_BUILD_ARCH)"
# Add minecraft-pi-reborn-server To PATH
export PATH="$(pwd)/out/server-$(dpkg-architecture -qDEB_BUILD_ARCH)/usr/bin:${PATH}"

View File

@ -63,7 +63,7 @@ struct AABB {
};
struct LevelSettings {
unsigned long seed;
int32_t seed;
int32_t game_type;
};
@ -243,6 +243,7 @@ static uint32_t Options_third_person_property_offset = 0xed; // unsigned char /
static uint32_t Options_render_distance_property_offset = 0x10; // int32_t
static uint32_t Options_sound_property_offset = 0x4; // int32_t
static uint32_t Options_debug_property_offset = 0xee; // unsigned char / bool
static uint32_t Options_server_visible_property_offset = 0x104; // unsigned char / bool
// MouseBuildInput
@ -401,6 +402,18 @@ static ProgressScreen_t ProgressScreen = (ProgressScreen_t) 0x37044;
static void *OptionsScreen_handleBackEvent_vtable_addr = (void *) 0x10499c;
// FurnaceScreen
typedef int32_t (*FurnaceScreen_handleAddItem_t)(unsigned char *furnace_screen, int32_t slot, ItemInstance const *item);
static FurnaceScreen_handleAddItem_t FurnaceScreen_handleAddItem = (FurnaceScreen_handleAddItem_t) 0x327a0;
static uint32_t FurnaceScreen_tile_entity_property_offset = 0x1d0; // FurnaceTileEntity *
// FurnaceTileEntity
typedef ItemInstance *(*FurnaceTileEntity_getItem_t)(unsigned char *furnace_tile_entity, int32_t slot);
static uint32_t FurnaceTileEntity_getItem_vtable_offset = 0x2c;
// Screen
typedef void (*Screen_updateEvents_t)(unsigned char *screen);
@ -637,7 +650,7 @@ static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_read
// Minecraft
typedef void (*Minecraft_selectLevel_t)(unsigned char *minecraft, std::string const& level_dir, std::string const& level_name, LevelSettings const& vsettings);
typedef void (*Minecraft_selectLevel_t)(unsigned char *minecraft, std::string const& level_dir, std::string const& level_name, LevelSettings const& settings);
static Minecraft_selectLevel_t Minecraft_selectLevel = (Minecraft_selectLevel_t) 0x16f38;
// ExternalFileLevelStorageSource