The Great Unification
Some checks failed
CI / Build (AMD64) (push) Successful in 17m8s
CI / Build (ARM64) (push) Successful in 17m45s
CI / Build (ARMHF) (push) Successful in 11m24s
CI / Test (ARM64, Client) (push) Failing after 2m9s
CI / Test (AMD64, Client) (push) Failing after 2m44s
CI / Test (AMD64, Server) (push) Successful in 3m53s
CI / Test (ARM64, Server) (push) Successful in 2m17s
CI / Build Example Mods (push) Failing after 2m31s
CI / Test (ARMHF, Client) (push) Failing after 1m58s
CI / Test (ARMHF, Server) (push) Failing after 1m55s
CI / Release (push) Has been skipped
Some checks failed
CI / Build (AMD64) (push) Successful in 17m8s
CI / Build (ARM64) (push) Successful in 17m45s
CI / Build (ARMHF) (push) Successful in 11m24s
CI / Test (ARM64, Client) (push) Failing after 2m9s
CI / Test (AMD64, Client) (push) Failing after 2m44s
CI / Test (AMD64, Server) (push) Successful in 3m53s
CI / Test (ARM64, Server) (push) Successful in 2m17s
CI / Build Example Mods (push) Failing after 2m31s
CI / Test (ARMHF, Client) (push) Failing after 1m58s
CI / Test (ARMHF, Server) (push) Failing after 1m55s
CI / Release (push) Has been skipped
This commit is contained in:
parent
460cd38ddf
commit
38d7dda1a7
@ -14,9 +14,6 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mode:
|
||||
- Client
|
||||
- Server
|
||||
arch:
|
||||
- AMD64
|
||||
- ARM64
|
||||
@ -31,40 +28,19 @@ jobs:
|
||||
submodules: true
|
||||
# Dependencies
|
||||
- name: Install Dependencies
|
||||
run: ./scripts/install-dependencies.sh ${{ matrix.arch }}
|
||||
run: ./scripts/install-dependencies.sh build ${{ matrix.arch }}
|
||||
# Build
|
||||
- name: Build
|
||||
run: ./scripts/build.mjs appimage ${{ matrix.mode }} ${{ matrix.arch }}
|
||||
run: ./scripts/build.mjs appimage ${{ matrix.arch }}
|
||||
- name: Upload Artifacts
|
||||
uses: christopherhx/gitea-upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.mode }} (${{ matrix.arch }})
|
||||
name: ${{ matrix.arch }}
|
||||
path: ./out/*.AppImage*
|
||||
if-no-files-found: error
|
||||
# Test Project
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mode:
|
||||
- Client
|
||||
- Server
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
container: node:lts-bullseye
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
# Dependencies
|
||||
- name: Install Dependencies
|
||||
run: ./scripts/install-dependencies.sh
|
||||
# Test
|
||||
- name: Test
|
||||
run: ./scripts/test.sh ${{ matrix.mode }}
|
||||
# Test Project On ARM
|
||||
rpi-test:
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -72,10 +48,11 @@ jobs:
|
||||
- Client
|
||||
- Server
|
||||
arch:
|
||||
- AMD64
|
||||
- ARM64
|
||||
- ARMHF
|
||||
name: Raspberry Pi Test
|
||||
runs-on: raspberry-pi
|
||||
name: Test
|
||||
runs-on: ${{ startsWith(matrix.arch, 'ARM') && 'raspberry-pi' || 'ubuntu-latest' }}
|
||||
container: node:lts-bullseye
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
@ -84,12 +61,19 @@ jobs:
|
||||
submodules: true
|
||||
# Dependencies
|
||||
- name: Install Dependencies
|
||||
run: ./scripts/install-dependencies.sh ${{ matrix.arch }}
|
||||
run: ./scripts/install-dependencies.sh test ${{ matrix.arch }}
|
||||
# Download Artifact
|
||||
- name: Download Artifact
|
||||
uses: christopherhx/gitea-download-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.arch }}
|
||||
path: out
|
||||
# Test
|
||||
- name: Test
|
||||
run: ./scripts/test.sh ${{ matrix.mode }}
|
||||
run: ./scripts/test.sh ${{ matrix.mode }} ${{ matrix.arch }}
|
||||
# Example Mods
|
||||
example-mods:
|
||||
needs: build
|
||||
name: Build Example Mods
|
||||
runs-on: ubuntu-latest
|
||||
container: node:lts-bullseye
|
||||
@ -100,16 +84,18 @@ jobs:
|
||||
submodules: true
|
||||
# Dependencies
|
||||
- name: Install Dependencies
|
||||
run: ./scripts/install-dependencies.sh
|
||||
- name: Install ARM Toolchain
|
||||
run: apt-get install --no-install-recommends -y g++-arm-linux-gnueabihf gcc-arm-linux-gnueabihf
|
||||
# Build SDK
|
||||
- name: Build SDK
|
||||
run: ./scripts/install-dependencies.sh example_mods amd64
|
||||
# SDK
|
||||
- name: Download SDK
|
||||
uses: christopherhx/gitea-download-artifact@v4
|
||||
with:
|
||||
name: AMD64
|
||||
path: out
|
||||
- name: Extract SDK
|
||||
run: |
|
||||
./scripts/build.mjs none client host
|
||||
export _MCPI_SKIP_ROOT_CHECK=1
|
||||
export DISPLAY=
|
||||
./out/client/host/usr/bin/minecraft-pi-reborn-client --copy-sdk
|
||||
./scripts/fix-appimage-for-docker.sh ./out/*.AppImage
|
||||
chmod +x ./out/*.AppImage
|
||||
./out/*.AppImage --copy-sdk
|
||||
# Build Example Mods
|
||||
- name: Build Example Mods
|
||||
run: ./example-mods/build.sh
|
||||
@ -122,7 +108,10 @@ jobs:
|
||||
# Create Release
|
||||
release:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: build
|
||||
needs:
|
||||
- build
|
||||
- test
|
||||
- example-mods
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
container: node:lts-bullseye
|
||||
|
@ -6,10 +6,6 @@ if(MCPI_IS_APPIMAGE_BUILD AND MCPI_IS_FLATPAK_BUILD)
|
||||
message(FATAL_ERROR "Invalid Build Configuration")
|
||||
endif()
|
||||
|
||||
# Server/Headless Builds
|
||||
mcpi_option(SERVER_MODE "Server Mode" BOOL FALSE)
|
||||
mcpi_option(HEADLESS_MODE "Headless Mode" BOOL "${MCPI_SERVER_MODE}")
|
||||
|
||||
# Prebuilt ARMHF Toolchain
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
set(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN FALSE)
|
||||
@ -22,16 +18,12 @@ if(BUILD_NATIVE_COMPONENTS)
|
||||
endif()
|
||||
|
||||
# Media Layer
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE TRUE)
|
||||
endif()
|
||||
mcpi_option(USE_MEDIA_LAYER_TRAMPOLINE "Whether To Enable The Media Layer Trampoline" BOOL "${DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE}")
|
||||
mcpi_option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" BOOL TRUE)
|
||||
else()
|
||||
set(MCPI_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING)
|
||||
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE TRUE)
|
||||
endif()
|
||||
mcpi_option(USE_MEDIA_LAYER_TRAMPOLINE "Whether To Enable The Media Layer Trampoline" BOOL "${DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE}")
|
||||
mcpi_option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" BOOL TRUE)
|
||||
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
|
||||
set(BUILD_MEDIA_LAYER_CORE "${BUILD_NATIVE_COMPONENTS}")
|
||||
else()
|
||||
@ -40,30 +32,12 @@ endif()
|
||||
|
||||
# Specify Variant Name
|
||||
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
|
||||
if(MCPI_SERVER_MODE)
|
||||
string(APPEND MCPI_VARIANT_NAME "-server")
|
||||
else()
|
||||
string(APPEND MCPI_VARIANT_NAME "-client")
|
||||
endif()
|
||||
|
||||
# App ID
|
||||
set(DEFAULT_APP_ID "com.thebrokenrail.MCPIReborn")
|
||||
if(MCPI_SERVER_MODE)
|
||||
string(APPEND DEFAULT_APP_ID "Server")
|
||||
else()
|
||||
string(APPEND DEFAULT_APP_ID "Client")
|
||||
endif()
|
||||
mcpi_option(APP_ID "App ID" STRING "${DEFAULT_APP_ID}")
|
||||
mcpi_option(APP_ID "App ID" STRING "com.thebrokenrail.MCPIReborn")
|
||||
|
||||
# App Title
|
||||
mcpi_option(APP_BASE_TITLE "Base App Title" STRING "Minecraft: Pi Edition: Reborn")
|
||||
set(DEFAULT_APP_TITLE "${MCPI_APP_BASE_TITLE}")
|
||||
if(MCPI_SERVER_MODE)
|
||||
string(APPEND DEFAULT_APP_TITLE " (Server)")
|
||||
else()
|
||||
string(APPEND DEFAULT_APP_TITLE " (Client)")
|
||||
endif()
|
||||
mcpi_option(APP_TITLE "App Title" STRING "${DEFAULT_APP_TITLE}")
|
||||
mcpi_option(APP_TITLE "App Title" STRING "Minecraft: Pi Edition: Reborn")
|
||||
|
||||
# Skin Server
|
||||
mcpi_option(SKIN_SERVER "Skin Server" STRING "https://raw.githubusercontent.com/MCPI-Revival/Skins/data")
|
||||
|
10
dependencies/CMakeLists.txt
vendored
10
dependencies/CMakeLists.txt
vendored
@ -1,7 +1,7 @@
|
||||
project(dependencies)
|
||||
|
||||
# stb_image
|
||||
if(BUILD_ARM_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_subdirectory(stb_image)
|
||||
endif()
|
||||
# Minecraft: Pi Edition
|
||||
@ -9,21 +9,21 @@ if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
|
||||
add_subdirectory(minecraft-pi)
|
||||
endif()
|
||||
# Zenity (Minimal Build)
|
||||
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE)
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
add_subdirectory(zenity)
|
||||
endif()
|
||||
# LIEF
|
||||
if(BUILD_NATIVE_COMPONENTS OR (BUILD_MEDIA_LAYER_CORE AND NOT MCPI_HEADLESS_MODE))
|
||||
if(BUILD_NATIVE_COMPONENTS OR BUILD_MEDIA_LAYER_CORE)
|
||||
add_subdirectory(LIEF)
|
||||
endif()
|
||||
# Extra Runtime
|
||||
add_subdirectory(runtime)
|
||||
# GLFW
|
||||
if(BUILD_MEDIA_LAYER_CORE AND NOT MCPI_HEADLESS_MODE)
|
||||
if(BUILD_MEDIA_LAYER_CORE)
|
||||
add_subdirectory(glfw)
|
||||
endif()
|
||||
# GLES Compatibility Layer
|
||||
if(BUILD_MEDIA_LAYER_CORE AND NOT MCPI_HEADLESS_MODE AND MCPI_USE_GLES1_COMPATIBILITY_LAYER)
|
||||
if(BUILD_MEDIA_LAYER_CORE AND MCPI_USE_GLES1_COMPATIBILITY_LAYER)
|
||||
add_subdirectory(gles-compatibility-layer)
|
||||
endif()
|
||||
# UTF8-CPP
|
||||
|
8
dependencies/minecraft-pi/CMakeLists.txt
vendored
8
dependencies/minecraft-pi/CMakeLists.txt
vendored
@ -17,13 +17,5 @@ install(
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/game"
|
||||
USE_SOURCE_PERMISSIONS
|
||||
REGEX "api" EXCLUDE
|
||||
REGEX "data" EXCLUDE
|
||||
)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
install(
|
||||
DIRECTORY "${minecraft-pi_SOURCE_DIR}/data/"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/game/data"
|
||||
USE_SOURCE_PERMISSIONS
|
||||
)
|
||||
endif()
|
||||
install_symlink("game/minecraft-pi" "${MCPI_INSTALL_DIR}/minecraft-pi")
|
||||
|
2
dependencies/runtime/src
vendored
2
dependencies/runtime/src
vendored
@ -1 +1 @@
|
||||
Subproject commit 790e7918b1d63102b7a7f39dc1db006b2a5abf48
|
||||
Subproject commit aa874884072a700750956e241c7a1ce91dbfa74c
|
@ -32,6 +32,8 @@
|
||||
* Fix Furnace Visual Bug When Using Lava Bucket As Fuel
|
||||
* Add Splash Text To Start Screen
|
||||
* `overwrite_calls` Now Scans VTables
|
||||
* Unify Server/Client Builds
|
||||
* Use `|` For Separator In `servers.txt` Instead Of `:`
|
||||
|
||||
**2.5.3**
|
||||
* Add `Replace Block Highlight With Outline` Feature Flag (Enabled By Default)
|
||||
|
@ -4,11 +4,11 @@ The dedicated server is a version of Minecraft: Pi Edition modified to run in a
|
||||
This server is also compatible with MCPE Alpha v0.6.1[^1].
|
||||
|
||||
## Setup
|
||||
To use, install and run the `minecraft-pi-reborn-server` AppImage. It will generate the world and `server.properties` in the current directory.
|
||||
To use, run the normal AppImage with the `--server` argument. It will generate the world and `server.properties` in the current directory.
|
||||
|
||||
## Server Limitations
|
||||
* Player data is not saved because of limitations with MCPE LAN worlds
|
||||
* An easy workaround is to place your inventory in a chest before logging off
|
||||
* Survival Mode servers are incompatible with unmodded MCPI
|
||||
* Survival Mode servers are incompatible with un-modded MCPI
|
||||
|
||||
[^1]: The exception to this is buckets, those will crash MCPE players.
|
||||
[^1]: The exception to this is buckets and other modded items, those will crash MCPE players.
|
||||
|
@ -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:
|
||||
```sh
|
||||
sudo apt install -y libfuse2 libgtk-3-0 libopenal1
|
||||
sudo apt install -y libfuse2 libgtk-3-0 libopenal1 libglib2.0-0
|
||||
```
|
||||
</details>
|
||||
|
||||
|
@ -1,19 +1,11 @@
|
||||
# Example Mods
|
||||
This is an example of a mod that can be built using the modding SDK.
|
||||
These are example mods that can be built using the modding SDK.
|
||||
|
||||
* **Expanded Creative Mod**: This specific mod adds even more items and blocks to the Creative Inventory. It was originally by [@Bigjango13](https://github.com/bigjango13).
|
||||
* **Chat Commands Mod**: This specific mod makes an chat message starting with a ``/`` handled by the MCPI API.
|
||||
* **Chat Commands Mod**: This specific mod makes a chat message starting with `/` handled by the MCPI API.
|
||||
* **Recipes Mod**: This specific mod demos custom recipes.
|
||||
|
||||
## The SDK
|
||||
The modding SDK is a collection of exported CMake targets that allows anyone to create their own MCPI mod!
|
||||
|
||||
The SDK is copied to ``~/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake`` whenever MCPI-Reborn is started.
|
||||
|
||||
## How do I use this?
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cp libexpanded-creative.so ~/.minecraft-pi/mods
|
||||
```
|
||||
The SDK is copied to `~/.minecraft-pi/sdk` whenever MCPI-Reborn is started.
|
||||
|
@ -10,7 +10,7 @@ set(CMAKE_SYSTEM_PROCESSOR "arm")
|
||||
project(chat-commands)
|
||||
|
||||
# Include SDK
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn/sdk/sdk.cmake")
|
||||
|
||||
# Build
|
||||
add_library(chat-commands SHARED chat-commands.cpp)
|
||||
|
@ -10,7 +10,7 @@ set(CMAKE_SYSTEM_PROCESSOR "arm")
|
||||
project(expanded-creative)
|
||||
|
||||
# Include SDK
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn/sdk/sdk.cmake")
|
||||
|
||||
# Build
|
||||
add_library(expanded-creative SHARED expanded-creative.cpp)
|
||||
|
@ -10,7 +10,7 @@ set(CMAKE_SYSTEM_PROCESSOR "arm")
|
||||
project(recipes)
|
||||
|
||||
# Include SDK
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
|
||||
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn/sdk/sdk.cmake")
|
||||
|
||||
# Build
|
||||
add_library(recipes SHARED recipes.cpp)
|
||||
|
@ -1,21 +1,17 @@
|
||||
project(images)
|
||||
|
||||
# Title Background
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
install(
|
||||
FILES "background.png"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui"
|
||||
RENAME "titleBG.png"
|
||||
)
|
||||
endif()
|
||||
install(
|
||||
FILES "background.png"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui"
|
||||
RENAME "titleBG.png"
|
||||
)
|
||||
|
||||
# Chest Model
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
install(
|
||||
FILES "chest.png"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/item"
|
||||
)
|
||||
endif()
|
||||
install(
|
||||
FILES "chest.png"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}/data/images/item"
|
||||
)
|
||||
|
||||
# Icon
|
||||
install(
|
||||
|
@ -10,15 +10,11 @@ add_executable(launcher
|
||||
src/mods.cpp
|
||||
src/options/parser.cpp
|
||||
src/main.cpp
|
||||
src/client/configuration.cpp
|
||||
src/client/cache.cpp
|
||||
src/client/available-feature-flags # Show In IDE
|
||||
)
|
||||
if(NOT MCPI_SERVER_MODE)
|
||||
embed_resource(launcher src/client/available-feature-flags)
|
||||
target_sources(launcher PRIVATE
|
||||
src/client/configuration.cpp
|
||||
src/client/cache.cpp
|
||||
src/client/available-feature-flags # Show In IDE
|
||||
)
|
||||
endif()
|
||||
embed_resource(launcher src/client/available-feature-flags)
|
||||
target_link_libraries(launcher reborn-util LIB_LIEF trampoline-headers)
|
||||
# RPath
|
||||
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
||||
@ -38,18 +34,10 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"Type=Application\n"
|
||||
"Categories=Game;\n"
|
||||
)
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"Terminal=true\n"
|
||||
"NoDisplay=true\n"
|
||||
)
|
||||
else()
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"Terminal=false\n"
|
||||
"StartupNotify=false\n"
|
||||
"StartupWMClass=${MCPI_APP_ID}\n"
|
||||
)
|
||||
endif()
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
"Terminal=true\n"
|
||||
"NoDisplay=true\n"
|
||||
)
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
|
||||
DESTINATION "${MCPI_SHARE_DIR}/applications"
|
||||
@ -100,17 +88,11 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
|
||||
" <releases>\n"
|
||||
" <release version=\"${MCPI_VERSION}\" date=\"${MCPI_VERSION_DATE}\"></release>\n"
|
||||
" </releases>\n"
|
||||
)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
|
||||
" <screenshots>\n"
|
||||
" <screenshot type=\"default\">\n"
|
||||
" <image>https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn/raw/branch/master/images/start.png</image>\n"
|
||||
" </screenshot>\n"
|
||||
" </screenshots>\n"
|
||||
)
|
||||
endif()
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
|
||||
" <screenshots>\n"
|
||||
" <screenshot type=\"default\">\n"
|
||||
" <image>https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn/raw/branch/master/images/start.png</image>\n"
|
||||
" </screenshot>\n"
|
||||
" </screenshots>\n"
|
||||
"</component>\n"
|
||||
)
|
||||
install(
|
||||
|
@ -17,7 +17,7 @@ static std::string get_cache_path() {
|
||||
if (home == nullptr) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
return std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA "/.launcher-cache";
|
||||
return std::string(home) + get_home_subdirectory_for_game_data() + "/.launcher-cache";
|
||||
}
|
||||
|
||||
// Load
|
||||
@ -165,7 +165,8 @@ void wipe_cache() {
|
||||
INFO("Wiping Launcher Cache...");
|
||||
|
||||
// Unlink File
|
||||
if (unlink(get_cache_path().c_str()) != 0) {
|
||||
const int ret = unlink(get_cache_path().c_str());
|
||||
if (ret != 0 && errno != ENOENT) {
|
||||
WARN("Failure While Wiping Cache: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ static void run_command_and_set_env(const char *env_name, const char *command[])
|
||||
// Use Zenity To Set Environmental Variable
|
||||
#define DIALOG_TITLE "Launcher"
|
||||
static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
|
||||
reborn_check_display();
|
||||
// Create Full Command
|
||||
std::vector<std::string> full_command;
|
||||
full_command.push_back("zenity");
|
||||
@ -146,31 +147,16 @@ void handle_non_launch_client_only_commands(const options_t &options) {
|
||||
});
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Check Environment
|
||||
void check_environment_client() {
|
||||
// Don't Run As Root
|
||||
if (getenv("_MCPI_SKIP_ROOT_CHECK") == nullptr && (getuid() == 0 || geteuid() == 0)) {
|
||||
ERR("Don't Run As Root");
|
||||
// Wipe Cache If Needed
|
||||
if (options.wipe_cache) {
|
||||
wipe_cache();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Check For Display
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (getenv("DISPLAY") == nullptr && getenv("WAYLAND_DISPLAY") == nullptr) {
|
||||
ERR("No display attached! Make sure $DISPLAY or $WAYLAND_DISPLAY is set.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Configure Client Options
|
||||
#define LIST_DIALOG_SIZE "400"
|
||||
void configure_client(const options_t &options) {
|
||||
// Wipe Cache If Needed
|
||||
if (options.wipe_cache) {
|
||||
wipe_cache();
|
||||
}
|
||||
|
||||
// Load Cache
|
||||
launcher_cache cache = options.no_cache ? empty_cache : load_cache();
|
||||
|
||||
|
@ -16,8 +16,5 @@ void load_available_feature_flags(const std::function<void(std::string)> &callba
|
||||
// Handle Non-Launch Commands
|
||||
void handle_non_launch_client_only_commands(const options_t &options);
|
||||
|
||||
// Check Environment
|
||||
void check_environment_client();
|
||||
|
||||
// Configure Client Options
|
||||
void configure_client(const options_t &options);
|
@ -15,7 +15,6 @@
|
||||
#include "crash-report.h"
|
||||
|
||||
// Show Crash Report Dialog
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#define DIALOG_TITLE "Crash Report"
|
||||
#define CRASH_REPORT_DIALOG_WIDTH "640"
|
||||
#define CRASH_REPORT_DIALOG_HEIGHT "480"
|
||||
@ -35,7 +34,7 @@ static void show_report(const char *log_filename) {
|
||||
"--width", CRASH_REPORT_DIALOG_WIDTH,
|
||||
"--height", CRASH_REPORT_DIALOG_HEIGHT,
|
||||
"--text-info",
|
||||
"--text", MCPI_APP_BASE_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"" MCPI_DISCORD_INVITE "\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_BASE_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
|
||||
"--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",
|
||||
@ -46,7 +45,6 @@ static void show_report(const char *log_filename) {
|
||||
safe_execvpe(command, (const char *const *) environ);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exit Handler
|
||||
static void exit_handler(__attribute__((unused)) int signal) {
|
||||
@ -248,11 +246,9 @@ void setup_crash_report() {
|
||||
unsetenv(MCPI_LOG_ENV);
|
||||
|
||||
// Show Crash Log
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (is_crash) {
|
||||
if (is_crash && !reborn_is_headless()) {
|
||||
show_report(log_filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exit
|
||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
||||
|
@ -6,9 +6,7 @@
|
||||
#include "options/parser.h"
|
||||
#include "crash-report.h"
|
||||
#include "util.h"
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#include "client/configuration.h"
|
||||
#endif
|
||||
|
||||
// Bind Options To Environmental Variable
|
||||
static void bind_to_env(const char *env, const bool value) {
|
||||
@ -19,16 +17,14 @@ static void bind_to_env(const char *env, const bool value) {
|
||||
}
|
||||
static void setup_environment(const options_t &options) {
|
||||
// Passthrough Options To Game
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
bind_to_env(MCPI_SERVER_MODE_ENV, options.server_mode);
|
||||
bind_to_env("_MCPI_BENCHMARK", options.benchmark);
|
||||
#else
|
||||
bind_to_env("_MCPI_ONLY_GENERATE", options.only_generate);
|
||||
#endif
|
||||
bind_to_env(MCPI_FORCE_HEADLESS_ENV, options.force_headless);
|
||||
bind_to_env(MCPI_FORCE_NON_HEADLESS_ENV, options.force_non_headless);
|
||||
|
||||
// GTK Dark Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
set_and_print_env("GTK_THEME", "Adwaita:dark");
|
||||
#endif
|
||||
|
||||
// Configure PATH
|
||||
{
|
||||
@ -72,9 +68,6 @@ static void start_game(const options_t &options) {
|
||||
// Disable stdout Buffering
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
// Environemntal Variable Options
|
||||
setup_environment(options);
|
||||
|
||||
// Setup Crash Reporting
|
||||
if (!options.disable_crash_report) {
|
||||
setup_log_file();
|
||||
@ -92,35 +85,35 @@ static void start_game(const options_t &options) {
|
||||
sigaction(SIGTERM, &act_sigterm, nullptr);
|
||||
|
||||
// Setup Home
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
// Ensure $HOME
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
ERR("$HOME Isn't Set");
|
||||
}
|
||||
// Create If Needed
|
||||
{
|
||||
std::string minecraft_folder = std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA;
|
||||
struct stat tmp_stat = {};
|
||||
bool exists = stat(minecraft_folder.c_str(), &tmp_stat) != 0 ? false : S_ISDIR(tmp_stat.st_mode);
|
||||
if (!exists) {
|
||||
// Doesn't Exist
|
||||
if (mkdir(minecraft_folder.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Create Data Directory: %s", strerror(errno));
|
||||
if (!reborn_is_server()) {
|
||||
// Ensure $HOME
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
ERR("$HOME Is Not Set");
|
||||
}
|
||||
// Create If Needed
|
||||
{
|
||||
std::string minecraft_folder = std::string(home) + get_home_subdirectory_for_game_data();
|
||||
struct stat tmp_stat = {};
|
||||
bool exists = stat(minecraft_folder.c_str(), &tmp_stat) != 0 ? false : S_ISDIR(tmp_stat.st_mode);
|
||||
if (!exists) {
|
||||
// Doesn't Exist
|
||||
if (mkdir(minecraft_folder.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
||||
ERR("Unable To Create Data Directory: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Set Home To Current Directory, So World Data Is Stored There
|
||||
char *launch_directory = getcwd(nullptr, 0);
|
||||
set_and_print_env("HOME", launch_directory);
|
||||
free(launch_directory);
|
||||
}
|
||||
#else
|
||||
// Set Home To Current Directory, So World Data Is Stored There
|
||||
char *launch_directory = getcwd(NULL, 0);
|
||||
set_and_print_env("HOME", launch_directory);
|
||||
free(launch_directory);
|
||||
#endif
|
||||
|
||||
// Configure Client Options
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
configure_client(options);
|
||||
#endif
|
||||
if (!reborn_is_server()) {
|
||||
configure_client(options);
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
bootstrap();
|
||||
@ -138,17 +131,12 @@ int main(int argc, char *argv[]) {
|
||||
unsetenv(MCPI_LOG_ENV);
|
||||
bind_to_env(MCPI_DEBUG_ENV, options.debug);
|
||||
|
||||
// Setup Environment
|
||||
setup_environment(options);
|
||||
|
||||
// Handle Non-Launch Commands (Copy SDK, Print Feature Flags, Etc)
|
||||
handle_non_launch_commands(options);
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
handle_non_launch_client_only_commands(options);
|
||||
#endif
|
||||
|
||||
// Check Environment
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
// Code After This Can Safely Open A Window
|
||||
check_environment_client();
|
||||
#endif
|
||||
|
||||
// Start The Game
|
||||
start_game(options);
|
||||
|
@ -60,7 +60,7 @@ std::string bootstrap_mods(const std::string &binary_directory) {
|
||||
// ~/.minecraft-pi/mods
|
||||
{
|
||||
// Get Mods Folder
|
||||
std::string mods_folder = std::string(getenv("HOME")) + HOME_SUBDIRECTORY_FOR_GAME_DATA SUBDIRECTORY_FOR_MODS;
|
||||
std::string mods_folder = std::string(getenv("HOME")) + get_home_subdirectory_for_game_data() + SUBDIRECTORY_FOR_MODS;
|
||||
// Load Mods From ./mods
|
||||
load(preload, mods_folder);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
OPTION(debug, "debug", 'd', "Enable Debug Logging (" MCPI_DEBUG_ENV ")")
|
||||
OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit")
|
||||
OPTION(disable_crash_report, "disable-crash-report", -1, "Disable Crash Report Dialog")
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
OPTION(use_default, "default", -3, "Skip Configuration Dialogs")
|
||||
OPTION(no_cache, "no-cache", -4, "Disable Configuration Cache")
|
||||
OPTION(wipe_cache, "wipe-cache", -5, "Wipe Cached Configuration")
|
||||
OPTION(print_available_feature_flags, "print-available-feature-flags", -6, "Print Available Feature Flags")
|
||||
OPTION(benchmark, "benchmark", -7, "Run Benchmark")
|
||||
#else
|
||||
OPTION(only_generate, "only-generate", -8, "Generate World And Exit")
|
||||
#endif
|
||||
OPTION(use_default, "default", -3, "Skip Client-Mode Configuration Dialogs")
|
||||
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(print_available_feature_flags, "print-available-feature-flags", -6, "Print Available Client-Mode Feature Flags")
|
||||
OPTION(benchmark, "benchmark", -7, "Run Client-Mode Benchmark")
|
||||
OPTION(only_generate, "only-generate", -8, "Generate World And Exit (Server-Mode Only)")
|
||||
OPTION(force_headless, "force-headless", -9, "Force Disable Game Rendering")
|
||||
OPTION(force_non_headless, "force-non-headless", -10, "Force Enable Game Rendering")
|
||||
OPTION(server_mode, "server", -11, "Run In Server-Mode")
|
@ -14,7 +14,7 @@
|
||||
}
|
||||
|
||||
// Copy SDK Into ~/.minecraft-pi
|
||||
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
|
||||
#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;
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#cmakedefine MCPI_SERVER_MODE
|
||||
#cmakedefine MCPI_HEADLESS_MODE
|
||||
#cmakedefine MCPI_IS_APPIMAGE_BUILD
|
||||
#cmakedefine MCPI_IS_FLATPAK_BUILD
|
||||
#cmakedefine MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Minecraft Pi Game Data Root
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
// Store Game Data In "~/.minecraft-pi" Instead Of "~/.minecraft" To Avoid Conflicts
|
||||
#define HOME_SUBDIRECTORY_FOR_GAME_DATA "/.minecraft-pi"
|
||||
#else
|
||||
// Store Game Data In $HOME Root (In Server Mode, $HOME Is Changed To The Launch Directory)
|
||||
#define HOME_SUBDIRECTORY_FOR_GAME_DATA ""
|
||||
#endif
|
@ -5,5 +5,4 @@
|
||||
#include "util.h"
|
||||
#include "string.h"
|
||||
#include "exec.h"
|
||||
#include "home.h"
|
||||
#include "patch.h"
|
||||
|
@ -51,10 +51,19 @@ int lock_file(const char *file);
|
||||
void unlock_file(const char *file, int fd);
|
||||
|
||||
// Access Configuration At Runtime
|
||||
#define MCPI_SERVER_MODE_ENV "_MCPI_SERVER_MODE"
|
||||
#define MCPI_FORCE_HEADLESS_ENV "_MCPI_FORCE_HEADLESS"
|
||||
#define MCPI_FORCE_NON_HEADLESS_ENV "_MCPI_FORCE_NON_HEADLESS"
|
||||
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();
|
||||
|
||||
// Customize VTable
|
||||
#define CUSTOM_VTABLE(name, parent) \
|
||||
void _setup_##name##_vtable(parent##_vtable *vtable); \
|
||||
|
@ -50,16 +50,43 @@ const char *reborn_get_version() {
|
||||
return MCPI_VERSION;
|
||||
}
|
||||
int reborn_is_headless() {
|
||||
#ifdef MCPI_HEADLESS_MODE
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
static int ret;
|
||||
static int is_set = 0;
|
||||
if (!is_set) {
|
||||
ret = reborn_is_server();
|
||||
if (getenv(MCPI_FORCE_HEADLESS_ENV)) {
|
||||
ret = 1;
|
||||
} else if (getenv(MCPI_FORCE_NON_HEADLESS_ENV)) {
|
||||
ret = 0;
|
||||
}
|
||||
is_set = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int reborn_is_server() {
|
||||
#ifdef MCPI_SERVER_MODE
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
static int ret;
|
||||
static int is_set = 0;
|
||||
if (!is_set) {
|
||||
ret = getenv(MCPI_SERVER_MODE_ENV) != NULL;
|
||||
is_set = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Check $DISPLAY
|
||||
void reborn_check_display() {
|
||||
if (!getenv("DISPLAY") && !getenv("WAYLAND_DISPLAY")) {
|
||||
ERR("No display attached! Make sure $DISPLAY or $WAYLAND_DISPLAY is set.");
|
||||
}
|
||||
}
|
||||
|
||||
// Home Subdirectory
|
||||
const char *get_home_subdirectory_for_game_data() {
|
||||
if (!reborn_is_server()) {
|
||||
// Store Game Data In "~/.minecraft-pi" Instead Of "~/.minecraft" To Avoid Conflicts
|
||||
return "/.minecraft-pi";
|
||||
} else {
|
||||
// Store Game Data In $HOME Root (In Server Mode, $HOME Is Changed To The Launch Directory)
|
||||
return "";
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
project(media-layer-core)
|
||||
|
||||
# OpenGL
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
add_subdirectory(gles)
|
||||
endif()
|
||||
add_subdirectory(gles)
|
||||
|
||||
# Configuration
|
||||
set(CORE_SRC src/base.cpp src/media.c $<TARGET_OBJECTS:media-layer-extras>) # SDL Re-Implementation Using GLFW
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
list(APPEND CORE_SRC src/audio/api.cpp src/audio/engine.c src/audio/file.cpp)
|
||||
else()
|
||||
list(APPEND CORE_SRC src/audio/stubs.c)
|
||||
endif()
|
||||
# SDL Re-Implementation Using GLFW
|
||||
set(CORE_SRC
|
||||
src/base.cpp
|
||||
src/media.cpp
|
||||
src/audio/api.cpp
|
||||
src/audio/engine.c
|
||||
src/audio/file.cpp
|
||||
$<TARGET_OBJECTS:media-layer-extras>
|
||||
)
|
||||
|
||||
# Build
|
||||
add_library(media-layer-core-real SHARED ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
@ -23,10 +23,14 @@ endif()
|
||||
install(TARGETS media-layer-core-real DESTINATION "${MCPI_LIB_DIR}")
|
||||
|
||||
# Link
|
||||
target_link_libraries(media-layer-core-real PUBLIC media-layer-headers PUBLIC reborn-util PUBLIC dl)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
# OpenAL
|
||||
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core-real PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw PUBLIC GLESv1_CM PRIVATE LIB_LIEF)
|
||||
endif()
|
||||
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
|
||||
target_link_libraries(media-layer-core-real
|
||||
PUBLIC media-layer-headers
|
||||
PUBLIC reborn-util
|
||||
PRIVATE "${OPENAL_LIBRARY}"
|
||||
PRIVATE m
|
||||
PRIVATE glfw
|
||||
PUBLIC GLESv1_CM
|
||||
PRIVATE LIB_LIEF
|
||||
PUBLIC dl
|
||||
)
|
||||
|
@ -1,6 +0,0 @@
|
||||
#include <media-layer/audio.h>
|
||||
|
||||
void media_audio_update(__attribute__((unused)) float volume, __attribute__((unused)) float x, __attribute__((unused)) float y, __attribute__((unused)) float z, __attribute__((unused)) float yaw) {
|
||||
}
|
||||
void media_audio_play(__attribute__((unused)) const char *source, __attribute__((unused)) const char *name, __attribute__((unused)) float x, __attribute__((unused)) float y, __attribute__((unused)) float z, __attribute__((unused)) float pitch, __attribute__((unused)) float volume, __attribute__((unused)) int is_ui) {
|
||||
}
|
@ -1,861 +0,0 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#include <time.h>
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#endif
|
||||
|
||||
#include <media-layer/core.h>
|
||||
#include <media-layer/internal.h>
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#include "audio/engine.h"
|
||||
#endif
|
||||
|
||||
// Allow Disabling Interaction
|
||||
static void update_cursor();
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static void emit_events_after_is_interactable_change();
|
||||
#endif
|
||||
static int is_interactable = 1;
|
||||
void media_set_interactable(int toggle) {
|
||||
if (toggle != is_interactable) {
|
||||
is_interactable = toggle;
|
||||
update_cursor();
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
emit_events_after_is_interactable_change();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Track Media Layer State
|
||||
static volatile int is_running = 0;
|
||||
|
||||
// Store Cursor State
|
||||
static int cursor_grabbed = 0;
|
||||
static int cursor_visible = 1;
|
||||
|
||||
// Track If Raw Mouse Motion Is Enabled
|
||||
static int raw_mouse_motion_enabled = 1;
|
||||
|
||||
// GLFW Code Not Needed In Headless Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
static GLFWwindow *glfw_window = NULL;
|
||||
|
||||
// Handle GLFW Error
|
||||
static void glfw_error(__attribute__((unused)) int error, const char *description) {
|
||||
WARN("GLFW Error: %s", description);
|
||||
}
|
||||
|
||||
// Pass Character Event
|
||||
static void character_event(char c) {
|
||||
// SDL_UserEvent Is Never Used In MCPI, So It Is Repurposed For Character Events
|
||||
SDL_Event event;
|
||||
event.type = SDL_USEREVENT;
|
||||
event.user.code = USER_EVENT_CHARACTER;
|
||||
event.user.data1 = (int) c;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
// Convert GLFW Key To SDL Key
|
||||
#define IMAGINARY_GLFW_CRAFTING_KEY GLFW_KEY_LAST
|
||||
static SDLKey glfw_key_to_sdl_key(int key) {
|
||||
switch (key) {
|
||||
// Movement
|
||||
case GLFW_KEY_W:
|
||||
return SDLK_w;
|
||||
case GLFW_KEY_A:
|
||||
return SDLK_a;
|
||||
case GLFW_KEY_S:
|
||||
return SDLK_s;
|
||||
case GLFW_KEY_D:
|
||||
return SDLK_d;
|
||||
case GLFW_KEY_SPACE:
|
||||
return SDLK_SPACE;
|
||||
case GLFW_KEY_LEFT_SHIFT:
|
||||
return SDLK_LSHIFT;
|
||||
case GLFW_KEY_RIGHT_SHIFT:
|
||||
return SDLK_RSHIFT;
|
||||
// Inventory
|
||||
case GLFW_KEY_E:
|
||||
return SDLK_e;
|
||||
// Drop Item
|
||||
case GLFW_KEY_Q:
|
||||
return SDLK_q;
|
||||
// Toolbar
|
||||
case GLFW_KEY_1:
|
||||
return SDLK_1;
|
||||
case GLFW_KEY_2:
|
||||
return SDLK_2;
|
||||
case GLFW_KEY_3:
|
||||
return SDLK_3;
|
||||
case GLFW_KEY_4:
|
||||
return SDLK_4;
|
||||
case GLFW_KEY_5:
|
||||
return SDLK_5;
|
||||
case GLFW_KEY_6:
|
||||
return SDLK_6;
|
||||
case GLFW_KEY_7:
|
||||
return SDLK_7;
|
||||
case GLFW_KEY_8:
|
||||
return SDLK_8;
|
||||
case GLFW_KEY_9:
|
||||
return SDLK_9;
|
||||
case GLFW_KEY_0:
|
||||
return SDLK_0;
|
||||
// UI Control
|
||||
case GLFW_KEY_ESCAPE:
|
||||
return SDLK_ESCAPE;
|
||||
case GLFW_KEY_UP:
|
||||
return SDLK_UP;
|
||||
case GLFW_KEY_DOWN:
|
||||
return SDLK_DOWN;
|
||||
case GLFW_KEY_LEFT:
|
||||
return SDLK_LEFT;
|
||||
case GLFW_KEY_RIGHT:
|
||||
return SDLK_RIGHT;
|
||||
case GLFW_KEY_TAB:
|
||||
return SDLK_TAB;
|
||||
case GLFW_KEY_ENTER:
|
||||
return SDLK_RETURN;
|
||||
case GLFW_KEY_BACKSPACE:
|
||||
return SDLK_BACKSPACE;
|
||||
case GLFW_KEY_DELETE:
|
||||
return SDLK_DELETE;
|
||||
// Fullscreen
|
||||
case GLFW_KEY_F11:
|
||||
return SDLK_F11;
|
||||
// Screenshot
|
||||
case GLFW_KEY_F2:
|
||||
return SDLK_F2;
|
||||
// Hide GUI
|
||||
case GLFW_KEY_F1:
|
||||
return SDLK_F1;
|
||||
// Third Person
|
||||
case GLFW_KEY_F5:
|
||||
return SDLK_F5;
|
||||
// Chat
|
||||
case GLFW_KEY_T:
|
||||
return SDLK_t;
|
||||
// Crafting
|
||||
case IMAGINARY_GLFW_CRAFTING_KEY:
|
||||
return SDLK_WORLD_0;
|
||||
// Unknown
|
||||
default:
|
||||
return SDLK_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert GLFW Key Modifier To SDL Key Modifier
|
||||
static SDLMod glfw_modifier_to_sdl_modifier(int mods) {
|
||||
SDLMod ret = KMOD_NONE;
|
||||
// Control
|
||||
if ((mods & GLFW_MOD_CONTROL) != 0) {
|
||||
ret |= KMOD_CTRL;
|
||||
}
|
||||
// Shift
|
||||
if ((mods & GLFW_MOD_SHIFT) != 0) {
|
||||
ret |= KMOD_SHIFT;
|
||||
}
|
||||
// Alt
|
||||
if ((mods & GLFW_MOD_ALT) != 0) {
|
||||
ret |= KMOD_ALT;
|
||||
}
|
||||
// Return
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Pass Key Presses To SDL
|
||||
static void glfw_key_raw(int key, int scancode, int action, int mods) {
|
||||
SDL_Event event1;
|
||||
int up = action == GLFW_RELEASE;
|
||||
event1.type = up ? SDL_KEYUP : SDL_KEYDOWN;
|
||||
event1.key.state = up ? SDL_RELEASED : SDL_PRESSED;
|
||||
event1.key.keysym.scancode = scancode;
|
||||
event1.key.keysym.mod = glfw_modifier_to_sdl_modifier(mods);
|
||||
event1.key.keysym.sym = glfw_key_to_sdl_key(key);
|
||||
SDL_PushEvent(&event1);
|
||||
// Allow MCPI To Access Original GLFW Keycode
|
||||
SDL_Event event2;
|
||||
event2.type = SDL_USEREVENT;
|
||||
event2.user.code = USER_EVENT_REAL_KEY;
|
||||
event2.user.data1 = event1.key.state;
|
||||
event2.user.data2 = key;
|
||||
SDL_PushEvent(&event2);
|
||||
}
|
||||
static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||||
if (is_interactable) {
|
||||
glfw_key_raw(key, scancode, action, mods);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass Text To Minecraft
|
||||
static void codepoint_to_utf8(unsigned char *const buffer, const unsigned int code) {
|
||||
// https://stackoverflow.com/a/42013433/16198887
|
||||
if (code <= 0x7f) {
|
||||
buffer[0] = code;
|
||||
} else if (code <= 0x7ff) {
|
||||
buffer[0] = 0xc0 | (code >> 6); // 110xxxxx
|
||||
buffer[1] = 0x80 | (code & 0x3f); // 10xxxxxx
|
||||
} else if (code <= 0xffff) {
|
||||
buffer[0] = 0xe0 | (code >> 12); // 1110xxxx
|
||||
buffer[1] = 0x80 | ((code >> 6) & 0x3f); // 10xxxxxx
|
||||
buffer[2] = 0x80 | (code & 0x3f); // 10xxxxxx
|
||||
} else if (code <= 0x10ffff) {
|
||||
buffer[0] = 0xf0 | (code >> 18); // 11110xxx
|
||||
buffer[1] = 0x80 | ((code >> 12) & 0x3f); // 10xxxxxx
|
||||
buffer[2] = 0x80 | ((code >> 6) & 0x3f); // 10xxxxxx
|
||||
buffer[3] = 0x80 | (code & 0x3f); // 10xxxxxx
|
||||
}
|
||||
}
|
||||
static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
|
||||
if (is_interactable) {
|
||||
// Convert
|
||||
size_t str_size = 4 /* Maximum UTF-8 character size */ + 1 /* NULL-terminator */;
|
||||
char str[str_size];
|
||||
memset(str, 0, str_size);
|
||||
codepoint_to_utf8((unsigned char *) str, codepoint);
|
||||
char *cp437_str = to_cp437(str);
|
||||
// Send Event
|
||||
for (int i = 0; cp437_str[i] != '\0'; i++) {
|
||||
character_event(cp437_str[i]);
|
||||
}
|
||||
// Free
|
||||
free(cp437_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Last Mouse Location
|
||||
static double last_mouse_x = 0;
|
||||
static double last_mouse_y = 0;
|
||||
// Ignore Relative Cursor Motion
|
||||
static int ignore_relative_motion = 0;
|
||||
|
||||
// Convert Screen Coordinates To Pixels
|
||||
static void convert_to_pixels(GLFWwindow *window, double *xpos, double *ypos) {
|
||||
// Skip If Cursor Is Grabbed
|
||||
if (cursor_grabbed && raw_mouse_motion_enabled) {
|
||||
return;
|
||||
}
|
||||
// Get Window Size
|
||||
int window_width;
|
||||
int window_height;
|
||||
glfwGetWindowSize(window, &window_width, &window_height);
|
||||
// Get Framebuffer Size
|
||||
int framebuffer_width;
|
||||
int framebuffer_height;
|
||||
glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
|
||||
// Calculate Ratios
|
||||
double width_ratio = ((double) framebuffer_width) / ((double) window_width);
|
||||
double height_ratio = ((double) framebuffer_height) / ((double) window_height);
|
||||
// Multiply
|
||||
*xpos *= width_ratio;
|
||||
*ypos *= height_ratio;
|
||||
}
|
||||
|
||||
// Pass Mouse Movement To SDL
|
||||
static void glfw_motion(__attribute__((unused)) GLFWwindow *window, double xpos, double ypos) {
|
||||
convert_to_pixels(window, &xpos, &ypos);
|
||||
if (is_interactable) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.x = xpos;
|
||||
event.motion.y = ypos;
|
||||
event.motion.xrel = !ignore_relative_motion ? (xpos - last_mouse_x) : 0;
|
||||
event.motion.yrel = !ignore_relative_motion ? (ypos - last_mouse_y) : 0;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
ignore_relative_motion = 0;
|
||||
last_mouse_x = xpos;
|
||||
last_mouse_y = ypos;
|
||||
}
|
||||
|
||||
// Create And Push SDL Mouse Click Event
|
||||
static void click_event(int button, int up) {
|
||||
SDL_Event event;
|
||||
event.type = up ? SDL_MOUSEBUTTONUP : SDL_MOUSEBUTTONDOWN;
|
||||
event.button.x = last_mouse_x;
|
||||
event.button.y = last_mouse_y;
|
||||
event.button.state = up ? SDL_RELEASED : SDL_PRESSED;
|
||||
event.button.button = button;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
// Pass Mouse Click To SDL
|
||||
static void glfw_click_raw(int button, int action) {
|
||||
int up = action == GLFW_RELEASE;
|
||||
int sdl_button = button == GLFW_MOUSE_BUTTON_RIGHT ? SDL_BUTTON_RIGHT : (button == GLFW_MOUSE_BUTTON_LEFT ? SDL_BUTTON_LEFT : SDL_BUTTON_MIDDLE);
|
||||
click_event(sdl_button, up);
|
||||
}
|
||||
static void glfw_click(__attribute__((unused)) GLFWwindow *window, int button, int action, __attribute__((unused)) int mods) {
|
||||
if (is_interactable) {
|
||||
glfw_click_raw(button, action);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass Mouse Scroll To SDL
|
||||
static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute__((unused)) double xoffset, double yoffset) {
|
||||
if (is_interactable && yoffset != 0) {
|
||||
int sdl_button = yoffset > 0 ? SDL_BUTTON_WHEELUP : SDL_BUTTON_WHEELDOWN;
|
||||
click_event(sdl_button, 0);
|
||||
click_event(sdl_button, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Controller Events
|
||||
static SDLKey glfw_controller_button_to_key(int button) {
|
||||
switch (button) {
|
||||
// Jump
|