Updated to latest minetest.

This commit is contained in:
sonicx 2016-02-27 03:50:18 +01:00
commit c195a202f2
650 changed files with 188257 additions and 192891 deletions

94
.gitignore vendored
View File

@ -1,79 +1,87 @@
## Generic ignorable patterns and files
## Editors and Development environments
*~
.*.swp
*bak*
tags
*.vim
*.swp
*.bak*
*.orig
# Vim
*.vim
# Kate
.*.kate-swp
.swp.*
# KDevelop4
.kdev4/
*.kdev4
# Eclipse (CDT and LDT)
.project
.cproject
.settings/
.buildpath
.metadata
# GNU Global
tags
!tags/
gtags.files
## Files related to minetest development cycle
/*.patch
# GNU Patch reject file
*.rej
## Non-static Minetest directories
## Non-static Minetest directories or symlinks to these
/bin/
/games/*
!/games/minimal/
/cache/
/cache
/textures/*
!/textures/base/
/sounds/
/screenshots
/sounds
/mods/*
!/mods/minetest/
/mods/minetest/*
!/mods/minetest/mods_here.txt
/worlds/
/worlds
/world/
## Configuration/log files
minetest.conf
debug.txt
## Doxygen files
doc/Doxyfile
doc/html/
doc/doxygen_*
## Build files
CMakeFiles/*
src/CMakeFiles/*
src/Makefile
src/cmake_config.h
src/cmake_config_githash.h
src/cmake_install.cmake
src/script/CMakeFiles/*
src/script/common/CMakeFiles/*
src/script/cpp_api/CMakeFiles/*
src/script/lua_api/CMakeFiles/*
src/util/CMakeFiles/*
src/jthread/CMakeFiles/*
src/jthread/Makefile
src/jthread/cmake_config.h
src/jthread/cmake_install.cmake
src/jthread/libjthread.a
src/json/libjson.a
src/lua/build/
src/lua/CMakeFiles/
src/cguittfont/CMakeFiles/
src/cguittfont/libcguittfont.a
src/cguittfont/cmake_install.cmake
src/cguittfont/Makefile
src/json/CMakeFiles/
src/json/libjsoncpp.a
src/sqlite/CMakeFiles/*
src/sqlite/libsqlite3.a
CMakeFiles
Makefile
!build/android/Makefile
cmake_install.cmake
CMakeCache.txt
CPackConfig.cmake
CPackSourceConfig.cmake
Makefile
cmake_install.cmake
src/android_version.h
src/android_version_githash.h
src/cmake_config.h
src/cmake_config_githash.h
src/lua/build/
locale/
.directory
*.cbp
*.layout
*.o
*.a
#build variants
## Android build files
build/android/assets
build/android/bin
build/android/Debug
build/android/deps
build/android/gen
build/android/jni/src/*
build/android/jni/src
build/android/libs
build/android/obj
build/android/path.cfg
build/android/and_env
build/android/AndroidManifest.xml
timestamp

View File

@ -2,15 +2,28 @@ language: cpp
compiler:
- gcc
- clang
before_install:
- if [ $CC = "clang" ]; then export PATH="/usr/bin/:$PATH"; sudo sh -c 'echo "deb http://ppa.launchpad.net/eudoxos/llvm-3.1/ubuntu precise main" >> /etc/apt/sources.list'; sudo apt-key adv --keyserver pool.sks-keyservers.net --recv-keys 92DE8183; sudo apt-get update; sudo apt-get install llvm-3.1; sudo apt-get install clang; fi
- sudo apt-get install libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev
script:
- mkdir -p travisbuild
- cd travisbuild
- cmake ..
- make -j2
os:
- osx
- linux
env:
- PLATFORM=Win32
- PLATFORM=Win64
- PLATFORM=Unix
before_install: ./util/travis/before_install.sh
script: ./util/travis/script.sh
sudo: required
notifications:
email: false
matrix:
fast_finish: true
exclude:
- env: PLATFORM=Win32
compiler: clang
- env: PLATFORM=Win64
compiler: clang
- env: PLATFORM=Win32
os: osx
- env: PLATFORM=Win64
os: osx
- compiler: gcc
os: osx

View File

@ -1,69 +1,64 @@
cmake_minimum_required(VERSION 2.6)
if(${CMAKE_VERSION} STREQUAL "2.8.2")
# bug http://vtk.org/Bug/view.php?id=11020
message( WARNING "CMake/CPack version 2.8.2 will not create working .deb packages!")
endif(${CMAKE_VERSION} STREQUAL "2.8.2")
# Bug http://vtk.org/Bug/view.php?id=11020
message(WARNING "CMake/CPack version 2.8.2 will not create working .deb packages!")
endif()
# This can be read from ${PROJECT_NAME} after project() is called
project(minetest)
set(PROJECT_NAME_CAPITALIZED "Minetest")
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
set(VERSION_PATCH 10)
set(VERSION_PATCH_ORIG ${VERSION_PATCH})
set(VERSION_PATCH 13)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Change to false for releases
set(DEVELOPMENT_BUILD TRUE)
if(VERSION_EXTRA)
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
else()
# Comment the following line during release
set(VERSION_PATCH ${VERSION_PATCH}-dev)
endif()
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
if(VERSION_EXTRA)
set(VERSION_STRING ${VERSION_STRING}-${VERSION_EXTRA})
elseif(DEVELOPMENT_BUILD)
set(VERSION_STRING "${VERSION_STRING}-dev")
endif()
message(STATUS "*** Will build version ${VERSION_STRING} ***")
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
# Configuration options
set(DEFAULT_RUN_IN_PLACE FALSE)
if(WIN32)
set(RUN_IN_PLACE 1 CACHE BOOL "Run directly in source directory structure")
else()
set(RUN_IN_PLACE 0 CACHE BOOL "Run directly in source directory structure")
set(DEFAULT_RUN_IN_PLACE TRUE)
endif()
set(RUN_IN_PLACE ${DEFAULT_RUN_IN_PLACE} CACHE BOOL
"Run directly in source directory structure")
# RUN_IN_PLACE is exported as a #define value, ensure it's 1/0 instead of ON/OFF
if(RUN_IN_PLACE)
set(RUN_IN_PLACE 1)
else()
set(RUN_IN_PLACE 0)
endif()
set(BUILD_CLIENT 1 CACHE BOOL "Build client")
if(WIN32)
set(BUILD_SERVER 0 CACHE BOOL "Build server")
else()
set(BUILD_SERVER 1 CACHE BOOL "Build server")
endif()
set(BUILD_CLIENT TRUE CACHE BOOL "Build client")
set(BUILD_SERVER FALSE CACHE BOOL "Build server")
set(WARN_ALL 1 CACHE BOOL "Enable -Wall for Release build")
set(WARN_ALL TRUE CACHE BOOL "Enable -Wall for Release build")
if(NOT CMAKE_BUILD_TYPE)
# Default to release
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type: Debug or Release" FORCE)
endif()
# Included stuff
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
include(${CMAKE_SOURCE_DIR}/cmake/Modules/misc.cmake)
# This is done here so that relative search paths are more reasnable
# This is done here so that relative search paths are more reasonable
find_package(Irrlicht)
#
# Installation
#
if(WIN32)
set(SHAREDIR ".")
@ -72,11 +67,13 @@ if(WIN32)
set(EXAMPLE_CONF_DIR ".")
set(LOCALEDIR "locale")
elseif(APPLE)
set(SHAREDIR ".")
set(BINDIR "./bin")
set(DOCDIR "./doc/${PROJECT_NAME}")
set(BUNDLE_NAME ${PROJECT_NAME}.app)
set(BUNDLE_PATH "${BUNDLE_NAME}")
set(BINDIR ${BUNDLE_NAME}/Contents/MacOS)
set(SHAREDIR ${BUNDLE_NAME}/Contents/Resources)
set(DOCDIR "${SHAREDIR}/${PROJECT_NAME}")
set(EXAMPLE_CONF_DIR ${DOCDIR})
set(LOCALEDIR "locale")
set(LOCALEDIR "${SHAREDIR}/locale")
elseif(UNIX) # Linux, BSD etc
if(RUN_IN_PLACE)
set(SHAREDIR ".")
@ -106,54 +103,55 @@ if(NOT CUSTOM_SHAREDIR STREQUAL "")
set(SHAREDIR "${CUSTOM_SHAREDIR}")
message(STATUS "Using SHAREDIR=${SHAREDIR}")
endif()
set(CUSTOM_BINDIR "" CACHE STRING "Directory to install binaries into")
if(NOT CUSTOM_BINDIR STREQUAL "")
set(BINDIR "${CUSTOM_BINDIR}")
message(STATUS "Using BINDIR=${BINDIR}")
endif()
set(CUSTOM_DOCDIR "" CACHE STRING "Directory to install documentation into")
if(NOT CUSTOM_DOCDIR STREQUAL "")
set(DOCDIR "${CUSTOM_DOCDIR}")
message(STATUS "Using DOCDIR=${DOCDIR}")
endif()
set(CUSTOM_MANDIR "" CACHE STRING "Directory to install manpages into")
if(NOT CUSTOM_MANDIR STREQUAL "")
set(MANDIR "${CUSTOM_MANDIR}")
message(STATUS "Using MANDIR=${MANDIR}")
endif()
set(CUSTOM_EXAMPLE_CONF_DIR "" CACHE STRING "Directory to install example config file into")
if(NOT CUSTOM_EXAMPLE_CONF_DIR STREQUAL "")
set(EXAMPLE_CONF_DIR "${CUSTOM_EXAMPLE_CONF_DIR}")
message(STATUS "Using EXAMPLE_CONF_DIR=${EXAMPLE_CONF_DIR}")
endif()
set(CUSTOM_XDG_APPS_DIR "" CACHE STRING "Directory to install .desktop files into")
if(NOT CUSTOM_XDG_APPS_DIR STREQUAL "")
set(XDG_APPS_DIR "${CUSTOM_XDG_APPS_DIR}")
message(STATUS "Using XDG_APPS_DIR=${XDG_APPS_DIR}")
endif()
set(CUSTOM_ICONDIR "" CACHE STRING "Directory to install icons into")
if(NOT CUSTOM_ICONDIR STREQUAL "")
set(ICONDIR "${CUSTOM_ICONDIR}")
message(STATUS "Using ICONDIR=${ICONDIR}")
endif()
set(CUSTOM_LOCALEDIR "" CACHE STRING "Directory to install l10n files into")
if(NOT CUSTOM_LOCALEDIR STREQUAL "")
set(LOCALEDIR "${CUSTOM_LOCALEDIR}")
message(STATUS "Using LOCALEDIR=${LOCALEDIR}")
endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minimal" DESTINATION "${SHAREDIR}/games")
set(MINETEST_GAME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game")
if(EXISTS ${MINETEST_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_GAME_SOURCE})
install(FILES ${MINETEST_GAME_SOURCE}/game.conf DESTINATION "${SHAREDIR}/games/minetest_game/")
install(FILES ${MINETEST_GAME_SOURCE}/README.txt DESTINATION "${SHAREDIR}/games/minetest_game/")
install(DIRECTORY ${MINETEST_GAME_SOURCE}/mods DESTINATION "${SHAREDIR}/games/minetest_game")
install(DIRECTORY ${MINETEST_GAME_SOURCE}/menu DESTINATION "${SHAREDIR}/games/minetest_game")
endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games" DESTINATION "${SHAREDIR}" PATTERN ".git*" EXCLUDE)
if(BUILD_CLIENT)
#install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/sounds/base/pack" DESTINATION "${SHAREDIR}/sounds/base")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/textures/base/pack" DESTINATION "${SHAREDIR}/textures/base")
endif()
if(RUN_IN_PLACE)
@ -166,23 +164,28 @@ install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/fonts" DESTINATION "${SHAREDIR}")
install(FILES "README.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/lua_api.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/menu_lua_api.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/mapformat.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/world_format.txt" DESTINATION "${DOCDIR}")
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
if(UNIX AND NOT APPLE)
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
install(FILES "misc/minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
install(FILES "misc/minetest.appdata.xml" DESTINATION "${APPDATADIR}")
install(FILES "misc/minetest-icon.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
endif()
#
if(APPLE)
install(FILES "misc/minetest-icon.icns" DESTINATION "${SHAREDIR}")
install(FILES "misc/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents")
endif()
# Subdirectories
# Be sure to add all relevant definitions above this
#
add_subdirectory(src)
# CPack
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An InfiniMiner/Minecraft inspired game")
@ -193,34 +196,17 @@ set(CPACK_PACKAGE_VENDOR "celeron55")
set(CPACK_PACKAGE_CONTACT "Perttu Ahola <celeron55@gmail.com>")
if(WIN32)
# For some reason these aren't copied otherwise
# NOTE: For some reason now it seems to work without these
#if(BUILD_CLIENT)
# install(FILES bin/minetest.exe DESTINATION bin)
#endif()
#if(BUILD_SERVER)
# install(FILES bin/minetestserver.exe DESTINATION bin)
#endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-win64")
else(CMAKE_SIZEOF_VOID_P EQUAL 8)
else()
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-win32")
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
endif()
set(CPACK_GENERATOR ZIP)
# This might be needed for some installer
#set(CPACK_PACKAGE_EXECUTABLES bin/minetest.exe "Minetest" bin/minetestserver.exe "Minetest Server")
elseif(APPLE)
# see http://cmake.org/Wiki/CMake:CPackPackageGenerators#Bundle_.28OSX_only.29
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-osx")
set(CPACK_PACKAGE_ICON ${CMAKE_CURRENT_SOURCE_DIR}/misc/mac/minetest-icon.icns)
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
set(CPACK_BUNDLE_ICON ${CPACK_PACKAGE_ICON})
set(CPACK_BUNDLE_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/misc/mac/Info.plist)
set(CPACK_BUNDLE_STARTUP_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/misc/mac/minetest-mac.sh)
set(CPACK_GENERATOR "Bundle")
set(CPACK_GENERATOR ZIP)
else()
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux")
set(CPACK_GENERATOR TGZ)
@ -229,3 +215,16 @@ endif()
include(CPack)
# Add a target to generate API documentation with Doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
endif()

View File

@ -1,4 +1,4 @@
Minetest
Minetest
========
An InfiniMiner/Minecraft inspired game.
@ -78,9 +78,9 @@ $share = /usr/share/minetest
$user = ~/.minetest
OS X:
$bin = ?
$share = ?
$user = ~/Library/Application Support/minetest
$bin = Contents/MacOS
$share = Contents/Resources
$user = Contents/User OR ~/Library/Application Support/minetest
World directory
----------------
@ -103,34 +103,54 @@ Compiling on GNU/Linux:
-----------------------
Install dependencies. Here's an example for Debian/Ubuntu:
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev
$ sudo apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
$ wget https://github.com/minetest/minetest/tarball/master -O master.tar.gz
For Fedora users:
$ sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl* openal* libvorbis* libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel irrlicht-devel bzip2-libs gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel doxygen spatialindex-dev bzip2-dev
You can install git for easily keeping your copy up to date.
If you dont want git, read below on how to get the source without git.
This is an example for installing git on Debian/Ubuntu:
$ sudo apt-get install git-core
For Fedora users:
$ sudo dnf install git-core
Download source (this is the URL to the latest of source repository, which might not work at all times) using git:
$ git clone --depth 1 https://github.com/minetest/minetest.git
$ cd minetest
Download minetest_game (otherwise only the "Minimal development test" game is available) using git:
$ git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
Download source, without using git:
$ wget https://github.com/minetest/minetest/archive/master.tar.gz
$ tar xf master.tar.gz
$ cd minetest-minetest-286edd4 (or similar)
$ cd minetest-master
Download minetest_game (otherwise only the "Minimal development test" game is available)
Download minetest_game, without using git:
$ cd games/
$ wget https://github.com/minetest/minetest_game/tarball/master -O minetest_game.tar.gz
$ tar xf minetest_game.tar.gz
$ mv minetest-minetest_game-* minetest_game
$ wget https://github.com/minetest/minetest_game/archive/master.tar.gz
$ tar xf master.tar.gz
$ mv minetest_game-master minetest_game
$ cd ..
Build a version that runs directly from the source directory:
$ cmake . -DRUN_IN_PLACE=1
$ make -j2
$ cmake . -DRUN_IN_PLACE=TRUE
$ make -j <number of processors>
Run it:
$ cd bin
$ ./minetest
$ ./bin/minetest
- Use cmake . -LH to see all CMake options and their current state
- If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0
- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
- If you want to install it system-wide (or are making a distribution package),
you will want to use -DRUN_IN_PLACE=FALSE
- You can build a bare server by specifying -DBUILD_SERVER=TRUE
- You can disable the client build by specifying -DBUILD_CLIENT=FALSE
- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
- Debug build is slower, but gives much more useful output in a debugger
- If you build a bare server, you don't need to have Irrlicht installed. In that case use -DIRRLICHT_SOURCE_DIR=/the/irrlicht/source
- If you build a bare server, you don't need to have Irrlicht installed.
In that case use -DIRRLICHT_SOURCE_DIR=/the/irrlicht/source
CMake options
-------------
@ -141,16 +161,20 @@ BUILD_SERVER - Build Minetest server
CMAKE_BUILD_TYPE - Type of build (Release vs. Debug)
Release - Release build
Debug - Debug build
SemiDebug - Partially optimized debug build
RelWithDebInfo - Release build with Debug information
MinSizeRel - Release build with -Os passed to compiler to make executable as small as possible
ENABLE_CURL - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
ENABLE_FREETYPE - Build with Freetype2; Allows using TTF fonts
ENABLE_CURSES - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_FREETYPE - Build with FreeType2; Allows using TTF fonts
ENABLE_GETTEXT - Build with Gettext; Allows using translations
ENABLE_GLES - Search for Open GLES headers & libraries and use them
ENABLE_LEVELDB - Build with LevelDB; Enables use of LevelDB, which is much faster than SQLite, as map backend
ENABLE_REDIS - Build with libhiredis; Enables use of redis map backend
ENABLE_LEVELDB - Build with LevelDB; Enables use of LevelDB map backend (faster than SQLite3)
ENABLE_REDIS - Build with libhiredis; Enables use of Redis map backend
ENABLE_SPATIAL - Build with LibSpatial; Speeds up AreaStores
ENABLE_SOUND - Build with OpenAL, libogg & libvorbis; in-game Sounds
DISABLE_LUAJIT - Do not search for LuaJIT headers & library
ENABLE_LUAJIT - Build with LuaJIT (much faster than non-JIT Lua)
ENABLE_SYSTEM_GMP - Use GMP from system (much faster than bundled mini-gmp)
RUN_IN_PLACE - Create a portable install (worlds, settings etc. in current directory)
USE_GPROF - Enable profiling using GProf
VERSION_EXTRA - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar)
@ -163,7 +187,7 @@ CURL_DLL - Only if building with cURL on Windows; path to
CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located
CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib
EGL_INCLUDE_DIR - Only if building with GLES; directory that contains egl.h
EGL_egl_LIBRARY - Only if building with GLES; path to libEGL.a/libEGL.so
EGL_LIBRARY - Only if building with GLES; path to libEGL.a/libEGL.so
FREETYPE_INCLUDE_DIR_freetype2 - Only if building with Freetype2; directory that contains an freetype directory with files such as ftimage.h in it
FREETYPE_INCLUDE_DIR_ft2build - Only if building with Freetype2; directory that contains ft2build.h
FREETYPE_LIBRARY - Only if building with Freetype2; path to libfreetype.a/libfreetype.so/freetype.lib
@ -173,14 +197,16 @@ GETTEXT_ICONV_DLL - Only when building with Gettext on Windows; pa
GETTEXT_INCLUDE_DIR - Only when building with Gettext; directory that contains iconv.h
GETTEXT_LIBRARY - Only when building with Gettext on Windows; path to libintl.dll.a
GETTEXT_MSGFMT - Only when building with Gettext; path to msgfmt/msgfmt.exe
IRRLICHT_DLL - path to Irrlicht.dll
IRRLICHT_INCLUDE_DIR - directory that contains IrrCompileConfig.h
IRRLICHT_LIBRARY - path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a
IRRLICHT_DLL - Only on Windows; path to Irrlicht.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h
IRRLICHT_LIBRARY - Path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a/Irrlicht.lib
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
REDIS_INCLUDE_DIR - Only when building with redis support; directory that contains hiredis.h
REDIS_LIBRARY - Only when building with redis support; path to libhiredis.a/libhiredis.so
REDIS_INCLUDE_DIR - Only when building with Redis; directory that contains hiredis.h
REDIS_LIBRARY - Only when building with Redis; path to libhiredis.a/libhiredis.so
SPATIAL_INCLUDE_DIR - Only when building with LibSpatial; directory that contains spatialindex/SpatialIndex.h
SPATIAL_LIBRARY - Only when building with LibSpatial; path to libspatialindex_c.so/spatialindex-32.lib
LUA_INCLUDE_DIR - Only if you want to use LuaJIT; directory where luajit.h is located
LUA_LIBRARY - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so
MINGWM10_DLL - Only if compiling with MinGW; path to mingwm10.dll
@ -191,9 +217,9 @@ OPENAL_DLL - Only if building with sound on Windows; path t
OPENAL_INCLUDE_DIR - Only if building with sound; directory where al.h is located
OPENAL_LIBRARY - Only if building with sound; path to libopenal.a/libopenal.so/OpenAL32.lib
OPENGLES2_INCLUDE_DIR - Only if building with GLES; directory that contains gl2.h
OPENGLES2_gl_LIBRARY - Only if building with GLES; path to libGLESv2.a/libGLESv2.so
SQLITE3_INCLUDE_DIR - Only if you want to use SQLite from your OS; directory that contains sqlite3.h
SQLITE3_LIBRARY - Only if you want to use the SQLite from your OS; path to libsqlite3.a/libsqlite3.so
OPENGLES2_LIBRARY - Only if building with GLES; path to libGLESv2.a/libGLESv2.so
SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h
SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib
VORBISFILE_DLL - Only if building with sound on Windows; path to libvorbisfile-3.dll
VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a
VORBIS_DLL - Only if building with sound on Windows; path to libvorbis-0.dll
@ -202,8 +228,8 @@ VORBIS_LIBRARY - Only if building with sound; path to libvorbis
XXF86VM_LIBRARY - Only on Linux; path to libXXf86vm.a/libXXf86vm.so
ZLIB_DLL - Only on Windows; path to zlib1.dll
ZLIBWAPI_DLL - Only on Windows; path to zlibwapi.dll
ZLIB_INCLUDE_DIR - directory where zlib.h is located
ZLIB_LIBRARY - path to libz.a/libz.so/zlibwapi.lib
ZLIB_INCLUDE_DIR - Directory that contains zlib.h
ZLIB_LIBRARY - Path to libz.a/libz.so/zlibwapi.lib
Compiling on Windows:
---------------------
@ -227,7 +253,7 @@ Compiling on Windows:
http://gnuwin32.sourceforge.net/downlinks/gettext.php
- This is used for other UI languages. Feel free to leave it out.
* And, of course, Minetest:
http://minetest.net/download.php
http://minetest.net/download
- Steps:
- Select a directory called DIR hereafter in which you will operate.
- Make sure you have CMake and a compiler installed.
@ -325,7 +351,7 @@ set irrlichtpath="C:\tmp\irrlicht-1.7.2"
set builddir=%sourcedir%\bvc10
mkdir %builddir%
pushd %builddir%
cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DRUN_IN_PLACE=1 -DCMAKE_INSTALL_PREFIX=%installpath%
cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DRUN_IN_PLACE=TRUE -DCMAKE_INSTALL_PREFIX=%installpath%
if %errorlevel% neq 0 goto fail
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" ALL_BUILD.vcxproj /p:Configuration=Release
if %errorlevel% neq 0 goto fail
@ -362,7 +388,7 @@ BlockMen:
erlehmann:
misc/minetest-icon-24x24.png
misc/minetest-icon.ico
misc/minetest-icon.svg
misc/minetest.svg
textures/base/pack/logo.png
License of Minetest source code

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.minetest.minetest"
package="net.minetest.minetest"
android:versionCode="###ANDROID_VERSION###"
android:versionName="###BASE_VERSION###.###ANDROID_VERSION###"
android:installLocation="auto">
@ -14,8 +14,8 @@
<activity android:name=".MtNativeActivity"
android:label="Minetest"
android:launchMode="singleTask"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboard|keyboardHidden|navigation"
android:screenOrientation="sensorLandscape"
android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -2,13 +2,6 @@
OS := $(shell uname)
#automaticaly set number of jobs
ifeq ($(OS),Linux)
PARALLEL := $(shell grep -c ^processor /proc/cpuinfo)
else
PARALLEL := 1
endif
# compile with GPROF
# GPROF = 1
@ -20,38 +13,50 @@ PATHCFGFILE = path.cfg
ROOT = $(shell pwd)
GAMES_TO_COPY = minetest_game
MODS_TO_COPY =
VERSION_MAJOR := $(shell cat $(ROOT)/../../CMakeLists.txt | \
grep ^set\(VERSION_MAJOR\ | sed 's/)/ /' | cut -f2 -d' ')
VERSION_MINOR := $(shell cat $(ROOT)/../../CMakeLists.txt | \
grep ^set\(VERSION_MINOR\ | sed 's/)/ /' | cut -f2 -d' ')
VERSION_PATCH := $(shell cat $(ROOT)/../../CMakeLists.txt | \
grep ^set\(VERSION_PATCH\ | sed 's/)/ /' | cut -f2 -d' ')
################################################################################
# Android Version code
# Increase for each build!
################################################################################
ANDROID_VERSION_CODE = 4
# Play Store actual version (16/03/15): 11
ANDROID_VERSION_CODE = 13
################################################################################
# toolchain config for arm old processors
################################################################################
TARGET_HOST = arm-linux
TARGET_ABI = armeabi
TARGET_LIBDIR = armeabi
TARGET_TOOLCHAIN = arm-linux-androideabi-
TARGET_CFLAGS_ADDON = -mfloat-abi=softfp -mfpu=vfp
CROSS_PREFIX = arm-linux-androideabi-
COMPILER_VERSION = 4.8
HAVE_LEVELDB = 1
#TARGET_HOST = arm-linux
#TARGET_ABI = armeabi
#TARGET_LIBDIR = armeabi
#TARGET_TOOLCHAIN = arm-linux-androideabi-
#TARGET_CFLAGS_ADDON = -mfloat-abi=softfp -mfpu=vfp
#TARGET_ARCH = arm
#CROSS_PREFIX = arm-linux-androideabi-
#COMPILER_VERSION = 4.8
#HAVE_LEVELDB = 1
################################################################################
# toolchain config for arm new processors
################################################################################
#TARGET_HOST = arm-linux
#TARGET_ABI = armeabi-v7a-hard
#TARGET_LIBDIR = armeabi-v7a
#TARGET_TOOLCHAIN = arm-linux-androideabi-
#TARGET_CFLAGS_ADDON = -mfpu=vfpv3-d16 -D_NDK_MATH_NO_SOFTFP=1 \
# -mfloat-abi=hard -march=armv7-a
#TARGET_CXXFLAGS_ADDON = $(TARGET_CFLAGS_ADDON)
#TARGET_LDFLAGS_ADDON = -Wl,--no-warn-mismatch -lm_hard
#CROSS_PREFIX = arm-linux-androideabi-
#COMPILER_VERSION = 4.8
#HAVE_LEVELDB = 1
TARGET_HOST = arm-linux
TARGET_ABI = armeabi-v7a
TARGET_LIBDIR = armeabi-v7a
TARGET_TOOLCHAIN = arm-linux-androideabi-
TARGET_CFLAGS_ADDON = -mfloat-abi=softfp -mfpu=vfpv3
TARGET_CXXFLAGS_ADDON = $(TARGET_CFLAGS_ADDON)
TARGET_ARCH = armv7
CROSS_PREFIX = arm-linux-androideabi-
COMPILER_VERSION = 4.8
HAVE_LEVELDB = 1
################################################################################
# toolchain config for little endian mips
@ -60,6 +65,7 @@ HAVE_LEVELDB = 1
#TARGET_ABI = mips
#TARGET_LIBDIR = mips
#TARGET_TOOLCHAIN = mipsel-linux-android-
#TARGET_ARCH = mips32
#CROSS_PREFIX = mipsel-linux-android-
#COMPILER_VERSION = 4.8
#HAVE_LEVELDB = 0
@ -72,6 +78,7 @@ HAVE_LEVELDB = 1
#TARGET_LIBDIR = x86
#TARGET_TOOLCHAIN = x86-
#CROSS_PREFIX = i686-linux-android-
#TARGET_ARCH = x86
#COMPILER_VERSION = 4.8
#HAVE_LEVELDB = 1
@ -82,7 +89,8 @@ LEVELDB_DIR = $(ROOT)/deps/leveldb/
LEVELDB_LIB = $(LEVELDB_DIR)libleveldb.a
LEVELDB_TIMESTAMP = $(LEVELDB_DIR)/timestamp
LEVELDB_TIMESTAMP_INT = $(ROOT)/deps/leveldb_timestamp
LEVELDB_URL_GIT = https://code.google.com/p/leveldb/
LEVELDB_URL_GIT = https://github.com/google/leveldb
LEVELDB_COMMIT = 2d0320a458d0e6a20fff46d5f80b18bfdcce7018
OPENAL_DIR = $(ROOT)/deps/openal-soft/
OPENAL_LIB = $(OPENAL_DIR)libs/$(TARGET_ABI)/libopenal.so
@ -97,38 +105,62 @@ OGG_TIMESTAMP = $(OGG_DIR)timestamp
OGG_TIMESTAMP_INT = $(ROOT)/deps/ogg_timestamp
OGG_URL_GIT = https://github.com/vincentjames501/libvorbis-libogg-android
IRRLICHT_REVISION = 5122
IRRLICHT_DIR = $(ROOT)/deps/irrlicht/
IRRLICHT_LIB = $(IRRLICHT_DIR)lib/Android/libIrrlicht.a
IRRLICHT_TIMESTAMP = $(IRRLICHT_DIR)timestamp
IRRLICHT_TIMESTAMP_INT = $(ROOT)/deps/irrlicht_timestamp
IRRLICHT_URL_SVN = http://svn.code.sf.net/p/irrlicht/code/branches/ogl-es/
IRRLICHT_URL_SVN = http://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@$(IRRLICHT_REVISION)
OPENSSL_BASEDIR = openssl-android
OPENSSL_VERSION = 1.0.1p
OPENSSL_BASEDIR = openssl-$(OPENSSL_VERSION)
OPENSSL_DIR = $(ROOT)/deps/$(OPENSSL_BASEDIR)/
OPENSSL_LIB = $(OPENSSL_DIR)libs/$(TARGET_ABI)/libopenssl.so
OPENSSL_LIB = $(OPENSSL_DIR)/libssl.so.1.0.0
OPENSSL_TIMESTAMP = $(OPENSSL_DIR)timestamp
OPENSSL_TIMESTAMP_INT = $(ROOT)/deps/openssl_timestamp
OPENSSL_URL_GIT = https://github.com/wobbals/openssl-android
OPENSSL_URL = http://www.openssl.org/source/openssl-$(OPENSSL_VERSION).tar.gz
CURL_VERSION = 7.35.0
CURL_VERSION = 7.45.0
CURL_DIR = $(ROOT)/deps/curl-$(CURL_VERSION)
CURL_LIB = $(CURL_DIR)/lib/.libs/libcurl.a
CURL_TIMESTAMP = $(CURL_DIR)/timestamp
CURL_TIMESTAMP_INT = $(ROOT)/deps/curl_timestamp
CURL_URL_HTTP = http://curl.haxx.se/download/curl-${CURL_VERSION}.tar.bz2
GMP_VERSION = 6.1.0
GMP_DIR = $(ROOT)/deps/gmp-$(GMP_VERSION)
GMP_LIB = $(GMP_DIR)/usr/lib/libgmp.so
GMP_TIMESTAMP = $(GMP_DIR)/timestamp
GMP_TIMESTAMP_INT = $(ROOT)/deps/gmp_timestamp
GMP_URL_HTTP = https://gmplib.org/download/gmp/gmp-$(GMP_VERSION).tar.bz2
FREETYPE_DIR = $(ROOT)/deps/freetype2-android/
FREETYPE_LIB = $(FREETYPE_DIR)/Android/obj/local/$(TARGER_ABI)/libfreetype2-static.a
FREETYPE_LIB = $(FREETYPE_DIR)/Android/obj/local/$(TARGET_ABI)/libfreetype2-static.a
FREETYPE_TIMESTAMP = $(FREETYPE_DIR)timestamp
FREETYPE_TIMESTAMP_INT = $(ROOT)/deps/freetype_timestamp
FREETYPE_URL_GIT = https://github.com/cdave1/freetype2-android
ICONV_VERSION = 1.14
ICONV_DIR = $(ROOT)/deps/libiconv/
ICONV_LIB = $(ICONV_DIR)/lib/.libs/libiconv.so
ICONV_TIMESTAMP = $(ICONV_DIR)timestamp
ICONV_TIMESTAMP_INT = $(ROOT)/deps/iconv_timestamp
ICONV_URL_HTTP = http://ftp.gnu.org/pub/gnu/libiconv/libiconv-$(ICONV_VERSION).tar.gz
SQLITE3_FOLDER = sqlite-amalgamation-3090200
SQLITE3_URL = http://www.sqlite.org/2015/$(SQLITE3_FOLDER).zip
-include $(PATHCFGFILE)
#use interim target variable to switch leveldb on or off
ifeq ($(HAVE_LEVELDB),1)
LEVELDB_TARGET = $(LEVELDB_LIB)
endif
.PHONY : debug release reconfig delconfig \
leveldb_download clean_leveldb leveldb\
irrlicht_download clean_irrlicht irrlicht \
clean_assets assets \
clean_assets assets sqlite3_download \
freetype_download clean_freetype freetype \
apk clean_apk \
clean_all clean prep_srcdir \
@ -137,28 +169,24 @@ FREETYPE_URL_GIT = https://github.com/cdave1/freetype2-android
$(ASSETS_TIMESTAMP) $(LEVELDB_TIMESTAMP) \
$(OPENAL_TIMESTAMP) $(OGG_TIMESTAMP) \
$(IRRLICHT_TIMESTAMP) $(CURL_TIMESTAMP) \
$(OPENSSL_TIMESTAMP) curl_binary \
$(ROOT)/jni/src/android_version.h
#use interim target variable to switch leveldb on or off
ifeq ($(HAVE_LEVELDB),1)
LEVELDB_TARGET = $(LEVELDB_LIB)
endif
$(OPENSSL_TIMESTAMP) \
$(ROOT)/jni/src/android_version.h \
$(ROOT)/jni/src/android_version_githash.h
debug : $(PATHCFGFILE)
export NDEBUG=; \
export BUILD_TYPE=debug; \
$(MAKE) -j${PARALLEL} apk
$(MAKE) apk
all : debug release
release : $(PATHCFGFILE)
@export NDEBUG=1; \
export BUILD_TYPE=release; \
$(MAKE) -j${PARALLEL} apk
$(MAKE) apk
reconfig: delconfig
@$(MAKE) -j${PARALLEL} $(PATHCFGFILE)
@$(MAKE) $(PATHCFGFILE)
delconfig :
$(RM) ${PATHCFGFILE}
@ -172,9 +200,9 @@ $(PATHCFGFILE) :
exit 1; \
fi; \
echo "ANDROID_NDK = $$ANDROID_NDK" > ${PATHCFGFILE}; \
echo "NDK_MODULE_PATH = $$ANDROID_NDK/tools" >> ${PATHCFGFILE}; \
echo "NDK_MODULE_PATH = $$ANDROID_NDK/toolchains" >> ${PATHCFGFILE}; \
echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";\
echo "+ Note: NDK_MODULE_PATH is set to $$ANDROID_NDK/tools"; \
echo "+ Note: NDK_MODULE_PATH is set to $$ANDROID_NDK/toolchains"; \
echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";\
echo "Please specify path of ANDROID SDK"; \
echo "e.g. /home/user/adt-bundle-linux-x86_64-20131030/sdk/"; \
@ -190,7 +218,7 @@ $(OPENAL_TIMESTAMP) : openal_download
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${OPENAL_TIMESTAMP}; \
fi
openal_download :
@if [ ! -d ${OPENAL_DIR} ] ; then \
echo "openal sources missing, downloading..."; \
@ -198,11 +226,11 @@ openal_download :
cd ${ROOT}/deps ; \
git clone ${OPENAL_URL_GIT} || exit 1; \
fi
openal : $(OPENAL_LIB)
$(OPENAL_LIB): $(OPENAL_TIMESTAMP)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${OPENAL_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
@ -214,8 +242,8 @@ $(OPENAL_LIB): $(OPENAL_TIMESTAMP)
echo "changed timestamp for openal detected building..."; \
cd ${OPENAL_DIR}; \
ndk-build NDEBUG=${NDEBUG} NDK_MODULE_PATH=${NDK_MODULE_PATH} \
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} -j${PARALLEL} \
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
APP_ABI=${TARGET_ABI} TARGET_ARCH_ABI=${TARGET_ABI} \
APP_PLATFORM=${APP_PLATFORM} TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
touch ${OPENAL_TIMESTAMP}; \
@ -223,16 +251,16 @@ $(OPENAL_LIB): $(OPENAL_TIMESTAMP)
else \
echo "nothing to be done for openal"; \
fi
clean_openal :
$(RM) -rf ${OPENAL_DIR}
$(OGG_TIMESTAMP) : ogg_download
@LAST_MODIF=$$(find ${OGG_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${OGG_TIMESTAMP}; \
fi
ogg_download :
@if [ ! -d ${OGG_DIR} ] ; then \
echo "ogg sources missing, downloading..."; \
@ -241,12 +269,13 @@ ogg_download :
git clone ${OGG_URL_GIT}|| exit 1; \
cd libvorbis-libogg-android ; \
patch -p1 < ../../libvorbis-libogg-fpu.patch || exit 1; \
sed -i 's-:-?-' jni/Application.mk; \
fi
ogg : $(OGG_LIB)
$(OGG_LIB): $(OGG_TIMESTAMP)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${OGG_TIMESTAMP_INT} ] ; then \
echo "${OGG_TIMESTAMP_INT} doesn't exist"; \
REFRESH=1; \
@ -259,7 +288,7 @@ $(OGG_LIB): $(OGG_TIMESTAMP)
echo "changed timestamp for ogg detected building..."; \
cd ${OGG_DIR}; \
ndk-build NDEBUG=${NDEBUG} NDK_MODULE_PATH=${NDK_MODULE_PATH} \
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} -j${PARALLEL} \
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} \
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
@ -271,21 +300,24 @@ $(OGG_LIB): $(OGG_TIMESTAMP)
clean_ogg :
$(RM) -rf ${OGG_DIR}
$(OPENSSL_TIMESTAMP) : openssl_download
@LAST_MODIF=$$(find ${OPENSSL_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${OPENSSL_TIMESTAMP}; \
fi
openssl_download :
@if [ ! -d ${OPENSSL_DIR} ] ; then \
echo "openssl sources missing, downloading..."; \
mkdir -p ${ROOT}/deps; \
cd ${ROOT}/deps ; \
git clone ${OPENSSL_URL_GIT} || exit 1; \
wget ${OPENSSL_URL} || exit 1; \
tar -xzf ${OPENSSL_BASEDIR}.tar.gz; \
cd ${OPENSSL_BASEDIR}; \
patch -p1 < ../../openssl_arch.patch; \
fi
openssl : $(OPENSSL_LIB)
$(OPENSSL_LIB): $(OPENSSL_TIMESTAMP)
@ -298,24 +330,27 @@ $(OPENSSL_LIB): $(OPENSSL_TIMESTAMP)
REFRESH=1; \
fi; \
if [ $$REFRESH -ne 0 ] ; then \
export PATH=$$PATH:${SDKFOLDER}/platform-tools:${ANDROID_NDK}; \
echo "changed timestamp for openssl detected building..."; \
cd ${OPENSSL_DIR}; \
cat jni/Application.mk | grep -v NDK_TOOLCHAIN_VERSION >jni/Application.mk.new;\
mv jni/Application.mk.new jni/Application.mk; \
ndk-build NDEBUG=${NDEBUG} NDK_MODULE_PATH=${NDK_MODULE_PATH} \
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} -j${PARALLEL} \
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
ln -s ${OPENSSL_DIR} ../openssl; \
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-openssl; \
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
--install-dir=$${TOOLCHAIN}; \
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
CC=${CROSS_PREFIX}gcc ./Configure android-${TARGET_ARCH} no-idea no-seed -no-sha0 -DL_ENDIAN;\
CC=${CROSS_PREFIX}gcc ANDROID_DEV=/tmp/ndk-${TARGET_HOST} make build_libs; \
touch ${OPENSSL_TIMESTAMP}; \
touch ${OPENSSL_TIMESTAMP_INT}; \
$(RM) -rf $${TOOLCHAIN}; \
else \
echo "nothing to be done for openssl"; \
fi
clean_openssl :
$(RM) -rf ${OPENSSL_DIR}
$(RM) -rf ${OPENSSL_DIR}; \
$(RM) -rf $(ROOT)/deps/${OPENSSL_BASEDIR}.tar.gz; \
$(RM) -rf $(ROOT)/deps/openssl
$(LEVELDB_TIMESTAMP) : leveldb_download
@LAST_MODIF=$$(find ${LEVELDB_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
@ -329,8 +364,10 @@ leveldb_download :
mkdir -p ${ROOT}/deps; \
cd ${ROOT}/deps ; \
git clone ${LEVELDB_URL_GIT} || exit 1; \
cd ${LEVELDB_DIR} || exit 1; \
git checkout ${LEVELDB_COMMIT} || exit 1; \
fi
leveldb : $(LEVELDB_LIB)
$(LEVELDB_LIB): $(LEVELDB_TIMESTAMP)
@ -346,10 +383,10 @@ $(LEVELDB_LIB): $(LEVELDB_TIMESTAMP)
echo "changed timestamp for leveldb detected building..."; \
cd deps/leveldb; \
export CROSS_PREFIX=${CROSS_PREFIX}; \
export TOOLCHAIN=/tmp/ndk-arm; \
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-leveldb; \
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
--install-dir=$${TOOLCHAIN} --system=linux-x86_64; \
--install-dir=$${TOOLCHAIN}; \
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
export CC=${CROSS_PREFIX}gcc; \
export CXX=${CROSS_PREFIX}g++; \
@ -357,16 +394,17 @@ $(LEVELDB_LIB): $(LEVELDB_TIMESTAMP)
export CPPFLAGS="$${CPPFLAGS} ${TARGET_CFLAGS_ADDON}"; \
export LDFLAGS="$${LDFLAGS} ${TARGET_LDFLAGS_ADDON}"; \
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
$(MAKE) -j${PARALLEL} -s || exit 1; \
$(MAKE) -s || exit 1; \
touch ${LEVELDB_TIMESTAMP}; \
touch ${LEVELDB_TIMESTAMP_INT}; \
$(RM) -rf $${TOOLCHAIN}; \
else \
echo "nothing to be done for leveldb"; \
fi
clean_leveldb :
$(RM) -rf deps/leveldb
$(FREETYPE_TIMESTAMP) : freetype_download
@LAST_MODIF=$$(find ${FREETYPE_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
@ -380,17 +418,11 @@ freetype_download :
cd deps; \
git clone ${FREETYPE_URL_GIT} || exit 1; \
fi
$(IRRLICHT_TIMESTAMP) : irrlicht_download
@LAST_MODIF=$$(find ${IRRLICHT_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${IRRLICHT_TIMESTAMP}; \
fi
freetype : $(FREETYPE_LIB)
$(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${FREETYPE_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
@ -406,7 +438,7 @@ $(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
echo "changed timestamp for freetype detected building..."; \
cd ${FREETYPE_DIR}/Android/jni; \
ndk-build NDEBUG=${NDEBUG} NDK_MODULE_PATH=${NDK_MODULE_PATH} \
APP_PLATFORM=${APP_PLATFORM} APP_ABI=${TARGET_ABI} -j${PARALLEL} \
APP_PLATFORM=${APP_PLATFORM} APP_ABI=${TARGET_ABI} \
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
@ -415,10 +447,71 @@ $(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
else \
echo "nothing to be done for freetype"; \
fi
clean_freetype :
$(RM) -rf ${FREETYPE_DIR}
$(ICONV_TIMESTAMP) : iconv_download
@LAST_MODIF=$$(find ${ICONV_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ICONV_TIMESTAMP}; \
fi
iconv_download :
@if [ ! -d ${ICONV_DIR} ] ; then \
echo "iconv sources missing, downloading..."; \
mkdir -p ${ROOT}/deps; \
cd ${ROOT}/deps; \
wget ${ICONV_URL_HTTP} || exit 1; \
tar -xzf libiconv-${ICONV_VERSION}.tar.gz || exit 1; \
rm libiconv-${ICONV_VERSION}.tar.gz; \
ln -s libiconv-${ICONV_VERSION} libiconv; \
cd ${ICONV_DIR}; \
patch -p1 < ${ROOT}/libiconv_android.patch; \
patch -p1 < ${ROOT}/libiconv_stdio.patch; \
fi
iconv : $(ICONV_LIB)
$(ICONV_LIB) : $(ICONV_TIMESTAMP)
@REFRESH=0; \
if [ ! -e ${ICONV_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
if [ ! -e ${ICONV_LIB} ] ; then \
REFRESH=1; \
fi; \
if [ ${ICONV_TIMESTAMP} -nt ${ICONV_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
if [ $$REFRESH -ne 0 ] ; then \
mkdir -p ${ICONV_DIR}; \
export PATH=$$PATH:${SDKFOLDER}/platform-tools:${ANDROID_NDK}; \
echo "changed timestamp for iconv detected building..."; \
cd ${ICONV_DIR}; \
\
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-iconv; \
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
--install-dir=$${TOOLCHAIN}; \
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
export CC=${CROSS_PREFIX}gcc; \
export CXX=${CROSS_PREFIX}g++; \
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
./configure --host=${TARGET_HOST} || exit 1; \
sed -i 's/LIBICONV_VERSION_INFO) /LIBICONV_VERSION_INFO) -avoid-version /g' lib/Makefile; \
grep "iconv_LDFLAGS" src/Makefile; \
$(MAKE) -s || exit 1; \
touch ${ICONV_TIMESTAMP}; \
touch ${ICONV_TIMESTAMP_INT}; \
rm -rf ${TOOLCHAIN}; \
else \
echo "nothing to be done for iconv"; \
fi
clean_iconv :
$(RM) -rf ${ICONV_DIR}
#Note: Texturehack patch is required for gpu's not supporting color format
# correctly. Known bad GPU:
# -geforce on emulator
@ -436,10 +529,16 @@ irrlicht_download :
patch -p1 < ../../irrlicht-texturehack.patch || exit 1; \
fi
$(IRRLICHT_TIMESTAMP) : irrlicht_download
@LAST_MODIF=$$(find ${IRRLICHT_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${IRRLICHT_TIMESTAMP}; \
fi
irrlicht : $(IRRLICHT_LIB)
$(IRRLICHT_LIB): $(IRRLICHT_TIMESTAMP) $(FREETYPE_LIB)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${IRRLICHT_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
@ -455,7 +554,7 @@ $(IRRLICHT_LIB): $(IRRLICHT_TIMESTAMP) $(FREETYPE_LIB)
echo "changed timestamp for irrlicht detected building..."; \
cd deps/irrlicht/source/Irrlicht/Android; \
ndk-build NDEBUG=${NDEBUG} NDK_MODULE_PATH=${NDK_MODULE_PATH} \
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} -j${PARALLEL} \
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} \
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
@ -464,10 +563,10 @@ $(IRRLICHT_LIB): $(IRRLICHT_TIMESTAMP) $(FREETYPE_LIB)
else \
echo "nothing to be done for irrlicht"; \
fi
clean_irrlicht :
$(RM) -rf deps/irrlicht
$(CURL_TIMESTAMP) : curl_download
@LAST_MODIF=$$(find ${CURL_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
@ -482,6 +581,7 @@ curl_download :
wget ${CURL_URL_HTTP} || exit 1; \
tar -xjf curl-${CURL_VERSION}.tar.bz2 || exit 1; \
rm curl-${CURL_VERSION}.tar.bz2; \
ln -s curl-${CURL_VERSION} curl; \
fi
curl : $(CURL_LIB)
@ -503,85 +603,111 @@ $(CURL_LIB): $(CURL_TIMESTAMP) $(OPENSSL_LIB)
echo "changed timestamp for curl detected building..."; \
cd deps/curl-${CURL_VERSION}; \
export CROSS_PREFIX=${CROSS_PREFIX}; \
export TOOLCHAIN=/tmp/ndk-arm; \
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-curl; \
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
--install-dir=$${TOOLCHAIN} --system=linux-x86_64; \
--install-dir=$${TOOLCHAIN}; \
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
export CC=${CROSS_PREFIX}gcc; \
export CXX=${CROSS_PREFIX}g++; \
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
export CPPFLAGS="$${CPPFLAGS} -I${OPENSSL_DIR}/include \
-L${OPENSSL_DIR}/libs/${TARGET_ABI}/ ${TARGET_CFLAGS_ADDON}"; \
-L${OPENSSL_DIR} ${TARGET_CFLAGS_ADDON}"; \
export CFLAGS="$${CFLAGS} ${TARGET_CFLAGS_ADDON}"; \
export LDFLAGS="$${LDFLAGS} -L${OPENSSL_DIR}/libs/${TARGET_ABI}/ \
${TARGET_LDFLAGS_ADDON}"; \
export LDFLAGS="$${LDFLAGS} -L${OPENSSL_DIR} ${TARGET_LDFLAGS_ADDON}"; \
./configure --host=${TARGET_HOST} --disable-shared --enable-static --with-ssl; \
$(MAKE) -j${PARALLEL} -s || exit 1; \
$(MAKE) -s || exit 1; \
touch ${CURL_TIMESTAMP}; \
touch ${CURL_TIMESTAMP_INT}; \
$(RM) -rf $${TOOLCHAIN}; \
else \
echo "nothing to be done for curl"; \
fi
clean_curl :
$(RM) -rf deps/curl-${CURL_VERSION}
curl_binary:
@if [ ! -d "deps/curl-${CURL_VERSION_BINARY}" ] ; then \
echo "curl sources missing, downloading..."; \
mkdir -p ${ROOT}/deps; \
cd deps; \
wget http://curl.haxx.se/gknw.net/7.34.0/dist-android/curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android.tar.gz || exit 1;\
tar -xzf curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android.tar.gz || exit 1;\
mv curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android curl-${CURL_VERSION_BINARY};\
rm curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android.tar.gz; \
$(RM) -rf deps/curl-${CURL_VERSION} \
$(RM) -f deps/curl
$(GMP_TIMESTAMP) : gmp_download
@LAST_MODIF=$$(find ${GMP_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${GMP_TIMESTAMP}; \
fi
gmp_download :
@if [ ! -d "${GMP_DIR}" ] ; then \
echo "gmp sources missing, downloading..."; \
mkdir -p ${ROOT}/deps; \
cd deps; \
wget ${GMP_URL_HTTP} || exit 1; \
tar -xjf gmp-${GMP_VERSION}.tar.bz2 || exit 1; \
rm gmp-${GMP_VERSION}.tar.bz2; \
ln -s gmp-${GMP_VERSION} gmp; \
fi
gmp : $(GMP_LIB)
$(GMP_LIB): $(GMP_TIMESTAMP)
@REFRESH=0; \
if [ ! -e ${GMP_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
if [ ! -e ${GMP_LIB} ] ; then \
REFRESH=1; \
fi; \
if [ ${GMP_TIMESTAMP} -nt ${GMP_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
if [ $$REFRESH -ne 0 ] ; then \
mkdir -p ${GMP_DIR}; \
export PATH="$${PATH}:${SDKFOLDER}/platform-tools:${ANDROID_NDK}"; \
echo "changed timestamp for gmp detected building..."; \
cd deps/gmp-${GMP_VERSION}; \
export CROSS_PREFIX=${CROSS_PREFIX}; \
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-gmp; \
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
--install-dir=$${TOOLCHAIN}; \
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
export CC=${CROSS_PREFIX}gcc; \
export CXX=${CROSS_PREFIX}g++; \
export LIBGMP_LDFLAGS="-avoid-version"; \
export LIBGMPXX_LDFLAGS="-avoid-version"; \
./configure --disable-static --host=${TARGET_HOST} --prefix=/usr; \
$(MAKE) install DESTDIR=/${GMP_DIR} || exit 1; \
touch ${GMP_TIMESTAMP}; \
touch ${GMP_TIMESTAMP_INT}; \
$(RM) -rf $${TOOLCHAIN}; \
else \
echo "nothing to be done for gmp"; \
fi
clean_gmp:
$(RM) -rf deps/gmp-${GMP_VERSION} \
$(RM) -f deps/gmp
sqlite3_download: deps/${SQLITE3_FOLDER}/sqlite3.c
deps/${SQLITE3_FOLDER}/sqlite3.c :
cd deps; \
wget ${SQLITE3_URL}; \
unzip ${SQLITE3_FOLDER}.zip; \
ln -s ${SQLITE3_FOLDER} sqlite
clean_sqlite3:
cd deps && $(RM) -rf ${SQLITE3_FOLDER} && $(RM) -f ${SQLITE3_FOLDER}.zip && \
$(RM) -f sqlite
$(ASSETS_TIMESTAMP) : $(IRRLICHT_LIB)
@mkdir -p ${ROOT}/deps; \
LAST_MODIF=$$(find ${ROOT}/../../builtin -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../builtin/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
echo builtin changed $$LAST_MODIF; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../client -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../client/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../doc -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../doc/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../fonts -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../fonts/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../games -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../games/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../mods -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../mods/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../po -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../po/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
LAST_MODIF=$$(find ${ROOT}/../../textures -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${ROOT}/../../textures/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
fi; \
for DIRNAME in {builtin,client,doc,fonts,games,mods,po,textures}; do \
LAST_MODIF=$$(find ${ROOT}/../../${DIRNAME} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ]; then \
touch ${ROOT}/../../${DIRNAME}/timestamp; \
touch ${ASSETS_TIMESTAMP}; \
echo ${DIRNAME} changed $$LAST_MODIF; \
fi; \
done; \
LAST_MODIF=$$(find ${IRRLICHT_DIR}/media -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
touch ${IRRLICHT_DIR}/media/timestamp; \
@ -597,7 +723,7 @@ $(ASSETS_TIMESTAMP) : $(IRRLICHT_LIB)
if [ ! -e $(ASSETS_TIMESTAMP) ] ; then \
touch $(ASSETS_TIMESTAMP); \
fi
assets : $(ASSETS_TIMESTAMP)
@REFRESH=0; \
if [ ! -e ${ASSETS_TIMESTAMP}.old ] ; then \
@ -611,24 +737,37 @@ assets : $(ASSETS_TIMESTAMP)
fi; \
if [ $$REFRESH -ne 0 ] ; then \
echo "assets changed, refreshing..."; \
$(MAKE) -j${PARALLEL} clean_assets; \
$(MAKE) clean_assets; \
mkdir -p ${ROOT}/assets/Minetest; \
cp ${ROOT}/../../minetest.conf.example ${ROOT}/assets/Minetest; \
cp ${ROOT}/../../README.txt ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../builtin ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../client ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../doc ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../fonts ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../games ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../mods ${ROOT}/assets/Minetest; \
mkdir ${ROOT}/assets/Minetest/client; \
cp -r ${ROOT}/../../client/shaders ${ROOT}/assets/Minetest/client; \
cp ${ROOT}/../../doc/lgpl-2.1.txt ${ROOT}/assets/Minetest/LICENSE.txt; \
mkdir ${ROOT}/assets/Minetest/fonts; \
cp -r ${ROOT}/../../fonts/*.ttf ${ROOT}/assets/Minetest/fonts/; \
mkdir ${ROOT}/assets/Minetest/games; \
for game in ${GAMES_TO_COPY}; do \
cp -r ${ROOT}/../../games/$$game ${ROOT}/assets/Minetest/games/; \
done; \
mkdir ${ROOT}/assets/Minetest/mods; \
for mod in ${MODS_TO_COPY}; do \
cp -r ${ROOT}/../../mods/$$mod ${ROOT}/assets/Minetest/mods/; \
done; \
cp -r ${ROOT}/../../po ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../textures ${ROOT}/assets/Minetest; \
mkdir -p ${ROOT}/assets/Minetest/media; \
cp -r ${IRRLICHT_DIR}/media/Shaders ${ROOT}/assets/Minetest/media; \
cd ${ROOT}/assets; \
cd ${ROOT}/assets || exit 1; \
find . -name "timestamp" -exec rm {} \; ; \
find . -name "*.blend" -exec rm {} \; ; \
find . -name "*~" -exec rm {} \; ; \
find . -type d -path "*.git" -exec rm -rf {} \; ; \
find . -type d -path "*.svn" -exec rm -rf {} \; ; \
find . -type f -path "*.gitignore" -exec rm -rf {} \; ; \
ls -R | grep ":$$" | sed -e 's/:$$//' -e 's/\.//' -e 's/^\///' > "index.txt"; \
find Minetest >"filelist.txt"; \
cp ${ROOT}/${ASSETS_TIMESTAMP} ${ROOT}/${ASSETS_TIMESTAMP}.old; \
else \
echo "nothing to be done for assets"; \
@ -636,14 +775,15 @@ assets : $(ASSETS_TIMESTAMP)
clean_assets :
@$(RM) -r assets
apk: $(PATHCFGFILE) assets $(IRRLICHT_LIB) $(CURL_LIB) $(LEVELDB_TARGET) \
$(OPENAL_LIB) $(OGG_LIB) prep_srcdir $(ROOT)/jni/src/android_version.h
@export NDEBUG=$$NDEBUG; $(MAKE) -j${PARALLEL} manifest; \
apk: $(PATHCFGFILE) assets $(ICONV_LIB) $(IRRLICHT_LIB) $(CURL_LIB) $(GMP_LIB) $(LEVELDB_TARGET) \
$(OPENAL_LIB) $(OGG_LIB) prep_srcdir $(ROOT)/jni/src/android_version.h \
$(ROOT)/jni/src/android_version_githash.h sqlite3_download
@export NDEBUG=$$NDEBUG; $(MAKE) manifest; \
export PATH=$$PATH:${SDKFOLDER}/platform-tools:${ANDROID_NDK}; \
export ANDROID_HOME=${SDKFOLDER}; \
mkdir -p ${ROOT}/src; \
ndk-build NDK_MODULE_PATH=${NDK_MODULE_PATH} -j${PARALLEL} \
ndk-build NDK_MODULE_PATH=${NDK_MODULE_PATH} \
GPROF=${GPROF} APP_ABI=${TARGET_ABI} HAVE_LEVELDB=${HAVE_LEVELDB} \
APP_PLATFORM=${APP_PLATFORM} \
TARGET_LIBDIR=${TARGET_LIBDIR} \
@ -654,70 +794,77 @@ apk: $(PATHCFGFILE) assets $(IRRLICHT_LIB) $(CURL_LIB) $(LEVELDB_TARGET) \
echo "++ Success!" && \
echo "APK: bin/Minetest-$$BUILD_TYPE.apk" && \
echo "You can install it with \`adb install -r bin/Minetest-$$BUILD_TYPE.apk\`"
prep_srcdir :
@rm ${ROOT}/jni/src; \
ln -s ${ROOT}/../../src ${ROOT}/jni/src
@if [ ! -e ${ROOT}/jni/src ]; then \
ln -s ${ROOT}/../../src ${ROOT}/jni/src; \
fi
clean_apk : manifest
@export PATH=$$PATH:${SDKFOLDER}platform-tools:${ANDROID_NDK}; \
export ANDROID_HOME=${SDKFOLDER}; \
ant clean
install_debug :
install_debug :
@export PATH=$$PATH:${SDKFOLDER}platform-tools:${ANDROID_NDK}; \
adb install -r ${ROOT}/bin/Minetest-debug.apk
install :
@export PATH=$$PATH:${SDKFOLDER}platform-tools:${ANDROID_NDK}; \
adb install -r ${ROOT}/bin/Minetest-release.apk
envpaths :
@echo "export PATH=$$PATH:${SDKFOLDER}platform-tools:${ANDROID_NDK}" > and_env;\
echo "export ANDROID_HOME=${SDKFOLDER}" >> and_env;
clean_all :
@$(MAKE) -j${PARALLEL} clean_apk; \
$(MAKE) clean_assets clean_irrlicht clean_leveldb clean_curl clean_openssl \
clean_openal clean_ogg clean_manifest; \
clean_all :
@$(MAKE) clean_apk; \
$(MAKE) clean_assets clean_iconv clean_irrlicht clean_leveldb clean_curl clean_openssl \
clean_openal clean_ogg clean_gmp clean_manifest; \
sleep 1; \
$(RM) -r gen libs obj deps bin Debug and_env
$(ROOT)/jni/src/android_version.h :
@echo "#define STR_HELPER(x) #x" \
>${ROOT}/jni/src/android_version.h; \
echo "#define STR(x) STR_HELPER(x)" \
>> ${ROOT}/jni/src/android_version.h; \
echo "#define VERSION_MAJOR $$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_MAJOR\ | sed 's/)/ /' | awk '{print $$2;}')" \
>> ${ROOT}/jni/src/android_version.h; \
echo "#define VERSION_MINOR $$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_MINOR\ | sed 's/)/ /' | awk '{print $$2;}')" \
>> ${ROOT}/jni/src/android_version.h; \
echo "#define VERSION_PATCH $$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_PATCH\ | sed 's/)/ /' | awk '{print $$2;}')" \
>> ${ROOT}/jni/src/android_version.h; \
echo "#define VERSION_PATCH_ORIG $$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_PATCH\ | sed 's/)/ /' | awk '{print $$2;}')" \
>> ${ROOT}/jni/src/android_version.h; \
$(ROOT)/jni/src/android_version_githash.h : prep_srcdir
@export VERSION_FILE=${ROOT}/jni/src/android_version_githash.h; \
export VERSION_FILE_NEW=$${VERSION_FILE}.new; \
{ \
echo "#ifndef ANDROID_MT_VERSION_GITHASH_H"; \
echo "#define ANDROID_MT_VERSION_GITHASH_H"; \
export GITHASH=$$(git rev-parse --short=8 HEAD); \
if [ "x$$GITHASH" = "x" ] ; then \
export GITHASH=gUnknown; \
fi; \
echo "#define CMAKE_VERSION_GITHASH \"$$GITHASH\"" \
>> ${ROOT}/jni/src/android_version.h; \
echo "#define CMAKE_VERSION_STRING STR(VERSION_MAJOR)\".\"STR(VERSION_MINOR)\
\".\"STR(VERSION_PATCH)" \
>> ${ROOT}/jni/src/android_version.h;
export VERSION_STR="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"; \
echo "#define VERSION_GITHASH \"$$VERSION_STR-$$GITHASH-Android\""; \
echo "#endif"; \
} > "$${VERSION_FILE_NEW}"; \
if ! cmp -s $${VERSION_FILE} $${VERSION_FILE_NEW}; then \
echo "android_version_githash.h changed, updating..."; \
mv "$${VERSION_FILE_NEW}" "$${VERSION_FILE}"; \
else \
rm "$${VERSION_FILE_NEW}"; \
fi
$(ROOT)/jni/src/android_version.h : prep_srcdir
@export VERSION_FILE=${ROOT}/jni/src/android_version.h; \
export VERSION_FILE_NEW=$${VERSION_FILE}.new; \
{ \
echo "#ifndef ANDROID_MT_VERSION_H"; \
echo "#define ANDROID_MT_VERSION_H"; \
echo "#define VERSION_MAJOR ${VERSION_MAJOR}"; \
echo "#define VERSION_MINOR ${VERSION_MINOR}"; \
echo "#define VERSION_PATCH ${VERSION_PATCH}"; \
echo "#define VERSION_STRING STR(VERSION_MAJOR) \".\" STR(VERSION_MINOR) \
\".\" STR(VERSION_PATCH)"; \
echo "#endif"; \
} > $${VERSION_FILE_NEW}; \
if ! cmp -s $${VERSION_FILE} $${VERSION_FILE_NEW}; then \
echo "android_version.h changed, updating..."; \
mv "$${VERSION_FILE_NEW}" "$${VERSION_FILE}"; \
else \
rm "$${VERSION_FILE_NEW}"; \
fi
manifest :
@VERS_MAJOR=$$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_MAJOR\ | sed 's/)/ /' | awk '{print $$2;}'); \
VERS_MINOR=$$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_MINOR\ | sed 's/)/ /' | awk '{print $$2;}'); \
VERS_PATCH=$$(cat ${ROOT}/../../CMakeLists.txt | \
grep ^set\(VERSION_PATCH\ | sed 's/)/ /' | awk '{print $$2;}'); \
BASE_VERSION="$$VERS_MAJOR.$$VERS_MINOR.$$VERS_PATCH"; \
@BASE_VERSION="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"; \
if [ "${NDEBUG}x" != "x" ] ; then \
DBG=''; \
DBG_FLAG="android:debuggable=\"false\""; \
@ -726,11 +873,11 @@ manifest :
DBG_FLAG="android:debuggable=\"true\""; \
fi; \
cat ${ROOT}/AndroidManifest.xml.template | \
sed s/###ANDROID_VERSION###/${ANDROID_VERSION_CODE}/g | \
sed s/###BASE_VERSION###/$$BASE_VERSION/g | \
sed "s/###ANDROID_VERSION###/${ANDROID_VERSION_CODE}/g" | \
sed "s/###BASE_VERSION###/$$BASE_VERSION/g" | \
sed -e "s@###DEBUG_BUILD###@$$DBG@g" | \
sed -e "s@###DEBUG_FLAG###@$$DBG_FLAG@g" >${ROOT}/AndroidManifest.xml
clean_manifest :
rm -rf ${ROOT}/AndroidManifest.xml

View File

@ -16,7 +16,7 @@ endif
include $(CLEAR_VARS)
LOCAL_MODULE := curl
LOCAL_SRC_FILES := deps/curl-7.35.0/lib/.libs/libcurl.a
LOCAL_SRC_FILES := deps/curl/lib/.libs/libcurl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
@ -24,6 +24,11 @@ LOCAL_MODULE := freetype
LOCAL_SRC_FILES := deps/freetype2-android/Android/obj/local/$(TARGET_ARCH_ABI)/libfreetype2-static.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := iconv
LOCAL_SRC_FILES := deps/libiconv/lib/.libs/libiconv.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := openal
LOCAL_SRC_FILES := deps/openal-soft/libs/$(TARGET_LIBDIR)/libopenal.so
@ -40,15 +45,19 @@ LOCAL_SRC_FILES := deps/libvorbis-libogg-android/libs/$(TARGET_LIBDIR)/libvorbis
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := deps/openssl-android/libs/$(TARGET_LIBDIR)/libssl.so
LOCAL_MODULE := gmp
LOCAL_SRC_FILES := deps/gmp/usr/lib/libgmp.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := crypto
LOCAL_SRC_FILES := deps/openssl-android/libs/$(TARGET_LIBDIR)/libcrypto.so
include $(PREBUILT_SHARED_LIBRARY)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := deps/openssl/libssl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := crypto
LOCAL_SRC_FILES := deps/openssl/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := minetest
@ -93,16 +102,18 @@ LOCAL_C_INCLUDES := \
jni/src/json \
jni/src/cguittfont \
deps/irrlicht/include \
deps/libiconv/include \
deps/freetype2-android/include \
deps/curl-7.35.0/include \
deps/curl/include \
deps/openal-soft/jni/OpenAL/include \
deps/libvorbis-libogg-android/jni/include \
deps/gmp/usr/include \
deps/leveldb/include \
deps/sqlite/
LOCAL_SRC_FILES := \
jni/src/areastore.cpp \
jni/src/ban.cpp \
jni/src/base64.cpp \
jni/src/biome.cpp \
jni/src/camera.cpp \
jni/src/cavegen.cpp \
jni/src/chat.cpp \
@ -113,7 +124,6 @@ LOCAL_SRC_FILES := \
jni/src/clientobject.cpp \
jni/src/clouds.cpp \
jni/src/collision.cpp \
jni/src/connection.cpp \
jni/src/content_abm.cpp \
jni/src/content_cao.cpp \
jni/src/content_cso.cpp \
@ -134,6 +144,7 @@ LOCAL_SRC_FILES := \
jni/src/environment.cpp \
jni/src/filecache.cpp \
jni/src/filesys.cpp \
jni/src/fontengine.cpp \
jni/src/game.cpp \
jni/src/genericobject.cpp \
jni/src/gettext.cpp \
@ -144,9 +155,12 @@ LOCAL_SRC_FILES := \
jni/src/guiKeyChangeMenu.cpp \
jni/src/guiPasswordChange.cpp \
jni/src/guiTable.cpp \
jni/src/guiscalingfilter.cpp \
jni/src/guiVolumeChange.cpp \
jni/src/httpfetch.cpp \
jni/src/hud.cpp \
jni/src/imagefilters.cpp \
jni/src/intlGUIEditBox.cpp \
jni/src/inventory.cpp \
jni/src/inventorymanager.cpp \
jni/src/itemdef.cpp \
@ -159,24 +173,35 @@ LOCAL_SRC_FILES := \
jni/src/mapblock.cpp \
jni/src/mapblock_mesh.cpp \
jni/src/mapgen.cpp \
jni/src/mapgen_flat.cpp \
jni/src/mapgen_fractal.cpp \
jni/src/mapgen_singlenode.cpp \
jni/src/mapgen_v5.cpp \
jni/src/mapgen_v6.cpp \
jni/src/mapgen_v7.cpp \
jni/src/mapgen_valleys.cpp \
jni/src/mapnode.cpp \
jni/src/mapsector.cpp \
jni/src/mesh.cpp \
jni/src/mg_biome.cpp \
jni/src/mg_decoration.cpp \
jni/src/mg_ore.cpp \
jni/src/mg_schematic.cpp \
jni/src/minimap.cpp \
jni/src/mods.cpp \
jni/src/nameidmapping.cpp \
jni/src/nodedef.cpp \
jni/src/nodemetadata.cpp \
jni/src/nodetimer.cpp \
jni/src/noise.cpp \
jni/src/objdef.cpp \
jni/src/object_properties.cpp \
jni/src/particles.cpp \
jni/src/pathfinder.cpp \
jni/src/player.cpp \
jni/src/porting_android.cpp \
jni/src/porting.cpp \
jni/src/profiler.cpp \
jni/src/quicktune.cpp \
jni/src/rollback.cpp \
jni/src/rollback_interface.cpp \
@ -184,7 +209,6 @@ LOCAL_SRC_FILES := \
jni/src/server.cpp \
jni/src/serverlist.cpp \
jni/src/serverobject.cpp \
jni/src/sha1.cpp \
jni/src/shader.cpp \
jni/src/sky.cpp \
jni/src/socket.cpp \
@ -192,22 +216,58 @@ LOCAL_SRC_FILES := \
jni/src/sound_openal.cpp \
jni/src/staticobject.cpp \
jni/src/subgame.cpp \
jni/src/test.cpp \
jni/src/tile.cpp \
jni/src/tool.cpp \
jni/src/treegen.cpp \
jni/src/version.cpp \
jni/src/voxel.cpp \
jni/src/voxelalgorithms.cpp \
jni/src/util/auth.cpp \
jni/src/util/base64.cpp \
jni/src/util/directiontables.cpp \
jni/src/util/numeric.cpp \
jni/src/util/pointedthing.cpp \
jni/src/util/serialize.cpp \
jni/src/util/sha1.cpp \
jni/src/util/string.cpp \
jni/src/util/srp.cpp \
jni/src/util/timetaker.cpp \
jni/src/unittest/test.cpp \
jni/src/unittest/test_collision.cpp \
jni/src/unittest/test_compression.cpp \
jni/src/unittest/test_connection.cpp \
jni/src/unittest/test_filepath.cpp \
jni/src/unittest/test_inventory.cpp \
jni/src/unittest/test_mapnode.cpp \
jni/src/unittest/test_nodedef.cpp \
jni/src/unittest/test_noderesolver.cpp \
jni/src/unittest/test_noise.cpp \
jni/src/unittest/test_objdef.cpp \
jni/src/unittest/test_profiler.cpp \
jni/src/unittest/test_random.cpp \
jni/src/unittest/test_schematic.cpp \
jni/src/unittest/test_serialization.cpp \
jni/src/unittest/test_settings.cpp \
jni/src/unittest/test_socket.cpp \
jni/src/unittest/test_utilities.cpp \
jni/src/unittest/test_voxelalgorithms.cpp \
jni/src/unittest/test_voxelmanipulator.cpp \
jni/src/touchscreengui.cpp \
jni/src/database-leveldb.cpp \
jni/src/settings.cpp
jni/src/database-leveldb.cpp \
jni/src/settings.cpp \
jni/src/wieldmesh.cpp \
jni/src/client/clientlauncher.cpp \
jni/src/client/tile.cpp
# intentionally kept out (we already build openssl itself): jni/src/util/sha256.c
# Network
LOCAL_SRC_FILES += \
jni/src/network/connection.cpp \
jni/src/network/networkpacket.cpp \
jni/src/network/clientopcodes.cpp \
jni/src/network/clientpackethandler.cpp \
jni/src/network/serveropcodes.cpp \
jni/src/network/serverpackethandler.cpp \
# lua api
LOCAL_SRC_FILES += \
@ -215,6 +275,7 @@ LOCAL_SRC_FILES += \
jni/src/script/common/c_converter.cpp \
jni/src/script/common/c_internal.cpp \
jni/src/script/common/c_types.cpp \
jni/src/script/cpp_api/s_async.cpp \
jni/src/script/cpp_api/s_base.cpp \
jni/src/script/cpp_api/s_entity.cpp \
jni/src/script/cpp_api/s_env.cpp \
@ -224,8 +285,9 @@ LOCAL_SRC_FILES += \
jni/src/script/cpp_api/s_node.cpp \
jni/src/script/cpp_api/s_nodemeta.cpp \
jni/src/script/cpp_api/s_player.cpp \
jni/src/script/cpp_api/s_security.cpp \
jni/src/script/cpp_api/s_server.cpp \
jni/src/script/cpp_api/s_async.cpp \
jni/src/script/lua_api/l_areastore.cpp \
jni/src/script/lua_api/l_base.cpp \
jni/src/script/lua_api/l_craft.cpp \
jni/src/script/lua_api/l_env.cpp \
@ -241,11 +303,12 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_rollback.cpp \
jni/src/script/lua_api/l_server.cpp \
jni/src/script/lua_api/l_settings.cpp \
jni/src/script/lua_api/l_http.cpp \
jni/src/script/lua_api/l_util.cpp \
jni/src/script/lua_api/l_vmanip.cpp \
jni/src/script/scripting_game.cpp \
jni/src/script/scripting_mainmenu.cpp
#freetype2 support
LOCAL_SRC_FILES += \
jni/src/cguittfont/xCGUITTFont.cpp
@ -283,21 +346,21 @@ LOCAL_SRC_FILES += \
jni/src/lua/src/lzio.c \
jni/src/lua/src/print.c
# sqlite
LOCAL_SRC_FILES += jni/src/sqlite/sqlite3.c
# SQLite3
LOCAL_SRC_FILES += deps/sqlite/sqlite3.c
# jthread
LOCAL_SRC_FILES += \
jni/src/jthread/pthread/jevent.cpp \
jni/src/jthread/pthread/jmutex.cpp \
jni/src/jthread/pthread/jsemaphore.cpp \
jni/src/jthread/pthread/jthread.cpp
# Threading
LOCAL_SRC_FILES += \
jni/src/threading/event.cpp \
jni/src/threading/mutex.cpp \
jni/src/threading/semaphore.cpp \
jni/src/threading/thread.cpp
# json
# JSONCPP
LOCAL_SRC_FILES += jni/src/json/jsoncpp.cpp
LOCAL_SHARED_LIBRARIES := openal ogg vorbis ssl crypto
LOCAL_STATIC_LIBRARIES := Irrlicht freetype curl android_native_app_glue $(PROFILER_LIBS)
LOCAL_SHARED_LIBRARIES := iconv openal ogg vorbis gmp
LOCAL_STATIC_LIBRARIES := Irrlicht freetype curl ssl crypto android_native_app_glue $(PROFILER_LIBS)
ifeq ($(HAVE_LEVELDB), 1)
LOCAL_STATIC_LIBRARIES += LevelDB

View File

@ -0,0 +1,39 @@
--- a/libcharset/lib/localcharset.c 2015-06-10 11:55:25.933870724 +0200
+++ b/libcharset/lib/localcharset.c 2015-06-10 11:55:39.578063493 +0200
@@ -47,7 +47,7 @@
#if !defined WIN32_NATIVE
# include <unistd.h>
-# if HAVE_LANGINFO_CODESET
+# if HAVE_LANGINFO_CODESET && !(defined __ANDROID__)
# include <langinfo.h>
# else
# if 0 /* see comment below */
@@ -124,7 +124,7 @@ get_charset_aliases (void)
cp = charset_aliases;
if (cp == NULL)
{
-#if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
+#if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__ || defined __ANDROID__)
const char *dir;
const char *base = "charset.alias";
char *file_name;
@@ -338,6 +338,9 @@ get_charset_aliases (void)
"CP54936" "\0" "GB18030" "\0"
"CP65001" "\0" "UTF-8" "\0";
# endif
+# if defined __ANDROID__
+ cp = "*" "\0" "UTF-8" "\0";
+# endif
#endif
charset_aliases = cp;
@@ -361,7 +364,7 @@ locale_charset (void)
const char *codeset;
const char *aliases;
-#if !(defined WIN32_NATIVE || defined OS2)
+#if !(defined WIN32_NATIVE || defined OS2 || defined __ANDROID__)
# if HAVE_LANGINFO_CODESET

View File

@ -0,0 +1,13 @@
--- a/srclib/stdio.in.h 2011-08-07 15:42:06.000000000 +0200
+++ b/srclib/stdio.in.h 2015-06-10 09:27:58.129056262 +0200
@@ -695,8 +696,9 @@ _GL_CXXALIASWARN (gets);
/* It is very rare that the developer ever has full control of stdin,
so any use of gets warrants an unconditional warning. Assume it is
always declared, since it is required by C89. */
-_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+/*_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");*/
+#define gets(a) fgets( a, sizeof(*(a)), stdin)
#endif
#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@

View File

@ -0,0 +1,11 @@
--- openssl-1.0.1j/Configure.orig 2014-10-15 14:53:39.000000000 +0200
+++ openssl-1.0.1j/Configure 2015-01-03 22:41:43.505749921 +0100
@@ -407,6 +407,8 @@
"android","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"android-x86","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"android-armv7","gcc:-march=armv7-a -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"android-arm","gcc:-march=armv4 -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"android-mips32","gcc:-march=mips32 -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
#### *BSD [do see comment about ${BSDthreads} above!]
"BSD-generic32","gcc:-DTERMIOS -O3 -fomit-frame-pointer -Wall::${BSDthreads}:::BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",

View File

@ -13,8 +13,10 @@
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:singleLine="true"
android:layout_gravity="center_horizontal"
android:text="preparing media ..."
android:textAppearance="?android:attr/textAppearanceSmall" />

View File

@ -0,0 +1,416 @@
package net.minetest.minetest;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Vector;
import java.util.Iterator;
import java.lang.Object;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Display;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.graphics.Rect;
import android.graphics.Paint;
import android.text.TextPaint;
public class MinetestAssetCopy extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.assetcopy);
m_ProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
m_Filename = (TextView) findViewById(R.id.textView1);
Display display = getWindowManager().getDefaultDisplay();
m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8);
m_ProgressBar.invalidate();
/* check if there's already a copy in progress and reuse in case it is*/
MinetestAssetCopy prevActivity =
(MinetestAssetCopy) getLastNonConfigurationInstance();
if(prevActivity!= null) {
m_AssetCopy = prevActivity.m_AssetCopy;
}
else {
m_AssetCopy = new copyAssetTask();
m_AssetCopy.execute();
}
}
/* preserve asset copy background task to prevent restart of copying */
/* this way of doing it is not recommended for latest android version */
/* but the recommended way isn't available on android 2.x */
public Object onRetainNonConfigurationInstance()
{
return this;
}
ProgressBar m_ProgressBar;
TextView m_Filename;
copyAssetTask m_AssetCopy;
private class copyAssetTask extends AsyncTask<String, Integer, String>
{
private long getFullSize(String filename)
{
long size = 0;
try {
InputStream src = getAssets().open(filename);
byte[] buf = new byte[4096];
int len = 0;
while ((len = src.read(buf)) > 0)
{
size += len;
}
}
catch (IOException e)
{
e.printStackTrace();
}
return size;
}
@Override
protected String doInBackground(String... files)
{
m_foldernames = new Vector<String>();
m_filenames = new Vector<String>();
m_tocopy = new Vector<String>();
m_asset_size_unknown = new Vector<String>();
String baseDir =
Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/";
// prepare temp folder
File TempFolder = new File(baseDir + "Minetest/tmp/");
if (!TempFolder.exists())
{
TempFolder.mkdir();
}
else {
File[] todel = TempFolder.listFiles();
for(int i=0; i < todel.length; i++)
{
Log.v("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath());
todel[i].delete();
}
}
// add a .nomedia file
try {
OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
dst.close();
} catch (IOException e) {
Log.e("MinetestAssetCopy","Failed to create .nomedia file");
e.printStackTrace();
}
// build lists from prepared data
BuildFolderList();
BuildFileList();
// scan filelist
ProcessFileList();
// doing work
m_copy_started = true;
m_ProgressBar.setMax(m_tocopy.size());
for (int i = 0; i < m_tocopy.size(); i++)
{
try
{
String filename = m_tocopy.get(i);
publishProgress(i);
boolean asset_size_unknown = false;
long filesize = -1;
if (m_asset_size_unknown.contains(filename))
{
File testme = new File(baseDir + "/" + filename);
if(testme.exists())
{
filesize = testme.length();
}
asset_size_unknown = true;
}
InputStream src;
try
{
src = getAssets().open(filename);
} catch (IOException e) {
Log.e("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)");
e.printStackTrace();
continue;
}
// Transfer bytes from in to out
byte[] buf = new byte[1*1024];
int len = src.read(buf, 0, 1024);
/* following handling is crazy but we need to deal with */
/* compressed assets.Flash chips limited livetime due to */
/* write operations, we can't allow large files to destroy */
/* users flash. */
if (asset_size_unknown)
{
if ( (len > 0) && (len < buf.length) && (len == filesize))
{
src.close();
continue;
}
if (len == buf.length)
{
src.close();
long size = getFullSize(filename);
if ( size == filesize)
{
continue;
}
src = getAssets().open(filename);
len = src.read(buf, 0, 1024);
}
}
if (len > 0)
{
int total_filesize = 0;
OutputStream dst;
try
{
dst = new FileOutputStream(baseDir + "/" + filename);
} catch (IOException e) {
Log.e("MinetestAssetCopy","Copying file: " + baseDir +
"/" + filename + " FAILED (couldn't open output file)");
e.printStackTrace();
src.close();
continue;
}
dst.write(buf, 0, len);
total_filesize += len;
while ((len = src.read(buf)) > 0)
{
dst.write(buf, 0, len);
total_filesize += len;
}
dst.close();
Log.v("MinetestAssetCopy","Copied file: " +
m_tocopy.get(i) + " (" + total_filesize +
" bytes)");
}
else if (len < 0)
{
Log.e("MinetestAssetCopy","Copying file: " +
m_tocopy.get(i) + " failed, size < 0");
}
src.close();
}
catch (IOException e)
{
Log.e("MinetestAssetCopy","Copying file: " +
m_tocopy.get(i) + " failed");
e.printStackTrace();
}
}
return "";
}
/**
* update progress bar
*/
protected void onProgressUpdate(Integer... progress)
{
if (m_copy_started)
{
boolean shortened = false;
String todisplay = m_tocopy.get(progress[0]);
m_ProgressBar.setProgress(progress[0]);
m_Filename.setText(todisplay);
}
else
{
boolean shortened = false;
String todisplay = m_Foldername;
String full_text = "scanning " + todisplay + " ...";
m_Filename.setText(full_text);
}
}
/**
* check al files and folders in filelist
*/
protected void ProcessFileList()
{
String FlashBaseDir =
Environment.getExternalStorageDirectory().getAbsolutePath();
Iterator itr = m_filenames.iterator();
while (itr.hasNext())
{
String current_path = (String) itr.next();
String FlashPath = FlashBaseDir + "/" + current_path;
if (isAssetFolder(current_path))
{
/* store information and update gui */
m_Foldername = current_path;
publishProgress(0);
/* open file in order to check if it's a folder */
File current_folder = new File(FlashPath);
if (!current_folder.exists())
{
if (!current_folder.mkdirs())
{
Log.e("MinetestAssetCopy","\t failed create folder: " +
FlashPath);
}
else
{
Log.v("MinetestAssetCopy","\t created folder: " +
FlashPath);
}
}
continue;
}
/* if it's not a folder it's most likely a file */
boolean refresh = true;
File testme = new File(FlashPath);
long asset_filesize = -1;
long stored_filesize = -1;
if (testme.exists())
{
try
{
AssetFileDescriptor fd = getAssets().openFd(current_path);
asset_filesize = fd.getLength();
fd.close();
}
catch (IOException e)
{
refresh = true;
m_asset_size_unknown.add(current_path);
Log.e("MinetestAssetCopy","Failed to open asset file \"" +
FlashPath + "\" for size check");
}
stored_filesize = testme.length();
if (asset_filesize == stored_filesize)
{
refresh = false;
}
}
if (refresh)
{
m_tocopy.add(current_path);
}
}
}
/**
* read list of folders prepared on package build
*/
protected void BuildFolderList()
{
try
{
InputStream is = getAssets().open("index.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine();
while (line != null)
{
m_foldernames.add(line);
line = reader.readLine();
}
is.close();
} catch (IOException e1)
{
Log.e("MinetestAssetCopy","Error on processing index.txt");
e1.printStackTrace();
}
}
/**
* read list of asset files prepared on package build
*/
protected void BuildFileList()
{
long entrycount = 0;
try
{
InputStream is = getAssets().open("filelist.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine();
while (line != null)
{
m_filenames.add(line);
line = reader.readLine();
entrycount ++;
}
is.close();
}
catch (IOException e1)
{
Log.e("MinetestAssetCopy","Error on processing filelist.txt");
e1.printStackTrace();
}
}
protected void onPostExecute (String result)
{
finish();
}
protected boolean isAssetFolder(String path)
{
return m_foldernames.contains(path);
}
boolean m_copy_started = false;
String m_Foldername = "media";
Vector<String> m_foldernames;
Vector<String> m_filenames;
Vector<String> m_tocopy;
Vector<String> m_asset_size_unknown;
}
}

View File

@ -1,4 +1,4 @@
package org.minetest.minetest;
package net.minetest.minetest;
import android.app.Activity;
import android.app.AlertDialog;

View File

@ -1,4 +1,4 @@
package org.minetest.minetest;
package net.minetest.minetest;
import android.app.NativeActivity;
import android.content.Intent;
@ -12,23 +12,23 @@ public class MtNativeActivity extends NativeActivity {
super.onCreate(savedInstanceState);
m_MessagReturnCode = -1;
m_MessageReturnValue = "";
}
@Override
public void onDestroy() {
super.onDestroy();
}
public void copyAssets() {
Intent intent = new Intent(this, MinetestAssetCopy.class);
startActivity(intent);
}
public void showDialog(String acceptButton, String hint, String current,
int editType) {
Intent intent = new Intent(this, MinetestTextEntry.class);
Bundle params = new Bundle();
params.putString("acceptButton", acceptButton);
@ -40,37 +40,37 @@ public class MtNativeActivity extends NativeActivity {
m_MessageReturnValue = "";
m_MessagReturnCode = -1;
}
public static native void putMessageBoxResult(String text);
/* ugly code to workaround putMessageBoxResult not beeing found */
public int getDialogState() {
return m_MessagReturnCode;
}
public String getDialogValue() {
m_MessagReturnCode = -1;
return m_MessageReturnValue;
}
public float getDensity() {
return getResources().getDisplayMetrics().density;
}
public int getDisplayWidth() {
return getResources().getDisplayMetrics().widthPixels;
}
public int getDisplayHeight() {
return getResources().getDisplayMetrics().heightPixels;
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == 101) {
if (resultCode == RESULT_OK) {
String text = data.getStringExtra("text");
String text = data.getStringExtra("text");
m_MessagReturnCode = 0;
m_MessageReturnValue = text;
}
@ -79,15 +79,22 @@ public class MtNativeActivity extends NativeActivity {
}
}
}
static {
System.loadLibrary("openal");
System.loadLibrary("ogg");
System.loadLibrary("vorbis");
System.loadLibrary("ssl");
System.loadLibrary("crypto");
System.loadLibrary("gmp");
System.loadLibrary("iconv");
// We don't have to load libminetest.so ourselves,
// but if we do, we get nicer logcat errors when
// loading fails.
System.loadLibrary("minetest");
}
private int m_MessagReturnCode;
private String m_MessageReturnValue;
}

View File

@ -1,288 +0,0 @@
package org.minetest.minetest;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Vector;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Display;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MinetestAssetCopy extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.assetcopy);
m_ProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
m_Filename = (TextView) findViewById(R.id.textView1);
Display display = getWindowManager().getDefaultDisplay();
m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8);
m_ProgressBar.invalidate();
m_AssetCopy = new copyAssetTask();
m_AssetCopy.execute();
}
ProgressBar m_ProgressBar;
TextView m_Filename;
copyAssetTask m_AssetCopy;
private class copyAssetTask extends AsyncTask<String, Integer, String>{
private void copyElement(String name, String path) {
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String full_path;
if (path != "") {
full_path = path + "/" + name;
}
else {
full_path = name;
}
//is a folder read asset list
if (m_foldernames.contains(full_path)) {
m_Foldername = full_path;
publishProgress(0);
File current_folder = new File(baseDir + "/" + full_path);
if (!current_folder.exists()) {
if (!current_folder.mkdirs()) {
Log.w("MinetestAssetCopy","\t failed create folder: " + baseDir + "/" + full_path);
}
else {
Log.w("MinetestAssetCopy","\t created folder: " + baseDir + "/" + full_path);
}
}
try {
String[] current_assets = getAssets().list(full_path);
for(int i=0; i < current_assets.length; i++) {
copyElement(current_assets[i],full_path);
}
} catch (IOException e) {
Log.w("MinetestAssetCopy","\t failed to read contents of folder");
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//is a file just copy
else {
boolean refresh = true;
File testme = new File(baseDir + "/" + full_path);
long asset_filesize = -1;
long stored_filesize = -1;
if (testme.exists()) {
try {
AssetFileDescriptor fd = getAssets().openFd(full_path);
asset_filesize = fd.getLength();
fd.close();
} catch (IOException e) {
refresh = true;
m_asset_size_unknown.add(full_path);
}
stored_filesize = testme.length();
if (asset_filesize == stored_filesize) {
refresh = false;
}
}
if (refresh) {
m_tocopy.add(full_path);
}
}
}
private long getFullSize(String filename) {
long size = 0;
try {
InputStream src = getAssets().open(filename);
byte[] buf = new byte[1024];
int len = 0;
while ((len = src.read(buf)) > 0) {
size += len;
}
}
catch (IOException e) {
e.printStackTrace();
}
return size;
}
@Override
protected String doInBackground(String... files) {
m_foldernames = new Vector<String>();
m_tocopy = new Vector<String>();
m_asset_size_unknown = new Vector<String>();
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
File TempFolder = new File(baseDir + "Minetest/tmp/");
if (!TempFolder.exists()) {
TempFolder.mkdir();
}
else {
File[] todel = TempFolder.listFiles();
for(int i=0; i < todel.length; i++) {
Log.w("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath());
todel[i].delete();
}
}
// add a .nomedia file
try {
OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
dst.close();
} catch (IOException e) {
Log.w("MinetestAssetCopy","Failed to create .nomedia file");
e.printStackTrace();
}
try {
InputStream is = getAssets().open("index.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine();
while(line != null){
m_foldernames.add(line);
line = reader.readLine();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
copyElement("Minetest","");
m_copy_started = true;
m_ProgressBar.setMax(m_tocopy.size());
for (int i = 0; i < m_tocopy.size(); i++) {
try {
String filename = m_tocopy.get(i);
publishProgress(i);
boolean asset_size_unknown = false;
long filesize = -1;
if (m_asset_size_unknown.contains(filename)) {
File testme = new File(baseDir + "/" + filename);
if(testme.exists()) {
filesize = testme.length();
}
asset_size_unknown = true;
}
InputStream src;
try {
src = getAssets().open(filename);
} catch (IOException e) {
Log.w("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)");
// TODO Auto-generated catch block
e.printStackTrace();
continue;
}
// Transfer bytes from in to out
byte[] buf = new byte[1*1024];
int len = src.read(buf, 0, 1024);
/* following handling is crazy but we need to deal with */
/* compressed assets.Flash chips limited livetime sue to */
/* write operations, we can't allow large files to destroy */
/* users flash. */
if (asset_size_unknown) {
if ( (len > 0) && (len < buf.length) && (len == filesize)) {
src.close();
continue;
}
if (len == buf.length) {
src.close();
long size = getFullSize(filename);
if ( size == filesize) {
continue;
}
src = getAssets().open(filename);
len = src.read(buf, 0, 1024);
}
}
if (len > 0) {
int total_filesize = 0;
OutputStream dst;
try {
dst = new FileOutputStream(baseDir + "/" + filename);
} catch (IOException e) {
Log.w("MinetestAssetCopy","Copying file: " + baseDir +
"/" + filename + " FAILED (couldn't open output file)");
e.printStackTrace();
src.close();
continue;
}
dst.write(buf, 0, len);
total_filesize += len;
while ((len = src.read(buf)) > 0) {
dst.write(buf, 0, len);
total_filesize += len;
}
dst.close();
Log.w("MinetestAssetCopy","Copied file: " + m_tocopy.get(i) + " (" + total_filesize + " bytes)");
}
else if (len < 0) {
Log.w("MinetestAssetCopy","Copying file: " + m_tocopy.get(i) + " failed, size < 0");
}
src.close();
} catch (IOException e) {
Log.w("MinetestAssetCopy","Copying file: " + m_tocopy.get(i) + " failed");
e.printStackTrace();
}
}
return "";
}
protected void onProgressUpdate(Integer... progress) {
if (m_copy_started) {
m_ProgressBar.setProgress(progress[0]);
m_Filename.setText(m_tocopy.get(progress[0]));
}
else {
m_Filename.setText("scanning " + m_Foldername + " ...");
}
}
protected void onPostExecute (String result) {
finish();
}
boolean m_copy_started = false;
String m_Foldername = "media";
Vector<String> m_foldernames;
Vector<String> m_tocopy;
Vector<String> m_asset_size_unknown;
}
}

View File

@ -1,5 +1,10 @@
-- Minetest: builtin/misc_helpers.lua
--------------------------------------------------------------------------------
-- Localize functions to avoid table lookups (better performance).
local table_insert = table.insert
local string_sub, string_find = string.sub, string.find
--------------------------------------------------------------------------------
function basic_dump(o)
local tp = type(o)
@ -89,13 +94,13 @@ function dump2(o, name, dumped)
-- the form _G["table: 0xFFFFFFF"]
keyStr = string.format("_G[%q]", tostring(k))
-- Dump key table
table.insert(t, dump2(k, keyStr, dumped))
table_insert(t, dump2(k, keyStr, dumped))
end
else
keyStr = basic_dump(k)
end
local vname = string.format("%s[%s]", name, keyStr)
table.insert(t, dump2(v, vname, dumped))
table_insert(t, dump2(v, vname, dumped))
end
return string.format("%s = {}\n%s", name, table.concat(t))
end
@ -130,7 +135,7 @@ function dump(o, indent, nested, level)
local t = {}
local dumped_indexes = {}
for i, v in ipairs(o) do
table.insert(t, dump(v, indent, nested, level + 1))
table_insert(t, dump(v, indent, nested, level + 1))
dumped_indexes[i] = true
end
for k, v in pairs(o) do
@ -139,13 +144,13 @@ function dump(o, indent, nested, level)
k = "["..dump(k, indent, nested, level + 1).."]"
end
v = dump(v, indent, nested, level + 1)
table.insert(t, k.." = "..v)
table_insert(t, k.." = "..v)
end
end
nested[o] = nil
if indent ~= "" then
local indent_str = "\n"..string.rep(indent, level)
local end_indent_str = "\n"..string.rep("\t", level - 1)
local end_indent_str = "\n"..string.rep(indent, level - 1)
return string.format("{%s%s%s}",
indent_str,
table.concat(t, ","..indent_str),
@ -155,17 +160,47 @@ function dump(o, indent, nested, level)
end
--------------------------------------------------------------------------------
function string:split(sep)
local sep, fields = sep or ",", {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
function string.split(str, delim, include_empty, max_splits, sep_is_pattern)
delim = delim or ","
max_splits = max_splits or -1
local items = {}
local pos, len, seplen = 1, #str, #delim
local plain = not sep_is_pattern
max_splits = max_splits + 1
repeat
local np, npe = string_find(str, delim, pos, plain)
np, npe = (np or (len+1)), (npe or (len+1))
if (not np) or (max_splits == 1) then
np = len + 1
npe = np
end
local s = string_sub(str, pos, np - 1)
if include_empty or (s ~= "") then
max_splits = max_splits - 1
table_insert(items, s)
end
pos = npe + 1
until (max_splits == 0) or (pos > (len + 1))
return items
end
--------------------------------------------------------------------------------
function table.indexof(list, val)
for i = 1, #list do
if list[i] == val then
return i
end
end
return -1
end
assert(table.indexof({"foo", "bar"}, "foo") == 1)
assert(table.indexof({"foo", "bar"}, "baz") == -1)
--------------------------------------------------------------------------------
function file_exists(filename)
local f = io.open(filename, "r")
if f==nil then
if f == nil then
return false
else
f:close()
@ -192,6 +227,17 @@ function math.hypot(x, y)
return x * math.sqrt(1 + t * t)
end
--------------------------------------------------------------------------------
function math.sign(x, tolerance)
tolerance = tolerance or 0
if x > tolerance then
return 1
elseif x < -tolerance then
return -1
end
return 0
end
--------------------------------------------------------------------------------
function get_last_folder(text,count)
local parts = text:split(DIR_DELIM)
@ -267,8 +313,8 @@ function core.splittext(text,charlimit)
local current_idx = 1
local start,stop = string.find(text," ",current_idx)
local nl_start,nl_stop = string.find(text,"\n",current_idx)
local start,stop = string_find(text, " ", current_idx)
local nl_start,nl_stop = string_find(text, "\n", current_idx)
local gotnewline = false
if nl_start ~= nil and (start == nil or nl_start < start) then
start = nl_start
@ -278,7 +324,7 @@ function core.splittext(text,charlimit)
local last_line = ""
while start ~= nil do
if string.len(last_line) + (stop-start) > charlimit then
table.insert(retval,last_line)
table_insert(retval, last_line)
last_line = ""
end
@ -286,17 +332,17 @@ function core.splittext(text,charlimit)
last_line = last_line .. " "
end
last_line = last_line .. string.sub(text,current_idx,stop -1)
last_line = last_line .. string_sub(text, current_idx, stop - 1)
if gotnewline then
table.insert(retval,last_line)
table_insert(retval, last_line)
last_line = ""
gotnewline = false
end
current_idx = stop+1
start,stop = string.find(text," ",current_idx)
nl_start,nl_stop = string.find(text,"\n",current_idx)
start,stop = string_find(text, " ", current_idx)
nl_start,nl_stop = string_find(text, "\n", current_idx)
if nl_start ~= nil and (start == nil or nl_start < start) then
start = nl_start
@ -307,11 +353,11 @@ function core.splittext(text,charlimit)
--add last part of text
if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
table.insert(retval,last_line)
table.insert(retval,string.sub(text,current_idx))
table_insert(retval, last_line)
table_insert(retval, string_sub(text, current_idx))
else
last_line = last_line .. " " .. string.sub(text,current_idx)
table.insert(retval,last_line)
last_line = last_line .. " " .. string_sub(text, current_idx)
table_insert(retval, last_line)
end
return retval
@ -432,7 +478,8 @@ function core.explode_table_event(evt)
local t = parts[1]:trim()
local r = tonumber(parts[2]:trim())
local c = tonumber(parts[3]:trim())
if type(r) == "number" and type(c) == "number" and t ~= "INV" then
if type(r) == "number" and type(c) == "number"
and t ~= "INV" then
return {type=t, row=r, column=c}
end
end
@ -466,10 +513,88 @@ function core.explode_scrollbar_event(evt)
end
--------------------------------------------------------------------------------
function core.pos_to_string(pos)
return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
function core.pos_to_string(pos, decimal_places)
local x = pos.x
local y = pos.y
local z = pos.z
if decimal_places ~= nil then
x = string.format("%." .. decimal_places .. "f", x)
y = string.format("%." .. decimal_places .. "f", y)
z = string.format("%." .. decimal_places .. "f", z)
end
return "(" .. x .. "," .. y .. "," .. z .. ")"
end
--------------------------------------------------------------------------------
function core.string_to_pos(value)
if value == nil then
return nil
end
local p = {}
p.x, p.y, p.z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
if p.x and p.y and p.z then
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
return p
end
local p = {}
p.x, p.y, p.z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
if p.x and p.y and p.z then
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
return p
end
return nil
end
assert(core.string_to_pos("10.0, 5, -2").x == 10)
assert(core.string_to_pos("( 10.0, 5, -2)").z == -2)
assert(core.string_to_pos("asd, 5, -2)") == nil)
--------------------------------------------------------------------------------
function core.string_to_area(value)
local p1, p2 = unpack(value:split(") ("))
if p1 == nil or p2 == nil then
return nil
end
p1 = core.string_to_pos(p1 .. ")")
p2 = core.string_to_pos("(" .. p2)
if p1 == nil or p2 == nil then
return nil
end
return p1, p2
end
local function test_string_to_area()
local p1, p2 = core.string_to_area("(10.0, 5, -2) ( 30.2, 4, -12.53)")
assert(p1.x == 10.0 and p1.y == 5 and p1.z == -2)
assert(p2.x == 30.2 and p2.y == 4 and p2.z == -12.53)
p1, p2 = core.string_to_area("(10.0, 5, -2 30.2, 4, -12.53")
assert(p1 == nil and p2 == nil)
p1, p2 = core.string_to_area("(10.0, 5,) -2 fgdf2, 4, -12.53")
assert(p1 == nil and p2 == nil)
end
test_string_to_area()
--------------------------------------------------------------------------------
function table.copy(t, seen)
local n = {}
seen = seen or {}
seen[t] = n
for k, v in pairs(t) do
n[(type(k) == "table" and (seen[k] or table.copy(k, seen))) or k] =
(type(v) == "table" and (seen[v] or table.copy(v, seen))) or v
end
return n
end
--------------------------------------------------------------------------------
-- mainmenu only functions
--------------------------------------------------------------------------------
@ -484,27 +609,33 @@ if INIT == "mainmenu" then
return nil
end
function fgettext(text, ...)
function fgettext_ne(text, ...)
text = core.gettext(text)
local arg = {n=select('#', ...), ...}
if arg.n >= 1 then
-- Insert positional parameters ($1, $2, ...)
result = ''
pos = 1
local result = ''
local pos = 1
while pos <= text:len() do
newpos = text:find('[$]', pos)
local newpos = text:find('[$]', pos)
if newpos == nil then
result = result .. text:sub(pos)
pos = text:len() + 1
else
paramindex = tonumber(text:sub(newpos+1, newpos+1))
result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
local paramindex =
tonumber(text:sub(newpos+1, newpos+1))
result = result .. text:sub(pos, newpos-1)
.. tostring(arg[paramindex])
pos = newpos + 2
end
end
text = result
end
return core.formspec_escape(text)
return text
end
function fgettext(text, ...)
return core.formspec_escape(fgettext_ne(text, ...))
end
end

View File

@ -1,223 +1,218 @@
-- Minetest: builtin/serialize.lua
-- https://github.com/fab13n/metalua/blob/no-dll/src/lib/serialize.lua
-- Copyright (c) 2006-2997 Fabien Fleutot <metalua@gmail.com>
--- Lua module to serialize values as Lua code.
-- From: https://github.com/fab13n/metalua/blob/no-dll/src/lib/serialize.lua
-- License: MIT
--------------------------------------------------------------------------------
-- Serialize an object into a source code string. This string, when passed as
-- an argument to deserialize(), returns an object structurally identical
-- to the original one. The following are currently supported:
-- * strings, numbers, booleans, nil
-- * tables thereof. Tables can have shared part, but can't be recursive yet.
-- Caveat: metatables and environments aren't saved.
-- @copyright 2006-2997 Fabien Fleutot <metalua@gmail.com>
-- @author Fabien Fleutot <metalua@gmail.com>
-- @author ShadowNinja <shadowninja@minetest.net>
--------------------------------------------------------------------------------
local no_identity = { number=1, boolean=1, string=1, ['nil']=1 }
--- Serialize an object into a source code string. This string, when passed as
-- an argument to deserialize(), returns an object structurally identical to
-- the original one. The following are currently supported:
-- * Booleans, numbers, strings, and nil.
-- * Functions; uses interpreter-dependent (and sometimes platform-dependent) bytecode!
-- * Tables; they can cantain multiple references and can be recursive, but metatables aren't saved.
-- This works in two phases:
-- 1. Recursively find and record multiple references and recursion.
-- 2. Recursively dump the value into a string.
-- @param x Value to serialize (nil is allowed).
-- @return load()able string containing the value.
function core.serialize(x)
local local_index = 1 -- Top index of the "_" local table in the dump
-- table->nil/1/2 set of tables seen.
-- nil = not seen, 1 = seen once, 2 = seen multiple times.
local seen = {}
local gensym_max = 0 -- index of the gensym() symbol generator
local seen_once = { } -- element->true set of elements seen exactly once in the table
local multiple = { } -- element->varname set of elements seen more than once
local nested = { } -- transient, set of elements currently being traversed
local nest_points = { }
local nest_patches = { }
local function gensym()
gensym_max = gensym_max + 1 ; return gensym_max
end
-----------------------------------------------------------------------------
-- nest_points are places where a table appears within itself, directly or not.
-- for instance, all of these chunks create nest points in table x:
-- "x = { }; x[x] = 1", "x = { }; x[1] = x", "x = { }; x[1] = { y = { x } }".
-- To handle those, two tables are created by mark_nest_point:
-- * nest_points [parent] associates all keys and values in table parent which
-- create a nest_point with boolean `true'
-- * nest_patches contain a list of { parent, key, value } tuples creating
-- a nest point. They're all dumped after all the other table operations
-- have been performed.
-- nest_points are places where a table appears within itself, directly
-- or not. For instance, all of these chunks create nest points in
-- table x: "x = {}; x[x] = 1", "x = {}; x[1] = x",
-- "x = {}; x[1] = {y = {x}}".
-- To handle those, two tables are used by mark_nest_point:
-- * nested - Transient set of tables being currently traversed.
-- Used for detecting nested tables.
-- * nest_points - parent->{key=value, ...} table cantaining the nested
-- keys and values in the parent. They're all dumped after all the
-- other table operations have been performed.
--
-- mark_nest_point (p, k, v) fills tables nest_points and nest_patches with
-- informations required to remember that key/value (k,v) create a nest point
-- in table parent. It also marks `parent' as occuring multiple times, since
-- several references to it will be required in order to patch the nest
-- points.
-----------------------------------------------------------------------------
local function mark_nest_point (parent, k, v)
-- mark_nest_point(p, k, v) fills nest_points with information required
-- to remember that key/value (k, v) creates a nest point in table
-- parent. It also marks "parent" and the nested item(s) as occuring
-- multiple times, since several references to it will be required in
-- order to patch the nest points.
local nest_points = {}
local nested = {}
local function mark_nest_point(parent, k, v)
local nk, nv = nested[k], nested[v]
assert (not nk or seen_once[k] or multiple[k])
assert (not nv or seen_once[v] or multiple[v])
local mode = (nk and nv and "kv") or (nk and "k") or ("v")
local parent_np = nest_points [parent]
local pair = { k, v }
if not parent_np then parent_np = { }; nest_points [parent] = parent_np end
parent_np [k], parent_np [v] = nk, nv
table.insert (nest_patches, { parent, k, v })
seen_once [parent], multiple [parent] = nil, true
local np = nest_points[parent]
if not np then
np = {}
nest_points[parent] = np
end
np[k] = v
seen[parent] = 2
if nk then seen[k] = 2 end
if nv then seen[v] = 2 end
end
-----------------------------------------------------------------------------
-- First pass, list the tables and functions which appear more than once in x
-----------------------------------------------------------------------------
local function mark_multiple_occurences (x)
if no_identity [type(x)] then return end
if seen_once [x] then seen_once [x], multiple [x] = nil, true
elseif multiple [x] then -- pass
else seen_once [x] = true end
if type (x) == 'table' then
nested [x] = true
for k, v in pairs (x) do
if nested[k] or nested[v] then mark_nest_point (x, k, v) else
mark_multiple_occurences (k)
mark_multiple_occurences (v)
-- First phase, list the tables and functions which appear more than
-- once in x.
local function mark_multiple_occurences(x)
local tp = type(x)
if tp ~= "table" and tp ~= "function" then
-- No identity (comparison is done by value, not by instance)
return
end
if seen[x] == 1 then
seen[x] = 2
elseif seen[x] ~= 2 then
seen[x] = 1
end
if tp == "table" then
nested[x] = true
for k, v in pairs(x) do
if nested[k] or nested[v] then
mark_nest_point(x, k, v)
else
mark_multiple_occurences(k)
mark_multiple_occurences(v)
end
end
nested [x] = nil
nested[x] = nil
end
end
local dumped = { } -- multiply occuring values already dumped in localdefs
local localdefs = { } -- already dumped local definitions as source code lines
local dumped = {} -- object->varname set
local local_defs = {} -- Dumped local definitions as source code lines
-- mutually recursive functions:
-- Mutually recursive local functions:
local dump_val, dump_or_ref_val
--------------------------------------------------------------------
-- if x occurs multiple times, dump the local var rather than the
-- value. If it's the first time it's dumped, also dump the content
-- in localdefs.
--------------------------------------------------------------------
function dump_or_ref_val (x)
if nested[x] then return 'false' end -- placeholder for recursive reference
if not multiple[x] then return dump_val (x) end
local var = dumped [x]
if var then return "_[" .. var .. "]" end -- already referenced
local val = dump_val(x) -- first occurence, create and register reference
var = gensym()
table.insert(localdefs, "_["..var.."]="..val)
dumped [x] = var
return "_[" .. var .. "]"
-- If x occurs multiple times, dump the local variable rather than
-- the value. If it's the first time it's dumped, also dump the
-- content in local_defs.
function dump_or_ref_val(x)
if seen[x] ~= 2 then
return dump_val(x)
end
local var = dumped[x]
if var then -- Already referenced
return var
end
-- First occurence, create and register reference
local val = dump_val(x)
local i = local_index
local_index = local_index + 1
var = "_["..i.."]"
table.insert(local_defs, var.." = "..val)
dumped[x] = var
return var
end
-----------------------------------------------------------------------------
-- Second pass, dump the object; subparts occuring multiple times are dumped
-- in local variables which can be referenced multiple times;
-- care is taken to dump locla vars in asensible order.
-----------------------------------------------------------------------------
-- Second phase. Dump the object; subparts occuring multiple times
-- are dumped in local variables which can be referenced multiple
-- times. Care is taken to dump local vars in a sensible order.
function dump_val(x)
local t = type(x)
if x==nil then return 'nil'
elseif t=="number" then return tostring(x)
elseif t=="string" then return string.format("%q", x)
elseif t=="boolean" then return x and "true" or "false"
elseif t=="function" then
local tp = type(x)
if x == nil then return "nil"
elseif tp == "string" then return string.format("%q", x)
elseif tp == "boolean" then return x and "true" or "false"
elseif tp == "function" then
return string.format("loadstring(%q)", string.dump(x))
elseif t=="table" then
local acc = { }
local idx_dumped = { }
local np = nest_points [x]
elseif tp == "number" then
-- Serialize integers with string.format to prevent
-- scientific notation, which doesn't preserve
-- precision and breaks things like node position
-- hashes. Serialize floats normally.
if math.floor(x) == x then
return string.format("%d", x)
else
return tostring(x)
end
elseif tp == "table" then
local vals = {}
local idx_dumped = {}
local np = nest_points[x]
for i, v in ipairs(x) do
if np and np[v] then
table.insert (acc, 'false') -- placeholder
else
table.insert (acc, dump_or_ref_val(v))
if not np or not np[i] then
table.insert(vals, dump_or_ref_val(v))
end
idx_dumped[i] = true
end
for k, v in pairs(x) do
if np and (np[k] or np[v]) then
--check_multiple(k); check_multiple(v) -- force dumps in localdefs
elseif not idx_dumped[k] then
table.insert (acc, "[" .. dump_or_ref_val(k) .. "] = " .. dump_or_ref_val(v))
if (not np or not np[k]) and
not idx_dumped[k] then
table.insert(vals,
"["..dump_or_ref_val(k).."] = "
..dump_or_ref_val(v))
end
end
return "{ "..table.concat(acc,", ").." }"
return "{"..table.concat(vals, ", ").."}"
else
error ("Can't serialize data of type "..t)
end
end
local function dump_nest_patches()
for _, entry in ipairs(nest_patches) do
local p, k, v = unpack (entry)
assert (multiple[p])
local set = dump_or_ref_val (p) .. "[" .. dump_or_ref_val (k) .. "] = " ..
dump_or_ref_val (v) .. " -- rec "
table.insert (localdefs, set)
error("Can't serialize data of type "..tp)
end
end
mark_multiple_occurences (x)
local toplevel = dump_or_ref_val (x)
dump_nest_patches()
local function dump_nest_points()
for parent, vals in pairs(nest_points) do
for k, v in pairs(vals) do
table.insert(local_defs, dump_or_ref_val(parent)
.."["..dump_or_ref_val(k).."] = "
..dump_or_ref_val(v))
end
end
end
if next (localdefs) then
return "local _={ }\n" ..
table.concat (localdefs, "\n") ..
"\nreturn " .. toplevel
mark_multiple_occurences(x)
local top_level = dump_or_ref_val(x)
dump_nest_points()
if next(local_defs) then
return "local _ = {}\n"
..table.concat(local_defs, "\n")
.."\nreturn "..top_level
else
return "return " .. toplevel
return "return "..top_level
end
end
-- Deserialization.
-- http://stackoverflow.com/questions/5958818/loading-serialized-data-into-a-table
--
-- Deserialization
local env = {
loadstring = loadstring,
}
local function noop() end
local safe_env = {
loadstring = noop,
loadstring = function() end,
}
local function stringtotable(sdata, safe)
if sdata:byte(1) == 27 then return nil, "binary bytecode prohibited" end
local f, message = assert(loadstring(sdata))
if not f then return nil, message end
if safe then
setfenv(f, safe_env)
function core.deserialize(str, safe)
if str:byte(1) == 0x1B then
return nil, "Bytecode prohibited"
end
local f, err = loadstring(str)
if not f then return nil, err end
setfenv(f, safe and safe_env or env)
local good, data = pcall(f)
if good then
return data
else
setfenv(f, env)
return nil, data
end
return f()
end
function core.deserialize(sdata, safe)
local table = {}
local okay, results = pcall(stringtotable, sdata, safe)
if okay then
return results
end
core.log('error', 'core.deserialize(): '.. results)
return nil
end
-- Run some unit tests
local function unit_test()
function unitTest(name, success)
if not success then
error(name .. ': failed')
end
end
-- Unit tests
local test_in = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
local test_out = core.deserialize(core.serialize(test_in))
unittest_input = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
unittest_output = core.deserialize(core.serialize(unittest_input))
assert(test_in.cat.sound == test_out.cat.sound)
assert(test_in.cat.speed == test_out.cat.speed)
assert(test_in.dog.sound == test_out.dog.sound)
unitTest("test 1a", unittest_input.cat.sound == unittest_output.cat.sound)
unitTest("test 1b", unittest_input.cat.speed == unittest_output.cat.speed)
unitTest("test 1c", unittest_input.dog.sound == unittest_output.dog.sound)
unittest_input = {escapechars="\n\r\t\v\\\"\'", noneuropean="θשׁ٩∂"}
unittest_output = core.deserialize(core.serialize(unittest_input))
unitTest("test 3a", unittest_input.escapechars == unittest_output.escapechars)
unitTest("test 3b", unittest_input.noneuropean == unittest_output.noneuropean)
end
unit_test() -- Run it
unit_test = nil -- Hide it
test_in = {escape_chars="\n\r\t\v\\\"\'", non_european="θשׁ٩∂"}
test_out = core.deserialize(core.serialize(test_in))
assert(test_in.escape_chars == test_out.escape_chars)
assert(test_in.non_european == test_out.non_european)

53
builtin/common/strict.lua Normal file
View File

@ -0,0 +1,53 @@
-- Always warn when creating a global variable, even outside of a function.
-- This ignores mod namespaces (variables with the same name as the current mod).
local WARN_INIT = false
function core.global_exists(name)
return rawget(_G, name) ~= nil
end
local meta = {}
local declared = {}
-- Key is source file, line, and variable name; seperated by NULs
local warned = {}
function meta:__newindex(name, value)
local info = debug.getinfo(2, "Sl")
local desc = ("%s:%d"):format(info.short_src, info.currentline)
if not declared[name] then
local warn_key = ("%s\0%d\0%s"):format(info.source,
info.currentline, name)
if not warned[warn_key] and info.what ~= "main" and
info.what ~= "C" then
core.log("warning", ("Assignment to undeclared "..
"global %q inside a function at %s.")
:format(name, desc))
warned[warn_key] = true
end
declared[name] = true
end
-- Ignore mod namespaces
if WARN_INIT and name ~= core.get_current_modname() then
core.log("warning", ("Global variable %q created at %s.")
:format(name, desc))
end
rawset(self, name, value)
end
function meta:__index(name)
local info = debug.getinfo(2, "Sl")
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
if not declared[name] and not warned[warn_key] and info.what ~= "C" then
core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
:format(name, info.short_src, info.currentline))
warned[warn_key] = true
end
return rawget(self, name)
end
setmetatable(_G, meta)

View File

@ -39,6 +39,14 @@ function vector.round(v)
}
end
function vector.apply(v, func)
return {
x = func(v.x),
y = func(v.y),
z = func(v.z)
}
end
function vector.distance(a, b)
local x = a.x - b.x
local y = a.y - b.y

View File

@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--self program is free software; you can redistribute it and/or modify
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--self program is distributed in the hope that it will be useful,
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with self program; if not, write to the Free Software Foundation, Inc.,
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@ -24,11 +24,11 @@ local function buttonbar_formspec(self)
local formspec = string.format("box[%f,%f;%f,%f;%s]",
self.pos.x,self.pos.y ,self.size.x,self.size.y,self.bgcolor)
for i=self.startbutton,#self.buttons,1 do
local btn_name = self.buttons[i].name
local btn_pos = {}
if self.orientation == "horizontal" then
btn_pos.x = self.pos.x + --base pos
(i - self.startbutton) * self.btn_size + --button offset
@ -36,7 +36,7 @@ local function buttonbar_formspec(self)
else
btn_pos.x = self.pos.x + (self.btn_size * 0.05)
end
if self.orientation == "vertical" then
btn_pos.y = self.pos.y + --base pos
(i - self.startbutton) * self.btn_size + --button offset
@ -44,23 +44,23 @@ local function buttonbar_formspec(self)
else
btn_pos.y = self.pos.y + (self.btn_size * 0.05)
end
if (self.orientation == "vertical" and
(btn_pos.y + self.btn_size <= self.pos.y + self.size.y)) or
(self.orientation == "horizontal" and
(btn_pos.x + self.btn_size <= self.pos.x + self.size.x)) then
local borders="true"
if self.buttons[i].image ~= nil then
borders="false"
end
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;%s]",
string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;%s]tooltip[%s;%s]",
btn_pos.x, btn_pos.y, self.btn_size, self.btn_size,
self.buttons[i].image, btn_name, self.buttons[i].caption,
borders)
borders, btn_name, self.buttons[i].tooltip)
else
--print("end of displayable buttons: orientation: " .. self.orientation)
--print( "button_end: " .. (btn_pos.y + self.btn_size - (self.btn_size * 0.05)))
@ -75,7 +75,7 @@ local function buttonbar_formspec(self)
btn_dec_pos.y = self.pos.y + (self.btn_size * 0.05)
local btn_inc_pos = {}
local btn_size = {}
if self.orientation == "horizontal" then
btn_size.x = 0.5
btn_size.y = self.btn_size
@ -87,25 +87,25 @@ local function buttonbar_formspec(self)
btn_inc_pos.x = self.pos.x + (self.btn_size * 0.05)
btn_inc_pos.y = self.pos.y + self.size.y - 0.5
end
local text_dec = "<"
local text_inc = ">"
if self.orientation == "vertical" then
text_dec = "^"
text_inc = "v"
end
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_dec_%s;%s;true;true]",
btn_dec_pos.x, btn_dec_pos.y, btn_size.x, btn_size.y,
self.name, text_dec)
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_inc_%s;%s;true;true]",
btn_inc_pos.x, btn_inc_pos.y, btn_size.x, btn_size.y,
self.name, text_inc)
end
return formspec
end
@ -113,16 +113,16 @@ local function buttonbar_buttonhandler(self, fields)
if fields["btnbar_inc_" .. self.name] ~= nil and
self.startbutton < #self.buttons then
self.startbutton = self.startbutton + 1
return true
end
if fields["btnbar_dec_" .. self.name] ~= nil and self.startbutton > 1 then
self.startbutton = self.startbutton - 1
return true
end
for i=1,#self.buttons,1 do
if fields[self.buttons[i].name] ~= nil then
return self.userbuttonhandler(fields)
@ -134,34 +134,35 @@ local buttonbar_metatable = {
handle_buttons = buttonbar_buttonhandler,
handle_events = function(self, event) end,
get_formspec = buttonbar_formspec,
hide = function(self) self.hidden = true end,
show = function(self) self.hidden = false end,
delete = function(self) ui.delete(self) end,
add_button = function(self, name, caption, image)
add_button = function(self, name, caption, image, tooltip)
if caption == nil then caption = "" end
if image == nil then image = "" end
table.insert(self.buttons,{ name=name, caption=caption, image=image})
if tooltip == nil then tooltip = "" end
table.insert(self.buttons,{ name=name, caption=caption, image=image, tooltip=tooltip})
if self.orientation == "horizontal" then
if ( (self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.x ) then
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
else
if ((self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.y ) then
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
end
end,
set_bgparams = function(self, bgcolor)
if (type(bgcolor) == "string") then
self.bgcolor = bgcolor
@ -188,20 +189,20 @@ function buttonbar_create(name, cbf_buttonhandler, pos, orientation, size)
self.startbutton = 1
self.have_move_buttons = false
self.hidden = false
if self.orientation == "horizontal" then
self.btn_size = self.size.y
else
self.btn_size = self.size.x
end
if (self.btn_initial_offset == nil) then
self.btn_initial_offset = self.btn_size * 0.05
end
self.userbuttonhandler = cbf_buttonhandler
self.buttons = {}
setmetatable(self,buttonbar_metatable)
ui.add(self)

View File

@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--self program is free software; you can redistribute it and/or modify
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--self program is distributed in the hope that it will be useful,
--this program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with self program; if not, write to the Free Software Foundation, Inc.,
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local function dialog_event_handler(self,event)
@ -61,7 +61,7 @@ function dialog_create(name,get_formspec,buttonhandler,eventhandler)
self.formspec = get_formspec
self.buttonhandler = buttonhandler
self.user_eventhandler = eventhandler
setmetatable(self,dialog_metatable)
ui.add(self)

View File

@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--self program is free software; you can redistribute it and/or modify
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--self program is distributed in the hope that it will be useful,
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with self program; if not, write to the Free Software Foundation, Inc.,
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@ -61,7 +61,7 @@ local function get_formspec(self)
local formspec = ""
if not self.hidden and (self.parent == nil or not self.parent.hidden) then
if self.parent == nil then
local tsize = self.tablist[self.last_tab_index].tabsize or
{width=self.width, height=self.height}
@ -87,11 +87,11 @@ local function handle_buttons(self,fields)
if self.hidden then
return false
end
if self:handle_tab_buttons(fields) then
return true
end
if self.glb_btn_handler ~= nil and
self.glb_btn_handler(self,fields) then
return true
@ -112,16 +112,16 @@ end
--------------------------------------------------------------------------------
local function handle_events(self,event)
if self.hidden then
return false
end
if self.glb_evt_handler ~= nil and
self.glb_evt_handler(self,event) then
return true
end
if self.tablist[self.last_tab_index].evt_handler ~= nil then
return
self.tablist[self.last_tab_index].evt_handler(
@ -131,7 +131,7 @@ local function handle_events(self,event)
self.tablist[self.last_tab_index].tabdata
)
end
return false
end
@ -160,16 +160,16 @@ local function switch_to_tab(self, index)
self.tablist[self.last_tab_index].on_change("LEAVE",
self.current_tab, self.tablist[index].name)
end
--update tabview data
self.last_tab_index = index
local old_tab = self.current_tab
self.current_tab = self.tablist[index].name
if (self.autosave_tab) then
core.setting_set(self.name .. "_LAST",self.current_tab)
end
-- call for tab to enter
if self.tablist[index].on_change ~= nil then
self.tablist[index].on_change("ENTER",
@ -197,14 +197,14 @@ local function set_tab_by_name(self, name)
return true
end
end
return false
end
--------------------------------------------------------------------------------
local function hide_tabview(self)
self.hidden=true
--call on_change as we're not gonna show self tab any longer
if self.tablist[self.last_tab_index].on_change ~= nil then
self.tablist[self.last_tab_index].on_change("LEAVE",
@ -215,7 +215,7 @@ end
--------------------------------------------------------------------------------
local function show_tabview(self)
self.hidden=false
-- call for tab to enter
if self.tablist[self.last_tab_index].on_change ~= nil then
self.tablist[self.last_tab_index].on_change("ENTER",
@ -265,7 +265,7 @@ function tabview_create(name, size, tabheaderpos)
self.current_tab = nil
self.last_tab_index = 1
self.tablist = {}
self.autosave_tab = false
ui.add(self)

View File

@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--self program is free software; you can redistribute it and/or modify
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--self program is distributed in the hope that it will be useful,
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with self program; if not, write to the Free Software Foundation, Inc.,
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ui = {}
@ -23,7 +23,7 @@ ui.default = nil
function ui.add(child)
--TODO check child
ui.childlist[child.name] = child
return child.name
end
@ -33,7 +33,7 @@ function ui.delete(child)
if ui.childlist[child.name] == nil then
return false
end
ui.childlist[child.name] = nil
return true
end
@ -54,17 +54,52 @@ end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function wordwrap_quickhack(str)
local res = ""
local ar = str:split("\n")
for i = 1, #ar do
local text = ar[i]
-- Hack to add word wrapping.
-- TODO: Add engine support for wrapping in formspecs
while #text > 80 do
if res ~= "" then
res = res .. ","
end
res = res .. core.formspec_escape(string.sub(text, 1, 79))
text = string.sub(text, 80, #text)
end
if res ~= "" then
res = res .. ","
end
res = res .. core.formspec_escape(text)
end
return res
end
--------------------------------------------------------------------------------
function ui.update()
local formspec = ""
-- handle errors
if gamedata ~= nil and gamedata.errormessage ~= nil then
formspec = "size[12,3.2]" ..
"textarea[1,1;10,2;;ERROR: " ..
core.formspec_escape(gamedata.errormessage) ..
";]"..
"button[4.5,2.5;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]"
if gamedata ~= nil and gamedata.reconnect_requested then
formspec = wordwrap_quickhack(gamedata.errormessage or "")
formspec = "size[12,5]" ..
"label[0.5,0;" .. fgettext("The server has requested a reconnect:") ..
"]textlist[0.2,0.8;11.5,3.5;;" .. formspec ..
"]button[6,4.6;3,0.5;btn_reconnect_no;" .. fgettext("Main menu") .. "]" ..
"button[3,4.6;3,0.5;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]"
elseif gamedata ~= nil and gamedata.errormessage ~= nil then
formspec = wordwrap_quickhack(gamedata.errormessage)
local error_title
if string.find(gamedata.errormessage, "ModError") then
error_title = fgettext("An error occured in a Lua script, such as a mod:")
else
error_title = fgettext("An error occured:")
end
formspec = "size[12,5]" ..
"label[0.5,0;" .. error_title ..
"]textlist[0.2,0.8;11.5,3.5;;" .. formspec ..
"]button[4.5,4.6;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]"
else
local active_toplevel_ui_elements = 0
for key,value in pairs(ui.childlist) do
@ -77,7 +112,7 @@ function ui.update()
end
end
end
-- no need to show addons if there ain't a toplevel element
if (active_toplevel_ui_elements > 0) then
for key,value in pairs(ui.childlist) do
@ -92,11 +127,13 @@ function ui.update()
end
if (active_toplevel_ui_elements > 1) then
print("WARNING: ui manager detected more then one active ui element, self most likely isn't intended")
core.log("warning", "more than one active ui "..
"element, self most likely isn't intended")
end
if (active_toplevel_ui_elements == 0) then
print("WARNING: not a single toplevel ui element active switching to default")
core.log("warning", "no toplevel ui element "..
"active; switching to default")
ui.childlist[ui.default]:show()
formspec = ui.childlist[ui.default]:get_formspec()
end
@ -106,13 +143,6 @@ end
--------------------------------------------------------------------------------
function ui.handle_buttons(fields)
if fields["btn_error_confirm"] then
gamedata.errormessage = nil
update_menu()
return
end
for key,value in pairs(ui.childlist) do
local retval = value:handle_buttons(fields)
@ -127,7 +157,7 @@ end
--------------------------------------------------------------------------------
function ui.handle_events(event)
for key,value in pairs(ui.childlist) do
if value.handle_events ~= nil then
@ -146,8 +176,15 @@ end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
core.button_handler = function(fields)
if fields["btn_error_confirm"] then
if fields["btn_reconnect_yes"] then
gamedata.reconnect_requested = false
gamedata.errormessage = nil
gamedata.do_reconnect = true
core.start()
return
elseif fields["btn_reconnect_no"] or fields["btn_error_confirm"] then
gamedata.errormessage = nil
gamedata.reconnect_requested = false
ui.update()
return
end

View File

@ -7,7 +7,7 @@
function core.string_to_privs(str, delim)
assert(type(str) == "string")
delim = delim or ','
privs = {}
local privs = {}
for _, priv in pairs(string.split(str, delim)) do
privs[priv:trim()] = true
end
@ -17,7 +17,7 @@ end
function core.privs_to_string(privs, delim)
assert(type(privs) == "table")
delim = delim or ','
list = {}
local list = {}
for priv, bool in pairs(privs) do
if bool then
table.insert(list, priv)
@ -41,12 +41,14 @@ local function read_auth_file()
end
for line in file:lines() do
if line ~= "" then
local name, password, privilegestring = string.match(line, "([^:]*):([^:]*):([^:]*)")
if not name or not password or not privilegestring then
local fields = line:split(":", true)
local name, password, privilege_string, last_login = unpack(fields)
last_login = tonumber(last_login)
if not (name and password and privilege_string) then
error("Invalid line in auth.txt: "..dump(line))
end
local privileges = core.string_to_privs(privilegestring)
newtable[name] = {password=password, privileges=privileges}
local privileges = core.string_to_privs(privilege_string)
newtable[name] = {password=password, privileges=privileges, last_login=last_login}
end
end
io.close(file)
@ -63,14 +65,16 @@ local function save_auth_file()
assert(type(stuff) == "table")
assert(type(stuff.password) == "string")
assert(type(stuff.privileges) == "table")
assert(stuff.last_login == nil or type(stuff.last_login) == "number")
end
local file, errmsg = io.open(core.auth_file_path, 'w+b')
if not file then
error(core.auth_file_path.." could not be opened for writing: "..errmsg)
end
for name, stuff in pairs(core.auth_table) do
local privstring = core.privs_to_string(stuff.privileges)
file:write(name..":"..stuff.password..":"..privstring..'\n')
local priv_string = core.privs_to_string(stuff.privileges)
local parts = {name, stuff.password, priv_string, stuff.last_login or ""}
file:write(table.concat(parts, ":").."\n")
end
io.close(file)
end
@ -111,6 +115,8 @@ core.builtin_auth_handler = {
return {
password = core.auth_table[name].password,
privileges = privileges,
-- Is set to nil if unknown
last_login = core.auth_table[name].last_login,
}
end,
create_auth = function(name, password)
@ -120,6 +126,7 @@ core.builtin_auth_handler = {
core.auth_table[name] = {
password = password,
privileges = core.string_to_privs(core.setting_get("default_privs")),
last_login = os.time(),
}
save_auth_file()
end,
@ -139,7 +146,9 @@ core.builtin_auth_handler = {
assert(type(name) == "string")
assert(type(privileges) == "table")
if not core.auth_table[name] then
core.builtin_auth_handler.create_auth(name, core.get_password_hash(name, core.setting_get("default_password")))
core.builtin_auth_handler.create_auth(name,
core.get_password_hash(name,
core.setting_get("default_password")))
end
core.auth_table[name].privileges = privileges
core.notify_authentication_modified(name)
@ -149,6 +158,11 @@ core.builtin_auth_handler = {
read_auth_file()
return true
end,
record_login = function(name)
assert(type(name) == "string")
assert(core.auth_table[name]).last_login = os.time()
save_auth_file()
end,
}
function core.register_authentication_handler(handler)
@ -157,32 +171,31 @@ function core.register_authentication_handler(handler)
end
core.registered_auth_handler = handler
core.registered_auth_handler_modname = core.get_current_modname()
handler.mod_origin = core.registered_auth_handler_modname
end
function core.get_auth_handler()
if core.registered_auth_handler then
return core.registered_auth_handler
end
return core.builtin_auth_handler
return core.registered_auth_handler or core.builtin_auth_handler
end
function core.set_player_password(name, password)
if core.get_auth_handler().set_password then
core.get_auth_handler().set_password(name, password)
local function auth_pass(name)
return function(...)
local auth_handler = core.get_auth_handler()
if auth_handler[name] then
return auth_handler[name](...)
end
return false
end
end
function core.set_player_privs(name, privs)
if core.get_auth_handler().set_privileges then
core.get_auth_handler().set_privileges(name, privs)
end
end
function core.auth_reload()
if core.get_auth_handler().reload then
return core.get_auth_handler().reload()
end
return false
end
core.set_player_password = auth_pass("set_password")
core.set_player_privs = auth_pass("set_privileges")
core.auth_reload = auth_pass("reload")
local record_login = auth_pass("record_login")
core.register_on_joinplayer(function(player)
record_login(player:get_player_name())
end)

View File

@ -10,6 +10,7 @@ function core.register_chatcommand(cmd, def)
def.params = def.params or ""
def.description = def.description or ""
def.privs = def.privs or {}
def.mod_origin = core.get_current_modname() or "??"
core.chatcommands[cmd] = def
end
@ -37,6 +38,7 @@ core.register_on_chat_message(function(name, message)
end
local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
if has_privs then
core.set_last_run_mod(cmd_def.mod_origin)
local success, message = cmd_def.func(name, param)
if message then
core.chat_send_player(name, message)
@ -49,6 +51,27 @@ core.register_on_chat_message(function(name, message)
return true -- Handled chat message
end)
-- Parses a "range" string in the format of "here (number)" or
-- "(x1, y1, z1) (x2, y2, z2)", returning two position vectors
local function parse_range_str(player_name, str)
local p1, p2
local args = str:split(" ")
if args[1] == "here" then
p1, p2 = core.get_player_radius_area(player_name, tonumber(args[2]))
if p1 == nil then
return false, "Unable to get player " .. player_name .. " position"
end
else
p1, p2 = core.string_to_area(str)
if p1 == nil then
return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
end
end
return p1, p2
end
--
-- Chat commands
--
@ -61,6 +84,18 @@ core.register_chatcommand("me", {
end,
})
core.register_chatcommand("admin", {
description = "Show the name of the server owner",
func = function(name)
local admin = minetest.setting_get("name")
if admin then
return true, "The administrator of this server is "..admin.."."
else
return false, "There's no administrator named in the config file."
end
end,
})
core.register_chatcommand("help", {
privs = {},
params = "[all/privs/<cmd>]",
@ -189,7 +224,7 @@ core.register_chatcommand("revoke", {
local revoke_privs = core.string_to_privs(revoke_priv_str)
local privs = core.get_player_privs(revoke_name)
for priv, _ in pairs(revoke_privs) do
if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and
if priv ~= "interact" and priv ~= "shout" and
not core.check_player_privs(name, {privs=true}) then
return false, "Your privileges are insufficient."
end
@ -229,21 +264,28 @@ core.register_chatcommand("setpassword", {
if not toname then
return false, "Name field required"
end
local actstr = "?"
local act_str_past = "?"
local act_str_pres = "?"
if not raw_password then
core.set_player_password(toname, "")
actstr = "cleared"
act_str_past = "cleared"
act_str_pres = "clears"
else
core.set_player_password(toname,
core.get_password_hash(toname,
raw_password))
actstr = "set"
act_str_past = "set"
act_str_pres = "sets"
end
if toname ~= name then
core.chat_send_player(toname, "Your password was "
.. actstr .. " by " .. name)
.. act_str_past .. " by " .. name)
end
return true, "Password of player \"" .. toname .. "\" " .. actstr
core.log("action", name .. " " .. act_str_pres
.. " password of " .. toname .. ".")
return true, "Password of player \"" .. toname .. "\" " .. act_str_past
end,
})
@ -252,11 +294,14 @@ core.register_chatcommand("clearpassword", {
description = "set empty password",
privs = {password=true},
func = function(name, param)
toname = param
local toname = param
if toname == "" then
return false, "Name field required"
end
core.set_player_password(toname, '')
core.log("action", name .. " clears password of " .. toname .. ".")
return true, "Password of player \"" .. toname .. "\" cleared"
end,
})
@ -308,7 +353,7 @@ core.register_chatcommand("teleport", {
teleportee:setpos(p)
return true, "Teleporting to "..core.pos_to_string(p)
end
local teleportee = nil
local p = nil
local target_name = nil
@ -345,7 +390,7 @@ core.register_chatcommand("teleport", {
return true, "Teleporting " .. teleportee_name
.. " to " .. core.pos_to_string(p)
end
local teleportee = nil
local p = nil
local teleportee_name = nil
@ -367,7 +412,7 @@ core.register_chatcommand("teleport", {
.. " to " .. target_name
.. " at " .. core.pos_to_string(p)
end
return false, 'Invalid parameters ("' .. param
.. '") or player not found (see /help teleport)'
end,
@ -403,6 +448,76 @@ core.register_chatcommand("set", {
end,
})
local function emergeblocks_callback(pos, action, num_calls_remaining, ctx)
if ctx.total_blocks == 0 then
ctx.total_blocks = num_calls_remaining + 1
ctx.current_blocks = 0
end
ctx.current_blocks = ctx.current_blocks + 1
if ctx.current_blocks == ctx.total_blocks then
core.chat_send_player(ctx.requestor_name,
string.format("Finished emerging %d blocks in %.2fms.",
ctx.total_blocks, (os.clock() - ctx.start_time) * 1000))
end
end
local function emergeblocks_progress_update(ctx)
if ctx.current_blocks ~= ctx.total_blocks then
core.chat_send_player(ctx.requestor_name,
string.format("emergeblocks update: %d/%d blocks emerged (%.1f%%)",
ctx.current_blocks, ctx.total_blocks,
(ctx.current_blocks / ctx.total_blocks) * 100))
core.after(2, emergeblocks_progress_update, ctx)
end
end
core.register_chatcommand("emergeblocks", {
params = "(here [radius]) | (<pos1> <pos2>)",
description = "starts loading (or generating, if inexistent) map blocks "
.. "contained in area pos1 to pos2",
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
if p1 == false then
return false, p2
end
local context = {
current_blocks = 0,
total_blocks = 0,
start_time = os.clock(),
requestor_name = name
}
core.emerge_area(p1, p2, emergeblocks_callback, context)
core.after(2, emergeblocks_progress_update, context)
return true, "Started emerge of area ranging from " ..
core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
end,
})
core.register_chatcommand("deleteblocks", {
params = "(here [radius]) | (<pos1> <pos2>)",
description = "delete map blocks contained in area pos1 to pos2",
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
if p1 == false then
return false, p2
end
if core.delete_area(p1, p2) then
return true, "Successfully cleared area ranging from " ..
core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
else
return false, "Failed to clear one or more blocks in area"
end
end,
})
core.register_chatcommand("mods", {
params = "",
description = "List mods installed on the server",
@ -426,6 +541,7 @@ local function handle_give_command(cmd, giver, receiver, stackstring)
return false, receiver .. " is not a known player"
end
local leftover = receiverref:get_inventory():add_item("main", itemstack)
local partiality
if leftover:is_empty() then
partiality = ""
elseif leftover:get_count() == itemstack:get_count() then
@ -474,22 +590,29 @@ core.register_chatcommand("giveme", {
})
core.register_chatcommand("spawnentity", {
params = "<EntityName>",
description = "Spawn entity at your position",
params = "<EntityName> [<X>,<Y>,<Z>]",
description = "Spawn entity at given (or your) position",
privs = {give=true, interact=true},
func = function(name, param)
local entityname = string.match(param, "(.+)$")
local entityname, p = string.match(param, "^([^ ]+) *(.*)$")
if not entityname then
return false, "EntityName required"
end
core.log("action", ("/spawnentity invoked, entityname=%q")
:format(entityname))
core.log("action", ("%s invokes /spawnentity, entityname=%q")
:format(name, entityname))
local player = core.get_player_by_name(name)
if player == nil then
core.log("error", "Unable to spawn entity, player is nil")
return false, "Unable to spawn entity, player is nil"
end
local p = player:getpos()
if p == "" then
p = player:getpos()
else
p = core.string_to_pos(p)
if p == nil then
return false, "Invalid parameters ('" .. param .. "')"
end
end
p.y = p.y + 1
core.add_entity(p, entityname)
return true, ("%q spawned."):format(entityname)
@ -531,6 +654,9 @@ core.register_chatcommand("rollback_check", {
.. " seconds=86400=24h, limit=5)",
privs = {rollback=true},
func = function(name, param)
if not core.setting_getbool("enable_rollback_recording") then
return false, "Rollback functions are disabled."
end
local range, seconds, limit =
param:match("(%d+) *(%d*) *(%d*)")
range = tonumber(range) or 0
@ -544,6 +670,10 @@ core.register_chatcommand("rollback_check", {
local name = puncher:get_player_name()
core.chat_send_player(name, "Checking " .. core.pos_to_string(pos) .. "...")
local actions = core.rollback_get_node_actions(pos, range, seconds, limit)
if not actions then
core.chat_send_player(name, "Rollback functions are disabled")
return
end
local num_actions = #actions
if num_actions == 0 then
core.chat_send_player(name, "Nobody has touched"
@ -575,6 +705,9 @@ core.register_chatcommand("rollback", {
description = "revert actions of a player; default for <seconds> is 60",
privs = {rollback=true},
func = function(name, param)
if not core.setting_getbool("enable_rollback_recording") then
return false, "Rollback functions are disabled."
end
local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
if not target_name then
local player_name = nil
@ -613,19 +746,41 @@ core.register_chatcommand("status", {
})
core.register_chatcommand("time", {
params = "<0...24000>",
params = "<0..23>:<0..59> | <0..24000>",
description = "set time of day",
privs = {settime=true},
privs = {},
func = function(name, param)
if param == "" then
return false, "Missing time."
local current_time = math.floor(core.get_timeofday() * 1440)
local minutes = current_time % 60
local hour = (current_time - minutes) / 60
return true, ("Current time is %d:%02d"):format(hour, minutes)
end
local newtime = tonumber(param)
if newtime == nil then
return false, "Invalid time."
local player_privs = core.get_player_privs(name)
if not player_privs.settime then
return false, "You don't have permission to run this command " ..
"(missing privilege: settime)."
end
core.set_timeofday((newtime % 24000) / 24000)
core.log("action", name .. " sets time " .. newtime)
local hour, minute = param:match("^(%d+):(%d+)$")
if not hour then
local new_time = tonumber(param)
if not new_time then
return false, "Invalid time."
end
-- Backward compatibility.
core.set_timeofday((new_time % 24000) / 24000)
core.log("action", name .. " sets time to " .. new_time)
return true, "Time of day changed."
end
hour = tonumber(hour)
minute = tonumber(minute)
if hour < 0 or hour > 23 then
return false, "Invalid hour (must be between 0 and 23 inclusive)."
elseif minute < 0 or minute > 59 then
return false, "Invalid minute (must be between 0 and 59 inclusive)."
end
core.set_timeofday((hour * 60 + minute) / 1440)
core.log("action", ("%s sets time to %d:%02d"):format(name, hour, minute))
return true, "Time of day changed."
end,
})
@ -683,20 +838,35 @@ core.register_chatcommand("kick", {
if not core.kick_player(tokick, reason) then
return false, "Failed to kick player " .. tokick
end
core.log("action", name .. " kicked " .. tokick)
local log_reason = ""
if reason then
log_reason = " with reason \"" .. reason .. "\""
end
core.log("action", name .. " kicks " .. tokick .. log_reason)
return true, "Kicked " .. tokick
end,
})
core.register_chatcommand("clearobjects", {
params = "[full|quick]",
description = "clear all objects in world",
privs = {server=true},
func = function(name, param)
core.log("action", name .. " clears all objects.")
options = {}
if param == "" or param == "full" then
options.mode = "full"
elseif param == "quick" then
options.mode = "quick"
else
return false, "Invalid usage, see /help clearobjects."
end
core.log("action", name .. " clears all objects ("
.. options.mode .. " mode).")
core.chat_send_all("Clearing all objects. This may take long."
.. " You may experience a timeout. (by "
.. name .. ")")
core.clear_objects()
core.clear_objects(options)
core.log("action", "Object clearing done.")
core.chat_send_all("*** Cleared all objects.")
end,
@ -723,3 +893,19 @@ core.register_chatcommand("msg", {
end,
})
core.register_chatcommand("last-login", {
params = "[name]",
description = "Get the last login time of a player",
func = function(name, param)
if param == "" then
param = name
end
local pauth = core.get_auth_handler().get_auth(param)
if pauth and pauth.last_login then
-- Time in UTC, ISO 8601 format
return true, "Last login time was " ..
os.date("!%Y-%m-%dT%H:%M:%SZ", pauth.last_login)
end
return false, "Last login time is unknown"
end,
})

View File

@ -0,0 +1,17 @@
-- Minetest: builtin/constants.lua
--
-- Constants values for use with the Lua API
--
-- Built-in Content IDs (for use with VoxelManip API)
core.CONTENT_UNKNOWN = 125
core.CONTENT_AIR = 126
core.CONTENT_IGNORE = 127
-- Block emerge status constants (for use with core.emerge_area)
core.EMERGE_CANCELLED = 0
core.EMERGE_ERRORED = 1
core.EMERGE_FROM_MEMORY = 2
core.EMERGE_FROM_DISK = 3
core.EMERGE_GENERATED = 4

View File

@ -3,9 +3,8 @@
--
-- Default material types
--
function digprop_err()
core.log("info", debug.traceback())
core.log("info", "WARNING: The core.digprop_* functions are obsolete and need to be replaced by item groups.")
local function digprop_err()
core.log("deprecated", "The core.digprop_* functions are obsolete and need to be replaced by item groups.")
end
core.digprop_constanttime = digprop_err
@ -16,12 +15,12 @@ core.digprop_woodlike = digprop_err
core.digprop_leaveslike = digprop_err
core.digprop_glasslike = digprop_err
core.node_metadata_inventory_move_allow_all = function()
core.log("info", "WARNING: core.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
function core.node_metadata_inventory_move_allow_all()
core.log("deprecated", "core.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
end
core.add_to_creative_inventory = function(itemstring)
core.log('info', "WARNING: core.add_to_creative_inventory: This function is deprecated and does nothing.")
function core.add_to_creative_inventory(itemstring)
core.log("deprecated", "core.add_to_creative_inventory: This function is deprecated and does nothing.")
end
--
@ -32,7 +31,7 @@ local envref_deprecation_message_printed = false
setmetatable(core.env, {
__index = function(table, key)
if not envref_deprecation_message_printed then
core.log("info", "WARNING: core.env:[...] is deprecated and should be replaced with core.[...]")
core.log("deprecated", "core.env:[...] is deprecated and should be replaced with core.[...]")
envref_deprecation_message_printed = true
end
local func = core[key]
@ -50,4 +49,3 @@ setmetatable(core.env, {
function core.rollback_get_last_node_actor(pos, range, seconds)
return core.rollback_get_node_actions(pos, range, seconds, 1)[1]
end

View File

@ -13,6 +13,7 @@ function core.create_detached_inventory(name, callbacks)
stuff.on_put = callbacks.on_put
stuff.on_take = callbacks.on_take
end
stuff.mod_origin = core.get_current_modname() or "??"
core.detached_inventories[name] = stuff
return core.create_detached_inventory_raw(name)
end

View File

@ -18,19 +18,7 @@ core.register_entity(":__builtin:falling_node", {
set_node = function(self, node)
self.node = node
local stack = ItemStack(node.name)
local itemtable = stack:to_table()
local itemname = nil
if itemtable then
itemname = stack:to_table().name
end
local item_texture = nil
local item_type = ""
if core.registered_items[itemname] then
item_texture = core.registered_items[itemname].inventory_image
item_type = core.registered_items[itemname].type
end
prop = {
local prop = {
is_visible = true,
textures = {node.name},
}
@ -43,7 +31,9 @@ core.register_entity(":__builtin:falling_node", {
on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal=1})
self:set_node({name=staticdata})
if staticdata then
self:set_node({name=staticdata})
end
end,
on_step = function(self, dtime)
@ -112,7 +102,7 @@ core.register_entity(":__builtin:falling_node", {
})
function spawn_falling_node(p, node)
obj = core.add_entity(p, "__builtin:falling_node")
local obj = core.add_entity(p, "__builtin:falling_node")
obj:get_luaentity():set_node(node)
end
@ -163,10 +153,10 @@ end
--
function nodeupdate_single(p, delay)
n = core.get_node(p)
local n = core.get_node(p)
if core.get_item_group(n.name, "falling_node") ~= 0 then
p_bottom = {x=p.x, y=p.y-1, z=p.z}
n_bottom = core.get_node(p_bottom)
local p_bottom = {x=p.x, y=p.y-1, z=p.z}
local n_bottom = core.get_node(p_bottom)
-- Note: walkable is in the node definition, not in item groups
if core.registered_nodes[n_bottom.name] and
(core.get_item_group(n.name, "float") == 0 or

View File

@ -12,9 +12,9 @@ core.features = {
function core.has_feature(arg)
if type(arg) == "table" then
missing_features = {}
result = true
for ft, _ in pairs(arg) do
local missing_features = {}
local result = true
for ftr in pairs(arg) do
if not core.features[ftr] then
missing_features[ftr] = true
result = false

View File

@ -1,10 +1,11 @@
local scriptpath = minetest.get_builtin_path()..DIR_DELIM
local scriptpath = core.get_builtin_path()..DIR_DELIM
local commonpath = scriptpath.."common"..DIR_DELIM
local gamepath = scriptpath.."game"..DIR_DELIM
dofile(commonpath.."vector.lua")
dofile(gamepath.."constants.lua")
dofile(gamepath.."item.lua")
dofile(gamepath.."register.lua")
@ -25,4 +26,3 @@ dofile(gamepath.."features.lua")
dofile(gamepath.."voxelarea.lua")
dofile(gamepath.."forceloading.lua")
dofile(gamepath.."statbars.lua")

View File

@ -27,19 +27,11 @@ function core.get_pointed_thing_position(pointed_thing, above)
if above then
-- The position where a node would be placed
return pointed_thing.above
else
-- The position where a node would be dug
return pointed_thing.under
end
-- The position where a node would be dug
return pointed_thing.under
elseif pointed_thing.type == "object" then
obj = pointed_thing.ref
if obj ~= nil then
return obj:getpos()
else
return nil
end
else
return nil
return pointed_thing.ref and pointed_thing.ref:getpos()
end
end
@ -96,25 +88,26 @@ function core.dir_to_facedir(dir, is6d)
end
end
-- Table of possible dirs
local facedir_to_dir = {
{x= 0, y=0, z= 1},
{x= 1, y=0, z= 0},
{x= 0, y=0, z=-1},
{x=-1, y=0, z= 0},
{x= 0, y=-1, z= 0},
{x= 0, y=1, z= 0},
}
-- Mapping from facedir value to index in facedir_to_dir.
local facedir_to_dir_map = {
[0]=1, 2, 3, 4,
5, 2, 6, 4,
6, 2, 5, 4,
1, 5, 3, 6,
1, 6, 3, 5,
1, 4, 3, 2,
}
function core.facedir_to_dir(facedir)
--a table of possible dirs
return ({{x=0, y=0, z=1},
{x=1, y=0, z=0},
{x=0, y=0, z=-1},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0},
{x=0, y=1, z=0}})
--indexed into by a table of correlating facedirs
[({[0]=1, 2, 3, 4,
5, 2, 6, 4,
6, 2, 5, 4,
1, 5, 3, 6,
1, 6, 3, 5,
1, 4, 3, 2})
--indexed into by the facedir in question
[facedir]]
return facedir_to_dir[facedir_to_dir_map[facedir]]
end
function core.dir_to_wallmounted(dir)
@ -139,6 +132,19 @@ function core.dir_to_wallmounted(dir)
end
end
-- table of dirs in wallmounted order
local wallmounted_to_dir = {
[0] = {x = 0, y = 1, z = 0},
{x = 0, y = -1, z = 0},
{x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0},
{x = 0, y = 0, z = 1},
{x = 0, y = 0, z = -1},
}
function core.wallmounted_to_dir(wallmounted)
return wallmounted_to_dir[wallmounted]
end
function core.get_node_drops(nodename, toolname)
local drop = ItemStack({name=nodename}):get_definition().drop
if drop == nil then
@ -238,7 +244,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
core.log("action", placer:get_player_name() .. " places node "
.. def.name .. " at " .. core.pos_to_string(place_to))
local oldnode = core.get_node(place_to)
local newnode = {name = def.name, param1 = 0, param2 = param2}
@ -334,8 +340,12 @@ function core.item_place(itemstack, placer, pointed_thing, param2)
return itemstack
end
function core.item_secondary_use(itemstack, placer)
return itemstack
end
function core.item_drop(itemstack, dropper, pos)
if dropper.is_player then
if dropper and dropper:is_player() then
local v = dropper:get_look_dir()
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
local cs = itemstack:get_count()
@ -349,27 +359,50 @@ function core.item_drop(itemstack, dropper, pos)
v.y = v.y*2 + 2
v.z = v.z*2
obj:setvelocity(v)
obj:get_luaentity().dropped_by = dropper:get_player_name()
return itemstack
end
else
core.add_item(pos, itemstack)
if core.add_item(pos, itemstack) then
return itemstack
end
end
-- If we reach this, adding the object to the
-- environment failed
end
function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
for _, callback in pairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
if result then
return result
end
end
if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change)
if replace_with_item then
if itemstack:is_empty() then
itemstack:add_item(replace_with_item)
else
local inv = user:get_inventory()
if inv:room_for_item("main", {name=replace_with_item}) then
inv:add_item("main", replace_with_item)
else
local pos = user:getpos()
pos.y = math.floor(pos.y + 0.5)
core.add_item(pos, replace_with_item)
end
end
end
end
return itemstack
end
function core.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing) -- closure
for _, callback in pairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
if result then
return result
end
end
if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change)
itemstack:add_item(replace_with_item) -- note: replace_with_item is optional
end
return itemstack
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
end
end
@ -425,7 +458,7 @@ function core.node_dig(pos, node, digger)
local wielded = digger:get_wielded_item()
local drops = core.get_node_drops(node.name, wielded:get_name())
local wdef = wielded:get_definition()
local tp = wielded:get_tool_capabilities()
local dp = core.get_dig_params(def.groups, tp)
@ -438,7 +471,7 @@ function core.node_dig(pos, node, digger)
end
end
digger:set_wielded_item(wielded)
-- Handle drops
core.handle_node_drops(pos, drops, digger)
@ -449,7 +482,7 @@ function core.node_dig(pos, node, digger)
-- Remove node and update
core.remove_node(pos)
-- Run callback
if def.after_dig_node then
-- Copy pos and node because callback can modify them
@ -461,6 +494,15 @@ function core.node_dig(pos, node, digger)
-- Run script hook
local _, callback
for _, callback in ipairs(core.registered_on_dignodes) do
local origin = core.callback_origins[callback]
if origin then
core.set_last_run_mod(origin.mod)
--print("Running " .. tostring(callback) ..
-- " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
else
--print("No data associated with callback")
end
-- Copy pos and node because callback can modify them
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
@ -507,7 +549,7 @@ core.nodedef_default = {
on_dig = redef_wrapper(core, 'node_dig'), -- core.node_dig
on_receive_fields = nil,
on_metadata_inventory_move = core.node_metadata_inventory_move_allow_all,
on_metadata_inventory_offer = core.node_metadata_inventory_offer_allow_all,
on_metadata_inventory_take = core.node_metadata_inventory_take_allow_all,
@ -533,6 +575,7 @@ core.nodedef_default = {
diggable = true,
climbable = false,
buildable_to = false,
floodable = false,
liquidtype = "none",
liquid_alternative_flowing = "",
liquid_alternative_source = "",
@ -560,6 +603,7 @@ core.craftitemdef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_use = nil,
}
@ -577,6 +621,7 @@ core.tooldef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_use = nil,
}
@ -595,6 +640,7 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'),
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = nil,
on_use = nil,
}

View File

@ -4,11 +4,14 @@ function core.spawn_item(pos, item)
-- Take item in any format
local stack = ItemStack(item)
local obj = core.add_entity(pos, "__builtin:item")
obj:get_luaentity():set_item(stack:to_string())
-- Don't use obj if it couldn't be added to the map.
if obj then
obj:get_luaentity():set_item(stack:to_string())
end
return obj
end
-- If item_entity_ttl is not set, enity will have default life time
-- If item_entity_ttl is not set, enity will have default life time
-- Setting it to -1 disables the feature
local time_to_live = tonumber(core.setting_get("item_entity_ttl"))
@ -21,13 +24,14 @@ core.register_entity(":__builtin:item", {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.24, -0.24, -0.24, 0.24, 0.24, 0.24},
collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
visual = "wielditem",
visual_size = {x = 0.3, y = 0.3},
visual_size = {x = 0.4, y = 0.4},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = false,
infotext = "",
},
itemstring = '',
@ -43,10 +47,11 @@ core.register_entity(":__builtin:item", {
count = max_count
self.itemstring = stack:get_name().." "..max_count
end
local s = 0.15 + 0.15 * (count / max_count)
local c = 0.8 * s
local s = 0.2 + 0.1 * (count / max_count)
local c = s
local itemtable = stack:to_table()
local itemname = nil
local description = ""
if itemtable then
itemname = stack:to_table().name
end
@ -55,14 +60,16 @@ core.register_entity(":__builtin:item", {
if core.registered_items[itemname] then
item_texture = core.registered_items[itemname].inventory_image
item_type = core.registered_items[itemname].type
description = core.registered_items[itemname].description
end
prop = {
local prop = {
is_visible = true,
visual = "wielditem",
textures = {itemname},
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c},
automatic_rotate = math.pi * 0.2,
automatic_rotate = math.pi * 0.5,
infotext = description,
}
self.object:set_properties(prop)
end,
@ -71,7 +78,8 @@ core.register_entity(":__builtin:item", {
return core.serialize({
itemstring = self.itemstring,
always_collect = self.always_collect,
age = self.age
age = self.age,
dropped_by = self.dropped_by
})
end,
@ -81,11 +89,12 @@ core.register_entity(":__builtin:item", {
if data and type(data) == "table" then
self.itemstring = data.itemstring
self.always_collect = data.always_collect
if data.age then
if data.age then
self.age = data.age + dtime_s
else
self.age = dtime_s
end
self.dropped_by = data.dropped_by
end
else
self.itemstring = staticdata
@ -96,6 +105,56 @@ core.register_entity(":__builtin:item", {
self:set_item(self.itemstring)
end,
try_merge_with = function(self, own_stack, object, obj)
local stack = ItemStack(obj.itemstring)
if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then
local overflow = false
local count = stack:get_count() + own_stack:get_count()
local max_count = stack:get_stack_max()
if count > max_count then
overflow = true
count = count - max_count
else
self.itemstring = ''
end
local pos = object:getpos()
pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15
object:moveto(pos, false)
local s, c
local max_count = stack:get_stack_max()
local name = stack:get_name()
if not overflow then
obj.itemstring = name .. " " .. count
s = 0.2 + 0.1 * (count / max_count)
c = s
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.object:remove()
-- merging succeeded
return true
else
s = 0.4
c = 0.3
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
obj.itemstring = name .. " " .. max_count
s = 0.2 + 0.1 * (count / max_count)
c = s
self.object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.itemstring = name .. " " .. count
end
end
-- merging didn't succeed
return false
end,
on_step = function(self, dtime)
self.age = self.age + dtime
if time_to_live > 0 and self.age > time_to_live then
@ -104,59 +163,30 @@ core.register_entity(":__builtin:item", {
return
end
local p = self.object:getpos()
p.y = p.y - 0.3
local nn = core.get_node(p).name
p.y = p.y - 0.5
local node = core.get_node_or_nil(p)
local in_unloaded = (node == nil)
if in_unloaded then
-- Don't infinetly fall into unloaded map
self.object:setvelocity({x = 0, y = 0, z = 0})
self.object:setacceleration({x = 0, y = 0, z = 0})
self.physical_state = false
self.object:set_properties({physical = false})
return
end
local nn = node.name
-- If node is not registered or node is walkably solid and resting on nodebox
local v = self.object:getvelocity()
if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then
if self.physical_state then
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
for _,object in ipairs(core.get_objects_inside_radius(p, 0.8)) do
-- Merge with close entities of the same item
for _, object in ipairs(core.get_objects_inside_radius(p, 0.8)) do
local obj = object:get_luaentity()
if obj and obj.name == "__builtin:item" and obj.physical_state == false then
local stack = ItemStack(obj.itemstring)
if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then
local overflow = false
local count = stack:get_count() + own_stack:get_count()
local max_count = stack:get_stack_max()
if count>max_count then
overflow = true
count = count - max_count
else
self.itemstring = ''
end
local pos=object:getpos()
pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15
object:moveto(pos, false)
local s, c
local max_count = stack:get_stack_max()
local name = stack:get_name()
if not overflow then
obj.itemstring = name.." "..count
s = 0.15 + 0.15 * (count / max_count)
c = 0.8 * s
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.object:remove()
return
else
s = 0.3
c = 0.24
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
obj.itemstring = name.." "..max_count
s = 0.15 + 0.15 * (count / max_count)
c = 0.8 * s
self.object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.itemstring = name.." "..count
end
if obj and obj.name == "__builtin:item"
and obj.physical_state == false then
if self:try_merge_with(own_stack, object, obj) then
return
end
end
end
@ -176,9 +206,10 @@ core.register_entity(":__builtin:item", {
end,
on_punch = function(self, hitter)
if self.itemstring ~= '' then
local left = hitter:get_inventory():add_item("main", self.itemstring)
if not left:is_empty() then
local inv = hitter:get_inventory()
if inv and self.itemstring ~= '' then
local left = inv:add_item("main", self.itemstring)
if left and not left:is_empty() then
self.itemstring = left:to_string()
return
end

View File

@ -4,45 +4,81 @@
-- Misc. API functions
--
core.timers_to_add = {}
core.timers = {}
local jobs = {}
local time = 0.0
local last = 0.0
core.register_globalstep(function(dtime)
for _, timer in ipairs(core.timers_to_add) do
table.insert(core.timers, timer)
local new = core.get_us_time() / 1000000
if new > last then
time = time + (new - last)
else
-- Overflow, we may lose a little bit of time here but
-- only 1 tick max, potentially running timers slightly
-- too early.
time = time + new
end
core.timers_to_add = {}
local index = 1
while index <= #core.timers do
local timer = core.timers[index]
timer.time = timer.time - dtime
if timer.time <= 0 then
timer.func(unpack(timer.args or {}))
table.remove(core.timers,index)
else
index = index + 1
last = new
if #jobs < 1 then
return
end
-- Iterate backwards so that we miss any new timers added by
-- a timer callback, and so that we don't skip the next timer
-- in the list if we remove one.
for i = #jobs, 1, -1 do
local job = jobs[i]
if time >= job.expire then
core.set_last_run_mod(job.mod_origin)
job.func(unpack(job.arg))
table.remove(jobs, i)
end
end
end)
function core.after(time, func, ...)
function core.after(after, func, ...)
assert(tonumber(time) and type(func) == "function",
"Invalid core.after invocation")
table.insert(core.timers_to_add, {time=time, func=func, args={...}})
table.insert(jobs, {
func = func,
expire = time + after,
arg = {...},
mod_origin = core.get_last_run_mod()
})
end
function core.check_player_privs(name, privs)
function core.check_player_privs(player_or_name, ...)
local name = player_or_name
-- Check if we have been provided with a Player object.
if type(name) ~= "string" then
name = name:get_player_name()
end
local requested_privs = {...}
local player_privs = core.get_player_privs(name)
local missing_privileges = {}
for priv, val in pairs(privs) do
if val then
if type(requested_privs[1]) == "table" then
-- We were provided with a table like { privA = true, privB = true }.
for priv, value in pairs(requested_privs[1]) do
if value and not player_privs[priv] then
table.insert(missing_privileges, priv)
end
end
else
-- Only a list, we can process it directly.
for key, priv in pairs(requested_privs) do
if not player_privs[priv] then
table.insert(missing_privileges, priv)
end
end
end
if #missing_privileges > 0 then
return false, missing_privileges
end
return true, ""
end
@ -66,6 +102,25 @@ function core.get_connected_players()
return temp_table
end
-- Returns two position vectors representing a box of `radius` in each
-- direction centered around the player corresponding to `player_name`
function core.get_player_radius_area(player_name, radius)
local player = core.get_player_by_name(player_name)
if player == nil then
return nil
end
local p1 = player:getpos()
local p2 = p1
if radius then
p1 = vector.subtract(p1, radius)
p2 = vector.add(p2, radius)
end
return p1, p2
end
function core.hash_node_position(pos)
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
end
@ -93,30 +148,6 @@ function core.get_node_group(name, group)
return core.get_item_group(name, group)
end
function core.string_to_pos(value)
local p = {}
p.x, p.y, p.z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
if p.x and p.y and p.z then
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
return p
end
local p = {}
p.x, p.y, p.z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
if p.x and p.y and p.z then
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
return p
end
return nil
end
assert(core.string_to_pos("10.0, 5, -2").x == 10)
assert(core.string_to_pos("( 10.0, 5, -2)").z == -2)
assert(core.string_to_pos("asd, 5, -2)") == nil)
function core.setting_get_pos(name)
local value = core.setting_get(name)
if not value then
@ -136,3 +167,33 @@ function core.record_protection_violation(pos, name)
end
end
local raillike_ids = {}
local raillike_cur_id = 0
function core.raillike_group(name)
local id = raillike_ids[name]
if not id then
raillike_cur_id = raillike_cur_id + 1
raillike_ids[name] = raillike_cur_id
id = raillike_cur_id
end
return id
end
-- HTTP callback interface
function core.http_add_fetch(httpenv)
httpenv.fetch = function(req, callback)
local handle = httpenv.fetch_async(req)
local function update_http_status()
local res = httpenv.fetch_async_get(handle)
if res.completed then
callback(res)
else
core.after(0, update_http_status)
end
end
core.after(0, update_http_status)
end
return httpenv
end

View File

@ -51,20 +51,24 @@ local forbidden_item_names = {
local function check_modname_prefix(name)
if name:sub(1,1) == ":" then
-- Escape the modname prefix enforcement mechanism
-- If the name starts with a colon, we can skip the modname prefix
-- mechanism.
return name:sub(2)
else
-- Modname prefix enforcement
-- Enforce that the name starts with the correct mod name.
local expected_prefix = core.get_current_modname() .. ":"
if name:sub(1, #expected_prefix) ~= expected_prefix then
error("Name " .. name .. " does not follow naming conventions: " ..
"\"modname:\" or \":\" prefix required")
"\"" .. expected_prefix .. "\" or \":\" prefix required")
end
-- Enforce that the name only contains letters, numbers and underscores.
local subname = name:sub(#expected_prefix+1)
if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
if subname:find("[^%w_]") then
error("Name " .. name .. " does not follow naming conventions: " ..
"contains unallowed characters")
end
return name
end
end
@ -72,6 +76,7 @@ end
function core.register_abm(spec)
-- Add to core.registered_abms
core.registered_abms[#core.registered_abms+1] = spec
spec.mod_origin = core.get_current_modname() or "??"
end
function core.register_entity(name, prototype)
@ -86,6 +91,7 @@ function core.register_entity(name, prototype)
-- Add to core.registered_entities
core.registered_entities[name] = prototype
prototype.mod_origin = core.get_current_modname() or "??"
end
function core.register_item(name, itemdef)
@ -147,6 +153,8 @@ function core.register_item(name, itemdef)
end
-- END Legacy stuff
itemdef.mod_origin = core.get_current_modname() or "??"
-- Disable all further modifications
getmetatable(itemdef).__newindex = {}
@ -217,7 +225,7 @@ function core.register_alias(name, convert_to)
error("Unable to register alias: Name is forbidden: " .. name)
end
if core.registered_items[name] ~= nil then
core.log("WARNING: Not registering alias, item with same name" ..
core.log("warning", "Not registering alias, item with same name" ..
" is already defined: " .. name .. " -> " .. convert_to)
else
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
@ -226,13 +234,6 @@ function core.register_alias(name, convert_to)
end
end
local register_biome_raw = core.register_biome
core.registered_biomes = {}
function core.register_biome(biome)
core.registered_biomes[biome.name] = biome
register_biome_raw(biome)
end
function core.on_craft(itemstack, player, old_craft_list, craft_inv)
for _, func in ipairs(core.registered_on_crafts) do
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
@ -271,6 +272,7 @@ core.register_item(":unknown", {
description = "Unknown Item",
inventory_image = "unknown_item.png",
on_place = core.item_place,
on_secondary_use = core.item_secondary_use,
on_drop = core.item_drop,
groups = {not_in_creative_inventory=1},
diggable = true,
@ -287,6 +289,7 @@ core.register_node(":air", {
pointable = false,
diggable = false,
buildable_to = true,
floodable = true,
air_equivalent = true,
drop = "",
groups = {not_in_creative_inventory=1},
@ -333,6 +336,8 @@ function core.override_item(name, redefinition)
end
core.callback_origins = {}
function core.run_callbacks(callbacks, mode, ...)
assert(type(callbacks) == "table")
local cb_len = #callbacks
@ -345,6 +350,14 @@ function core.run_callbacks(callbacks, mode, ...)
end
local ret = nil
for i = 1, cb_len do
local origin = core.callback_origins[callbacks[i]]
if origin then
core.set_last_run_mod(origin.mod)
--print("Running " .. tostring(callbacks[i]) ..
-- " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
else
--print("No data associated with callback")
end
local cb_ret = callbacks[i](...)
if mode == 0 and i == 1 then
@ -377,20 +390,100 @@ end
local function make_registration()
local t = {}
local registerfunc = function(func) table.insert(t, func) end
local registerfunc = function(func)
table.insert(t, func)
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
--local origin = core.callback_origins[func]
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
end
return t, registerfunc
end
local function make_registration_reverse()
local t = {}
local registerfunc = function(func) table.insert(t, 1, func) end
local registerfunc = function(func)
table.insert(t, 1, func)
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
--local origin = core.callback_origins[func]
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
end
return t, registerfunc
end
local function make_registration_wrap(reg_fn_name, clear_fn_name)
local list = {}
local orig_reg_fn = core[reg_fn_name]
core[reg_fn_name] = function(def)
local retval = orig_reg_fn(def)
if retval ~= nil then
if def.name ~= nil then
list[def.name] = def
else
list[retval] = def
end
end
return retval
end
local orig_clear_fn = core[clear_fn_name]
core[clear_fn_name] = function()
for k in pairs(list) do
list[k] = nil
end
return orig_clear_fn()
end
return list
end
core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } }
function core.registered_on_player_hpchange(player, hp_change)
local last = false
for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do
local func = core.registered_on_player_hpchanges.modifiers[i]
hp_change, last = func(player, hp_change)
if type(hp_change) ~= "number" then
local debuginfo = debug.getinfo(func)
error("The register_on_hp_changes function has to return a number at " ..
debuginfo.short_src .. " line " .. debuginfo.linedefined)
end
if last then
break
end
end
for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do
func(player, hp_change)
end
return hp_change
end
function core.register_on_player_hpchange(func, modifier)
if modifier then
table.insert(core.registered_on_player_hpchanges.modifiers, func)
else
table.insert(core.registered_on_player_hpchanges.loggers, func)
end
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
end
core.registered_biomes = make_registration_wrap("register_biome", "clear_registered_biomes")
core.registered_ores = make_registration_wrap("register_ore", "clear_registered_ores")
core.registered_decorations = make_registration_wrap("register_decoration", "clear_registered_decorations")
core.registered_on_chat_messages, core.register_on_chat_message = make_registration()
core.registered_globalsteps, core.register_globalstep = make_registration()
core.registered_playerevents, core.register_playerevent = make_registration()
core.registered_on_mapgen_inits, core.register_on_mapgen_init = make_registration()
core.registered_on_shutdown, core.register_on_shutdown = make_registration()
core.registered_on_punchnodes, core.register_on_punchnode = make_registration()
core.registered_on_placenodes, core.register_on_placenode = make_registration()
@ -408,4 +501,11 @@ core.registered_on_crafts, core.register_on_craft = make_registration()
core.registered_craft_predicts, core.register_craft_predict = make_registration()
core.registered_on_protection_violation, core.register_on_protection_violation = make_registration()
core.registered_on_item_eats, core.register_on_item_eat = make_registration()
core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
--
-- Compatibility for on_mapgen_init()
--
core.register_on_mapgen_init = function(func) func(core.get_mapgen_params()) end

View File

@ -7,7 +7,7 @@ local health_bar_definition =
number = 20,
direction = 0,
size = { x=24, y=24 },
offset = { x=(-10*24)-25, y=-(48+24+10)},
offset = { x=(-10*24)-25, y=-(48+24+16)},
}
local breath_bar_definition =
@ -18,7 +18,7 @@ local breath_bar_definition =
number = 20,
direction = 0,
size = { x=24, y=24 },
offset = {x=25,y=-(48+24+10)},
offset = {x=25,y=-(48+24+16)},
}
local hud_ids = {}

View File

@ -3,31 +3,23 @@
local function warn_invalid_static_spawnpoint()
if core.setting_get("static_spawnpoint") and
not core.setting_get_pos("static_spawnpoint") then
core.log('error', "The static_spawnpoint setting is invalid: \""..
core.log("error", "The static_spawnpoint setting is invalid: \""..
core.setting_get("static_spawnpoint").."\"")
end
end
warn_invalid_static_spawnpoint()
local function put_player_in_spawn(obj)
warn_invalid_static_spawnpoint()
local function put_player_in_spawn(player_obj)
local static_spawnpoint = core.setting_get_pos("static_spawnpoint")
if not static_spawnpoint then
return false
end
core.log('action', "Moving "..obj:get_player_name()..
" to static spawnpoint at "..
core.pos_to_string(static_spawnpoint))
obj:setpos(static_spawnpoint)
core.log("action", "Moving " .. player_obj:get_player_name() ..
" to static spawnpoint at " .. core.pos_to_string(static_spawnpoint))
player_obj:setpos(static_spawnpoint)
return true
end
core.register_on_newplayer(function(obj)
put_player_in_spawn(obj)
end)
core.register_on_respawnplayer(function(obj)
return put_player_in_spawn(obj)
end)
core.register_on_newplayer(put_player_in_spawn)
core.register_on_respawnplayer(put_player_in_spawn)

View File

@ -18,10 +18,11 @@ function VoxelArea:new(o)
end
function VoxelArea:getExtent()
local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
return {
x = self.MaxEdge.x - self.MinEdge.x + 1,
y = self.MaxEdge.y - self.MinEdge.y + 1,
z = self.MaxEdge.z - self.MinEdge.z + 1,
x = MaxEdge.x - MinEdge.x + 1,
y = MaxEdge.y - MinEdge.y + 1,
z = MaxEdge.z - MinEdge.z + 1,
}
end
@ -31,45 +32,50 @@ function VoxelArea:getVolume()
end
function VoxelArea:index(x, y, z)
local i = (z - self.MinEdge.z) * self.zstride +
(y - self.MinEdge.y) * self.ystride +
(x - self.MinEdge.x) + 1
local MinEdge = self.MinEdge
local i = (z - MinEdge.z) * self.zstride +
(y - MinEdge.y) * self.ystride +
(x - MinEdge.x) + 1
return math.floor(i)
end
function VoxelArea:indexp(p)
local i = (p.z - self.MinEdge.z) * self.zstride +
(p.y - self.MinEdge.y) * self.ystride +
(p.x - self.MinEdge.x) + 1
local MinEdge = self.MinEdge
local i = (p.z - MinEdge.z) * self.zstride +
(p.y - MinEdge.y) * self.ystride +
(p.x - MinEdge.x) + 1
return math.floor(i)
end
function VoxelArea:position(i)
local p = {}
local MinEdge = self.MinEdge
i = i - 1
p.z = math.floor(i / self.zstride) + self.MinEdge.z
p.z = math.floor(i / self.zstride) + MinEdge.z
i = i % self.zstride
p.y = math.floor(i / self.ystride) + self.MinEdge.y
p.y = math.floor(i / self.ystride) + MinEdge.y
i = i % self.ystride
p.x = math.floor(i) + self.MinEdge.x
p.x = math.floor(i) + MinEdge.x
return p
end
function VoxelArea:contains(x, y, z)
return (x >= self.MinEdge.x) and (x <= self.MaxEdge.x) and
(y >= self.MinEdge.y) and (y <= self.MaxEdge.y) and
(z >= self.MinEdge.z) and (z <= self.MaxEdge.z)
local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
return (x >= MinEdge.x) and (x <= MaxEdge.x) and
(y >= MinEdge.y) and (y <= MaxEdge.y) and
(z >= MinEdge.z) and (z <= MaxEdge.z)
end
function VoxelArea:containsp(p)
return (p.x >= self.MinEdge.x) and (p.x <= self.MaxEdge.x) and
(p.y >= self.MinEdge.y) and (p.y <= self.MaxEdge.y) and
(p.z >= self.MinEdge.z) and (p.z <= self.MaxEdge.z)
local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
return (p.x >= MinEdge.x) and (p.x <= MaxEdge.x) and
(p.y >= MinEdge.y) and (p.y <= MaxEdge.y) and
(p.z >= MinEdge.z) and (p.z <= MaxEdge.z)
end
function VoxelArea:containsi(i)

View File

@ -6,7 +6,20 @@
--
-- Initialize some very basic things
print = core.debug
function core.debug(...) core.log(table.concat({...}, "\t")) end
if core.print then
local core_print = core.print
-- Override native print and use
-- terminal if that's turned on
function print(...)
local n, t = select("#", ...), { ... }
for i = 1, n do
t[i] = tostring(t[i])
end
core_print(table.concat(t, "\t"))
end
core.print = nil -- don't pollute our namespace
end
math.randomseed(os.time())
os.setlocale("C", "numeric")
minetest = core
@ -17,6 +30,7 @@ local gamepath = scriptdir.."game"..DIR_DELIM
local commonpath = scriptdir.."common"..DIR_DELIM
local asyncpath = scriptdir.."async"..DIR_DELIM
dofile(commonpath.."strict.lua")
dofile(commonpath.."serialize.lua")
dofile(commonpath.."misc_helpers.lua")

View File

@ -16,13 +16,69 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
-- Global menu data
---------------------------------------------------------------------------------
--------------------------------------------------------------------------------
menudata = {}
--------------------------------------------------------------------------------
-- Local cached values
--------------------------------------------------------------------------------
local min_supp_proto = core.get_min_supp_proto()
local max_supp_proto = core.get_max_supp_proto()
--------------------------------------------------------------------------------
-- Menu helper functions
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function render_client_count(n)
if n > 99 then
return '99+'
elseif n >= 0 then
return tostring(n)
else
return '?'
end
end
local function configure_selected_world_params(idx)
local worldconfig = modmgr.get_worldconfig(
menudata.worldlist:get_list()[idx].path)
if worldconfig.creative_mode ~= nil then
core.setting_set("creative_mode", worldconfig.creative_mode)
end
if worldconfig.enable_damage ~= nil then
core.setting_set("enable_damage", worldconfig.enable_damage)
end
end
--------------------------------------------------------------------------------
function image_column(tooltip, flagname)
return "image," ..
"tooltip=" .. core.formspec_escape(tooltip) .. "," ..
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_" .. flagname .. ".png")
end
--------------------------------------------------------------------------------
function order_favorite_list(list)
local res = {}
--orders the favorite list after support
for i=1,#list,1 do
local fav = list[i]
if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
table.insert(res, fav)
end
end
for i=1,#list,1 do
local fav = list[i]
if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
table.insert(res, fav)
end
end
return res
end
--------------------------------------------------------------------------------
function render_favorite(spec,render_details)
local text = ""
@ -49,40 +105,60 @@ function render_favorite(spec,render_details)
end
local details = ""
if spec.password == true then
details = details .. "*"
local grey_out = not is_server_protocol_compat(spec.proto_max, spec.proto_min)
if spec.clients ~= nil and spec.clients_max ~= nil then
local clients_color = ''
local clients_percent = 100 * spec.clients / spec.clients_max
-- Choose a color depending on how many clients are connected
-- (relatively to clients_max)
if spec.clients == 0 then
clients_color = '' -- 0 players: default/white
elseif spec.clients == spec.clients_max then
clients_color = '#dd5b5b' -- full server: red (darker)
elseif clients_percent <= 60 then
clients_color = '#a1e587' -- 0-60%: green
elseif clients_percent <= 90 then
clients_color = '#ffdc97' -- 60-90%: yellow
else
clients_color = '#ffba97' -- 90-100%: orange
end
if grey_out then
clients_color = '#aaaaaa'
end
details = details ..
clients_color .. ',' ..
render_client_count(spec.clients) .. ',' ..
'/,' ..
render_client_count(spec.clients_max) .. ','
elseif grey_out then
details = details .. '#aaaaaa,?,/,?,'
else
details = details .. "_"
details = details .. ',?,/,?,'
end
if spec.creative then
details = details .. "C"
details = details .. "1,"
else
details = details .. "_"
details = details .. "0,"
end
if spec.damage then
details = details .. "D"
details = details .. "1,"
else
details = details .. "_"
details = details .. "0,"
end
if spec.pvp then
details = details .. "P"
details = details .. "1,"
else
details = details .. "_"
end
details = details .. " "
local playercount = ""
if spec.clients ~= nil and
spec.clients_max ~= nil then
playercount = string.format("%03d",spec.clients) .. "/" ..
string.format("%03d",spec.clients_max) .. " "
details = details .. "0,"
end
return playercount .. core.formspec_escape(details) .. text
return details .. (grey_out and '#aaaaaa,' or ',') .. text
end
--------------------------------------------------------------------------------
@ -125,7 +201,6 @@ end
--------------------------------------------------------------------------------
function menu_handle_key_up_down(fields,textlist,settingname)
if fields["key_up"] then
local oldidx = core.get_textlist_index(textlist)
@ -133,6 +208,8 @@ function menu_handle_key_up_down(fields,textlist,settingname)
local newidx = oldidx -1
core.setting_set(settingname,
menudata.worldlist:get_raw_index(newidx))
configure_selected_world_params(newidx)
end
return true
end
@ -144,50 +221,127 @@ function menu_handle_key_up_down(fields,textlist,settingname)
local newidx = oldidx + 1
core.setting_set(settingname,
menudata.worldlist:get_raw_index(newidx))
configure_selected_world_params(newidx)
end
return true
end
return false
end
--------------------------------------------------------------------------------
function asyncOnlineFavourites()
menudata.favorites = {}
if not menudata.public_known then
menudata.public_known = {{
name = fgettext("Loading..."),
description = fgettext_ne("Try reenabling public serverlist and check your internet connection.")
}}
end
menudata.favorites = menudata.public_known
core.handle_async(
function(param)
return core.get_favorites("online")
end,
nil,
function(result)
menudata.favorites = result
core.event_handler("Refresh")
if core.setting_getbool("public_serverlist") then
local favs = order_favorite_list(result)
if favs[1] then
menudata.public_known = favs
menudata.favorites = menudata.public_known
end
core.event_handler("Refresh")
end
end
)
)
end
--------------------------------------------------------------------------------
function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
local textlines = core.splittext(text,textlen)
local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
.. width .. "," .. height .. ";"
.. tl_name .. ";"
for i=1, #textlines, 1 do
textlines[i] = textlines[i]:gsub("\r","")
retval = retval .. core.formspec_escape(textlines[i]) .. ","
end
retval = retval .. ";0;"
if transparency then
retval = retval .. "true"
end
retval = retval .. "]"
return retval
end
--------------------------------------------------------------------------------
function is_server_protocol_compat(server_proto_min, server_proto_max)
return not ((min_supp_proto > (server_proto_max or 24)) or (max_supp_proto < (server_proto_min or 13)))
end
--------------------------------------------------------------------------------
function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
if not is_server_protocol_compat(server_proto_min, server_proto_max) then
local server_prot_ver_info
local client_prot_ver_info
if server_proto_min ~= server_proto_max then
server_prot_ver_info = fgettext_ne("Server supports protocol versions between $1 and $2. ",
server_proto_min or 13, server_proto_max or 24)
else
server_prot_ver_info = fgettext_ne("Server enforces protocol version $1. ",
server_proto_min or 13)
end
if min_supp_proto ~= max_supp_proto then
client_prot_ver_info= fgettext_ne("We support protocol versions between version $1 and $2.",
min_supp_proto, max_supp_proto)
else
client_prot_ver_info = fgettext_ne("We only support protocol version $1.", min_supp_proto)
end
gamedata.errormessage = fgettext_ne("Protocol version mismatch. ")
.. server_prot_ver_info
.. client_prot_ver_info
return false
end
return true
end
--------------------------------------------------------------------------------
function menu_worldmt(selected, setting, value)
local world = menudata.worldlist:get_list()[selected]
if world then
local filename = world.path .. DIR_DELIM .. "world.mt"
local world_conf = Settings(filename)
if value ~= nil then
if not world_conf:write() then
core.log("error", "Failed to write world config file")
end
world_conf:set(setting, value)
world_conf:write()
else
return world_conf:get(setting)
end
else
return nil
end
end
function menu_worldmt_legacy(selected)
local modes_names = {"creative_mode", "enable_damage", "server_announce"}
for _, mode_name in pairs(modes_names) do
local mode_val = menu_worldmt(selected, mode_name)
if mode_val ~= nil then
core.setting_set(mode_name, mode_val)
else
menu_worldmt(selected, mode_name, core.setting_get(mode_name))
end
end
end

View File

@ -16,6 +16,9 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
local function modname_valid(name)
return not name:find("[^a-z0-9_]")
end
local function get_formspec(data)
@ -118,6 +121,7 @@ local function handle_buttons(this, fields)
if fields["world_config_modlist"] ~= nil then
local event = core.explode_textlist_event(fields["world_config_modlist"])
this.data.selected_mod = event.index
core.setting_set("world_config_selected_mod", event.index)
if event.type == "DCL" then
enable_mod(this)
@ -151,21 +155,29 @@ local function handle_buttons(this, fields)
if current == nil then
current = {}
end
if core.is_yes(fields["cb_hide_gamemods"]) then
current.hide_game = true
this.data.hide_gamemods = true
else
current.hide_game = false
this.data.hide_gamemods = false
end
if core.is_yes(fields["cb_hide_mpcontent"]) then
current.hide_modpackcontents = true
this.data.hide_modpackcontents = true
else
current.hide_modpackcontents = false
this.data.hide_modpackcontents = false
if fields["cb_hide_gamemods"] ~= nil then
if core.is_yes(fields["cb_hide_gamemods"]) then
current.hide_game = true
this.data.hide_gamemods = true
core.setting_set("world_config_hide_gamemods", "true")
else
current.hide_game = false
this.data.hide_gamemods = false
core.setting_set("world_config_hide_gamemods", "false")
end
end
if fields["cb_hide_mpcontent"] ~= nil then
if core.is_yes(fields["cb_hide_mpcontent"]) then
current.hide_modpackcontents = true
this.data.hide_modpackcontents = true
core.setting_set("world_config_hide_modpackcontents", "true")
else
current.hide_modpackcontents = false
this.data.hide_modpackcontents = false
core.setting_set("world_config_hide_modpackcontents", "false")
end
end
this.data.list:set_filtercriteria(current)
@ -186,10 +198,12 @@ local function handle_buttons(this, fields)
for i,mod in ipairs(rawlist) do
if not mod.is_modpack and
mod.typ ~= "game_mod" then
if mod.enabled then
worldfile:set("load_mod_"..mod.name, "true")
if modname_valid(mod.name) then
worldfile:set("load_mod_"..mod.name, tostring(mod.enabled))
else
worldfile:set("load_mod_"..mod.name, "false")
if mod.enabled then
gamedata.errormessage = fgettext_ne("Failed to enable mod \"$1\" as it contains disallowed characters. Only chararacters [a-z0-9_] are allowed.", mod.name)
end
end
mods["load_mod_"..mod.name] = nil
end
@ -237,10 +251,12 @@ function create_configure_world_dlg(worldidx)
handle_buttons,
nil)
--TODO read from settings
dlg.data.hide_gamemods = false
dlg.data.hide_modpackcontents = false
dlg.data.selected_mod = 0
dlg.data.hide_gamemods = core.setting_getbool("world_config_hide_gamemods")
dlg.data.hide_modpackcontents = core.setting_getbool("world_config_hide_modpackcontents")
dlg.data.selected_mod = tonumber(core.setting_get("world_config_selected_mod"))
if dlg.data.selected_mod == nil then
dlg.data.selected_mod = 0
end
dlg.data.worldspec = core.get_worlds()[worldidx]
if dlg.data.worldspec == nil then dlg:delete() return nil end
@ -277,7 +293,12 @@ function create_configure_world_dlg(worldidx)
{ worldpath= dlg.data.worldspec.path,
gameid = dlg.data.worldspec.gameid }
)
if dlg.data.selected_mod > dlg.data.list:size() then
dlg.data.selected_mod = 0
end
dlg.data.list:set_filtercriteria(
{
hide_game=dlg.data.hide_gamemods,
@ -285,6 +306,6 @@ function create_configure_world_dlg(worldidx)
})
dlg.data.list:add_sort_mechanism("alphabetic", sort_mod_list)
dlg.data.list:set_sortmode("alphabetic")
return dlg
end

View File

@ -16,7 +16,7 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local function create_world_formspec(dialogdata)
local mapgens = {"v6", "v7", "singlenode"}
local mapgens = core.get_mapgen_names()
local current_seed = core.setting_get("fixed_map_seed") or ""
local current_mg = core.setting_get("mg_name")
@ -62,6 +62,16 @@ local function create_world_formspec(dialogdata)
"button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
"button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
if #gamemgr.games == 0 then
retval = retval .. "box[2,4;8,1;#ff8800]label[2.25,4;" ..
fgettext("You have no subgames installed.") .. "]label[2.25,4.4;" ..
fgettext("Download one from minetest.net") .. "]"
elseif #gamemgr.games == 1 and gamemgr.games[1].id == "minimal" then
retval = retval .. "box[1.75,4;8.7,1;#ff8800]label[2,4;" ..
fgettext("Warning: The minimal development test is meant for developers.") .. "]label[2,4.4;" ..
fgettext("Download a subgame, such as minetest_game, from minetest.net") .. "]"
end
return retval
@ -80,6 +90,8 @@ local function create_world_buttonhandler(this, fields)
local message = nil
core.setting_set("fixed_map_seed", fields["te_seed"])
if not menudata.worldlist:uid_exists_raw(worldname) then
core.setting_set("mg_name",fields["dd_mapgen"])
message = core.create_world(worldname,gameindex)
@ -87,8 +99,6 @@ local function create_world_buttonhandler(this, fields)
message = fgettext("A world named \"$1\" already exists", worldname)
end
core.setting_set("fixed_map_seed", fields["te_seed"])
if message ~= nil then
gamedata.errormessage = message
else

View File

@ -0,0 +1,756 @@
--Minetest
--Copyright (C) 2015 PilzAdam
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local FILENAME = "settingtypes.txt"
local CHAR_CLASSES = {
SPACE = "[%s]",
VARIABLE = "[%w_%-%.]",
INTEGER = "[+-]?[%d]",
FLOAT = "[+-]?[%d%.]",
FLAGS = "[%w_%-%.,]",
}
-- returns error message, or nil
local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
-- comment
local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
if comment then
if settings.current_comment == "" then
settings.current_comment = comment
else
settings.current_comment = settings.current_comment .. "\n" .. comment
end
return
end
-- clear current_comment so only comments directly above a setting are bound to it
-- but keep a local reference to it for variables in the current line
local current_comment = settings.current_comment
settings.current_comment = ""
-- empty lines
if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then
return
end
-- category
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
if category then
table.insert(settings, {
name = category,
level = stars:len() + base_level,
type = "category",
})
return
end
-- settings
local first_part, name, readable_name, setting_type = line:match("^"
-- this first capture group matches the whole first part,
-- so we can later strip it from the rest of the line
.. "("
.. "([" .. CHAR_CLASSES.VARIABLE .. "+)" -- variable name
.. CHAR_CLASSES.SPACE .. "*"
.. "%(([^%)]*)%)" -- readable name
.. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
.. CHAR_CLASSES.SPACE .. "*"
.. ")")
if not first_part then
return "Invalid line"
end
if name:match("secure%.[.]*") and not allow_secure then
return "Tried to add \"secure.\" setting"
end
if readable_name == "" then
readable_name = nil
end
local remaining_line = line:sub(first_part:len() + 1)
if setting_type == "int" then
local default, min, max = remaining_line:match("^"
-- first int is required, the last 2 are optional
.. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.INTEGER .. "*)"
.. "$")
if not default or not tonumber(default) then
return "Invalid integer setting"
end
min = tonumber(min)
max = tonumber(max)
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "int",
default = default,
min = min,
max = max,
comment = current_comment,
})
return
end
if setting_type == "string" or setting_type == "noise_params"
or setting_type == "key" or setting_type == "v3f" then
local default = remaining_line:match("^(.*)$")
if not default then
return "Invalid string setting"
end
if setting_type == "key" and not read_all then
-- ignore key type if read_all is false
return
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = setting_type,
default = default,
comment = current_comment,
})
return
end
if setting_type == "bool" then
if remaining_line ~= "false" and remaining_line ~= "true" then
return "Invalid boolean setting"
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "bool",
default = remaining_line,
comment = current_comment,
})
return
end
if setting_type == "float" then
local default, min, max = remaining_line:match("^"
-- first float is required, the last 2 are optional
.. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "?"
.. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "?"
.. "(" .. CHAR_CLASSES.FLOAT .. "*)"
.."$")
if not default or not tonumber(default) then
return "Invalid float setting"
end
min = tonumber(min)
max = tonumber(max)
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "float",
default = default,
min = min,
max = max,
comment = current_comment,
})
return
end
if setting_type == "enum" then
local default, values = remaining_line:match("^"
-- first value (default) may be empty (i.e. is optional)
.. "(" .. CHAR_CLASSES.VARIABLE .. "*)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.FLAGS .. "+)"
.. "$")
if not default or values == "" then
return "Invalid enum setting"
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "enum",
default = default,
values = values:split(",", true),
comment = current_comment,
})
return
end
if setting_type == "path" then
local default = remaining_line:match("^(.*)$")
if not default then
return "Invalid path setting"
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "path",
default = default,
comment = current_comment,
})
return
end
if setting_type == "flags" then
local default, possible = remaining_line:match("^"
-- first value (default) may be empty (i.e. is optional)
-- this is implemented by making the last value optional, and
-- swapping them around if it turns out empty.
.. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.FLAGS .. "*)"
.. "$")
if not default or not possible then
return "Invalid flags setting"
end
if possible == "" then
possible = default
default = ""
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "flags",
default = default,
possible = possible,
comment = current_comment,
})
return
end
return "Invalid setting type \"" .. setting_type .. "\""
end
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
result.current_comment = ""
local line = file:read("*line")
while line do
local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
if error_msg then
core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
end
line = file:read("*line")
end
result.current_comment = nil
end
-- read_all: whether to ignore certain setting types for GUI or not
-- parse_mods: whether to parse settingtypes.txt in mods and games
local function parse_config_file(read_all, parse_mods)
local builtin_path = core.get_builtin_path() .. DIR_DELIM .. FILENAME
local file = io.open(builtin_path, "r")
local settings = {}
if not file then
core.log("error", "Can't load " .. FILENAME)
return settings
end
parse_single_file(file, builtin_path, read_all, settings, 0, true)
file:close()
if parse_mods then
-- Parse games
local games_category_initialized = false
local index = 1
local game = gamemgr.get_game(index)
while game do
local path = game.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not games_category_initialized then
local translation = fgettext_ne("Games"), -- not used, but needed for xgettext
table.insert(settings, {
name = "Games",
level = 0,
type = "category",
})
games_category_initialized = true
end
table.insert(settings, {
name = game.name,
level = 1,
type = "category",
})
parse_single_file(file, path, read_all, settings, 2, false)
file:close()
end
index = index + 1
game = gamemgr.get_game(index)
end
-- Parse mods
local mods_category_initialized = false
local mods = {}
get_mods(core.get_modpath(), mods)
for _, mod in ipairs(mods) do
local path = mod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not mods_category_initialized then
local translation = fgettext_ne("Mods"), -- not used, but needed for xgettext
table.insert(settings, {
name = "Mods",
level = 0,
type = "category",
})
mods_category_initialized = true
end
table.insert(settings, {
name = mod.name,
level = 1,
type = "category",
})
parse_single_file(file, path, read_all, settings, 2, false)
file:close()
end
end
end
return settings
end
local settings = parse_config_file(false, true)
local selected_setting = 1
local function get_current_value(setting)
local value = core.setting_get(setting.name)
if value == nil then
value = setting.default
end
return value
end
local function create_change_setting_formspec(dialogdata)
local setting = settings[selected_setting]
local formspec = "size[10,5.2,true]" ..
"button[5,4.5;2,1;btn_done;" .. fgettext("Save") .. "]" ..
"button[3,4.5;2,1;btn_cancel;" .. fgettext("Cancel") .. "]" ..
"tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[0,0;10,3;info;"
if setting.readable_name then
formspec = formspec .. "#FFFF00," .. fgettext(setting.readable_name)
.. " (" .. core.formspec_escape(setting.name) .. "),"
else
formspec = formspec .. "#FFFF00," .. core.formspec_escape(setting.name) .. ","
end
formspec = formspec .. ",,"
local comment_text = ""
if setting.comment == "" then
comment_text = fgettext_ne("(No description of setting given)")
else
comment_text = fgettext_ne(setting.comment)
end
for _, comment_line in ipairs(comment_text:split("\n", true)) do
formspec = formspec .. "," .. core.formspec_escape(comment_line) .. ","
end
if setting.type == "flags" then
formspec = formspec .. ",,"
.. "," .. fgettext("Please enter a comma seperated list of flags.") .. ","
.. "," .. fgettext("Possible values are: ")
.. core.formspec_escape(setting.possible:gsub(",", ", ")) .. ","
elseif setting.type == "noise_params" then
formspec = formspec .. ",,"
.. "," .. fgettext("Format: <offset>, <scale>, (<spreadX>, <spreadY>, <spreadZ>), <seed>, <octaves>, <persistence>") .. ","
.. "," .. fgettext("Optionally the lacunarity can be appended with a leading comma.") .. ","
elseif setting.type == "v3f" then
formspec = formspec .. ",,"
.. "," .. fgettext_ne("Format is 3 numbers separated by commas and inside brackets.") .. ","
end
formspec = formspec:sub(1, -2) -- remove trailing comma
formspec = formspec .. ";1]"
if setting.type == "bool" then
local selected_index
if core.is_yes(get_current_value(setting)) then
selected_index = 2
else
selected_index = 1
end
formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
.. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";"
.. selected_index .. "]"
elseif setting.type == "enum" then
local selected_index = 0
formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
for index, value in ipairs(setting.values) do
-- translating value is not possible, since it's the value
-- that we set the setting to
formspec = formspec .. core.formspec_escape(value) .. ","
if get_current_value(setting) == value then
selected_index = index
end
end
if #setting.values > 0 then
formspec = formspec:sub(1, -2) -- remove trailing comma
end
formspec = formspec .. ";" .. selected_index .. "]"
elseif setting.type == "path" then
local current_value = dialogdata.selected_path
if not current_value then
current_value = get_current_value(setting)
end
formspec = formspec .. "field[0.5,4;7.5,1;te_setting_value;;"
.. core.formspec_escape(current_value) .. "]"
.. "button[8,3.75;2,1;btn_browser_path;" .. fgettext("Browse") .. "]"
else
-- TODO: fancy input for float, int, flags, noise_params, v3f
local width = 10
local text = get_current_value(setting)
if dialogdata.error_message then
formspec = formspec .. "tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[5,3.9;5,0.6;error_message;#FF0000,"
.. core.formspec_escape(dialogdata.error_message) .. ";0]"
width = 5
if dialogdata.entered_text then
text = dialogdata.entered_text
end
end
formspec = formspec .. "field[0.5,4;" .. width .. ",1;te_setting_value;;"
.. core.formspec_escape(text) .. "]"
end
return formspec
end
local function handle_change_setting_buttons(this, fields)
if fields["btn_done"] or fields["key_enter"] then
local setting = settings[selected_setting]
if setting.type == "bool" then
local new_value = fields["dd_setting_value"]
-- Note: new_value is the actual (translated) value shown in the dropdown
core.setting_setbool(setting.name, new_value == fgettext("Enabled"))
elseif setting.type == "enum" then
local new_value = fields["dd_setting_value"]
core.setting_set(setting.name, new_value)
elseif setting.type == "int" then
local new_value = tonumber(fields["te_setting_value"])
if not new_value or math.floor(new_value) ~= new_value then
this.data.error_message = fgettext_ne("Please enter a valid integer.")
this.data.entered_text = fields["te_setting_value"]
core.update_formspec(this:get_formspec())
return true
end
if setting.min and new_value < setting.min then
this.data.error_message = fgettext_ne("The value must be greater than $1.", setting.min)
this.data.entered_text = fields["te_setting_value"]
core.update_formspec(this:get_formspec())
return true
end
if setting.max and new_value > setting.max then
this.data.error_message = fgettext_ne("The value must be lower than $1.", setting.max)
this.data.entered_text = fields["te_setting_value"]
core.update_formspec(this:get_formspec())
return true
end
core.setting_set(setting.name, new_value)
elseif setting.type == "float" then
local new_value = tonumber(fields["te_setting_value"])
if not new_value then
this.data.error_message = fgettext_ne("Please enter a valid number.")
this.data.entered_text = fields["te_setting_value"]
core.update_formspec(this:get_formspec())
return true
end
core.setting_set(setting.name, new_value)
elseif setting.type == "flags" then
local new_value = fields["te_setting_value"]
for _,value in ipairs(new_value:split(",", true)) do
value = value:trim()
local possible = "," .. setting.possible .. ","
if not possible:find("," .. value .. ",", 0, true) then
this.data.error_message = fgettext_ne("\"$1\" is not a valid flag.", value)
this.data.entered_text = fields["te_setting_value"]
core.update_formspec(this:get_formspec())
return true
end
end
core.setting_set(setting.name, new_value)
else
local new_value = fields["te_setting_value"]
core.setting_set(setting.name, new_value)
end
core.setting_save()
this:delete()
return true
end
if fields["btn_cancel"] then
this:delete()
return true
end
if fields["btn_browser_path"] then
core.show_file_open_dialog("dlg_browse_path", fgettext_ne("Select path"))
end
if fields["dlg_browse_path_accepted"] then
this.data.selected_path = fields["dlg_browse_path_accepted"]
core.update_formspec(this:get_formspec())
end
return false
end
local function create_settings_formspec(tabview, name, tabdata)
local formspec = "size[12,6.5;true]" ..
"tablecolumns[color;tree;text;text]" ..
"tableoptions[background=#00000000;border=false]" ..
"table[0,0;12,5.5;list_settings;"
local current_level = 0
for _, entry in ipairs(settings) do
local name
if not core.setting_getbool("main_menu_technical_settings") and entry.readable_name then
name = fgettext_ne(entry.readable_name)
else
name = entry.name
end
if entry.type == "category" then
current_level = entry.level
formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
elseif entry.type == "bool" then
local value = get_current_value(entry)
if core.is_yes(value) then
value = fgettext("Enabled")
else
value = fgettext("Disabled")
end
formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
.. value .. ","
elseif entry.type == "key" then
-- ignore key settings, since we have a special dialog for them
else
formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
.. core.formspec_escape(get_current_value(entry)) .. ","
end
end
if #settings > 0 then
formspec = formspec:sub(1, -2) -- remove trailing comma
end
formspec = formspec .. ";" .. selected_setting .. "]" ..
"button[0,6;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
"button[10,6;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
"button[7,6;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
"checkbox[0,5.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
.. dump(core.setting_getbool("main_menu_technical_settings")) .. "]"
return formspec
end
local function handle_settings_buttons(this, fields, tabname, tabdata)
local list_enter = false
if fields["list_settings"] then
selected_setting = core.get_table_index("list_settings")
if core.explode_table_event(fields["list_settings"]).type == "DCL" then
-- Directly toggle booleans
local setting = settings[selected_setting]
if setting.type == "bool" then
local current_value = get_current_value(setting)
core.setting_setbool(setting.name, not core.is_yes(current_value))
core.setting_save()
return true
else
list_enter = true
end
else
return true
end
end
if fields["btn_edit"] or list_enter then
local setting = settings[selected_setting]
if setting.type ~= "category" then
local edit_dialog = dialog_create("change_setting", create_change_setting_formspec,
handle_change_setting_buttons)
edit_dialog:set_parent(this)
this:hide()
edit_dialog:show()
end
return true
end
if fields["btn_restore"] then
local setting = settings[selected_setting]
if setting.type ~= "category" then
core.setting_set(setting.name, setting.default)
core.setting_save()
core.update_formspec(this:get_formspec())
end
return true
end
if fields["btn_back"] then
this:delete()
return true
end
if fields["cb_tech_settings"] then
core.setting_set("main_menu_technical_settings", fields["cb_tech_settings"])
core.setting_save()
core.update_formspec(this:get_formspec())
return true
end
return false
end
function create_adv_settings_dlg()
local dlg = dialog_create("settings_advanced",
create_settings_formspec,
handle_settings_buttons,
nil)
return dlg
end
local function create_minetest_conf_example()
local result = "# This file contains a list of all available settings and their default value for minetest.conf\n" ..
"\n" ..
"# By default, all the settings are commented and not functional.\n" ..
"# Uncomment settings by removing the preceding #.\n" ..
"\n" ..
"# minetest.conf is read by default from:\n" ..
"# ../minetest.conf\n" ..
"# ../../minetest.conf\n" ..
"# Any other path can be chosen by passing the path as a parameter\n" ..
"# to the program, eg. \"minetest.exe --config ../minetest.conf.example\".\n" ..
"\n" ..
"# Further documentation:\n" ..
"# http://wiki.minetest.net/\n" ..
"\n"
local settings = parse_config_file(true, false)
for _, entry in ipairs(settings) do
if entry.type == "category" then
if entry.level == 0 then
result = result .. "#\n# " .. entry.name .. "\n#\n\n"
else
for i = 1, entry.level do
result = result .. "#"
end
result = result .. "# " .. entry.name .. "\n\n"
end
else
if entry.comment ~= "" then
for _, comment_line in ipairs(entry.comment:split("\n", true)) do
result = result .."# " .. comment_line .. "\n"
end
end
result = result .. "# type: " .. entry.type
if entry.min then
result = result .. " min: " .. entry.min
end
if entry.max then
result = result .. " max: " .. entry.max
end
if entry.values then
result = result .. " values: " .. table.concat(entry.values, ", ")
end
if entry.possible then
result = result .. " possible values: " .. entry.possible:gsub(",", ", ")
end
result = result .. "\n"
result = result .. "# " .. entry.name .. " = ".. entry.default .. "\n\n"
end
end
return result
end
local function create_translation_file()
local result = "// This file is automatically generated\n" ..
"// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files\n" ..
"// To update it, refer to the bottom of builtin/mainmenu/tab_settings.lua\n\n" ..
"fake_function() {\n"
local settings = parse_config_file(true, false)
for _, entry in ipairs(settings) do
if entry.type == "category" then
local name_escaped = entry.name:gsub("\"", "\\\"")
result = result .. "\tgettext(\"" .. name_escaped .. "\");\n"
else
if entry.readable_name then
local readable_name_escaped = entry.readable_name:gsub("\"", "\\\"")
result = result .. "\tgettext(\"" .. readable_name_escaped .. "\");\n"
end
if entry.comment ~= "" then
local comment_escaped = entry.comment:gsub("\n", "\\n")
comment_escaped = comment_escaped:gsub("\"", "\\\"")
result = result .. "\tgettext(\"" .. comment_escaped .. "\");\n"
end
end
end
result = result .. "}\n"
return result
end
if false then
local file = io.open("minetest.conf.example", "w")
if file then
file:write(create_minetest_conf_example())
file:close()
end
end
if false then
local file = io.open("src/settings_translation_file.cpp", "w")
if file then
file:write(create_translation_file())
file:close()
end
end

View File

@ -68,7 +68,7 @@ end
function gamemgr.gamelist()
local retval = ""
if #gamemgr.games > 0 then
retval = retval .. gamemgr.games[1].id
retval = retval .. gamemgr.games[1].name
for i=2,#gamemgr.games,1 do
retval = retval .. "," .. gamemgr.games[i].name

View File

@ -38,21 +38,26 @@ dofile(menupath .. DIR_DELIM .. "gamemgr.lua")
dofile(menupath .. DIR_DELIM .. "modmgr.lua")
dofile(menupath .. DIR_DELIM .. "store.lua")
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
dofile(menupath .. DIR_DELIM .. "tab_server.lua")
dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
dofile(menupath .. DIR_DELIM .. "textures.lua")
dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua")
if PLATFORM ~= "Android" then
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
dofile(menupath .. DIR_DELIM .. "tab_server.lua")
dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
dofile(menupath .. DIR_DELIM .. "textures.lua")
else
dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua")
end
--------------------------------------------------------------------------------
local function main_event_handler(tabview,event)
local function main_event_handler(tabview, event)
if event == "MenuQuit" then
core.close()
end
@ -61,55 +66,95 @@ end
--------------------------------------------------------------------------------
local function init_globals()
--init gamedata
-- Init gamedata
gamedata.worldindex = 0
menudata.worldlist = filterlist.create(
core.get_worlds,
compare_worlds,
function(element,uid)
if element.name == uid then
return true
end
return false
end, --unique id compare fct
function(element,gameid)
if element.gameid == gameid then
return true
end
return false
end --filter fct
)
menudata.worldlist:add_sort_mechanism("alphabetic",sort_worlds_alphabetic)
menudata.worldlist:set_sortmode("alphabetic")
if PLATFORM ~= "Android" then
menudata.worldlist = filterlist.create(
core.get_worlds,
compare_worlds,
-- Unique id comparison function
function(element, uid)
return element.name == uid
end,
-- Filter function
function(element, gameid)
return element.gameid == gameid
end
)
if not core.setting_get("menu_last_game") then
local default_game = core.setting_get("default_game") or "minetest"
core.setting_set("menu_last_game", default_game )
menudata.worldlist:add_sort_mechanism("alphabetic", sort_worlds_alphabetic)
menudata.worldlist:set_sortmode("alphabetic")
if not core.setting_get("menu_last_game") then
local default_game = core.setting_get("default_game") or "minetest"
core.setting_set("menu_last_game", default_game )
end
mm_texture.init()
else
local world_list = core.get_worlds()
local found_singleplayerworld = false
for i,world in pairs(world_list) do
if world.name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
break
end
end
if not found_singleplayerworld then
core.create_world("singleplayerworld", 1)
local world_list = core.get_worlds()
for i,world in pairs(world_list) do
if world.name == "singleplayerworld" then
gamedata.worldindex = i
break
end
end
end
end
mm_texture.init()
--create main tabview
-- Create main tabview
local tv_main = tabview_create("maintab",{x=12,y=5.2},{x=0,y=0})
tv_main:set_autosave_tab(true)
tv_main:add(tab_singleplayer)
tv_main:add(tab_multiplayer)
tv_main:add(tab_server)
if PLATFORM ~= "Android" then
tv_main:set_autosave_tab(true)
end
if PLATFORM ~= "Android" then
tv_main:add(tab_singleplayer)
tv_main:add(tab_multiplayer)
tv_main:add(tab_server)
else
tv_main:add(tab_simple_main)
end
tv_main:add(tab_settings)
tv_main:add(tab_texturepacks)
if PLATFORM ~= "Android" then
tv_main:add(tab_texturepacks)
end
tv_main:add(tab_mods)
tv_main:add(tab_credits)
tv_main:set_global_event_handler(main_event_handler)
tv_main:set_tab(core.setting_get("maintab_LAST"))
tv_main:set_fixed_size(false)
if not (PLATFORM == "Android") then
tv_main:set_tab(core.setting_get("maintab_LAST"))
end
ui.set_default("maintab")
tv_main:show()
--create modstore ui
modstore.init({x=12,y=8},4,3)
-- Create modstore ui
if PLATFORM == "Android" then
modstore.init({x=12, y=6}, 3, 2)
else
modstore.init({x=12, y=8}, 4, 3)
end
ui.update()
@ -117,3 +162,4 @@ local function init_globals()
end
init_globals()

View File

@ -1,102 +0,0 @@
--Minetest
--Copyright (C) 2014 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
mt_color_grey = "#AAAAAA"
mt_color_blue = "#0000DD"
mt_color_green = "#00DD00"
mt_color_dark_green = "#003300"
--marker for android specific code
ANDROID = true
local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path()
defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
dofile(basepath .. DIR_DELIM .. "common" .. DIR_DELIM .. "async_event.lua")
dofile(basepath .. DIR_DELIM .. "common" .. DIR_DELIM .. "filterlist.lua")
dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "buttonbar.lua")
dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "dialog.lua")
dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "tabview.lua")
dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "ui.lua")
dofile(menupath .. DIR_DELIM .. "common.lua")
dofile(menupath .. DIR_DELIM .. "gamemgr.lua")
dofile(menupath .. DIR_DELIM .. "modmgr.lua")
dofile(menupath .. DIR_DELIM .. "store.lua")
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua")
dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
--------------------------------------------------------------------------------
local function main_event_handler(tabview,event)
if event == "MenuQuit" then
core.close()
end
return true
end
local function init_globals()
--init gamedata
gamedata.worldindex = 0
local worldlist = core.get_worlds()
local found_singleplayerworld = false
for i=1,#worldlist,1 do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
end
end
if not found_singleplayerworld then
core.create_world("singleplayerworld", 1)
local worldlist = core.get_worlds()
for i=1,#worldlist,1 do
if worldlist[i].name == "singleplayerworld" then
gamedata.worldindex = i
end
end
end
--create main tabview
local tv_main = tabview_create("maintab",{x=12,y=5.2},{x=-0,y=-0})
tv_main:add(tab_simple_main)
tv_main:add(tab_mods)
tv_main:add(tab_settings)
tv_main:add(tab_credits)
tv_main:set_global_event_handler(main_event_handler)
tv_main:set_fixed_size(false)
ui.set_default("maintab")
tv_main:show()
--create modstore ui
modstore.init({x=12,y=6},3,2)
ui.update()
core.sound_play("main_menu", true)
end
init_globals()

View File

@ -0,0 +1,4 @@
-- helper file to be able to debug the simple menu on PC
-- without messing around with actual menu code!
PLATFORM="Android"
dofile("builtin/mainmenu/init.lua")

View File

@ -17,30 +17,32 @@
--------------------------------------------------------------------------------
function get_mods(path,retval,modpack)
local mods = core.get_dir_list(path, true)
for _, name in ipairs(mods) do
if name:sub(1, 1) ~= "." then
local prefix = path .. DIR_DELIM .. name .. DIR_DELIM
local toadd = {}
table.insert(retval, toadd)
local mods = core.get_dirlist(path,true)
for i=1,#mods,1 do
local toadd = {}
local modpackfile = nil
local mod_conf = Settings(prefix .. "mod.conf"):to_table()
if mod_conf.name then
name = mod_conf.name
end
toadd.name = mods[i]
toadd.path = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
if modpack ~= nil and
modpack ~= "" then
toadd.modpack = modpack
else
local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
local error = nil
modpackfile,error = io.open(filename,"r")
end
toadd.name = name
toadd.path = prefix
if modpackfile ~= nil then
modpackfile:close()
toadd.is_modpack = true
table.insert(retval,toadd)
get_mods(path .. DIR_DELIM .. mods[i],retval,mods[i])
else
table.insert(retval,toadd)
if modpack ~= nil and modpack ~= "" then
toadd.modpack = modpack
else
local modpackfile = io.open(prefix .. "modpack.txt")
if modpackfile then
modpackfile:close()
toadd.is_modpack = true
get_mods(prefix, retval, name)
end
end
end
end
end
@ -92,7 +94,7 @@ function modmgr.getbasefolder(temppath)
}
end
local subdirs = core.get_dirlist(temppath,true)
local subdirs = core.get_dir_list(temppath, true)
--only single mod or modpack allowed
if #subdirs ~= 1 then
@ -319,8 +321,10 @@ function modmgr.get_worldconfig(worldpath)
for key,value in pairs(worldfile:to_table()) do
if key == "gameid" then
worldconfig.id = value
else
elseif key:sub(0, 9) == "load_mod_" then
worldconfig.global_mods[key] = core.is_yes(value)
else
worldconfig[key] = value
end
end

View File

@ -122,35 +122,36 @@ end
function modstore.showdownloading(title)
local new_dlg = dialog_create("store_downloading",
function(data)
return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
" " .. data.title .. " " ..
fgettext("please wait...") .. "]"
return "size[6,2]label[0.25,0.75;" ..
fgettext("Downloading $1, please wait...", data.title) .. "]"
end,
function(this,fields)
if fields["btn_hidden_close_download"] ~= nil then
if fields["btn_hidden_close_download"].successfull then
modstore.lastmodentry = fields["btn_hidden_close_download"]
modstore.successfulldialog()
modstore.successfulldialog(this)
else
this.parent:show()
this:delete()
modstore.lastmodtitle = ""
end
this:delete()
return true
end
return false
end,
nil,
modstore.tv_store)
nil)
new_dlg:set_parent(modstore.tv_store)
modstore.tv_store:hide()
new_dlg.data.title = title
new_dlg:show()
end
--------------------------------------------------------------------------------
-- @function [parent=#modstore] successfulldialog
function modstore.successfulldialog()
function modstore.successfulldialog(downloading_dlg)
local new_dlg = dialog_create("store_downloading",
function(data)
local retval = ""
@ -158,18 +159,16 @@ function modstore.successfulldialog()
if modstore.lastmodentry ~= nil then
retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
retval = retval .. "label[3,0.75;" .. core.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
end
retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
retval = retval .. "button[2.2,1.5;1.5,0.5;btn_confirm_mod_successfull;" .. fgettext("Ok") .. "]"
return retval
end,
function(this,fields)
if fields["btn_confirm_mod_successfull"] ~= nil then
this.parent:show()
this:hide()
downloading_dlg:delete()
this:delete()
return true
@ -177,10 +176,10 @@ function modstore.successfulldialog()
return false
end,
nil,
modstore.tv_store)
nil)
new_dlg.data.title = title
new_dlg:set_parent(modstore.tv_store)
modstore.tv_store:hide()
new_dlg:show()
end
@ -217,7 +216,9 @@ function modstore.handle_buttons(parent, fields, name, data)
end
if fields["btn_modstore_close"] then
local maintab = ui.find_by_name("maintab")
parent:hide()
maintab:show()
return true
end
@ -228,12 +229,7 @@ function modstore.handle_buttons(parent, fields, name, data)
for i=1,#modstore.modlist_unsorted.data,1 do
if modstore.modlist_unsorted.data[i].id == modid then
local moddetails = modstore.modlist_unsorted.data[i].details
if modstore.lastmodtitle ~= "" then
modstore.lastmodtitle = modstore.lastmodtitle .. ", "
end
modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
modstore.lastmodtitle = moddetails.title
if not core.handle_async(
function(param)
@ -281,7 +277,7 @@ function modstore.handle_buttons(parent, fields, name, data)
texturename = modstore.modlist_unsorted.data[i].texturename
},
function(result)
print("Result from async: " .. dump(result.successfull))
--print("Result from async: " .. dump(result.successfull))
if result.successfull then
modmgr.installmod(result.filename,result.moddetails.basename)
os.remove(result.filename)
@ -299,7 +295,7 @@ function modstore.handle_buttons(parent, fields, name, data)
print("ERROR: async event failed")
gamedata.errormessage = "Failed to download " .. modstore.lastmodtitle
end
parent:hide()
modstore.showdownloading(modstore.lastmodtitle)
return true
end
@ -391,7 +387,7 @@ function modstore.getscreenshot(ypos,listentry)
listentry.details.screenshot_url == "") then
if listentry.texturename == nil then
listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
listentry.texturename = defaulttexturedir .. "no_screenshot.png"
end
return "image[0,".. ypos .. ";3,2;" ..

View File

@ -22,40 +22,59 @@ tab_credits = {
caption = fgettext("Credits"),
cbf_formspec = function (tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
return "vertlabel[0,-0.25;CREDITS]" ..
"label[0.5,3;Minetest " .. core.get_version() .. "]" ..
"label[0.5,3.3;http://minetest.net]" ..
return "label[0.5,3.2;Minetest " .. core.get_version() .. "]" ..
"label[0.5,3.5;http://minetest.net]" ..
"image[0.5,1;" .. core.formspec_escape(logofile) .. "]" ..
"textlist[3.5,-0.25;8.5,5.8;list_credits;" ..
"#FFFF00" .. fgettext("Core Developers") .."," ..
"Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
"PilzAdam <pilzadam@minetest.net>," ..
"Ilya Zhuravlev (xyz) <xyz@minetest.net>,"..
"Lisa Milne (darkrose) <lisa@ltmnet.com>,"..
"Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,"..
"sfan5 <sfan5@live.de>,"..
"kahrl <kahrl@gmx.net>,"..
"sapier,"..
"ShadowNinja <shadowninja@minetest.net>,"..
"Nathanael Courant (Nore/Novatux) <nore@mesecons.net>,"..
"BlockMen,"..
","..
"#FFFF00" .. fgettext("Active Contributors") .. "," ..
"Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
"Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
"Jeija <jeija@mesecons.net>,"..
"MirceaKitsune <mirceakitsune@gmail.com>,"..
"dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
"0gb.us <0gb.us@0gb.us>,"..
"," ..
"#FFFF00" .. fgettext("Previous Contributors") .. "," ..
"Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
"Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
"Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
"matttpt <matttpt@gmail.com>,"..
"JacobF <queatz@gmail.com>,"..
";0;true]"
"tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[3.5,-0.25;8.5,5.8;list_credits;" ..
"#FFFF00," .. fgettext("Core Developers") .."," ..
",Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
",Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
",PilzAdam <pilzadam@minetest.net>," ..
",sfan5 <sfan5@live.de>,"..
",kahrl <kahrl@gmx.net>,"..
",sapier,"..
",ShadowNinja <shadowninja@minetest.net>,"..
",Nathanael Courant (Nore/Ekdohibs) <nore@mesecons.net>,"..
",BlockMen,"..
",Craig Robbins (Zeno),"..
",Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>,"..
",Mat Gregory (paramat),"..
",est31 <MTest31@outlook.com>," ..
",,"..
"#FFFF00," .. fgettext("Active Contributors") .. "," ..
",SmallJoker <mk939@ymail.com>," ..
",Andrew Ward (rubenwardy) <rubenwardy@gmail.com>," ..
",Aaron Suen <warr1024@gmail.com>," ..
",Sokomine <wegwerf@anarres.dyndns.org>," ..
",Břetislav Štec (t0suj4/TBC_x)," ..
",TeTpaAka," ..
",Jean-Patrick G (kilbith) <jeanpatrick.guerrero@gmail.com>," ..
",Diego Martinez (kaeza) <kaeza@users.sf.net>," ..
",," ..
"#FFFF00," .. fgettext("Previous Core Developers") .."," ..
",Maciej Kasatkin (RealBadAngel) <maciej.kasatkin@o2.pl>,"..
",Lisa Milne (darkrose) <lisa@ltmnet.com>," ..
",proller," ..
",Ilya Zhuravlev (xyz) <xyz@minetest.net>," ..
",," ..
"#FFFF00," .. fgettext("Previous Contributors") .. "," ..
",Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
",Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
",Gregory Currie (gregorycu)," ..
",Jeija <jeija@mesecons.net>,"..
",MirceaKitsune <mirceakitsune@gmail.com>,"..
",dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
",0gb.us <0gb.us@0gb.us>,"..
",Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
",Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
",Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
",Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
",matttpt <matttpt@gmail.com>,"..
",JacobF <queatz@gmail.com>,"..
",TriBlade9 <triblade9@mail.com>,"..
",Zefram <zefram@fysh.org>,"..
";1]"
end
}

View File

@ -27,17 +27,19 @@ local function get_formspec(tabview, name, tabdata)
end
local retval =
"vertlabel[0,-0.25;".. fgettext("MODS") .. "]" ..
"label[0.8,-0.25;".. fgettext("Installed Mods:") .. "]" ..
"textlist[0.75,0.25;4.5,4;modlist;" ..
"label[0.05,-0.25;".. fgettext("Installed Mods:") .. "]" ..
"textlist[0,0.25;5.1,4.35;modlist;" ..
modmgr.render_modlist(modmgr.global_mods) ..
";" .. tabdata.selected_mod .. "]"
retval = retval ..
"label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
-- "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
-- TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
-- "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
"button[2.45,4.85;3.05,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]"
-- TODO Disabled due to service being offline, and not likely to come online again, in this form
-- "button[0,4.85;5.25,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]"
""
local selected_mod = nil
@ -58,7 +60,7 @@ local function get_formspec(tabview, name, tabdata)
end
if modscreenshot == nil then
modscreenshot = modstore.basetexturedir .. "no_screenshot.png"
modscreenshot = defaulttexturedir .. "no_screenshot.png"
end
retval = retval
@ -97,7 +99,7 @@ local function get_formspec(tabview, name, tabdata)
else
--show dependencies
retval = retval .. ",Depends:,"
retval = retval .. "," .. fgettext("Depends:") .. ","
local toadd = modmgr.get_dependencies(selected_mod.path)

View File

@ -20,25 +20,27 @@ local function get_formspec(tabview, name, tabdata)
local render_details = core.is_yes(core.setting_getbool("public_serverlist"))
local retval =
"vertlabel[0,-0.25;".. fgettext("CLIENT") .. "]" ..
"label[1,-0.25;".. fgettext("Favorites:") .. "]"..
"label[1,4.25;".. fgettext("Address/Port") .. "]"..
"label[9,2.75;".. fgettext("Name/Password") .. "]" ..
"field[1.25,5.25;5.5,0.5;te_address;;" ..core.setting_get("address") .."]" ..
"field[6.75,5.25;2.25,0.5;te_port;;" ..core.setting_get("remote_port") .."]" ..
"checkbox[1,3.6;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
"label[7.75,-0.15;" .. fgettext("Address / Port :") .. "]" ..
"label[7.75,1.05;" .. fgettext("Name / Password :") .. "]" ..
"field[8,0.75;3.4,0.5;te_address;;" ..
core.formspec_escape(core.setting_get("address")) .. "]" ..
"field[11.25,0.75;1.3,0.5;te_port;;" ..
core.formspec_escape(core.setting_get("remote_port")) .. "]" ..
"checkbox[0,4.85;cb_public_serverlist;" .. fgettext("Public Serverlist") .. ";" ..
dump(core.setting_getbool("public_serverlist")) .. "]"
if not core.setting_getbool("public_serverlist") then
retval = retval ..
"button[6.45,3.95;2.25,0.5;btn_delete_favorite;".. fgettext("Delete") .. "]"
"button[8,4.9;2,0.5;btn_delete_favorite;" .. fgettext("Delete") .. "]"
end
retval = retval ..
"button[9,4.95;2.5,0.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
"field[9.3,3.75;2.5,0.5;te_name;;" ..core.setting_get("name") .."]" ..
"pwdfield[9.3,4.5;2.5,0.5;te_pwd;]" ..
"textarea[9.3,0.25;2.5,2.75;;"
"button[10,4.9;2,0.5;btn_mp_connect;" .. fgettext("Connect") .. "]" ..
"field[8,1.95;2.95,0.5;te_name;;" ..
core.formspec_escape(core.setting_get("name")) .. "]" ..
"pwdfield[10.78,1.95;1.77,0.5;te_pwd;]" ..
"box[7.73,2.35;4.3,2.28;#999999]" ..
"textarea[8.1,2.4;4.26,2.6;;"
if tabdata.fav_selected ~= nil and
menudata.favorites[tabdata.fav_selected] ~= nil and
@ -49,10 +51,24 @@ local function get_formspec(tabview, name, tabdata)
retval = retval ..
";]"
--favourites
if render_details then
retval = retval .. "tablecolumns[" ..
"color,span=3;" ..
"text,align=right;" .. -- clients
"text,align=center,padding=0.25;" .. -- "/"
"text,align=right,padding=0.25;" .. -- clients_max
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" -- name
else
retval = retval .. "tablecolumns[text]"
end
retval = retval ..
"textlist[1,0.35;7.5,3.35;favourites;"
"table[-0.15,-0.1;7.75,5;favourites;"
if #menudata.favorites > 0 then
retval = retval .. render_favorite(menudata.favorites[1],render_details)
@ -73,18 +89,21 @@ end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
if fields["te_name"] ~= nil then
gamedata.playername = fields["te_name"]
core.setting_set("name", fields["te_name"])
end
if fields["favourites"] ~= nil then
local event = core.explode_textlist_event(fields["favourites"])
local event = core.explode_table_event(fields["favourites"])
if event.type == "DCL" then
if event.index <= #menudata.favorites then
gamedata.address = menudata.favorites[event.index].address
gamedata.port = menudata.favorites[event.index].port
if event.row <= #menudata.favorites then
if not is_server_protocol_compat_or_error(menudata.favorites[event.row].proto_min,
menudata.favorites[event.row].proto_max) then
return true
end
gamedata.address = menudata.favorites[event.row].address
gamedata.port = menudata.favorites[event.row].port
gamedata.playername = fields["te_name"]
if fields["te_pwd"] ~= nil then
gamedata.password = fields["te_pwd"]
@ -92,8 +111,8 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.selected_world = 0
if menudata.favorites ~= nil then
gamedata.servername = menudata.favorites[event.index].name
gamedata.serverdescription = menudata.favorites[event.index].description
gamedata.servername = menudata.favorites[event.row].name
gamedata.serverdescription = menudata.favorites[event.row].description
end
if gamedata.address ~= nil and
@ -107,9 +126,9 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
if event.type == "CHG" then
if event.index <= #menudata.favorites then
local address = menudata.favorites[event.index].address
local port = menudata.favorites[event.index].port
if event.row <= #menudata.favorites then
local address = menudata.favorites[event.row].address
local port = menudata.favorites[event.row].port
if address ~= nil and
port ~= nil then
@ -117,7 +136,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
core.setting_set("remote_port",port)
end
tabdata.fav_selected = event.index
tabdata.fav_selected = event.row
end
return true
@ -127,7 +146,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
if fields["key_up"] ~= nil or
fields["key_down"] ~= nil then
local fav_idx = core.get_textlist_index("favourites")
local fav_idx = core.get_table_index("favourites")
if fav_idx ~= nil then
if fields["key_up"] ~= nil and fav_idx > 1 then
@ -171,10 +190,10 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
if fields["btn_delete_favorite"] ~= nil then
local current_favourite = core.get_textlist_index("favourites")
local current_favourite = core.get_table_index("favourites")
if current_favourite == nil then return end
core.delete_favorite(current_favourite)
menudata.favorites = core.get_favorites()
menudata.favorites = order_favorite_list(core.get_favorites())
tabdata.fav_selected = nil
core.setting_set("address","")
@ -183,15 +202,16 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
if fields["btn_mp_connect"] ~= nil or
fields["key_enter"] ~= nil then
if (fields["btn_mp_connect"] ~= nil or
fields["key_enter"] ~= nil) and fields["te_address"] ~= nil and
fields["te_port"] ~= nil then
gamedata.playername = fields["te_name"]
gamedata.password = fields["te_pwd"]
gamedata.address = fields["te_address"]
gamedata.port = fields["te_port"]
local fav_idx = core.get_textlist_index("favourites")
local fav_idx = core.get_table_index("favourites")
if fav_idx ~= nil and fav_idx <= #menudata.favorites and
menudata.favorites[fav_idx].address == fields["te_address"] and
@ -199,6 +219,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.servername = menudata.favorites[fav_idx].name
gamedata.serverdescription = menudata.favorites[fav_idx].description
if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
menudata.favorites[fav_idx].proto_max)then
return true
end
else
gamedata.servername = ""
gamedata.serverdescription = ""

View File

@ -23,33 +23,33 @@ local function get_formspec(tabview, name, tabdata)
)
local retval =
"button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
"button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
"button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
"button[8.5,4.9;3.25,0.5;start_server;".. fgettext("Start Game") .. "]" ..
"label[4,-0.25;".. fgettext("Select World:") .. "]"..
"vertlabel[0,-0.25;".. fgettext("START SERVER") .. "]" ..
"checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
dump(core.setting_getbool("creative_mode")) .. "]"..
"checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]"..
"checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
dump(core.setting_getbool("server_announce")) .. "]"..
"field[0.8,3.2;3.5,0.5;te_playername;".. fgettext("Name") .. ";" ..
core.setting_get("name") .. "]" ..
"pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
"button[4,4.15;2.6,0.5;world_delete;" .. fgettext("Delete") .. "]" ..
"button[6.5,4.15;2.8,0.5;world_create;" .. fgettext("New") .. "]" ..
"button[9.2,4.15;2.55,0.5;world_configure;" .. fgettext("Configure") .. "]" ..
"button[8.5,4.95;3.25,0.5;start_server;" .. fgettext("Start Game") .. "]" ..
"label[4,-0.25;" .. fgettext("Select World:") .. "]" ..
"checkbox[0.25,0.25;cb_creative_mode;" .. fgettext("Creative Mode") .. ";" ..
dump(core.setting_getbool("creative_mode")) .. "]" ..
"checkbox[0.25,0.7;cb_enable_damage;" .. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]" ..
"checkbox[0.25,1.15;cb_server_announce;" .. fgettext("Public") .. ";" ..
dump(core.setting_getbool("server_announce")) .. "]" ..
"label[0.25,2.2;" .. fgettext("Name/Password") .. "]" ..
"field[0.55,3.2;3.5,0.5;te_playername;;" ..
core.formspec_escape(core.setting_get("name")) .. "]" ..
"pwdfield[0.55,4;3.5,0.5;te_passwd;]"
local bind_addr = core.setting_get("bind_address")
if bind_addr ~= nil and bind_addr ~= "" then
retval = retval ..
"field[0.8,5.2;2.25,0.5;te_serveraddr;".. fgettext("Bind Address") .. ";" ..
core.setting_get("bind_address") .."]" ..
"field[3.05,5.2;1.25,0.5;te_serverport;".. fgettext("Port") .. ";" ..
core.setting_get("port") .."]"
"field[0.55,5.2;2.25,0.5;te_serveraddr;" .. fgettext("Bind Address") .. ";" ..
core.formspec_escape(core.setting_get("bind_address")) .. "]" ..
"field[2.8,5.2;1.25,0.5;te_serverport;" .. fgettext("Port") .. ";" ..
core.formspec_escape(core.setting_get("port")) .. "]"
else
retval = retval ..
"field[0.8,5.2;3.5,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
core.setting_get("port") .."]"
"field[0.55,5.2;3.5,0.5;te_serverport;" .. fgettext("Server Port") .. ";" ..
core.formspec_escape(core.setting_get("port")) .. "]"
end
retval = retval ..
@ -67,6 +67,9 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["srv_worlds"] ~= nil then
local event = core.explode_textlist_event(fields["srv_worlds"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt_legacy(selected)
if event.type == "DCL" then
world_doubleclick = true
@ -84,16 +87,25 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["cb_creative_mode"] then
core.setting_set("creative_mode", fields["cb_creative_mode"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"])
return true
end
if fields["cb_enable_damage"] then
core.setting_set("enable_damage", fields["cb_enable_damage"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"])
return true
end
if fields["cb_server_announce"] then
core.setting_set("server_announce", fields["cb_server_announce"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt(selected, "server_announce", fields["cb_server_announce"])
return true
end
@ -101,12 +113,12 @@ local function main_button_handler(this, fields, name, tabdata)
world_doubleclick or
fields["key_enter"] then
local selected = core.get_textlist_index("srv_worlds")
if selected ~= nil then
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
if selected ~= nil and gamedata.selected_world ~= 0 then
gamedata.playername = fields["te_playername"]
gamedata.password = fields["te_passwd"]
gamedata.port = fields["te_serverport"]
gamedata.address = ""
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
core.setting_set("port",gamedata.port)
if fields["te_serveraddr"] ~= nil then
@ -115,12 +127,17 @@ local function main_button_handler(this, fields, name, tabdata)
--update last game
local world = menudata.worldlist:get_raw_element(gamedata.selected_world)
if world then
local game, index = gamemgr.find_by_gameid(world.gameid)
core.setting_set("menu_last_game", game.id)
end
local game,index = gamemgr.find_by_gameid(world.gameid)
core.setting_set("menu_last_game",game.id)
core.start()
return true
else
gamedata.errormessage =
fgettext("No world created or selected!")
end
return true
end
if fields["world_create"] ~= nil then

View File

@ -17,13 +17,108 @@
--------------------------------------------------------------------------------
local leaves_style_labels = {
fgettext("Opaque Leaves"),
fgettext("Simple Leaves"),
fgettext("Fancy Leaves")
}
local leaves_style = {
{leaves_style_labels[1] .. "," .. leaves_style_labels[2] .. "," .. leaves_style_labels[3]},
{"opaque", "simple", "fancy"},
}
local dd_filter_labels = {
fgettext("No Filter"),
fgettext("Bilinear Filter"),
fgettext("Trilinear Filter")
}
local filters = {
{dd_filter_labels[1] .. "," .. dd_filter_labels[2] .. "," .. dd_filter_labels[3]},
{"", "bilinear_filter", "trilinear_filter"},
}
local dd_mipmap_labels = {
fgettext("No Mipmap"),
fgettext("Mipmap"),
fgettext("Mipmap + Aniso. Filter")
}
local mipmap = {
{dd_mipmap_labels[1] .. "," .. dd_mipmap_labels[2] .. "," .. dd_mipmap_labels[3]},
{"", "mip_map", "anisotropic_filter"},
}
local function getLeavesStyleSettingIndex()
local style = core.setting_get("leaves_style")
if (style == leaves_style[2][3]) then
return 3
elseif (style == leaves_style[2][2]) then
return 2
end
return 1
end
local dd_antialiasing_labels = {
fgettext("None"),
fgettext("2x"),
fgettext("4x"),
fgettext("8x"),
}
local antialiasing = {
{dd_antialiasing_labels[1] .. "," .. dd_antialiasing_labels[2] .. "," ..
dd_antialiasing_labels[3] .. "," .. dd_antialiasing_labels[4]},
{"0", "2", "4", "8"}
}
local function getFilterSettingIndex()
if (core.setting_get(filters[2][3]) == "true") then
return 3
end
if (core.setting_get(filters[2][3]) == "false" and core.setting_get(filters[2][2]) == "true") then
return 2
end
return 1
end
local function getMipmapSettingIndex()
if (core.setting_get(mipmap[2][3]) == "true") then
return 3
end
if (core.setting_get(mipmap[2][3]) == "false" and core.setting_get(mipmap[2][2]) == "true") then
return 2
end
return 1
end
local function getAntialiasingSettingIndex()
local antialiasing_setting = core.setting_get("fsaa")
for i = 1, #(antialiasing[2]) do
if antialiasing_setting == antialiasing[2][i] then
return i
end
end
return 1
end
local function antialiasing_fname_to_name(fname)
for i = 1, #(dd_antialiasing_labels) do
if fname == dd_antialiasing_labels[i] then
return antialiasing[2][i]
end
end
return 0
end
local function dlg_confirm_reset_formspec(data)
local retval =
"size[8,3]" ..
"label[1,1;".. fgettext("Are you sure to reset your singleplayer world?") .. "]"..
"button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;"..
"label[1,1;" .. fgettext("Are you sure to reset your singleplayer world?") .. "]" ..
"button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;" ..
fgettext("Yes") .. "]" ..
"button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;"..
"button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;" ..
fgettext("No!!!") .. "]"
return retval
end
@ -34,7 +129,7 @@ local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
local worldlist = core.get_worlds()
local found_singleplayerworld = false
for i=1,#worldlist,1 do
for i = 1, #worldlist, 1 do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
@ -51,7 +146,7 @@ local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
found_singleplayerworld = false
for i=1,#worldlist,1 do
for i = 1, #worldlist, 1 do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
@ -76,17 +171,14 @@ local function showconfirm_reset(tabview)
end
local function gui_scale_to_scrollbar()
local current_value = tonumber(core.setting_get("gui_scaling"))
if (current_value == nil) or current_value < 0.25 then
return 0
end
if current_value <= 1.25 then
return ((current_value - 0.25)/ 1.0) * 700
end
if current_value <= 6 then
return ((current_value -1.25) * 100) + 700
end
@ -95,14 +187,12 @@ local function gui_scale_to_scrollbar()
end
local function scrollbar_to_gui_scale(value)
value = tonumber(value)
if (value <= 700) then
return ((value / 700) * 1.0) + 0.25
end
if (value <=1000) then
if (value <= 1000) then
return ((value - 700) / 100) + 1.25
end
@ -110,122 +200,98 @@ local function scrollbar_to_gui_scale(value)
end
local function formspec(tabview, name, tabdata)
local video_drivers = core.get_video_drivers()
local video_driver_string = ""
local current_video_driver_idx = 0
local current_video_driver = core.setting_get("video_driver")
for i=1, #video_drivers, 1 do
if i ~= 1 then
video_driver_string = video_driver_string .. ","
end
video_driver_string = video_driver_string .. video_drivers[i]
local video_driver = string.gsub(video_drivers[i], " ", "")
if current_video_driver:lower() == video_driver:lower() then
current_video_driver_idx = i
end
end
local tab_string =
"vertlabel[0,-0.25;" .. fgettext("SETTINGS") .. "]" ..
"box[0.75,0;3.25,4;#999999]" ..
"checkbox[1,0;cb_smooth_lighting;".. fgettext("Smooth Lighting")
.. ";".. dump(core.setting_getbool("smooth_lighting")) .. "]"..
"checkbox[1,0.5;cb_particles;".. fgettext("Enable Particles") .. ";"
.. dump(core.setting_getbool("enable_particles")) .. "]"..
"checkbox[1,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
.. dump(core.setting_getbool("enable_3d_clouds")) .. "]"..
"checkbox[1,1.5;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";"
.. dump(core.setting_getbool("new_style_leaves")) .. "]"..
"checkbox[1,2.0;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
.. dump(core.setting_getbool("opaque_water")) .. "]"..
"checkbox[1,2.5;cb_connected_glass;".. fgettext("Connected Glass") .. ";"
.. dump(core.setting_getbool("connected_glass")) .. "]"..
"dropdown[1,3.25;3;dd_video_driver;"
.. video_driver_string .. ";" .. current_video_driver_idx .. "]" ..
"tooltip[dd_video_driver;" ..
fgettext("Restart minetest for driver change to take effect") .. "]" ..
"box[4.25,0;3.25,2.5;#999999]" ..
"checkbox[4.5,0;cb_mipmapping;".. fgettext("Mip-Mapping") .. ";"
.. dump(core.setting_getbool("mip_map")) .. "]"..
"checkbox[4.5,0.5;cb_anisotrophic;".. fgettext("Anisotropic Filtering") .. ";"
.. dump(core.setting_getbool("anisotropic_filter")) .. "]"..
"checkbox[4.5,1.0;cb_bilinear;".. fgettext("Bi-Linear Filtering") .. ";"
.. dump(core.setting_getbool("bilinear_filter")) .. "]"..
"checkbox[4.5,1.5;cb_trilinear;".. fgettext("Tri-Linear Filtering") .. ";"
.. dump(core.setting_getbool("trilinear_filter")) .. "]"..
"box[0,0;3.5,4.3;#999999]" ..
"checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting")
.. ";" .. dump(core.setting_getbool("smooth_lighting")) .. "]" ..
"checkbox[0.25,0.5;cb_particles;" .. fgettext("Enable Particles") .. ";"
.. dump(core.setting_getbool("enable_particles")) .. "]" ..
"checkbox[0.25,1;cb_3d_clouds;" .. fgettext("3D Clouds") .. ";"
.. dump(core.setting_getbool("enable_3d_clouds")) .. "]" ..
"checkbox[0.25,1.5;cb_opaque_water;" .. fgettext("Opaque Water") .. ";"
.. dump(core.setting_getbool("opaque_water")) .. "]" ..
"checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";"
.. dump(core.setting_getbool("connected_glass")) .. "]" ..
"checkbox[0.25,2.5;cb_node_highlighting;" .. fgettext("Node Highlighting") .. ";"
.. dump(core.setting_getbool("enable_node_highlighting")) .. "]" ..
"dropdown[0.25,3.4;3.3;dd_leaves_style;" .. leaves_style[1][1] .. ";"
.. getLeavesStyleSettingIndex() .. "]" ..
"box[3.75,0;3.75,3.45;#999999]" ..
"label[3.85,0.1;" .. fgettext("Texturing:") .. "]" ..
"dropdown[3.85,0.55;3.85;dd_filters;" .. filters[1][1] .. ";"
.. getFilterSettingIndex() .. "]" ..
"dropdown[3.85,1.35;3.85;dd_mipmap;" .. mipmap[1][1] .. ";"
.. getMipmapSettingIndex() .. "]" ..
"label[3.85,2.15;" .. fgettext("Antialiasing:") .. "]" ..
"dropdown[3.85,2.6;3.85;dd_antialiasing;" .. antialiasing[1][1] .. ";"
.. getAntialiasingSettingIndex() .. "]" ..
"box[7.75,0;4,4;#999999]" ..
"checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
"checkbox[8,0;cb_shaders;" .. fgettext("Shaders") .. ";"
.. dump(core.setting_getbool("enable_shaders")) .. "]"
if not ANDROID then
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
else
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_reset_singleplayer;".. fgettext("Reset singleplayer world") .. "]"
end
tab_string = tab_string ..
"box[0.75,4.25;3.25,1.25;#999999]" ..
"label[1,4.25;" .. fgettext("GUI scale factor") .. "]" ..
"scrollbar[1,4.75;2.75,0.4;sb_gui_scaling;horizontal;" ..
gui_scale_to_scrollbar() .. "]" ..
"tooltip[sb_gui_scaling;" ..
fgettext("Scaling factor applied to menu elements: ") ..
dump(core.setting_get("gui_scaling")) .. "]"
if ANDROID then
tab_string = tab_string ..
"box[4.25,2.75;3.25,2.15;#999999]" ..
"checkbox[4.5,2.75;cb_touchscreen_target;".. fgettext("Touch free target") .. ";"
.. dump(core.setting_getbool("touchtarget")) .. "]"
end
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_change_keys;" .. fgettext("Change keys") .. "]" ..
"button[0,4.75;3.75,0.5;btn_advanced_settings;" .. fgettext("Advanced Settings") .. "]"
if core.setting_get("touchscreen_threshold") ~= nil then
tab_string = tab_string ..
"label[4.5,3.5;" .. fgettext("Touchthreshold (px)") .. "]" ..
"dropdown[4.5,4;3;dd_touchthreshold;0,10,20,30,40,50;" ..
"label[4.3,4.1;" .. fgettext("Touchthreshold (px)") .. "]" ..
"dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;" ..
((tonumber(core.setting_get("touchscreen_threshold"))/10)+1) .. "]"
end
if core.setting_getbool("enable_shaders") then
tab_string = tab_string ..
"checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
.. dump(core.setting_getbool("enable_bumpmapping")) .. "]"..
"checkbox[8,1.0;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";"
.. dump(core.setting_getbool("generate_normalmaps")) .. "]"..
"checkbox[8,1.5;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
.. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]"..
"checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";"
.. dump(core.setting_getbool("enable_waving_water")) .. "]"..
"checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
.. dump(core.setting_getbool("enable_waving_leaves")) .. "]"..
"checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
"checkbox[8,0.5;cb_bumpmapping;" .. fgettext("Bumpmapping") .. ";"
.. dump(core.setting_getbool("enable_bumpmapping")) .. "]" ..
"checkbox[8,1.0;cb_generate_normalmaps;" .. fgettext("Generate Normalmaps") .. ";"
.. dump(core.setting_getbool("generate_normalmaps")) .. "]" ..
"checkbox[8,1.5;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
.. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]" ..
"checkbox[8,2.0;cb_waving_water;" .. fgettext("Waving Water") .. ";"
.. dump(core.setting_getbool("enable_waving_water")) .. "]" ..
"checkbox[8,2.5;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
.. dump(core.setting_getbool("enable_waving_leaves")) .. "]" ..
"checkbox[8,3.0;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
.. dump(core.setting_getbool("enable_waving_plants")) .. "]"
else
tab_string = tab_string ..
"textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
"textlist[8.33,1.2;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" ..
"textlist[8.33,1.7;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
"textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
"textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
"textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
end
"tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[8.33,0.7;3.5,4;shaders;" ..
"#888888," .. fgettext("Bumpmapping") .. "," ..
"#888888," .. fgettext("Generate Normalmaps") .. "," ..
"#888888," .. fgettext("Parallax Occlusion") .. "," ..
"#888888," .. fgettext("Waving Water") .. "," ..
"#888888," .. fgettext("Waving Leaves") .. "," ..
"#888888," .. fgettext("Waving Plants") .. "," ..
";1]"
end
return tab_string
end
--------------------------------------------------------------------------------
local function handle_settings_buttons(this, fields, tabname, tabdata)
if fields["cb_fancy_trees"] then
core.setting_set("new_style_leaves", fields["cb_fancy_trees"])
if fields["btn_advanced_settings"] ~= nil then
local adv_settings_dlg = create_adv_settings_dlg()
adv_settings_dlg:set_parent(this)
this:hide()
adv_settings_dlg:show()
--mm_texture.update("singleplayer", current_game())
return true
end
if fields["cb_smooth_lighting"] then
core.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
return true
end
if fields["cb_particles"] then
core.setting_set("enable_particles", fields["cb_particles"])
return true
end
if fields["cb_3d_clouds"] then
core.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
return true
@ -234,24 +300,17 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.setting_set("opaque_water", fields["cb_opaque_water"])
return true
end
if fields["cb_mipmapping"] then
core.setting_set("mip_map", fields["cb_mipmapping"])
if fields["cb_connected_glass"] then
core.setting_set("connected_glass", fields["cb_connected_glass"])
return true
end
if fields["cb_anisotrophic"] then
core.setting_set("anisotropic_filter", fields["cb_anisotrophic"])
return true
end
if fields["cb_bilinear"] then
core.setting_set("bilinear_filter", fields["cb_bilinear"])
return true
end
if fields["cb_trilinear"] then
core.setting_set("trilinear_filter", fields["cb_trilinear"])
if fields["cb_node_highlighting"] then
core.setting_set("enable_node_highlighting", fields["cb_node_highlighting"])
return true
end
if fields["cb_shaders"] then
if (core.setting_get("video_driver") == "direct3d8" or core.setting_get("video_driver") == "direct3d9") then
if (core.setting_get("video_driver") == "direct3d8"
or core.setting_get("video_driver") == "direct3d9") then
core.setting_set("enable_shaders", "false")
gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
else
@ -259,14 +318,6 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
end
return true
end
if fields["cb_connected_glass"] then
core.setting_set("connected_glass", fields["cb_connected_glass"])
return true
end
if fields["cb_particles"] then
core.setting_set("enable_particles", fields["cb_particles"])
return true
end
if fields["cb_bumpmapping"] then
core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
end
@ -288,20 +339,21 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.setting_set("enable_waving_plants", fields["cb_waving_plants"])
return true
end
if fields["btn_change_keys"] ~= nil then
core.show_keys_menu()
return true
end
if fields["sb_gui_scaling"] then
local event = core.explode_scrollbar_event(fields["sb_gui_scaling"])
if event.type == "CHG" then
local tosave = string.format("%.2f",scrollbar_to_gui_scale(event.value))
core.setting_set("gui_scaling",tosave)
core.setting_set("gui_scaling", tosave)
return true
end
end
if fields["btn_change_keys"] then
core.show_keys_menu()
return true
end
if fields["cb_touchscreen_target"] then
core.setting_set("touchtarget", fields["cb_touchscreen_target"])
return true
@ -313,16 +365,53 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
--Note dropdowns have to be handled LAST!
local ddhandled = false
if fields["dd_leaves_style"] == leaves_style_labels[1] then
core.setting_set("leaves_style", leaves_style[2][1])
ddhandled = true
elseif fields["dd_leaves_style"] == leaves_style_labels[2] then
core.setting_set("leaves_style", leaves_style[2][2])
ddhandled = true
elseif fields["dd_leaves_style"] == leaves_style_labels[3] then
core.setting_set("leaves_style", leaves_style[2][3])
ddhandled = true
end
if fields["dd_filters"] == dd_filter_labels[1] then
core.setting_set("bilinear_filter", "false")
core.setting_set("trilinear_filter", "false")
ddhandled = true
elseif fields["dd_filters"] == dd_filter_labels[2] then
core.setting_set("bilinear_filter", "true")
core.setting_set("trilinear_filter", "false")
ddhandled = true
elseif fields["dd_filters"] == dd_filter_labels[3] then
core.setting_set("bilinear_filter", "false")
core.setting_set("trilinear_filter", "true")
ddhandled = true
end
if fields["dd_mipmap"] == dd_mipmap_labels[1] then
core.setting_set("mip_map", "false")
core.setting_set("anisotropic_filter", "false")
ddhandled = true
elseif fields["dd_mipmap"] == dd_mipmap_labels[2] then
core.setting_set("mip_map", "true")
core.setting_set("anisotropic_filter", "false")
ddhandled = true
elseif fields["dd_mipmap"] == dd_mipmap_labels[3] then
core.setting_set("mip_map", "true")
core.setting_set("anisotropic_filter", "true")
ddhandled = true
end
if fields["dd_antialiasing"] then
core.setting_set("fsaa",
antialiasing_fname_to_name(fields["dd_antialiasing"]))
ddhandled = true
end
if fields["dd_touchthreshold"] then
core.setting_set("touchscreen_threshold",fields["dd_touchthreshold"])
ddhandled = true
end
if fields["dd_video_driver"] then
local video_driver = string.gsub(fields["dd_video_driver"], " ", "")
core.setting_set("video_driver",string.lower(video_driver))
ddhandled = true
end
return ddhandled
end
@ -331,4 +420,4 @@ tab_settings = {
caption = fgettext("Settings"),
cbf_formspec = formspec,
cbf_button_handler = handle_settings_buttons
}
}

View File

@ -23,19 +23,35 @@ local function get_formspec(tabview, name, tabdata)
retval = retval ..
"label[8,0.5;".. fgettext("Name/Password") .. "]" ..
"field[0.25,3.25;5.5,0.5;te_address;;" ..core.setting_get("address") .."]" ..
"field[5.75,3.25;2.25,0.5;te_port;;" ..core.setting_get("remote_port") .."]" ..
"field[0.25,3.25;5.5,0.5;te_address;;" ..
core.formspec_escape(core.setting_get("address")) .."]" ..
"field[5.75,3.25;2.25,0.5;te_port;;" ..
core.formspec_escape(core.setting_get("remote_port")) .."]" ..
"checkbox[8,-0.25;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
render_details .. "]"
retval = retval ..
"button[8,2.5;4,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
"field[8.75,1.5;3.5,0.5;te_name;;" ..core.setting_get("name") .."]" ..
"field[8.75,1.5;3.5,0.5;te_name;;" ..
core.formspec_escape(core.setting_get("name")) .."]" ..
"pwdfield[8.75,2.3;3.5,0.5;te_pwd;]"
--favourites
if render_details then
retval = retval .. "tablecolumns[" ..
"color,span=3;" ..
"text,align=right;" .. -- clients
"text,align=center,padding=0.25;" .. -- "/"
"text,align=right,padding=0.25;" .. -- clients_max
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" -- name
else
retval = retval .. "tablecolumns[text]"
end
retval = retval ..
"textlist[-0.05,0.0;7.55,2.75;favourites;"
"table[-0.05,0;7.55,2.75;favourites;"
if #menudata.favorites > 0 then
retval = retval .. render_favorite(menudata.favorites[1],render_details)
@ -53,26 +69,23 @@ local function get_formspec(tabview, name, tabdata)
-- separator
retval = retval ..
"box[-0.3,3.75;12.4,0.1;#FFFFFF]"
"box[-0.28,3.75;12.4,0.1;#FFFFFF]"
-- checkboxes
retval = retval ..
"checkbox[1.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" ..
"checkbox[8.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" ..
dump(core.setting_getbool("creative_mode")) .. "]"..
"checkbox[5.0,3.9;cb_damage;".. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]" ..
"checkbox[8,3.9;cb_fly_mode;".. fgettext("Fly mode") .. ";" ..
dump(core.setting_getbool("free_move")) .. "]"
"checkbox[8.0,4.4;cb_damage;".. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]"
-- buttons
retval = retval ..
"button[2.0,4.5;6,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" ..
"button[8.25,4.5;2.5,1.5;btn_config_sp_world;" .. fgettext("Config mods") .. "]"
"button[0,3.7;8,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" ..
"button[0,4.5;8,1.5;btn_config_sp_world;" .. fgettext("Config mods") .. "]"
return retval
end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
if fields["btn_start_singleplayer"] then
@ -83,12 +96,12 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
if fields["favourites"] ~= nil then
local event = core.explode_textlist_event(fields["favourites"])
local event = core.explode_table_event(fields["favourites"])
if event.type == "CHG" then
if event.index <= #menudata.favorites then
local address = menudata.favorites[event.index].address
local port = menudata.favorites[event.index].port
if event.row <= #menudata.favorites then
local address = menudata.favorites[event.row].address
local port = menudata.favorites[event.row].port
if address ~= nil and
port ~= nil then
@ -96,7 +109,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
core.setting_set("remote_port",port)
end
tabdata.fav_selected = event.index
tabdata.fav_selected = event.row
end
end
return true
@ -123,11 +136,6 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
if fields["cb_fly_mode"] then
core.setting_set("free_move", fields["cb_fly_mode"])
return true
end
if fields["btn_mp_connect"] ~= nil or
fields["key_enter"] ~= nil then
@ -144,6 +152,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.servername = menudata.favorites[fav_idx].name
gamedata.serverdescription = menudata.favorites[fav_idx].description
if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
menudata.favorites[fav_idx].proto_max) then
return true
end
else
gamedata.servername = ""
gamedata.serverdescription = ""

View File

@ -23,9 +23,9 @@ local function current_game()
end
local function singleplayer_refresh_gamebar()
local old_bar = ui.find_by_name("game_button_bar")
if old_bar ~= nil then
old_bar:delete()
end
@ -38,6 +38,17 @@ local function singleplayer_refresh_gamebar()
core.set_topleft_text(gamemgr.games[j].name)
core.setting_set("menu_last_game",gamemgr.games[j].id)
menudata.worldlist:set_filtercriteria(gamemgr.games[j].id)
local index = filterlist.get_current_index(menudata.worldlist,
tonumber(core.setting_get("mainmenu_last_selected_world")))
if not index or index < 1 then
local selected = core.get_textlist_index("sp_worlds")
if selected ~= nil and selected < #menudata.worldlist:get_list() then
index = selected
else
index = #menudata.worldlist:get_list()
end
end
menu_worldmt_legacy(index)
return true
end
end
@ -53,6 +64,7 @@ local function singleplayer_refresh_gamebar()
local image = nil
local text = nil
local tooltip = core.formspec_escape(gamemgr.games[i].name)
if gamemgr.games[i].menuicon_path ~= nil and
gamemgr.games[i].menuicon_path ~= "" then
@ -69,13 +81,13 @@ local function singleplayer_refresh_gamebar()
text = text .. "\n" .. part3
end
end
btnbar:add_button(btn_name, text, image)
btnbar:add_button(btn_name, text, image, tooltip)
end
end
local function get_formspec(tabview, name, tabdata)
local retval = ""
local index = filterlist.get_current_index(menudata.worldlist,
tonumber(core.setting_get("mainmenu_last_selected_world"))
)
@ -86,10 +98,9 @@ local function get_formspec(tabview, name, tabdata)
"button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
"button[8.5,4.95;3.25,0.5;play;".. fgettext("Play") .. "]" ..
"label[4,-0.25;".. fgettext("Select World:") .. "]"..
"vertlabel[0,-0.25;".. fgettext("SINGLE PLAYER") .. "]" ..
"checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
"checkbox[0.25,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
dump(core.setting_getbool("creative_mode")) .. "]"..
"checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
"checkbox[0.25,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]"..
"textlist[4,0.25;7.5,3.7;sp_worlds;" ..
menu_render_worldlist() ..
@ -105,14 +116,17 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["sp_worlds"] ~= nil then
local event = core.explode_textlist_event(fields["sp_worlds"])
local selected = core.get_textlist_index("sp_worlds")
menu_worldmt_legacy(selected)
if event.type == "DCL" then
world_doubleclick = true
end
if event.type == "CHG" then
if event.type == "CHG" and selected ~= nil then
core.setting_set("mainmenu_last_selected_world",
menudata.worldlist:get_raw_index(core.get_textlist_index("sp_worlds")))
menudata.worldlist:get_raw_index(selected))
return true
end
end
@ -123,11 +137,17 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["cb_creative_mode"] then
core.setting_set("creative_mode", fields["cb_creative_mode"])
local selected = core.get_textlist_index("sp_worlds")
menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"])
return true
end
if fields["cb_enable_damage"] then
core.setting_set("enable_damage", fields["cb_enable_damage"])
local selected = core.get_textlist_index("sp_worlds")
menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"])
return true
end
@ -135,12 +155,14 @@ local function main_button_handler(this, fields, name, tabdata)
world_doubleclick or
fields["key_enter"] then
local selected = core.get_textlist_index("sp_worlds")
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
if selected ~= nil then
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
gamedata.singleplayer = true
if selected ~= nil and gamedata.selected_world ~= 0 then
gamedata.singleplayer = true
core.start()
else
gamedata.errormessage =
fgettext("No world created or selected!")
end
return true
end

View File

@ -17,12 +17,16 @@
--------------------------------------------------------------------------------
local function filter_texture_pack_list(list)
retval = {"None"}
for _,i in ipairs(list) do
if i~="base" then
table.insert(retval, i)
local retval = {}
for _, item in ipairs(list) do
if item ~= "base" then
table.insert(retval, item)
end
end
table.sort(retval)
table.insert(retval, 1, fgettext("None"))
return retval
end
@ -31,11 +35,13 @@ local function render_texture_pack_list(list)
local retval = ""
for i, v in ipairs(list) do
if retval ~= "" then
retval = retval ..","
end
if v:sub(1,1) ~= "." then
if retval ~= "" then
retval = retval ..","
end
retval = retval .. core.formspec_escape(v)
retval = retval .. core.formspec_escape(v)
end
end
return retval
@ -43,13 +49,12 @@ end
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
"vertlabel[0,-0.25;".. fgettext("TEXTURE PACKS") .. "]" ..
"textlist[4,0.25;7.5,5.0;TPs;"
local current_texture_path = core.setting_get("texture_path")
local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true))
local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true))
local index = tonumber(core.setting_get("mainmenu_last_selected_TP"))
if index == nil then index = 1 end
@ -61,10 +66,18 @@ local function get_formspec(tabview, name, tabdata)
return retval
end
local infofile = current_texture_path ..DIR_DELIM.."info.txt"
local infofile = current_texture_path ..DIR_DELIM.."description.txt"
-- This adds backwards compatibility for old texture pack description files named
-- "info.txt", and should be removed once all such texture packs have been updated
if not file_exists(infofile) then
infofile = current_texture_path ..DIR_DELIM.."info.txt"
if file_exists(infofile) then
core.log("info.txt is depreciated. description.txt should be used instead.");
end
end
local infotext = ""
local f = io.open(infofile, "r")
if f==nil then
if not f then
infotext = fgettext("No information available")
else
infotext = f:read("*all")
@ -81,8 +94,8 @@ local function get_formspec(tabview, name, tabdata)
return retval ..
render_texture_pack_list(list) ..
";" .. index .. "]" ..
"image[0.65,0.25;4.0,3.7;"..core.formspec_escape(screenfile or no_screenshot).."]"..
"textarea[1.0,3.25;3.7,1.5;;"..core.formspec_escape(infotext or "")..";]"
"image[0.25,0.25;4.0,3.7;"..core.formspec_escape(screenfile or no_screenshot).."]"..
"textarea[0.6,3.25;3.7,1.5;;"..core.formspec_escape(infotext or "")..";]"
end
--------------------------------------------------------------------------------
@ -93,11 +106,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
local index = core.get_textlist_index("TPs")
core.setting_set("mainmenu_last_selected_TP",
index)
local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true))
local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true))
local current_index = core.get_textlist_index("TPs")
if current_index ~= nil and #list >= current_index then
local new_path = core.get_texturepath()..DIR_DELIM..list[current_index]
if list[current_index] == "None" then new_path = "" end
if list[current_index] == fgettext("None") then new_path = "" end
core.setting_set("texture_path", new_path)
end

View File

@ -129,7 +129,7 @@ function mm_texture.set_generic(identifier)
end
--------------------------------------------------------------------------------
function mm_texture.set_game(identifier,gamedetails)
function mm_texture.set_game(identifier, gamedetails)
if gamedetails == nil then
return false
@ -137,15 +137,34 @@ function mm_texture.set_game(identifier,gamedetails)
if mm_texture.texturepack ~= nil then
local path = mm_texture.texturepack .. DIR_DELIM ..
gamedetails.id .. "_menu_" .. identifier .. ".png"
if core.set_background(identifier,path) then
gamedetails.id .. "_menu_" .. identifier .. ".png"
if core.set_background(identifier, path) then
return true
end
end
local path = gamedetails.path .. DIR_DELIM .."menu" ..
DIR_DELIM .. identifier .. ".png"
if core.set_background(identifier,path) then
-- Find out how many randomized textures the subgame provides
local n = 0
local filename
local menu_files = core.get_dir_list(gamedetails.path .. DIR_DELIM .. "menu", false)
for i = 1, #menu_files do
filename = identifier .. "." .. i .. ".png"
if table.indexof(menu_files, filename) == -1 then
n = i - 1
break
end
end
-- Select random texture, 0 means standard texture
n = math.random(0, n)
if n == 0 then
filename = identifier .. ".png"
else
filename = identifier .. "." .. n .. ".png"
end
local path = gamedetails.path .. DIR_DELIM .. "menu" ..
DIR_DELIM .. filename
if core.set_background(identifier, path) then
return true
end

1159
builtin/settingtypes.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
void main(void)
{
gl_FragColor = gl_Color;
}

View File

@ -0,0 +1,9 @@
uniform mat4 mWorldViewProj;
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = mWorldViewProj * gl_Vertex;
gl_FrontColor = gl_BackColor = gl_Color;
}

View File

@ -0,0 +1,32 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform vec3 yawVec;
void main (void)
{
vec2 uv = gl_TexCoord[0].st;
//texture sampling rate
const float step = 1.0 / 256.0;
float tl = texture2D(normalTexture, vec2(uv.x - step, uv.y + step)).r;
float t = texture2D(normalTexture, vec2(uv.x - step, uv.y - step)).r;
float tr = texture2D(normalTexture, vec2(uv.x + step, uv.y + step)).r;
float r = texture2D(normalTexture, vec2(uv.x + step, uv.y)).r;
float br = texture2D(normalTexture, vec2(uv.x + step, uv.y - step)).r;
float b = texture2D(normalTexture, vec2(uv.x, uv.y - step)).r;
float bl = texture2D(normalTexture, vec2(uv.x - step, uv.y - step)).r;
float l = texture2D(normalTexture, vec2(uv.x - step, uv.y)).r;
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
vec4 bump = vec4 (normalize(vec3 (dX, dY, 0.1)),1.0);
float height = 2.0 * texture2D(normalTexture, vec2(uv.x, uv.y)).r - 1.0;
vec4 base = texture2D(baseTexture, uv).rgba;
vec3 L = normalize(vec3(0.0, 0.75, 1.0));
float specular = pow(clamp(dot(reflect(L, bump.xyz), yawVec), 0.0, 1.0), 1.0);
float diffuse = dot(yawVec, bump.xyz);
vec3 color = (1.1 * diffuse + 0.05 * height + 0.5 * specular) * base.rgb;
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
gl_FragColor = vec4(col.rgb, base.a);
}

View File

@ -0,0 +1,11 @@
uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform mat4 mWorld;
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = mWorldViewProj * gl_Vertex;
gl_FrontColor = gl_BackColor = gl_Color;
}

View File

@ -1,6 +1,6 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform sampler2D useNormalmap;
uniform sampler2D textureFlags;
uniform vec4 skyBgColor;
uniform float fogDistance;
@ -8,86 +8,183 @@ uniform vec3 eyePosition;
varying vec3 vPosition;
varying vec3 worldPosition;
varying float area_enable_parallax;
varying vec3 eyeVec;
varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
bool normalTexturePresent = false;
bool normalTexturePresent = false;
const float e = 2.718281828459;
const float BS = 10.0;
float intensity (vec3 color){
#ifdef ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters
A = 0.22;
B = 0.30;
C = 0.10;
D = 0.20;
E = 0.01;
F = 0.30;
W = 11.2;
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
*/
vec3 uncharted2Tonemap(vec3 x)
{
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03334;
}
vec4 applyToneMapping(vec4 color)
{
color = vec4(pow(color.rgb, vec3(2.2)), color.a);
const float gamma = 1.6;
const float exposureBias = 5.5;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale;
return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
}
#endif
void get_texture_flags()
{
vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
if (flags.r > 0.5) {
normalTexturePresent = true;
}
}
float intensity(vec3 color)
{
return (color.r + color.g + color.b) / 3.0;
}
float get_rgb_height (vec2 uv){
return intensity(texture2D(baseTexture,uv).rgb);
float get_rgb_height(vec2 uv)
{
return intensity(texture2D(baseTexture, uv).rgb);
}
vec4 get_normal_map(vec2 uv){
vec4 get_normal_map(vec2 uv)
{
vec4 bump = texture2D(normalTexture, uv).rgba;
bump.xyz = normalize(bump.xyz * 2.0 -1.0);
bump.y = -bump.y;
bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
return bump;
}
void main (void)
float find_intersection(vec2 dp, vec2 ds)
{
float depth = 1.0;
float best_depth = 0.0;
float size = 0.0625;
for (int i = 0; i < 15; i++) {
depth -= size;
float h = texture2D(normalTexture, dp + ds * depth).a;
if (depth <= h) {
best_depth = depth;
break;
}
}
depth = best_depth;
for (int i = 0; i < 4; i++) {
size *= 0.5;
float h = texture2D(normalTexture,dp + ds * depth).a;
if (depth <= h) {
best_depth = depth;
depth += size;
} else {
depth -= size;
}
}
return best_depth;
}
float find_intersectionRGB(vec2 dp, vec2 ds)
{
const float depth_step = 1.0 / 24.0;
float depth = 1.0;
for (int i = 0 ; i < 24 ; i++) {
float h = get_rgb_height(dp + ds * depth);
if (h >= depth)
break;
depth -= depth_step;
}
return depth;
}
void main(void)
{
vec3 color;
vec4 bump;
vec2 uv = gl_TexCoord[0].st;
bool use_normalmap = false;
#ifdef USE_NORMALMAPS
if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){
normalTexturePresent = true;
}
#endif
get_texture_flags();
#ifdef ENABLE_PARALLAX_OCCLUSION
if (normalTexturePresent){
vec3 tsEye = normalize(tsEyeVec);
float height = PARALLAX_OCCLUSION_SCALE * texture2D(normalTexture, uv).a - PARALLAX_OCCLUSION_BIAS;
uv = uv + texture2D(normalTexture, uv).z * height * vec2(tsEye.x,-tsEye.y);
vec2 eyeRay = vec2 (tsEyeVec.x, -tsEyeVec.y);
const float scale = PARALLAX_OCCLUSION_SCALE / PARALLAX_OCCLUSION_ITERATIONS;
const float bias = PARALLAX_OCCLUSION_BIAS / PARALLAX_OCCLUSION_ITERATIONS;
#if PARALLAX_OCCLUSION_MODE == 0
// Parallax occlusion with slope information
if (normalTexturePresent && area_enable_parallax > 0.0) {
for (int i = 0; i < PARALLAX_OCCLUSION_ITERATIONS; i++) {
vec4 normal = texture2D(normalTexture, uv.xy);
float h = normal.a * scale - bias;
uv += h * normal.z * eyeRay;
}
#endif
#if PARALLAX_OCCLUSION_MODE == 1
// Relief mapping
if (normalTexturePresent && area_enable_parallax > 0.0) {
vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE;
float dist = find_intersection(uv, ds);
uv += dist * ds;
#endif
} else if (GENERATE_NORMALMAPS == 1 && area_enable_parallax > 0.0) {
vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE;
float dist = find_intersectionRGB(uv, ds);
uv += dist * ds;
}
#endif
#ifdef USE_NORMALMAPS
if (normalTexturePresent){
#if USE_NORMALMAPS == 1
if (normalTexturePresent) {
bump = get_normal_map(uv);
use_normalmap = true;
}
#endif
#ifdef GENERATE_NORMALMAPS
if (use_normalmap == false){
float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP));
float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP));
float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP));
float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y));
float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP));
float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP));
float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP));
float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y));
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0);
use_normalmap = true;
}
#endif
vec4 base = texture2D(baseTexture, uv).rgba;
if (GENERATE_NORMALMAPS == 1 && normalTexturePresent == false) {
float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
use_normalmap = true;
}
vec4 base = texture2D(baseTexture, uv).rgba;
#ifdef ENABLE_BUMPMAPPING
if (use_normalmap){
if (use_normalmap) {
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5);
float diffuse = dot(E,bump.xyz);
color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb;
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
float diffuse = dot(-E,bump.xyz);
color = (diffuse + 0.1 * specular) * base.rgb;
} else {
color = base.rgb;
}
@ -95,22 +192,26 @@ vec4 base = texture2D(baseTexture, uv).rgba;
color = base.rgb;
#endif
#if MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE
vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0);
#if MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT
float alpha = gl_Color.a;
vec4 col = vec4(color.rgb, alpha);
col *= gl_Color;
if(fogDistance != 0.0){
if (fogDistance != 0.0) {
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
alpha = mix(alpha, 0.0, d);
}
gl_FragColor = vec4(col.rgb, alpha);
col = vec4(col.rgb, alpha);
#else
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
if(fogDistance != 0.0){
if (fogDistance != 0.0) {
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
col = mix(col, skyBgColor, d);
}
gl_FragColor = vec4(col.rgb, base.a);
col = vec4(col.rgb, base.a);
#endif
#ifdef ENABLE_TONE_MAPPING
gl_FragColor = applyToneMapping(col);
#else
gl_FragColor = col;
#endif
}

View File

@ -14,88 +14,134 @@ varying vec3 eyeVec;
varying vec3 lightVec;
varying vec3 tsEyeVec;
varying vec3 tsLightVec;
varying float area_enable_parallax;
varying float disp;
const float e = 2.718281828459;
const float BS = 10.0;
float smoothCurve( float x ) {
return x * x *( 3.0 - 2.0 * x );
float smoothCurve(float x)
{
return x * x * (3.0 - 2.0 * x);
}
float triangleWave( float x ) {
return abs( fract( x + 0.5 ) * 2.0 - 1.0 );
float triangleWave(float x)
{
return abs(fract(x + 0.5) * 2.0 - 1.0);
}
float smoothTriangleWave( float x ) {
return smoothCurve( triangleWave( x ) ) * 2.0 - 1.0;
float smoothTriangleWave(float x)
{
return smoothCurve(triangleWave(x)) * 2.0 - 1.0;
}
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER
//TODO: make offset depending on view angle and parallax uv displacement
//thats for textures that doesnt align vertically, like dirt with grass
//gl_TexCoord[0].y += 0.008;
//Allow parallax/relief mapping only for certain kind of nodes
//Variable is also used to control area of the effect
#if (DRAW_TYPE == NDT_NORMAL || DRAW_TYPE == NDT_LIQUID || DRAW_TYPE == NDT_FLOWINGLIQUID)
area_enable_parallax = 1.0;
#else
area_enable_parallax = 0.0;
#endif
#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES) || (MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS)
vec4 pos2 = mWorld * gl_Vertex;
float tOffset = (pos2.x + pos2.y) * 0.001 + pos2.z * 0.002;
disp = (smoothTriangleWave(animationTimer * 31.0 + tOffset) +
smoothTriangleWave(animationTimer * 29.0 + tOffset) +
smoothTriangleWave(animationTimer * 13.0 + tOffset)) - 0.9;
#endif
#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER
vec4 pos = gl_Vertex;
pos.y -= 2.0;
pos.y -= sin (pos.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) * WATER_WAVE_HEIGHT
+ sin ((pos.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) / 7.0) * WATER_WAVE_HEIGHT;
float posYbuf = (pos.z / WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH);
pos.y -= sin(posYbuf) * WATER_WAVE_HEIGHT + sin(posYbuf / 7.0) * WATER_WAVE_HEIGHT;
gl_Position = mWorldViewProj * pos;
#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES
vec4 pos = gl_Vertex;
vec4 pos2 = mWorld * gl_Vertex;
pos.x += (smoothTriangleWave(animationTimer*10.0 + pos2.x * 0.01 + pos2.z * 0.01) * 2.0 - 1.0) * 0.4;
pos.y += (smoothTriangleWave(animationTimer*15.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.2;
pos.z += (smoothTriangleWave(animationTimer*10.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.4;
pos.x += disp * 0.1;
pos.y += disp * 0.1;
pos.z += disp;
gl_Position = mWorldViewProj * pos;
#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS
vec4 pos = gl_Vertex;
vec4 pos2 = mWorld * gl_Vertex;
if (gl_TexCoord[0].y < 0.05) {
pos.x += (smoothTriangleWave(animationTimer * 20.0 + pos2.x * 0.1 + pos2.z * 0.1) * 2.0 - 1.0) * 0.8;
pos.y -= (smoothTriangleWave(animationTimer * 10.0 + pos2.x * -0.5 + pos2.z * -0.5) * 2.0 - 1.0) * 0.4;
pos.z += disp;
}
gl_Position = mWorldViewProj * pos;
#else
gl_Position = mWorldViewProj * gl_Vertex;
#endif
vPosition = gl_Position.xyz;
worldPosition = (mWorld * gl_Vertex).xyz;
// Don't generate heightmaps when too far from the eye
float dist = distance (vec3(0.0, 0.0 ,0.0), vPosition);
if (dist > 150.0) {
area_enable_parallax = 0.0;
}
vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0);
vec3 normal, tangent, binormal;
normal = normalize(gl_NormalMatrix * gl_Normal);
if (gl_Normal.x > 0.5) {
// 1.0, 0.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, -1.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
} else if (gl_Normal.x < -0.5) {
// -1.0, 0.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
} else if (gl_Normal.y > 0.5) {
// 0.0, 1.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
} else if (gl_Normal.y < -0.5) {
// 0.0, -1.0, 0.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
} else if (gl_Normal.z > 0.5) {
// 0.0, 0.0, 1.0
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
} else if (gl_Normal.z < -0.5) {
// 0.0, 0.0, -1.0
tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
}
mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x,
tangent.y, binormal.y, normal.y,
tangent.z, binormal.z, normal.z);
tangent = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
binormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
vec3 v;
lightVec = sunPosition - worldPosition;
tsLightVec = lightVec * tbnMatrix;
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
tsEyeVec = eyeVec * tbnMatrix;
v.x = dot(lightVec, tangent);
v.y = dot(lightVec, binormal);
v.z = dot(lightVec, normal);
tsLightVec = normalize (v);
eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz;
v.x = dot(eyeVec, tangent);
v.y = dot(eyeVec, binormal);
v.z = dot(eyeVec, normal);
tsEyeVec = normalize (v);
gl_FrontColor = gl_BackColor = gl_Color;
vec4 color;
float day = gl_Color.r;
float night = gl_Color.g;
float light_source = gl_Color.b;
float rg = mix(night, day, dayNightRatio);
rg += light_source * 2.5; // Make light sources brighter
float b = rg;
// Moonlight is blue
b += (day - night) / 13.0;
rg -= (day - night) / 23.0;
// Emphase blue a bit in darker places
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
// Artificial light is yellow-ish
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
color.r = rg;
color.g = rg;
color.b = b;
color.a = gl_Color.a;
gl_FrontColor = gl_BackColor = clamp(color,0.0,1.0);
}

View File

@ -0,0 +1,9 @@
uniform sampler2D baseTexture;
void main(void)
{
vec2 uv = gl_TexCoord[0].st;
vec4 color = texture2D(baseTexture, uv);
color.rgb *= gl_Color.rgb;
gl_FragColor = color;
}

View File

@ -0,0 +1,9 @@
uniform mat4 mWorldViewProj;
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = mWorldViewProj * gl_Vertex;
gl_FrontColor = gl_BackColor = gl_Color;
}

View File

@ -1,6 +1,6 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform sampler2D useNormalmap;
uniform sampler2D textureFlags;
uniform vec4 skyBgColor;
uniform float fogDistance;
@ -14,41 +14,91 @@ varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
bool normalTexturePresent = false;
bool normalTexturePresent = false;
bool texTileableHorizontal = false;
bool texTileableVertical = false;
bool texSeamless = false;
const float e = 2.718281828459;
const float BS = 10.0;
float intensity (vec3 color){
#ifdef ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters
A = 0.22;
B = 0.30;
C = 0.10;
D = 0.20;
E = 0.01;
F = 0.30;
W = 11.2;
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
*/
vec3 uncharted2Tonemap(vec3 x)
{
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03334;
}
vec4 applyToneMapping(vec4 color)
{
color = vec4(pow(color.rgb, vec3(2.2)), color.a);
const float gamma = 1.6;
const float exposureBias = 5.5;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale;
return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
}
#endif
void get_texture_flags()
{
vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
if (flags.r > 0.5) {
normalTexturePresent = true;
}
if (flags.g > 0.5) {
texTileableHorizontal = true;
}
if (flags.b > 0.5) {
texTileableVertical = true;
}
if (texTileableHorizontal && texTileableVertical) {
texSeamless = true;
}
}
float intensity(vec3 color)
{
return (color.r + color.g + color.b) / 3.0;
}
float get_rgb_height (vec2 uv){
float get_rgb_height(vec2 uv)
{
return intensity(texture2D(baseTexture,uv).rgb);
}
vec4 get_normal_map(vec2 uv){
vec4 get_normal_map(vec2 uv)
{
vec4 bump = texture2D(normalTexture, uv).rgba;
bump.xyz = normalize(bump.xyz * 2.0 -1.0);
bump.y = -bump.y;
return bump;
}
void main (void)
void main(void)
{
vec3 color;
vec4 bump;
vec2 uv = gl_TexCoord[0].st;
bool use_normalmap = false;
#ifdef USE_NORMALMAPS
if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){
normalTexturePresent = true;
}
#endif
get_texture_flags();
#ifdef ENABLE_PARALLAX_OCCLUSION
if (normalTexturePresent){
if (normalTexturePresent) {
vec3 tsEye = normalize(tsEyeVec);
float height = PARALLAX_OCCLUSION_SCALE * texture2D(normalTexture, uv).a - PARALLAX_OCCLUSION_BIAS;
uv = uv + texture2D(normalTexture, uv).z * height * vec2(tsEye.x,-tsEye.y);
@ -56,14 +106,13 @@ void main (void)
#endif
#ifdef USE_NORMALMAPS
if (normalTexturePresent){
if (normalTexturePresent) {
bump = get_normal_map(uv);
use_normalmap = true;
}
#endif
#ifdef GENERATE_NORMALMAPS
if (use_normalmap == false){
if (GENERATE_NORMALMAPS == 1 && use_normalmap == false) {
float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP));
float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP));
float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP));
@ -77,17 +126,21 @@ void main (void)
bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0);
use_normalmap = true;
}
#endif
vec4 base = texture2D(baseTexture, uv).rgba;
#ifdef ENABLE_BUMPMAPPING
if (use_normalmap){
if (use_normalmap) {
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5);
float diffuse = dot(E,bump.xyz);
color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb;
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5);
float diffuse = dot(E,bump.xyz);
/* Mathematic optimization
* Original: color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb;
* This optimization save 2 multiplications (orig: 4 multiplications + 3 additions
* end: 2 multiplications + 3 additions)
*/
color = (0.05 + diffuse + 0.2 * specular) * base.rgb;
} else {
color = base.rgb;
}
@ -95,22 +148,26 @@ vec4 base = texture2D(baseTexture, uv).rgba;
color = base.rgb;
#endif
vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0);
#if MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE
float alpha = gl_Color.a;
vec4 col = vec4(color.rgb, alpha);
col *= gl_Color;
if(fogDistance != 0.0){
if (fogDistance != 0.0) {
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
alpha = mix(alpha, 0.0, d);
}
gl_FragColor = vec4(col.rgb, alpha);
col = vec4(col.rgb, alpha);
#else
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
if(fogDistance != 0.0){
if (fogDistance != 0.0) {
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
col = mix(col, skyBgColor, d);
}
gl_FragColor = vec4(col.rgb, base.a);
col = vec4(col.rgb, base.a);
#endif
#ifdef ENABLE_TONE_MAPPING
gl_FragColor = applyToneMapping(col);
#else
gl_FragColor = col;
#endif
}

View File

@ -18,39 +18,56 @@ varying vec3 tsLightVec;
const float e = 2.718281828459;
const float BS = 10.0;
float smoothCurve( float x ) {
return x * x *( 3.0 - 2.0 * x );
float smoothCurve(float x)
{
return x * x * (3.0 - 2.0 * x);
}
float triangleWave( float x ) {
return abs( fract( x + 0.5 ) * 2.0 - 1.0 );
float triangleWave(float x)
{
return abs(fract( x + 0.5 ) * 2.0 - 1.0);
}
float smoothTriangleWave( float x ) {
return smoothCurve( triangleWave( x ) ) * 2.0 - 1.0;
float smoothTriangleWave(float x)
{
return smoothCurve(triangleWave( x )) * 2.0 - 1.0;
}
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER
vec4 pos = gl_Vertex;
pos.y -= 2.0;
pos.y -= sin (pos.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) * WATER_WAVE_HEIGHT
+ sin ((pos.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) / 7.0) * WATER_WAVE_HEIGHT;
float posYbuf = (pos.z / WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH);
pos.y -= sin(posYbuf) * WATER_WAVE_HEIGHT + sin(posYbuf / 7.0) * WATER_WAVE_HEIGHT;
gl_Position = mWorldViewProj * pos;
#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES
vec4 pos = gl_Vertex;
vec4 pos2 = mWorld * gl_Vertex;
pos.x += (smoothTriangleWave(animationTimer*10.0 + pos2.x * 0.01 + pos2.z * 0.01) * 2.0 - 1.0) * 0.4;
pos.y += (smoothTriangleWave(animationTimer*15.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.2;
pos.z += (smoothTriangleWave(animationTimer*10.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.4;
/*
* Mathematic optimization: pos2.x * A + pos2.z * A (2 multiplications + 1 addition)
* replaced with: (pos2.x + pos2.z) * A (1 addition + 1 multiplication)
* And bufferize calcul to a float
*/
float pos2XpZ = pos2.x + pos2.z;
pos.x += (smoothTriangleWave(animationTimer*10.0 + pos2XpZ * 0.01) * 2.0 - 1.0) * 0.4;
pos.y += (smoothTriangleWave(animationTimer*15.0 + pos2XpZ * -0.01) * 2.0 - 1.0) * 0.2;
pos.z += (smoothTriangleWave(animationTimer*10.0 + pos2XpZ * -0.01) * 2.0 - 1.0) * 0.4;
gl_Position = mWorldViewProj * pos;
#elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS
vec4 pos = gl_Vertex;
vec4 pos2 = mWorld * gl_Vertex;
if (gl_TexCoord[0].y < 0.05) {
pos.x += (smoothTriangleWave(animationTimer * 20.0 + pos2.x * 0.1 + pos2.z * 0.1) * 2.0 - 1.0) * 0.8;
pos.y -= (smoothTriangleWave(animationTimer * 10.0 + pos2.x * -0.5 + pos2.z * -0.5) * 2.0 - 1.0) * 0.4;
/*
* Mathematic optimization: pos2.x * A + pos2.z * A (2 multiplications + 1 addition)
* replaced with: (pos2.x + pos2.z) * A (1 addition + 1 multiplication)
* And bufferize calcul to a float
*/
float pos2XpZ = pos2.x + pos2.z;
pos.x += (smoothTriangleWave(animationTimer * 20.0 + pos2XpZ * 0.1) * 2.0 - 1.0) * 0.8;
pos.y -= (smoothTriangleWave(animationTimer * 10.0 + pos2XpZ * -0.5) * 2.0 - 1.0) * 0.4;
}
gl_Position = mWorldViewProj * pos;
#else
@ -88,7 +105,7 @@ void main(void)
tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0));
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
}
mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x,
mat3 tbnMatrix = mat3(tangent.x, binormal.x, normal.x,
tangent.y, binormal.y, normal.y,
tangent.z, binormal.z, normal.z);
@ -97,5 +114,31 @@ void main(void)
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
tsEyeVec = eyeVec * tbnMatrix;
gl_FrontColor = gl_BackColor = gl_Color;
vec4 color;
float day = gl_Color.r;
float night = gl_Color.g;
float light_source = gl_Color.b;
float rg = mix(night, day, dayNightRatio);
rg += light_source * 2.5; // Make light sources brighter
float b = rg;
// Moonlight is blue
b += (day - night) / 13.0;
rg -= (day - night) / 23.0;
// Emphase blue a bit in darker places
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
// Artificial light is yellow-ish
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
color.r = rg;
color.g = rg;
color.b = b;
color.a = gl_Color.a;
gl_FrontColor = gl_BackColor = clamp(color,0.0,1.0);
}

View File

@ -0,0 +1,114 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform sampler2D textureFlags;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;
varying vec3 vPosition;
varying vec3 worldPosition;
varying vec3 eyeVec;
varying vec3 lightVec;
bool normalTexturePresent = false;
bool texTileableHorizontal = false;
bool texTileableVertical = false;
bool texSeamless = false;
const float e = 2.718281828459;
const float BS = 10.0;
void get_texture_flags()
{
vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
if (flags.r > 0.5) {
normalTexturePresent = true;
}
if (flags.g > 0.5) {
texTileableHorizontal = true;
}
if (flags.b > 0.5) {
texTileableVertical = true;
}
if (texTileableHorizontal && texTileableVertical) {
texSeamless = true;
}
}
float intensity(vec3 color)
{
return (color.r + color.g + color.b) / 3.0;
}
float get_rgb_height(vec2 uv)
{
if (texSeamless) {
return intensity(texture2D(baseTexture, uv).rgb);
} else {
return intensity(texture2D(baseTexture, clamp(uv, 0.0, 0.999)).rgb);
}
}
vec4 get_normal_map(vec2 uv)
{
vec4 bump = texture2D(normalTexture, uv).rgba;
bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
return bump;
}
void main(void)
{
vec3 color;
vec4 bump;
vec2 uv = gl_TexCoord[0].st;
bool use_normalmap = false;
get_texture_flags();
#if USE_NORMALMAPS == 1
if (normalTexturePresent) {
bump = get_normal_map(uv);
use_normalmap = true;
}
#endif
if (GENERATE_NORMALMAPS == 1 && normalTexturePresent == false) {
float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
use_normalmap = true;
}
vec4 base = texture2D(baseTexture, uv).rgba;
#ifdef ENABLE_BUMPMAPPING
if (use_normalmap) {
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
float diffuse = dot(-E,bump.xyz);
color = (diffuse + 0.1 * specular) * base.rgb;
} else {
color = base.rgb;
}
#else
color = base.rgb;
#endif
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
if (fogDistance != 0.0) {
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
col = mix(col, skyBgColor, d);
}
gl_FragColor = vec4(col.rgb, base.a);
}

View File

@ -0,0 +1,35 @@
uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform mat4 mWorld;
uniform float dayNightRatio;
uniform vec3 eyePosition;
uniform float animationTimer;
varying vec3 vPosition;
varying vec3 worldPosition;
varying vec3 eyeVec;
varying vec3 lightVec;
varying vec3 tsEyeVec;
varying vec3 tsLightVec;
const float e = 2.718281828459;
const float BS = 10.0;
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = mWorldViewProj * gl_Vertex;
vPosition = gl_Position.xyz;
worldPosition = (mWorld * gl_Vertex).xyz;
vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0);
lightVec = sunPosition - worldPosition;
eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz;
gl_FrontColor = gl_BackColor = gl_Color;
}

View File

@ -1,47 +1,19 @@
# - Find curl
# Find the native CURL headers and libraries.
#
# CURL_INCLUDE_DIR - where to find curl/curl.h, etc.
# CURL_LIBRARY - List of libraries when using curl.
# CURL_FOUND - True if curl found.
mark_as_advanced(CURL_LIBRARY CURL_INCLUDE_DIR)
if( UNIX )
FIND_PATH(CURL_INCLUDE_DIR NAMES curl.h
PATHS
/usr/local/include/curl
/usr/include/curl
)
find_library(CURL_LIBRARY NAMES curl)
find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
FIND_LIBRARY(CURL_LIBRARY NAMES curl
PATHS
/usr/local/lib
/usr/lib
)
else( UNIX )
FIND_PATH(CURL_INCLUDE_DIR NAMES curl/curl.h) # Look for the header file.
FIND_LIBRARY(CURL_LIBRARY NAMES curl) # Look for the library.
FIND_FILE(CURL_DLL NAMES libcurl.dll
PATHS
"c:/windows/system32"
DOC "Path of the cURL dll (for installation)")
INCLUDE(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CURL_FOUND to TRUE if
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL DEFAULT_MSG CURL_LIBRARY CURL_INCLUDE_DIR) # all listed variables are TRUE
endif( UNIX )
set(CURL_REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR)
if( WIN32 )
if( CURL_LIBRARY AND CURL_INCLUDE_DIR AND CURL_DLL ) # libcurl.dll is required on Windows
SET(CURL_FOUND TRUE)
else( CURL_LIBRARY AND CURL_INCLUDE_DIR AND CURL_DLL )
SET(CURL_FOUND FALSE)
endif( CURL_LIBRARY AND CURL_INCLUDE_DIR AND CURL_DLL )
else ( WIN32 )
if( CURL_LIBRARY AND CURL_INCLUDE_DIR )
SET(CURL_FOUND TRUE)
else( CURL_LIBRARY AND CURL_INCLUDE_DIR )
SET(CURL_FOUND FALSE)
endif( CURL_LIBRARY AND CURL_INCLUDE_DIR )
endif ( WIN32 )
if(WIN32)
find_file(CURL_DLL NAMES libcurl-4.dll
PATHS
"C:/Windows/System32"
DOC "Path to the cURL DLL (for installation)")
mark_as_advanced(CURL_DLL)
set(CURL_REQUIRED_VARS ${CURL_REQUIRED_VARS} CURL_DLL)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CURL DEFAULT_MSG ${CURL_REQUIRED_VARS})
MESSAGE(STATUS "CURL_INCLUDE_DIR = ${CURL_INCLUDE_DIR}")
MESSAGE(STATUS "CURL_LIBRARY = ${CURL_LIBRARY}")
MESSAGE(STATUS "CURL_DLL = ${CURL_DLL}")

View File

@ -0,0 +1,28 @@
option(ENABLE_SYSTEM_GMP "Use GMP from system" TRUE)
mark_as_advanced(GMP_LIBRARY GMP_INCLUDE_DIR)
set(USE_SYSTEM_GMP FALSE)
if(ENABLE_SYSTEM_GMP)
find_library(GMP_LIBRARY NAMES libgmp.so)
find_path(GMP_INCLUDE_DIR NAMES gmp.h)
if(GMP_LIBRARY AND GMP_INCLUDE_DIR)
message (STATUS "Using GMP provided by system.")
set(USE_SYSTEM_GMP TRUE)
else()
message (STATUS "Detecting GMP from system failed.")
endif()
else()
message (STATUS "Detecting GMP from system disabled! (ENABLE_SYSTEM_GMP=0)")
endif()
if(NOT USE_SYSTEM_GMP)
message(STATUS "Using bundled mini-gmp library.")
set(GMP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/gmp)
set(GMP_LIBRARY gmp)
add_subdirectory(gmp)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GMP DEFAULT_MSG GMP_LIBRARY GMP_INCLUDE_DIR)

View File

@ -1,84 +1,78 @@
# Package finder for gettext libs and include files
SET(CUSTOM_GETTEXT_PATH "${PROJECT_SOURCE_DIR}/../../gettext"
set(CUSTOM_GETTEXT_PATH "${PROJECT_SOURCE_DIR}/../../gettext"
CACHE FILEPATH "path to custom gettext")
# by default
SET(GETTEXT_FOUND FALSE)
FIND_PATH(GETTEXT_INCLUDE_DIR
find_path(GETTEXT_INCLUDE_DIR
NAMES libintl.h
PATHS "${CUSTOM_GETTEXT_PATH}/include"
DOC "gettext include directory")
DOC "GetText include directory")
FIND_PROGRAM(GETTEXT_MSGFMT
find_program(GETTEXT_MSGFMT
NAMES msgfmt
PATHS "${CUSTOM_GETTEXT_PATH}/bin"
DOC "path to msgfmt")
DOC "Path to msgfmt")
set(GETTEXT_REQUIRED_VARS GETTEXT_INCLUDE_DIR GETTEXT_MSGFMT)
if(APPLE)
FIND_LIBRARY(GETTEXT_LIBRARY
find_library(GETTEXT_LIBRARY
NAMES libintl.a
PATHS "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *intl*.lib")
DOC "GetText library")
FIND_LIBRARY(ICONV_LIBRARY
find_library(ICONV_LIBRARY
NAMES libiconv.dylib
PATHS "/usr/lib"
DOC "iconv lib")
DOC "IConv library")
set(GETTEXT_REQUIRED_VARS ${GETTEXT_REQUIRED_VARS} GETTEXT_LIBRARY ICONV_LIBRARY)
endif(APPLE)
# modern Linux, as well as Mac, seem to not need require special linking
# they do not because gettext is part of glibc
# TODO check the requirements on other BSDs and older Linux
IF (WIN32)
IF(MSVC)
SET(GETTEXT_LIB_NAMES
# Modern Linux, as well as OSX, does not require special linking because
# GetText is part of glibc.
# TODO: check the requirements on other BSDs and older Linux
if(WIN32)
if(MSVC)
set(GETTEXT_LIB_NAMES
libintl.lib intl.lib libintl3.lib intl3.lib)
ELSE()
SET(GETTEXT_LIB_NAMES
else()
set(GETTEXT_LIB_NAMES
libintl.dll.a intl.dll.a libintl3.dll.a intl3.dll.a)
ENDIF()
FIND_LIBRARY(GETTEXT_LIBRARY
endif()
find_library(GETTEXT_LIBRARY
NAMES ${GETTEXT_LIB_NAMES}
PATHS "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *intl*.lib")
FIND_FILE(GETTEXT_DLL
DOC "GetText library")
find_file(GETTEXT_DLL
NAMES libintl.dll intl.dll libintl3.dll intl3.dll
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *intl*.dll")
FIND_FILE(GETTEXT_ICONV_DLL
find_file(GETTEXT_ICONV_DLL
NAMES libiconv2.dll
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *iconv*.lib")
ENDIF(WIN32)
set(GETTEXT_REQUIRED_VARS ${GETTEXT_REQUIRED_VARS} GETTEXT_DLL GETTEXT_ICONV_DLL)
endif(WIN32)
IF(GETTEXT_INCLUDE_DIR AND GETTEXT_MSGFMT)
IF (WIN32)
# in the Win32 case check also for the extra linking requirements
IF(GETTEXT_LIBRARY AND GETTEXT_DLL AND GETTEXT_ICONV_DLL)
SET(GETTEXT_FOUND TRUE)
ENDIF()
ELSE(WIN32)
# *BSD variants require special linkage as they don't use glibc
IF(${CMAKE_SYSTEM_NAME} MATCHES "BSD")
SET(GETTEXT_LIBRARY "intl")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "BSD")
SET(GETTEXT_FOUND TRUE)
ENDIF(WIN32)
ENDIF()
IF(GETTEXT_FOUND)
SET(GETTEXT_PO_PATH ${CMAKE_SOURCE_DIR}/po)
SET(GETTEXT_MO_BUILD_PATH ${CMAKE_BINARY_DIR}/locale/<locale>/LC_MESSAGES)
SET(GETTEXT_MO_DEST_PATH ${LOCALEDIR}/<locale>/LC_MESSAGES)
FILE(GLOB GETTEXT_AVAILABLE_LOCALES RELATIVE ${GETTEXT_PO_PATH} "${GETTEXT_PO_PATH}/*")
LIST(REMOVE_ITEM GETTEXT_AVAILABLE_LOCALES minetest.pot)
MACRO(SET_MO_PATHS _buildvar _destvar _locale)
STRING(REPLACE "<locale>" ${_locale} ${_buildvar} ${GETTEXT_MO_BUILD_PATH})
STRING(REPLACE "<locale>" ${_locale} ${_destvar} ${GETTEXT_MO_DEST_PATH})
ENDMACRO(SET_MO_PATHS)
ELSE()
SET(GETTEXT_INCLUDE_DIR "")
SET(GETTEXT_LIBRARY "")
ENDIF()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GetText DEFAULT_MSG ${GETTEXT_REQUIRED_VARS})
if(GETTEXT_FOUND)
# BSD variants require special linkage as they don't use glibc
if(${CMAKE_SYSTEM_NAME} MATCHES "BSD")
set(GETTEXT_LIBRARY "intl")
endif()
set(GETTEXT_PO_PATH ${CMAKE_SOURCE_DIR}/po)
set(GETTEXT_MO_BUILD_PATH ${CMAKE_BINARY_DIR}/locale/<locale>/LC_MESSAGES)
set(GETTEXT_MO_DEST_PATH ${LOCALEDIR}/<locale>/LC_MESSAGES)
file(GLOB GETTEXT_AVAILABLE_LOCALES RELATIVE ${GETTEXT_PO_PATH} "${GETTEXT_PO_PATH}/*")
list(REMOVE_ITEM GETTEXT_AVAILABLE_LOCALES minetest.pot)
list(REMOVE_ITEM GETTEXT_AVAILABLE_LOCALES timestamp)
macro(SET_MO_PATHS _buildvar _destvar _locale)
string(REPLACE "<locale>" ${_locale} ${_buildvar} ${GETTEXT_MO_BUILD_PATH})
string(REPLACE "<locale>" ${_locale} ${_destvar} ${GETTEXT_MO_DEST_PATH})
endmacro()
endif()

View File

@ -1,12 +1,7 @@
#FindIrrlicht.cmake
mark_as_advanced(IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR IRRLICHT_DLL)
set(IRRLICHT_SOURCE_DIR "" CACHE PATH "Path to irrlicht source directory (optional)")
if( UNIX )
# Unix
else( UNIX )
# Windows
endif( UNIX )
# Find include directory
@ -30,65 +25,47 @@ if(NOT IRRLICHT_SOURCE_DIR STREQUAL "")
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a)
endif()
FIND_PATH(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
PATHS
${IRRLICHT_SOURCE_DIR_INCLUDE}
NO_DEFAULT_PATH
)
FIND_LIBRARY(IRRLICHT_LIBRARY NAMES ${IRRLICHT_LIBRARY_NAMES}
find_library(IRRLICHT_LIBRARY NAMES ${IRRLICHT_LIBRARY_NAMES}
PATHS
${IRRLICHT_SOURCE_DIR_LIBS}
NO_DEFAULT_PATH
)
else()
FIND_PATH(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
PATHS
/usr/local/include/irrlicht
/usr/include/irrlicht
)
FIND_LIBRARY(IRRLICHT_LIBRARY NAMES libIrrlicht.a Irrlicht
find_library(IRRLICHT_LIBRARY NAMES libIrrlicht.so libIrrlicht.a Irrlicht
PATHS
/usr/local/lib
/usr/lib
)
endif()
MESSAGE(STATUS "IRRLICHT_SOURCE_DIR = ${IRRLICHT_SOURCE_DIR}")
MESSAGE(STATUS "IRRLICHT_INCLUDE_DIR = ${IRRLICHT_INCLUDE_DIR}")
MESSAGE(STATUS "IRRLICHT_LIBRARY = ${IRRLICHT_LIBRARY}")
# On windows, find the dll for installation
# On Windows, find the DLL for installation
if(WIN32)
if(MSVC)
FIND_FILE(IRRLICHT_DLL NAMES Irrlicht.dll
PATHS
"${IRRLICHT_SOURCE_DIR}/bin/Win32-VisualStudio"
DOC "Path of the Irrlicht dll (for installation)"
)
set(IRRLICHT_COMPILER "VisualStudio")
else()
FIND_FILE(IRRLICHT_DLL NAMES Irrlicht.dll
PATHS
"${IRRLICHT_SOURCE_DIR}/bin/Win32-gcc"
DOC "Path of the Irrlicht dll (for installation)"
)
set(IRRLICHT_COMPILER "gcc")
endif()
MESSAGE(STATUS "IRRLICHT_DLL = ${IRRLICHT_DLL}")
find_file(IRRLICHT_DLL NAMES Irrlicht.dll
PATHS
"${IRRLICHT_SOURCE_DIR}/bin/Win32-${IRRLICHT_COMPILER}"
DOC "Path of the Irrlicht dll (for installation)"
)
endif(WIN32)
# handle the QUIETLY and REQUIRED arguments and set IRRLICHT_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(IRRLICHT DEFAULT_MSG IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR)
IF(IRRLICHT_FOUND)
SET(IRRLICHT_LIBRARIES ${IRRLICHT_LIBRARY})
ELSE(IRRLICHT_FOUND)
SET(IRRLICHT_LIBRARIES)
ENDIF(IRRLICHT_FOUND)
MARK_AS_ADVANCED(IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR IRRLICHT_DLL)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Irrlicht DEFAULT_MSG IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR)

View File

@ -1,18 +1,27 @@
# Look for json, use our own if not found
# Look for JSONCPP if asked to.
# We use a bundled version by default because some distros ship versions of
# JSONCPP that cause segfaults and other memory errors when we link with them.
# See https://github.com/minetest/minetest/issues/1793
#FIND_PATH(JSON_INCLUDE_DIR json.h)
mark_as_advanced(JSON_LIBRARY JSON_INCLUDE_DIR)
option(ENABLE_SYSTEM_JSONCPP "Enable using a system-wide JSONCPP. May cause segfaults and other memory errors!" FALSE)
#FIND_LIBRARY(JSON_LIBRARY NAMES jsoncpp)
if(ENABLE_SYSTEM_JSONCPP)
find_library(JSON_LIBRARY NAMES jsoncpp)
find_path(JSON_INCLUDE_DIR json/features.h PATH_SUFFIXES jsoncpp)
#IF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
# SET( JSON_FOUND TRUE )
#ENDIF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JSONCPP DEFAULT_MSG JSON_LIBRARY JSON_INCLUDE_DIR)
if(JSONCPP_FOUND)
message(STATUS "Using system JSONCPP library.")
endif()
endif()
if(NOT JSONCPP_FOUND)
message(STATUS "Using bundled JSONCPP library.")
set(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/json)
set(JSON_LIBRARY jsoncpp)
add_subdirectory(json)
endif()
#IF(JSON_FOUND)
# MESSAGE(STATUS "Found system jsoncpp header file in ${JSON_INCLUDE_DIR}")
# MESSAGE(STATUS "Found system jsoncpp library ${JSON_LIBRARY}")
#ELSE(JSON_FOUND)
SET(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/json)
SET(JSON_LIBRARY jsoncpp)
MESSAGE(STATUS "Using project jsoncpp library")
#ENDIF(JSON_FOUND)

View File

@ -0,0 +1,50 @@
# Locate LuaJIT library
# This module defines
# LUAJIT_FOUND, if false, do not try to link to Lua
# LUA_INCLUDE_DIR, where to find lua.h
# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
#
# This module is similar to FindLua51.cmake except that it finds LuaJit instead.
FIND_PATH(LUA_INCLUDE_DIR luajit.h
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES include/luajit-2.0 include/luajit-5_1-2.0 include
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
FIND_LIBRARY(LUA_LIBRARY
NAMES luajit-5.1
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw
/opt/local
/opt/csw
/opt
)
IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/luajit.h")
FILE(STRINGS "${LUA_INCLUDE_DIR}/luajit.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"LuaJIT .+\"")
STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"LuaJIT ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
UNSET(lua_version_str)
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LuaJit
REQUIRED_VARS LUA_LIBRARY LUA_INCLUDE_DIR
VERSION_VAR LUA_VERSION_STRING)
MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARY LUA_MATH_LIBRARY)

View File

@ -0,0 +1,189 @@
#.rst:
# FindNcursesw
# ------------
#
# Find the ncursesw (wide ncurses) include file and library.
#
# Based on FindCurses.cmake which comes with CMake.
#
# Checks for ncursesw first. If not found, it then executes the
# regular old FindCurses.cmake to look for for ncurses (or curses).
#
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This module defines the following variables:
#
# ``CURSES_FOUND``
# True if curses is found.
# ``NCURSESW_FOUND``
# True if ncursesw is found.
# ``CURSES_INCLUDE_DIRS``
# The include directories needed to use Curses.
# ``CURSES_LIBRARIES``
# The libraries needed to use Curses.
# ``CURSES_HAVE_CURSES_H``
# True if curses.h is available.
# ``CURSES_HAVE_NCURSES_H``
# True if ncurses.h is available.
# ``CURSES_HAVE_NCURSES_NCURSES_H``
# True if ``ncurses/ncurses.h`` is available.
# ``CURSES_HAVE_NCURSES_CURSES_H``
# True if ``ncurses/curses.h`` is available.
# ``CURSES_HAVE_NCURSESW_NCURSES_H``
# True if ``ncursesw/ncurses.h`` is available.
# ``CURSES_HAVE_NCURSESW_CURSES_H``
# True if ``ncursesw/curses.h`` is available.
#
# Set ``CURSES_NEED_NCURSES`` to ``TRUE`` before the
# ``find_package(Ncursesw)`` call if NCurses functionality is required.
#
#=============================================================================
# Copyright 2001-2014 Kitware, Inc.
# modifications: Copyright 2015 kahrl <kahrl@gmx.net>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
# nor the names of their contributors may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ------------------------------------------------------------------------------
#
# The above copyright and license notice applies to distributions of
# CMake in source and binary form. Some source files contain additional
# notices of original copyright by their contributors; see each source
# for details. Third-party software packages supplied with CMake under
# compatible licenses provide their own copyright notices documented in
# corresponding subdirectories.
#
# ------------------------------------------------------------------------------
#
# CMake was initially developed by Kitware with the following sponsorship:
#
# * National Library of Medicine at the National Institutes of Health
# as part of the Insight Segmentation and Registration Toolkit (ITK).
#
# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
# Visualization Initiative.
#
# * National Alliance for Medical Image Computing (NAMIC) is funded by the
# National Institutes of Health through the NIH Roadmap for Medical Research,
# Grant U54 EB005149.
#
# * Kitware, Inc.
#=============================================================================
include(CheckLibraryExists)
find_library(CURSES_NCURSESW_LIBRARY NAMES ncursesw
DOC "Path to libncursesw.so or .lib or .a")
set(CURSES_USE_NCURSES FALSE)
set(CURSES_USE_NCURSESW FALSE)
if(CURSES_NCURSESW_LIBRARY)
set(CURSES_USE_NCURSES TRUE)
set(CURSES_USE_NCURSESW TRUE)
endif()
if(CURSES_USE_NCURSESW)
get_filename_component(_cursesLibDir "${CURSES_NCURSESW_LIBRARY}" PATH)
get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH)
find_path(CURSES_INCLUDE_PATH
NAMES ncursesw/ncurses.h ncursesw/curses.h
HINTS "${_cursesParentDir}/include"
)
# Previous versions of FindCurses provided these values.
if(NOT DEFINED CURSES_LIBRARY)
set(CURSES_LIBRARY "${CURSES_NCURSESW_LIBRARY}")
endif()
CHECK_LIBRARY_EXISTS("${CURSES_NCURSESW_LIBRARY}"
cbreak "" CURSES_NCURSESW_HAS_CBREAK)
if(NOT CURSES_NCURSESW_HAS_CBREAK)
find_library(CURSES_EXTRA_LIBRARY tinfo HINTS "${_cursesLibDir}"
DOC "Path to libtinfo.so or .lib or .a")
find_library(CURSES_EXTRA_LIBRARY tinfo )
endif()
# Report whether each possible header name exists in the include directory.
if(NOT DEFINED CURSES_HAVE_NCURSESW_NCURSES_H)
if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h")
set(CURSES_HAVE_NCURSESW_NCURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h")
else()
set(CURSES_HAVE_NCURSESW_NCURSES_H "CURSES_HAVE_NCURSESW_NCURSES_H-NOTFOUND")
endif()
endif()
if(NOT DEFINED CURSES_HAVE_NCURSESW_CURSES_H)
if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/curses.h")
set(CURSES_HAVE_NCURSESW_CURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/curses.h")
else()
set(CURSES_HAVE_NCURSESW_CURSES_H "CURSES_HAVE_NCURSESW_CURSES_H-NOTFOUND")
endif()
endif()
find_library(CURSES_FORM_LIBRARY form HINTS "${_cursesLibDir}"
DOC "Path to libform.so or .lib or .a")
find_library(CURSES_FORM_LIBRARY form )
# Need to provide the *_LIBRARIES
set(CURSES_LIBRARIES ${CURSES_LIBRARY})
if(CURSES_EXTRA_LIBRARY)
set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_EXTRA_LIBRARY})
endif()
if(CURSES_FORM_LIBRARY)
set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_FORM_LIBRARY})
endif()
# Provide the *_INCLUDE_DIRS result.
set(CURSES_INCLUDE_DIRS ${CURSES_INCLUDE_PATH})
set(CURSES_INCLUDE_DIR ${CURSES_INCLUDE_PATH}) # compatibility
# handle the QUIETLY and REQUIRED arguments and set CURSES_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ncursesw DEFAULT_MSG
CURSES_LIBRARY CURSES_INCLUDE_PATH)
set(CURSES_FOUND ${NCURSESW_FOUND})
else()
find_package(Curses)
set(NCURSESW_FOUND FALSE)
endif()
mark_as_advanced(
CURSES_INCLUDE_PATH
CURSES_CURSES_LIBRARY
CURSES_NCURSES_LIBRARY
CURSES_NCURSESW_LIBRARY
CURSES_EXTRA_LIBRARY
CURSES_FORM_LIBRARY
)

View File

@ -16,115 +16,97 @@
# EGL_INCLUDE_DIR - the EGL include directory
# EGL_LIBRARIES - Link these to use EGL
# win32, apple, android NOT TESED
# linux tested and works
IF (WIN32)
IF (CYGWIN)
FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h )
FIND_LIBRARY(OPENGLES2_gl_LIBRARY libGLESv2 )
ELSE (CYGWIN)
IF(BORLAND)
SET (OPENGLES2_gl_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for win32")
ELSE(BORLAND)
# todo
# SET (OPENGLES_gl_LIBRARY ${SOURCE_DIR}/Dependencies/lib/release/libGLESv2.lib CACHE STRING "OpenGL ES 2.x library for win32"
ENDIF(BORLAND)
ENDIF (CYGWIN)
ELSE (WIN32)
IF (APPLE)
# Win32, Apple, and Android are not tested!
# Linux tested and works
if(WIN32)
if(CYGWIN)
find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h)
find_library(OPENGLES2_LIBRARY libGLESv2)
else()
if(BORLAND)
set(OPENGLES2_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for Win32")
else()
# TODO
# set(OPENGLES_LIBRARY ${SOURCE_DIR}/Dependencies/lib/release/libGLESv2.lib CACHE STRING "OpenGL ES 2.x library for win32"
endif()
endif()
elseif(APPLE)
create_search_paths(/Developer/Platforms)
findpkg_framework(OpenGLES2)
set(OPENGLES2_gl_LIBRARY "-framework OpenGLES")
set(OPENGLES2_LIBRARY "-framework OpenGLES")
else()
find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h
PATHS /usr/openwin/share/include
/opt/graphics/OpenGL/include
/usr/X11R6/include
/usr/include
)
ELSE(APPLE)
find_library(OPENGLES2_LIBRARY
NAMES GLESv2
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib /usr/X11R6/lib
/usr/lib
)
FIND_PATH(OPENGLES2_INCLUDE_DIR GLES2/gl2.h
/usr/openwin/share/include
/opt/graphics/OpenGL/include /usr/X11R6/include
/usr/include
)
FIND_LIBRARY(OPENGLES2_gl_LIBRARY
NAMES GLESv2
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib /usr/X11R6/lib
/usr/lib
)
IF (NOT BUILD_ANDROID)
FIND_PATH(EGL_INCLUDE_DIR EGL/egl.h
/usr/openwin/share/include
/opt/graphics/OpenGL/include /usr/X11R6/include
/usr/include
if(NOT BUILD_ANDROID)
find_path(EGL_INCLUDE_DIR EGL/egl.h
PATHS /usr/openwin/share/include
/opt/graphics/OpenGL/include
/usr/X11R6/include
/usr/include
)
FIND_LIBRARY(EGL_egl_LIBRARY
NAMES EGL
PATHS /opt/graphics/OpenGL/lib
find_library(EGL_LIBRARY
NAMES EGL
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib /usr/X11R6/lib
/usr/shlib
/usr/X11R6/lib
/usr/lib
)
# On Unix OpenGL most certainly always requires X11.
# Feel free to tighten up these conditions if you don't
# think this is always true.
# It's not true on OSX.
# On Unix OpenGL usually requires X11.
# It doesn't require X11 on OSX.
IF (OPENGLES2_gl_LIBRARY)
IF(NOT X11_FOUND)
INCLUDE(FindX11)
ENDIF(NOT X11_FOUND)
IF (X11_FOUND)
IF (NOT APPLE)
SET (OPENGLES2_LIBRARIES ${X11_LIBRARIES})
ENDIF (NOT APPLE)
ENDIF (X11_FOUND)
ENDIF (OPENGLES2_gl_LIBRARY)
ENDIF ()
if(OPENGLES2_LIBRARY)
if(NOT X11_FOUND)
include(FindX11)
endif()
if(X11_FOUND)
set(OPENGLES2_LIBRARIES ${X11_LIBRARIES})
endif()
endif()
endif()
endif()
ENDIF(APPLE)
ENDIF (WIN32)
set(OPENGLES2_LIBRARIES ${OPENGLES2_LIBRARIES} ${OPENGLES2_LIBRARY})
#SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
if(BUILD_ANDROID)
if(OPENGLES2_LIBRARY)
set(EGL_LIBRARIES)
set(OPENGLES2_FOUND TRUE)
endif()
else()
if(OPENGLES2_LIBRARY AND EGL_LIBRARY)
set(OPENGLES2_LIBRARIES ${OPENGLES2_LIBRARY} ${OPENGLES2_LIBRARIES})
set(EGL_LIBRARIES ${EGL_LIBRARY} ${EGL_LIBRARIES})
set(OPENGLES2_FOUND TRUE)
endif()
endif()
IF (BUILD_ANDROID)
IF(OPENGLES2_gl_LIBRARY)
SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
SET( EGL_LIBRARIES)
SET( OPENGLES2_FOUND "YES" )
ENDIF(OPENGLES2_gl_LIBRARY)
ELSE ()
SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
IF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY)
SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
SET( EGL_LIBRARIES ${EGL_egl_LIBRARY} ${EGL_LIBRARIES})
SET( OPENGLES2_FOUND "YES" )
ENDIF(OPENGLES2_gl_LIBRARY AND EGL_egl_LIBRARY)
ENDIF ()
MARK_AS_ADVANCED(
OPENGLES2_INCLUDE_DIR
OPENGLES2_gl_LIBRARY
EGL_INCLUDE_DIR
EGL_egl_LIBRARY
mark_as_advanced(
OPENGLES2_INCLUDE_DIR
OPENGLES2_LIBRARY
EGL_INCLUDE_DIR
EGL_LIBRARY
)
IF(OPENGLES2_FOUND)
MESSAGE(STATUS "Found system opengles2 library ${OPENGLES2_LIBRARIES}")
ELSE ()
SET(OPENGLES2_LIBRARIES "")
ENDIF ()
if(OPENGLES2_FOUND)
message(STATUS "Found system OpenGL ES 2 library: ${OPENGLES2_LIBRARIES}")
else()
set(OPENGLES2_LIBRARIES "")
endif()

View File

@ -0,0 +1,9 @@
mark_as_advanced(SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR)
find_path(SQLITE3_INCLUDE_DIR sqlite3.h)
find_library(SQLITE3_LIBRARY NAMES sqlite3)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SQLite3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR)

View File

@ -1,18 +0,0 @@
# Look for sqlite3, use our own if not found
FIND_PATH(SQLITE3_INCLUDE_DIR sqlite3.h)
FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3)
IF(SQLITE3_LIBRARY AND SQLITE3_INCLUDE_DIR)
SET( SQLITE3_FOUND TRUE )
ENDIF(SQLITE3_LIBRARY AND SQLITE3_INCLUDE_DIR)
IF(SQLITE3_FOUND)
MESSAGE(STATUS "Found system sqlite3 header file in ${SQLITE3_INCLUDE_DIR}")
MESSAGE(STATUS "Found system sqlite3 library ${SQLITE3_LIBRARY}")
ELSE(SQLITE3_FOUND)
SET(SQLITE3_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/sqlite)
SET(SQLITE3_LIBRARY sqlite3)
MESSAGE(STATUS "Using project sqlite3 library")
ENDIF(SQLITE3_FOUND)

View File

@ -1,20 +1,26 @@
# Always run during 'make'
if(VERSION_EXTRA)
set(VERSION_GITHASH "${VERSION_STRING}")
else(VERSION_EXTRA)
execute_process(COMMAND git describe --always --tag --dirty
if(DEVELOPMENT_BUILD)
execute_process(COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY "${GENERATE_VERSION_SOURCE_DIR}"
OUTPUT_VARIABLE VERSION_GITHASH OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if(VERSION_GITHASH)
message(STATUS "*** Detected git version ${VERSION_GITHASH} ***")
else()
set(VERSION_GITHASH "${VERSION_STRING}")
set(VERSION_GITHASH "${VERSION_STRING}-${VERSION_GITHASH}")
execute_process(COMMAND git diff-index --quiet HEAD
WORKING_DIRECTORY "${GENERATE_VERSION_SOURCE_DIR}"
RESULT_VARIABLE IS_DIRTY)
if(IS_DIRTY)
set(VERSION_GITHASH "${VERSION_GITHASH}-dirty")
endif()
message(STATUS "*** Detected Git version ${VERSION_GITHASH} ***")
endif()
endif()
if(NOT VERSION_GITHASH)
set(VERSION_GITHASH "${VERSION_STRING}")
endif()
configure_file(
${GENERATE_VERSION_SOURCE_DIR}/cmake_config_githash.h.in
${GENERATE_VERSION_BINARY_DIR}/cmake_config_githash.h)

View File

@ -1,21 +0,0 @@
#
# Random macros
#
# Not used ATM
MACRO (GETDATETIME RESULT)
IF (WIN32)
EXECUTE_PROCESS(COMMAND "cmd" /C echo %date% %time% OUTPUT_VARIABLE ${RESULT})
string(REGEX REPLACE "\n" "" ${RESULT} "${${RESULT}}")
ELSEIF(UNIX)
EXECUTE_PROCESS(COMMAND "date" "+%Y-%m-%d_%H:%M:%S" OUTPUT_VARIABLE ${RESULT})
string(REGEX REPLACE "\n" "" ${RESULT} "${${RESULT}}")
ELSE (WIN32)
MESSAGE(SEND_ERROR "date not implemented")
SET(${RESULT} "Unknown")
ENDIF (WIN32)
string(REGEX REPLACE " " "_" ${RESULT} "${${RESULT}}")
ENDMACRO (GETDATETIME)

53
doc/Doxyfile.in Normal file
View File

@ -0,0 +1,53 @@
# Project properties
PROJECT_NAME = @PROJECT_NAME_CAPITALIZED@
PROJECT_NUMBER = @VERSION_STRING@
PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/misc/minetest.svg
# Parsing
JAVADOC_AUTOBRIEF = YES
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
SORT_MEMBERS_CTORS_1ST = YES
WARN_IF_UNDOCUMENTED = NO
BUILTIN_STL_SUPPORT = YES
PREDEFINED = "USE_SPATIAL=1" \
"USE_LEVELDB=1" \
"USE_REDIS=1" \
"USE_SOUND=1" \
"USE_CURL=1" \
"USE_FREETYPE=1" \
"USE_GETTEXT=1"
# Input
RECURSIVE = NO
STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@/src
INPUT = @CMAKE_CURRENT_SOURCE_DIR@/doc/main_page.dox \
@CMAKE_CURRENT_SOURCE_DIR@/src/ \
@CMAKE_CURRENT_SOURCE_DIR@/src/client \
@CMAKE_CURRENT_SOURCE_DIR@/src/network \
@CMAKE_CURRENT_SOURCE_DIR@/src/util \
@CMAKE_CURRENT_SOURCE_DIR@/src/script \
@CMAKE_CURRENT_SOURCE_DIR@/src/script/common \
@CMAKE_CURRENT_SOURCE_DIR@/src/script/cpp_api \
@CMAKE_CURRENT_SOURCE_DIR@/src/script/lua_api \
@CMAKE_CURRENT_SOURCE_DIR@/src/threading
# Dot graphs
HAVE_DOT = @DOXYGEN_DOT_FOUND@
CALL_GRAPH = YES
CALLER_GRAPH = YES
MAX_DOT_GRAPH_DEPTH = 3
DOT_MULTI_TARGETS = YES
DOT_IMAGE_FORMAT = svg
# Output
GENERATE_LATEX = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
SEARCHENGINE = YES
DISABLE_INDEX = YES
GENERATE_TREEVIEW = YES
HTML_DYNAMIC_SECTIONS = YES
HTML_TIMESTAMP = YES

File diff suppressed because it is too large Load Diff

8
doc/main_page.dox Normal file
View File

@ -0,0 +1,8 @@
/** @mainpage The Minetest engine internal documentation
Welcome to the Minetest engine Doxygen documentation site!\n
This page documents the internal structure of the Minetest engine's C++ code.\n
Use the tree view at the left to navigate.
*/

View File

@ -1,4 +1,4 @@
Minetest Lua Mainmenu API Reference 0.4.10
Minetest Lua Mainmenu API Reference 0.4.13
========================================
Introduction
@ -31,8 +31,8 @@ core.start()
core.close()
Filesystem:
core.get_scriptdir()
^ returns directory of script
core.get_builtin_path()
^ returns path to builtin root
core.get_modpath() (possible in async calls)
^ returns path to global modpath
core.get_modstore_details(modid) (possible in async calls)
@ -59,10 +59,6 @@ core.get_gamepath() (possible in async calls)
^ returns path to global gamepath
core.get_texturepath() (possible in async calls)
^ returns path to default textures
core.get_dirlist(path,onlydirs) (possible in async calls)
^ path to get subdirs from
^ onlydirs should result contain only dirs?
^ returns list of folders within path
core.create_dir(absolute_path) (possible in async calls)
^ absolute_path to directory to create (needs to be absolute)
^ returns true/false
@ -90,7 +86,9 @@ core.sound_play(spec, looped) -> handle
core.sound_stop(handle)
core.get_video_drivers()
^ get list of video drivers supported by engine (not all modes are guaranteed to work)
^ returns list of available video drivers e.g. { "OpenGL", "Software" }
^ returns list of available video drivers' settings name and 'friendly' display name
^ e.g. { {name="opengl", friendly_name="OpenGL"}, {name="software", friendly_name="Software Renderer"} }
^ first element of returned list is guaranteed to be the NULL driver
Formspec:
core.update_formspec(formspec)
@ -143,6 +141,8 @@ core.get_game(index)
addon_mods_paths = {[1] = <path>,},
}
core.get_games() -> table of all games in upper format (possible in async calls)
core.get_mapgen_names([include_hidden=false]) -> table of map generator algorithms
registered in the core (possible in async calls)
Favorites:
core.get_favorites(location) -> list of favorites (possible in async calls)
@ -191,11 +191,15 @@ core.create_world(worldname, gameid)
core.delete_world(index)
Helpers:
core.get_us_time()
^ returns time with microsecond precision
core.gettext(string) -> string
^ look up the translation of a string in the gettext message catalog
fgettext(string, ...) -> string
fgettext_ne(string, ...)
^ call core.gettext(string), replace "$1"..."$9" with the given
^ extra arguments, call core.formspec_escape and return the result
^ extra arguments and return the result
fgettext(string, ...) -> string
^ same as fgettext_ne(), but calls core.formspec_escape before returning result
core.parse_json(string[, nullvalue]) -> something (possible in async calls)
^ see core.parse_json (lua_api.txt)
dump(obj, dumped={})
@ -207,6 +211,12 @@ string:trim()
core.is_yes(arg) (possible in async calls)
^ returns whether arg can be interpreted as yes
Version compat:
core.get_min_supp_proto()
^ returns the minimum supported network protocol version
core.get_max_supp_proto()
^ returns the maximum supported network protocol version
Async:
core.handle_async(async_job,parameters,finished)
^ execute a function asynchronously

View File

@ -1,12 +1,18 @@
.\" Minetest man page
.TH minetest 6 "10 September 2013" "" ""
.SH NAME
minetest \- Multiplayer infinite-world block sandbox
minetest, minetestserver \- Multiplayer infinite-world block sandbox
.SH SYNOPSIS
.B minetest
[ OPTION ... ]
[\fB--server SERVER OPTIONS\fR | \fBCLIENT OPTIONS\fR]
[\fBCOMMON OPTIONS\fR]
[\fBWORLD PATH\fR]
.B minetestserver
[\fBSERVER OPTIONS\fR]
[\fBCOMMON OPTIONS\fR]
[\fBWORLD PATH\fR]
.SH DESCRIPTION
.B Minetest
@ -14,74 +20,83 @@ is one of the first InfiniMiner/Minecraft(/whatever) inspired games (started Oct
.PP
The main design philosophy is to keep it technically simple, stable and portable. It will be kept lightweight enough to run on fairly old hardware.
.SH OPTIONS
.SH COMMON OPTIONS
.TP
\-\-address <value>
Address to connect to
.B \-\-help
Print allowed options and exit
.TP
\-\-config <value>
.B \-\-version
Print version information and exit
.TP
.B \-\-config <value>
Load configuration from specified file
.TP
\-\-disable\-unittests
Disable unit tests
.TP
\-\-enable\-unittests
Enable unit tests
.TP
\-\-gameid <value>
Set gameid
.TP
\-\-go
Disable main menu
.TP
\-\-help
Show allowed options
.TP
\-\-version
Show version information
.TP
\-\-logfile <value>
.B \-\-logfile <value>
Set logfile path (debug.txt)
.TP
\-\-map\-dir <value>
Same as \-\-world (deprecated)
.TP
\-\-name <value>
Set player name
.TP
\-\-password <value>
Set password
.TP
\-\-port <value>
Set network port (UDP) to use
.TP
\-\-random\-input
Enable random user input, for testing
.TP
\-\-server
Run dedicated server
.TP
\-\-speedtests
Run speed tests
.TP
\-\-videomodes
List available video modes
.TP
\-\-info
.B \-\-info
Print more information to console
.TP
\-\-verbose
.B \-\-verbose
Print even more information to console
.TP
\-\-trace
.B \-\-trace
Print enormous amounts of information to console
.TP
\-\-world <value>
Set world path
.B \-\-gameid <value>
Set gameid
.TP
\-\-migrate <value>
Migrate from current map backend to another. Possible values are sqlite3
and leveldb. Only works when using --server.
.B \-\-worldname <value>
Set world path by name
.TP
.B \-\-world <value> | list
Set world path or list worlds
.TP
.B \-\-map\-dir <value>
Same as \-\-world (deprecated)
.TP
.B \-\-port <value>
Set network port (UDP) to use
.TP
.B \-\-run\-unittests
Run unit tests and exit
.SH CLIENT OPTIONS
.TP
.B \-\-address <value>
Address to connect to
.TP
.B \-\-go
Disable main menu
.TP
.B \-\-name <value>
Set player name
.TP
.B \-\-password <value>
Set password
.TP
.B \-\-random\-input
Enable random user input, for testing (client only)
.TP
.B \-\-videomodes
List available video modes (client only)
.TP
.B \-\-speedtests
Run speed tests
.SH SERVER OPTIONS
.TP
.B \-\-migrate <value>
Migrate from current map backend to another. Possible values are sqlite3,
leveldb, redis, and dummy.
.TP
.B \-\-terminal
Display an interactive terminal over ncurses during execution.
.SH ENVIRONMENT
.TP
.B MINETEST_SUBGAME_PATH
Colon delimited list of directories to search for subgames.
.SH BUGS
Please report all bugs to Perttu Ahola <celeron55@gmail.com>.
@ -97,5 +112,3 @@ Juhani Numminen <juhaninumminen0@gmail.com>.
.SH WWW
http://www.minetest.net/
.SH "SEE ALSO"
.BR minetestserver(6)

View File

@ -1,77 +1,2 @@
.\" Minetestserver man page
.TH minetestserver 6 "10 September 2013" "" ""
.so man6/minetest.6
.SH NAME
minetestserver \- Minetest server
.SH SYNOPSIS
.B minetestserver
[ OPTION ... ]
.SH DESCRIPTION
.B Minetest
is one of the first InfiniMiner/Minecraft(/whatever) inspired games (started October 2010), with a goal of taking the survival multiplayer gameplay to a slightly different direction.
.PP
The main design philosophy is to keep it technically simple, stable and portable. It will be kept lightweight enough to run on fairly old hardware.
.SH OPTIONS
.TP
\-\-config <value>
Load configuration from specified file
.TP
\-\-disable\-unittests
Disable unit tests
.TP
\-\-enable\-unittests
Enable unit tests
.TP
\-\-gameid <value>
Set gameid
.TP
\-\-help
Show allowed options
.TP
\-\-version
Show version information
.TP
\-\-logfile <value>
Set logfile path (debug.txt)
.TP
\-\-map\-dir <value>
Same as \-\-world (deprecated)
.TP
\-\-port <value>
Set network port (UDP) to use
.TP
\-\-info
Print more information to console
.TP
\-\-verbose
Print even more information to console
.TP
\-\-trace
Print enormous amounts of information to console
.TP
\-\-world <value>
Set world path
.TP
\-\-migrate <value>
Migrate from current map backend to another. Possible values are sqlite3
and leveldb.
.SH BUGS
Please report all bugs to Perttu Ahola <celeron55@gmail.com>.
.SH AUTHOR
.PP
Perttu Ahola <celeron55@gmail.com>
and contributors.
.PP
This man page was originally written by
Juhani Numminen <juhaninumminen0@gmail.com>.
.SH WWW
http://www.minetest.net/
.SH "SEE ALSO"
.BR minetest(6)

35
doc/texture_overrides.txt Normal file
View File

@ -0,0 +1,35 @@
Texture Overrides
=================
You can override the textures of a node from a texture pack using
texture overrides. To do this, create a file in a texture pack
called override.txt
Basic Format
------------
Each line in an override.txt file is a rule. It consists of
nodename face-selector texture
For example,
default:dirt_with_grass sides default_stone.png
You can use ^ operators as usual:
default:dirt_with_grass sides default_stone.png^[brighten
Face Selectors
--------------
| face-selector | behavior |
|---------------|---------------------------------------------------|
| left | x- |
| right | x+ |
| front | z- |
| back | z+ |
| top | y+ |
| bottom | y- |
| sides | x-, x+, z-, z+ |
| all | All faces. You can also use '*' instead of 'all'. |

View File

@ -41,13 +41,23 @@ auth.txt
---------
Contains authentication data, player per line.
<name>:<password hash>:<privilege1,...>
Format of password hash is <name><password> SHA1'd, in the base64 encoding.
Legacy format (until 0.4.12) of password hash is <name><password> SHA1'd,
in the base64 encoding.
Format (since 0.4.13) of password hash is #1#<salt>#<verifier>, with the
parts inside <> encoded in the base64 encoding.
<verifier> is an RFC 2945 compatible SRP verifier,
of the given salt, password, and the player's name lowercased,
using the 2048-bit group specified in RFC 5054 and the SHA-256 hash function.
Example lines:
- Player "celeron55", no password, privileges "interact" and "shout":
celeron55::interact,shout
- Player "Foo", password "bar", privilege "shout":
- Player "Foo", password "bar", privilege "shout", with a legacy password hash:
foo:iEPX+SQWIR3p67lj/0zigSWTKHg:shout
- Player "Foo", password "bar", privilege "shout", with a 0.4.13 pw hash:
foo:#1#hPpy4O3IAn1hsNK00A6wNw#Kpu6rj7McsrPCt4euTb5RA5ltF7wdcWGoYMcRngwDi11cZhPuuR9i5Bo7o6A877TgcEwoc//HNrj9EjR/CGjdyTFmNhiermZOADvd8eu32FYK1kf7RMC0rXWxCenYuOQCG4WF9mMGiyTPxC63VAjAMuc1nCZzmy6D9zt0SIKxOmteI75pAEAIee2hx4OkSXRIiU4Zrxo1Xf7QFxkMY4x77vgaPcvfmuzom0y/fU1EdSnZeopGPvzMpFx80ODFx1P34R52nmVl0W8h4GNo0k8ZiWtRCdrJxs8xIg7z5P1h3Th/BJ0lwexpdK8sQZWng8xaO5ElthNuhO8UQx1l6FgEA:shout
- Player "bar", no password, no privileges:
bar::
@ -204,14 +214,14 @@ algorithm, defined here in Python:
def getBlockAsInteger(p):
return int64(p[2]*16777216 + p[1]*4096 + p[0])
def int64(u):
while u >= 2**63:
u -= 2**64
while u <= -2**63:
u += 2**64
return u
It can be converted the other way by using this code:
def getIntegerAsBlock(i):
@ -221,7 +231,7 @@ It can be converted the other way by using this code:
i = int((i - y) / 4096)
z = unsignedToSigned(i % 4096, 2048)
return x,y,z
def unsignedToSigned(i, max_positive):
if i < max_positive:
return i
@ -241,7 +251,7 @@ NOTE: Zlib data is in such a format that Python's zlib at least can
directly decompress.
u8 version
- map format version number, this one is version 22
- map format version number, see serialisation.h for the latest number
u8 flags
- Flag bitmasks:
@ -287,13 +297,26 @@ if content_width == 2:
zlib-compressed node metadata list
- content:
if map format version <= 22:
u16 version (=1)
u16 count of metadata
foreach count:
u16 position (p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
u16 type_id
u16 content_size
u8[content_size] (content of metadata)
u8[content_size] content of metadata. Format depends on type_id, see below.
if map format version >= 23:
u8 version (=1) -- Note the type is u8, while for map format version <= 22 it's u16
u16 count of metadata
foreach count:
u16 position (p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
u32 num_vars
foreach num_vars:
u16 key_len
u8[key_len] key
u32 val_len
u8[val_len] value
serialized inventory
- Node timers
if map format version == 23:
@ -308,6 +331,8 @@ if map format version == 24: (NOTE: Not released as stable)
u16 timer position (z*16*16 + y*16 + x)
s32 timeout*1000
s32 elapsed*1000
if map format version >= 25:
-- Nothing right here, node timers are serialized later
u8 static object version:
- Always 0
@ -367,8 +392,9 @@ The name-id-mapping
--------------------
The mapping maps node content ids to node names.
Node metadata format
---------------------
Node metadata format for map format versions <= 22
---------------------------------------------------
The node metadata are serialized depending on the type_id field.
1: Generic metadata
serialized inventory

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

BIN
fonts/lucida_sans_10.xml Executable file

Binary file not shown.

BIN
fonts/lucida_sans_100.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
fonts/lucida_sans_11.xml Executable file

Binary file not shown.

BIN
fonts/lucida_sans_110.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
fonts/lucida_sans_12.xml Executable file

Binary file not shown.

BIN
fonts/lucida_sans_120.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
fonts/lucida_sans_14.xml Executable file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More