Compare commits
83 Commits
Author | SHA1 | Date | |
---|---|---|---|
6f5f405327 | |||
489615d47f | |||
00fee9c410 | |||
b055980103 | |||
b767b9d4ec | |||
c5f9a519c5 | |||
9428a5a1e1 | |||
013c1db336 | |||
a80b5fb5c2 | |||
bf24ace78e | |||
2568b05053 | |||
dcafeb5c44 | |||
3771666a14 | |||
b71c089fb3 | |||
71946d2087 | |||
b2ec2728e3 | |||
71042da861 | |||
5d8aa28113 | |||
aea31dd4c8 | |||
f0005ff002 | |||
587ba38ffe | |||
c6048ec4fb | |||
0ccf578478 | |||
814217a259 | |||
cfac7d0a12 | |||
c531e7ba7d | |||
bddc299664 | |||
cc060accaf | |||
09c8af0396 | |||
a740814354 | |||
890bd537b2 | |||
983e474b33 | |||
2c3bb41293 | |||
3d89fb691a | |||
4e1476bcfd | |||
8ed425392a | |||
b2c13c8257 | |||
2eb6a1c5be | |||
ef3292c5e0 | |||
67ceb4ad00 | |||
e1d9fc492b | |||
acec86b9b5 | |||
66d2e43f55 | |||
596ff01f75 | |||
57aed4d0b3 | |||
fd26000fd4 | |||
454734ab68 | |||
d3b70878be | |||
7f9d1d843e | |||
900169a728 | |||
633b165af0 | |||
86e8c0dd67 | |||
332acd49fb | |||
c2750bbaec | |||
70ef421780 | |||
ed59e19c52 | |||
dd760cc6f2 | |||
00f90afc2a | |||
4a91937b0a | |||
a6cc0b88b5 | |||
0b542701c5 | |||
fc7ecd528a | |||
2785e3f138 | |||
386f52a85f | |||
871288ee12 | |||
5d7056645d | |||
ecbbcef203 | |||
bbae01a471 | |||
6b5105e74d | |||
57503d6a31 | |||
58a6706cf9 | |||
f501f9a7c9 | |||
203d46c849 | |||
58efe19609 | |||
23b3cbe72f | |||
b339b53f42 | |||
a8d0962491 | |||
a63125f335 | |||
eeace9cf14 | |||
dd25805af9 | |||
a6dad72778 | |||
9ae6cd17cf | |||
644e9e421b |
@ -1,5 +1,4 @@
|
|||||||
name: 'CI'
|
name: 'CI'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
@ -8,6 +7,7 @@ on:
|
|||||||
- '*'
|
- '*'
|
||||||
- '!flatpak'
|
- '!flatpak'
|
||||||
|
|
||||||
|
# Jobs
|
||||||
jobs:
|
jobs:
|
||||||
# Build Project
|
# Build Project
|
||||||
build:
|
build:
|
||||||
@ -28,12 +28,12 @@ jobs:
|
|||||||
submodules: true
|
submodules: true
|
||||||
# Dependencies
|
# Dependencies
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: ./scripts/install-dependencies.sh build ${{ matrix.arch }}
|
run: ./scripts/install-dependencies.mjs build ${{ matrix.arch }}
|
||||||
# Build
|
# Build
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./scripts/build.mjs appimage ${{ matrix.arch }}
|
run: ./scripts/build.mjs appimage ${{ matrix.arch }}
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
uses: christopherhx/gitea-upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.arch }}
|
name: ${{ matrix.arch }}
|
||||||
path: ./out/*.AppImage*
|
path: ./out/*.AppImage*
|
||||||
@ -61,10 +61,10 @@ jobs:
|
|||||||
submodules: false
|
submodules: false
|
||||||
# Dependencies
|
# Dependencies
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: ./scripts/install-dependencies.sh test ${{ matrix.arch }}
|
run: ./scripts/install-dependencies.mjs test ${{ matrix.arch }}
|
||||||
# Download Artifact
|
# Download Artifact
|
||||||
- name: Download Artifact
|
- name: Download Artifact
|
||||||
uses: christopherhx/gitea-download-artifact@v4
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.arch }}
|
name: ${{ matrix.arch }}
|
||||||
path: out
|
path: out
|
||||||
@ -84,10 +84,10 @@ jobs:
|
|||||||
submodules: false
|
submodules: false
|
||||||
# Dependencies
|
# Dependencies
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: ./scripts/install-dependencies.sh example_mods amd64
|
run: ./scripts/install-dependencies.mjs sdk amd64
|
||||||
# SDK
|
# SDK
|
||||||
- name: Download SDK
|
- name: Download SDK
|
||||||
uses: christopherhx/gitea-download-artifact@v4
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: AMD64
|
name: AMD64
|
||||||
path: out
|
path: out
|
||||||
@ -100,7 +100,7 @@ jobs:
|
|||||||
- name: Build Example Mods
|
- name: Build Example Mods
|
||||||
run: ./example-mods/build.sh
|
run: ./example-mods/build.sh
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
uses: christopherhx/gitea-upload-artifact@v4
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: Example Mods
|
name: Example Mods
|
||||||
path: ./example-mods/out/*
|
path: ./example-mods/out/*
|
||||||
@ -123,7 +123,7 @@ jobs:
|
|||||||
go-version: '>=1.20.1'
|
go-version: '>=1.20.1'
|
||||||
# Download Artifacts
|
# Download Artifacts
|
||||||
- name: Download Artifacts
|
- name: Download Artifacts
|
||||||
uses: christopherhx/gitea-download-artifact@v4
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: out
|
path: out
|
||||||
# Create Release
|
# Create Release
|
||||||
@ -133,4 +133,4 @@ jobs:
|
|||||||
files: ./out/*/*.AppImage*
|
files: ./out/*/*.AppImage*
|
||||||
api_key: ${{ secrets.RELEASE_TOKEN }}
|
api_key: ${{ secrets.RELEASE_TOKEN }}
|
||||||
title: v${{ github.ref_name }}
|
title: v${{ github.ref_name }}
|
||||||
body: "[View Changelog](https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/CHANGELOG.md)"
|
body: '[View Changelog](https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/branch/master/docs/CHANGELOG.md)'
|
||||||
|
11
.gitmodules
vendored
11
.gitmodules
vendored
@ -1,9 +1,6 @@
|
|||||||
[submodule "dependencies/glfw/src"]
|
[submodule "dependencies/glfw/src"]
|
||||||
path = dependencies/glfw/src
|
path = dependencies/glfw/src
|
||||||
url = https://github.com/glfw/glfw.git
|
url = https://github.com/glfw/glfw.git
|
||||||
[submodule "dependencies/zenity/src"]
|
|
||||||
path = dependencies/zenity/src
|
|
||||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git
|
|
||||||
[submodule "dependencies/LIEF/src"]
|
[submodule "dependencies/LIEF/src"]
|
||||||
path = dependencies/LIEF/src
|
path = dependencies/LIEF/src
|
||||||
url = https://github.com/lief-project/LIEF.git
|
url = https://github.com/lief-project/LIEF.git
|
||||||
@ -16,9 +13,17 @@
|
|||||||
[submodule "archives"]
|
[submodule "archives"]
|
||||||
path = archives
|
path = archives
|
||||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/archives.git
|
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/archives.git
|
||||||
|
shallow = true
|
||||||
[submodule "dependencies/symbol-processor/src"]
|
[submodule "dependencies/symbol-processor/src"]
|
||||||
path = dependencies/symbol-processor/src
|
path = dependencies/symbol-processor/src
|
||||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/symbol-processor.git
|
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/symbol-processor.git
|
||||||
[submodule "dependencies/runtime/src"]
|
[submodule "dependencies/runtime/src"]
|
||||||
path = dependencies/runtime/src
|
path = dependencies/runtime/src
|
||||||
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/runtime.git
|
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/runtime.git
|
||||||
|
[submodule "dependencies/imgui/src"]
|
||||||
|
path = dependencies/imgui/src
|
||||||
|
url = https://github.com/ocornut/imgui.git
|
||||||
|
ignore = dirty
|
||||||
|
[submodule "dependencies/imgui/glad/src"]
|
||||||
|
path = dependencies/imgui/glad/src
|
||||||
|
url = https://github.com/Dav1dde/glad.git
|
||||||
|
103
CMakeLists.txt
103
CMakeLists.txt
@ -1,35 +1,39 @@
|
|||||||
cmake_minimum_required(VERSION 3.17.0)
|
cmake_minimum_required(VERSION 3.25.0)
|
||||||
|
|
||||||
# Avoid Warning About DOWNLOAD_EXTRACT_TIMESTAMP
|
# Avoid Warning About DOWNLOAD_EXTRACT_TIMESTAMP
|
||||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24.0)
|
cmake_policy(SET CMP0135 NEW)
|
||||||
cmake_policy(SET CMP0135 NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Core Options
|
# Core Options
|
||||||
include(cmake/options/core-options.cmake)
|
include(cmake/options/core-options.cmake)
|
||||||
|
|
||||||
|
# Utility Functions
|
||||||
|
include(cmake/util/util.cmake)
|
||||||
|
|
||||||
# Build Mode
|
# Build Mode
|
||||||
if(NOT DEFINED CMAKE_BUILD_TYPE)
|
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
|
if(IS_MULTI_CONFIG)
|
||||||
|
force_set(CMAKE_CONFIGURATION_TYPES "Release;Debug" STRING)
|
||||||
|
set(FORCE_BUILD_TYPE "")
|
||||||
|
elseif(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||||
|
set(FORCE_BUILD_TYPE "Release")
|
||||||
|
endif()
|
||||||
|
if(DEFINED FORCE_BUILD_TYPE)
|
||||||
|
force_set(CMAKE_BUILD_TYPE "${FORCE_BUILD_TYPE}" STRING)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Start Project
|
# Start Project
|
||||||
project(minecraft-pi-reborn)
|
project(minecraft-pi-reborn)
|
||||||
|
|
||||||
# Utility Functions
|
|
||||||
include(cmake/util/util.cmake)
|
|
||||||
|
|
||||||
# Sanity Checks
|
# Sanity Checks
|
||||||
string(CONCAT ARM_SANITY_CHECK
|
string(CONCAT ARM_SANITY_CHECK
|
||||||
"include(CheckSymbolExists)\n"
|
"include(CheckSymbolExists)\n"
|
||||||
"check_symbol_exists(\"__arm__\" \"\" IS_ARM_TARGETING)"
|
"check_symbol_exists(\"__arm__\" \"\" IS_ARM_TARGETING)\n"
|
||||||
)
|
)
|
||||||
if(BUILD_ARM_COMPONENTS)
|
if(BUILD_ARM_COMPONENTS)
|
||||||
string(CONCAT ARM_SANITY_CHECK
|
string(APPEND ARM_SANITY_CHECK
|
||||||
"${ARM_SANITY_CHECK}\n"
|
|
||||||
"if(NOT IS_ARM_TARGETING)\n"
|
"if(NOT IS_ARM_TARGETING)\n"
|
||||||
" message(FATAL_ERROR \"ARM-Targeting Compiler Required\")\n"
|
" message(FATAL_ERROR \"ARM-Targeting Compiler Required\")\n"
|
||||||
"endif()"
|
"endif()\n"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
cmake_language(EVAL CODE "${ARM_SANITY_CHECK}")
|
cmake_language(EVAL CODE "${ARM_SANITY_CHECK}")
|
||||||
@ -41,14 +45,11 @@ include(cmake/options/extra-options.cmake)
|
|||||||
include(cmake/options/paths.cmake)
|
include(cmake/options/paths.cmake)
|
||||||
|
|
||||||
# Required Compile Flags
|
# Required Compile Flags
|
||||||
|
set(RELEASE_MODE_GENERATOR "\$<CONFIG:Release>")
|
||||||
string(CONCAT COMPILE_FLAGS_SETUP
|
string(CONCAT COMPILE_FLAGS_SETUP
|
||||||
# Optimizations
|
# Optimizations
|
||||||
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n"
|
"add_compile_options(\"\$<IF:${RELEASE_MODE_GENERATOR},-O3,-g>\")\n"
|
||||||
" add_compile_options(-O3)\n"
|
"add_link_options(\"\$<${RELEASE_MODE_GENERATOR}:-s>\")\n"
|
||||||
" add_link_options(-s)\n"
|
|
||||||
"else()\n"
|
|
||||||
" add_compile_options(-g)\n"
|
|
||||||
"endif()\n"
|
|
||||||
|
|
||||||
# PIC
|
# PIC
|
||||||
"set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)\n"
|
"set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)\n"
|
||||||
@ -62,10 +63,22 @@ string(CONCAT COMPILE_FLAGS_SETUP
|
|||||||
"set(CMAKE_CXX_STANDARD 20)\n"
|
"set(CMAKE_CXX_STANDARD 20)\n"
|
||||||
|
|
||||||
# Skip RPath
|
# Skip RPath
|
||||||
"set(CMAKE_SKIP_BUILD_RPATH TRUE)"
|
"set(CMAKE_SKIP_BUILD_RPATH TRUE)\n"
|
||||||
|
|
||||||
|
# Always Build Shared Libraries
|
||||||
|
"set(BUILD_SHARED_LIBS TRUE CACHE BOOL \"\" FORCE)\n"
|
||||||
)
|
)
|
||||||
|
if(BUILD_ARM_COMPONENTS)
|
||||||
|
string(APPEND COMPILE_FLAGS_SETUP
|
||||||
|
# Disable C++11 String ABI
|
||||||
|
"add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)\n"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
cmake_language(EVAL CODE "${COMPILE_FLAGS_SETUP}")
|
cmake_language(EVAL CODE "${COMPILE_FLAGS_SETUP}")
|
||||||
|
|
||||||
|
# Build Dependencies
|
||||||
|
add_subdirectory(dependencies)
|
||||||
|
|
||||||
# Fast Math
|
# Fast Math
|
||||||
add_compile_options(-ffast-math)
|
add_compile_options(-ffast-math)
|
||||||
|
|
||||||
@ -81,9 +94,6 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Buld Dependencies
|
|
||||||
add_subdirectory(dependencies)
|
|
||||||
|
|
||||||
# Build libreborn
|
# Build libreborn
|
||||||
add_subdirectory(libreborn)
|
add_subdirectory(libreborn)
|
||||||
|
|
||||||
@ -117,18 +127,35 @@ endif()
|
|||||||
|
|
||||||
# Install SDK
|
# Install SDK
|
||||||
if(BUILD_ARM_COMPONENTS)
|
if(BUILD_ARM_COMPONENTS)
|
||||||
install(EXPORT sdk DESTINATION "${MCPI_SDK_DIR}" FILE "sdk-targets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES)
|
install(EXPORT sdk DESTINATION "${MCPI_SDK_DIR}" FILE "sdk-targets.cmake")
|
||||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake"
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake"
|
||||||
|
# Sanity Check
|
||||||
|
"${ARM_SANITY_CHECK}"
|
||||||
# Compile Flags
|
# Compile Flags
|
||||||
"${COMPILE_FLAGS_SETUP}\n"
|
"${COMPILE_FLAGS_SETUP}"
|
||||||
# Snaity Check
|
|
||||||
"${ARM_SANITY_CHECK}\n"
|
|
||||||
# Log
|
# Log
|
||||||
"message(STATUS \"Using Reborn SDK v${MCPI_VERSION}\")\n"
|
"message(STATUS \"Using Reborn SDK v${MCPI_VERSION}\")\n"
|
||||||
# Include Targets
|
# Include Targets
|
||||||
"include(\"\${CMAKE_CURRENT_LIST_DIR}/sdk-targets.cmake\")\n"
|
"include(\"\${CMAKE_CURRENT_LIST_DIR}/sdk-targets.cmake\")\n"
|
||||||
)
|
)
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake" DESTINATION "${MCPI_SDK_DIR}")
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake" DESTINATION "${MCPI_SDK_DIR}")
|
||||||
|
# Calculate Hash Of SDK
|
||||||
|
string(CONCAT SDK_HASH_SCRIPT
|
||||||
|
# Prepare
|
||||||
|
"set(dir \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${MCPI_SDK_DIR}\")\n"
|
||||||
|
"set(out \"\${dir}/.hash\")\n"
|
||||||
|
# Calculate Hashes
|
||||||
|
"set(content \"\")\n"
|
||||||
|
"file(GLOB_RECURSE files LIST_DIRECTORIES FALSE \"\${dir}/*\")\n"
|
||||||
|
"foreach(file IN LISTS files)\n"
|
||||||
|
" file(SHA256 \"\${file}\" hash)\n"
|
||||||
|
" cmake_path(RELATIVE_PATH file BASE_DIRECTORY \"\${dir}\")\n"
|
||||||
|
" string(APPEND content \"\${hash} \${file}\\n\")\n"
|
||||||
|
"endforeach()\n"
|
||||||
|
# Write File
|
||||||
|
"file(WRITE \"\${out}\" \"\${content}\")\n"
|
||||||
|
)
|
||||||
|
install(CODE "${SDK_HASH_SCRIPT}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Packaging
|
# Packaging
|
||||||
@ -146,27 +173,37 @@ if(BUILD_NATIVE_COMPONENTS)
|
|||||||
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>")
|
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>")
|
||||||
if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
|
||||||
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||||
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}")
|
set(ARM_TOOLCHAIN "${CMAKE_TOOLCHAIN_FILE}")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${MCPI_CMAKE_TOOLCHAIN_FILE}")
|
set(ARM_TOOLCHAIN "${MCPI_CMAKE_TOOLCHAIN_FILE}")
|
||||||
|
endif()
|
||||||
|
if(DEFINED ARM_TOOLCHAIN)
|
||||||
|
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${ARM_TOOLCHAIN}")
|
||||||
endif()
|
endif()
|
||||||
list(APPEND ARM_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}")
|
|
||||||
# Build
|
# Build
|
||||||
ExternalProject_Add(arm-components
|
ExternalProject_Add(arm-components
|
||||||
|
# Source Directory
|
||||||
DOWNLOAD_COMMAND ""
|
DOWNLOAD_COMMAND ""
|
||||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
|
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
# Configure
|
||||||
CMAKE_CACHE_ARGS ${ARM_OPTIONS}
|
CMAKE_CACHE_ARGS ${ARM_OPTIONS}
|
||||||
|
CMAKE_GENERATOR "Ninja Multi-Config"
|
||||||
|
# Build
|
||||||
|
BUILD_COMMAND
|
||||||
|
"${CMAKE_COMMAND}" "--build" "<BINARY_DIR>" "--config" "$<CONFIG>"
|
||||||
|
# Install
|
||||||
INSTALL_COMMAND
|
INSTALL_COMMAND
|
||||||
"${CMAKE_COMMAND}" "-E"
|
"${CMAKE_COMMAND}" "-E"
|
||||||
"rm" "-rf" "<INSTALL_DIR>/${MCPI_INSTALL_DIR}"
|
"rm" "-rf" "<INSTALL_DIR>/${MCPI_INSTALL_DIR}"
|
||||||
COMMAND
|
COMMAND
|
||||||
"${CMAKE_COMMAND}" "-E" "env"
|
"${CMAKE_COMMAND}" "-E" "env" "DESTDIR="
|
||||||
"DESTDIR="
|
"${CMAKE_COMMAND}" "--install" "<BINARY_DIR>" "--config" "$<CONFIG>"
|
||||||
"${CMAKE_COMMAND}" "--install" "<BINARY_DIR>"
|
# Use Terminal
|
||||||
USES_TERMINAL_CONFIGURE TRUE
|
USES_TERMINAL_CONFIGURE TRUE
|
||||||
USES_TERMINAL_BUILD TRUE
|
USES_TERMINAL_BUILD TRUE
|
||||||
USES_TERMINAL_INSTALL TRUE
|
USES_TERMINAL_INSTALL TRUE
|
||||||
|
# Always Build
|
||||||
BUILD_ALWAYS TRUE
|
BUILD_ALWAYS TRUE
|
||||||
)
|
)
|
||||||
# Install
|
# Install
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 TheBrokenRail
|
Copyright (c) 2025 TheBrokenRail
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
2
archives
2
archives
@ -1 +1 @@
|
|||||||
Subproject commit 2f5953779674ec3a14114aa34b24c81005571ec4
|
Subproject commit 5baa6b1948aeebb5e13af31ff62dc97f00a3b71e
|
@ -1,4 +1,4 @@
|
|||||||
# Downlaod AppImage Runtime
|
# Download AppImage Runtime
|
||||||
set(RUNTIME_ARCH "unknown")
|
set(RUNTIME_ARCH "unknown")
|
||||||
if(CPACK_MCPI_ARCH STREQUAL "armhf")
|
if(CPACK_MCPI_ARCH STREQUAL "armhf")
|
||||||
set(RUNTIME_ARCH "armhf")
|
set(RUNTIME_ARCH "armhf")
|
||||||
@ -9,14 +9,14 @@ elseif(CPACK_MCPI_ARCH STREQUAL "amd64")
|
|||||||
endif()
|
endif()
|
||||||
set(RUNTIME "${CPACK_TOPLEVEL_DIRECTORY}/runtime")
|
set(RUNTIME "${CPACK_TOPLEVEL_DIRECTORY}/runtime")
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
"https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-${RUNTIME_ARCH}"
|
"https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-${RUNTIME_ARCH}"
|
||||||
"${RUNTIME}"
|
"${RUNTIME}"
|
||||||
STATUS DOWNLOAD_STATUS
|
STATUS DOWNLOAD_STATUS
|
||||||
)
|
)
|
||||||
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||||
list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
|
list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
|
||||||
if(NOT STATUS_CODE EQUAL 0)
|
if(NOT STATUS_CODE EQUAL 0)
|
||||||
message(FATAL_ERROR "Unable To Downlopad AppImage Runtime: ${ERROR_MESSAGE}")
|
message(FATAL_ERROR "Unable To Download AppImage Runtime: ${ERROR_MESSAGE}")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Downloaded AppImage Runtime: ${RUNTIME}")
|
message(STATUS "Downloaded AppImage Runtime: ${RUNTIME}")
|
||||||
endif()
|
endif()
|
||||||
@ -34,21 +34,19 @@ execute_process(
|
|||||||
COMMAND
|
COMMAND
|
||||||
"${CMAKE_COMMAND}" "-E" "env"
|
"${CMAKE_COMMAND}" "-E" "env"
|
||||||
"ARCH=${APPIMAGE_ARCH}"
|
"ARCH=${APPIMAGE_ARCH}"
|
||||||
|
"VERSION=${CPACK_MCPI_VERSION}"
|
||||||
"appimagetool"
|
"appimagetool"
|
||||||
"--updateinformation" "zsync|https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/releases/download/latest/${CPACK_PACKAGE_FILE_NAME_ZSYNC}.AppImage.zsync"
|
"--updateinformation" "zsync|${CPACK_MCPI_REPO}/releases/download/latest/${CPACK_PACKAGE_FILE_NAME_ZSYNC}${CPACK_MCPI_APPIMAGE_ZSYNC_EXT}"
|
||||||
"--runtime-file" "${RUNTIME}"
|
"--runtime-file" "${RUNTIME}"
|
||||||
"--comp" "xz"
|
"--comp" "zstd"
|
||||||
"${CPACK_TEMPORARY_DIRECTORY}"
|
"${CPACK_TEMPORARY_DIRECTORY}"
|
||||||
"${CPACK_PACKAGE_FILE_NAME}.AppImage"
|
"${CPACK_PACKAGE_FILE_NAME}${CPACK_MCPI_APPIMAGE_EXT}"
|
||||||
WORKING_DIRECTORY "${CPACK_PACKAGE_DIRECTORY}"
|
WORKING_DIRECTORY "${CPACK_PACKAGE_DIRECTORY}"
|
||||||
RESULT_VARIABLE APPIMAGETOOL_RESULT
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
)
|
)
|
||||||
if(NOT APPIMAGETOOL_RESULT EQUAL 0)
|
|
||||||
message(FATAL_ERROR "Unable Package AppImage")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Rename ZSync File
|
# Rename ZSync File
|
||||||
file(RENAME "${CPACK_PACKAGE_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}.AppImage.zsync" "${CPACK_PACKAGE_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME_ZSYNC}.AppImage.zsync")
|
file(RENAME "${CPACK_PACKAGE_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_MCPI_APPIMAGE_ZSYNC_EXT}" "${CPACK_PACKAGE_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME_ZSYNC}${CPACK_MCPI_APPIMAGE_ZSYNC_EXT}")
|
||||||
|
|
||||||
# Summary Message
|
# Summary Message
|
||||||
function(check_file name)
|
function(check_file name)
|
||||||
@ -58,5 +56,5 @@ function(check_file name)
|
|||||||
message(FATAL_ERROR "Missing File: ${name}")
|
message(FATAL_ERROR "Missing File: ${name}")
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
check_file("${CPACK_PACKAGE_FILE_NAME}.AppImage")
|
check_file("${CPACK_PACKAGE_FILE_NAME}${CPACK_MCPI_APPIMAGE_EXT}")
|
||||||
check_file("${CPACK_PACKAGE_FILE_NAME_ZSYNC}.AppImage.zsync")
|
check_file("${CPACK_PACKAGE_FILE_NAME_ZSYNC}${CPACK_MCPI_APPIMAGE_ZSYNC_EXT}")
|
||||||
|
@ -1,25 +1,10 @@
|
|||||||
# Determine Architecture
|
|
||||||
set(CPACK_MCPI_ARCH "unknown")
|
|
||||||
include(CheckSymbolExists)
|
|
||||||
function(check_arch symbol name)
|
|
||||||
set(CMAKE_REQUIRED_QUIET TRUE)
|
|
||||||
check_symbol_exists("${symbol}" "" "IS_ARCH_${name}")
|
|
||||||
unset(CMAKE_REQUIRED_QUIET)
|
|
||||||
if("${IS_ARCH_${name}}")
|
|
||||||
set(CPACK_MCPI_ARCH "${name}" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
check_arch("__arm__" "armhf")
|
|
||||||
check_arch("__aarch64__" "arm64")
|
|
||||||
check_arch("__x86_64__" "amd64")
|
|
||||||
|
|
||||||
# CPack
|
# CPack
|
||||||
set(CPACK_PACKAGE_NAME "${MCPI_VARIANT_NAME}")
|
set(CPACK_PACKAGE_NAME "${MCPI_APP_NAME}")
|
||||||
set(CPACK_PACKAGE_VENDOR "TheBrokenRail & Mojang AB")
|
set(CPACK_PACKAGE_VENDOR "${MCPI_AUTHOR} & Mojang AB")
|
||||||
set(CPACK_VERBATIM_VARIABLES TRUE)
|
set(CPACK_VERBATIM_VARIABLES TRUE)
|
||||||
set(CPACK_MONOLITHIC_INSTALL TRUE)
|
set(CPACK_MONOLITHIC_INSTALL TRUE)
|
||||||
set(CPACK_PACKAGE_FILE_NAME "${MCPI_VARIANT_NAME}-${MCPI_VERSION}-${CPACK_MCPI_ARCH}")
|
get_package_file_name(CPACK_PACKAGE_FILE_NAME "${MCPI_VERSION}")
|
||||||
set(CPACK_PACKAGE_FILE_NAME_ZSYNC "${MCPI_VARIANT_NAME}-latest-${CPACK_MCPI_ARCH}")
|
get_package_file_name(CPACK_PACKAGE_FILE_NAME_ZSYNC "latest")
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
string(REPLACE "." ";" VERSION_LIST "${MCPI_VERSION}")
|
string(REPLACE "." ";" VERSION_LIST "${MCPI_VERSION}")
|
||||||
@ -32,6 +17,15 @@ if(MCPI_IS_APPIMAGE_BUILD)
|
|||||||
set(CPACK_GENERATOR "External")
|
set(CPACK_GENERATOR "External")
|
||||||
set(CPACK_EXTERNAL_ENABLE_STAGING TRUE)
|
set(CPACK_EXTERNAL_ENABLE_STAGING TRUE)
|
||||||
set(CPACK_EXTERNAL_PACKAGE_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/appimage.cmake")
|
set(CPACK_EXTERNAL_PACKAGE_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/appimage.cmake")
|
||||||
|
# Pass Variable To CPack
|
||||||
|
macro(pass_to_cpack var)
|
||||||
|
set("CPACK_MCPI_${var}" "${MCPI_${var}}")
|
||||||
|
endmacro()
|
||||||
|
pass_to_cpack(VERSION)
|
||||||
|
pass_to_cpack(ARCH)
|
||||||
|
pass_to_cpack(REPO)
|
||||||
|
pass_to_cpack(APPIMAGE_EXT)
|
||||||
|
pass_to_cpack(APPIMAGE_ZSYNC_EXT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Package
|
# Package
|
||||||
|
0
cmake/options/appimage.cmake
Normal file
0
cmake/options/appimage.cmake
Normal file
@ -29,13 +29,9 @@ else()
|
|||||||
set(BUILD_MEDIA_LAYER_CORE "${BUILD_ARM_COMPONENTS}")
|
set(BUILD_MEDIA_LAYER_CORE "${BUILD_ARM_COMPONENTS}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Specify Variant Name
|
# App Information
|
||||||
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
|
mcpi_option(APP_NAME "App Name" STRING "minecraft-pi-reborn")
|
||||||
|
|
||||||
# App ID
|
|
||||||
mcpi_option(APP_ID "App ID" STRING "com.thebrokenrail.MCPIReborn")
|
mcpi_option(APP_ID "App ID" STRING "com.thebrokenrail.MCPIReborn")
|
||||||
|
|
||||||
# App Title
|
|
||||||
mcpi_option(APP_TITLE "App Title" STRING "Minecraft: Pi Edition: Reborn")
|
mcpi_option(APP_TITLE "App Title" STRING "Minecraft: Pi Edition: Reborn")
|
||||||
|
|
||||||
# Skin Server
|
# Skin Server
|
||||||
@ -53,5 +49,41 @@ set_property(
|
|||||||
file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/../../VERSION" MCPI_VERSION)
|
file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/../../VERSION" MCPI_VERSION)
|
||||||
file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/../../VERSION" MCPI_VERSION_DATE "%Y-%m-%d" UTC)
|
file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/../../VERSION" MCPI_VERSION_DATE "%Y-%m-%d" UTC)
|
||||||
|
|
||||||
|
# Author
|
||||||
|
mcpi_option(AUTHOR "Author" STRING "TheBrokenRail")
|
||||||
|
|
||||||
|
# Homepage
|
||||||
|
mcpi_option(REPO_HOST "Repository Host" STRING "https://gitea.thebrokenrail.com")
|
||||||
|
mcpi_option(REPO_PATH "Repository Path" STRING "minecraft-pi-reborn/minecraft-pi-reborn")
|
||||||
|
mcpi_option(REPO "Repository URL" STRING "${MCPI_REPO_HOST}/${MCPI_REPO_PATH}")
|
||||||
|
|
||||||
# Documentation URL
|
# Documentation URL
|
||||||
mcpi_option(DOCUMENTATION "Documentation URL" STRING "https://gitea.thebrokenrail.com/minecraft-pi-reborn/minecraft-pi-reborn/src/tag/${MCPI_VERSION}/docs/")
|
mcpi_option(DOCS "Documentation URL" STRING "${MCPI_REPO}/src/tag/${MCPI_VERSION}/docs/")
|
||||||
|
|
||||||
|
# Packaging
|
||||||
|
set(MCPI_ARCH "unknown")
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
function(check_arch symbol name)
|
||||||
|
set(CMAKE_REQUIRED_QUIET TRUE)
|
||||||
|
check_symbol_exists("${symbol}" "" "IS_ARCH_${name}")
|
||||||
|
unset(CMAKE_REQUIRED_QUIET)
|
||||||
|
if("${IS_ARCH_${name}}")
|
||||||
|
set(MCPI_ARCH "${name}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
check_arch("__arm__" "armhf")
|
||||||
|
check_arch("__aarch64__" "arm64")
|
||||||
|
check_arch("__x86_64__" "amd64")
|
||||||
|
macro(get_package_file_name out version)
|
||||||
|
set("${out}" "${MCPI_APP_NAME}-${version}-${MCPI_ARCH}")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# AppImage
|
||||||
|
if(MCPI_IS_APPIMAGE_BUILD)
|
||||||
|
mcpi_option(APPIMAGE_EXT "AppImage Extension" STRING ".AppImage")
|
||||||
|
mcpi_option(APPIMAGE_ZSYNC_EXT "AppImage Update Extension" STRING "${MCPI_APPIMAGE_EXT}.zsync")
|
||||||
|
mcpi_option(APPIMAGE_JSON_URL "AppImage Update Checker URL" STRING "${MCPI_REPO_HOST}/api/v1/repos/${MCPI_REPO_PATH}/releases/latest")
|
||||||
|
mcpi_option(APPIMAGE_VERSION_PLACEHOLDER "Version Placeholder In AppImage Download URL" STRING "%VERSION%")
|
||||||
|
get_package_file_name(appimage_package_file_name "${MCPI_APPIMAGE_VERSION_PLACEHOLDER}")
|
||||||
|
mcpi_option(APPIMAGE_DOWNLOAD_URL "AppImage Download URL" STRING "${MCPI_REPO}/releases/download/${MCPI_APPIMAGE_VERSION_PLACEHOLDER}/${appimage_package_file_name}${MCPI_APPIMAGE_EXT}")
|
||||||
|
endif()
|
@ -1,5 +1,5 @@
|
|||||||
# Specify Installation Paths
|
# Specify Installation Paths
|
||||||
set(MCPI_INSTALL_DIR "lib/${MCPI_VARIANT_NAME}")
|
set(MCPI_INSTALL_DIR "lib/${MCPI_APP_NAME}")
|
||||||
set(MCPI_BIN_DIR "${MCPI_INSTALL_DIR}/bin")
|
set(MCPI_BIN_DIR "${MCPI_INSTALL_DIR}/bin")
|
||||||
set(MCPI_LEGAL_DIR "${MCPI_INSTALL_DIR}/legal") # For Software Licenses
|
set(MCPI_LEGAL_DIR "${MCPI_INSTALL_DIR}/legal") # For Software Licenses
|
||||||
set(MCPI_SDK_DIR "${MCPI_INSTALL_DIR}/sdk")
|
set(MCPI_SDK_DIR "${MCPI_INSTALL_DIR}/sdk")
|
||||||
@ -28,6 +28,6 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
|||||||
elseif(MCPI_IS_FLATPAK_BUILD)
|
elseif(MCPI_IS_FLATPAK_BUILD)
|
||||||
set(DEFAULT_PREFIX "/app")
|
set(DEFAULT_PREFIX "/app")
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
|
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "Install Prefix" FORCE)
|
||||||
set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE)
|
set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
|
# Target
|
||||||
|
set(target "arm-none-linux-gnueabihf")
|
||||||
|
|
||||||
# Pick Archive
|
# Pick Archive
|
||||||
set(toolchain_version "13.3.rel1")
|
set(toolchain_version "13.3.rel1")
|
||||||
execute_process(COMMAND uname -m OUTPUT_VARIABLE arch OUTPUT_STRIP_TRAILING_WHITESPACE)
|
execute_process(COMMAND uname -m OUTPUT_VARIABLE arch OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
if(arch STREQUAL "x86_64")
|
if(arch STREQUAL "x86_64")
|
||||||
set(toolchain_file "arm-gnu-toolchain-${toolchain_version}-x86_64-arm-none-linux-gnueabihf.tar.xz")
|
set(toolchain_file "arm-gnu-toolchain-${toolchain_version}-x86_64-${target}.tar.xz")
|
||||||
elseif(arch STREQUAL "aarch64" OR arch STREQUAL "armv8b" OR arch STREQUAL "armv8l")
|
elseif(arch STREQUAL "aarch64" OR arch STREQUAL "armv8b" OR arch STREQUAL "armv8l")
|
||||||
set(toolchain_file "arm-gnu-toolchain-${toolchain_version}-aarch64-arm-none-linux-gnueabihf.tar.xz")
|
set(toolchain_file "arm-gnu-toolchain-${toolchain_version}-aarch64-${target}.tar.xz")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unable To Download Prebuilt ARMHF Toolchain")
|
message(FATAL_ERROR "Unable To Download Prebuilt ARMHF Toolchain")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Download If Needed
|
# Download If Needed
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(prebuilt-armhf-toolchain
|
||||||
prebuilt-armhf-toolchain
|
|
||||||
URL "${CMAKE_CURRENT_LIST_DIR}/../../archives/${toolchain_file}"
|
URL "${CMAKE_CURRENT_LIST_DIR}/../../archives/${toolchain_file}"
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(prebuilt-armhf-toolchain)
|
FetchContent_MakeAvailable(prebuilt-armhf-toolchain)
|
||||||
@ -20,53 +22,67 @@ set(toolchain_dir "${prebuilt-armhf-toolchain_SOURCE_DIR}")
|
|||||||
|
|
||||||
# Force Toolchain
|
# Force Toolchain
|
||||||
file(WRITE "${toolchain_dir}/toolchain.cmake"
|
file(WRITE "${toolchain_dir}/toolchain.cmake"
|
||||||
"set(CMAKE_C_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-gcc\")\n"
|
"set(CMAKE_C_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/${target}-gcc\")\n"
|
||||||
"set(CMAKE_CXX_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-g++\")\n"
|
"set(CMAKE_CXX_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/${target}-g++\")\n"
|
||||||
"set(CMAKE_SYSTEM_NAME \"Linux\")\n"
|
"set(CMAKE_SYSTEM_NAME \"Linux\")\n"
|
||||||
"set(CMAKE_SYSTEM_PROCESSOR \"arm\")\n"
|
"set(CMAKE_SYSTEM_PROCESSOR \"arm\")\n"
|
||||||
"set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n"
|
"set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n"
|
||||||
)
|
)
|
||||||
set(MCPI_CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" CACHE FILEPATH "" FORCE)
|
force_set(MCPI_CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" FILEPATH)
|
||||||
|
|
||||||
# Build Sysroot
|
# Build Sysroot
|
||||||
set(sysroot_dir "${CMAKE_CURRENT_BINARY_DIR}/bundled-armhf-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}")
|
set(sysroot_dir_debug "${sysroot_dir}/debug")
|
||||||
|
set(sysroot_dir_release "${sysroot_dir}/release")
|
||||||
|
if("${toolchain_dir}/bin/${target}-gcc" IS_NEWER_THAN "${sysroot_dir}")
|
||||||
# Create Directory
|
# Create Directory
|
||||||
file(REMOVE_RECURSE "${sysroot_dir}")
|
file(REMOVE_RECURSE "${sysroot_dir}")
|
||||||
file(MAKE_DIRECTORY "${sysroot_dir}")
|
file(MAKE_DIRECTORY "${sysroot_dir_debug}")
|
||||||
|
file(MAKE_DIRECTORY "${sysroot_dir_release}")
|
||||||
|
|
||||||
# Copy Files From Toolchain
|
# Copy Files From Toolchain
|
||||||
file(
|
file(
|
||||||
COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/"
|
COPY "${toolchain_dir}/${target}/libc/"
|
||||||
DESTINATION "${sysroot_dir}"
|
DESTINATION "${sysroot_dir_debug}"
|
||||||
USE_SOURCE_PERMISSIONS
|
USE_SOURCE_PERMISSIONS
|
||||||
FILES_MATCHING
|
FILES_MATCHING
|
||||||
PATTERN "*.so*"
|
PATTERN "*.so*"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Delete Unneeded Files
|
# Delete Unneeded Files
|
||||||
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit")
|
file(REMOVE_RECURSE "${sysroot_dir_debug}/usr/lib/audit")
|
||||||
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/gconv")
|
file(REMOVE_RECURSE "${sysroot_dir_debug}/usr/lib/gconv")
|
||||||
|
|
||||||
# Strip Files
|
# Strip Files
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
file(COPY "${sysroot_dir_debug}/." DESTINATION "${sysroot_dir_release}")
|
||||||
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*")
|
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir_release}/*")
|
||||||
foreach(file IN LISTS files)
|
foreach(file IN LISTS files)
|
||||||
execute_process(COMMAND "${toolchain_dir}/bin/arm-none-linux-gnueabihf-strip" "${file}" RESULT_VARIABLE ret)
|
execute_process(
|
||||||
# Check Result
|
COMMAND "${toolchain_dir}/bin/${target}-strip" "${file}"
|
||||||
if(NOT ret EQUAL 0)
|
RESULT_VARIABLE ret
|
||||||
# Delete Invalid Files
|
ERROR_QUIET
|
||||||
file(REMOVE "${file}")
|
)
|
||||||
endif()
|
# Delete Invalid Files
|
||||||
endforeach()
|
if(NOT ret EQUAL 0)
|
||||||
endif()
|
file(REMOVE "${file}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Install Sysroot (Skipping Empty Directories)
|
# Install Sysroot (Skipping Empty Directories)
|
||||||
function(install_arm_sysroot)
|
function(install_arm_sysroot_config config)
|
||||||
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE RELATIVE "${sysroot_dir}" "${sysroot_dir}/*")
|
set(dir "${sysroot_dir_${config}}")
|
||||||
|
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE RELATIVE "${dir}" "${dir}/*")
|
||||||
foreach(file IN LISTS files)
|
foreach(file IN LISTS files)
|
||||||
get_filename_component(parent "${file}" DIRECTORY)
|
cmake_path(GET file PARENT_PATH parent)
|
||||||
install(PROGRAMS "${sysroot_dir}/${file}" DESTINATION "${MCPI_INSTALL_DIR}/sysroot/${parent}")
|
install(
|
||||||
|
PROGRAMS "${dir}/${file}"
|
||||||
|
DESTINATION "${MCPI_INSTALL_DIR}/sysroot/${parent}"
|
||||||
|
CONFIGURATIONS "${config}"
|
||||||
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
function(install_arm_sysroot)
|
||||||
|
install_arm_sysroot_config(debug)
|
||||||
|
install_arm_sysroot_config(release)
|
||||||
|
endfunction()
|
@ -1,12 +1,12 @@
|
|||||||
# Read Hex Data
|
# Read Hex Data
|
||||||
file(READ "${EMBED_IN}" data HEX)
|
file(READ "${EMBED_IN}" data HEX)
|
||||||
|
|
||||||
# Convert Hex Data For C Compatibility
|
# Convert Hex Data For C Compatibility
|
||||||
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${data}")
|
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${data}")
|
||||||
|
|
||||||
# Get C Name
|
# Get C Name
|
||||||
get_filename_component(name "${EMBED_IN}" NAME)
|
cmake_path(GET EMBED_OUT STEM name)
|
||||||
string(MAKE_C_IDENTIFIER "${name}" name)
|
|
||||||
|
|
||||||
# Write Data
|
# Write Data
|
||||||
file(WRITE "${EMBED_OUT}" "#include <stddef.h>\nconst unsigned char ${name}[] = {${data}};\nconst size_t ${name}_len = sizeof (${name});\n")
|
file(WRITE "${EMBED_OUT}"
|
||||||
|
"#include <stddef.h>\n"
|
||||||
|
"const unsigned char ${name}[] = {${data}};\n"
|
||||||
|
"const size_t ${name}_len = sizeof (${name});\n"
|
||||||
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Symlink Function
|
# Symlink Function
|
||||||
function(install_symlink target link)
|
function(install_symlink target link)
|
||||||
get_filename_component(parent "${link}" DIRECTORY)
|
cmake_path(GET link PARENT_PATH parent)
|
||||||
if(parent STREQUAL "")
|
if(parent STREQUAL "")
|
||||||
set(parent ".")
|
set(parent ".")
|
||||||
endif()
|
endif()
|
||||||
@ -13,16 +13,20 @@ endfunction()
|
|||||||
set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}")
|
set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
function(embed_resource target file)
|
function(embed_resource target file)
|
||||||
# Get C Name
|
# Get C Name
|
||||||
get_filename_component(name "${file}" NAME)
|
cmake_path(GET file FILENAME name)
|
||||||
string(MAKE_C_IDENTIFIER "${name}" name)
|
string(MAKE_C_IDENTIFIER "${name}" name)
|
||||||
# Add Command
|
# Add Command
|
||||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
|
set(in "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
|
||||||
|
set(out "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
|
||||||
|
set(script "${util_list_dir}/embed-resource.cmake")
|
||||||
|
add_custom_command(OUTPUT "${out}"
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
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"
|
ARGS "-DEMBED_IN=${in}" "-DEMBED_OUT=${out}" "-P" "${script}"
|
||||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${file}" "${util_list_dir}/embed-resource.cmake"
|
DEPENDS "${in}" "${script}"
|
||||||
|
VERBATIM
|
||||||
)
|
)
|
||||||
# Add To Target
|
# Add To Target
|
||||||
target_sources("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
|
target_sources("${target}" PRIVATE "${out}")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Nicer Output
|
# Nicer Output
|
||||||
@ -31,3 +35,57 @@ function(message log_level)
|
|||||||
_message("${log_level}" ${ARGN})
|
_message("${log_level}" ${ARGN})
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# Exporting Targets And Headers
|
||||||
|
macro(_get_sdk_header_dir target)
|
||||||
|
set(sdk_dir "${MCPI_SDK_INCLUDE_DIR}/${target}")
|
||||||
|
endmacro()
|
||||||
|
function(setup_header_dirs target)
|
||||||
|
_get_sdk_header_dir("${target}")
|
||||||
|
# Get Header Type
|
||||||
|
set(header_type "PUBLIC")
|
||||||
|
get_target_property(type "${target}" TYPE)
|
||||||
|
if ("${type}" STREQUAL "INTERFACE_LIBRARY")
|
||||||
|
set(header_type "INTERFACE")
|
||||||
|
endif()
|
||||||
|
# Loop
|
||||||
|
foreach(dir IN LISTS ARGN)
|
||||||
|
# Add To Target
|
||||||
|
target_include_directories("${target}" "${header_type}" "$<BUILD_INTERFACE:${dir}>")
|
||||||
|
# Add To SDK
|
||||||
|
if(BUILD_ARM_COMPONENTS)
|
||||||
|
install(
|
||||||
|
DIRECTORY "${dir}/"
|
||||||
|
DESTINATION "${sdk_dir}"
|
||||||
|
FILES_MATCHING
|
||||||
|
PATTERN "*.h"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
# Add SDK Headers To Target
|
||||||
|
if(BUILD_ARM_COMPONENTS)
|
||||||
|
target_include_directories("${target}" "${header_type}" "$<INSTALL_INTERFACE:${sdk_dir}>")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
function(setup_library target should_install should_export)
|
||||||
|
# Install
|
||||||
|
if(should_install)
|
||||||
|
install(TARGETS "${target}" DESTINATION "${MCPI_LIB_DIR}")
|
||||||
|
endif()
|
||||||
|
# SDK
|
||||||
|
if(should_export AND BUILD_ARM_COMPONENTS)
|
||||||
|
install(TARGETS "${target}" EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Force Set Configuration Variable
|
||||||
|
function(force_set name value type)
|
||||||
|
set("${name}" "${value}" CACHE "${type}" "" FORCE)
|
||||||
|
mark_as_advanced(FORCE "${name}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Make Directory
|
||||||
|
function(set_and_mkdir name dir)
|
||||||
|
set("${name}" "${dir}" PARENT_SCOPE)
|
||||||
|
file(MAKE_DIRECTORY "${dir}")
|
||||||
|
endfunction()
|
12
dependencies/CMakeLists.txt
vendored
12
dependencies/CMakeLists.txt
vendored
@ -8,10 +8,6 @@ endif()
|
|||||||
if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
|
if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
|
||||||
add_subdirectory(minecraft-pi)
|
add_subdirectory(minecraft-pi)
|
||||||
endif()
|
endif()
|
||||||
# Zenity (Minimal Build)
|
|
||||||
if(BUILD_NATIVE_COMPONENTS)
|
|
||||||
add_subdirectory(zenity)
|
|
||||||
endif()
|
|
||||||
# LIEF
|
# LIEF
|
||||||
if(BUILD_NATIVE_COMPONENTS OR BUILD_MEDIA_LAYER_CORE)
|
if(BUILD_NATIVE_COMPONENTS OR BUILD_MEDIA_LAYER_CORE)
|
||||||
add_subdirectory(LIEF)
|
add_subdirectory(LIEF)
|
||||||
@ -19,12 +15,16 @@ endif()
|
|||||||
# Extra Runtime
|
# Extra Runtime
|
||||||
add_subdirectory(runtime)
|
add_subdirectory(runtime)
|
||||||
# GLFW
|
# GLFW
|
||||||
if(BUILD_MEDIA_LAYER_CORE)
|
if(BUILD_NATIVE_COMPONENTS OR BUILD_MEDIA_LAYER_CORE)
|
||||||
add_subdirectory(glfw)
|
add_subdirectory(glfw)
|
||||||
endif()
|
endif()
|
||||||
|
# ImGui
|
||||||
|
if(BUILD_NATIVE_COMPONENTS)
|
||||||
|
add_subdirectory(imgui)
|
||||||
|
endif()
|
||||||
# UTF8-CPP
|
# UTF8-CPP
|
||||||
add_subdirectory(utf8cpp)
|
add_subdirectory(utf8cpp)
|
||||||
# Symbol Prcoessor
|
# Symbol Processor
|
||||||
if(BUILD_ARM_COMPONENTS)
|
if(BUILD_ARM_COMPONENTS)
|
||||||
add_subdirectory(symbol-processor)
|
add_subdirectory(symbol-processor)
|
||||||
endif()
|
endif()
|
||||||
|
47
dependencies/LIEF/CMakeLists.txt
vendored
47
dependencies/LIEF/CMakeLists.txt
vendored
@ -6,33 +6,38 @@ add_compile_options(-w -Wno-psabi)
|
|||||||
## LIEF
|
## LIEF
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
|
force_set(LIEF_C_API FALSE BOOL)
|
||||||
set(LIEF_C_API FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_EXAMPLES FALSE BOOL)
|
||||||
set(LIEF_EXAMPLES FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_PYTHON_API FALSE BOOL)
|
||||||
set(LIEF_PYTHON_API FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_TESTS FALSE BOOL)
|
||||||
set(LIEF_TESTS FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_USE_CCACHE FALSE BOOL)
|
||||||
set(LIEF_USE_CCACHE FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_LOGGING FALSE BOOL)
|
||||||
set(LIEF_LOGGING FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_LOGGING_DEBUG FALSE BOOL)
|
||||||
set(LIEF_LOGGING_DEBUG FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_ENABLE_JSON FALSE BOOL)
|
||||||
set(LIEF_ENABLE_JSON FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_ELF TRUE BOOL)
|
||||||
set(LIEF_ELF TRUE CACHE BOOL "" FORCE)
|
force_set(LIEF_PE FALSE BOOL)
|
||||||
set(LIEF_PE FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_MACHO FALSE BOOL)
|
||||||
set(LIEF_MACHO FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_DEX FALSE BOOL)
|
||||||
set(LIEF_DEX FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_ART FALSE BOOL)
|
||||||
set(LIEF_ART FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_OAT FALSE BOOL)
|
||||||
set(LIEF_OAT FALSE CACHE BOOL "" FORCE)
|
force_set(LIEF_VDEX FALSE BOOL)
|
||||||
set(LIEF_VDEX FALSE CACHE BOOL "" FORCE)
|
|
||||||
|
|
||||||
# Download
|
# Download
|
||||||
set(MESSAGE_QUIET TRUE)
|
set(MESSAGE_QUIET TRUE)
|
||||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
add_subdirectory(src EXCLUDE_FROM_ALL SYSTEM)
|
||||||
unset(MESSAGE_QUIET)
|
unset(MESSAGE_QUIET)
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
install(TARGETS LIB_LIEF DESTINATION "${MCPI_LIB_DIR}")
|
setup_library(LIB_LIEF TRUE TRUE)
|
||||||
if(BUILD_ARM_COMPONENTS)
|
|
||||||
install(TARGETS LIB_LIEF EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/LIEF")
|
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/LIEF")
|
||||||
|
|
||||||
|
# Fix Flags
|
||||||
|
function(fix_flags property)
|
||||||
|
get_target_property(flags LIB_LIEF "${property}")
|
||||||
|
list(REMOVE_ITEM flags "_GLIBCXX_USE_CXX11_ABI=1")
|
||||||
|
set_target_properties(LIB_LIEF PROPERTIES "${property}" "${flags}")
|
||||||
|
endfunction()
|
||||||
|
fix_flags(COMPILE_DEFINITIONS)
|
||||||
|
fix_flags(INTERFACE_COMPILE_DEFINITIONS)
|
2
dependencies/LIEF/src
vendored
2
dependencies/LIEF/src
vendored
@ -1 +1 @@
|
|||||||
Subproject commit bae887e095d87e756d1bf4aa4f95a97693a97b62
|
Subproject commit d4900dab6a9eea864fb14ed1ff7ea5b9f8678e04
|
25
dependencies/glfw/CMakeLists.txt
vendored
25
dependencies/glfw/CMakeLists.txt
vendored
@ -6,22 +6,21 @@ add_compile_options(-w)
|
|||||||
## GLFW
|
## GLFW
|
||||||
|
|
||||||
# Download
|
# Download
|
||||||
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_EXAMPLES FALSE BOOL)
|
||||||
set(GLFW_BUILD_EXAMPLES FALSE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_TESTS FALSE BOOL)
|
||||||
set(GLFW_BUILD_TESTS FALSE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_DOCS FALSE BOOL)
|
||||||
set(GLFW_BUILD_DOCS FALSE CACHE BOOL "" FORCE)
|
force_set(GLFW_INSTALL FALSE BOOL)
|
||||||
set(GLFW_INSTALL FALSE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_WIN32 FALSE BOOL)
|
||||||
set(GLFW_BUILD_WIN32 FALSE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_COCOA FALSE BOOL)
|
||||||
set(GLFW_BUILD_COCOA FALSE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_X11 TRUE BOOL)
|
||||||
set(GLFW_BUILD_X11 TRUE CACHE BOOL "" FORCE)
|
force_set(GLFW_BUILD_WAYLAND TRUE BOOL)
|
||||||
set(GLFW_BUILD_WAYLAND TRUE CACHE BOOL "" FORCE)
|
force_set(GLFW_LIBRARY_TYPE "SHARED" STRING)
|
||||||
set(GLFW_LIBRARY_TYPE "SHARED" CACHE BOOL "" FORCE)
|
|
||||||
set(MESSAGE_QUIET TRUE)
|
set(MESSAGE_QUIET TRUE)
|
||||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
add_subdirectory(src EXCLUDE_FROM_ALL SYSTEM)
|
||||||
unset(MESSAGE_QUIET)
|
unset(MESSAGE_QUIET)
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
install(TARGETS glfw DESTINATION "${MCPI_LIB_DIR}")
|
setup_library(glfw TRUE TRUE)
|
||||||
|
|
||||||
# License
|
# License
|
||||||
install(FILES src/LICENSE.md DESTINATION "${MCPI_LEGAL_DIR}/glfw")
|
install(FILES src/LICENSE.md DESTINATION "${MCPI_LEGAL_DIR}/GLFW")
|
||||||
|
2
dependencies/glfw/src
vendored
2
dependencies/glfw/src
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 7b6aead9fb88b3623e3b3725ebb42670cbe4c579
|
Subproject commit 21fea01161e0d6b70c0c5c1f52dc8e7a7df14a50
|
52
dependencies/imgui/CMakeLists.txt
vendored
Normal file
52
dependencies/imgui/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
project(imgui)
|
||||||
|
|
||||||
|
# Silence Warnings
|
||||||
|
add_compile_options(-w)
|
||||||
|
|
||||||
|
## ImGui
|
||||||
|
|
||||||
|
# Build
|
||||||
|
add_library(imgui SHARED
|
||||||
|
src/imgui.cpp
|
||||||
|
src/imgui_draw.cpp
|
||||||
|
src/imgui_tables.cpp
|
||||||
|
src/imgui_widgets.cpp
|
||||||
|
src/misc/cpp/imgui_stdlib.cpp
|
||||||
|
src/backends/imgui_impl_glfw.cpp
|
||||||
|
src/backends/imgui_impl_opengl2.cpp
|
||||||
|
)
|
||||||
|
setup_header_dirs(imgui
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/backends"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/misc/cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
# OpenGL
|
||||||
|
add_subdirectory(glad)
|
||||||
|
target_link_libraries(imgui PUBLIC glfw glad)
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
embed_resource(imgui src/misc/fonts/Roboto-Medium.ttf)
|
||||||
|
embed_resource(imgui src/misc/fonts/Cousine-Regular.ttf)
|
||||||
|
|
||||||
|
# Configure
|
||||||
|
target_compile_definitions(imgui PUBLIC
|
||||||
|
IMGUI_DISABLE_DEMO_WINDOWS
|
||||||
|
IMGUI_DISABLE_DEBUG_TOOLS
|
||||||
|
IMGUI_DISABLE_DEFAULT_FONT
|
||||||
|
IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
)
|
||||||
|
|
||||||
|
# Patch
|
||||||
|
execute_process(
|
||||||
|
COMMAND "patch" "-p1" "--forward" "--reject-file=-"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/fix-hidpi.patch"
|
||||||
|
OUTPUT_QUIET
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install
|
||||||
|
setup_library(imgui TRUE FALSE)
|
||||||
|
|
||||||
|
# License
|
||||||
|
install(FILES src/LICENSE.txt src/docs/FONTS.md DESTINATION "${MCPI_LEGAL_DIR}/ImGui")
|
55
dependencies/imgui/fix-hidpi.patch
vendored
Normal file
55
dependencies/imgui/fix-hidpi.patch
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
--- a/backends/imgui_impl_glfw.cpp
|
||||||
|
+++ b/backends/imgui_impl_glfw.cpp
|
||||||
|
@@ -422,6 +422,21 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||||
|
io.AddFocusEvent(focused != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void ImGui_ImplGlfw_ScaleMousePos(GLFWwindow* window, double &x, double &y) {
|
||||||
|
+ // Get Window Size
|
||||||
|
+ int window_width, window_height;
|
||||||
|
+ glfwGetWindowSize(window, &window_width, &window_height);
|
||||||
|
+ if (window_width <= 0 || window_height <= 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Get Framebuffer Size
|
||||||
|
+ int framebuffer_width, framebuffer_height;
|
||||||
|
+ glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
|
||||||
|
+ // Multiply
|
||||||
|
+ x *= double(framebuffer_width) / double(window_width);
|
||||||
|
+ y *= double(framebuffer_height) / double(window_height);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
@@ -429,6 +444,7 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||||
|
bd->PrevUserCallbackCursorPos(window, x, y);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
+ ImGui_ImplGlfw_ScaleMousePos(window, x, y);
|
||||||
|
io.AddMousePosEvent((float)x, (float)y);
|
||||||
|
bd->LastValidMousePos = ImVec2((float)x, (float)y);
|
||||||
|
}
|
||||||
|
@@ -738,6 +754,7 @@ static void ImGui_ImplGlfw_UpdateMouseData()
|
||||||
|
{
|
||||||
|
double mouse_x, mouse_y;
|
||||||
|
glfwGetCursorPos(window, &mouse_x, &mouse_y);
|
||||||
|
+ ImGui_ImplGlfw_ScaleMousePos(window, mouse_x, mouse_y);
|
||||||
|
bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||||
|
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
|
||||||
|
}
|
||||||
|
@@ -831,13 +848,9 @@ void ImGui_ImplGlfw_NewFrame()
|
||||||
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
- int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
- glfwGetWindowSize(bd->Window, &w, &h);
|
||||||
|
glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
|
||||||
|
- io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
- if (w > 0 && h > 0)
|
||||||
|
- io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);
|
||||||
|
+ io.DisplaySize = ImVec2((float)display_w, (float)display_h);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
// (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
|
49
dependencies/imgui/glad/CMakeLists.txt
vendored
Normal file
49
dependencies/imgui/glad/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
project(imgui-glad)
|
||||||
|
|
||||||
|
# Directories
|
||||||
|
set_and_mkdir(GLAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/glad")
|
||||||
|
set_and_mkdir(GLAD_SRC_DIR "${GLAD_DIR}/src")
|
||||||
|
set_and_mkdir(GLAD_INCLUDE_DIR "${GLAD_DIR}/include")
|
||||||
|
|
||||||
|
# Files
|
||||||
|
set(GLAD_SOURCES
|
||||||
|
"${GLAD_INCLUDE_DIR}/KHR/khrplatform.h"
|
||||||
|
"${GLAD_INCLUDE_DIR}/glad/glad.h"
|
||||||
|
"${GLAD_SRC_DIR}/glad.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find Python
|
||||||
|
find_package(Python REQUIRED QUIET)
|
||||||
|
|
||||||
|
# Generate
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${GLAD_SOURCES}
|
||||||
|
COMMAND "${Python_EXECUTABLE}"
|
||||||
|
ARGS "-m" "glad"
|
||||||
|
"--out" "${GLAD_DIR}"
|
||||||
|
"--api" "gl=1.1"
|
||||||
|
"--generator" "c"
|
||||||
|
"--reproducible"
|
||||||
|
"--quiet"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build
|
||||||
|
add_library(glad SHARED ${GLAD_SOURCES})
|
||||||
|
target_compile_definitions(glad
|
||||||
|
PUBLIC GLAD_GLAPI_EXPORT
|
||||||
|
PRIVATE GLAD_GLAPI_EXPORT_BUILD
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link
|
||||||
|
target_link_libraries(glad PRIVATE dl)
|
||||||
|
|
||||||
|
# Headers
|
||||||
|
setup_header_dirs(glad
|
||||||
|
"${GLAD_INCLUDE_DIR}"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install
|
||||||
|
setup_library(glad TRUE FALSE)
|
2
dependencies/imgui/glad/include/GL/gl.h
vendored
Normal file
2
dependencies/imgui/glad/include/GL/gl.h
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <glad/glad.h>
|
1
dependencies/imgui/glad/src
vendored
Submodule
1
dependencies/imgui/glad/src
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit e86f90457371c6233053bacf0d6f486a51ddcd67
|
1
dependencies/imgui/src
vendored
Submodule
1
dependencies/imgui/src
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 6982ce43f5b143c5dce5fab0ce07dd4867b705ae
|
5
dependencies/minecraft-pi/CMakeLists.txt
vendored
5
dependencies/minecraft-pi/CMakeLists.txt
vendored
@ -5,11 +5,10 @@ include(FetchContent)
|
|||||||
## Minecraft: Pi Edition
|
## Minecraft: Pi Edition
|
||||||
|
|
||||||
# Download
|
# Download
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(minecraft-pi
|
||||||
minecraft-pi
|
|
||||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/minecraft-pi-0.1.1.tar.gz"
|
URL "${CMAKE_CURRENT_SOURCE_DIR}/minecraft-pi-0.1.1.tar.gz"
|
||||||
)
|
)
|
||||||
FetchContent_Populate(minecraft-pi)
|
FetchContent_MakeAvailable(minecraft-pi)
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
install(
|
install(
|
||||||
|
14
dependencies/runtime/CMakeLists.txt
vendored
14
dependencies/runtime/CMakeLists.txt
vendored
@ -2,17 +2,11 @@ project(runtime)
|
|||||||
|
|
||||||
## Extra Runtime
|
## Extra Runtime
|
||||||
|
|
||||||
# QEMU
|
|
||||||
set(QEMU_VERSION "9.0.2")
|
|
||||||
set(RUNTIME_QEMU_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/../../archives/qemu-${QEMU_VERSION}.tar.xz")
|
|
||||||
if(NOT BUILD_NATIVE_COMPONENTS)
|
|
||||||
set(TRAMPOLINE_HEADERS_ONLY TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
# Install
|
# RPath
|
||||||
if(COMMAND install_runtime)
|
if(TARGET runtime)
|
||||||
install_runtime("${MCPI_BIN_DIR}" "${MCPI_LEGAL_DIR}")
|
set_target_properties(runtime PROPERTIES INSTALL_RPATH "$ORIGIN/../lib/native")
|
||||||
|
target_link_options(runtime PRIVATE "LINKER:--disable-new-dtags")
|
||||||
endif()
|
endif()
|
2
dependencies/runtime/src
vendored
2
dependencies/runtime/src
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 377f9ddbc4747ca3a640231d259c0e6fcc71b4b0
|
Subproject commit 84e37b572b55afb1eaa2ada1e37bc36de1584cfd
|
16
dependencies/stb_image/CMakeLists.txt
vendored
16
dependencies/stb_image/CMakeLists.txt
vendored
@ -7,24 +7,12 @@ add_compile_options(-w)
|
|||||||
|
|
||||||
# Build
|
# Build
|
||||||
add_library(stb_image SHARED src/stb_image_impl.c)
|
add_library(stb_image SHARED src/stb_image_impl.c)
|
||||||
target_include_directories(
|
|
||||||
stb_image
|
|
||||||
PUBLIC
|
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
|
||||||
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/stb_image>"
|
|
||||||
)
|
|
||||||
target_link_libraries(stb_image PRIVATE m)
|
target_link_libraries(stb_image PRIVATE m)
|
||||||
target_compile_definitions(stb_image PUBLIC STBI_ONLY_PNG)
|
target_compile_definitions(stb_image PUBLIC STBI_ONLY_PNG)
|
||||||
|
setup_header_dirs(stb_image "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
install(TARGETS stb_image DESTINATION "${MCPI_LIB_DIR}")
|
setup_library(stb_image TRUE TRUE)
|
||||||
install(
|
|
||||||
DIRECTORY "include/"
|
|
||||||
DESTINATION "${MCPI_SDK_INCLUDE_DIR}/stb_image"
|
|
||||||
FILES_MATCHING
|
|
||||||
PATTERN "*.h"
|
|
||||||
)
|
|
||||||
install(TARGETS stb_image EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
install(FILES include/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/stb_image")
|
install(FILES include/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/stb_image")
|
||||||
|
2
dependencies/symbol-processor/src
vendored
2
dependencies/symbol-processor/src
vendored
@ -1 +1 @@
|
|||||||
Subproject commit f72c4f0567c62897d74c734819c11705df0bf4ee
|
Subproject commit c803572e248998cc9d197f84661fea56bebf7346
|
2
dependencies/utf8cpp/CMakeLists.txt
vendored
2
dependencies/utf8cpp/CMakeLists.txt
vendored
@ -9,4 +9,4 @@ add_compile_options(-w)
|
|||||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
add_subdirectory(src EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
# License
|
# License
|
||||||
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/utf8cpp")
|
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/UTF8-CPP")
|
||||||
|
20
dependencies/zenity/CMakeLists.txt
vendored
20
dependencies/zenity/CMakeLists.txt
vendored
@ -1,20 +0,0 @@
|
|||||||
project(zenity)
|
|
||||||
|
|
||||||
# Silence Warnings
|
|
||||||
add_compile_options(-w)
|
|
||||||
|
|
||||||
## Zenity
|
|
||||||
|
|
||||||
# Download
|
|
||||||
set(MESSAGE_QUIET TRUE)
|
|
||||||
add_subdirectory(src EXCLUDE_FROM_ALL)
|
|
||||||
unset(MESSAGE_QUIET)
|
|
||||||
|
|
||||||
# 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")
|
|
1
dependencies/zenity/src
vendored
1
dependencies/zenity/src
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit a7496461161c917878d58131711425e7c8e59436
|
|
@ -51,6 +51,16 @@
|
|||||||
* `Render Vignette` (Enabled By Default)
|
* `Render Vignette` (Enabled By Default)
|
||||||
* `Increase Render Chunk Size` (Enabled By Default)
|
* `Increase Render Chunk Size` (Enabled By Default)
|
||||||
* `Proper Entity Shading` (Enabled By Default)
|
* `Proper Entity Shading` (Enabled By Default)
|
||||||
|
* `Fix Sugar Position In Hand` (Enabled By Default)
|
||||||
|
* `Fix Reloading Textures On Resize` (Enabled By Default)
|
||||||
|
* `Improved UI Scaling` (Enabled By Default)
|
||||||
|
* `Text Rendering Fixes` (Enabled By Default)
|
||||||
|
* `Close Editor When Sign Is Destroyed` (Enabled By Default)
|
||||||
|
* `Remove Chest Placement Restrictions` (Enabled By Default)
|
||||||
|
* `Fix Hanging When No Valid Spawn Point Exists` (Enabled By Default)
|
||||||
|
* `Batch Font Rendering` (Enabled By Default)
|
||||||
|
* `Fix Furnace Screen Visual Bug` (Enabled By Default)
|
||||||
|
* `Fix Held Item Poking Through Screen Overlay` (Enabled By Default)
|
||||||
* Existing Functionality (All Enabled By Default)
|
* Existing Functionality (All Enabled By Default)
|
||||||
* `Fix Screen Rendering When Hiding HUD`
|
* `Fix Screen Rendering When Hiding HUD`
|
||||||
* `Sanitize Usernames`
|
* `Sanitize Usernames`
|
||||||
@ -58,8 +68,6 @@
|
|||||||
* `Log RakNet Startup Errors`
|
* `Log RakNet Startup Errors`
|
||||||
* `Prevent Unnecessary Server Pinging`
|
* `Prevent Unnecessary Server Pinging`
|
||||||
* `Proper OpenGL Buffer Generation`
|
* `Proper OpenGL Buffer Generation`
|
||||||
* `Fix Furnace Screen Visual Bug`
|
|
||||||
* `Fix Text Wrapping`
|
|
||||||
* `Fullscreen Support`
|
* `Fullscreen Support`
|
||||||
* `Always Save Chest Tile Entities`
|
* `Always Save Chest Tile Entities`
|
||||||
* `Fix Transferring Durability When Using Items`
|
* `Fix Transferring Durability When Using Items`
|
||||||
@ -69,14 +77,31 @@
|
|||||||
* `Screenshot Support`
|
* `Screenshot Support`
|
||||||
* `Fix Camera Functionality`
|
* `Fix Camera Functionality`
|
||||||
* `Property Scale Animated Textures`
|
* `Property Scale Animated Textures`
|
||||||
|
* `Enable Text Input`
|
||||||
|
* `Update Default Options`
|
||||||
|
* `Fix options.txt Loading/Saving`
|
||||||
|
* `Extend Supported Keycodes`
|
||||||
* Split Up `Remove Creative Mode Restrictions` Feature Flag
|
* Split Up `Remove Creative Mode Restrictions` Feature Flag
|
||||||
* `Remove Creative Mode Restrictions` (Disabled By Default)
|
* `Remove Creative Mode Restrictions` (Disabled By Default)
|
||||||
* `Display Slot Count In Creative Mode` (Disabled By Default)
|
* `Display Slot Count In Creative Mode` (Disabled By Default)
|
||||||
* `Force Survival Mode Inventory UI` (Disabled By Default)
|
* `Force Survival Mode Inventory UI` (Disabled By Default)
|
||||||
* `Force Survival Mode Inventory Behavior` (Disabled By Default)
|
* `Force Survival Mode Inventory Behavior` (Disabled By Default)
|
||||||
* `Maximize Creative Mode Inventory Stack Size` (Disabled By Default)
|
* `Maximize Creative Mode Inventory Stack Size` (Disabled By Default)
|
||||||
* Rename `Disable Buggy Held Item Caching` Feature Flag To `Fix Held Item Caching`
|
* Split Up `Miscellaneous Input Fixes` Feature Flag
|
||||||
* Rename `Disable 'gui_blocks' Atlas` Feature Flag To `Regenerate "gui_blocks" Atlas`
|
* `Fix Escape Key Handling` (Enabled By Default)
|
||||||
|
* `Stop Locked Mouse From Interacting With HUD` (Enabled By Default)
|
||||||
|
* Rename Feature Flags
|
||||||
|
* `Disable Buggy Held Item Caching` To `Fix Held Item Caching`
|
||||||
|
* `Disable 'gui_blocks' Atlas` To `Regenerate "gui_blocks" Atlas`
|
||||||
|
* `Fix Sign Placement` To `Enable Sign Screen`
|
||||||
|
* `Force Touch GUI Inventory` To `Force Touch UI Inventory`
|
||||||
|
* `Full Touch GUI` To `Full Touch UI`
|
||||||
|
* `Force Touch GUI Button Behavior` To `Force Touch UI Button Behavior`
|
||||||
|
* `Remove Forced GUI Lag (Can Break Joining Servers)` To `Remove Forced UI Lag (Can Break Joining Servers)`
|
||||||
|
* `Hide Block Outline When GUI Is Hidden` To `Hide Block Outline When UI Is Hidden`
|
||||||
|
* `Fix Camera Functionality` To `Add Camera Functionality`
|
||||||
|
* `Fix Camera Rendering` To `Enable Camera Rendering`
|
||||||
|
* `Fix Camera Legs` To `Render Camera Legs`
|
||||||
* Add Milk Buckets
|
* Add Milk Buckets
|
||||||
* Included In The `Add Buckets` Feature Flag
|
* Included In The `Add Buckets` Feature Flag
|
||||||
* Removed `Property Scale Animated Textures` Feature Flag
|
* Removed `Property Scale Animated Textures` Feature Flag
|
||||||
@ -88,6 +113,7 @@
|
|||||||
* `overwrite_calls` Now Scans VTables
|
* `overwrite_calls` Now Scans VTables
|
||||||
* Unify Server/Client Builds
|
* Unify Server/Client Builds
|
||||||
* Controller Support Removed
|
* Controller Support Removed
|
||||||
|
* Brand New Launcher UI!
|
||||||
|
|
||||||
**2.5.3**
|
**2.5.3**
|
||||||
* Add `Replace Block Highlight With Outline` Feature Flag (Enabled By Default)
|
* Add `Replace Block Highlight With Outline` Feature Flag (Enabled By Default)
|
||||||
|
@ -7,4 +7,5 @@
|
|||||||
| [Ghidra](https://ghidra-sre.org) | Used For Decompiling Minecraft: Pi Edition |
|
| [Ghidra](https://ghidra-sre.org) | Used For Decompiling Minecraft: Pi Edition |
|
||||||
| [RetDec](https://retdec.com) | Used For Decompiling Minecraft: Pi Edition |
|
| [RetDec](https://retdec.com) | Used For Decompiling Minecraft: Pi Edition |
|
||||||
| [minecraft-linux/mcpelauncher-core](https://github.com/minecraft-linux/mcpelauncher-core/blob/6b5e17b5685a612143297ae4595bdd12327284f3/src/patch_utils.cpp#L42) | Original Function Overwrite Code |
|
| [minecraft-linux/mcpelauncher-core](https://github.com/minecraft-linux/mcpelauncher-core/blob/6b5e17b5685a612143297ae4595bdd12327284f3/src/patch_utils.cpp#L42) | Original Function Overwrite Code |
|
||||||
| [Hooking C Functions at Runtime - Thomas Finch](http://thomasfinch.me/blog/2015/07/24/Hooking-C-Functions-At-Runtime.html) | Original Patching Code |
|
| [Hooking C Functions at Runtime - Thomas Finch](http://thomasfinch.me/blog/2015/07/24/Hooking-C-Functions-At-Runtime.html) | Original Patching Code |
|
||||||
|
| [ReMinecraftPE](https://github.com/ReMinecraftPE/mcpe) | A Lot Of Decompiled Code |
|
@ -27,7 +27,7 @@ The AppImage requires Debian Bullseye or higher. This is equivalent to Ubuntu 20
|
|||||||
|
|
||||||
It also requires some additional packages. To install them, run:
|
It also requires some additional packages. To install them, run:
|
||||||
```sh
|
```sh
|
||||||
sudo apt install -y libfuse2 libgtk-3-0 libopenal1 libglib2.0-0
|
sudo apt install -y libopenal1 libglib2.0-0
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
@ -3,7 +3,6 @@
|
|||||||
* [View Dedicated Server](DEDICATED_SERVER.md)
|
* [View Dedicated Server](DEDICATED_SERVER.md)
|
||||||
* [View Credits](CREDITS.md)
|
* [View Credits](CREDITS.md)
|
||||||
* [View Terminology](TERMINOLOGY.md)
|
* [View Terminology](TERMINOLOGY.md)
|
||||||
* [View Multiplayer](MULTIPLAYER.md)
|
|
||||||
* [View In-Game Controls](CONTROLS.md)
|
* [View In-Game Controls](CONTROLS.md)
|
||||||
* [View Custom Skins](CUSTOM_SKINS.md)
|
* [View Custom Skins](CUSTOM_SKINS.md)
|
||||||
* [View Changelog](CHANGELOG.md)
|
* [View Changelog](CHANGELOG.md)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// Headers
|
#include <libreborn/patch.h>
|
||||||
#include <libreborn/libreborn.h>
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/util/string.h>
|
||||||
|
|
||||||
#include <symbols/minecraft.h>
|
#include <symbols/minecraft.h>
|
||||||
|
|
||||||
#include <mods/chat/chat.h>
|
#include <mods/chat/chat.h>
|
||||||
#include <mods/misc/misc.h>
|
#include <mods/misc/misc.h>
|
||||||
#include <mods/server/server.h>
|
#include <mods/server/server.h>
|
||||||
@ -17,7 +20,8 @@ HOOK(chat_handle_packet_send, void, (const Minecraft *minecraft, ChatPacket *pac
|
|||||||
if (out.length() > 0 && out[out.length() - 1] == '\n') {
|
if (out.length() > 0 && out[out.length() - 1] == '\n') {
|
||||||
out[out.length() - 1] = '\0';
|
out[out.length() - 1] = '\0';
|
||||||
}
|
}
|
||||||
gui->addMessage(out);
|
std::string cp437_out = to_cp437(out);
|
||||||
|
gui->addMessage(cp437_out);
|
||||||
} else {
|
} else {
|
||||||
// Call Original Method
|
// Call Original Method
|
||||||
real_chat_handle_packet_send()(minecraft, packet);
|
real_chat_handle_packet_send()(minecraft, packet);
|
||||||
|
@ -1,628 +1,540 @@
|
|||||||
// Headers
|
#include <libreborn/patch.h>
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
#include <symbols/minecraft.h>
|
#include <symbols/minecraft.h>
|
||||||
|
|
||||||
#include <mods/misc/misc.h>
|
#include <mods/misc/misc.h>
|
||||||
|
|
||||||
// The Actual Mod
|
// The Actual Mod
|
||||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
|
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
|
||||||
ItemInstance *fire_instance = new ItemInstance;
|
ItemInstance *fire_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(fire_instance);
|
|
||||||
fire_instance->count = 255;
|
fire_instance->count = 255;
|
||||||
fire_instance->auxiliary = 0;
|
fire_instance->auxiliary = 0;
|
||||||
fire_instance->id = 51;
|
fire_instance->id = 51;
|
||||||
filling_container->addItem(fire_instance);
|
filling_container->addItem(fire_instance);
|
||||||
|
|
||||||
ItemInstance *mushroomStew_instance = new ItemInstance;
|
ItemInstance *mushroomStew_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(mushroomStew_instance);
|
|
||||||
mushroomStew_instance->count = 255;
|
mushroomStew_instance->count = 255;
|
||||||
mushroomStew_instance->auxiliary = 0;
|
mushroomStew_instance->auxiliary = 0;
|
||||||
mushroomStew_instance->id = 282;
|
mushroomStew_instance->id = 282;
|
||||||
filling_container->addItem(mushroomStew_instance);
|
filling_container->addItem(mushroomStew_instance);
|
||||||
|
|
||||||
ItemInstance *steak_instance = new ItemInstance;
|
ItemInstance *steak_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(steak_instance);
|
|
||||||
steak_instance->count = 255;
|
steak_instance->count = 255;
|
||||||
steak_instance->auxiliary = 0;
|
steak_instance->auxiliary = 0;
|
||||||
steak_instance->id = 364;
|
steak_instance->id = 364;
|
||||||
filling_container->addItem(steak_instance);
|
filling_container->addItem(steak_instance);
|
||||||
|
|
||||||
ItemInstance *cookedChicken_instance = new ItemInstance;
|
ItemInstance *cookedChicken_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(cookedChicken_instance);
|
|
||||||
cookedChicken_instance->count = 255;
|
cookedChicken_instance->count = 255;
|
||||||
cookedChicken_instance->auxiliary = 0;
|
cookedChicken_instance->auxiliary = 0;
|
||||||
cookedChicken_instance->id = 366;
|
cookedChicken_instance->id = 366;
|
||||||
filling_container->addItem(cookedChicken_instance);
|
filling_container->addItem(cookedChicken_instance);
|
||||||
|
|
||||||
ItemInstance *porkCooked_instance = new ItemInstance;
|
ItemInstance *porkCooked_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(porkCooked_instance);
|
|
||||||
porkCooked_instance->count = 255;
|
porkCooked_instance->count = 255;
|
||||||
porkCooked_instance->auxiliary = 0;
|
porkCooked_instance->auxiliary = 0;
|
||||||
porkCooked_instance->id = 320;
|
porkCooked_instance->id = 320;
|
||||||
filling_container->addItem(porkCooked_instance);
|
filling_container->addItem(porkCooked_instance);
|
||||||
|
|
||||||
ItemInstance *apple_instance = new ItemInstance;
|
ItemInstance *apple_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(apple_instance);
|
|
||||||
apple_instance->count = 255;
|
apple_instance->count = 255;
|
||||||
apple_instance->auxiliary = 0;
|
apple_instance->auxiliary = 0;
|
||||||
apple_instance->id = 260;
|
apple_instance->id = 260;
|
||||||
filling_container->addItem(apple_instance);
|
filling_container->addItem(apple_instance);
|
||||||
|
|
||||||
ItemInstance *tallGrass_instance = new ItemInstance;
|
ItemInstance *tallGrass_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(tallGrass_instance);
|
|
||||||
tallGrass_instance->count = 255;
|
tallGrass_instance->count = 255;
|
||||||
tallGrass_instance->auxiliary = 0;
|
tallGrass_instance->auxiliary = 0;
|
||||||
tallGrass_instance->id = 31;
|
tallGrass_instance->id = 31;
|
||||||
filling_container->addItem(tallGrass_instance);
|
filling_container->addItem(tallGrass_instance);
|
||||||
|
|
||||||
ItemInstance *crops_instance = new ItemInstance;
|
ItemInstance *crops_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(crops_instance);
|
|
||||||
crops_instance->count = 255;
|
crops_instance->count = 255;
|
||||||
crops_instance->auxiliary = 0;
|
crops_instance->auxiliary = 0;
|
||||||
crops_instance->id = 59;
|
crops_instance->id = 59;
|
||||||
filling_container->addItem(crops_instance);
|
filling_container->addItem(crops_instance);
|
||||||
|
|
||||||
ItemInstance *farmland_instance = new ItemInstance;
|
ItemInstance *farmland_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(farmland_instance);
|
|
||||||
farmland_instance->count = 255;
|
farmland_instance->count = 255;
|
||||||
farmland_instance->auxiliary = 0;
|
farmland_instance->auxiliary = 0;
|
||||||
farmland_instance->id = 60;
|
farmland_instance->id = 60;
|
||||||
filling_container->addItem(farmland_instance);
|
filling_container->addItem(farmland_instance);
|
||||||
|
|
||||||
ItemInstance *activeFurnace_instance = new ItemInstance;
|
ItemInstance *activeFurnace_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(activeFurnace_instance);
|
|
||||||
activeFurnace_instance->count = 255;
|
activeFurnace_instance->count = 255;
|
||||||
activeFurnace_instance->auxiliary = 0;
|
activeFurnace_instance->auxiliary = 0;
|
||||||
activeFurnace_instance->id = 62;
|
activeFurnace_instance->id = 62;
|
||||||
filling_container->addItem(activeFurnace_instance);
|
filling_container->addItem(activeFurnace_instance);
|
||||||
|
|
||||||
ItemInstance *ironDoor_instance = new ItemInstance;
|
ItemInstance *ironDoor_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironDoor_instance);
|
|
||||||
ironDoor_instance->count = 255;
|
ironDoor_instance->count = 255;
|
||||||
ironDoor_instance->auxiliary = 0;
|
ironDoor_instance->auxiliary = 0;
|
||||||
ironDoor_instance->id = 330;
|
ironDoor_instance->id = 330;
|
||||||
filling_container->addItem(ironDoor_instance);
|
filling_container->addItem(ironDoor_instance);
|
||||||
|
|
||||||
ItemInstance *activeRedstoneOre_instance = new ItemInstance;
|
ItemInstance *activeRedstoneOre_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(activeRedstoneOre_instance);
|
|
||||||
activeRedstoneOre_instance->count = 255;
|
activeRedstoneOre_instance->count = 255;
|
||||||
activeRedstoneOre_instance->auxiliary = 0;
|
activeRedstoneOre_instance->auxiliary = 0;
|
||||||
activeRedstoneOre_instance->id = 74;
|
activeRedstoneOre_instance->id = 74;
|
||||||
filling_container->addItem(activeRedstoneOre_instance);
|
filling_container->addItem(activeRedstoneOre_instance);
|
||||||
|
|
||||||
ItemInstance *pumkinStem_instance = new ItemInstance;
|
ItemInstance *pumkinStem_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(pumkinStem_instance);
|
|
||||||
pumkinStem_instance->count = 255;
|
pumkinStem_instance->count = 255;
|
||||||
pumkinStem_instance->auxiliary = 0;
|
pumkinStem_instance->auxiliary = 0;
|
||||||
pumkinStem_instance->id = 105;
|
pumkinStem_instance->id = 105;
|
||||||
filling_container->addItem(pumkinStem_instance);
|
filling_container->addItem(pumkinStem_instance);
|
||||||
|
|
||||||
ItemInstance *newGrass_instance = new ItemInstance;
|
ItemInstance *newGrass_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(newGrass_instance);
|
|
||||||
newGrass_instance->count = 255;
|
newGrass_instance->count = 255;
|
||||||
newGrass_instance->auxiliary = 0;
|
newGrass_instance->auxiliary = 0;
|
||||||
newGrass_instance->id = 253;
|
newGrass_instance->id = 253;
|
||||||
filling_container->addItem(newGrass_instance);
|
filling_container->addItem(newGrass_instance);
|
||||||
|
|
||||||
ItemInstance *reserved6_instance = new ItemInstance;
|
ItemInstance *reserved6_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(reserved6_instance);
|
|
||||||
reserved6_instance->count = 255;
|
reserved6_instance->count = 255;
|
||||||
reserved6_instance->auxiliary = 0;
|
reserved6_instance->auxiliary = 0;
|
||||||
reserved6_instance->id = 1;
|
reserved6_instance->id = 1;
|
||||||
filling_container->addItem(reserved6_instance);
|
filling_container->addItem(reserved6_instance);
|
||||||
|
|
||||||
ItemInstance *doubleStoneSlab_instance = new ItemInstance;
|
ItemInstance *doubleStoneSlab_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(doubleStoneSlab_instance);
|
|
||||||
doubleStoneSlab_instance->count = 255;
|
doubleStoneSlab_instance->count = 255;
|
||||||
doubleStoneSlab_instance->auxiliary = 0;
|
doubleStoneSlab_instance->auxiliary = 0;
|
||||||
doubleStoneSlab_instance->id = 43;
|
doubleStoneSlab_instance->id = 43;
|
||||||
filling_container->addItem(doubleStoneSlab_instance);
|
filling_container->addItem(doubleStoneSlab_instance);
|
||||||
|
|
||||||
ItemInstance *arrow_instance = new ItemInstance;
|
ItemInstance *arrow_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(arrow_instance);
|
|
||||||
arrow_instance->count = 255;
|
arrow_instance->count = 255;
|
||||||
arrow_instance->auxiliary = 0;
|
arrow_instance->auxiliary = 0;
|
||||||
arrow_instance->id = 262;
|
arrow_instance->id = 262;
|
||||||
filling_container->addItem(arrow_instance);
|
filling_container->addItem(arrow_instance);
|
||||||
|
|
||||||
ItemInstance *coal_instance = new ItemInstance;
|
ItemInstance *coal_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(coal_instance);
|
|
||||||
coal_instance->count = 255;
|
coal_instance->count = 255;
|
||||||
coal_instance->auxiliary = 0;
|
coal_instance->auxiliary = 0;
|
||||||
coal_instance->id = 263;
|
coal_instance->id = 263;
|
||||||
filling_container->addItem(coal_instance);
|
filling_container->addItem(coal_instance);
|
||||||
|
|
||||||
ItemInstance *diamond_instance = new ItemInstance;
|
ItemInstance *diamond_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamond_instance);
|
|
||||||
diamond_instance->count = 255;
|
diamond_instance->count = 255;
|
||||||
diamond_instance->auxiliary = 0;
|
diamond_instance->auxiliary = 0;
|
||||||
diamond_instance->id = 264;
|
diamond_instance->id = 264;
|
||||||
filling_container->addItem(diamond_instance);
|
filling_container->addItem(diamond_instance);
|
||||||
|
|
||||||
ItemInstance *ironIngot_instance = new ItemInstance;
|
ItemInstance *ironIngot_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironIngot_instance);
|
|
||||||
ironIngot_instance->count = 255;
|
ironIngot_instance->count = 255;
|
||||||
ironIngot_instance->auxiliary = 0;
|
ironIngot_instance->auxiliary = 0;
|
||||||
ironIngot_instance->id = 265;
|
ironIngot_instance->id = 265;
|
||||||
filling_container->addItem(ironIngot_instance);
|
filling_container->addItem(ironIngot_instance);
|
||||||
|
|
||||||
ItemInstance *goldIngot_instance = new ItemInstance;
|
ItemInstance *goldIngot_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldIngot_instance);
|
|
||||||
goldIngot_instance->count = 255;
|
goldIngot_instance->count = 255;
|
||||||
goldIngot_instance->auxiliary = 0;
|
goldIngot_instance->auxiliary = 0;
|
||||||
goldIngot_instance->id = 266;
|
goldIngot_instance->id = 266;
|
||||||
filling_container->addItem(goldIngot_instance);
|
filling_container->addItem(goldIngot_instance);
|
||||||
|
|
||||||
ItemInstance *woodSword_instance = new ItemInstance;
|
ItemInstance *woodSword_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(woodSword_instance);
|
|
||||||
woodSword_instance->count = 255;
|
woodSword_instance->count = 255;
|
||||||
woodSword_instance->auxiliary = 0;
|
woodSword_instance->auxiliary = 0;
|
||||||
woodSword_instance->id = 268;
|
woodSword_instance->id = 268;
|
||||||
filling_container->addItem(woodSword_instance);
|
filling_container->addItem(woodSword_instance);
|
||||||
|
|
||||||
ItemInstance *woodShovel_instance = new ItemInstance;
|
ItemInstance *woodShovel_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(woodShovel_instance);
|
|
||||||
woodShovel_instance->count = 255;
|
woodShovel_instance->count = 255;
|
||||||
woodShovel_instance->auxiliary = 0;
|
woodShovel_instance->auxiliary = 0;
|
||||||
woodShovel_instance->id = 269;
|
woodShovel_instance->id = 269;
|
||||||
filling_container->addItem(woodShovel_instance);
|
filling_container->addItem(woodShovel_instance);
|
||||||
|
|
||||||
ItemInstance *woodPickaxe_instance = new ItemInstance;
|
ItemInstance *woodPickaxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(woodPickaxe_instance);
|
|
||||||
woodPickaxe_instance->count = 255;
|
woodPickaxe_instance->count = 255;
|
||||||
woodPickaxe_instance->auxiliary = 0;
|
woodPickaxe_instance->auxiliary = 0;
|
||||||
woodPickaxe_instance->id = 270;
|
woodPickaxe_instance->id = 270;
|
||||||
filling_container->addItem(woodPickaxe_instance);
|
filling_container->addItem(woodPickaxe_instance);
|
||||||
|
|
||||||
ItemInstance *woodAxe_instance = new ItemInstance;
|
ItemInstance *woodAxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(woodAxe_instance);
|
|
||||||
woodAxe_instance->count = 255;
|
woodAxe_instance->count = 255;
|
||||||
woodAxe_instance->auxiliary = 0;
|
woodAxe_instance->auxiliary = 0;
|
||||||
woodAxe_instance->id = 271;
|
woodAxe_instance->id = 271;
|
||||||
filling_container->addItem(woodAxe_instance);
|
filling_container->addItem(woodAxe_instance);
|
||||||
|
|
||||||
ItemInstance *stoneSword_instance = new ItemInstance;
|
ItemInstance *stoneSword_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(stoneSword_instance);
|
|
||||||
stoneSword_instance->count = 255;
|
stoneSword_instance->count = 255;
|
||||||
stoneSword_instance->auxiliary = 0;
|
stoneSword_instance->auxiliary = 0;
|
||||||
stoneSword_instance->id = 272;
|
stoneSword_instance->id = 272;
|
||||||
filling_container->addItem(stoneSword_instance);
|
filling_container->addItem(stoneSword_instance);
|
||||||
|
|
||||||
ItemInstance *stoneShovel_instance = new ItemInstance;
|
ItemInstance *stoneShovel_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(stoneShovel_instance);
|
|
||||||
stoneShovel_instance->count = 255;
|
stoneShovel_instance->count = 255;
|
||||||
stoneShovel_instance->auxiliary = 0;
|
stoneShovel_instance->auxiliary = 0;
|
||||||
stoneShovel_instance->id = 273;
|
stoneShovel_instance->id = 273;
|
||||||
filling_container->addItem(stoneShovel_instance);
|
filling_container->addItem(stoneShovel_instance);
|
||||||
|
|
||||||
ItemInstance *stonePickaxe_instance = new ItemInstance;
|
ItemInstance *stonePickaxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(stonePickaxe_instance);
|
|
||||||
stonePickaxe_instance->count = 255;
|
stonePickaxe_instance->count = 255;
|
||||||
stonePickaxe_instance->auxiliary = 0;
|
stonePickaxe_instance->auxiliary = 0;
|
||||||
stonePickaxe_instance->id = 274;
|
stonePickaxe_instance->id = 274;
|
||||||
filling_container->addItem(stonePickaxe_instance);
|
filling_container->addItem(stonePickaxe_instance);
|
||||||
|
|
||||||
ItemInstance *stoneAxe_instance = new ItemInstance;
|
ItemInstance *stoneAxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(stoneAxe_instance);
|
|
||||||
stoneAxe_instance->count = 255;
|
stoneAxe_instance->count = 255;
|
||||||
stoneAxe_instance->auxiliary = 0;
|
stoneAxe_instance->auxiliary = 0;
|
||||||
stoneAxe_instance->id = 275;
|
stoneAxe_instance->id = 275;
|
||||||
filling_container->addItem(stoneAxe_instance);
|
filling_container->addItem(stoneAxe_instance);
|
||||||
|
|
||||||
ItemInstance *shovelIron_instance = new ItemInstance;
|
ItemInstance *shovelIron_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(shovelIron_instance);
|
|
||||||
shovelIron_instance->count = 255;
|
shovelIron_instance->count = 255;
|
||||||
shovelIron_instance->auxiliary = 0;
|
shovelIron_instance->auxiliary = 0;
|
||||||
shovelIron_instance->id = 256;
|
shovelIron_instance->id = 256;
|
||||||
filling_container->addItem(shovelIron_instance);
|
filling_container->addItem(shovelIron_instance);
|
||||||
|
|
||||||
ItemInstance *ironPick_instance = new ItemInstance;
|
ItemInstance *ironPick_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironPick_instance);
|
|
||||||
ironPick_instance->count = 255;
|
ironPick_instance->count = 255;
|
||||||
ironPick_instance->auxiliary = 0;
|
ironPick_instance->auxiliary = 0;
|
||||||
ironPick_instance->id = 257;
|
ironPick_instance->id = 257;
|
||||||
filling_container->addItem(ironPick_instance);
|
filling_container->addItem(ironPick_instance);
|
||||||
|
|
||||||
ItemInstance *ironAxe_instance = new ItemInstance;
|
ItemInstance *ironAxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironAxe_instance);
|
|
||||||
ironAxe_instance->count = 255;
|
ironAxe_instance->count = 255;
|
||||||
ironAxe_instance->auxiliary = 0;
|
ironAxe_instance->auxiliary = 0;
|
||||||
ironAxe_instance->id = 258;
|
ironAxe_instance->id = 258;
|
||||||
filling_container->addItem(ironAxe_instance);
|
filling_container->addItem(ironAxe_instance);
|
||||||
|
|
||||||
ItemInstance *diamondSword_instance = new ItemInstance;
|
ItemInstance *diamondSword_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondSword_instance);
|
|
||||||
diamondSword_instance->count = 255;
|
diamondSword_instance->count = 255;
|
||||||
diamondSword_instance->auxiliary = 0;
|
diamondSword_instance->auxiliary = 0;
|
||||||
diamondSword_instance->id = 276;
|
diamondSword_instance->id = 276;
|
||||||
filling_container->addItem(diamondSword_instance);
|
filling_container->addItem(diamondSword_instance);
|
||||||
|
|
||||||
ItemInstance *diamondShovel_instance = new ItemInstance;
|
ItemInstance *diamondShovel_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondShovel_instance);
|
|
||||||
diamondShovel_instance->count = 255;
|
diamondShovel_instance->count = 255;
|
||||||
diamondShovel_instance->auxiliary = 0;
|
diamondShovel_instance->auxiliary = 0;
|
||||||
diamondShovel_instance->id = 277;
|
diamondShovel_instance->id = 277;
|
||||||
filling_container->addItem(diamondShovel_instance);
|
filling_container->addItem(diamondShovel_instance);
|
||||||
|
|
||||||
ItemInstance *diamondPickaxe_instance = new ItemInstance;
|
ItemInstance *diamondPickaxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondPickaxe_instance);
|
|
||||||
diamondPickaxe_instance->count = 255;
|
diamondPickaxe_instance->count = 255;
|
||||||
diamondPickaxe_instance->auxiliary = 0;
|
diamondPickaxe_instance->auxiliary = 0;
|
||||||
diamondPickaxe_instance->id = 278;
|
diamondPickaxe_instance->id = 278;
|
||||||
filling_container->addItem(diamondPickaxe_instance);
|
filling_container->addItem(diamondPickaxe_instance);
|
||||||
|
|
||||||
ItemInstance *diamondAxe_instance = new ItemInstance;
|
ItemInstance *diamondAxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondAxe_instance);
|
|
||||||
diamondAxe_instance->count = 255;
|
diamondAxe_instance->count = 255;
|
||||||
diamondAxe_instance->auxiliary = 0;
|
diamondAxe_instance->auxiliary = 0;
|
||||||
diamondAxe_instance->id = 279;
|
diamondAxe_instance->id = 279;
|
||||||
filling_container->addItem(diamondAxe_instance);
|
filling_container->addItem(diamondAxe_instance);
|
||||||
|
|
||||||
ItemInstance *magicWand_instance = new ItemInstance;
|
ItemInstance *magicWand_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(magicWand_instance);
|
|
||||||
magicWand_instance->count = 255;
|
magicWand_instance->count = 255;
|
||||||
magicWand_instance->auxiliary = 0;
|
magicWand_instance->auxiliary = 0;
|
||||||
magicWand_instance->id = 280;
|
magicWand_instance->id = 280;
|
||||||
filling_container->addItem(magicWand_instance);
|
filling_container->addItem(magicWand_instance);
|
||||||
|
|
||||||
ItemInstance *bowl_instance = new ItemInstance;
|
ItemInstance *bowl_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(bowl_instance);
|
|
||||||
bowl_instance->count = 255;
|
bowl_instance->count = 255;
|
||||||
bowl_instance->auxiliary = 0;
|
bowl_instance->auxiliary = 0;
|
||||||
bowl_instance->id = 281;
|
bowl_instance->id = 281;
|
||||||
filling_container->addItem(bowl_instance);
|
filling_container->addItem(bowl_instance);
|
||||||
|
|
||||||
ItemInstance *goldSword_instance = new ItemInstance;
|
ItemInstance *goldSword_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldSword_instance);
|
|
||||||
goldSword_instance->count = 255;
|
goldSword_instance->count = 255;
|
||||||
goldSword_instance->auxiliary = 0;
|
goldSword_instance->auxiliary = 0;
|
||||||
goldSword_instance->id = 283;
|
goldSword_instance->id = 283;
|
||||||
filling_container->addItem(goldSword_instance);
|
filling_container->addItem(goldSword_instance);
|
||||||
|
|
||||||
ItemInstance *goldShovel_instance = new ItemInstance;
|
ItemInstance *goldShovel_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldShovel_instance);
|
|
||||||
goldShovel_instance->count = 255;
|
goldShovel_instance->count = 255;
|
||||||
goldShovel_instance->auxiliary = 0;
|
goldShovel_instance->auxiliary = 0;
|
||||||
goldShovel_instance->id = 284;
|
goldShovel_instance->id = 284;
|
||||||
filling_container->addItem(goldShovel_instance);
|
filling_container->addItem(goldShovel_instance);
|
||||||
|
|
||||||
ItemInstance *goldPickaxe_instance = new ItemInstance;
|
ItemInstance *goldPickaxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldPickaxe_instance);
|
|
||||||
goldPickaxe_instance->count = 255;
|
goldPickaxe_instance->count = 255;
|
||||||
goldPickaxe_instance->auxiliary = 0;
|
goldPickaxe_instance->auxiliary = 0;
|
||||||
goldPickaxe_instance->id = 285;
|
goldPickaxe_instance->id = 285;
|
||||||
filling_container->addItem(goldPickaxe_instance);
|
filling_container->addItem(goldPickaxe_instance);
|
||||||
|
|
||||||
ItemInstance *goldAxe_instance = new ItemInstance;
|
ItemInstance *goldAxe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldAxe_instance);
|
|
||||||
goldAxe_instance->count = 255;
|
goldAxe_instance->count = 255;
|
||||||
goldAxe_instance->auxiliary = 0;
|
goldAxe_instance->auxiliary = 0;
|
||||||
goldAxe_instance->id = 286;
|
goldAxe_instance->id = 286;
|
||||||
filling_container->addItem(goldAxe_instance);
|
filling_container->addItem(goldAxe_instance);
|
||||||
|
|
||||||
ItemInstance *string_instance = new ItemInstance;
|
ItemInstance *string_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(string_instance);
|
|
||||||
string_instance->count = 255;
|
string_instance->count = 255;
|
||||||
string_instance->auxiliary = 0;
|
string_instance->auxiliary = 0;
|
||||||
string_instance->id = 287;
|
string_instance->id = 287;
|
||||||
filling_container->addItem(string_instance);
|
filling_container->addItem(string_instance);
|
||||||
|
|
||||||
ItemInstance *feather_instance = new ItemInstance;
|
ItemInstance *feather_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(feather_instance);
|
|
||||||
feather_instance->count = 255;
|
feather_instance->count = 255;
|
||||||
feather_instance->auxiliary = 0;
|
feather_instance->auxiliary = 0;
|
||||||
feather_instance->id = 288;
|
feather_instance->id = 288;
|
||||||
filling_container->addItem(feather_instance);
|
filling_container->addItem(feather_instance);
|
||||||
|
|
||||||
ItemInstance *gunpowder_instance = new ItemInstance;
|
ItemInstance *gunpowder_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(gunpowder_instance);
|
|
||||||
gunpowder_instance->count = 255;
|
gunpowder_instance->count = 255;
|
||||||
gunpowder_instance->auxiliary = 0;
|
gunpowder_instance->auxiliary = 0;
|
||||||
gunpowder_instance->id = 289;
|
gunpowder_instance->id = 289;
|
||||||
filling_container->addItem(gunpowder_instance);
|
filling_container->addItem(gunpowder_instance);
|
||||||
|
|
||||||
ItemInstance *woodHoe_instance = new ItemInstance;
|
ItemInstance *woodHoe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(woodHoe_instance);
|
|
||||||
woodHoe_instance->count = 255;
|
woodHoe_instance->count = 255;
|
||||||
woodHoe_instance->auxiliary = 0;
|
woodHoe_instance->auxiliary = 0;
|
||||||
woodHoe_instance->id = 290;
|
woodHoe_instance->id = 290;
|
||||||
filling_container->addItem(woodHoe_instance);
|
filling_container->addItem(woodHoe_instance);
|
||||||
|
|
||||||
ItemInstance *stoneHoe_instance = new ItemInstance;
|
ItemInstance *stoneHoe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(stoneHoe_instance);
|
|
||||||
stoneHoe_instance->count = 255;
|
stoneHoe_instance->count = 255;
|
||||||
stoneHoe_instance->auxiliary = 0;
|
stoneHoe_instance->auxiliary = 0;
|
||||||
stoneHoe_instance->id = 291;
|
stoneHoe_instance->id = 291;
|
||||||
filling_container->addItem(stoneHoe_instance);
|
filling_container->addItem(stoneHoe_instance);
|
||||||
|
|
||||||
ItemInstance *flint1_instance = new ItemInstance;
|
ItemInstance *flint1_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(flint1_instance);
|
|
||||||
flint1_instance->count = 255;
|
flint1_instance->count = 255;
|
||||||
flint1_instance->auxiliary = 0;
|
flint1_instance->auxiliary = 0;
|
||||||
flint1_instance->id = 292;
|
flint1_instance->id = 292;
|
||||||
filling_container->addItem(flint1_instance);
|
filling_container->addItem(flint1_instance);
|
||||||
|
|
||||||
ItemInstance *diamondHoe_instance = new ItemInstance;
|
ItemInstance *diamondHoe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondHoe_instance);
|
|
||||||
diamondHoe_instance->count = 255;
|
diamondHoe_instance->count = 255;
|
||||||
diamondHoe_instance->auxiliary = 0;
|
diamondHoe_instance->auxiliary = 0;
|
||||||
diamondHoe_instance->id = 293;
|
diamondHoe_instance->id = 293;
|
||||||
filling_container->addItem(diamondHoe_instance);
|
filling_container->addItem(diamondHoe_instance);
|
||||||
|
|
||||||
ItemInstance *goldHoe_instance = new ItemInstance;
|
ItemInstance *goldHoe_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldHoe_instance);
|
|
||||||
goldHoe_instance->count = 255;
|
goldHoe_instance->count = 255;
|
||||||
goldHoe_instance->auxiliary = 0;
|
goldHoe_instance->auxiliary = 0;
|
||||||
goldHoe_instance->id = 294;
|
goldHoe_instance->id = 294;
|
||||||
filling_container->addItem(goldHoe_instance);
|
filling_container->addItem(goldHoe_instance);
|
||||||
|
|
||||||
ItemInstance *seeds_instance = new ItemInstance;
|
ItemInstance *seeds_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(seeds_instance);
|
|
||||||
seeds_instance->count = 255;
|
seeds_instance->count = 255;
|
||||||
seeds_instance->auxiliary = 0;
|
seeds_instance->auxiliary = 0;
|
||||||
seeds_instance->id = 295;
|
seeds_instance->id = 295;
|
||||||
filling_container->addItem(seeds_instance);
|
filling_container->addItem(seeds_instance);
|
||||||
|
|
||||||
ItemInstance *wheat_instance = new ItemInstance;
|
ItemInstance *wheat_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(wheat_instance);
|
|
||||||
wheat_instance->count = 255;
|
wheat_instance->count = 255;
|
||||||
wheat_instance->auxiliary = 0;
|
wheat_instance->auxiliary = 0;
|
||||||
wheat_instance->id = 296;
|
wheat_instance->id = 296;
|
||||||
filling_container->addItem(wheat_instance);
|
filling_container->addItem(wheat_instance);
|
||||||
|
|
||||||
ItemInstance *bread_instance = new ItemInstance;
|
ItemInstance *bread_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(bread_instance);
|
|
||||||
bread_instance->count = 255;
|
bread_instance->count = 255;
|
||||||
bread_instance->auxiliary = 0;
|
bread_instance->auxiliary = 0;
|
||||||
bread_instance->id = 297;
|
bread_instance->id = 297;
|
||||||
filling_container->addItem(bread_instance);
|
filling_container->addItem(bread_instance);
|
||||||
|
|
||||||
ItemInstance *diamondHelm_instance = new ItemInstance;
|
ItemInstance *diamondHelm_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondHelm_instance);
|
|
||||||
diamondHelm_instance->count = 255;
|
diamondHelm_instance->count = 255;
|
||||||
diamondHelm_instance->auxiliary = 0;
|
diamondHelm_instance->auxiliary = 0;
|
||||||
diamondHelm_instance->id = 310;
|
diamondHelm_instance->id = 310;
|
||||||
filling_container->addItem(diamondHelm_instance);
|
filling_container->addItem(diamondHelm_instance);
|
||||||
|
|
||||||
ItemInstance *diamondChest_instance = new ItemInstance;
|
ItemInstance *diamondChest_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondChest_instance);
|
|
||||||
diamondChest_instance->count = 255;
|
diamondChest_instance->count = 255;
|
||||||
diamondChest_instance->auxiliary = 0;
|
diamondChest_instance->auxiliary = 0;
|
||||||
diamondChest_instance->id = 311;
|
diamondChest_instance->id = 311;
|
||||||
filling_container->addItem(diamondChest_instance);
|
filling_container->addItem(diamondChest_instance);
|
||||||
|
|
||||||
ItemInstance *diamondLeg_instance = new ItemInstance;
|
ItemInstance *diamondLeg_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondLeg_instance);
|
|
||||||
diamondLeg_instance->count = 255;
|
diamondLeg_instance->count = 255;
|
||||||
diamondLeg_instance->auxiliary = 0;
|
diamondLeg_instance->auxiliary = 0;
|
||||||
diamondLeg_instance->id = 312;
|
diamondLeg_instance->id = 312;
|
||||||
filling_container->addItem(diamondLeg_instance);
|
filling_container->addItem(diamondLeg_instance);
|
||||||
|
|
||||||
ItemInstance *diamondBoot_instance = new ItemInstance;
|
ItemInstance *diamondBoot_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(diamondBoot_instance);
|
|
||||||
diamondBoot_instance->count = 255;
|
diamondBoot_instance->count = 255;
|
||||||
diamondBoot_instance->auxiliary = 0;
|
diamondBoot_instance->auxiliary = 0;
|
||||||
diamondBoot_instance->id = 313;
|
diamondBoot_instance->id = 313;
|
||||||
filling_container->addItem(diamondBoot_instance);
|
filling_container->addItem(diamondBoot_instance);
|
||||||
|
|
||||||
ItemInstance *leatherCap_instance = new ItemInstance;
|
ItemInstance *leatherCap_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(leatherCap_instance);
|
|
||||||
leatherCap_instance->count = 255;
|
leatherCap_instance->count = 255;
|
||||||
leatherCap_instance->auxiliary = 0;
|
leatherCap_instance->auxiliary = 0;
|
||||||
leatherCap_instance->id = 298;
|
leatherCap_instance->id = 298;
|
||||||
filling_container->addItem(leatherCap_instance);
|
filling_container->addItem(leatherCap_instance);
|
||||||
|
|
||||||
ItemInstance *leatherShirt_instance = new ItemInstance;
|
ItemInstance *leatherShirt_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(leatherShirt_instance);
|
|
||||||
leatherShirt_instance->count = 255;
|
leatherShirt_instance->count = 255;
|
||||||
leatherShirt_instance->auxiliary = 0;
|
leatherShirt_instance->auxiliary = 0;
|
||||||
leatherShirt_instance->id = 299;
|
leatherShirt_instance->id = 299;
|
||||||
filling_container->addItem(leatherShirt_instance);
|
filling_container->addItem(leatherShirt_instance);
|
||||||
|
|
||||||
ItemInstance *leatherPants_instance = new ItemInstance;
|
ItemInstance *leatherPants_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(leatherPants_instance);
|
|
||||||
leatherPants_instance->count = 255;
|
leatherPants_instance->count = 255;
|
||||||
leatherPants_instance->auxiliary = 0;
|
leatherPants_instance->auxiliary = 0;
|
||||||
leatherPants_instance->id = 300;
|
leatherPants_instance->id = 300;
|
||||||
filling_container->addItem(leatherPants_instance);
|
filling_container->addItem(leatherPants_instance);
|
||||||
|
|
||||||
ItemInstance *leatherBoots_instance = new ItemInstance;
|
ItemInstance *leatherBoots_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(leatherBoots_instance);
|
|
||||||
leatherBoots_instance->count = 255;
|
leatherBoots_instance->count = 255;
|
||||||
leatherBoots_instance->auxiliary = 0;
|
leatherBoots_instance->auxiliary = 0;
|
||||||
leatherBoots_instance->id = 301;
|
leatherBoots_instance->id = 301;
|
||||||
filling_container->addItem(leatherBoots_instance);
|
filling_container->addItem(leatherBoots_instance);
|
||||||
|
|
||||||
ItemInstance *chainHelm_instance = new ItemInstance;
|
ItemInstance *chainHelm_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(chainHelm_instance);
|
|
||||||
chainHelm_instance->count = 255;
|
chainHelm_instance->count = 255;
|
||||||
chainHelm_instance->auxiliary = 0;
|
chainHelm_instance->auxiliary = 0;
|
||||||
chainHelm_instance->id = 302;
|
chainHelm_instance->id = 302;
|
||||||
filling_container->addItem(chainHelm_instance);
|
filling_container->addItem(chainHelm_instance);
|
||||||
|
|
||||||
ItemInstance *chainShirt_instance = new ItemInstance;
|
ItemInstance *chainShirt_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(chainShirt_instance);
|
|
||||||
chainShirt_instance->count = 255;
|
chainShirt_instance->count = 255;
|
||||||
chainShirt_instance->auxiliary = 0;
|
chainShirt_instance->auxiliary = 0;
|
||||||
chainShirt_instance->id = 303;
|
chainShirt_instance->id = 303;
|
||||||
filling_container->addItem(chainShirt_instance);
|
filling_container->addItem(chainShirt_instance);
|
||||||
|
|
||||||
ItemInstance *chainLegs_instance = new ItemInstance;
|
ItemInstance *chainLegs_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(chainLegs_instance);
|
|
||||||
chainLegs_instance->count = 255;
|
chainLegs_instance->count = 255;
|
||||||
chainLegs_instance->auxiliary = 0;
|
chainLegs_instance->auxiliary = 0;
|
||||||
chainLegs_instance->id = 304;
|
chainLegs_instance->id = 304;
|
||||||
filling_container->addItem(chainLegs_instance);
|
filling_container->addItem(chainLegs_instance);
|
||||||
|
|
||||||
ItemInstance *chainBoots_instance = new ItemInstance;
|
ItemInstance *chainBoots_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(chainBoots_instance);
|
|
||||||
chainBoots_instance->count = 255;
|
chainBoots_instance->count = 255;
|
||||||
chainBoots_instance->auxiliary = 0;
|
chainBoots_instance->auxiliary = 0;
|
||||||
chainBoots_instance->id = 305;
|
chainBoots_instance->id = 305;
|
||||||
filling_container->addItem(chainBoots_instance);
|
filling_container->addItem(chainBoots_instance);
|
||||||
|
|
||||||
ItemInstance *goldHelm_instance = new ItemInstance;
|
ItemInstance *goldHelm_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldHelm_instance);
|
|
||||||
goldHelm_instance->count = 255;
|
goldHelm_instance->count = 255;
|
||||||
goldHelm_instance->auxiliary = 0;
|
goldHelm_instance->auxiliary = 0;
|
||||||
goldHelm_instance->id = 314;
|
goldHelm_instance->id = 314;
|
||||||
filling_container->addItem(goldHelm_instance);
|
filling_container->addItem(goldHelm_instance);
|
||||||
|
|
||||||
ItemInstance *goldChest_instance = new ItemInstance;
|
ItemInstance *goldChest_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldChest_instance);
|
|
||||||
goldChest_instance->count = 255;
|
goldChest_instance->count = 255;
|
||||||
goldChest_instance->auxiliary = 0;
|
goldChest_instance->auxiliary = 0;
|
||||||
goldChest_instance->id = 315;
|
goldChest_instance->id = 315;
|
||||||
filling_container->addItem(goldChest_instance);
|
filling_container->addItem(goldChest_instance);
|
||||||
|
|
||||||
ItemInstance *goldLegs_instance = new ItemInstance;
|
ItemInstance *goldLegs_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldLegs_instance);
|
|
||||||
goldLegs_instance->count = 255;
|
goldLegs_instance->count = 255;
|
||||||
goldLegs_instance->auxiliary = 0;
|
goldLegs_instance->auxiliary = 0;
|
||||||
goldLegs_instance->id = 316;
|
goldLegs_instance->id = 316;
|
||||||
filling_container->addItem(goldLegs_instance);
|
filling_container->addItem(goldLegs_instance);
|
||||||
|
|
||||||
ItemInstance *goldBoots_instance = new ItemInstance;
|
ItemInstance *goldBoots_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(goldBoots_instance);
|
|
||||||
goldBoots_instance->count = 255;
|
goldBoots_instance->count = 255;
|
||||||
goldBoots_instance->auxiliary = 0;
|
goldBoots_instance->auxiliary = 0;
|
||||||
goldBoots_instance->id = 317;
|
goldBoots_instance->id = 317;
|
||||||
filling_container->addItem(goldBoots_instance);
|
filling_container->addItem(goldBoots_instance);
|
||||||
|
|
||||||
ItemInstance *ironHelm_instance = new ItemInstance;
|
ItemInstance *ironHelm_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironHelm_instance);
|
|
||||||
ironHelm_instance->count = 255;
|
ironHelm_instance->count = 255;
|
||||||
ironHelm_instance->auxiliary = 0;
|
ironHelm_instance->auxiliary = 0;
|
||||||
ironHelm_instance->id = 306;
|
ironHelm_instance->id = 306;
|
||||||
filling_container->addItem(ironHelm_instance);
|
filling_container->addItem(ironHelm_instance);
|
||||||
|
|
||||||
ItemInstance *ironChest_instance = new ItemInstance;
|
ItemInstance *ironChest_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironChest_instance);
|
|
||||||
ironChest_instance->count = 255;
|
ironChest_instance->count = 255;
|
||||||
ironChest_instance->auxiliary = 0;
|
ironChest_instance->auxiliary = 0;
|
||||||
ironChest_instance->id = 307;
|
ironChest_instance->id = 307;
|
||||||
filling_container->addItem(ironChest_instance);
|
filling_container->addItem(ironChest_instance);
|
||||||
|
|
||||||
ItemInstance *ironLegs_instance = new ItemInstance;
|
ItemInstance *ironLegs_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironLegs_instance);
|
|
||||||
ironLegs_instance->count = 255;
|
ironLegs_instance->count = 255;
|
||||||
ironLegs_instance->auxiliary = 0;
|
ironLegs_instance->auxiliary = 0;
|
||||||
ironLegs_instance->id = 308;
|
ironLegs_instance->id = 308;
|
||||||
filling_container->addItem(ironLegs_instance);
|
filling_container->addItem(ironLegs_instance);
|
||||||
|
|
||||||
ItemInstance *ironBoots_instance = new ItemInstance;
|
ItemInstance *ironBoots_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(ironBoots_instance);
|
|
||||||
ironBoots_instance->count = 255;
|
ironBoots_instance->count = 255;
|
||||||
ironBoots_instance->auxiliary = 0;
|
ironBoots_instance->auxiliary = 0;
|
||||||
ironBoots_instance->id = 309;
|
ironBoots_instance->id = 309;
|
||||||
filling_container->addItem(ironBoots_instance);
|
filling_container->addItem(ironBoots_instance);
|
||||||
|
|
||||||
ItemInstance *flint2_instance = new ItemInstance;
|
ItemInstance *flint2_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(flint2_instance);
|
|
||||||
flint2_instance->count = 255;
|
flint2_instance->count = 255;
|
||||||
flint2_instance->auxiliary = 0;
|
flint2_instance->auxiliary = 0;
|
||||||
flint2_instance->id = 318;
|
flint2_instance->id = 318;
|
||||||
filling_container->addItem(flint2_instance);
|
filling_container->addItem(flint2_instance);
|
||||||
|
|
||||||
ItemInstance *porkRaw_instance = new ItemInstance;
|
ItemInstance *porkRaw_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(porkRaw_instance);
|
|
||||||
porkRaw_instance->count = 255;
|
porkRaw_instance->count = 255;
|
||||||
porkRaw_instance->auxiliary = 0;
|
porkRaw_instance->auxiliary = 0;
|
||||||
porkRaw_instance->id = 319;
|
porkRaw_instance->id = 319;
|
||||||
filling_container->addItem(porkRaw_instance);
|
filling_container->addItem(porkRaw_instance);
|
||||||
|
|
||||||
ItemInstance *leather_instance = new ItemInstance;
|
ItemInstance *leather_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(leather_instance);
|
|
||||||
leather_instance->count = 255;
|
leather_instance->count = 255;
|
||||||
leather_instance->auxiliary = 0;
|
leather_instance->auxiliary = 0;
|
||||||
leather_instance->id = 334;
|
leather_instance->id = 334;
|
||||||
filling_container->addItem(leather_instance);
|
filling_container->addItem(leather_instance);
|
||||||
|
|
||||||
ItemInstance *clayBrick_instance = new ItemInstance;
|
ItemInstance *clayBrick_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(clayBrick_instance);
|
|
||||||
clayBrick_instance->count = 255;
|
clayBrick_instance->count = 255;
|
||||||
clayBrick_instance->auxiliary = 0;
|
clayBrick_instance->auxiliary = 0;
|
||||||
clayBrick_instance->id = 336;
|
clayBrick_instance->id = 336;
|
||||||
filling_container->addItem(clayBrick_instance);
|
filling_container->addItem(clayBrick_instance);
|
||||||
|
|
||||||
ItemInstance *clay_instance = new ItemInstance;
|
ItemInstance *clay_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(clay_instance);
|
|
||||||
clay_instance->count = 255;
|
clay_instance->count = 255;
|
||||||
clay_instance->auxiliary = 0;
|
clay_instance->auxiliary = 0;
|
||||||
clay_instance->id = 337;
|
clay_instance->id = 337;
|
||||||
filling_container->addItem(clay_instance);
|
filling_container->addItem(clay_instance);
|
||||||
|
|
||||||
ItemInstance *notepad_instance = new ItemInstance;
|
ItemInstance *notepad_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(notepad_instance);
|
|
||||||
notepad_instance->count = 255;
|
notepad_instance->count = 255;
|
||||||
notepad_instance->auxiliary = 0;
|
notepad_instance->auxiliary = 0;
|
||||||
notepad_instance->id = 339;
|
notepad_instance->id = 339;
|
||||||
filling_container->addItem(notepad_instance);
|
filling_container->addItem(notepad_instance);
|
||||||
|
|
||||||
ItemInstance *book_instance = new ItemInstance;
|
ItemInstance *book_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(book_instance);
|
|
||||||
book_instance->count = 255;
|
book_instance->count = 255;
|
||||||
book_instance->auxiliary = 0;
|
book_instance->auxiliary = 0;
|
||||||
book_instance->id = 340;
|
book_instance->id = 340;
|
||||||
filling_container->addItem(book_instance);
|
filling_container->addItem(book_instance);
|
||||||
|
|
||||||
ItemInstance *slimeball_instance = new ItemInstance;
|
ItemInstance *slimeball_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(slimeball_instance);
|
|
||||||
slimeball_instance->count = 255;
|
slimeball_instance->count = 255;
|
||||||
slimeball_instance->auxiliary = 0;
|
slimeball_instance->auxiliary = 0;
|
||||||
slimeball_instance->id = 341;
|
slimeball_instance->id = 341;
|
||||||
filling_container->addItem(slimeball_instance);
|
filling_container->addItem(slimeball_instance);
|
||||||
|
|
||||||
ItemInstance *compass_instance = new ItemInstance;
|
ItemInstance *compass_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(compass_instance);
|
|
||||||
compass_instance->count = 255;
|
compass_instance->count = 255;
|
||||||
compass_instance->auxiliary = 0;
|
compass_instance->auxiliary = 0;
|
||||||
compass_instance->id = 345;
|
compass_instance->id = 345;
|
||||||
filling_container->addItem(compass_instance);
|
filling_container->addItem(compass_instance);
|
||||||
|
|
||||||
ItemInstance *clock_instance = new ItemInstance;
|
ItemInstance *clock_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(clock_instance);
|
|
||||||
clock_instance->count = 255;
|
clock_instance->count = 255;
|
||||||
clock_instance->auxiliary = 0;
|
clock_instance->auxiliary = 0;
|
||||||
clock_instance->id = 347;
|
clock_instance->id = 347;
|
||||||
filling_container->addItem(clock_instance);
|
filling_container->addItem(clock_instance);
|
||||||
|
|
||||||
ItemInstance *glowDust_instance = new ItemInstance;
|
ItemInstance *glowDust_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(glowDust_instance);
|
|
||||||
glowDust_instance->count = 255;
|
glowDust_instance->count = 255;
|
||||||
glowDust_instance->auxiliary = 0;
|
glowDust_instance->auxiliary = 0;
|
||||||
glowDust_instance->id = 348;
|
glowDust_instance->id = 348;
|
||||||
filling_container->addItem(glowDust_instance);
|
filling_container->addItem(glowDust_instance);
|
||||||
|
|
||||||
ItemInstance *bone_instance = new ItemInstance;
|
ItemInstance *bone_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(bone_instance);
|
|
||||||
bone_instance->count = 255;
|
bone_instance->count = 255;
|
||||||
bone_instance->auxiliary = 0;
|
bone_instance->auxiliary = 0;
|
||||||
bone_instance->id = 352;
|
bone_instance->id = 352;
|
||||||
filling_container->addItem(bone_instance);
|
filling_container->addItem(bone_instance);
|
||||||
|
|
||||||
ItemInstance *sugar_instance = new ItemInstance;
|
ItemInstance *sugar_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(sugar_instance);
|
|
||||||
sugar_instance->count = 255;
|
sugar_instance->count = 255;
|
||||||
sugar_instance->auxiliary = 0;
|
sugar_instance->auxiliary = 0;
|
||||||
sugar_instance->id = 353;
|
sugar_instance->id = 353;
|
||||||
filling_container->addItem(sugar_instance);
|
filling_container->addItem(sugar_instance);
|
||||||
|
|
||||||
ItemInstance *melon_instance = new ItemInstance;
|
ItemInstance *melon_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(melon_instance);
|
|
||||||
melon_instance->count = 255;
|
melon_instance->count = 255;
|
||||||
melon_instance->auxiliary = 0;
|
melon_instance->auxiliary = 0;
|
||||||
melon_instance->id = 360;
|
melon_instance->id = 360;
|
||||||
filling_container->addItem(melon_instance);
|
filling_container->addItem(melon_instance);
|
||||||
|
|
||||||
ItemInstance *beefRaw_instance = new ItemInstance;
|
ItemInstance *beefRaw_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(beefRaw_instance);
|
|
||||||
beefRaw_instance->count = 255;
|
beefRaw_instance->count = 255;
|
||||||
beefRaw_instance->auxiliary = 0;
|
beefRaw_instance->auxiliary = 0;
|
||||||
beefRaw_instance->id = 363;
|
beefRaw_instance->id = 363;
|
||||||
filling_container->addItem(beefRaw_instance);
|
filling_container->addItem(beefRaw_instance);
|
||||||
|
|
||||||
ItemInstance *chickenRaw_instance = new ItemInstance;
|
ItemInstance *chickenRaw_instance = new ItemInstance;
|
||||||
ALLOC_CHECK(chickenRaw_instance);
|
|
||||||
chickenRaw_instance->count = 255;
|
chickenRaw_instance->count = 255;
|
||||||
chickenRaw_instance->auxiliary = 0;
|
chickenRaw_instance->auxiliary = 0;
|
||||||
chickenRaw_instance->id = 365;
|
chickenRaw_instance->id = 365;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Headers
|
#include <libreborn/patch.h>
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
#include <symbols/minecraft.h>
|
#include <symbols/minecraft.h>
|
||||||
|
|
||||||
#include <mods/misc/misc.h>
|
#include <mods/misc/misc.h>
|
||||||
|
|
||||||
// Custom Crafting Recipes
|
// Custom Crafting Recipes
|
||||||
|
@ -19,7 +19,7 @@ install(
|
|||||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/item"
|
DESTINATION "${MCPI_INSTALL_DIR}/data/images/item"
|
||||||
)
|
)
|
||||||
install(
|
install(
|
||||||
FILES "mojang/shadow.png" "mojang/vignette.png"
|
FILES "mojang/shadow.png" "mojang/vignette.png" "mojang/grasscolor.png"
|
||||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/misc"
|
DESTINATION "${MCPI_INSTALL_DIR}/data/images/misc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
BIN
images/mojang/grasscolor.png
Normal file
BIN
images/mojang/grasscolor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
images/start.png
BIN
images/start.png
Binary file not shown.
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 133 KiB |
@ -2,27 +2,41 @@ project(launcher)
|
|||||||
|
|
||||||
# Launcher
|
# Launcher
|
||||||
add_executable(launcher
|
add_executable(launcher
|
||||||
src/bootstrap.cpp
|
src/bootstrap/bootstrap.cpp
|
||||||
src/patchelf.cpp
|
src/bootstrap/mods.cpp
|
||||||
src/util.cpp
|
src/bootstrap/assets.cpp
|
||||||
src/crash-report.cpp
|
src/bootstrap/patchelf.cpp
|
||||||
src/sdk.cpp
|
src/bootstrap/debug.cpp
|
||||||
src/mods.cpp
|
src/util/util.cpp
|
||||||
|
src/util/sdk.cpp
|
||||||
|
src/util/env.cpp
|
||||||
|
src/logger/logger.cpp
|
||||||
|
src/logger/crash-report.cpp
|
||||||
src/options/parser.cpp
|
src/options/parser.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
src/ui/frame.cpp
|
||||||
|
src/ui/color.cpp
|
||||||
src/client/configuration.cpp
|
src/client/configuration.cpp
|
||||||
src/client/cache.cpp
|
src/client/cache.cpp
|
||||||
src/client/available-feature-flags # Show In IDE
|
src/client/ui.cpp
|
||||||
|
src/updater/updater.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(launcher
|
||||||
|
reborn-util
|
||||||
|
LIB_LIEF
|
||||||
|
imgui
|
||||||
|
trampoline-headers
|
||||||
|
pthread
|
||||||
)
|
)
|
||||||
embed_resource(launcher src/client/available-feature-flags)
|
|
||||||
target_link_libraries(launcher reborn-util LIB_LIEF trampoline-headers)
|
|
||||||
# RPath
|
# RPath
|
||||||
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
||||||
target_link_options(launcher PRIVATE "LINKER:--disable-new-dtags")
|
target_link_options(launcher PRIVATE "LINKER:--disable-new-dtags")
|
||||||
|
# Files
|
||||||
|
target_compile_definitions(launcher PRIVATE _FILE_OFFSET_BITS=64)
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
||||||
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
|
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_APP_NAME}")
|
||||||
|
|
||||||
# Install Desktop Entry
|
# Install Desktop Entry
|
||||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||||
@ -30,11 +44,9 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
|||||||
"Name=${MCPI_APP_TITLE}\n"
|
"Name=${MCPI_APP_TITLE}\n"
|
||||||
"Comment=Fun with Blocks\n"
|
"Comment=Fun with Blocks\n"
|
||||||
"Icon=${MCPI_APP_ID}\n"
|
"Icon=${MCPI_APP_ID}\n"
|
||||||
"Exec=${MCPI_VARIANT_NAME}\n"
|
"Exec=${MCPI_APP_NAME}\n"
|
||||||
"Type=Application\n"
|
"Type=Application\n"
|
||||||
"Categories=Game;\n"
|
"Categories=Game;\n"
|
||||||
)
|
|
||||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
|
||||||
"Terminal=false\n"
|
"Terminal=false\n"
|
||||||
"StartupNotify=false\n"
|
"StartupNotify=false\n"
|
||||||
"StartupWMClass=${MCPI_APP_ID}\n"
|
"StartupWMClass=${MCPI_APP_ID}\n"
|
||||||
@ -57,13 +69,13 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
|
|||||||
" <p>Minecraft: Pi Edition Modding Project.</p>\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"
|
" <p>NOTE: This is not verified by, affiliated with, or supported by Mojang or Microsoft.</p>\n"
|
||||||
" </description>\n"
|
" </description>\n"
|
||||||
" <url type=\"homepage\">https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn</url>\n"
|
" <url type=\"homepage\">${MCPI_REPO}</url>\n"
|
||||||
" <launchable type=\"desktop-id\">${MCPI_APP_ID}.desktop</launchable>\n"
|
" <launchable type=\"desktop-id\">${MCPI_APP_ID}.desktop</launchable>\n"
|
||||||
" <provides>\n"
|
" <provides>\n"
|
||||||
" <id>com.thebrokenrail.MCPIRebornClient.desktop</id>\n"
|
" <id>${MCPI_APP_ID}.desktop</id>\n"
|
||||||
" </provides>\n"
|
" </provides>\n"
|
||||||
" <project_license>LicenseRef-proprietary</project_license>\n"
|
" <project_license>LicenseRef-proprietary</project_license>\n"
|
||||||
" <developer_name>TheBrokenRail & Mojang AB</developer_name>\n"
|
" <developer_name>${MCPI_AUTHOR} & Mojang AB</developer_name>\n"
|
||||||
" <content_rating type=\"oars-1.0\">\n"
|
" <content_rating type=\"oars-1.0\">\n"
|
||||||
" <content_attribute id=\"violence-cartoon\">moderate</content_attribute>\n"
|
" <content_attribute id=\"violence-cartoon\">moderate</content_attribute>\n"
|
||||||
" <content_attribute id=\"violence-fantasy\">none</content_attribute>\n"
|
" <content_attribute id=\"violence-fantasy\">none</content_attribute>\n"
|
||||||
@ -91,7 +103,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
|
|||||||
" </releases>\n"
|
" </releases>\n"
|
||||||
" <screenshots>\n"
|
" <screenshots>\n"
|
||||||
" <screenshot type=\"default\">\n"
|
" <screenshot type=\"default\">\n"
|
||||||
" <image>https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn/raw/branch/master/images/start.png</image>\n"
|
" <image>${MCPI_REPO}/raw/branch/master/images/start.png</image>\n"
|
||||||
" </screenshot>\n"
|
" </screenshot>\n"
|
||||||
" </screenshots>\n"
|
" </screenshots>\n"
|
||||||
"</component>\n"
|
"</component>\n"
|
||||||
@ -104,6 +116,8 @@ install(
|
|||||||
|
|
||||||
# AppImage
|
# AppImage
|
||||||
if(MCPI_IS_APPIMAGE_BUILD)
|
if(MCPI_IS_APPIMAGE_BUILD)
|
||||||
install_symlink("bin/${MCPI_VARIANT_NAME}" "AppRun")
|
install_symlink("bin/${MCPI_APP_NAME}" "AppRun")
|
||||||
install_symlink("${MCPI_SHARE_DIR}/applications/${MCPI_APP_ID}.desktop" "${MCPI_APP_ID}.desktop")
|
install_symlink("${MCPI_SHARE_DIR}/applications/${MCPI_APP_ID}.desktop" "${MCPI_APP_ID}.desktop")
|
||||||
|
# Updater
|
||||||
|
target_sources(launcher PRIVATE src/updater/appimage.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,196 +0,0 @@
|
|||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
#include <trampoline/types.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
#include "bootstrap.h"
|
|
||||||
#include "patchelf.h"
|
|
||||||
|
|
||||||
#define MCPI_BINARY "minecraft-pi"
|
|
||||||
|
|
||||||
#define REQUIRED_PAGE_SIZE 4096
|
|
||||||
|
|
||||||
// Debug Information
|
|
||||||
static void run_debug_command(const char *const command[], const char *prefix) {
|
|
||||||
int status = 0;
|
|
||||||
char *output = run_command(command, &status, nullptr);
|
|
||||||
if (output != nullptr) {
|
|
||||||
// Remove Newline
|
|
||||||
size_t length = strlen(output);
|
|
||||||
if (length > 0 && output[length - 1] == '\n') {
|
|
||||||
output[length - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print
|
|
||||||
DEBUG("%s: %s", prefix, output);
|
|
||||||
free(output);
|
|
||||||
}
|
|
||||||
if (!is_exit_status_success(status)) {
|
|
||||||
ERR("Unable To Gather Debug Information");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void print_debug_information() {
|
|
||||||
// System Information
|
|
||||||
const char *const command[] = {"uname", "-a", nullptr};
|
|
||||||
run_debug_command(command, "System Information");
|
|
||||||
|
|
||||||
// Version
|
|
||||||
DEBUG("Reborn Version: v%s", MCPI_VERSION);
|
|
||||||
|
|
||||||
// Architecture
|
|
||||||
const char *arch =
|
|
||||||
#ifdef __x86_64__
|
|
||||||
"AMD64"
|
|
||||||
#elif defined(__aarch64__)
|
|
||||||
"ARM64"
|
|
||||||
#elif defined(__arm__)
|
|
||||||
"ARM32"
|
|
||||||
#else
|
|
||||||
"Unknown"
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
DEBUG("Reborn Target Architecture: %s", arch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bootstrap
|
|
||||||
void bootstrap(const options_t &options) {
|
|
||||||
// Debug Information
|
|
||||||
print_debug_information();
|
|
||||||
|
|
||||||
// Check Page Size (Not Needed When Using QEMU)
|
|
||||||
long page_size = sysconf(_SC_PAGESIZE);
|
|
||||||
if (page_size != REQUIRED_PAGE_SIZE) {
|
|
||||||
CONDITIONAL_ERR(!options.skip_pagesize_check, "Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Binary Directory
|
|
||||||
const std::string binary_directory = get_binary_directory();
|
|
||||||
DEBUG("Binary Directory: %s", binary_directory.c_str());
|
|
||||||
|
|
||||||
// Copy SDK
|
|
||||||
if (!reborn_is_server()) {
|
|
||||||
copy_sdk(binary_directory, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set MCPI_REBORN_ASSETS_PATH
|
|
||||||
{
|
|
||||||
std::string assets_path = safe_realpath("/proc/self/exe");
|
|
||||||
chop_last_component(assets_path);
|
|
||||||
assets_path += "/data";
|
|
||||||
set_and_print_env(_MCPI_REBORN_ASSETS_PATH_ENV, assets_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
|
||||||
std::string original_game_binary;
|
|
||||||
std::string game_binary;
|
|
||||||
{
|
|
||||||
// Log
|
|
||||||
DEBUG("Resolving File Paths...");
|
|
||||||
|
|
||||||
// Resolve Full Binary Path
|
|
||||||
const std::string full_path = binary_directory + ("/" MCPI_BINARY);
|
|
||||||
original_game_binary = safe_realpath(full_path);
|
|
||||||
const char *custom_binary = getenv(MCPI_BINARY_ENV);
|
|
||||||
if (custom_binary != nullptr) {
|
|
||||||
game_binary = safe_realpath(custom_binary);
|
|
||||||
} else {
|
|
||||||
game_binary = original_game_binary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure Preloaded Objects
|
|
||||||
std::vector<std::string> mcpi_ld_preload;
|
|
||||||
{
|
|
||||||
// Log
|
|
||||||
DEBUG("Locating Mods...");
|
|
||||||
|
|
||||||
// ARM Components
|
|
||||||
mcpi_ld_preload = bootstrap_mods(binary_directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure Library Search Path
|
|
||||||
std::vector<std::string> mcpi_ld_path;
|
|
||||||
{
|
|
||||||
// Log
|
|
||||||
DEBUG("Setting Linker Search Paths...");
|
|
||||||
|
|
||||||
// Library Search Path For ARM Components
|
|
||||||
{
|
|
||||||
// Add ARM Library Directory
|
|
||||||
mcpi_ld_path.push_back("lib/arm");
|
|
||||||
|
|
||||||
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
|
|
||||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
|
||||||
mcpi_ld_path.push_back("sysroot/lib");
|
|
||||||
mcpi_ld_path.push_back("sysroot/lib/arm-linux-gnueabihf");
|
|
||||||
mcpi_ld_path.push_back("sysroot/usr/lib");
|
|
||||||
mcpi_ld_path.push_back("sysroot/usr/lib/arm-linux-gnueabihf");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Fix Paths
|
|
||||||
for (std::string &path : mcpi_ld_path) {
|
|
||||||
path = binary_directory + '/' + path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix MCPI Dependencies
|
|
||||||
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
|
||||||
{
|
|
||||||
// Log
|
|
||||||
DEBUG("Patching ELF...");
|
|
||||||
|
|
||||||
// Find Linker
|
|
||||||
std::string linker = "/lib/ld-linux-armhf.so.3";
|
|
||||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
|
||||||
// Use ARM Sysroot Linker
|
|
||||||
linker = binary_directory + "/sysroot" + linker;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Patch
|
|
||||||
patch_mcpi_elf_dependencies(game_binary, new_mcpi_exe_path, linker, mcpi_ld_path, mcpi_ld_preload);
|
|
||||||
|
|
||||||
// Verify
|
|
||||||
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
|
|
||||||
IMPOSSIBLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set MCPI_VANILLA_ASSETS_PATH
|
|
||||||
{
|
|
||||||
std::string assets_path = original_game_binary;
|
|
||||||
chop_last_component(assets_path);
|
|
||||||
assets_path += "/data";
|
|
||||||
set_and_print_env(_MCPI_VANILLA_ASSETS_PATH_ENV, assets_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start Game
|
|
||||||
INFO("Starting Game...");
|
|
||||||
|
|
||||||
// Arguments
|
|
||||||
std::vector<std::string> args;
|
|
||||||
// Use Extra If Needed
|
|
||||||
#ifdef MCPI_BUILD_RUNTIME
|
|
||||||
args.push_back("runtime");
|
|
||||||
#endif
|
|
||||||
// Fix QEMU Bug
|
|
||||||
#ifdef MCPI_RUNTIME_IS_QEMU
|
|
||||||
args.push_back("-B");
|
|
||||||
args.push_back(std::to_string(QEMU_GUEST_BASE));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Specify MCPI Binary
|
|
||||||
args.push_back(new_mcpi_exe_path);
|
|
||||||
|
|
||||||
// Run
|
|
||||||
const char *new_argv[args.size() + 1];
|
|
||||||
for (std::vector<std::string>::size_type i = 0; i < args.size(); i++) {
|
|
||||||
new_argv[i] = args[i].c_str();
|
|
||||||
}
|
|
||||||
new_argv[args.size()] = nullptr;
|
|
||||||
safe_execvpe(new_argv, environ);
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "options/parser.h"
|
|
||||||
|
|
||||||
void bootstrap(const options_t &options);
|
|
||||||
void copy_sdk(const std::string &binary_directory, bool log_with_debug);
|
|
||||||
std::vector<std::string> bootstrap_mods(const std::string &binary_directory);
|
|
15
launcher/src/bootstrap/assets.cpp
Normal file
15
launcher/src/bootstrap/assets.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <libreborn/env/env.h>
|
||||||
|
|
||||||
|
#include "bootstrap.h"
|
||||||
|
#include "../util/util.h"
|
||||||
|
|
||||||
|
// Setup Asset Paths
|
||||||
|
static void setup_path(const char *env_name, std::string assets_path) {
|
||||||
|
chop_last_component(assets_path);
|
||||||
|
assets_path += "/data";
|
||||||
|
set_and_print_env(env_name, assets_path.c_str());
|
||||||
|
}
|
||||||
|
void bootstrap_assets(const std::string &original_game_binary) {
|
||||||
|
setup_path(_MCPI_REBORN_ASSETS_PATH_ENV, safe_realpath("/proc/self/exe"));
|
||||||
|
setup_path(_MCPI_VANILLA_ASSETS_PATH_ENV, original_game_binary);
|
||||||
|
}
|
78
launcher/src/bootstrap/bootstrap.cpp
Normal file
78
launcher/src/bootstrap/bootstrap.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/env/env.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
|
||||||
|
#include "../util/util.h"
|
||||||
|
#include "bootstrap.h"
|
||||||
|
|
||||||
|
#define MCPI_BINARY "minecraft-pi"
|
||||||
|
|
||||||
|
#define REQUIRED_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
void bootstrap(const options_t &options) {
|
||||||
|
// Debug Information
|
||||||
|
print_debug_information();
|
||||||
|
|
||||||
|
// Check Page Size
|
||||||
|
const long page_size = sysconf(_SC_PAGESIZE);
|
||||||
|
if (page_size != REQUIRED_PAGE_SIZE) {
|
||||||
|
CONDITIONAL_ERR(!options.skip_pagesize_check, "Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Binary Directory
|
||||||
|
const std::string binary_directory = get_binary_directory();
|
||||||
|
DEBUG("Binary Directory: %s", binary_directory.c_str());
|
||||||
|
|
||||||
|
// Copy SDK
|
||||||
|
if (!reborn_is_server()) {
|
||||||
|
copy_sdk(binary_directory, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve Binary Path
|
||||||
|
DEBUG("Resolving File Paths...");
|
||||||
|
std::string original_game_binary = binary_directory + ("/" MCPI_BINARY);
|
||||||
|
original_game_binary = safe_realpath(original_game_binary);
|
||||||
|
const char *custom_binary = getenv(MCPI_BINARY_ENV);
|
||||||
|
const std::string game_binary = custom_binary ? safe_realpath(custom_binary) : original_game_binary;
|
||||||
|
|
||||||
|
// Configure Preloaded Objects
|
||||||
|
DEBUG("Locating Mods...");
|
||||||
|
const std::vector<std::string> mcpi_ld_preload = bootstrap_mods(binary_directory);
|
||||||
|
|
||||||
|
// Configure Library Search Path
|
||||||
|
DEBUG("Setting Linker Search Paths...");
|
||||||
|
const std::vector<std::string> mcpi_ld_path = get_ld_path(binary_directory);
|
||||||
|
|
||||||
|
// Assets
|
||||||
|
DEBUG("Finding Assets...");
|
||||||
|
bootstrap_assets(original_game_binary);
|
||||||
|
|
||||||
|
// Patch Binary
|
||||||
|
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
||||||
|
DEBUG("Patching ELF...");
|
||||||
|
patch_mcpi_elf_dependencies(game_binary, new_mcpi_exe_path, get_new_linker(binary_directory), mcpi_ld_path, mcpi_ld_preload);
|
||||||
|
|
||||||
|
// Start Game
|
||||||
|
INFO("Starting Game...");
|
||||||
|
|
||||||
|
// Arguments
|
||||||
|
const std::vector<std::string> args {
|
||||||
|
#ifdef MCPI_BUILD_RUNTIME
|
||||||
|
"runtime",
|
||||||
|
#endif
|
||||||
|
new_mcpi_exe_path
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run
|
||||||
|
const char *new_argv[args.size() + 1];
|
||||||
|
for (std::vector<std::string>::size_type i = 0; i < args.size(); i++) {
|
||||||
|
new_argv[i] = args[i].c_str();
|
||||||
|
}
|
||||||
|
new_argv[args.size()] = nullptr;
|
||||||
|
safe_execvpe(new_argv, environ);
|
||||||
|
}
|
20
launcher/src/bootstrap/bootstrap.h
Normal file
20
launcher/src/bootstrap/bootstrap.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../options/parser.h"
|
||||||
|
|
||||||
|
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
|
||||||
|
|
||||||
|
void bootstrap(const options_t &options);
|
||||||
|
// Debugging
|
||||||
|
void print_debug_information();
|
||||||
|
// Mods
|
||||||
|
std::vector<std::string> bootstrap_mods(const std::string &binary_directory);
|
||||||
|
// Assets
|
||||||
|
void bootstrap_assets(const std::string &original_game_binary);
|
||||||
|
// ELF
|
||||||
|
std::string get_new_linker(const std::string &binary_directory);
|
||||||
|
std::vector<std::string> get_ld_path(const std::string &binary_directory);
|
||||||
|
void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_path, const std::string &interpreter, const std::vector<std::string> &rpath, const std::vector<std::string> &mods);
|
38
launcher/src/bootstrap/debug.cpp
Normal file
38
launcher/src/bootstrap/debug.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
|
#include "bootstrap.h"
|
||||||
|
|
||||||
|
// Debug Information
|
||||||
|
static void run_debug_command(const char *const command[], const char *prefix) {
|
||||||
|
int status = 0;
|
||||||
|
const std::vector<unsigned char> *output = run_command(command, &status);
|
||||||
|
if (!is_exit_status_success(status)) {
|
||||||
|
ERR("Unable To Gather Debug Information");
|
||||||
|
}
|
||||||
|
std::string output_str = (const char *) output->data();
|
||||||
|
delete output;
|
||||||
|
// Trim
|
||||||
|
const std::string::size_type length = output_str.length();
|
||||||
|
if (length > 0 && output_str[length - 1] == '\n') {
|
||||||
|
output_str.pop_back();
|
||||||
|
}
|
||||||
|
// Print
|
||||||
|
DEBUG("%s: %s", prefix, output_str.c_str());
|
||||||
|
}
|
||||||
|
void print_debug_information() {
|
||||||
|
// System Information
|
||||||
|
constexpr const char *const command[] = {"uname", "-a", nullptr};
|
||||||
|
run_debug_command(command, "System Information");
|
||||||
|
|
||||||
|
// Version
|
||||||
|
DEBUG("Reborn Version: v%s", MCPI_VERSION);
|
||||||
|
|
||||||
|
// Architecture
|
||||||
|
std::string arch = MCPI_ARCH;
|
||||||
|
for (char &c : arch) {
|
||||||
|
c = char(std::toupper(c));
|
||||||
|
}
|
||||||
|
DEBUG("Reborn Target Architecture: %s", arch.c_str());
|
||||||
|
}
|
@ -2,10 +2,13 @@
|
|||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
|
||||||
#include "bootstrap.h"
|
#include "bootstrap.h"
|
||||||
|
#include "../util/util.h"
|
||||||
|
|
||||||
// Get All Mods In Folder
|
// Get All Mods In Folder
|
||||||
static void load(std::vector<std::string> &ld_preload, const std::string &folder, int recursion_limit = 128);
|
static void load(std::vector<std::string> &ld_preload, const std::string &folder, int recursion_limit = 128);
|
||||||
@ -18,10 +21,8 @@ static void handle_file(std::vector<std::string> &ld_preload, const std::string
|
|||||||
load(ld_preload, std::string(file) + '/', recursion_limit - 1);
|
load(ld_preload, std::string(file) + '/', recursion_limit - 1);
|
||||||
} else if (S_ISLNK(file_stat.st_mode)) {
|
} else if (S_ISLNK(file_stat.st_mode)) {
|
||||||
// Resolve Symlink
|
// Resolve Symlink
|
||||||
char *resolved_file = realpath(file.c_str(), nullptr);
|
const std::string resolved_file = safe_realpath(file);
|
||||||
ALLOC_CHECK(resolved_file);
|
|
||||||
handle_file(ld_preload, resolved_file, recursion_limit);
|
handle_file(ld_preload, resolved_file, recursion_limit);
|
||||||
free(resolved_file);
|
|
||||||
} else if (S_ISREG(file_stat.st_mode)) {
|
} else if (S_ISREG(file_stat.st_mode)) {
|
||||||
// Check If File Is Accessible
|
// Check If File Is Accessible
|
||||||
const int result = access(file.c_str(), R_OK);
|
const int result = access(file.c_str(), R_OK);
|
||||||
@ -41,36 +42,15 @@ static void load(std::vector<std::string> &ld_preload, const std::string &folder
|
|||||||
if (recursion_limit <= 0) {
|
if (recursion_limit <= 0) {
|
||||||
ERR("Reached Recursion Limit While Loading Mods");
|
ERR("Reached Recursion Limit While Loading Mods");
|
||||||
}
|
}
|
||||||
// Open Folder
|
// Make Directory
|
||||||
ensure_directory(folder.c_str());
|
ensure_directory(folder.c_str());
|
||||||
DIR *dp = opendir(folder.c_str());
|
// Read
|
||||||
if (dp == nullptr) {
|
read_directory(folder, [&folder, &ld_preload, &recursion_limit](const dirent *entry) {
|
||||||
// Unable To Open Folder
|
// Get Full Name
|
||||||
ERR("Error Opening Directory: %s: %s", folder.c_str(), strerror(errno));
|
const std::string name = folder + entry->d_name;
|
||||||
}
|
// Handle
|
||||||
// Loop Through Folder
|
handle_file(ld_preload, name, recursion_limit);
|
||||||
while (true) {
|
});
|
||||||
errno = 0;
|
|
||||||
const dirent *entry = readdir(dp);
|
|
||||||
if (entry != nullptr) {
|
|
||||||
// Block Pseudo-Directories
|
|
||||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Get Full Name
|
|
||||||
std::string name = folder + entry->d_name;
|
|
||||||
// Handle
|
|
||||||
handle_file(ld_preload, name, recursion_limit);
|
|
||||||
} else if (errno != 0) {
|
|
||||||
// Error Reading Contents Of Folder
|
|
||||||
ERR("Error Reading Directory: %s: %s", folder.c_str(), strerror(errno));
|
|
||||||
} else {
|
|
||||||
// Done!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Close Folder
|
|
||||||
closedir(dp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bootstrap Mods
|
// Bootstrap Mods
|
||||||
@ -79,19 +59,13 @@ std::vector<std::string> bootstrap_mods(const std::string &binary_directory) {
|
|||||||
// Prepare
|
// Prepare
|
||||||
std::vector<std::string> preload;
|
std::vector<std::string> preload;
|
||||||
|
|
||||||
// ~/.minecraft-pi/mods
|
// Load
|
||||||
{
|
const std::vector folders = {
|
||||||
// Get Mods Folder
|
home_get(),
|
||||||
const std::string mods_folder = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data() + SUBDIRECTORY_FOR_MODS;
|
binary_directory
|
||||||
// Load Mods From ./mods
|
};
|
||||||
load(preload, mods_folder);
|
for (std::string mods_folder : folders) {
|
||||||
}
|
mods_folder += SUBDIRECTORY_FOR_MODS;
|
||||||
|
|
||||||
// Built-In Mods
|
|
||||||
{
|
|
||||||
// Get Mods Folder
|
|
||||||
const std::string mods_folder = binary_directory + SUBDIRECTORY_FOR_MODS;
|
|
||||||
// Load Mods From ./mods
|
|
||||||
load(preload, mods_folder);
|
load(preload, mods_folder);
|
||||||
}
|
}
|
||||||
|
|
@ -4,12 +4,10 @@
|
|||||||
|
|
||||||
#include <LIEF/ELF.hpp>
|
#include <LIEF/ELF.hpp>
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <libreborn/util/util.h>
|
||||||
#include <link.h>
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
#include "bootstrap.h"
|
||||||
|
|
||||||
#include "patchelf.h"
|
|
||||||
|
|
||||||
// Duplicate MCPI Executable Into /tmp
|
// Duplicate MCPI Executable Into /tmp
|
||||||
static void duplicate_mcpi_executable(char *new_path) {
|
static void duplicate_mcpi_executable(char *new_path) {
|
||||||
@ -43,12 +41,10 @@ void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_pat
|
|||||||
duplicate_mcpi_executable(new_path);
|
duplicate_mcpi_executable(new_path);
|
||||||
|
|
||||||
// Load Binary
|
// Load Binary
|
||||||
std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
|
const std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
|
||||||
|
|
||||||
// Set Interpreter
|
// Set Interpreter
|
||||||
if (!interpreter.empty()) {
|
binary->interpreter(interpreter);
|
||||||
binary->interpreter(interpreter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove Existing Needed Libraries
|
// Remove Existing Needed Libraries
|
||||||
std::vector<std::string> to_remove;
|
std::vector<std::string> to_remove;
|
||||||
@ -96,3 +92,34 @@ void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_pat
|
|||||||
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
|
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Linker
|
||||||
|
std::string get_new_linker(const std::string &binary_directory) {
|
||||||
|
std::string linker = "/lib/ld-linux-armhf.so.3";
|
||||||
|
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||||
|
linker = binary_directory + "/sysroot" + linker;
|
||||||
|
#else
|
||||||
|
(void) binary_directory;
|
||||||
|
#endif
|
||||||
|
return linker;
|
||||||
|
}
|
||||||
|
std::vector<std::string> get_ld_path(const std::string &binary_directory) {
|
||||||
|
std::vector<std::string> mcpi_ld_path = {
|
||||||
|
// ARM Sysroot
|
||||||
|
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||||
|
"sysroot/lib",
|
||||||
|
"sysroot/lib/arm-linux-gnueabihf",
|
||||||
|
"sysroot/usr/lib",
|
||||||
|
"sysroot/usr/lib/arm-linux-gnueabihf",
|
||||||
|
#endif
|
||||||
|
// Libraries
|
||||||
|
"lib/arm"
|
||||||
|
};
|
||||||
|
// Fix Paths
|
||||||
|
for (std::string &path : mcpi_ld_path) {
|
||||||
|
path.insert(0, 1, '/');
|
||||||
|
path.insert(0, binary_directory);
|
||||||
|
}
|
||||||
|
// Return
|
||||||
|
return mcpi_ld_path;
|
||||||
|
}
|
@ -1,114 +0,0 @@
|
|||||||
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
|
|
||||||
FALSE Display Slot Count In Creative Mode
|
|
||||||
FALSE Force Survival Mode Inventory UI
|
|
||||||
FALSE Force Survival Mode Inventory Behavior
|
|
||||||
FALSE Maximize Creative Mode Inventory Stack Size
|
|
||||||
TRUE Animated Water
|
|
||||||
TRUE Animated Lava
|
|
||||||
TRUE Animated Fire
|
|
||||||
TRUE Regenerate "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
|
|
||||||
FALSE Add Biome Colors To Grass
|
|
||||||
TRUE Generate Caves
|
|
||||||
FALSE Disable Block Tinting
|
|
||||||
TRUE Disable Hostile AI In Creative Mode
|
|
||||||
TRUE Load Custom Skins
|
|
||||||
TRUE 3D Chest Model
|
|
||||||
TRUE Replace Block Highlight With Outline
|
|
||||||
TRUE Add Cake
|
|
||||||
TRUE Use Java Beta 1.3 Light Ramp
|
|
||||||
TRUE Send Full Level When Hosting Game
|
|
||||||
FALSE Food Overlay
|
|
||||||
TRUE Add Splashes
|
|
||||||
TRUE Display Date In Select World Screen
|
|
||||||
TRUE Optimized Chunk Sorting
|
|
||||||
TRUE Fix Held Item Caching
|
|
||||||
TRUE Add Reborn Info To Options
|
|
||||||
FALSE Log FPS
|
|
||||||
TRUE Add Welcome Screen
|
|
||||||
TRUE F3 Debug Information
|
|
||||||
TRUE Multidraw Rendering
|
|
||||||
TRUE Add Missing Language Strings
|
|
||||||
TRUE Fix Pigmen Burning In The Sun
|
|
||||||
TRUE Fix Carried Grass's Bottom Texture
|
|
||||||
TRUE Hide Crosshair In Third-Person
|
|
||||||
TRUE Fix Camera Legs
|
|
||||||
TRUE Implement Crafting Remainders
|
|
||||||
TRUE Fix Door Duplication
|
|
||||||
TRUE Fix Cobweb Lighting
|
|
||||||
TRUE Fix Sneaking Syncing
|
|
||||||
TRUE Fix Fire Immunity
|
|
||||||
TRUE Fix Fire Syncing
|
|
||||||
TRUE Fix Sunlight Not Properly Setting Mobs On Fire
|
|
||||||
TRUE Stop Creative Players From Burning
|
|
||||||
TRUE Render Fire In Third-Person
|
|
||||||
TRUE Improved Water Rendering
|
|
||||||
TRUE Classic Item Count UI
|
|
||||||
TRUE Fix Screen Rendering When Hiding HUD
|
|
||||||
TRUE Sanitize Usernames
|
|
||||||
TRUE Patch RakNet Security Bug
|
|
||||||
TRUE Log RakNet Startup Errors
|
|
||||||
TRUE Prevent Unnecessary Server Pinging
|
|
||||||
TRUE Proper OpenGL Buffer Generation
|
|
||||||
TRUE Fix Furnace Screen Visual Bug
|
|
||||||
TRUE Fix Text Wrapping
|
|
||||||
TRUE Fullscreen Support
|
|
||||||
TRUE Always Save Chest Tile Entities
|
|
||||||
TRUE Fix Transferring Durability When Using Items
|
|
||||||
TRUE Fix Switching Perspective While Sneaking
|
|
||||||
TRUE Log Chat Messages
|
|
||||||
TRUE Log Game Status
|
|
||||||
TRUE Screenshot Support
|
|
||||||
TRUE Fix Camera Functionality
|
|
||||||
TRUE Allow High-Resolution Title
|
|
||||||
TRUE Improved Classic Title Positioning
|
|
||||||
TRUE Use Updated Title
|
|
||||||
TRUE Hide Block Outline When GUI Is Hidden
|
|
||||||
TRUE Fix Crash When Generating Certain Seeds
|
|
||||||
TRUE Click Buttons On Mouse Down
|
|
||||||
TRUE 3D Dropped Items
|
|
||||||
TRUE Render Entity Shadows
|
|
||||||
TRUE Render Vignette
|
|
||||||
TRUE Increase Render Chunk Size
|
|
||||||
TRUE Proper Entity Shading
|
|
@ -3,87 +3,105 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/util/io.h>
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
// Get Cache Path
|
// Get Cache Path
|
||||||
static std::string get_cache_path() {
|
static std::string get_cache_path() {
|
||||||
const char *home = getenv(_MCPI_HOME_ENV);
|
return home_get() + "/.launcher-cache";
|
||||||
if (home == nullptr) {
|
|
||||||
IMPOSSIBLE();
|
|
||||||
}
|
|
||||||
return std::string(home) + get_home_subdirectory_for_game_data() + "/.launcher-cache";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load
|
// Load
|
||||||
launcher_cache empty_cache = {
|
template <typename T>
|
||||||
.username = DEFAULT_USERNAME,
|
static T simple_read(std::ifstream &stream) {
|
||||||
.render_distance = DEFAULT_RENDER_DISTANCE,
|
T out;
|
||||||
.feature_flags = {}
|
stream.read((char *) &out, sizeof(T));
|
||||||
};
|
return out;
|
||||||
launcher_cache load_cache() {
|
}
|
||||||
|
template <>
|
||||||
|
std::string simple_read<std::string>(std::ifstream &stream) {
|
||||||
|
std::string out;
|
||||||
|
if (!std::getline(stream, out, '\0')) {
|
||||||
|
out = "";
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
static void read_cache(std::ifstream &stream, State &ret) {
|
||||||
|
// Cache Version
|
||||||
|
const unsigned char cache_version = simple_read<unsigned char>(stream);
|
||||||
|
if (stream.eof()) {
|
||||||
|
// Unable To Read Version
|
||||||
|
WARN("Unable To Read Launcher Cache Version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support Older Versions
|
||||||
|
bool load_new_fields = true;
|
||||||
|
if (cache_version == 0) {
|
||||||
|
// Pre-v3.0.0 Cache
|
||||||
|
load_new_fields = false;
|
||||||
|
} else if (cache_version != (unsigned char) CACHE_VERSION) {
|
||||||
|
// Invalid Version
|
||||||
|
WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", CACHE_VERSION, (int) cache_version);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Username And Render Distance
|
||||||
|
State state;
|
||||||
|
state.username = simple_read<std::string>(stream);
|
||||||
|
state.render_distance = simple_read<std::string>(stream);
|
||||||
|
if (load_new_fields) {
|
||||||
|
state.gui_scale = simple_read<float>(stream);
|
||||||
|
state.servers.load(simple_read<std::string>(stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Feature Flags
|
||||||
|
std::unordered_map<std::string, bool> flags;
|
||||||
|
while (!stream.eof()) {
|
||||||
|
std::string flag = simple_read<std::string>(stream);
|
||||||
|
flags[flag] = simple_read<bool>(stream);
|
||||||
|
stream.peek();
|
||||||
|
}
|
||||||
|
state.flags.from_cache(flags);
|
||||||
|
|
||||||
|
// Check For Error
|
||||||
|
if (!stream) {
|
||||||
|
WARN("Failure While Loading Launcher Cache");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
ret = state;
|
||||||
|
}
|
||||||
|
State load_cache() {
|
||||||
// Log
|
// Log
|
||||||
DEBUG("Loading Launcher Cache...");
|
DEBUG("Loading Launcher Cache...");
|
||||||
|
|
||||||
// Return Value
|
// Return Value
|
||||||
launcher_cache ret = empty_cache;
|
State ret;
|
||||||
|
|
||||||
// Open File
|
// Open File
|
||||||
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
|
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
// Fail
|
|
||||||
struct stat s;
|
|
||||||
// No Warning If File Doesn't Exist
|
// No Warning If File Doesn't Exist
|
||||||
if (stat(get_cache_path().c_str(), &s) == 0) {
|
if (errno != ENOENT) {
|
||||||
WARN("Unable To Open Launcher Cache For Loading");
|
WARN("Unable To Open Launcher Cache For Loading");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Lock File
|
// Lock File
|
||||||
int lock_fd = lock_file(get_cache_path().c_str());
|
int lock_fd = lock_file(get_cache_path().c_str());
|
||||||
|
|
||||||
// Check Version
|
// Load
|
||||||
unsigned char cache_version;
|
read_cache(stream, ret);
|
||||||
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
|
// Close
|
||||||
std::string flag;
|
stream.close();
|
||||||
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
|
||||||
unlock_file(get_cache_path().c_str(), lock_fd);
|
unlock_file(get_cache_path().c_str(), lock_fd);
|
||||||
@ -94,15 +112,33 @@ launcher_cache load_cache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
#define write_env_to_stream(stream, env) \
|
template <typename T>
|
||||||
{ \
|
static void simple_write(std::ostream &stream, const T &val) {
|
||||||
const char *env_value = getenv(env); \
|
stream.write((const char *) &val, sizeof(T));
|
||||||
if (env == NULL) { \
|
}
|
||||||
IMPOSSIBLE(); \
|
template <>
|
||||||
} \
|
void simple_write<std::string>(std::ostream &stream, const std::string &val) {
|
||||||
stream.write(env_value, strlen(env_value) + 1); \
|
stream.write(val.c_str(), int(val.size()) + 1);
|
||||||
|
}
|
||||||
|
void write_cache(std::ostream &stream, const State &state) {
|
||||||
|
// Save Cache Version
|
||||||
|
constexpr unsigned char cache_version = CACHE_VERSION;
|
||||||
|
simple_write(stream, cache_version);
|
||||||
|
|
||||||
|
// Save Username And Render Distance
|
||||||
|
simple_write(stream, state.username);
|
||||||
|
simple_write(stream, state.render_distance);
|
||||||
|
simple_write(stream, state.gui_scale);
|
||||||
|
simple_write(stream, state.servers.to_string());
|
||||||
|
|
||||||
|
// Save Feature Flags
|
||||||
|
const std::unordered_map<std::string, bool> flags_cache = state.flags.to_cache();
|
||||||
|
for (const std::pair<const std::string, bool> &it : flags_cache) {
|
||||||
|
simple_write(stream, it.first);
|
||||||
|
simple_write(stream, it.second);
|
||||||
}
|
}
|
||||||
void save_cache() {
|
}
|
||||||
|
void save_cache(const State &state) {
|
||||||
// Log
|
// Log
|
||||||
DEBUG("Saving Launcher Cache...");
|
DEBUG("Saving Launcher Cache...");
|
||||||
|
|
||||||
@ -113,44 +149,14 @@ void save_cache() {
|
|||||||
WARN("Unable To Open Launcher Cache For Saving");
|
WARN("Unable To Open Launcher Cache For Saving");
|
||||||
} else {
|
} else {
|
||||||
// Lock File
|
// Lock File
|
||||||
int lock_fd = lock_file(get_cache_path().c_str());
|
const int lock_fd = lock_file(get_cache_path().c_str());
|
||||||
|
|
||||||
// Save Cache Version
|
// Write
|
||||||
unsigned char cache_version = (unsigned char) CACHE_VERSION;
|
write_cache(stream, state);
|
||||||
stream.write((const char *) &cache_version, 1);
|
|
||||||
|
|
||||||
// Save Username And Render Distance
|
|
||||||
write_env_to_stream(stream, MCPI_USERNAME_ENV);
|
|
||||||
write_env_to_stream(stream, MCPI_RENDER_DISTANCE_ENV);
|
|
||||||
|
|
||||||
// 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, nullptr);
|
|
||||||
flags[stripped_flag] = false;
|
|
||||||
});
|
|
||||||
{
|
|
||||||
const char *enabled_flags = getenv(MCPI_FEATURE_FLAGS_ENV);
|
|
||||||
if (enabled_flags == nullptr) {
|
|
||||||
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
|
// Finish
|
||||||
stream.close();
|
stream.close();
|
||||||
if (!stream.good()) {
|
if (!stream) {
|
||||||
WARN("Failure While Saving Launcher Cache");
|
WARN("Failure While Saving Launcher Cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <ostream>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
// Cache Version
|
// Cache Version
|
||||||
#define CACHE_VERSION 0
|
#define CACHE_VERSION 1
|
||||||
|
|
||||||
// Load Cache
|
// Load Cache
|
||||||
typedef struct {
|
struct State;
|
||||||
std::string username;
|
State load_cache();
|
||||||
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
|
// Save Cache
|
||||||
void save_cache();
|
void write_cache(std::ostream &stream, const State &state);
|
||||||
|
void save_cache(const State &state);
|
||||||
|
|
||||||
// Wipe Cache
|
// Wipe Cache
|
||||||
void wipe_cache();
|
void wipe_cache();
|
||||||
|
@ -1,147 +1,49 @@
|
|||||||
#include <sstream>
|
#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 <libreborn/env/env.h>
|
||||||
|
|
||||||
#include "../util.h"
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
// Strip Feature Flag Default
|
// State
|
||||||
std::string strip_feature_flag_default(const std::string &flag, bool *default_ret) {
|
State::State(): flags("") {
|
||||||
// Valid Values
|
username = DEFAULT_USERNAME;
|
||||||
std::string true_str = "TRUE ";
|
render_distance = DEFAULT_RENDER_DISTANCE;
|
||||||
std::string false_str = "FALSE ";
|
gui_scale = AUTO_GUI_SCALE;
|
||||||
// Test
|
flags = Flags::get();
|
||||||
if (flag.rfind(true_str, 0) == 0) {
|
}
|
||||||
// Enabled By Default
|
template <typename T>
|
||||||
if (default_ret != nullptr) {
|
static void update_from_env(const char *env, T &value, const bool save) {
|
||||||
*default_ret = true;
|
if (save) {
|
||||||
}
|
set_and_print_env(env, obj_to_env_value(value).c_str());
|
||||||
return flag.substr(true_str.length(), std::string::npos);
|
|
||||||
} else if (flag.rfind(false_str, 0) == 0) {
|
|
||||||
// Disabled By Default
|
|
||||||
if (default_ret != nullptr) {
|
|
||||||
*default_ret = false;
|
|
||||||
}
|
|
||||||
return flag.substr(false_str.length(), std::string::npos);
|
|
||||||
} else {
|
} else {
|
||||||
// Invalid
|
const char *env_value = getenv(env);
|
||||||
ERR("Invalid Feature Flag Default");
|
if (env_value != nullptr) {
|
||||||
}
|
env_value_to_obj(value, env_value);
|
||||||
}
|
|
||||||
|
|
||||||
// Load Available Feature Flags
|
|
||||||
extern unsigned char available_feature_flags[];
|
|
||||||
extern size_t available_feature_flags_len;
|
|
||||||
void load_available_feature_flags(const std::function<void(std::string)> &callback) {
|
|
||||||
// Load Data
|
|
||||||
const 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.empty()) {
|
|
||||||
// Verify Line
|
|
||||||
if (line.find('|') == std::string::npos) {
|
|
||||||
lines.push_back(line);
|
|
||||||
} else {
|
|
||||||
// Invalid Line
|
|
||||||
ERR("Feature Flag Contains Invalid '|'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sort
|
|
||||||
std::sort(lines.begin(), lines.end(), [](const std::string &a, const std::string &b) {
|
|
||||||
// Strip Defaults
|
|
||||||
const std::string stripped_a = strip_feature_flag_default(a, nullptr);
|
|
||||||
const std::string stripped_b = strip_feature_flag_default(b, nullptr);
|
|
||||||
// Sort
|
|
||||||
return stripped_a < stripped_b;
|
|
||||||
});
|
|
||||||
// Run Callbacks
|
|
||||||
for (const std::string &line : lines) {
|
|
||||||
callback(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run Command And Set Environmental Variable
|
|
||||||
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) == nullptr) {
|
|
||||||
// Check $DISPLAY
|
|
||||||
reborn_check_display();
|
|
||||||
// Run
|
|
||||||
int return_code;
|
|
||||||
char *output = run_command(command, &return_code, nullptr);
|
|
||||||
if (output != nullptr) {
|
|
||||||
// Trim
|
|
||||||
const size_t length = strlen(output);
|
|
||||||
if (output[length - 1] == '\n') {
|
|
||||||
output[length - 1] = '\0';
|
|
||||||
}
|
|
||||||
// Set
|
|
||||||
set_and_print_env(env_name, output);
|
|
||||||
// Free
|
|
||||||
free(output);
|
|
||||||
}
|
|
||||||
// Check Return Code
|
|
||||||
if (!is_exit_status_success(return_code)) {
|
|
||||||
// Launch Interrupted
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void State::update(const bool save) {
|
||||||
// Use Zenity To Set Environmental Variable
|
update_from_env(MCPI_FEATURE_FLAGS_ENV, flags, save);
|
||||||
#define DIALOG_TITLE "Launcher"
|
update_from_env(MCPI_USERNAME_ENV, username, save);
|
||||||
static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
|
update_from_env(MCPI_RENDER_DISTANCE_ENV, render_distance, save);
|
||||||
// Create Full Command
|
update_from_env(MCPI_GUI_SCALE_ENV, gui_scale, save);
|
||||||
std::vector<std::string> full_command;
|
update_from_env(MCPI_SERVER_LIST_ENV, servers, save);
|
||||||
full_command.push_back("zenity");
|
|
||||||
full_command.push_back("--title");
|
|
||||||
full_command.push_back(DIALOG_TITLE);
|
|
||||||
full_command.push_back("--name");
|
|
||||||
full_command.push_back(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];
|
|
||||||
for (std::vector<std::string>::size_type i = 0; i < full_command.size(); i++) {
|
|
||||||
full_command_array[i] = full_command[i].c_str();
|
|
||||||
}
|
|
||||||
full_command_array[full_command.size()] = nullptr;
|
|
||||||
// Run
|
|
||||||
run_command_and_set_env(env_name, full_command_array);
|
|
||||||
}
|
}
|
||||||
|
bool State::operator==(const State &other) const {
|
||||||
// Set Variable If Not Already Set
|
std::ostringstream one;
|
||||||
static void set_env_if_unset(const char *env_name, const std::function<std::string()> &callback) {
|
write_cache(one, *this);
|
||||||
if (getenv(env_name) == nullptr) {
|
std::ostringstream two;
|
||||||
char *value = strdup(callback().c_str());
|
write_cache(two, other);
|
||||||
ALLOC_CHECK(value);
|
return one.str() == two.str();
|
||||||
set_and_print_env(env_name, value);
|
|
||||||
free(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Non-Launch Commands
|
// Handle Non-Launch Commands
|
||||||
void handle_non_launch_client_only_commands(const options_t &options) {
|
void handle_non_launch_client_only_commands(const options_t &options) {
|
||||||
// Print Available Feature Flags
|
// Print Available Feature Flags
|
||||||
if (options.print_available_feature_flags) {
|
if (options.print_available_feature_flags) {
|
||||||
load_available_feature_flags([](const std::string &line) {
|
const Flags flags = Flags::get();
|
||||||
printf("%s\n", line.c_str());
|
flags.print();
|
||||||
fflush(stdout);
|
|
||||||
});
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
// Wipe Cache If Needed
|
// Wipe Cache If Needed
|
||||||
@ -152,115 +54,33 @@ void handle_non_launch_client_only_commands(const options_t &options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure Client Options
|
// Configure Client Options
|
||||||
#define LIST_DIALOG_SIZE "400"
|
|
||||||
void configure_client(const options_t &options) {
|
void configure_client(const options_t &options) {
|
||||||
// Load Cache
|
// Load Cache
|
||||||
launcher_cache cache = options.no_cache ? empty_cache : load_cache();
|
State state;
|
||||||
|
bool save_settings = !options.no_cache;
|
||||||
// --default
|
if (save_settings) {
|
||||||
if (options.use_default) {
|
state = load_cache();
|
||||||
// Use Default Feature Flags
|
|
||||||
set_env_if_unset(MCPI_FEATURE_FLAGS_ENV, [&cache]() {
|
|
||||||
std::string feature_flags = "";
|
|
||||||
load_available_feature_flags([&feature_flags, &cache](const 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.empty() && feature_flags[feature_flags.length() - 1] == '|') {
|
|
||||||
feature_flags.pop_back();
|
|
||||||
}
|
|
||||||
return feature_flags;
|
|
||||||
});
|
|
||||||
set_env_if_unset(MCPI_RENDER_DISTANCE_ENV, [&cache]() {
|
|
||||||
return cache.render_distance;
|
|
||||||
});
|
|
||||||
set_env_if_unset(MCPI_USERNAME_ENV, [&cache]() {
|
|
||||||
return cache.username;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup MCPI_FEATURE_FLAGS
|
// Read From Environment
|
||||||
{
|
state.update(false);
|
||||||
std::vector<std::string> command;
|
|
||||||
command.push_back("--list");
|
// Show UI
|
||||||
command.push_back("--checklist");
|
if (!options.use_default) {
|
||||||
command.push_back("--width");
|
ConfigurationUI *ui = new ConfigurationUI(state, save_settings);
|
||||||
command.push_back(LIST_DIALOG_SIZE);
|
const int ret = ui->run();
|
||||||
command.push_back("--height");
|
delete ui;
|
||||||
command.push_back(LIST_DIALOG_SIZE);
|
if (ret <= 0) {
|
||||||
command.push_back("--column");
|
// Cancel Launch
|
||||||
command.push_back("Enabled");
|
exit(EXIT_SUCCESS);
|
||||||
command.push_back("--column");
|
|
||||||
command.push_back("Feature");
|
|
||||||
load_available_feature_flags([&command, &cache](const 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");
|
|
||||||
} else {
|
|
||||||
// Disabled By Default
|
|
||||||
command.push_back("FALSE");
|
|
||||||
}
|
|
||||||
// Specify Name
|
|
||||||
command.push_back(stripped_flag);
|
|
||||||
});
|
|
||||||
// Run
|
|
||||||
run_zenity_and_set_env(MCPI_FEATURE_FLAGS_ENV, command);
|
|
||||||
}
|
|
||||||
// Setup MCPI_RENDER_DISTANCE
|
|
||||||
{
|
|
||||||
std::vector<std::string> command;
|
|
||||||
command.push_back("--list");
|
|
||||||
command.push_back("--radiolist");
|
|
||||||
command.push_back("--width");
|
|
||||||
command.push_back(LIST_DIALOG_SIZE);
|
|
||||||
command.push_back("--height");
|
|
||||||
command.push_back(LIST_DIALOG_SIZE);
|
|
||||||
command.push_back("--text");
|
|
||||||
command.push_back("Select Minecraft Render Distance:");
|
|
||||||
command.push_back("--column");
|
|
||||||
command.push_back("Selected");
|
|
||||||
command.push_back("--column");
|
|
||||||
command.push_back("Name");
|
|
||||||
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
|
|
||||||
for (std::string &render_distance : render_distances) {
|
|
||||||
command.push_back(render_distance == cache.render_distance ? "TRUE" : "FALSE");
|
|
||||||
command.push_back(render_distance);
|
|
||||||
}
|
}
|
||||||
// Run
|
|
||||||
run_zenity_and_set_env(MCPI_RENDER_DISTANCE_ENV, command);
|
|
||||||
}
|
|
||||||
// Setup MCPI_USERNAME
|
|
||||||
{
|
|
||||||
std::vector<std::string> command;
|
|
||||||
command.push_back("--entry");
|
|
||||||
command.push_back("--text");
|
|
||||||
command.push_back("Enter Minecraft Username:");
|
|
||||||
command.push_back("--entry-text");
|
|
||||||
command.push_back(cache.username);
|
|
||||||
// Run
|
|
||||||
run_zenity_and_set_env(MCPI_USERNAME_ENV, command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save Cache
|
// Save Cache
|
||||||
if (!options.no_cache) {
|
if (save_settings) {
|
||||||
save_cache();
|
save_cache(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update Environment
|
||||||
|
state.update(true);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,57 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "../options/parser.h"
|
#include "../options/parser.h"
|
||||||
|
#include "../ui/frame.h"
|
||||||
|
|
||||||
// Defaults
|
#include <libreborn/env/flags.h>
|
||||||
|
#include <libreborn/env/servers.h>
|
||||||
|
|
||||||
|
// Default Configuration
|
||||||
#define DEFAULT_USERNAME "StevePi"
|
#define DEFAULT_USERNAME "StevePi"
|
||||||
#define DEFAULT_RENDER_DISTANCE "Short"
|
#define DEFAULT_RENDER_DISTANCE "Short"
|
||||||
|
#define AUTO_GUI_SCALE 0
|
||||||
|
|
||||||
// Feature Flags
|
// State
|
||||||
std::string strip_feature_flag_default(const std::string& flag, bool *default_ret);
|
struct State {
|
||||||
void load_available_feature_flags(const std::function<void(std::string)> &callback);
|
State();
|
||||||
|
// Methods
|
||||||
|
void update(bool save);
|
||||||
|
bool operator==(const State &other) const;
|
||||||
|
// Properties
|
||||||
|
std::string username;
|
||||||
|
std::string render_distance;
|
||||||
|
ServerList servers;
|
||||||
|
float gui_scale;
|
||||||
|
Flags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
// UI
|
||||||
|
struct ConfigurationUI final : Frame {
|
||||||
|
explicit ConfigurationUI(State &state_, bool &save_settings_);
|
||||||
|
int render() override;
|
||||||
|
private:
|
||||||
|
// Bottom Row
|
||||||
|
[[nodiscard]] int get_render_distance_index() const;
|
||||||
|
[[nodiscard]] int draw_bottom() const;
|
||||||
|
// General
|
||||||
|
void draw_main() const;
|
||||||
|
// Advanced
|
||||||
|
void draw_advanced() const;
|
||||||
|
static void draw_category(FlagNode &category);
|
||||||
|
// Server List
|
||||||
|
void draw_servers() const;
|
||||||
|
void draw_server_list() const;
|
||||||
|
// About
|
||||||
|
static void draw_centered_text(const std::string &str);
|
||||||
|
static void draw_links(const std::vector<std::pair<std::string, std::string>> &links);
|
||||||
|
static void draw_about();
|
||||||
|
// State
|
||||||
|
const State original_state;
|
||||||
|
State &state;
|
||||||
|
bool &save_settings;
|
||||||
|
};
|
||||||
|
|
||||||
// Handle Non-Launch Commands
|
// Handle Non-Launch Commands
|
||||||
void handle_non_launch_client_only_commands(const options_t &options);
|
void handle_non_launch_client_only_commands(const options_t &options);
|
||||||
|
302
launcher/src/client/ui.cpp
Normal file
302
launcher/src/client/ui.cpp
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <limits>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "../updater/updater.h"
|
||||||
|
|
||||||
|
#include <imgui_stdlib.h>
|
||||||
|
|
||||||
|
// Render Distances
|
||||||
|
static constexpr std::array render_distances = {
|
||||||
|
"Far",
|
||||||
|
"Normal",
|
||||||
|
"Short",
|
||||||
|
"Tiny"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Construct
|
||||||
|
static constexpr int size = 400;
|
||||||
|
ConfigurationUI::ConfigurationUI(State &state_, bool &save_settings_):
|
||||||
|
Frame("Launcher", size, size),
|
||||||
|
original_state(state_),
|
||||||
|
state(state_),
|
||||||
|
save_settings(save_settings_) {}
|
||||||
|
|
||||||
|
// Render
|
||||||
|
int ConfigurationUI::render() {
|
||||||
|
if (ImGui::BeginChild("Main", ImVec2(0, -ImGui::GetFrameHeightWithSpacing() /* Leave Room For Bottom Row */), ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||||
|
// Tabs
|
||||||
|
if (ImGui::BeginTabBar("TabBar")) {
|
||||||
|
// Main Tab
|
||||||
|
if (ImGui::BeginTabItem("General")) {
|
||||||
|
draw_main();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
// Advanced Tab
|
||||||
|
if (ImGui::BeginTabItem("Advanced")) {
|
||||||
|
draw_advanced();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
// Servers Tab
|
||||||
|
if (ImGui::BeginTabItem("Servers")) {
|
||||||
|
draw_servers();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
// About Tab
|
||||||
|
if (ImGui::BeginTabItem("About")) {
|
||||||
|
draw_about();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
// Bottom Row
|
||||||
|
return draw_bottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom Row
|
||||||
|
int ConfigurationUI::draw_bottom() const {
|
||||||
|
// Reset Settings
|
||||||
|
const State default_state;
|
||||||
|
std::vector<std::tuple<std::string, std::string, const State *>> reset_options = {
|
||||||
|
{"Revert", "Last Saved", &original_state},
|
||||||
|
{"Reset", "Default", &default_state},
|
||||||
|
};
|
||||||
|
for (const std::tuple<std::string, std::string, const State *> &option : reset_options) {
|
||||||
|
const State &new_state = *std::get<2>(option);
|
||||||
|
ImGui::BeginDisabled(state == new_state);
|
||||||
|
if (ImGui::Button(std::get<0>(option).c_str())) {
|
||||||
|
state = new_state;
|
||||||
|
}
|
||||||
|
ImGui::SetItemTooltip("Use %s Settings", std::get<1>(option).c_str());
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
// Right-Align Buttons
|
||||||
|
int ret = 0;
|
||||||
|
draw_right_aligned_buttons({quit_text, "Launch"}, [&ret](const int id, const bool was_clicked) {
|
||||||
|
if (id == 0) {
|
||||||
|
// Quit
|
||||||
|
if (was_clicked) {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
ImGui::SetItemTooltip("Changes Will Not Be Saved!");
|
||||||
|
} else if (was_clicked) {
|
||||||
|
// Launch
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Return
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main Tab
|
||||||
|
int ConfigurationUI::get_render_distance_index() const {
|
||||||
|
int render_distance_index = 0;
|
||||||
|
for (std::vector<std::string>::size_type i = 0; i < render_distances.size(); i++) {
|
||||||
|
if (std::string(render_distances[i]) == state.render_distance) {
|
||||||
|
render_distance_index = int(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return render_distance_index;
|
||||||
|
}
|
||||||
|
void ConfigurationUI::draw_main() const {
|
||||||
|
const ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
const char *labels[] = {"Username", "Render Distance", "UI Scale"};
|
||||||
|
// Calculate Label Size
|
||||||
|
float label_size = 0;
|
||||||
|
for (const char *label : labels) {
|
||||||
|
label_size = std::max(label_size, ImGui::CalcTextSize(label).x + style.ItemInnerSpacing.x);
|
||||||
|
}
|
||||||
|
ImGui::PushItemWidth(-label_size);
|
||||||
|
// Username
|
||||||
|
ImGui::InputText(labels[0], &state.username);
|
||||||
|
// Render Distance
|
||||||
|
int render_distance_index = get_render_distance_index();
|
||||||
|
if (ImGui::Combo(labels[1], &render_distance_index, render_distances.data(), int(render_distances.size()))) {
|
||||||
|
state.render_distance = render_distances[render_distance_index];
|
||||||
|
}
|
||||||
|
// UI Scale
|
||||||
|
int gui_scale_int = int(state.gui_scale); // Fractional GUI Scales Are Messy
|
||||||
|
std::string scale_format = "%ix";
|
||||||
|
if (gui_scale_int <= AUTO_GUI_SCALE) {
|
||||||
|
scale_format = "Automatic";
|
||||||
|
}
|
||||||
|
if (ImGui::SliderInt(labels[2], &gui_scale_int, 0, 8, scale_format.c_str())) {
|
||||||
|
state.gui_scale = float(gui_scale_int);
|
||||||
|
if (state.gui_scale < AUTO_GUI_SCALE) {
|
||||||
|
state.gui_scale = AUTO_GUI_SCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
// Launcher Cache
|
||||||
|
ImGui::Checkbox("Save Settings On Launch", &save_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advanced Tab
|
||||||
|
static std::string get_label_for_flag_node(const FlagNode &node) {
|
||||||
|
return node.name + "##FlagNode" + std::to_string(node.id);
|
||||||
|
}
|
||||||
|
void ConfigurationUI::draw_advanced() const {
|
||||||
|
if (ImGui::BeginChild("Features", ImVec2(0, 0), ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||||
|
// Categories
|
||||||
|
for (FlagNode &category : state.flags.root.children) {
|
||||||
|
const std::string label = get_label_for_flag_node(category);
|
||||||
|
if (ImGui::CollapsingHeader(label.c_str())) {
|
||||||
|
draw_category(category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
void ConfigurationUI::draw_category(FlagNode &category) {
|
||||||
|
for (FlagNode &child : category.children) {
|
||||||
|
const std::string label = get_label_for_flag_node(child);
|
||||||
|
if (!child.children.empty()) {
|
||||||
|
// Sub-Category
|
||||||
|
if (ImGui::TreeNode(label.c_str())) {
|
||||||
|
draw_category(child);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Flag
|
||||||
|
ImGui::Checkbox(label.c_str(), &child.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Servers
|
||||||
|
void ConfigurationUI::draw_servers() const {
|
||||||
|
// Add
|
||||||
|
bool scroll_to_bottom = false;
|
||||||
|
if (ImGui::Button("Add")) {
|
||||||
|
state.servers.entries.emplace_back("", DEFAULT_MULTIPLAYER_PORT);
|
||||||
|
scroll_to_bottom = true;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
// Clear
|
||||||
|
bool should_clear = false;
|
||||||
|
ImGui::BeginDisabled(state.servers.entries.empty());
|
||||||
|
draw_right_aligned_buttons({"Clear"}, [&should_clear](__attribute__((unused)) const int id, const bool was_clicked) {
|
||||||
|
should_clear = was_clicked;
|
||||||
|
});
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
if (should_clear) {
|
||||||
|
state.servers.entries.clear();
|
||||||
|
}
|
||||||
|
// List
|
||||||
|
if (ImGui::BeginChild("ServerList", ImVec2(0, 0), ImGuiChildFlags_Borders)) {
|
||||||
|
draw_server_list();
|
||||||
|
if (scroll_to_bottom) {
|
||||||
|
ImGui::SetScrollHereY(1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
static int server_list_address_filter(ImGuiInputTextCallbackData *data) {
|
||||||
|
// Lowercase
|
||||||
|
constexpr std::pair lower_alpha = {'a', 'z'};
|
||||||
|
constexpr std::pair upper_alpha = {'A', 'Z'};
|
||||||
|
ImWchar &x = data->EventChar;
|
||||||
|
if (x >= upper_alpha.first && x <= upper_alpha.second) {
|
||||||
|
x += lower_alpha.first - upper_alpha.first;
|
||||||
|
}
|
||||||
|
// Check Characters
|
||||||
|
return (x >= lower_alpha.first && x <= lower_alpha.second) || x == '.' ? 0 : 1;
|
||||||
|
}
|
||||||
|
static int server_list_port_filter(ImGuiInputTextCallbackData *data) {
|
||||||
|
// Only Allow Integers
|
||||||
|
const ImWchar &x = data->EventChar;
|
||||||
|
return x >= '0' && x <= '9' ? 0 : 1;
|
||||||
|
}
|
||||||
|
void ConfigurationUI::draw_server_list() const {
|
||||||
|
for (std::vector<ServerList::Entry>::size_type i = 0; i < state.servers.entries.size(); ++i) {
|
||||||
|
ServerList::Entry &entry = state.servers.entries[i];
|
||||||
|
|
||||||
|
// Calculate Item Widths
|
||||||
|
const ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
const std::string port_width_text = std::to_string(int(std::numeric_limits<ServerList::port_t>::max()) * 2); // Should Comfortably Fit All Port Numbers
|
||||||
|
const std::string delete_text = "Delete";
|
||||||
|
const float port_width = get_frame_width(port_width_text.c_str());
|
||||||
|
const float width_needed = (style.ItemSpacing.x * 2.0f) + port_width + get_frame_width(delete_text.c_str());
|
||||||
|
|
||||||
|
// Labels
|
||||||
|
const std::string base_label = "##ServerEntry" + std::to_string(i);
|
||||||
|
|
||||||
|
// Hints
|
||||||
|
const char *address_hint = "Address";
|
||||||
|
const char *port_hint = "Port";
|
||||||
|
|
||||||
|
// Address
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - width_needed);
|
||||||
|
ImGui::InputTextWithHint((base_label + address_hint).c_str(), address_hint, &entry.first, ImGuiInputTextFlags_CallbackCharFilter, server_list_address_filter);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
// Port
|
||||||
|
ServerList::port_t &port = entry.second;
|
||||||
|
std::string port_str = port > 0 ? std::to_string(port) : "";
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushItemWidth(port_width);
|
||||||
|
if (ImGui::InputTextWithHint((base_label + port_hint).c_str(), port_hint, &port_str, ImGuiInputTextFlags_CallbackCharFilter | ImGuiInputTextFlags_NoHorizontalScroll, server_list_port_filter)) {
|
||||||
|
port = ServerList::parse_port(port_str);
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button((delete_text + base_label).c_str())) {
|
||||||
|
state.servers.entries.erase(state.servers.entries.begin() + int(i));
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// About
|
||||||
|
void ConfigurationUI::draw_centered_text(const std::string &str) {
|
||||||
|
const float width = ImGui::GetWindowSize().x;
|
||||||
|
const float text_width = ImGui::CalcTextSize(str.c_str()).x;
|
||||||
|
ImGui::SetCursorPosX((width - text_width) / 2.0f);
|
||||||
|
ImGui::Text("%s", str.c_str());
|
||||||
|
}
|
||||||
|
void ConfigurationUI::draw_links(const std::vector<std::pair<std::string, std::string>> &links) {
|
||||||
|
std::vector<const char *> buttons;
|
||||||
|
for (const std::string &text : links | std::views::keys) {
|
||||||
|
buttons.push_back(text.c_str());
|
||||||
|
}
|
||||||
|
draw_right_aligned_buttons(buttons, [&links](const int id, const bool was_clicked) {
|
||||||
|
if (was_clicked) {
|
||||||
|
open_url(links[id].second);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
void ConfigurationUI::draw_about() {
|
||||||
|
// Text
|
||||||
|
draw_centered_text("By " MCPI_AUTHOR);
|
||||||
|
draw_centered_text("Version " MCPI_VERSION);
|
||||||
|
// Links
|
||||||
|
ImGui::Separator();
|
||||||
|
draw_links({
|
||||||
|
{"Home", MCPI_REPO},
|
||||||
|
{"Changelog", MCPI_DOCS_CHANGELOG},
|
||||||
|
{"Credits", MCPI_DOCS "CREDITS.md"}
|
||||||
|
});
|
||||||
|
// Updater
|
||||||
|
Updater *updater = Updater::instance;
|
||||||
|
if (updater) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::BeginDisabled(!updater->can_start());
|
||||||
|
draw_right_aligned_buttons({updater->get_status().c_str()}, [&updater](__attribute__((unused)) int id, const bool was_clicked) {
|
||||||
|
if (was_clicked) {
|
||||||
|
updater->start();
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
}
|
@ -1,259 +0,0 @@
|
|||||||
#include <unistd.h>
|
|
||||||
#include <cstring>
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <csignal>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <ctime>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
|
|
||||||
#include "crash-report.h"
|
|
||||||
|
|
||||||
// Show Crash Report Dialog
|
|
||||||
#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_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"" MCPI_DISCORD_INVITE "\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit Handler
|
|
||||||
static pid_t child_pid = -1;
|
|
||||||
static void exit_handler(__attribute__((unused)) int signal) {
|
|
||||||
// Murder
|
|
||||||
kill(child_pid, SIGTERM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log File
|
|
||||||
static std::string log_filename;
|
|
||||||
static int log_fd;
|
|
||||||
static void setup_log_file() {
|
|
||||||
// Get Log Directory
|
|
||||||
const std::string home = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data();
|
|
||||||
ensure_directory(home.c_str());
|
|
||||||
const std::string logs = home + "/logs";
|
|
||||||
ensure_directory(logs.c_str());
|
|
||||||
|
|
||||||
// Get Timestamp
|
|
||||||
time_t raw_time;
|
|
||||||
time(&raw_time);
|
|
||||||
const tm *time_info = localtime(&raw_time);
|
|
||||||
char time[512];
|
|
||||||
strftime(time, 512, "%Y-%m-%d", time_info);
|
|
||||||
|
|
||||||
// Get Log Filename
|
|
||||||
std::string file;
|
|
||||||
int num = 1;
|
|
||||||
do {
|
|
||||||
file = std::string(time) + '-' + std::to_string(num) + ".log";
|
|
||||||
log_filename = logs + '/' + file;
|
|
||||||
num++;
|
|
||||||
} while (access(log_filename.c_str(), F_OK) != -1);
|
|
||||||
|
|
||||||
// Create latest.log Symlink
|
|
||||||
const std::string latest_log = logs + "/latest.log";
|
|
||||||
unlink(latest_log.c_str());
|
|
||||||
if (symlink(file.c_str(), latest_log.c_str()) != 0) {
|
|
||||||
WARN("Unable To Create Latest Log Symlink: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create File
|
|
||||||
log_fd = open(log_filename.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
||||||
if (log_fd == -1) {
|
|
||||||
ERR("Unable To Create Log File: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
reborn_set_log(log_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup
|
|
||||||
#define PIPE_READ 0
|
|
||||||
#define PIPE_WRITE 1
|
|
||||||
#define BUFFER_SIZE 1024
|
|
||||||
static void safe_write(int fd, const void *buf, size_t size) {
|
|
||||||
const ssize_t bytes_written = write(fd, buf, size);
|
|
||||||
if (bytes_written < 0) {
|
|
||||||
ERR("Unable To Write Data: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void setup_crash_report() {
|
|
||||||
// Setup Logging
|
|
||||||
setup_log_file();
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Kill Child If Parent Exits First
|
|
||||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
|
||||||
|
|
||||||
// Continue Execution
|
|
||||||
} else {
|
|
||||||
// Install Signal Handlers
|
|
||||||
child_pid = ret;
|
|
||||||
struct sigaction act_sigint = {};
|
|
||||||
act_sigint.sa_flags = SA_RESTART;
|
|
||||||
act_sigint.sa_handler = &exit_handler;
|
|
||||||
sigaction(SIGINT, &act_sigint, nullptr);
|
|
||||||
struct sigaction act_sigterm = {};
|
|
||||||
act_sigterm.sa_flags = SA_RESTART;
|
|
||||||
act_sigterm.sa_handler = &exit_handler;
|
|
||||||
sigaction(SIGTERM, &act_sigterm, nullptr);
|
|
||||||
|
|
||||||
// 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 Polling
|
|
||||||
const int number_fds = 3;
|
|
||||||
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 (pollfd &poll_fd : poll_fds) {
|
|
||||||
poll_fd.events = POLLIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Poll Data
|
|
||||||
int status;
|
|
||||||
while (waitpid(ret, &status, WNOHANG) != ret) {
|
|
||||||
const 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 (pollfd &poll_fd : poll_fds) {
|
|
||||||
if (poll_fd.revents != 0) {
|
|
||||||
if (poll_fd.revents & POLLIN) {
|
|
||||||
char buf[BUFFER_SIZE];
|
|
||||||
if (poll_fd.fd == STDIN_FILENO) {
|
|
||||||
// Data Available From stdin
|
|
||||||
int bytes_available;
|
|
||||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
|
||||||
bytes_available = 0;
|
|
||||||
}
|
|
||||||
// Read
|
|
||||||
const ssize_t bytes_read = read(poll_fd.fd, buf, BUFFER_SIZE);
|
|
||||||
if (bytes_read == -1) {
|
|
||||||
ERR("Unable To Read Input: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
// Write To Child
|
|
||||||
safe_write(input_pipe[PIPE_WRITE], buf, bytes_read);
|
|
||||||
} else {
|
|
||||||
// Data Available From Child's stdout/stderr
|
|
||||||
const ssize_t bytes_read = read(poll_fd.fd, buf, BUFFER_SIZE);
|
|
||||||
if (bytes_read == -1) {
|
|
||||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
// Print To Terminal
|
|
||||||
safe_write(poll_fd.fd == output_pipe[PIPE_READ] ? STDOUT_FILENO : STDERR_FILENO, buf, bytes_read);
|
|
||||||
// Write To log
|
|
||||||
safe_write(reborn_get_log_fd(), buf, bytes_read);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// File Descriptor No Longer Accessible
|
|
||||||
poll_fd.events = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close Pipes
|
|
||||||
close(output_pipe[PIPE_READ]);
|
|
||||||
close(error_pipe[PIPE_READ]);
|
|
||||||
close(input_pipe[PIPE_WRITE]);
|
|
||||||
|
|
||||||
// Check If Is Crash
|
|
||||||
const bool 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 = nullptr;
|
|
||||||
get_exit_status_string(status, &exit_status);
|
|
||||||
const std::string exit_code_line = "[CRASH]: Terminated" + std::string(exit_status) + '\n';
|
|
||||||
free(exit_status);
|
|
||||||
|
|
||||||
// Print Exit Code Log Line
|
|
||||||
safe_write(STDERR_FILENO, exit_code_line.c_str(), strlen(exit_code_line.c_str()));
|
|
||||||
// Write Exit Code Log Line
|
|
||||||
safe_write(reborn_get_log_fd(), exit_code_line.c_str(), strlen(exit_code_line.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close Log File
|
|
||||||
close(log_fd);
|
|
||||||
unsetenv(_MCPI_LOG_FD_ENV);
|
|
||||||
|
|
||||||
// Show Crash Log
|
|
||||||
if (is_crash && !reborn_is_headless()) {
|
|
||||||
show_report(log_filename.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit
|
|
||||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void setup_crash_report();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
92
launcher/src/logger/crash-report.cpp
Normal file
92
launcher/src/logger/crash-report.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
#include "../ui/frame.h"
|
||||||
|
|
||||||
|
// UI
|
||||||
|
struct CrashReport final : Frame {
|
||||||
|
explicit CrashReport(const char *filename): Frame("Crash Report", 640, 480) {
|
||||||
|
// Open File
|
||||||
|
std::ifstream stream(filename, std::ios::binary | std::ios::ate);
|
||||||
|
if (stream) {
|
||||||
|
// Read File
|
||||||
|
const std::streamoff size = stream.tellg();
|
||||||
|
stream.seekg(0, std::ifstream::beg);
|
||||||
|
log.resize(size);
|
||||||
|
stream.read(log.data(), size);
|
||||||
|
// Close File
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool first_render = true;
|
||||||
|
int render() override {
|
||||||
|
// Text
|
||||||
|
ImGui::TextWrapped("%s", MCPI_APP_TITLE " has crashed!");
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::TextWrapped("Need help? Consider asking on the Discord server!");
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::TextWrapped("If you believe this is a problem with " MCPI_APP_TITLE " itself, please upload this crash report to the #bugs Discord channel.");
|
||||||
|
// Log
|
||||||
|
if (ImGui::BeginChild("Log", ImVec2(0, -ImGui::GetFrameHeightWithSpacing() /* Leave Room For Bottom Row */), ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||||
|
ImGui::PushFont(monospace);
|
||||||
|
ImGui::TextUnformatted(log.data(), log.data() + log.size());
|
||||||
|
ImGui::PopFont();
|
||||||
|
if (first_render) {
|
||||||
|
ImGui::SetScrollHereY(1.0f);
|
||||||
|
first_render = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
// Buttons
|
||||||
|
if (ImGui::Button("Join Discord")) {
|
||||||
|
open_url(MCPI_DISCORD_INVITE);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("View All Logs")) {
|
||||||
|
open_url("file://" + get_logs_folder());
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
// Right-Aligned
|
||||||
|
int ret = 0;
|
||||||
|
const std::string &log_ref = log;
|
||||||
|
draw_right_aligned_buttons({"Copy", quit_text}, [&ret, &log_ref](const int id, const bool was_clicked) {
|
||||||
|
if (was_clicked) {
|
||||||
|
if (id == 0) {
|
||||||
|
// Copy Log
|
||||||
|
ImGui::SetClipboardText(log_ref.c_str());
|
||||||
|
} else {
|
||||||
|
// Exit
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::string log;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show Crash Report Dialog
|
||||||
|
static void redirect_file(FILE *file, const char *mode) {
|
||||||
|
const FILE *ret = freopen("/dev/null", mode, file);
|
||||||
|
if (!ret) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void show_report(const char *log_filename) {
|
||||||
|
// Fork
|
||||||
|
const pid_t pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
// Child
|
||||||
|
setsid();
|
||||||
|
redirect_file(stdout, "w");
|
||||||
|
redirect_file(stderr, "w");
|
||||||
|
redirect_file(stdin, "r");
|
||||||
|
CrashReport ui(log_filename);
|
||||||
|
ui.run();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
143
launcher/src/logger/logger.cpp
Normal file
143
launcher/src/logger/logger.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <csignal>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <string>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/util/string.h>
|
||||||
|
#include <libreborn/util/io.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
// Exit Handler
|
||||||
|
static pid_t child_pid = -1;
|
||||||
|
static void exit_handler(__attribute__((unused)) int signal) {
|
||||||
|
// Murder
|
||||||
|
kill(child_pid, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log File
|
||||||
|
static std::string log_filename;
|
||||||
|
static int log_fd;
|
||||||
|
std::string get_logs_folder() {
|
||||||
|
const std::string home = home_get();
|
||||||
|
ensure_directory(home.c_str());
|
||||||
|
const std::string logs = home + "/logs";
|
||||||
|
ensure_directory(logs.c_str());
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
static void setup_log_file() {
|
||||||
|
// Get Log Directory
|
||||||
|
const std::string logs = get_logs_folder();
|
||||||
|
|
||||||
|
// Get Timestamp
|
||||||
|
const std::string time = format_time("%Y-%m-%d");
|
||||||
|
|
||||||
|
// Get Log Filename
|
||||||
|
std::string file;
|
||||||
|
int num = 1;
|
||||||
|
do {
|
||||||
|
file = time + '-' + std::to_string(num) + ".log";
|
||||||
|
log_filename = logs + '/' + file;
|
||||||
|
num++;
|
||||||
|
} while (access(log_filename.c_str(), F_OK) != -1);
|
||||||
|
|
||||||
|
// Create latest.log Symlink
|
||||||
|
const std::string latest_log = logs + "/latest.log";
|
||||||
|
unlink(latest_log.c_str());
|
||||||
|
if (symlink(file.c_str(), latest_log.c_str()) != 0) {
|
||||||
|
WARN("Unable To Create Latest Log Symlink: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create File
|
||||||
|
log_fd = open(log_filename.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (log_fd == -1) {
|
||||||
|
ERR("Unable To Create Log File: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
reborn_set_log(log_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
void setup_logger() {
|
||||||
|
// Setup Logging
|
||||||
|
setup_log_file();
|
||||||
|
|
||||||
|
// Fork
|
||||||
|
std::optional<Process> child = fork_with_stdio();
|
||||||
|
if (!child) {
|
||||||
|
// Child Process
|
||||||
|
|
||||||
|
// Create New Process Group
|
||||||
|
setpgid(0, 0);
|
||||||
|
|
||||||
|
// Continue Execution
|
||||||
|
} else {
|
||||||
|
// Set Debug Tag
|
||||||
|
reborn_debug_tag = "(Logger) ";
|
||||||
|
DEBUG("Writing To: %s", log_filename.c_str());
|
||||||
|
|
||||||
|
// Install Signal Handlers
|
||||||
|
child_pid = child->pid;
|
||||||
|
struct sigaction act_sigint = {};
|
||||||
|
act_sigint.sa_flags = SA_RESTART;
|
||||||
|
act_sigint.sa_handler = &exit_handler;
|
||||||
|
sigaction(SIGINT, &act_sigint, nullptr);
|
||||||
|
struct sigaction act_sigterm = {};
|
||||||
|
act_sigterm.sa_flags = SA_RESTART;
|
||||||
|
act_sigterm.sa_handler = &exit_handler;
|
||||||
|
sigaction(SIGTERM, &act_sigterm, nullptr);
|
||||||
|
|
||||||
|
// Poll
|
||||||
|
poll_fds({child->fds[0], child->fds[1], STDIN_FILENO}, [&child](const int i, const size_t size, unsigned char *buf) {
|
||||||
|
if (i == 0 || i == 1) {
|
||||||
|
// stdout/stderr
|
||||||
|
|
||||||
|
// Print To Terminal
|
||||||
|
safe_write(i == 0 ? STDOUT_FILENO : STDERR_FILENO, buf, size);
|
||||||
|
// Write To log
|
||||||
|
safe_write(reborn_get_log_fd(), buf, size);
|
||||||
|
} else {
|
||||||
|
// stdin
|
||||||
|
|
||||||
|
// Write To Child
|
||||||
|
safe_write(child->fds[2], buf, size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get Exit Status
|
||||||
|
const int status = child->close();
|
||||||
|
const bool is_crash = !is_exit_status_success(status);
|
||||||
|
|
||||||
|
// Log Exit Code To log If Crash
|
||||||
|
if (is_crash) {
|
||||||
|
// Create Exit Code Log Line
|
||||||
|
const std::string exit_status = get_exit_status_string(status);
|
||||||
|
const std::string exit_code_line = "[CRASH]: Terminated" + exit_status + '\n';
|
||||||
|
|
||||||
|
// Print Exit Code Log Line
|
||||||
|
safe_write(STDERR_FILENO, exit_code_line.c_str(), exit_code_line.size());
|
||||||
|
// Write Exit Code Log Line
|
||||||
|
safe_write(reborn_get_log_fd(), exit_code_line.c_str(), exit_code_line.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close Log File
|
||||||
|
close(log_fd);
|
||||||
|
reborn_set_log(-1);
|
||||||
|
|
||||||
|
// Show Crash Log
|
||||||
|
if (is_crash && !reborn_is_headless()) {
|
||||||
|
show_report(log_filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit
|
||||||
|
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
7
launcher/src/logger/logger.h
Normal file
7
launcher/src/logger/logger.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string get_logs_folder();
|
||||||
|
void setup_logger();
|
||||||
|
void show_report(const char *log_filename);
|
@ -1,12 +1,15 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "bootstrap.h"
|
#include <libreborn/env/env.h>
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
|
#include "bootstrap/bootstrap.h"
|
||||||
#include "options/parser.h"
|
#include "options/parser.h"
|
||||||
#include "crash-report.h"
|
#include "logger/logger.h"
|
||||||
#include "util.h"
|
#include "util/util.h"
|
||||||
#include "client/configuration.h"
|
#include "client/configuration.h"
|
||||||
|
#include "updater/updater.h"
|
||||||
|
|
||||||
// Bind Options To Environmental Variable
|
// Bind Options To Environmental Variable
|
||||||
static void bind_to_env(const char *env, const bool value) {
|
static void bind_to_env(const char *env, const bool value) {
|
||||||
@ -25,56 +28,43 @@ static void setup_environment(const options_t &options) {
|
|||||||
bind_to_env(_MCPI_FORCE_HEADLESS_ENV, options.force_headless);
|
bind_to_env(_MCPI_FORCE_HEADLESS_ENV, options.force_headless);
|
||||||
bind_to_env(_MCPI_FORCE_NON_HEADLESS_ENV, options.force_non_headless);
|
bind_to_env(_MCPI_FORCE_NON_HEADLESS_ENV, options.force_non_headless);
|
||||||
|
|
||||||
// GTK Dark Mode
|
|
||||||
set_and_print_env("GTK_THEME", "Adwaita:dark");
|
|
||||||
|
|
||||||
// Configure PATH
|
// Configure PATH
|
||||||
{
|
setup_path();
|
||||||
// Get Binary Directory
|
|
||||||
const std::string binary_directory = get_binary_directory();
|
|
||||||
std::string new_path = binary_directory + "/bin";
|
|
||||||
// Add Existing PATH
|
|
||||||
{
|
|
||||||
const char *value = getenv("PATH");
|
|
||||||
if (value != nullptr && strlen(value) > 0) {
|
|
||||||
new_path += std::string(":") + value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Set And Free
|
|
||||||
set_and_print_env("PATH", new_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup MCPI_HOME
|
// Setup MCPI_HOME
|
||||||
if (const char *custom_profile_directory = getenv(MCPI_PROFILE_DIRECTORY_ENV); custom_profile_directory != nullptr) {
|
setup_home();
|
||||||
// Custom Directory
|
|
||||||
custom_profile_directory = realpath(custom_profile_directory, nullptr);
|
|
||||||
ALLOC_CHECK(custom_profile_directory);
|
|
||||||
set_and_print_env(_MCPI_HOME_ENV, custom_profile_directory);
|
|
||||||
free((void *) custom_profile_directory);
|
|
||||||
} else if (!reborn_is_server()) {
|
|
||||||
// Ensure $HOME
|
|
||||||
const char *home = getenv("HOME");
|
|
||||||
if (home == nullptr) {
|
|
||||||
ERR("$HOME Is Not Set");
|
|
||||||
}
|
|
||||||
set_and_print_env(_MCPI_HOME_ENV, home);
|
|
||||||
} else {
|
|
||||||
// Set Home To Current Directory, So World Data Is Stored There
|
|
||||||
char *launch_directory = getcwd(nullptr, 0);
|
|
||||||
ALLOC_CHECK(launch_directory);
|
|
||||||
set_and_print_env(_MCPI_HOME_ENV, launch_directory);
|
|
||||||
free(launch_directory);
|
|
||||||
}
|
|
||||||
// Create If Needed
|
// Create If Needed
|
||||||
const std::string minecraft_folder = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data();
|
const std::string minecraft_folder = home_get();
|
||||||
ensure_directory(minecraft_folder.c_str());
|
ensure_directory(minecraft_folder.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-Launch Commands
|
// Non-Launch Commands
|
||||||
static void handle_non_launch_commands(const options_t &options) {
|
static void handle_non_launch_commands(const options_t &options) {
|
||||||
|
// SDK
|
||||||
if (options.copy_sdk) {
|
if (options.copy_sdk) {
|
||||||
const std::string binary_directory = get_binary_directory();
|
const std::string binary_directory = get_binary_directory();
|
||||||
copy_sdk(binary_directory, false);
|
copy_sdk(binary_directory, true);
|
||||||
|
fflush(stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
// Updater
|
||||||
|
if (options.run_update) {
|
||||||
|
Updater *updater = Updater::instance;
|
||||||
|
if (updater) {
|
||||||
|
updater->update();
|
||||||
|
if (updater->status == ERROR) {
|
||||||
|
ERR("Unable To Update");
|
||||||
|
} else if (updater->status == UP_TO_DATE) {
|
||||||
|
INFO("Already Up-To-Date");
|
||||||
|
} else {
|
||||||
|
if (updater->status != RESTART_NEEDED) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
INFO("Update Completed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ERR("Built-In Updater Unavailable, Use System Package Manager");
|
||||||
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
@ -85,30 +75,30 @@ static void start_game(const options_t &options) {
|
|||||||
// Disable stdout Buffering
|
// Disable stdout Buffering
|
||||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||||
|
|
||||||
// Setup Crash Reporting
|
|
||||||
if (!options.disable_crash_report) {
|
|
||||||
setup_crash_report();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure Client Options
|
// Configure Client Options
|
||||||
if (!reborn_is_server()) {
|
if (!reborn_is_server()) {
|
||||||
configure_client(options);
|
configure_client(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start Logging
|
||||||
|
if (!options.disable_logger) {
|
||||||
|
setup_logger();
|
||||||
|
}
|
||||||
|
|
||||||
// Bootstrap
|
// Bootstrap
|
||||||
bootstrap(options);
|
bootstrap(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
int main(int argc, char *argv[]) {
|
int main(const int argc, char *argv[]) {
|
||||||
// Parse Options
|
// Parse Options
|
||||||
options_t options = parse_options(argc, argv);
|
const options_t options = parse_options(argc, argv);
|
||||||
|
|
||||||
// Set Debug Tag
|
// Set Debug Tag
|
||||||
reborn_debug_tag = "(Launcher) ";
|
reborn_debug_tag = "(Launcher) ";
|
||||||
|
|
||||||
// Debug Logging
|
// Debug Logging
|
||||||
unsetenv(_MCPI_LOG_FD_ENV);
|
reborn_set_log(-1);
|
||||||
bind_to_env(MCPI_DEBUG_ENV, options.debug);
|
bind_to_env(MCPI_DEBUG_ENV, options.debug);
|
||||||
|
|
||||||
// Setup Environment
|
// Setup Environment
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
OPTION(debug, "debug", 'd', "Enable Debug Logging")
|
OPTION(debug, "debug", 'd', "Enable Debug Logging")
|
||||||
OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit")
|
OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit")
|
||||||
OPTION(disable_crash_report, "disable-crash-report", -1, "Disable Crash Report Dialog")
|
OPTION(disable_logger, "disable-logger", -1, "Disable Logger (And Crash Report Dialog)")
|
||||||
OPTION(use_default, "default", -3, "Skip Client-Mode Configuration Dialogs")
|
OPTION(use_default, "default", -3, "Skip Client-Mode Configuration Dialogs")
|
||||||
OPTION(no_cache, "no-cache", -4, "Disable Client-Mode Configuration Cache")
|
OPTION(no_cache, "no-cache", -4, "Disable Client-Mode Configuration Cache")
|
||||||
OPTION(wipe_cache, "wipe-cache", -5, "Wipe Cached Client-Mode Configuration And Exit")
|
OPTION(wipe_cache, "wipe-cache", -5, "Wipe Cached Client-Mode Configuration And Exit")
|
||||||
@ -10,4 +10,5 @@ OPTION(only_generate, "only-generate", -8, "Generate World And Exit (Server-Mode
|
|||||||
OPTION(force_headless, "force-headless", -9, "Force Disable Game Rendering")
|
OPTION(force_headless, "force-headless", -9, "Force Disable Game Rendering")
|
||||||
OPTION(force_non_headless, "force-non-headless", -10, "Force Enable Game Rendering")
|
OPTION(force_non_headless, "force-non-headless", -10, "Force Enable Game Rendering")
|
||||||
OPTION(server_mode, "server", -11, "Run In Server-Mode")
|
OPTION(server_mode, "server", -11, "Run In Server-Mode")
|
||||||
OPTION(skip_pagesize_check, "skip-pagesize-check", -12, "Skip Page-Size Check (Not Recommended)")
|
OPTION(skip_pagesize_check, "skip-pagesize-check", -12, "Skip Page-Size Check (Not Recommended)")
|
||||||
|
OPTION(run_update, "update", -13, "Run Updater (If Available)")
|
@ -1,5 +1,9 @@
|
|||||||
#include <argp.h>
|
#include <argp.h>
|
||||||
|
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
#include <libreborn/env/env.h>
|
||||||
|
#include <trampoline/types.h>
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
@ -16,7 +20,10 @@ static argp_option options_data[] = {
|
|||||||
#undef OPTION
|
#undef OPTION
|
||||||
{nullptr, 0, nullptr, 0, "Environmental Variables:", 0},
|
{nullptr, 0, nullptr, 0, "Environmental Variables:", 0},
|
||||||
#define ENV(name, doc) {#name, env_key--, nullptr, OPTION_DOC | OPTION_NO_USAGE | (is_env_var_internal(name##_ENV) ? OPTION_HIDDEN : 0), doc, 0},
|
#define ENV(name, doc) {#name, env_key--, nullptr, OPTION_DOC | OPTION_NO_USAGE | (is_env_var_internal(name##_ENV) ? OPTION_HIDDEN : 0), doc, 0},
|
||||||
#include <libreborn/env-list.h>
|
#include <libreborn/env/list.h>
|
||||||
|
#ifdef MCPI_BUILD_RUNTIME
|
||||||
|
#include <trampoline/env-list.h>
|
||||||
|
#endif
|
||||||
#undef ENV
|
#undef ENV
|
||||||
{nullptr, 0, nullptr, 0, "Help Options:", -1},
|
{nullptr, 0, nullptr, 0, "Help Options:", -1},
|
||||||
{nullptr, 0, nullptr, 0, nullptr, 0}
|
{nullptr, 0, nullptr, 0, nullptr, 0}
|
||||||
@ -27,7 +34,7 @@ static argp_option options_data[] = {
|
|||||||
case key: \
|
case key: \
|
||||||
options->name = true; \
|
options->name = true; \
|
||||||
break;
|
break;
|
||||||
static error_t parse_opt(int key, __attribute__((unused)) char *arg, argp_state *state) {
|
static error_t parse_opt(const int key, __attribute__((unused)) char *arg, argp_state *state) {
|
||||||
options_t *options = (options_t *) state->input;
|
options_t *options = (options_t *) state->input;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
#include "option-list.h"
|
#include "option-list.h"
|
||||||
@ -38,7 +45,7 @@ static error_t parse_opt(int key, __attribute__((unused)) char *arg, argp_state
|
|||||||
}
|
}
|
||||||
#undef OPTION
|
#undef OPTION
|
||||||
static argp argp = {options_data, parse_opt, nullptr, doc, nullptr, nullptr, nullptr};
|
static argp argp = {options_data, parse_opt, nullptr, doc, nullptr, nullptr, nullptr};
|
||||||
options_t parse_options(int argc, char *argv[]) {
|
options_t parse_options(const int argc, char *argv[]) {
|
||||||
options_t options = {};
|
options_t options = {};
|
||||||
argp_parse(&argp, argc, argv, 0, nullptr, &options);
|
argp_parse(&argp, argc, argv, 0, nullptr, &options);
|
||||||
return options;
|
return options;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
|
||||||
|
|
||||||
#define OPTION(name, ...) bool name;
|
#define OPTION(name, ...) bool name;
|
||||||
struct options_t {
|
struct options_t {
|
||||||
#include "option-list.h"
|
#include "option-list.h"
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
|
|
||||||
|
|
||||||
void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_path, const std::string &interpreter, const std::vector<std::string> &rpath, const std::vector<std::string> &mods);
|
|
@ -1,59 +0,0 @@
|
|||||||
#include <libreborn/libreborn.h>
|
|
||||||
|
|
||||||
#include "bootstrap.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
// Log
|
|
||||||
#define LOG(is_debug, ...) \
|
|
||||||
{ \
|
|
||||||
if (is_debug) { \
|
|
||||||
DEBUG(__VA_ARGS__); \
|
|
||||||
} else { \
|
|
||||||
INFO(__VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy SDK Into ~/.minecraft-pi
|
|
||||||
#define HOME_SUBDIRECTORY_FOR_SDK (std::string(get_home_subdirectory_for_game_data()) + "/sdk")
|
|
||||||
void copy_sdk(const std::string &binary_directory, const bool log_with_debug) {
|
|
||||||
// Ensure SDK Directory
|
|
||||||
std::string sdk_path;
|
|
||||||
{
|
|
||||||
sdk_path = std::string(getenv(_MCPI_HOME_ENV)) + HOME_SUBDIRECTORY_FOR_SDK;
|
|
||||||
const char *const command[] = {"mkdir", "-p", sdk_path.c_str(), nullptr};
|
|
||||||
run_simple_command(command, "Unable To Create SDK Directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock File
|
|
||||||
const std::string lock_file_path = sdk_path + "/.lock";
|
|
||||||
const int lock_file_fd = lock_file(lock_file_path.c_str());
|
|
||||||
|
|
||||||
// Output Directory
|
|
||||||
const std::string output = sdk_path + "/" MCPI_SDK_DIR;
|
|
||||||
// Source Directory
|
|
||||||
const std::string source = binary_directory + "/sdk/.";
|
|
||||||
|
|
||||||
// Clean
|
|
||||||
{
|
|
||||||
const char *const command[] = {"rm", "-rf", output.c_str(), nullptr};
|
|
||||||
run_simple_command(command, "Unable To Clean SDK Output Directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make Directory
|
|
||||||
{
|
|
||||||
const char *const command[] = {"mkdir", "-p", output.c_str(), nullptr};
|
|
||||||
run_simple_command(command, "Unable To Create SDK Output Directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy
|
|
||||||
{
|
|
||||||
const char *const command[] = {"cp", "-ar", source.c_str(), output.c_str(), nullptr};
|
|
||||||
run_simple_command(command, "Unable To Copy SDK");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log
|
|
||||||
LOG(log_with_debug, "Copied SDK To: %s", output.c_str());
|
|
||||||
|
|
||||||
// Unlock File
|
|
||||||
unlock_file(lock_file_path.c_str(), lock_file_fd);
|
|
||||||
}
|
|
83
launcher/src/ui/color.cpp
Normal file
83
launcher/src/ui/color.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "frame.h"
|
||||||
|
|
||||||
|
// Calculate Perceived Brightness Of Color
|
||||||
|
// See: https://en.wikipedia.org/w/index.php?title=Relative_luminance&useskin=vector
|
||||||
|
static float compute_luma(const ImVec4 &color) {
|
||||||
|
return (0.2126f * color.x) + (0.7152f * color.y) + (0.0722f * color.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply Luma To RGB
|
||||||
|
static float clamp(const float value) {
|
||||||
|
return std::max(0.0f, std::min(value, 1.0f));
|
||||||
|
}
|
||||||
|
static ImVec4 apply_luma_to_color(const float target_luma, const ImVec4 &color) {
|
||||||
|
const float current_luma = compute_luma(color);
|
||||||
|
const float luma_ratio = (current_luma != 0) ? target_luma / current_luma : 0;
|
||||||
|
ImVec4 out = color;
|
||||||
|
for (float *x : {&out.x, &out.y, &out.z}) {
|
||||||
|
*x = clamp(*x * luma_ratio);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blend Color
|
||||||
|
static ImVec4 blend_color(const ImVec4 &top, const ImVec4 &bottom) {
|
||||||
|
const float luma = compute_luma(bottom);
|
||||||
|
ImVec4 out = apply_luma_to_color(luma, top);
|
||||||
|
out.w = bottom.w;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
static ImVec4 blend_with_primary(const ImVec4 &color) {
|
||||||
|
static constexpr ImVec4 primary_color = {1.0f, (69.0f / 255.0f), 0.0f, 1.0f};
|
||||||
|
return blend_color(primary_color, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify Colors
|
||||||
|
void Frame::patch_colors(ImGuiStyle &style) {
|
||||||
|
// Blend Colors
|
||||||
|
static int target_colors_blend[] = {
|
||||||
|
ImGuiCol_FrameBg,
|
||||||
|
ImGuiCol_FrameBgHovered,
|
||||||
|
ImGuiCol_FrameBgActive,
|
||||||
|
ImGuiCol_TitleBgActive,
|
||||||
|
ImGuiCol_CheckMark,
|
||||||
|
ImGuiCol_SliderGrab,
|
||||||
|
ImGuiCol_SliderGrabActive,
|
||||||
|
ImGuiCol_Button,
|
||||||
|
ImGuiCol_ButtonHovered,
|
||||||
|
ImGuiCol_ButtonActive,
|
||||||
|
ImGuiCol_Header,
|
||||||
|
ImGuiCol_HeaderHovered,
|
||||||
|
ImGuiCol_HeaderActive,
|
||||||
|
ImGuiCol_SeparatorHovered,
|
||||||
|
ImGuiCol_SeparatorActive,
|
||||||
|
ImGuiCol_ResizeGrip,
|
||||||
|
ImGuiCol_ResizeGripHovered,
|
||||||
|
ImGuiCol_ResizeGripActive,
|
||||||
|
ImGuiCol_TabHovered,
|
||||||
|
ImGuiCol_Tab,
|
||||||
|
ImGuiCol_TabSelected,
|
||||||
|
ImGuiCol_TabSelectedOverline,
|
||||||
|
ImGuiCol_TabDimmed,
|
||||||
|
ImGuiCol_TabDimmedSelected,
|
||||||
|
ImGuiCol_TextLink,
|
||||||
|
ImGuiCol_TextSelectedBg,
|
||||||
|
ImGuiCol_NavCursor
|
||||||
|
};
|
||||||
|
for (const int target_color : target_colors_blend) {
|
||||||
|
ImVec4 &color = style.Colors[target_color];
|
||||||
|
color = blend_with_primary(color);
|
||||||
|
}
|
||||||
|
// Remove Blue Accent From Colors
|
||||||
|
static int target_colors_modify[] = {
|
||||||
|
ImGuiCol_Separator,
|
||||||
|
ImGuiCol_Border,
|
||||||
|
ImGuiCol_TableHeaderBg,
|
||||||
|
ImGuiCol_TableBorderStrong,
|
||||||
|
ImGuiCol_TableBorderLight
|
||||||
|
};
|
||||||
|
for (const int target_color : target_colors_modify) {
|
||||||
|
ImVec4 &color = style.Colors[target_color];
|
||||||
|
color.y = color.z = color.x;
|
||||||
|
}
|
||||||
|
}
|
135
launcher/src/ui/frame.cpp
Normal file
135
launcher/src/ui/frame.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "frame.h"
|
||||||
|
|
||||||
|
#include <imgui_impl_glfw.h>
|
||||||
|
#include <imgui_impl_opengl2.h>
|
||||||
|
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/glfw.h>
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
|
||||||
|
// Init/Cleanup
|
||||||
|
Frame::Frame(const char *title, const int width, const int height) {
|
||||||
|
// Create Window
|
||||||
|
init_glfw();
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||||
|
window = create_glfw_window(title, width, height);
|
||||||
|
|
||||||
|
// Load OpenGL
|
||||||
|
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
|
||||||
|
ERR("Unable To Load GLAD");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable V-Sync
|
||||||
|
// (On Wayland, This Fixes Issues With The Clipboard)
|
||||||
|
glfwSwapInterval(0);
|
||||||
|
|
||||||
|
// Setup ImGui Context
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||||
|
io.IniFilename = nullptr;
|
||||||
|
io.LogFilename = nullptr;
|
||||||
|
|
||||||
|
// Setup Platform/Renderer Backends
|
||||||
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||||
|
ImGui_ImplOpenGL2_Init();
|
||||||
|
}
|
||||||
|
Frame::~Frame() {
|
||||||
|
// Shutdown ImGui
|
||||||
|
ImGui_ImplOpenGL2_Shutdown();
|
||||||
|
ImGui_ImplGlfw_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
// Cleanup GLFW
|
||||||
|
cleanup_glfw(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run Loop
|
||||||
|
int Frame::run() {
|
||||||
|
int ret = 0;
|
||||||
|
while (!glfwWindowShouldClose(window) && ret == 0) {
|
||||||
|
glfwPollEvents();
|
||||||
|
// Update Style
|
||||||
|
static float last_scale = -1.0f;
|
||||||
|
float scale;
|
||||||
|
get_glfw_scale(window, &scale, nullptr);
|
||||||
|
if (scale != last_scale) {
|
||||||
|
last_scale = scale;
|
||||||
|
setup_style(scale);
|
||||||
|
}
|
||||||
|
// Start Frame
|
||||||
|
ImGui_ImplOpenGL2_NewFrame();
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
// Main Window
|
||||||
|
ImGui::SetNextWindowPos({0, 0});
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
ImGui::SetNextWindowSize({float(width), float(height)});
|
||||||
|
if (ImGui::Begin("##Frame", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||||
|
ret = render();
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
// Render To OpenGL
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style
|
||||||
|
EMBEDDED_RESOURCE(Roboto_Medium_ttf);
|
||||||
|
EMBEDDED_RESOURCE(Cousine_Regular_ttf);
|
||||||
|
void Frame::setup_style(const float scale) {
|
||||||
|
// Fonts
|
||||||
|
const ImGuiIO &io = ImGui::GetIO();
|
||||||
|
io.Fonts->Clear();
|
||||||
|
ImFontConfig font_cfg;
|
||||||
|
font_cfg.FontDataOwnedByAtlas = false;
|
||||||
|
io.Fonts->AddFontFromMemoryTTF(Roboto_Medium_ttf, int(Roboto_Medium_ttf_len), std::floor(20.0f * scale), &font_cfg);
|
||||||
|
monospace = io.Fonts->AddFontFromMemoryTTF(Cousine_Regular_ttf, int(Cousine_Regular_ttf_len), std::floor(18.0f * scale), &font_cfg);
|
||||||
|
ImGui_ImplOpenGL2_DestroyFontsTexture();
|
||||||
|
// Style
|
||||||
|
ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
style = ImGuiStyle();
|
||||||
|
style.WindowBorderSize = 0;
|
||||||
|
ImGui::StyleColorsDark(&style);
|
||||||
|
style.ScaleAllSizes(scale);
|
||||||
|
patch_colors(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right-Aligned Buttons
|
||||||
|
float Frame::get_frame_width(const char *str) {
|
||||||
|
const ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
return ImGui::CalcTextSize(str).x + style.FramePadding.x * 2.0f;
|
||||||
|
}
|
||||||
|
void Frame::draw_right_aligned_buttons(const std::vector<const char *> &buttons, const std::function<void(int, bool)> &callback, const bool should_actually_center) {
|
||||||
|
// Calculate Position
|
||||||
|
const ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
float width_needed = 0;
|
||||||
|
for (const char *text : buttons) {
|
||||||
|
if (width_needed > 0) {
|
||||||
|
width_needed += style.ItemSpacing.x;
|
||||||
|
}
|
||||||
|
width_needed += get_frame_width(text);
|
||||||
|
}
|
||||||
|
float cursor_pos;
|
||||||
|
if (should_actually_center) {
|
||||||
|
cursor_pos = ImGui::GetWindowSize().x - width_needed;
|
||||||
|
cursor_pos /= 2.0f;
|
||||||
|
} else {
|
||||||
|
cursor_pos = ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - width_needed;
|
||||||
|
}
|
||||||
|
ImGui::SetCursorPosX(cursor_pos);
|
||||||
|
// Draw
|
||||||
|
for (std::vector<const char *>::size_type id = 0; id < buttons.size(); id++) {
|
||||||
|
if (id > 0) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
callback(int(id), ImGui::Button(buttons[id]));
|
||||||
|
}
|
||||||
|
}
|
32
launcher/src/ui/frame.h
Normal file
32
launcher/src/ui/frame.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
// UI Frame
|
||||||
|
struct Frame {
|
||||||
|
Frame(const char *title, int width, int height);
|
||||||
|
virtual ~Frame();
|
||||||
|
// Prevent Copying
|
||||||
|
Frame(const Frame &) = delete;
|
||||||
|
Frame &operator=(const Frame &) = delete;
|
||||||
|
// Run
|
||||||
|
int run();
|
||||||
|
virtual int render() = 0;
|
||||||
|
protected:
|
||||||
|
// API For Sub-Classes
|
||||||
|
ImFont *monospace = nullptr;
|
||||||
|
static float get_frame_width(const char *str);
|
||||||
|
static void draw_right_aligned_buttons(const std::vector<const char *> &buttons, const std::function<void(int, bool)> &callback, bool should_actually_center = false);
|
||||||
|
static constexpr const char *quit_text = "Quit";
|
||||||
|
private:
|
||||||
|
// Properties
|
||||||
|
GLFWwindow *window = nullptr;
|
||||||
|
// Internal Methods
|
||||||
|
float get_scale();
|
||||||
|
void setup_style(float scale);
|
||||||
|
static void patch_colors(ImGuiStyle &style);
|
||||||
|
};
|
122
launcher/src/updater/appimage.cpp
Normal file
122
launcher/src/updater/appimage.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
|
#include "updater.h"
|
||||||
|
|
||||||
|
// Implement
|
||||||
|
struct AppImageUpdater final : Updater {
|
||||||
|
void update() override;
|
||||||
|
void restart() override;
|
||||||
|
static AppImageUpdater instance;
|
||||||
|
};
|
||||||
|
AppImageUpdater AppImageUpdater::instance;
|
||||||
|
|
||||||
|
// Update
|
||||||
|
template <typename... Args>
|
||||||
|
static std::optional<std::string> run_wget(Args... args) {
|
||||||
|
int status = 0;
|
||||||
|
const char *const command[] = {"wget", "-O", std::forward<Args>(args)..., nullptr};
|
||||||
|
const std::vector<unsigned char> *output = run_command(command, &status);
|
||||||
|
std::string output_str = (const char *) output->data();
|
||||||
|
delete output;
|
||||||
|
if (!is_exit_status_success(status)) {
|
||||||
|
return std::nullopt;
|
||||||
|
} else {
|
||||||
|
return output_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static std::string extract_from_json(const std::string &json_str, const std::string &key) {
|
||||||
|
std::string::size_type pos = json_str.find(key);
|
||||||
|
std::array<std::string::size_type, 3> indices = {};
|
||||||
|
unsigned int i = 0;
|
||||||
|
while (true) {
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (i >= indices.size()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos = json_str.find('"', pos) + 1;
|
||||||
|
indices[i++] = pos;
|
||||||
|
}
|
||||||
|
const std::string::size_type start = indices[1];
|
||||||
|
const std::string::size_type end = indices[2];
|
||||||
|
return json_str.substr(start, end - start - 1);
|
||||||
|
}
|
||||||
|
static const char *get_appimage_path() {
|
||||||
|
const char *path = getenv("APPIMAGE");
|
||||||
|
if (path == nullptr) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
void AppImageUpdater::update() {
|
||||||
|
// Check
|
||||||
|
if (status != CHECKING) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
const std::optional<std::string> json = run_wget("-", MCPI_APPIMAGE_JSON_URL);
|
||||||
|
if (!json.has_value()) {
|
||||||
|
status = ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const std::string tag_name = extract_from_json(json.value(), "tag_name");
|
||||||
|
|
||||||
|
// Check Version
|
||||||
|
if (tag_name == MCPI_VERSION) {
|
||||||
|
status = UP_TO_DATE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get URL
|
||||||
|
std::string url = MCPI_APPIMAGE_DOWNLOAD_URL;
|
||||||
|
while (true) {
|
||||||
|
const std::string placeholder = MCPI_APPIMAGE_VERSION_PLACEHOLDER;
|
||||||
|
const std::string::size_type pos = url.find(placeholder);
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
url.replace(pos, placeholder.size(), tag_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Path
|
||||||
|
const char *appimage_path = get_appimage_path();
|
||||||
|
const std::string new_appimage_path_base = std::string(appimage_path) + ".new";
|
||||||
|
std::string new_appimage_path = new_appimage_path_base;
|
||||||
|
int num = 1;
|
||||||
|
while (access(new_appimage_path.c_str(), F_OK) != -1) {
|
||||||
|
new_appimage_path = new_appimage_path_base + '.' + std::to_string(num++);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download
|
||||||
|
status = DOWNLOADING;
|
||||||
|
const std::optional<std::string> out = run_wget(new_appimage_path.c_str(), url.c_str());
|
||||||
|
bool ret = out.has_value();
|
||||||
|
if (ret) {
|
||||||
|
ret = chmod(new_appimage_path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0;
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
ret = rename(new_appimage_path.c_str(), appimage_path) == 0;
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
unlink(new_appimage_path.c_str());
|
||||||
|
status = ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
status = RESTART_NEEDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart
|
||||||
|
void AppImageUpdater::restart() {
|
||||||
|
const char *const command[] = {get_appimage_path(), nullptr};
|
||||||
|
safe_execvpe(command, environ);
|
||||||
|
}
|
48
launcher/src/updater/updater.cpp
Normal file
48
launcher/src/updater/updater.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <pthread.h>
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
|
||||||
|
#include "updater.h"
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
Updater *Updater::instance = nullptr;
|
||||||
|
Updater::Updater() {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Status
|
||||||
|
bool Updater::can_start() const {
|
||||||
|
return status == NOT_STARTED || status == RESTART_NEEDED;
|
||||||
|
}
|
||||||
|
std::string Updater::get_status() const {
|
||||||
|
switch (status) {
|
||||||
|
case NOT_STARTED: return "Update";
|
||||||
|
case RESTART_NEEDED: return "Restart!";
|
||||||
|
case CHECKING: return "Checking...";
|
||||||
|
case UP_TO_DATE: return "Up-To-Date";
|
||||||
|
case DOWNLOADING: return "Downloading...";
|
||||||
|
case ERROR: return "Error";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run
|
||||||
|
static void *update_thread(void *data) {
|
||||||
|
Updater *updater = (Updater *) data;
|
||||||
|
updater->update();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void Updater::start() {
|
||||||
|
switch (status) {
|
||||||
|
case NOT_STARTED: {
|
||||||
|
status = CHECKING;
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, nullptr, update_thread, this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RESTART_NEEDED: {
|
||||||
|
restart();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
}
|
31
launcher/src/updater/updater.h
Normal file
31
launcher/src/updater/updater.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// Update Status
|
||||||
|
enum UpdateStatus {
|
||||||
|
NOT_STARTED,
|
||||||
|
CHECKING,
|
||||||
|
UP_TO_DATE,
|
||||||
|
DOWNLOADING,
|
||||||
|
RESTART_NEEDED,
|
||||||
|
ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
// Updater
|
||||||
|
struct Updater {
|
||||||
|
// Instance
|
||||||
|
static Updater *instance;
|
||||||
|
// Constructor
|
||||||
|
Updater();
|
||||||
|
virtual ~Updater() = default;
|
||||||
|
// Implementation
|
||||||
|
virtual void update() = 0;
|
||||||
|
virtual void restart() = 0;
|
||||||
|
// Methods
|
||||||
|
[[nodiscard]] std::string get_status() const;
|
||||||
|
[[nodiscard]] bool can_start() const;
|
||||||
|
void start();
|
||||||
|
// Properties
|
||||||
|
UpdateStatus status = NOT_STARTED;
|
||||||
|
};
|
@ -1,43 +0,0 @@
|
|||||||
#include <libreborn/libreborn.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
// Simpler Version Of run_command()
|
|
||||||
void run_simple_command(const char *const command[], const char *error) {
|
|
||||||
int status = 0;
|
|
||||||
char *output = run_command(command, &status, nullptr);
|
|
||||||
if (output != nullptr) {
|
|
||||||
free(output);
|
|
||||||
}
|
|
||||||
if (!is_exit_status_success(status)) {
|
|
||||||
ERR("%s", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chop Off Last Component
|
|
||||||
void chop_last_component(std::string &str) {
|
|
||||||
const std::string::size_type pos = str.find_last_of('/');
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
str = str.substr(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Binary Directory (Remember To Free)
|
|
||||||
std::string safe_realpath(const std::string &path) {
|
|
||||||
char *raw = realpath(path.c_str(), nullptr);
|
|
||||||
if (raw == nullptr) {
|
|
||||||
ERR("Unable To Resolve: %s", path.c_str());
|
|
||||||
}
|
|
||||||
std::string str = raw;
|
|
||||||
free(raw);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
std::string get_binary_directory() {
|
|
||||||
// Get Path To Current Executable
|
|
||||||
std::string exe = safe_realpath("/proc/self/exe");
|
|
||||||
// Chop Off Last Component
|
|
||||||
chop_last_component(exe);
|
|
||||||
// Return
|
|
||||||
return exe;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
void run_simple_command(const char *const command[], const char *error);
|
|
||||||
|
|
||||||
void chop_last_component(std::string &str);
|
|
||||||
std::string safe_realpath(const std::string &path);
|
|
||||||
std::string get_binary_directory();
|
|
52
launcher/src/util/env.cpp
Normal file
52
launcher/src/util/env.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/env/env.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
|
// $PATH
|
||||||
|
void setup_path() {
|
||||||
|
// Get Binary Directory
|
||||||
|
const std::string binary_directory = get_binary_directory();
|
||||||
|
std::string new_path = binary_directory + "/bin";
|
||||||
|
// Add Existing PATH
|
||||||
|
const char *value = getenv("PATH");
|
||||||
|
if (value != nullptr && strlen(value) > 0) {
|
||||||
|
new_path += std::string(":") + value;
|
||||||
|
}
|
||||||
|
// Set And Free
|
||||||
|
set_and_print_env("PATH", new_path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profile Directory
|
||||||
|
void setup_home() {
|
||||||
|
const char *custom_profile_directory = getenv(MCPI_PROFILE_DIRECTORY_ENV);
|
||||||
|
std::string home;
|
||||||
|
if (custom_profile_directory != nullptr) {
|
||||||
|
// Custom Directory
|
||||||
|
home = safe_realpath(custom_profile_directory);
|
||||||
|
} else if (!reborn_is_server()) {
|
||||||
|
// Ensure $HOME
|
||||||
|
const char *value = getenv("HOME");
|
||||||
|
if (value == nullptr) {
|
||||||
|
ERR("$HOME Is Not Set");
|
||||||
|
}
|
||||||
|
home = value;
|
||||||
|
// Flatpak
|
||||||
|
#ifdef MCPI_IS_FLATPAK_BUILD
|
||||||
|
home += "/.var/app/" MCPI_APP_ID;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// Set Home To Current Directory, So World Data Is Stored There
|
||||||
|
char *launch_directory = getcwd(nullptr, 0);
|
||||||
|
if (launch_directory == nullptr) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
home = launch_directory;
|
||||||
|
free(launch_directory);
|
||||||
|
}
|
||||||
|
// Set
|
||||||
|
set_and_print_env(_MCPI_HOME_ENV, home.c_str());
|
||||||
|
}
|
167
launcher/src/util/sdk.cpp
Normal file
167
launcher/src/util/sdk.cpp
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#include <optional>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/util.h>
|
||||||
|
#include <libreborn/util/io.h>
|
||||||
|
#include <libreborn/config.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
// Utility Functions
|
||||||
|
static constexpr char path_separator = '/';
|
||||||
|
static void make_directory(std::string path /* Must Be Absolute */) {
|
||||||
|
path += path_separator;
|
||||||
|
std::stringstream stream(path);
|
||||||
|
path = "";
|
||||||
|
std::string path_segment;
|
||||||
|
while (std::getline(stream, path_segment, path_separator)) {
|
||||||
|
path += path_segment;
|
||||||
|
ensure_directory(path.c_str());
|
||||||
|
path += path_separator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void delete_recursively(const std::string &path, const bool allow_nonexistent_dir) {
|
||||||
|
// Loop Through Children
|
||||||
|
const bool success = read_directory(path, [&path](const dirent *entry) {
|
||||||
|
// Handle
|
||||||
|
const std::string child = path + path_separator + entry->d_name;
|
||||||
|
if (entry->d_type == DT_DIR) {
|
||||||
|
delete_recursively(child, false);
|
||||||
|
} else if (unlink(child.c_str()) != 0) {
|
||||||
|
ERR("Unable To Delete File: %s: %s", child.c_str(), strerror(errno));
|
||||||
|
}
|
||||||
|
}, allow_nonexistent_dir);
|
||||||
|
// Delete
|
||||||
|
if (success && rmdir(path.c_str()) != 0) {
|
||||||
|
ERR("Unable To Delete Directory: %s: %s", path.c_str(), strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void copy_file(const std::string &src, const std::string &dst) {
|
||||||
|
std::ifstream in(src, std::ios::binary);
|
||||||
|
if (!in) {
|
||||||
|
ERR("Unable To Open Source File: %s", src.c_str());
|
||||||
|
}
|
||||||
|
std::ofstream out(dst, std::ios::binary);
|
||||||
|
if (!out) {
|
||||||
|
ERR("Unable To Create Destination File: %s", dst.c_str());
|
||||||
|
}
|
||||||
|
out << in.rdbuf();
|
||||||
|
out.close();
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
static void copy_directory(const std::string &src, const std::string &dst) {
|
||||||
|
read_directory(src, [&src, &dst](const dirent *entry) {
|
||||||
|
const std::string name = path_separator + std::string(entry->d_name);
|
||||||
|
const std::string in = src + name;
|
||||||
|
const std::string out = dst + name;
|
||||||
|
if (entry->d_type == DT_DIR) {
|
||||||
|
ensure_directory(out.c_str());
|
||||||
|
copy_directory(in, out);
|
||||||
|
} else {
|
||||||
|
copy_file(in, out);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path
|
||||||
|
static std::string get_sdk_root(const std::string &home) {
|
||||||
|
return home + path_separator + "sdk";
|
||||||
|
}
|
||||||
|
static std::string get_sdk_path_home() {
|
||||||
|
return get_sdk_root(home_get()) + path_separator + MCPI_SDK_DIR;
|
||||||
|
}
|
||||||
|
static std::string get_sdk_path_bundled(const std::string &binary_directory) {
|
||||||
|
return get_sdk_root(binary_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Whether SDK Should Be Copied
|
||||||
|
static std::optional<std::string> get_sdk_hash(const std::string &sdk) {
|
||||||
|
const std::string path = sdk + path_separator + ".hash";
|
||||||
|
// Open File
|
||||||
|
std::ifstream stream(path, std::ios::binary | std::ios::ate);
|
||||||
|
if (stream) {
|
||||||
|
std::string hash;
|
||||||
|
// Read File
|
||||||
|
const std::streamoff size = stream.tellg();
|
||||||
|
stream.seekg(0, std::ifstream::beg);
|
||||||
|
hash.resize(size);
|
||||||
|
stream.read(hash.data(), size);
|
||||||
|
// Close File
|
||||||
|
stream.close();
|
||||||
|
// Return
|
||||||
|
return hash;
|
||||||
|
} else {
|
||||||
|
// Unable To Read
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static bool should_copy_sdk(const std::string &binary_directory) {
|
||||||
|
// Read Hashes
|
||||||
|
const std::optional<std::string> home_hash = get_sdk_hash(get_sdk_path_home());
|
||||||
|
if (!home_hash.has_value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const std::optional<std::string> bundled_hash = get_sdk_hash(get_sdk_path_bundled(binary_directory));
|
||||||
|
if (!home_hash.has_value()) {
|
||||||
|
IMPOSSIBLE();
|
||||||
|
}
|
||||||
|
const bool should_copy = home_hash.value() != bundled_hash.value();
|
||||||
|
if (!should_copy) {
|
||||||
|
DEBUG("Skipped Unnecessary SDK Copy");
|
||||||
|
}
|
||||||
|
return should_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log
|
||||||
|
#define LOG(is_debug, ...) \
|
||||||
|
({ \
|
||||||
|
if ((is_debug)) { \
|
||||||
|
DEBUG(__VA_ARGS__); \
|
||||||
|
} else { \
|
||||||
|
INFO(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
|
// Copy SDK Into ~/.minecraft-pi
|
||||||
|
static void do_copy_sdk(const std::string &binary_directory, const bool force) {
|
||||||
|
// Check If Copy Is Needed
|
||||||
|
bool should_copy = force;
|
||||||
|
if (!should_copy) {
|
||||||
|
should_copy = should_copy_sdk(binary_directory);
|
||||||
|
}
|
||||||
|
if (!should_copy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Paths
|
||||||
|
const std::string src_sdk = get_sdk_path_bundled(binary_directory);
|
||||||
|
const std::string dst_sdk = get_sdk_path_home();
|
||||||
|
|
||||||
|
// Create Output Directory
|
||||||
|
delete_recursively(dst_sdk, true);
|
||||||
|
make_directory(dst_sdk);
|
||||||
|
|
||||||
|
// Copy Directory
|
||||||
|
copy_directory(src_sdk, dst_sdk);
|
||||||
|
|
||||||
|
// Log
|
||||||
|
LOG(!force, "Copied SDK To: %s", dst_sdk.c_str());
|
||||||
|
}
|
||||||
|
void copy_sdk(const std::string &binary_directory, const bool force) {
|
||||||
|
// Lock File
|
||||||
|
const std::string root = get_sdk_root(home_get());
|
||||||
|
ensure_directory(root.c_str());
|
||||||
|
const std::string lock_file_path = root + path_separator + ".lock";
|
||||||
|
const int lock_file_fd = lock_file(lock_file_path.c_str());
|
||||||
|
|
||||||
|
// Do
|
||||||
|
do_copy_sdk(binary_directory, force);
|
||||||
|
|
||||||
|
// Unlock File
|
||||||
|
unlock_file(lock_file_path.c_str(), lock_file_fd);
|
||||||
|
}
|
60
launcher/src/util/util.cpp
Normal file
60
launcher/src/util/util.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include <dirent.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <libreborn/log.h>
|
||||||
|
#include <libreborn/util/exec.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
// Chop Off Last Component
|
||||||
|
void chop_last_component(std::string &str) {
|
||||||
|
const std::string::size_type pos = str.find_last_of('/');
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str = str.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Binary Directory (Remember To Free)
|
||||||
|
std::string safe_realpath(const std::string &path) {
|
||||||
|
char *raw = realpath(path.c_str(), nullptr);
|
||||||
|
if (raw == nullptr) {
|
||||||
|
ERR("Unable To Resolve: %s", path.c_str());
|
||||||
|
}
|
||||||
|
std::string str = raw;
|
||||||
|
free(raw);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
std::string get_binary_directory() {
|
||||||
|
// Get Path To Current Executable
|
||||||
|
std::string exe = safe_realpath("/proc/self/exe");
|
||||||
|
// Chop Off Last Component
|
||||||
|
chop_last_component(exe);
|
||||||
|
// Return
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Directory
|
||||||
|
bool read_directory(const std::string &path, const std::function<void(const dirent *)> &callback, const bool allow_nonexistent_dir) {
|
||||||
|
// Open Directory
|
||||||
|
DIR *dp = opendir(path.c_str());
|
||||||
|
if (dp == nullptr) {
|
||||||
|
if (allow_nonexistent_dir) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ERR("Unable To Open Directory: %s: %s", path.c_str(), strerror(errno));
|
||||||
|
}
|
||||||
|
// Read
|
||||||
|
const dirent *entry;
|
||||||
|
while ((entry = readdir(dp)) != nullptr) {
|
||||||
|
// Block Pseudo-Directories
|
||||||
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Run
|
||||||
|
callback(entry);
|
||||||
|
}
|
||||||
|
// Close
|
||||||
|
closedir(dp);
|
||||||
|
return true;
|
||||||
|
}
|
15
launcher/src/util/util.h
Normal file
15
launcher/src/util/util.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
void chop_last_component(std::string &str);
|
||||||
|
std::string safe_realpath(const std::string &path);
|
||||||
|
std::string get_binary_directory();
|
||||||
|
|
||||||
|
void copy_sdk(const std::string &binary_directory, bool force);
|
||||||
|
|
||||||
|
void setup_path();
|
||||||
|
void setup_home();
|
||||||
|
|
||||||
|
bool read_directory(const std::string &path, const std::function<void(const struct dirent *)> &callback, bool allow_nonexistent_dir = false);
|
@ -6,29 +6,29 @@ configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/includ
|
|||||||
|
|
||||||
# Util
|
# Util
|
||||||
add_library(reborn-util SHARED
|
add_library(reborn-util SHARED
|
||||||
src/util/exec.c
|
src/util/exec.cpp
|
||||||
src/util/string.c
|
src/util/string.cpp
|
||||||
src/util/util.c
|
src/util/util.cpp
|
||||||
src/util/log.c
|
src/util/log.cpp
|
||||||
src/util/cp437.cpp
|
src/util/cp437.cpp
|
||||||
src/util/env.c
|
src/util/env/env.cpp
|
||||||
)
|
src/util/config.cpp
|
||||||
target_include_directories(
|
src/util/env/flags/node.cpp
|
||||||
reborn-util
|
src/util/env/flags/flags.cpp
|
||||||
PUBLIC
|
src/util/env/flags/available-feature-flags # Show In IDE
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
src/util/env/servers.cpp
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
|
||||||
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/libreborn>"
|
|
||||||
)
|
)
|
||||||
|
embed_resource(reborn-util src/util/env/flags/available-feature-flags)
|
||||||
target_link_libraries(reborn-util PRIVATE utf8cpp)
|
target_link_libraries(reborn-util PRIVATE utf8cpp)
|
||||||
# Install
|
if(TARGET glfw)
|
||||||
install(TARGETS reborn-util DESTINATION "${MCPI_LIB_DIR}")
|
target_sources(reborn-util PRIVATE src/util/glfw.cpp)
|
||||||
# SDK
|
target_link_libraries(reborn-util PRIVATE glfw)
|
||||||
if(BUILD_ARM_COMPONENTS)
|
|
||||||
install(TARGETS reborn-util EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
|
||||||
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
|
|
||||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
|
|
||||||
endif()
|
endif()
|
||||||
|
setup_header_dirs(reborn-util
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||||
|
)
|
||||||
|
setup_library(reborn-util TRUE TRUE)
|
||||||
|
|
||||||
# Patch
|
# Patch
|
||||||
if(BUILD_ARM_COMPONENTS)
|
if(BUILD_ARM_COMPONENTS)
|
||||||
@ -39,11 +39,9 @@ if(BUILD_ARM_COMPONENTS)
|
|||||||
src/patch/instruction.cpp
|
src/patch/instruction.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(reborn-patch dl pthread reborn-util)
|
target_link_libraries(reborn-patch dl pthread reborn-util)
|
||||||
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
|
target_compile_definitions(reborn-patch PUBLIC REBORN_HAS_PATCH_CODE)
|
||||||
# Install
|
# Install
|
||||||
install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}")
|
setup_library(reborn-patch TRUE TRUE)
|
||||||
# SDK
|
|
||||||
install(TARGETS reborn-patch EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Fake LibPNG To Satisfy Symbol Versioning Requirement
|
# Fake LibPNG To Satisfy Symbol Versioning Requirement
|
||||||
@ -55,5 +53,5 @@ if(BUILD_ARM_COMPONENTS)
|
|||||||
)
|
)
|
||||||
target_link_options(fake-libpng PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/fake-libpng/empty.vers")
|
target_link_options(fake-libpng PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/fake-libpng/empty.vers")
|
||||||
# Install
|
# Install
|
||||||
install(TARGETS fake-libpng DESTINATION "${MCPI_LIB_DIR}")
|
setup_library(fake-libpng TRUE FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,14 +1,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#cmakedefine MCPI_IS_APPIMAGE_BUILD
|
// General
|
||||||
#cmakedefine MCPI_IS_FLATPAK_BUILD
|
#cmakedefine MCPI_VERSION "@MCPI_VERSION@"
|
||||||
#cmakedefine MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
#cmakedefine MCPI_AUTHOR "@MCPI_AUTHOR@"
|
||||||
#cmakedefine MCPI_APP_BASE_TITLE "@MCPI_APP_BASE_TITLE@"
|
#cmakedefine MCPI_ARCH "@MCPI_ARCH@"
|
||||||
|
|
||||||
|
// App Information
|
||||||
#cmakedefine MCPI_APP_TITLE "@MCPI_APP_TITLE@"
|
#cmakedefine MCPI_APP_TITLE "@MCPI_APP_TITLE@"
|
||||||
#cmakedefine MCPI_APP_ID "@MCPI_APP_ID@"
|
#cmakedefine MCPI_APP_ID "@MCPI_APP_ID@"
|
||||||
#cmakedefine MCPI_VERSION "@MCPI_VERSION@"
|
#cmakedefine MCPI_APP_NAME "@MCPI_APP_NAME@"
|
||||||
#cmakedefine MCPI_VARIANT_NAME "@MCPI_VARIANT_NAME@"
|
|
||||||
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"
|
// Extra Options
|
||||||
#cmakedefine MCPI_SKIN_SERVER "@MCPI_SKIN_SERVER@"
|
#cmakedefine MCPI_SKIN_SERVER "@MCPI_SKIN_SERVER@"
|
||||||
#cmakedefine MCPI_DISCORD_INVITE "@MCPI_DISCORD_INVITE@"
|
#cmakedefine MCPI_DISCORD_INVITE "@MCPI_DISCORD_INVITE@"
|
||||||
#cmakedefine MCPI_DOCUMENTATION "@MCPI_DOCUMENTATION@"
|
#cmakedefine MCPI_REPO "@MCPI_REPO@"
|
||||||
|
|
||||||
|
// Documentation
|
||||||
|
#cmakedefine MCPI_DOCS "@MCPI_DOCUMENTATION@"
|
||||||
|
#define MCPI_DOCS_CHANGELOG MCPI_DOCS "CHANGELOG.md"
|
||||||
|
#define MCPI_DOCS_GETTING_STARTED MCPI_DOCS "GETTING_STARTED.md"
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
#cmakedefine MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||||
|
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"
|
||||||
|
|
||||||
|
// AppImage
|
||||||
|
#cmakedefine MCPI_IS_APPIMAGE_BUILD
|
||||||
|
#cmakedefine MCPI_APPIMAGE_JSON_URL "@MCPI_APPIMAGE_JSON_URL@"
|
||||||
|
#cmakedefine MCPI_APPIMAGE_VERSION_PLACEHOLDER "@MCPI_APPIMAGE_VERSION_PLACEHOLDER@"
|
||||||
|
#cmakedefine MCPI_APPIMAGE_DOWNLOAD_URL "@MCPI_APPIMAGE_DOWNLOAD_URL@"
|
||||||
|
|
||||||
|
// Flatpak
|
||||||
|
#cmakedefine MCPI_IS_FLATPAK_BUILD
|
||||||
|
|
||||||
|
// Access Configuration At Runtime
|
||||||
|
const char *reborn_get_version();
|
||||||
|
bool reborn_is_headless();
|
||||||
|
bool reborn_is_server();
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ENV(name, ...) extern const char *const name##_ENV;
|
|
||||||
#include "env-list.h"
|
|
||||||
#undef ENV
|
|
||||||
|
|
||||||
int is_env_var_internal(const char *env);
|
|
||||||
void clear_internal_env_vars();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
26
libreborn/include/libreborn/env/env.h
vendored
Normal file
26
libreborn/include/libreborn/env/env.h
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define ENV(name, ...) constexpr const char *name##_ENV = #name;
|
||||||
|
#include "list.h"
|
||||||
|
#undef ENV
|
||||||
|
|
||||||
|
bool is_env_var_internal(const char *env);
|
||||||
|
void clear_internal_env_vars();
|
||||||
|
|
||||||
|
// Set Environmental Variable
|
||||||
|
void setenv_safe(const char *name, const char *value);
|
||||||
|
void set_and_print_env(const char *name, const char *value);
|
||||||
|
|
||||||
|
// Convert Variable To Value And Vice-Versa
|
||||||
|
struct Flags;
|
||||||
|
struct ServerList;
|
||||||
|
#define overload(type) \
|
||||||
|
std::string obj_to_env_value(const type &obj); \
|
||||||
|
void env_value_to_obj(type &out, const char *value)
|
||||||
|
overload(std::string);
|
||||||
|
overload(float);
|
||||||
|
overload(Flags);
|
||||||
|
overload(ServerList);
|
||||||
|
#undef overload
|
49
libreborn/include/libreborn/env/flags.h
vendored
Normal file
49
libreborn/include/libreborn/env/flags.h
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// Seperator
|
||||||
|
#define FLAG_SEPERATOR_CHAR '|'
|
||||||
|
|
||||||
|
// Flag
|
||||||
|
struct FlagNode {
|
||||||
|
private:
|
||||||
|
explicit FlagNode(const std::string &name_);
|
||||||
|
public:
|
||||||
|
FlagNode();
|
||||||
|
// Methods
|
||||||
|
void sort();
|
||||||
|
void for_each(const std::function<void(FlagNode &)> &callback);
|
||||||
|
void for_each_const(const std::function<void(const FlagNode &)> &callback) const;
|
||||||
|
void add_flag(std::string line);
|
||||||
|
FlagNode &add_category(const std::string &new_name);
|
||||||
|
// Properties
|
||||||
|
std::string name;
|
||||||
|
bool value;
|
||||||
|
std::vector<FlagNode> children;
|
||||||
|
int id;
|
||||||
|
// Internal
|
||||||
|
static bool handle_line_prefix(const std::string &prefix, std::string &line);
|
||||||
|
static std::unordered_map<std::string, bool> flag_prefixes;
|
||||||
|
static void reset_id_counter();
|
||||||
|
};
|
||||||
|
|
||||||
|
// All Flags
|
||||||
|
struct Flags {
|
||||||
|
explicit Flags(const std::string &data);
|
||||||
|
static Flags get();
|
||||||
|
// To/From Strings
|
||||||
|
std::string to_string() const;
|
||||||
|
void from_string(const std::string &str);
|
||||||
|
bool operator==(const Flags &other) const;
|
||||||
|
// To/From Cache
|
||||||
|
[[nodiscard]] std::unordered_map<std::string, bool> to_cache() const;
|
||||||
|
void from_cache(const std::unordered_map<std::string, bool> &cache);
|
||||||
|
// Print
|
||||||
|
void print() const;
|
||||||
|
// Properties
|
||||||
|
FlagNode root;
|
||||||
|
};
|
@ -2,6 +2,7 @@
|
|||||||
ENV(MCPI_FEATURE_FLAGS, "Client-Mode Feature Flags")
|
ENV(MCPI_FEATURE_FLAGS, "Client-Mode Feature Flags")
|
||||||
ENV(MCPI_USERNAME, "Player Username")
|
ENV(MCPI_USERNAME, "Player Username")
|
||||||
ENV(MCPI_RENDER_DISTANCE, "Render Distance")
|
ENV(MCPI_RENDER_DISTANCE, "Render Distance")
|
||||||
|
ENV(MCPI_SERVER_LIST, "Server List")
|
||||||
// Game Assets
|
// Game Assets
|
||||||
ENV(_MCPI_REBORN_ASSETS_PATH, "")
|
ENV(_MCPI_REBORN_ASSETS_PATH, "")
|
||||||
ENV(_MCPI_VANILLA_ASSETS_PATH, "")
|
ENV(_MCPI_VANILLA_ASSETS_PATH, "")
|
19
libreborn/include/libreborn/env/servers.h
vendored
Normal file
19
libreborn/include/libreborn/env/servers.h
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Parse servers.txt
|
||||||
|
struct ServerList {
|
||||||
|
// Type
|
||||||
|
typedef unsigned short port_t;
|
||||||
|
typedef std::pair<std::string, port_t> Entry;
|
||||||
|
// Load
|
||||||
|
static port_t parse_port(const std::string &s);
|
||||||
|
void load(const std::string &str);
|
||||||
|
// Save
|
||||||
|
[[nodiscard]] std::string to_string() const;
|
||||||
|
// Entries
|
||||||
|
std::vector<Entry> entries;
|
||||||
|
};
|
@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <errno.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)) void safe_execvpe(const char *const argv[], const char *const envp[]);
|
|
||||||
|
|
||||||
// Debug Tag
|
|
||||||
#define CHILD_PROCESS_TAG "(Child Process) "
|
|
||||||
|
|
||||||
// Run Command And Get Output
|
|
||||||
char *run_command(const char *const command[], int *exit_status, size_t *output_size);
|
|
||||||
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
||||||
|
|
||||||
// Get Exit Status String
|
|
||||||
void get_exit_status_string(int status, char **out);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <libreborn/config.h>
|
|
||||||
#include "env.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "exec.h"
|
|
||||||
#include "patch.h"
|
|
@ -1,11 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
|
#include <unistd.h>
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Log File
|
// Log File
|
||||||
int reborn_get_log_fd();
|
int reborn_get_log_fd();
|
||||||
@ -17,19 +14,18 @@ int reborn_get_debug_fd();
|
|||||||
// Logging
|
// Logging
|
||||||
#define INFO(format, ...) fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__)
|
#define INFO(format, ...) fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__)
|
||||||
#define WARN(format, ...) fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__)
|
#define WARN(format, ...) fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__)
|
||||||
#define RAW_DEBUG(tag, format, ...) dprintf(reborn_get_debug_fd(), "[DEBUG]: %s" format "\n", tag, ##__VA_ARGS__)
|
#define DEBUG(format, ...) dprintf(reborn_get_debug_fd(), "[DEBUG]: %s" format "\n", reborn_debug_tag, ##__VA_ARGS__)
|
||||||
#define DEBUG(format, ...) RAW_DEBUG(reborn_debug_tag, format, ##__VA_ARGS__)
|
#define ERR(format, ...) \
|
||||||
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
|
({ \
|
||||||
|
fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
_exit(EXIT_FAILURE); \
|
||||||
|
})
|
||||||
#define IMPOSSIBLE() ERR("This Should Never Be Called")
|
#define IMPOSSIBLE() ERR("This Should Never Be Called")
|
||||||
#define CONDITIONAL_ERR(is_error, ...) \
|
#define CONDITIONAL_ERR(is_error, ...) \
|
||||||
{ \
|
({ \
|
||||||
if ((is_error)) { \
|
if ((is_error)) { \
|
||||||
ERR(__VA_ARGS__); \
|
ERR(__VA_ARGS__); \
|
||||||
} else { \
|
} else { \
|
||||||
WARN(__VA_ARGS__); \
|
WARN(__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}
|
})
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
// Patching Functions
|
// Patching Functions
|
||||||
|
#ifndef REBORN_HAS_PATCH_CODE
|
||||||
#if defined(REBORN_HAS_PATCH_CODE) && defined(__cplusplus)
|
#error "Missing Patching Functions"
|
||||||
|
#endif
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
void reborn_init_patch();
|
void reborn_init_patch();
|
||||||
|
|
||||||
// Replace Call Located At start With A Call To target
|
// Replace Call Located At start With A Call To target
|
||||||
void overwrite_call(void *start, void *target, bool force_b_instruction = false);
|
void overwrite_call_manual(void *addr, void *new_target, bool force_b_instruction = false);
|
||||||
|
template <typename T>
|
||||||
|
void overwrite_call(void *addr, __attribute__((unused)) T *target_type, typename T::ptr_type new_target, const bool force_b_instruction = false) {
|
||||||
|
overwrite_call_manual(addr, (void *) new_target, force_b_instruction);
|
||||||
|
}
|
||||||
|
|
||||||
// Replace All Calls To Method start With target
|
// Replace All Calls To Method start With target
|
||||||
void *overwrite_calls_manual(void *start, void *target, bool allow_no_callsites = false);
|
void *overwrite_calls_manual(void *target, void *replacement, bool allow_no_callsites = false);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void overwrite_calls(T *target, typename T::overwrite_type replacement) {
|
void overwrite_calls(T *target, typename T::overwrite_type replacement) {
|
||||||
DEBUG("Overwriting Method: %s", target->name);
|
DEBUG("Overwriting Method: %s", target->name.c_str());
|
||||||
if (!target->overwrite(replacement)) {
|
if (!target->overwrite(replacement)) {
|
||||||
ERR("Unable To Overwrite Method!");
|
ERR("Unable To Overwrite Method! Use patch_vtable() Instead!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,30 +31,28 @@ void overwrite_calls(T *target, typename T::overwrite_type replacement) {
|
|||||||
void *reborn_thunk_enabler(void *target, void *thunk);
|
void *reborn_thunk_enabler(void *target, void *thunk);
|
||||||
|
|
||||||
// Replace All Calls To start With target Within [to, from)
|
// Replace All Calls To start With target Within [to, from)
|
||||||
void overwrite_calls_within_manual(void *from, void *to, void *start, void *target);
|
void overwrite_calls_within_manual(void *from, void *to, const void *target, void *replacement);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void _overwrite_calls_within(void *from, void *to, T *start, typename T::ptr_type target) {
|
void overwrite_calls_within(void *from, void *to, T *target, typename T::ptr_type replacement) {
|
||||||
overwrite_calls_within_manual(from, to, (void *) start->get(), (void *) target);
|
overwrite_calls_within_manual(from, to, (void *) target->get(), (void *) replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Target Address From BL Instruction
|
// Get Target Address From BL Instruction
|
||||||
void *extract_from_bl_instruction(unsigned char *from);
|
void *extract_from_bl_instruction(unsigned char *addr);
|
||||||
|
|
||||||
// Patch Instruction
|
// Patch Instruction
|
||||||
void patch(void *start, unsigned char patch[4]);
|
void patch(void *addr, unsigned char patch[4]);
|
||||||
|
|
||||||
// Patch 4 Bytes Of Data
|
// Patch 4 Bytes Of Data
|
||||||
void patch_address(void *start, void *target);
|
void patch_address(void *addr, void *target);
|
||||||
|
|
||||||
// Patch VTable Entry
|
// Patch VTable Entry
|
||||||
// This does not affect subclasses.
|
// IMPORTANT NOTE: This does not affect subclasses.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void patch_vtable(const T *start, typename T::ptr_type target) {
|
void patch_vtable(const T *target, typename T::ptr_type replacement) {
|
||||||
DEBUG("Patching VTable: %s", start->name);
|
DEBUG("Patching VTable: %s", target->name.c_str());
|
||||||
if (start->enabled) {
|
if (target->enabled) {
|
||||||
WARN("Use overwrite_calls() Instead!");
|
WARN("Use overwrite_calls() Instead!");
|
||||||
}
|
}
|
||||||
patch_address((void *) start->get_vtable_addr(), (void *) target);
|
patch_address((void *) target->get_vtable_addr(), (void *) replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Sanitize String
|
|
||||||
void sanitize_string(char *str, int max_length, int allow_newlines);
|
|
||||||
|
|
||||||
// CP437
|
|
||||||
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
|
|
@ -1,101 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
// Check Memory Allocation
|
|
||||||
#define ALLOC_CHECK(obj) \
|
|
||||||
{ \
|
|
||||||
if (obj == NULL) { \
|
|
||||||
ERR("Memory Allocation Failed"); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Align Number
|
|
||||||
#define ALIGN_UP(x, alignment) \
|
|
||||||
({ \
|
|
||||||
int _align_x = (x); \
|
|
||||||
int _align_alignment = (alignment); \
|
|
||||||
int _align_diff = _align_x % _align_alignment; \
|
|
||||||
if (_align_diff > 0) { \
|
|
||||||
_align_x += (_align_alignment - _align_diff); \
|
|
||||||
} \
|
|
||||||
_align_x; \
|
|
||||||
})
|
|
||||||
|
|
||||||
// Hook Library Function
|
|
||||||
#define EXTERNAL_FUNC(name, return_type, args) \
|
|
||||||
typedef return_type (*real_##name##_t)args; \
|
|
||||||
__attribute__((__unused__)) static real_##name##_t real_##name() { \
|
|
||||||
static real_##name##_t func = NULL; \
|
|
||||||
if (!func) { \
|
|
||||||
dlerror(); \
|
|
||||||
func = (real_##name##_t) dlsym(RTLD_NEXT, #name); \
|
|
||||||
if (!func) { \
|
|
||||||
ERR("Error Resolving Symbol: " #name ": %s", dlerror()); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return func; \
|
|
||||||
}
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define hooked_function_setup extern "C"
|
|
||||||
#else
|
|
||||||
#define hooked_function_setup
|
|
||||||
#endif
|
|
||||||
#define HOOK(name, return_type, args) \
|
|
||||||
EXTERNAL_FUNC(name, return_type, args) \
|
|
||||||
hooked_function_setup __attribute__((__used__)) return_type name args
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Safe Version Of pipe()
|
|
||||||
void safe_pipe2(int pipefd[2], int flags);
|
|
||||||
// Check If Two Percentages Are Different Enough To Be Logged
|
|
||||||
int is_progress_difference_significant(int32_t new_val, int32_t old_val);
|
|
||||||
|
|
||||||
// Lock File
|
|
||||||
int lock_file(const char *file);
|
|
||||||
void unlock_file(const char *file, int fd);
|
|
||||||
|
|
||||||
// Access Configuration At Runtime
|
|
||||||
const char *reborn_get_version();
|
|
||||||
int reborn_is_headless();
|
|
||||||
int reborn_is_server();
|
|
||||||
|
|
||||||
// Check $DISPLAY
|
|
||||||
void reborn_check_display();
|
|
||||||
|
|
||||||
// Get Home Subdirectory
|
|
||||||
const char *get_home_subdirectory_for_game_data();
|
|
||||||
|
|
||||||
// Make Sure Directory Exists
|
|
||||||
void ensure_directory(const char *path);
|
|
||||||
|
|
||||||
// Customize VTable
|
|
||||||
#define CUSTOM_VTABLE(name, parent) \
|
|
||||||
void _setup_##name##_vtable(parent##_vtable *vtable); \
|
|
||||||
static parent##_vtable *get_##name##_vtable() { \
|
|
||||||
static parent##_vtable *vtable = NULL; \
|
|
||||||
/* Allocate VTable */ \
|
|
||||||
if (vtable == NULL) { \
|
|
||||||
/* Init */ \
|
|
||||||
vtable = dup_vtable(parent##_vtable_base); \
|
|
||||||
ALLOC_CHECK(vtable); \
|
|
||||||
/* Setup */ \
|
|
||||||
_setup_##name##_vtable(vtable); \
|
|
||||||
} \
|
|
||||||
/* Return */ \
|
|
||||||
return vtable; \
|
|
||||||
} \
|
|
||||||
/* User-Defined Setup Code */ \
|
|
||||||
void _setup_##name##_vtable(parent##_vtable *vtable)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
31
libreborn/include/libreborn/util/exec.h
Normal file
31
libreborn/include/libreborn/util/exec.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// fork() With I/O
|
||||||
|
struct Process {
|
||||||
|
static constexpr int fd_count = 3;
|
||||||
|
Process(pid_t pid_, const std::array<int, fd_count> &fds_);
|
||||||
|
[[nodiscard]] int close() const;
|
||||||
|
const pid_t pid;
|
||||||
|
const std::array<int, fd_count> fds;
|
||||||
|
};
|
||||||
|
std::optional<Process> fork_with_stdio();
|
||||||
|
void poll_fds(const std::vector<int> &fds, const std::function<void(int, size_t, unsigned char *)> &on_data);
|
||||||
|
|
||||||
|
// Safe execvpe()
|
||||||
|
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
|
||||||
|
|
||||||
|
// Run Command And Get Output
|
||||||
|
std::vector<unsigned char> *run_command(const char *const command[], int *exit_status);
|
||||||
|
bool is_exit_status_success(int status);
|
||||||
|
|
||||||
|
// Get Exit Status String
|
||||||
|
std::string get_exit_status_string(int status);
|
||||||
|
|
||||||
|
// Open URL
|
||||||
|
void open_url(const std::string &url);
|
11
libreborn/include/libreborn/util/glfw.h
Normal file
11
libreborn/include/libreborn/util/glfw.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// GLFW Helpers
|
||||||
|
#ifndef GLFW_VERSION_MAJOR
|
||||||
|
#error "Missing GLFW"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void init_glfw();
|
||||||
|
GLFWwindow *create_glfw_window(const char *title, int width, int height);
|
||||||
|
void cleanup_glfw(GLFWwindow *window);
|
||||||
|
void get_glfw_scale(GLFWwindow *window, float *x_scale, float *y_scale);
|
17
libreborn/include/libreborn/util/io.h
Normal file
17
libreborn/include/libreborn/util/io.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
// Safe Version Of pipe()
|
||||||
|
struct Pipe {
|
||||||
|
Pipe();
|
||||||
|
const int read;
|
||||||
|
const int write;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lock File
|
||||||
|
int lock_file(const char *file);
|
||||||
|
void unlock_file(const char *file, int fd);
|
||||||
|
|
||||||
|
// Safe write()
|
||||||
|
void safe_write(int fd, const void *buf, size_t size);
|
14
libreborn/include/libreborn/util/string.h
Normal file
14
libreborn/include/libreborn/util/string.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// Sanitize String
|
||||||
|
void sanitize_string(std::string &str, int max_length, bool allow_newlines);
|
||||||
|
|
||||||
|
// CP437
|
||||||
|
std::string to_cp437(const std::string &input);
|
||||||
|
std::string from_cp437(const std::string &input);
|
||||||
|
|
||||||
|
// Format Time
|
||||||
|
std::string format_time(const char *fmt);
|
||||||
|
std::string format_time(const char *fmt, int time);
|
49
libreborn/include/libreborn/util/util.h
Normal file
49
libreborn/include/libreborn/util/util.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../log.h"
|
||||||
|
|
||||||
|
// Align Number
|
||||||
|
int align_up(int x, int alignment);
|
||||||
|
|
||||||
|
// Hook Library Function
|
||||||
|
#define HOOK(name, return_type, args) \
|
||||||
|
typedef return_type (*real_##name##_t)args; \
|
||||||
|
__attribute__((__unused__)) static real_##name##_t real_##name() { \
|
||||||
|
static real_##name##_t func = NULL; \
|
||||||
|
if (!func) { \
|
||||||
|
dlerror(); \
|
||||||
|
func = (real_##name##_t) dlsym(RTLD_NEXT, #name); \
|
||||||
|
if (!func) { \
|
||||||
|
ERR("Error Resolving Symbol: " #name ": %s", dlerror()); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return func; \
|
||||||
|
} \
|
||||||
|
extern "C" __attribute__((__used__)) return_type name args
|
||||||
|
|
||||||
|
// Check If Two Percentages Are Different Enough To Be Logged
|
||||||
|
bool is_progress_difference_significant(int32_t new_val, int32_t old_val);
|
||||||
|
|
||||||
|
// Check $DISPLAY
|
||||||
|
void reborn_check_display();
|
||||||
|
|
||||||
|
// Get Home Subdirectory
|
||||||
|
const char *get_home_subdirectory_for_game_data();
|
||||||
|
|
||||||
|
// Make Sure Directory Exists
|
||||||
|
void ensure_directory(const char *path);
|
||||||
|
|
||||||
|
// embed_resource()
|
||||||
|
#define EMBEDDED_RESOURCE(name) \
|
||||||
|
extern unsigned char name[]; \
|
||||||
|
extern size_t name##_len
|
||||||
|
|
||||||
|
// Profile Directory
|
||||||
|
std::string home_get();
|
||||||
|
|
||||||
|
// Default MCPI Port
|
||||||
|
// This Macro DOES NOT Control MCPI
|
||||||
|
#define DEFAULT_MULTIPLAYER_PORT 19132
|
@ -1,6 +1,8 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
#include <libreborn/libreborn.h>
|
#include <libreborn/patch.h>
|
||||||
#include "patch-internal.h"
|
#include "patch-internal.h"
|
||||||
|
|
||||||
// Limit Amount Of overwrite_calls() Calls
|
// Limit Amount Of overwrite_calls() Calls
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user