diff --git a/.gitattributes b/.gitattributes index 2e62a4e59..06b76c6c8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,5 @@ +# Forces all files which git considers text files to use LF line endings +* text=auto eol=lf + *.cpp diff=cpp *.h diff=cpp diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index ffcae5cf5..c59dd6732 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -8,6 +8,8 @@ on: - 'lib/**.cpp' - 'src/**.[ch]' - 'src/**.cpp' + - 'irr/**.[ch]' + - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' - 'android/**' diff --git a/.github/workflows/cpp_lint.yml b/.github/workflows/cpp_lint.yml index 51c6c8273..79b8ffc4e 100644 --- a/.github/workflows/cpp_lint.yml +++ b/.github/workflows/cpp_lint.yml @@ -8,6 +8,8 @@ on: - 'lib/**.cpp' - 'src/**.[ch]' - 'src/**.cpp' + - 'irr/**.[ch]' + - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' - 'util/ci/**' diff --git a/.github/workflows/docker_image.yml b/.github/workflows/docker_image.yml new file mode 100644 index 000000000..eaac7bf1b --- /dev/null +++ b/.github/workflows/docker_image.yml @@ -0,0 +1,89 @@ +--- +name: docker_image + +# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images +# https://docs.docker.com/build/ci/github-actions/multi-platform +# https://github.com/opencontainers/image-spec/blob/main/annotations.md + +on: + push: + branches: [ "master" ] + # Publish semver tags as releases. + tags: [ "*.*.*" ] + pull_request: + # Build docker image on pull requests. (but do not publish) + paths: + - 'lib/**.[ch]' + - 'lib/**.cpp' + - 'src/**.[ch]' + - 'src/**.cpp' + - '**/CMakeLists.txt' + - 'cmake/Modules/**' + - 'util/ci/**' + - 'misc/irrlichtmt_tag.txt' + - 'Dockerfile' + - '.dockerignore' + - '.github/workflows/docker_image.yml' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} + +jobs: + publish: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v3.0.0 + + # Login against the Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@v3.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5.5.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + labels: | + org.opencontainers.image.title=Minetest + org.opencontainers.image.vendor=Minetest + org.opencontainers.image.licenses=LGPL-2.1-only + + # Build and push Docker image + # https://github.com/docker/build-push-action + # No arm support for now. Require cross-compilation support in Dockerfile to not use QEMU. + - name: Build and push Docker image + uses: docker/build-push-action@v5.1.0 + with: + context: . + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + load: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test Docker Image + run: | + docker run --rm $(cut -d, -f1 <<<"$DOCKER_METADATA_OUTPUT_TAGS") minetestserver --version + shell: bash diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3d831d92f..eb2b032da 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -8,10 +8,11 @@ on: - 'lib/**.cpp' - 'src/**.[ch]' - 'src/**.cpp' + - 'irr/**.[ch]' + - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' - 'util/ci/**' - - 'misc/irrlichtmt_tag.txt' - 'Dockerfile' - '.dockerignore' - '.github/workflows/linux.yml' @@ -24,7 +25,6 @@ on: - '**/CMakeLists.txt' - 'cmake/Modules/**' - 'util/ci/**' - - 'misc/irrlichtmt_tag.txt' - 'Dockerfile' - '.dockerignore' - '.github/workflows/linux.yml' @@ -108,7 +108,7 @@ jobs: - name: Install deps run: | source ./util/ci/common.sh - install_linux_deps clang-14 gdb + install_linux_deps clang-14 lldb - name: Build run: | @@ -151,13 +151,3 @@ jobs: - name: Test run: | ./bin/minetestserver --run-unittests - - docker: - name: "Docker image" - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - - name: Build docker image - run: | - docker build . -t minetest:latest - docker run --rm minetest:latest /usr/local/bin/minetestserver --version diff --git a/.github/workflows/lua.yml b/.github/workflows/lua.yml index ff556908f..6f803d133 100644 --- a/.github/workflows/lua.yml +++ b/.github/workflows/lua.yml @@ -14,24 +14,24 @@ on: - '.github/workflows/**.yml' jobs: - # Note that the integration tests are also run build.yml, but only when C++ code is changed. + # Note that the integration tests are also run in build.yml, but only when C++ code is changed. integration_tests: name: "Compile and run multiplayer tests" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: Install deps run: | source ./util/ci/common.sh - install_linux_deps clang-10 gdb libluajit-5.1-dev + install_linux_deps clang gdb libluajit-5.1-dev - name: Build run: | ./util/ci/build.sh env: - CC: clang-10 - CXX: clang++-10 - CMAKE_FLAGS: "-DENABLE_GETTEXT=0 -DBUILD_SERVER=0" + CC: clang + CXX: clang++ + CMAKE_FLAGS: "-DENABLE_GETTEXT=0 -DBUILD_SERVER=0 -DBUILD_UNITTESTS=0" - name: Integration test + devtest run: | diff --git a/.github/workflows/lua_api_deploy.yml b/.github/workflows/lua_api_deploy.yml index bcefb0972..e42335a78 100644 --- a/.github/workflows/lua_api_deploy.yml +++ b/.github/workflows/lua_api_deploy.yml @@ -16,8 +16,8 @@ on: jobs: build: - runs-on: ubuntu-22.04 - + if: github.repository == 'minetest/minetest' + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 56b3f9fdc..24c2b9f51 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -8,6 +8,8 @@ on: - 'lib/**.cpp' - 'src/**.[ch]' - 'src/**.cpp' + - 'irr/**.[ch]' + - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' - '.github/workflows/macos.yml' @@ -33,7 +35,6 @@ jobs: - name: Build run: | - git clone https://github.com/minetest/irrlicht lib/irrlichtmt --depth 1 -b $(cat misc/irrlichtmt_tag.txt) mkdir build cd build cmake .. \ diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index eb9a13fac..061bd704b 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -8,10 +8,11 @@ on: - 'lib/**.cpp' - 'src/**.[ch]' - 'src/**.cpp' + - 'irr/**.[ch]' + - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' - 'util/buildbot/**' - - 'misc/irrlichtmt_tag.txt' - 'misc/*.manifest' - '.github/workflows/windows.yml' pull_request: @@ -23,7 +24,6 @@ on: - '**/CMakeLists.txt' - 'cmake/Modules/**' - 'util/buildbot/**' - - 'misc/irrlichtmt_tag.txt' - 'misc/*.manifest' - '.github/workflows/windows.yml' @@ -97,11 +97,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Checkout IrrlichtMt - run: | - $ref = @(Get-Content misc\irrlichtmt_tag.txt) - git clone https://github.com/minetest/irrlicht lib\irrlichtmt --depth 1 -b $ref[0] - - name: Restore from cache and run vcpkg uses: lukka/run-vcpkg@v7 with: diff --git a/.gitignore b/.gitignore index d996a0d4c..37e27bfed 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ AppDir /clientmods/* !/clientmods/preview/ /client/mod_storage/ +/mod_data ## Configuration/log files minetest.conf @@ -118,7 +119,7 @@ compile_commands.json *.sln .vs/ -# Optional user provided library folder +# Old irrlichtmt. Still ignored to make bisecting easier. lib/irrlichtmt # Generated mod storage database diff --git a/CMakeLists.txt b/CMakeLists.txt index e6586425e..3e867d3b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,27 +91,12 @@ if(ANDROID) endif() -set(IRRLICHTMT_BUILD_DIR "" CACHE PATH "Path to IrrlichtMt build directory.") -if(ANDROID) - # currently manually provided -elseif(NOT "${IRRLICHTMT_BUILD_DIR}" STREQUAL "") - find_package(IrrlichtMt QUIET - PATHS "${IRRLICHTMT_BUILD_DIR}" - NO_DEFAULT_PATH - ) - - if(NOT TARGET IrrlichtMt::IrrlichtMt) - # find_package() searches certain subdirectories. ${PATH}/cmake is not - # the only one, but it is the one where IrrlichtMt is supposed to export - # IrrlichtMtConfig.cmake - message(FATAL_ERROR "Could not find IrrlichtMtConfig.cmake in ${IRRLICHTMT_BUILD_DIR}/cmake.") - endif() -elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt") - message(STATUS "Using user-provided IrrlichtMt at subdirectory 'lib/irrlichtmt'") +if(TRUE) + message(STATUS "Using imported IrrlichtMt at subdirectory 'irr'") if(BUILD_CLIENT) # tell IrrlichtMt to create a static library set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared library" FORCE) - add_subdirectory(lib/irrlichtmt EXCLUDE_FROM_ALL) + add_subdirectory(irr EXCLUDE_FROM_ALL) unset(BUILD_SHARED_LIBS CACHE) if(NOT TARGET IrrlichtMt) @@ -120,44 +105,7 @@ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt") else() add_library(IrrlichtMt::IrrlichtMt INTERFACE IMPORTED) set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt/include") - endif() -else() - find_package(IrrlichtMt QUIET) - if(NOT TARGET IrrlichtMt::IrrlichtMt) - string(CONCAT explanation_msg - "You must install IrrlichMt as described in docs/compiling/\n") - if(BUILD_CLIENT) - message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.\n${explanation_msg}") - endif() - - include(MinetestFindIrrlichtHeaders) - if(NOT IRRLICHT_INCLUDE_DIR) - message(FATAL_ERROR "IrrlichtMt headers are required to build the server, but none found.\n${explanation_msg}") - endif() - message(STATUS "Found IrrlichtMt headers: ${IRRLICHT_INCLUDE_DIR}") - add_library(IrrlichtMt::IrrlichtMt INTERFACE IMPORTED) - # Note that we can't use target_include_directories() since that doesn't work for IMPORTED targets before CMake 3.11 - set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${IRRLICHT_INCLUDE_DIR}") - endif() -endif() - -if(ANDROID) - # skipped for now -elseif(BUILD_CLIENT AND TARGET IrrlichtMt::IrrlichtMt) - # retrieve version somehow - if(NOT IrrlichtMt_VERSION) - get_target_property(IrrlichtMt_VERSION IrrlichtMt VERSION) - endif() - message(STATUS "Found IrrlichtMt ${IrrlichtMt_VERSION}") - - set(TARGET_VER_S 1.9.0mt15) - string(REPLACE "mt" "." TARGET_VER ${TARGET_VER_S}) - if(IrrlichtMt_VERSION VERSION_LESS ${TARGET_VER}) - message(FATAL_ERROR "At least IrrlichtMt ${TARGET_VER_S} is required to build") - elseif(NOT DEVELOPMENT_BUILD AND IrrlichtMt_VERSION VERSION_GREATER ${TARGET_VER}) - message(FATAL_ERROR "IrrlichtMt ${TARGET_VER_S} is required to build") + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/irr/include") endif() endif() diff --git a/Dockerfile b/Dockerfile index 95476663f..701c0492a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,6 @@ ARG DOCKER_IMAGE=alpine:3.19 FROM $DOCKER_IMAGE AS dev -ENV IRRLICHT_VERSION master ENV SPATIALINDEX_VERSION master ENV LUAJIT_VERSION v2.1 @@ -30,9 +29,7 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp && \ git clone --recursive https://luajit.org/git/luajit.git -b ${LUAJIT_VERSION} && \ cd luajit && \ make amalg && make install && \ - cd /usr/src/ && \ - git clone --depth=1 https://github.com/minetest/irrlicht -b ${IRRLICHT_VERSION} && \ - cp -r irrlicht/include /usr/include/irrlichtmt + cd /usr/src/ FROM dev as builder @@ -48,6 +45,7 @@ COPY lib /usr/src/minetest/lib COPY misc /usr/src/minetest/misc COPY po /usr/src/minetest/po COPY src /usr/src/minetest/src +COPY irr /usr/src/minetest/irr COPY textures /usr/src/minetest/textures WORKDIR /usr/src/minetest diff --git a/README.md b/README.md index 60cc7da7d..a16f5eb67 100644 --- a/README.md +++ b/README.md @@ -108,9 +108,9 @@ Use `--help` ## Docker -* [Developing minetestserver with Docker](doc/developing/docker.md) +- [Developing minetestserver with Docker](doc/developing/docker.md) -We provide a Dockerfile that can be used to build the server. +- [Running a server with Docker](doc/docker_server.md) ## Version Scheme diff --git a/android/app/build.gradle b/android/app/build.gradle index 6bacc3d55..30ee19c95 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -75,7 +75,7 @@ task prepareAssets() { from "${projRoot}/client/shaders" into "${assetsFolder}/client/shaders" } copy { - from "../native/deps/armeabi-v7a/Irrlicht/Shaders" into "${assetsFolder}/client/shaders/Irrlicht" + from "${projRoot}/irr/media/Shaders" into "${assetsFolder}/client/shaders/Irrlicht" } copy { from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts" @@ -108,6 +108,10 @@ task prepareAssets() { preBuild.dependsOn zipAssets prepareAssets.dependsOn ':native:getDeps' +clean { + delete new File("src/main/assets", "Minetest.zip") +} + // Map for the version code that gives each ABI a value. import com.android.build.OutputFile diff --git a/android/build.gradle b/android/build.gradle index 6aead7aba..1805ba856 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -10,7 +10,7 @@ project.ext.set("versionCode", 46) // Android Version Code // each APK must have a larger `versionCode` than the previous buildscript { - ext.ndk_version = '25.2.9519653' + ext.ndk_version = '26.2.11394342' repositories { google() mavenCentral() diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf01..d64cd4917 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 0e9a61051..1af9e0930 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip diff --git a/android/gradlew b/android/gradlew index 25e0c1148..1aa94a426 100755 --- a/android/gradlew +++ b/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,111 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - command -v java >/dev/null || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat deleted file mode 100644 index 9618d8d96..000000000 --- a/android/gradlew.bat +++ /dev/null @@ -1,100 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/android/native/build.gradle b/android/native/build.gradle index 396ccff85..925ab8912 100644 --- a/android/native/build.gradle +++ b/android/native/build.gradle @@ -43,19 +43,25 @@ android { } // get precompiled deps -task downloadDeps(type: Download) { - def depsDir = new File(buildDir.parent, 'deps') - def depsZip = new File(buildDir, 'deps.zip') +def depsDir = new File(buildDir.parent, 'deps') +if (new File(depsDir, 'armeabi-v7a').exists()) { + task getDeps { + doLast { logger.lifecycle('Using existing deps from {}', depsDir) } + } +} else { + task downloadDeps(type: Download) { + def depsZip = new File(buildDir, 'deps.zip') - src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps.zip' - dest depsZip - overwrite false + src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps-lite.zip' + dest depsZip + overwrite false - task getDeps(dependsOn: downloadDeps, type: Copy) { - depsDir.mkdir() - from zipTree(depsZip) - into depsDir - doFirst { logger.lifecycle('Extracting to {}', depsDir) } + task getDeps(dependsOn: downloadDeps, type: Copy) { + depsDir.mkdir() + from zipTree(depsZip) + into depsDir + doFirst { logger.lifecycle('Extracting to {}', depsDir) } + } } } diff --git a/builtin/common/metatable.lua b/builtin/common/metatable.lua new file mode 100644 index 000000000..b402dd63a --- /dev/null +++ b/builtin/common/metatable.lua @@ -0,0 +1,13 @@ +-- Registered metatables, used by the C++ packer +local known_metatables = {} +function core.register_async_metatable(name, mt) + assert(type(name) == "string", ("attempt to use %s value as metatable name"):format(type(name))) + assert(type(mt) == "table", ("attempt to register a %s value as metatable"):format(type(mt))) + assert(known_metatables[name] == nil or known_metatables[name] == mt, + ("attempt to override metatable %s"):format(name)) + known_metatables[name] = mt + known_metatables[mt] = name +end +core.known_metatables = known_metatables + +core.register_async_metatable("__builtin:vector", vector.metatable) diff --git a/builtin/emerge/env.lua b/builtin/emerge/env.lua index 43848082a..2b32a0339 100644 --- a/builtin/emerge/env.lua +++ b/builtin/emerge/env.lua @@ -31,11 +31,6 @@ function core.get_node(pos) return core.vmanip:get_node_at(pos) end -function core.get_node_or_nil(pos) - local node = core.vmanip:get_node_at(pos) - return node.name ~= "ignore" and node -end - function core.get_perlin(seed, octaves, persist, spread) local params if type(seed) == "table" then diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 68005811f..874d3e885 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -37,6 +37,8 @@ core.features = { blocking_pointability_type = true, dynamic_add_media_startup = true, dynamic_add_media_filepath = true, + lsystem_decoration_type = true, + item_meta_range = true, } function core.has_feature(arg) diff --git a/builtin/game/init.lua b/builtin/game/init.lua index e6a8e800b..f6432a73d 100644 --- a/builtin/game/init.lua +++ b/builtin/game/init.lua @@ -18,6 +18,7 @@ if core.settings:get_bool("profiler.load") then end dofile(commonpath .. "after.lua") +dofile(commonpath .. "metatable.lua") dofile(commonpath .. "mod_storage.lua") dofile(gamepath .. "item_entity.lua") dofile(gamepath .. "deprecated.lua") diff --git a/builtin/game/item.lua b/builtin/game/item.lua index 498e5899f..8b79d2d71 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -736,3 +736,22 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items on_drop = nil, on_use = nil, } + +-- +-- get_node implementation +-- + +local get_node_raw = core.get_node_raw +core.get_node_raw = nil + +function core.get_node(pos) + local content, param1, param2 = get_node_raw(pos.x, pos.y, pos.z) + return {name = core.get_name_from_content_id(content), param1 = param1, param2 = param2} +end + +function core.get_node_or_nil(pos) + local content, param1, param2, pos_ok = get_node_raw(pos.x, pos.y, pos.z) + return pos_ok and + {name = core.get_name_from_content_id(content), param1 = param1, param2 = param2} + or nil +end diff --git a/builtin/game/tests/test_moveaction.lua b/builtin/game/tests/test_moveaction.lua new file mode 100644 index 000000000..476579348 --- /dev/null +++ b/builtin/game/tests/test_moveaction.lua @@ -0,0 +1,84 @@ +-- Table to keep track of callback executions +-- [i + 0] = count of expected patterns of index (i + 1) +-- [i + 1] = pattern to check +local PATTERN_NORMAL = { 4, "allow_%w", 2, "on_take", 1, "on_put", 1 } +local PATTERN_SWAP = { 8, "allow_%w", 4, "on_take", 2, "on_put", 2 } +local exec_listing = {} -- List of logged callbacks (e.g. "on_take", "allow_put") + +-- Checks whether the logged callbacks equal the expected pattern +core.__helper_check_callbacks = function(expect_swap) + local exec_pattern = expect_swap and PATTERN_SWAP or PATTERN_NORMAL + local ok = #exec_listing == exec_pattern[1] + if ok then + local list_index = 1 + for i = 2, #exec_pattern, 2 do + for n = 1, exec_pattern[i + 1] do + -- Match the list for "n" occurrences of the wanted callback name pattern + ok = exec_listing[list_index]:find(exec_pattern[i]) + list_index = list_index + 1 + if not ok then break end + end + if not ok then break end + end + end + + if not ok then + print("Execution order mismatch!") + print("Expected patterns: ", dump(exec_pattern)) + print("Got list: ", dump(exec_listing)) + end + exec_listing = {} + return ok +end + +-- Uncomment the other line for easier callback debugging +local log = function(...) end +--local log = print + +minetest.register_allow_player_inventory_action(function(_, action, inv, info) + log("\tallow " .. action, info.count or info.stack:to_string()) + + if action == "move" then + -- testMoveFillStack + return info.count + end + + if action == "take" or action == "put" then + assert(not info.stack:is_empty(), "Stack empty in: " .. action) + + -- testMoveUnallowed + -- testSwapFromUnallowed + -- testSwapToUnallowed + if info.stack:get_name() == "default:takeput_deny" then + return 0 + end + + -- testMovePartial + if info.stack:get_name() == "default:takeput_max_5" then + return 5 + end + + -- testCallbacks + if info.stack:get_name():find("default:takeput_cb_%d") then + -- Log callback as executed + table.insert(exec_listing, "allow_" .. action) + return -- Unlimited + end + end + + return -- Unlimited +end) + +minetest.register_on_player_inventory_action(function(_, action, inv, info) + log("\ton " .. action, info.count or info.stack:to_string()) + + if action == "take" or action == "put" then + assert(not info.stack:is_empty(), action) + + if info.stack:get_name():find("default:takeput_cb_%d") then + -- Log callback as executed + table.insert(exec_listing, "on_" .. action) + return + end + end +end) diff --git a/builtin/init.lua b/builtin/init.lua index b62dbf07a..cf4e8704e 100644 --- a/builtin/init.lua +++ b/builtin/init.lua @@ -63,6 +63,7 @@ elseif INIT == "mainmenu" then elseif INIT == "async" then dofile(asyncpath .. "mainmenu.lua") elseif INIT == "async_game" then + dofile(commonpath .. "metatable.lua") dofile(asyncpath .. "game.lua") elseif INIT == "client" then dofile(scriptdir .. "client" .. DIR_DELIM .. "init.lua") diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index 471360581..16c5c9d95 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -18,6 +18,26 @@ -- Global menu data menudata = {} +-- located in user cache path, for remembering this like e.g. last update check +cache_settings = Settings(core.get_cache_path() .. DIR_DELIM .. "common.conf") + +--- Checks if the given key contains a timestamp less than a certain age. +--- Pair this with a call to `cache_settings:set(key, tostring(os.time()))` +--- after successfully refreshing the cache. +--- @param key Name of entry in cache_settings +--- @param max_age Age to check against, in seconds +--- @return true if the max age is not reached +function check_cache_age(key, max_age) + local time_now = os.time() + local time_checked = tonumber(cache_settings:get(key)) or 0 + return time_now - time_checked < max_age +end + +function core.on_before_close() + -- called before the menu is closed, either exit or to join a game + cache_settings:write() +end + -- Local cached values local min_supp_proto, max_supp_proto @@ -27,6 +47,16 @@ function common_update_cached_supp_proto() end common_update_cached_supp_proto() +-- Other global functions + +function core.sound_stop(handle, ...) + return handle:stop(...) +end + +function os.tmpname() + error('do not use') -- instead: core.get_temp_path() +end + -- Menu helper functions local function render_client_count(n) @@ -140,11 +170,6 @@ function render_serverlist_row(spec) return table.concat(details, ",") end ---------------------------------------------------------------------------------- -os.tmpname = function() - error('do not use') -- instead use core.get_temp_path() -end --------------------------------------------------------------------------------- function menu_render_worldlist() local retval = {} diff --git a/builtin/mainmenu/content/update_detector.lua b/builtin/mainmenu/content/update_detector.lua index 558a0fabb..f70220224 100644 --- a/builtin/mainmenu/content/update_detector.lua +++ b/builtin/mainmenu/content/update_detector.lua @@ -26,13 +26,23 @@ if not core.get_http_api then end +assert(core.create_dir(core.get_cache_path() .. DIR_DELIM .. "cdb")) +local cache_file_path = core.get_cache_path() .. DIR_DELIM .. "cdb" .. DIR_DELIM .. "updates.json" local has_fetched = false local latest_releases do - local tmp = core.get_once("cdb_latest_releases") - if tmp then - latest_releases = core.deserialize(tmp, true) - has_fetched = latest_releases ~= nil + if check_cache_age("cdb_updates_last_checked", 3 * 3600) then + local f = io.open(cache_file_path, "r") + local data = "" + if f then + data = f:read("*a") + f:close() + end + data = data ~= "" and core.parse_json(data) or nil + if type(data) == "table" then + latest_releases = data + has_fetched = true + end end end @@ -97,7 +107,8 @@ local function fetch() return end latest_releases = lowercase_keys(releases) - core.set_once("cdb_latest_releases", core.serialize(latest_releases)) + core.safe_file_write(cache_file_path, core.write_json(latest_releases)) + cache_settings:set("cdb_updates_last_checked", tostring(os.time())) if update_detector.get_count() > 0 then local maintab = ui.find_by_name("maintab") diff --git a/builtin/mainmenu/dlg_reinstall_mtg.lua b/builtin/mainmenu/dlg_reinstall_mtg.lua index 77652e968..c86c75d2b 100644 --- a/builtin/mainmenu/dlg_reinstall_mtg.lua +++ b/builtin/mainmenu/dlg_reinstall_mtg.lua @@ -15,15 +15,30 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +---- IMPORTANT ---- +-- This whole file can be removed after a while. +-- It was only directly useful for upgrades from 5.7.0 to 5.8.0, but +-- maybe some odd fellow directly upgrades from 5.6.1 to 5.9.0 in the future... +-- see in case it's not obvious +---- ---- + +local SETTING_NAME = "no_mtg_notification" + function check_reinstall_mtg() - if core.settings:get_bool("no_mtg_notification") then + -- used to be in minetest.conf + if core.settings:get_bool(SETTING_NAME) then + cache_settings:set_bool(SETTING_NAME, true) + core.settings:remove(SETTING_NAME) + end + + if cache_settings:get_bool(SETTING_NAME) then return end local games = core.get_games() for _, game in ipairs(games) do if game.id == "minetest" then - core.settings:set_bool("no_mtg_notification", true) + cache_settings:set_bool(SETTING_NAME, true) return end end @@ -37,7 +52,7 @@ function check_reinstall_mtg() end end if not mtg_world_found then - core.settings:set_bool("no_mtg_notification", true) + cache_settings:set_bool(SETTING_NAME, true) return end @@ -87,7 +102,7 @@ local function buttonhandler(this, fields) end if fields.dismiss then - core.settings:set_bool("no_mtg_notification", true) + cache_settings:set_bool("no_mtg_notification", true) this:delete() return true end diff --git a/builtin/mainmenu/dlg_version_info.lua b/builtin/mainmenu/dlg_version_info.lua index 98085ee4a..483cd30bd 100644 --- a/builtin/mainmenu/dlg_version_info.lua +++ b/builtin/mainmenu/dlg_version_info.lua @@ -51,12 +51,13 @@ end local function version_info_buttonhandler(this, fields) if fields.version_check_remind then -- Erase last known, user will be reminded again at next check - core.settings:set("update_last_known", "") + cache_settings:set("update_last_known", "") this:delete() return true end if fields.version_check_never then - core.settings:set("update_last_checked", "disabled") + -- clear checked URL + core.settings:set("update_information_url", "") this:delete() return true end @@ -116,7 +117,7 @@ local function on_version_info_received(json) return end - local known_update = tonumber(core.settings:get("update_last_known")) or 0 + local known_update = tonumber(cache_settings:get("update_last_known")) or 0 -- Format: MMNNPPP (Major, Minor, Patch) local new_number = type(json.latest) == "table" and json.latest.version_code @@ -135,7 +136,7 @@ local function on_version_info_received(json) return end - core.settings:set("update_last_known", tostring(new_number)) + cache_settings:set("update_last_known", tostring(new_number)) -- Show version info dialog (once) maintab:hide() @@ -149,20 +150,20 @@ end function check_new_version() local url = core.settings:get("update_information_url") - if core.settings:get("update_last_checked") == "disabled" or - url == "" then + if url == "" then -- Never show any updates return end - local time_now = os.time() - local time_checked = tonumber(core.settings:get("update_last_checked")) or 0 - if time_now - time_checked < 2 * 24 * 3600 then - -- Check interval of 2 entire days + -- every 2 days + if check_cache_age("update_last_checked", 2 * 24 * 3600) then return end + cache_settings:set("update_last_checked", tostring(os.time())) - core.settings:set("update_last_checked", tostring(time_now)) + -- Clean old leftovers (this can be removed after 5.9.0 or so) + core.settings:remove("update_last_checked") + core.settings:remove("update_last_known") core.handle_async(function(params) local http = core.get_http_api() diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 388ab458d..41885e298 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -28,8 +28,6 @@ local basepath = core.get_builtin_path() defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. DIR_DELIM .. "pack" .. DIR_DELIM -dofile(menupath .. DIR_DELIM .. "misc.lua") - dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua") dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua") dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua") diff --git a/builtin/mainmenu/misc.lua b/builtin/mainmenu/misc.lua deleted file mode 100644 index 0677e96a3..000000000 --- a/builtin/mainmenu/misc.lua +++ /dev/null @@ -1,6 +0,0 @@ - --- old non-method sound function - -function core.sound_stop(handle, ...) - return handle:stop(...) -end diff --git a/builtin/mainmenu/serverlistmgr.lua b/builtin/mainmenu/serverlistmgr.lua index ab686ded0..997768c15 100644 --- a/builtin/mainmenu/serverlistmgr.lua +++ b/builtin/mainmenu/serverlistmgr.lua @@ -17,7 +17,7 @@ serverlistmgr = { -- continent code we detected for ourselves - my_continent = core.get_once("continent"), + my_continent = nil, -- list of locally favorites servers favorites = nil, @@ -26,6 +26,15 @@ serverlistmgr = { servers = nil, } +do + if check_cache_age("geoip_last_checked", 3600) then + local tmp = cache_settings:get("geoip") or "" + if tmp:match("^[A-Z][A-Z]$") then + serverlistmgr.my_continent = tmp + end + end +end + -------------------------------------------------------------------------------- -- Efficient data structure for normalizing arbitrary scores attached to objects -- e.g. {{"a", 3.14}, {"b", 3.14}, {"c", 20}, {"d", 0}} @@ -112,6 +121,22 @@ local public_downloading = false local geoip_downloading = false -------------------------------------------------------------------------------- +local function fetch_geoip() + local http = core.get_http_api() + local url = core.settings:get("serverlist_url") .. "/geoip" + + local response = http.fetch_sync({ url = url }) + if not response.succeeded then + return + end + + local retval = core.parse_json(response.data) + if type(retval) ~= "table" then + return + end + return type(retval.continent) == "string" and retval.continent +end + function serverlistmgr.sync() if not serverlistmgr.servers then serverlistmgr.servers = {{ @@ -129,37 +154,23 @@ function serverlistmgr.sync() return end - -- only fetched once per MT instance if not serverlistmgr.my_continent and not geoip_downloading then geoip_downloading = true - core.handle_async( - function(param) - local http = core.get_http_api() - local url = core.settings:get("serverlist_url") .. "/geoip" - - local response = http.fetch_sync({ url = url }) - if not response.succeeded then - return - end - - local retval = core.parse_json(response.data) - return retval and type(retval.continent) == "string" and retval.continent - end, - nil, - function(result) - geoip_downloading = false - if not result then - return - end - serverlistmgr.my_continent = result - core.set_once("continent", result) - -- reorder list if we already have it - if serverlistmgr.servers then - serverlistmgr.servers = order_server_list(serverlistmgr.servers) - core.event_handler("Refresh") - end + core.handle_async(fetch_geoip, nil, function(result) + geoip_downloading = false + if not result then + return end - ) + serverlistmgr.my_continent = result + cache_settings:set("geoip", result) + cache_settings:set("geoip_last_checked", tostring(os.time())) + + -- re-sort list if applicable + if serverlistmgr.servers then + serverlistmgr.servers = order_server_list(serverlistmgr.servers) + core.event_handler("Refresh") + end + end) end if public_downloading then @@ -167,6 +178,7 @@ function serverlistmgr.sync() end public_downloading = true + -- note: this isn't cached because it's way too dynamic core.handle_async( function(param) local http = core.get_http_api() diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua index 8c5573399..1805acc81 100644 --- a/builtin/mainmenu/tab_about.lua +++ b/builtin/mainmenu/tab_about.lua @@ -158,7 +158,7 @@ return { "style[label_button;border=false]" .. "button[0.1,3.4;5.3,0.5;label_button;" .. core.formspec_escape(version.project .. " " .. version.string) .. "]" .. - "button[1.5,4.1;2.5,0.8;homepage;minetest.net]" .. + "button_url[1.5,4.1;2.5,0.8;homepage;minetest.net;https://www.minetest.net/]" .. "hypertext[5.5,0.25;9.75,6.6;credits;" .. minetest.formspec_escape(hypertext) .. "]" -- Render information @@ -188,10 +188,6 @@ return { end, cbf_button_handler = function(this, fields, name, tabdata) - if fields.homepage then - core.open_url("https://www.minetest.net") - end - if fields.share_debug then local path = core.get_user_path() .. DIR_DELIM .. "debug.txt" core.share_file(path) diff --git a/builtin/mainmenu/tests/serverlistmgr_spec.lua b/builtin/mainmenu/tests/serverlistmgr_spec.lua index 25e208d10..21ce8a226 100644 --- a/builtin/mainmenu/tests/serverlistmgr_spec.lua +++ b/builtin/mainmenu/tests/serverlistmgr_spec.lua @@ -1,5 +1,6 @@ -_G.core = {get_once = function(_) end} +_G.core = {} _G.unpack = table.unpack +_G.check_cache_age = function() return false end _G.serverlistmgr = {} dofile("builtin/common/vector.lua") diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index cecf3d963..8ffb1c3c1 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -114,7 +114,11 @@ always_fly_fast (Always fly fast) bool true # the place button. # # Requires: keyboard_mouse -repeat_place_time (Place repetition interval) float 0.25 0.16 2 +repeat_place_time (Place repetition interval) float 0.25 0.15 2.0 + +# The minimum time in seconds it takes between digging nodes when holding +# the dig button. +repeat_dig_time (Dig repetition interval) float 0.15 0.15 2.0 # Automatically jump up single-node obstacles. autojump (Automatic jumping) bool false @@ -153,16 +157,21 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false # Requires: !android enable_touch (Enable touchscreen) bool true -# The length in pixels it takes for touchscreen interaction to start. -# -# Requires: touchscreen_gui -touchscreen_threshold (Touchscreen threshold) int 20 0 100 - # Touchscreen sensitivity multiplier. # # Requires: touchscreen_gui touchscreen_sensitivity (Touchscreen sensitivity) float 0.2 0.001 10.0 +# The length in pixels after which a touch interaction is considered movement. +# +# Requires: touchscreen_gui +touchscreen_threshold (Movement threshold) int 20 0 100 + +# The delay in milliseconds after which a touch interaction is considered a long tap. +# +# Requires: touchscreen_gui +touch_long_tap_delay (Threshold for long taps) int 400 100 1000 + # Use crosshair to select object instead of whole screen. # If enabled, a crosshair will be shown and will be used for selecting object. # @@ -181,6 +190,19 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false # Requires: touchscreen_gui virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false +# The gesture for for punching players/entities. +# This can be overridden by games and mods. +# +# * short_tap +# Easy to use and well-known from other games that shall not be named. +# +# * long_tap +# Known from the classic Minetest mobile controls. +# Combat is more or less impossible. +# +# Requires: touchscreen_gui +touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap + [Graphics and Audio] @@ -772,6 +794,7 @@ serverlist_url (Serverlist URL) string servers.minetest.net enable_split_login_register (Enable split login/register) bool true # URL to JSON file which provides information about the newest Minetest release +# If this is empty the engine will never check for updates. update_information_url (Update information URL) string https://www.minetest.net/release_info.json [*Server] @@ -1816,10 +1839,6 @@ video_driver (Video driver) enum ,opengl,opengl3,ogles1,ogles2 # Use this to limit the performance impact of transparency depth sorting transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128 -# Enable vertex buffer objects. -# This should greatly improve graphics performance. -enable_vbo (VBO) bool true - # Radius of cloud area stated in number of 64 node cloud squares. # Values larger than 26 will start to produce sharp cutoffs at cloud area corners. cloud_radius (Cloud radius) int 12 1 62 @@ -2291,20 +2310,6 @@ show_advanced (Show advanced settings) bool false # Changing this setting requires a restart. enable_sound (Sound) bool true -# Unix timestamp (integer) of when the client last checked for an update -# Set this value to "disabled" to never check for updates. -update_last_checked (Last update check) string - -# Version number which was last seen during an update check. -# -# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch -# Ex: 5.5.0 is 005005000 -update_last_known (Last known version update) int 0 - -# If this is set to true, the user will never (again) be shown the -# "reinstall Minetest Game" notification. -no_mtg_notification (Don't show "reinstall Minetest Game" notification) bool false - # Key for moving the player forward. keymap_forward (Forward key) key KEY_KEY_W diff --git a/client/shaders/Irrlicht b/client/shaders/Irrlicht new file mode 120000 index 000000000..9349d3073 --- /dev/null +++ b/client/shaders/Irrlicht @@ -0,0 +1 @@ +../../irr/media/Shaders \ No newline at end of file diff --git a/client/shaders/cloud_shader/opengl_fragment.glsl b/client/shaders/cloud_shader/opengl_fragment.glsl new file mode 100644 index 000000000..fe416d121 --- /dev/null +++ b/client/shaders/cloud_shader/opengl_fragment.glsl @@ -0,0 +1,17 @@ +uniform vec4 fogColor; +uniform float fogDistance; +uniform float fogShadingParameter; +varying vec3 eyeVec; + +varying lowp vec4 varColor; + +void main(void) +{ + vec4 col = varColor; + + float clarity = clamp(fogShadingParameter + - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); + col.rgb = mix(fogColor.rgb, col.rgb, clarity); + + gl_FragColor = col; +} diff --git a/client/shaders/cloud_shader/opengl_vertex.glsl b/client/shaders/cloud_shader/opengl_vertex.glsl new file mode 100644 index 000000000..4bc6eb65e --- /dev/null +++ b/client/shaders/cloud_shader/opengl_vertex.glsl @@ -0,0 +1,21 @@ +uniform vec4 emissiveColor; + +varying lowp vec4 varColor; + +varying vec3 eyeVec; + +void main(void) +{ + gl_Position = mWorldViewProj * inVertexPosition; + +#ifdef GL_ES + vec4 color = inVertexColor.bgra; +#else + vec4 color = inVertexColor; +#endif + + color *= emissiveColor; + varColor = color; + + eyeVec = -(mWorldView * inVertexPosition).xyz; +} diff --git a/client/shaders/stars_shader/opengl_fragment.glsl b/client/shaders/stars_shader/opengl_fragment.glsl index a9ed741bf..209b6dc89 100644 --- a/client/shaders/stars_shader/opengl_fragment.glsl +++ b/client/shaders/stars_shader/opengl_fragment.glsl @@ -1,6 +1,6 @@ -uniform vec4 starColor; +uniform vec4 emissiveColor; void main(void) { - gl_FragColor = starColor; + gl_FragColor = emissiveColor; } diff --git a/cmake/Modules/MinetestAndroidLibs.cmake b/cmake/Modules/MinetestAndroidLibs.cmake index a133976cb..02383903f 100644 --- a/cmake/Modules/MinetestAndroidLibs.cmake +++ b/cmake/Modules/MinetestAndroidLibs.cmake @@ -1,31 +1,27 @@ set(DEPS "${CMAKE_SOURCE_DIR}/android/native/deps/${ANDROID_ABI}") -add_library(IrrlichtMt::IrrlichtMt STATIC IMPORTED) -set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES ${DEPS}/Irrlicht/include) -set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES - IMPORTED_LOCATION ${DEPS}/Irrlicht/libIrrlichtMt.a) -set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES - INTERFACE_LINK_LIBRARIES "EGL;GLESv1_CM;GLESv2;${DEPS}/Irrlicht/libpng.a;${DEPS}/Irrlicht/libjpeg.a") - set(CURL_INCLUDE_DIR ${DEPS}/Curl/include) set(CURL_LIBRARY ${DEPS}/Curl/libcurl.a;${DEPS}/Curl/libmbedcrypto.a;${DEPS}/Curl/libmbedtls.a;${DEPS}/Curl/libmbedx509.a) -set(FREETYPE_INCLUDE_DIR_ft2build ${DEPS}/Freetype/include/freetype2) set(FREETYPE_INCLUDE_DIR_freetype2 ${FREETYPE_INCLUDE_DIR_ft2build}/freetype) +set(FREETYPE_INCLUDE_DIR_ft2build ${DEPS}/Freetype/include/freetype2) set(FREETYPE_LIBRARY ${DEPS}/Freetype/libfreetype.a) set(GETTEXT_INCLUDE_DIR ${DEPS}/Gettext/include;${DEPS}/Iconv/include) set(GETTEXT_LIBRARY ${DEPS}/Gettext/libintl.a) set(ICONV_LIBRARY ${DEPS}/Iconv/libiconv.a;${DEPS}/Iconv/libcharset.a) +set(JPEG_INCLUDE_DIR ${DEPS}/JPEG/include) +set(JPEG_LIBRARY ${DEPS}/JPEG/libjpeg.a) set(LUA_INCLUDE_DIR ${DEPS}/LuaJIT/include) set(LUA_LIBRARY ${DEPS}/LuaJIT/libluajit.a) set(OGG_INCLUDE_DIR ${DEPS}/Vorbis/include) set(OGG_LIBRARY ${DEPS}/Vorbis/libogg.a) set(OPENAL_INCLUDE_DIR ${DEPS}/OpenAL-Soft/include) set(OPENAL_LIBRARY ${DEPS}/OpenAL-Soft/libopenal.a;OpenSLES) +set(PNG_LIBRARY ${DEPS}/PNG/libpng.a) +set(PNG_PNG_INCLUDE_DIR ${DEPS}/PNG/include) set(SQLITE3_INCLUDE_DIR ${DEPS}/SQLite/include) set(SQLITE3_LIBRARY ${DEPS}/SQLite/libsqlite3.a) set(VORBIS_INCLUDE_DIR ${DEPS}/Vorbis/include) -set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a) set(VORBIS_LIBRARY ${DEPS}/Vorbis/libvorbis.a) +set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a) set(ZSTD_INCLUDE_DIR ${DEPS}/Zstd/include) set(ZSTD_LIBRARY ${DEPS}/Zstd/libzstd.a) diff --git a/cmake/Modules/MinetestFindIrrlichtHeaders.cmake b/cmake/Modules/MinetestFindIrrlichtHeaders.cmake deleted file mode 100644 index e434b582f..000000000 --- a/cmake/Modules/MinetestFindIrrlichtHeaders.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# Locate IrrlichtMt headers on system. - -find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h - DOC "Path to the directory with IrrlichtMt includes" - PATHS - /usr/local/include/irrlichtmt - /usr/include/irrlichtmt - /system/develop/headers/irrlichtmt #Haiku - PATH_SUFFIXES "include/irrlichtmt" -) - -# Handholding for users -if(IRRLICHT_INCLUDE_DIR AND (NOT IS_DIRECTORY "${IRRLICHT_INCLUDE_DIR}" OR - NOT EXISTS "${IRRLICHT_INCLUDE_DIR}/irrlicht.h")) - message(WARNING "IRRLICHT_INCLUDE_DIR was set to ${IRRLICHT_INCLUDE_DIR} " - "but irrlicht.h does not exist inside. The path will not be used.") - unset(IRRLICHT_INCLUDE_DIR CACHE) -endif() diff --git a/doc/compiling/README.md b/doc/compiling/README.md index febe4fbf7..a80a2e55c 100644 --- a/doc/compiling/README.md +++ b/doc/compiling/README.md @@ -54,8 +54,6 @@ Library specific options: GETTEXT_LIBRARY - Optional/platform-dependent with gettext; path to libintl.so/libintl.dll.a GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe ICONV_LIBRARY - Optional/platform-dependent; path to libiconv.so/libiconv.dylib - IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll - IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h (usable for server build only) LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll diff --git a/doc/compiling/linux.md b/doc/compiling/linux.md index 9d5e36b72..2dea68fab 100644 --- a/doc/compiling/linux.md +++ b/doc/compiling/linux.md @@ -2,47 +2,47 @@ ## Dependencies -| Dependency | Version | Commentary | -| ---------- | ------- | -------------------------------------------------------------------- | -| GCC | 7.5+ | or Clang 7.0.1+ | -| CMake | 3.5+ | | +| Dependency | Version | Commentary | +| ---------- | ------- | ---------- | +| GCC | 7.5+ | or Clang 7.0.1+ | +| CMake | 3.5+ | | | IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht | -| libjpeg | - | (via IrrlichtMt) | -| libpng | - | (via IrrlichtMt) | -| SDL | 2.x | (via IrrlichtMt) | -| Freetype | 2.0+ | | -| SQLite3 | 3+ | | -| Zlib | - | | -| Zstd | 1.0+ | | -| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present | -| GMP | 5.0.0+ | Bundled mini-GMP is used if not present | -| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present | -| Curl | 7.56.0+ | Optional | -| gettext | - | Optional | +| libjpeg | - | | +| libpng | - | | +| SDL | 2.x | | +| Freetype | 2.0+ | | +| SQLite3 | 3+ | | +| Zlib | - | | +| Zstd | 1.0+ | | +| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present | +| GMP | 5.0.0+ | Bundled mini-GMP is used if not present | +| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present | +| Curl | 7.56.0+ | Optional | +| gettext | - | Optional | For Debian/Ubuntu users: - sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev + sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev For Fedora users: - sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel + sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel For openSUSE users: - sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel SDL2-devel + sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libvorbis-devel freetype2-devel SDL2-devel For Arch users: - sudo pacman -S --needed base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2 + sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2 For Alpine users: - sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev + sudo apk add build-base cmake libpng-dev jpeg-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev For Void users: - sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext SDL2-devel + sudo xbps-install cmake libpng-devel jpeg-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext SDL2-devel ## Download @@ -73,24 +73,12 @@ Download source (this is the URL to the latest of source repository, which might git clone --depth 1 https://github.com/minetest/minetest.git cd minetest -Download IrrlichtMt to `lib/irrlichtmt`, it will be used to satisfy the IrrlichtMt dependency that way: - - git clone --depth 1 --branch "$(cat misc/irrlichtmt_tag.txt)" https://github.com/minetest/irrlicht.git lib/irrlichtmt - Download source, without using Git: wget https://github.com/minetest/minetest/archive/master.tar.gz tar xf master.tar.gz cd minetest-master -Download IrrlichtMt, without using Git: - - cd lib/ - wget https://github.com/minetest/irrlicht/archive/master.tar.gz - tar xf master.tar.gz - mv irrlicht-master irrlichtmt - cd .. - ## Build Build a version that runs directly from the source directory: @@ -109,13 +97,3 @@ Run it: * You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`. * You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=`. * Debug build is slower, but gives much more useful output in a debugger. -* If you build a bare server you don't need to compile IrrlichtMt, just the headers suffice. - * In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlichtmt/include`. - -* Minetest will use the IrrlichtMt package that is found first, given by the following order: - 1. Specified `IRRLICHTMT_BUILD_DIR` CMake variable - 2. `${PROJECT_SOURCE_DIR}/lib/irrlichtmt` (if existent) - 3. Installation of IrrlichtMt in the system-specific library paths - 4. For server builds with disabled `BUILD_CLIENT` variable, the headers from `IRRLICHT_INCLUDE_DIR` will be used. -> [!NOTE] -> Changing the IrrlichtMt build directory (includes system installs) requires regenerating the CMake cache (`rm CMakeCache.txt`) \ No newline at end of file diff --git a/doc/compiling/macos.md b/doc/compiling/macos.md index bef1301b3..e63bff650 100644 --- a/doc/compiling/macos.md +++ b/doc/compiling/macos.md @@ -19,12 +19,6 @@ git clone --depth 1 https://github.com/minetest/minetest.git cd minetest ``` -Download Minetest's fork of Irrlicht: - -```bash -git clone --depth 1 --branch "$(cat misc/irrlichtmt_tag.txt)" https://github.com/minetest/irrlicht.git lib/irrlichtmt -``` - ## Build ```bash diff --git a/doc/compiling/windows.md b/doc/compiling/windows.md index d9e5ad98b..3add62093 100644 --- a/doc/compiling/windows.md +++ b/doc/compiling/windows.md @@ -17,12 +17,6 @@ After you successfully built vcpkg you can easily install the required libraries vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp gettext sdl2 --triplet x64-windows ``` -* **Don't forget about IrrlichtMt.** The easiest way is to clone it to `lib/irrlichtmt`: - -```bat -for /F %i in (misc\irrlichtmt_tag.txt) do git clone --depth 1 --branch %i https://github.com/minetest/irrlicht.git lib\irrlichtmt -``` - * `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store. * `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound. * `luajit` is optional, it replaces the integrated Lua interpreter with a faster just-in-time interpreter. diff --git a/doc/developing/README.md b/doc/developing/README.md index 5272035a5..6ced745ec 100644 --- a/doc/developing/README.md +++ b/doc/developing/README.md @@ -15,6 +15,7 @@ Notable pages: ## In This Folder * [Developing minetestserver with Docker](docker.md) +* [Android Tips & Tricks](android.md) * [Miscellaneous](misc.md) ## IRC diff --git a/doc/developing/android.md b/doc/developing/android.md new file mode 100644 index 000000000..e278c48d8 --- /dev/null +++ b/doc/developing/android.md @@ -0,0 +1,63 @@ +# Android tips & tricks + +## Sign the Android APK from CI + +The [Github Actions Workflow](https://github.com/minetest/minetest/actions?query=workflow%3Aandroid+event%3Apush) +automatically produces an APK for each architecture. +Before installing them onto a device they however need to be signed. + +This requires an installation of the Android SDK and `adb`. +```bash +.../android-sdk/build-tools/30.0.3/apksigner sign --ks ~/.android/debug.keystore \ + app-arm64-v8a-release-unsigned.apk +# Enter 'android' (without quotes) when asked for a password +``` + +Note that the `debug.keystore` will not exist if you have never compiled an +Android app on your system (probably). + +After that installing it will work: +```bash +adb install -r -d ./app-arm64-v8a-release-unsigned.apk +``` + +## How to get debug output from Minetest on Android + +In case debug.txt isn't enough (e.g. when debugging a crash), you can get debug +output using logcat: + +`adb logcat -s 'Minetest:*' '*:F'` + +Note that you can do this even *after* the app has crashed, +since Android keeps an internal buffer. + +A segmentation fault for example looks like this: + +``` +01-10 17:20:22.215 19308 20560 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 20560 (MinetestNativeT), pid 19308 (netest.minetest) +01-10 17:20:22.287 20576 20576 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** +01-10 17:20:22.287 20576 20576 F DEBUG : Build fingerprint: '...' +01-10 17:20:22.287 20576 20576 F DEBUG : Revision: '4' +01-10 17:20:22.287 20576 20576 F DEBUG : ABI: 'arm64' +01-10 17:20:22.288 20576 20576 F DEBUG : Timestamp: 2024-01-10 17:20:22+0100 +01-10 17:20:22.288 20576 20576 F DEBUG : pid: 19308, tid: 20560, name: MinetestNativeT >>> net.minetest.minetest <<< +01-10 17:20:22.288 20576 20576 F DEBUG : uid: 10385 +01-10 17:20:22.288 20576 20576 F DEBUG : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- +[ ... more information follows ... ] +``` + +If you want get rid of previous output you can do that with `adb logcat -c`. + +## I edited builtin, shaders, ... but nothing changed. Help! + +You're probably hitting two problems: +* the build system only generates assets once +* the app only re-extracts assets when the version changes + +Force regenerating the assets: `./gradlew app:clean` + +Erase the app's memory of which version was installed: `adb shell run-as net.minetest.minetest rm shared_prefs/MinetestSettings.xml` + +If this doesn't work you can also uninstall it using `adb shell pm uninstall net.minetest.minetest`. You will obviously lose your data. + +Then build and install as normal and your changes should be applied. diff --git a/doc/developing/misc.md b/doc/developing/misc.md index fcf3f6ffc..dfecd031d 100644 --- a/doc/developing/misc.md +++ b/doc/developing/misc.md @@ -1,51 +1,5 @@ # Miscellaneous -## Sign the Android APK from CI - -The [Github Actions Workflow](https://github.com/minetest/minetest/actions?query=workflow%3Aandroid+event%3Apush) -automatically produces an APK for each architecture. -Before installing them onto a device they however need to be signed. - -This requires an installation of the Android SDK and `adb`. -```bash -.../android-sdk/build-tools/30.0.3/apksigner sign --ks ~/.android/debug.keystore \ - app-arm64-v8a-release-unsigned.apk -# Enter 'android' (without quotes) when asked for a password -``` - -Note that the `debug.keystore` will not exist if you have never compiled an -Android app on your system (probably). - -After that installing it will work: -```bash -adb install -r -d ./app-arm64-v8a-release-unsigned.apk -``` - -## How to get debug output from Minetest on Android - -In case debug.txt isn't enough (e.g. when debugging a crash), you can get debug -output using logcat: - -`adb logcat -s 'Minetest:*' '*:F'` - -Note that you can do this even *after* the app has crashed, -since Android keeps an internal buffer. - -A segmentation fault for example looks like this: - -``` -01-10 17:20:22.215 19308 20560 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 20560 (MinetestNativeT), pid 19308 (netest.minetest) -01-10 17:20:22.287 20576 20576 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** -01-10 17:20:22.287 20576 20576 F DEBUG : Build fingerprint: '...' -01-10 17:20:22.287 20576 20576 F DEBUG : Revision: '4' -01-10 17:20:22.287 20576 20576 F DEBUG : ABI: 'arm64' -01-10 17:20:22.288 20576 20576 F DEBUG : Timestamp: 2024-01-10 17:20:22+0100 -01-10 17:20:22.288 20576 20576 F DEBUG : pid: 19308, tid: 20560, name: MinetestNativeT >>> net.minetest.minetest <<< -01-10 17:20:22.288 20576 20576 F DEBUG : uid: 10385 -01-10 17:20:22.288 20576 20576 F DEBUG : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- -[ ... more information follows ... ] -``` - ## Profiling Minetest on Linux We will be using a tool called "perf", which you can get by installing `perf` or `linux-perf` or `linux-tools-common`. diff --git a/doc/docker_server.md b/doc/docker_server.md new file mode 100644 index 000000000..01a068536 --- /dev/null +++ b/doc/docker_server.md @@ -0,0 +1,46 @@ +# Docker Server + +We provide Minetest server Docker images using the GitHub container registry. + +Images are built on each commit and available using the following tag scheme: + +* `ghcr.io/minetest/minetest:master` (latest build) +* `ghcr.io/minetest/minetest:` (specific Git tag) +* `ghcr.io/minetest/minetest:latest` (latest Git tag, which is the stable release) + +See [here](https://github.com/minetest/minetest/pkgs/container/minetest) for all available tags. + +For a quick test you can easily run: + +```shell +docker run ghcr.io/minetest/minetest:master +``` + +To use it in a production environment, you should use volumes bound to the Docker host to persist data and modify the configuration: + +```shell +docker create -v /home/minetest/data/:/var/lib/minetest/ -v /home/minetest/conf/:/etc/minetest/ ghcr.io/minetest/minetest:master +``` + +You may also want to use [Docker Compose](https://docs.docker.com/compose): + +```yaml +--- +version: "2" +services: + minetest_server: + image: ghcr.io/minetest/minetest:master + restart: always + networks: + - default + volumes: + - /home/minetest/data/:/var/lib/minetest/ + - /home/minetest/conf/:/etc/minetest/ + ports: + - "30000:30000/udp" + - "127.0.0.1:30000:30000/tcp" +``` + +Data will be written to `/home/minetest/data` on the host, and configuration will be read from `/home/minetest/conf/minetest.conf`. + +**Note:** If you don't understand the previous commands please read the [official Docker documentation](https://docs.docker.com) before use. diff --git a/doc/lua_api.md b/doc/lua_api.md index 8deb0dc1a..757d5c802 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -652,8 +652,9 @@ The mask is applied using binary AND. #### `[sheet:x:,` -Retrieves a tile at position x,y from the base image -which it assumes to be a tilesheet with dimensions w,h. +Retrieves a tile at position x, y (in tiles, 0-indexed) +from the base image, which it assumes to be a tilesheet +with dimensions w, h (in tiles). #### `[colorize::` @@ -1085,6 +1086,7 @@ Table used to specify how a sound is played: -- its end in `-start_time` seconds. -- It is unspecified what happens if `loop` is false and `start_time` is -- smaller than minus the sound's length. + -- Available since feature `sound_params_start_time`. loop = false, @@ -1098,6 +1100,21 @@ Table used to specify how a sound is played: -- Attach the sound to an object. -- Can't be used together with `pos`. + -- For backward compatibility, sounds continue playing at the last location + -- of the object if an object is removed (for example if an entity dies). + -- It is not recommended to rely on this. + -- For death sounds, prefer playing a positional sound instead. + + -- If you want to stop a sound when an entity dies or is deactivated, + -- store the handle and call `minetest.sound_stop` in `on_die` / `on_deactivate`. + + -- Ephemeral sounds are entirely unaffected by the object being removed + -- or leaving the active object range. + + -- Non-ephemeral sounds stop playing on clients if objects leave + -- the active object range; they should start playing again if objects + --- come back into range (but due to a known bug, they don't yet). + to_player = name, -- Only play for this player. -- Can't be used together with `exclude_player`. @@ -1382,8 +1399,7 @@ Look for examples in `games/devtest` or `games/minetest_game`. * `liquid` * The cubic source node for a liquid. * Faces bordering to the same node are never rendered. - * Connects to node specified in `liquid_alternative_flowing`. - * You *must* set `liquid_alternative_source` to the node's own name. + * Connects to node specified in `liquid_alternative_flowing` if specified. * Use `backface_culling = false` for the tiles you want to make visible when inside the node. * `flowingliquid` @@ -2499,6 +2515,8 @@ Some of the values in the key-value store are handled specially: 0 = default, 1 = left / up, 2 = middle, 3 = right / down The default currently is the same as right/down. Example: 6 = 2 + 1*4 = middle,up +* `range`: Overrides the pointing range + Example: `meta:set_float("range", 4.2)` Example: @@ -2965,6 +2983,16 @@ background elements are drawn before all other elements. centered on `H`. With the new coordinate system, `H` will modify the height. * `label` is the text on the button +### `button_url[,;,;;