Initial commit (NOT usable)
|
@ -0,0 +1,2 @@
|
||||||
|
*.cpp diff=cpp
|
||||||
|
*.h diff=cpp
|
|
@ -0,0 +1,65 @@
|
||||||
|
## Generic ignorable patterns and files
|
||||||
|
*~
|
||||||
|
.*.swp
|
||||||
|
*bak*
|
||||||
|
tags
|
||||||
|
*.vim
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
||||||
|
## Non-static Minetest directories
|
||||||
|
/bin/
|
||||||
|
/games/*
|
||||||
|
!/games/minimal/
|
||||||
|
/cache/
|
||||||
|
/textures/*
|
||||||
|
!/textures/base/
|
||||||
|
/sounds/
|
||||||
|
/mods/*
|
||||||
|
!/mods/minetest/
|
||||||
|
/mods/minetest/*
|
||||||
|
!/mods/minetest/mods_here.txt
|
||||||
|
/worlds/
|
||||||
|
/world/
|
||||||
|
|
||||||
|
## Configuration/log files
|
||||||
|
minetest.conf
|
||||||
|
debug.txt
|
||||||
|
|
||||||
|
## Build files
|
||||||
|
CMakeFiles/*
|
||||||
|
src/CMakeFiles/*
|
||||||
|
src/Makefile
|
||||||
|
src/cmake_config.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
|
||||||
|
CMakeCache.txt
|
||||||
|
CPackConfig.cmake
|
||||||
|
CPackSourceConfig.cmake
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
locale/
|
||||||
|
*.cbp
|
||||||
|
*.layout
|
||||||
|
*.o
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
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 keyserver.ubuntu.com --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: cmake . && make
|
||||||
|
notifications:
|
||||||
|
email: false
|
|
@ -0,0 +1,222 @@
|
||||||
|
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")
|
||||||
|
|
||||||
|
# This can be read from ${PROJECT_NAME} after project() is called
|
||||||
|
project(minetest)
|
||||||
|
|
||||||
|
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||||
|
|
||||||
|
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
||||||
|
set(VERSION_MAJOR 0)
|
||||||
|
set(VERSION_MINOR 4)
|
||||||
|
set(VERSION_PATCH 7)
|
||||||
|
if(VERSION_EXTRA)
|
||||||
|
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
|
||||||
|
endif()
|
||||||
|
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||||
|
|
||||||
|
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
|
||||||
|
|
||||||
|
# Configuration options
|
||||||
|
|
||||||
|
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")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# 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(WARN_ALL 1 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
|
||||||
|
find_package(Irrlicht)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Installation
|
||||||
|
#
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(SHAREDIR ".")
|
||||||
|
set(BINDIR "bin")
|
||||||
|
set(DOCDIR "doc")
|
||||||
|
set(EXAMPLE_CONF_DIR ".")
|
||||||
|
set(LOCALEDIR "locale")
|
||||||
|
elseif(APPLE)
|
||||||
|
# Random placeholders; this isn't usually used and may not work
|
||||||
|
# See https://github.com/toabi/minetest-mac/
|
||||||
|
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}")
|
||||||
|
set(BINDIR "bin")
|
||||||
|
set(DOCDIR "share/doc/${PROJECT_NAME}")
|
||||||
|
set(EXAMPLE_CONF_DIR ${DOCDIR})
|
||||||
|
set(LOCALEDIR "locale")
|
||||||
|
elseif(UNIX) # Linux, BSD etc
|
||||||
|
if(RUN_IN_PLACE)
|
||||||
|
set(SHAREDIR ".")
|
||||||
|
set(BINDIR "bin")
|
||||||
|
set(DOCDIR "doc")
|
||||||
|
set(EXAMPLE_CONF_DIR ".")
|
||||||
|
set(MANDIR "unix/man")
|
||||||
|
set(XDG_APPS_DIR "unix/applications")
|
||||||
|
set(ICONDIR "unix/icons")
|
||||||
|
set(LOCALEDIR "locale")
|
||||||
|
else()
|
||||||
|
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}")
|
||||||
|
set(BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
|
||||||
|
set(DOCDIR "${CMAKE_INSTALL_PREFIX}/share/doc/${PROJECT_NAME}")
|
||||||
|
set(MANDIR "${CMAKE_INSTALL_PREFIX}/share/man")
|
||||||
|
set(EXAMPLE_CONF_DIR ${DOCDIR})
|
||||||
|
set(XDG_APPS_DIR "${CMAKE_INSTALL_PREFIX}/share/applications")
|
||||||
|
set(ICONDIR "${CMAKE_INSTALL_PREFIX}/share/icons")
|
||||||
|
set(LOCALEDIR "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/locale")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CUSTOM_SHAREDIR "" CACHE STRING "Directory to install data files into")
|
||||||
|
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()
|
||||||
|
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)
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mods/mods_here.txt" DESTINATION "${SHAREDIR}/mods")
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/all/textures_here.txt" DESTINATION "${SHAREDIR}/textures/all")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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/mapformat.txt" DESTINATION "${DOCDIR}")
|
||||||
|
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
|
||||||
|
install(FILES "misc/minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
|
||||||
|
install(FILES "misc/minetest-icon.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
|
||||||
|
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")
|
||||||
|
set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
|
||||||
|
set(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
|
||||||
|
set(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
|
||||||
|
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()
|
||||||
|
|
||||||
|
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-win32")
|
||||||
|
|
||||||
|
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)
|
||||||
|
# TODO
|
||||||
|
# see http://cmake.org/Wiki/CMake:CPackPackageGenerators#Bundle_.28OSX_only.29
|
||||||
|
#
|
||||||
|
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-osx")
|
||||||
|
set(CPACK_PACKAGE_ICON "")
|
||||||
|
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
|
||||||
|
set(CPACK_BUNDLE_ICON "")
|
||||||
|
set(CPACK_BUNDLE_PLIST "")
|
||||||
|
set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/${PROJECT_NAME}")
|
||||||
|
set(CPACK_GENERATOR "Bundle")
|
||||||
|
else()
|
||||||
|
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux")
|
||||||
|
set(CPACK_GENERATOR TGZ)
|
||||||
|
set(CPACK_SOURCE_GENERATOR TGZ)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CPack)
|
||||||
|
|
|
@ -0,0 +1,398 @@
|
||||||
|
Minetest
|
||||||
|
============
|
||||||
|
|
||||||
|
An InfiniMiner/Minecraft inspired game.
|
||||||
|
|
||||||
|
Copyright (c) 2010-2013 Perttu Ahola <celeron55@gmail.com>
|
||||||
|
and contributors (see source file comments and the version control log)
|
||||||
|
|
||||||
|
In case you downloaded the source code:
|
||||||
|
---------------------------------------
|
||||||
|
If you downloaded the Minetest Engine source code in which this file is
|
||||||
|
contained, you probably want to download the minetest_game project too:
|
||||||
|
https://github.com/minetest/minetest_game/
|
||||||
|
See the README.txt in it.
|
||||||
|
|
||||||
|
Further documentation
|
||||||
|
----------------------
|
||||||
|
- Website: http://minetest.net/
|
||||||
|
- Wiki: http://wiki.minetest.com/
|
||||||
|
- Developer wiki: http://dev.minetest.net/
|
||||||
|
- Forum: http://forum.minetest.net/
|
||||||
|
- Github: https://github.com/minetest/minetest/
|
||||||
|
- doc/ directory of source distribution
|
||||||
|
|
||||||
|
This game is not finished
|
||||||
|
--------------------------
|
||||||
|
- Don't expect it to work as well as a finished game will.
|
||||||
|
- Please report any bugs. When doing that, debug.txt is useful.
|
||||||
|
|
||||||
|
Default Controls
|
||||||
|
-----------------
|
||||||
|
- WASD: move
|
||||||
|
- Space: jump/climb
|
||||||
|
- Shift: sneak/go down
|
||||||
|
- Q: drop item
|
||||||
|
- I: inventory
|
||||||
|
- Mouse: turn/look
|
||||||
|
- Mouse left: dig/punch
|
||||||
|
- Mouse right: place/use
|
||||||
|
- Mouse wheel: select item
|
||||||
|
- Esc: pause menu
|
||||||
|
- T: chat
|
||||||
|
- Settable in the configuration file, see the section below.
|
||||||
|
|
||||||
|
Paths
|
||||||
|
------
|
||||||
|
$bin - Compiled binaries
|
||||||
|
$share - Distributed read-only data
|
||||||
|
$user - User-created modifiable data
|
||||||
|
|
||||||
|
Windows .zip / RUN_IN_PLACE source:
|
||||||
|
$bin = bin
|
||||||
|
$share = .
|
||||||
|
$user = .
|
||||||
|
|
||||||
|
Linux installed:
|
||||||
|
$bin = /usr/bin
|
||||||
|
$share = /usr/share/minetest
|
||||||
|
$user = ~/.minetest
|
||||||
|
|
||||||
|
OS X:
|
||||||
|
$bin = ?
|
||||||
|
$share = ?
|
||||||
|
$user = ~/Library/Application Support/minetest
|
||||||
|
|
||||||
|
World directory
|
||||||
|
----------------
|
||||||
|
- Worlds can be found as separate folders in:
|
||||||
|
$user/worlds/
|
||||||
|
|
||||||
|
Configuration file:
|
||||||
|
-------------------
|
||||||
|
- Default location:
|
||||||
|
$user/minetest.conf
|
||||||
|
- It is created by Minetest when it is ran the first time.
|
||||||
|
- A specific file can be specified on the command line:
|
||||||
|
--config <path-to-file>
|
||||||
|
|
||||||
|
Command-line options:
|
||||||
|
---------------------
|
||||||
|
- Use --help
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
$ tar xf master.tar.gz
|
||||||
|
$ cd minetest-minetest-286edd4 (or similar)
|
||||||
|
|
||||||
|
Download minetest_game (otherwise only the "Minimal development test" game is available)
|
||||||
|
$ 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
|
||||||
|
$ cd ..
|
||||||
|
|
||||||
|
Build a version that runs directly from the source directory:
|
||||||
|
$ cmake . -DRUN_IN_PLACE=1
|
||||||
|
$ make -j2
|
||||||
|
|
||||||
|
Run it:
|
||||||
|
$ cd 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
|
||||||
|
- 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
|
||||||
|
|
||||||
|
Compiling on Windows:
|
||||||
|
---------------------
|
||||||
|
- This section is outdated. In addition to what is described here:
|
||||||
|
- In addition to minetest, you need to download minetest_game.
|
||||||
|
- If you wish to have sound support, you need libogg, libvorbis and libopenal
|
||||||
|
|
||||||
|
- You need:
|
||||||
|
* CMake:
|
||||||
|
http://www.cmake.org/cmake/resources/software.html
|
||||||
|
* MinGW or Visual Studio
|
||||||
|
http://www.mingw.org/
|
||||||
|
http://msdn.microsoft.com/en-us/vstudio/default
|
||||||
|
* Irrlicht SDK 1.7:
|
||||||
|
http://irrlicht.sourceforge.net/downloads.html
|
||||||
|
* Zlib headers (zlib125.zip)
|
||||||
|
http://www.winimage.com/zLibDll/index.html
|
||||||
|
* Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
|
||||||
|
http://www.winimage.com/zLibDll/index.html
|
||||||
|
* Optional: gettext library and tools:
|
||||||
|
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
|
||||||
|
- Steps:
|
||||||
|
- Select a directory called DIR hereafter in which you will operate.
|
||||||
|
- Make sure you have CMake and a compiler installed.
|
||||||
|
- Download all the other stuff to DIR and extract them into there.
|
||||||
|
("extract here", not "extract to packagename/")
|
||||||
|
NOTE: zlib125dll.zip needs to be extracted into zlib125dll
|
||||||
|
- All those packages contain a nice base directory in them, which
|
||||||
|
should end up being the direct subdirectories of DIR.
|
||||||
|
- You will end up with a directory structure like this (+=dir, -=file):
|
||||||
|
-----------------
|
||||||
|
+ DIR
|
||||||
|
- zlib-1.2.5.tar.gz
|
||||||
|
- zlib125dll.zip
|
||||||
|
- irrlicht-1.7.1.zip
|
||||||
|
- 110214175330.zip (or whatever, this is the minetest source)
|
||||||
|
+ zlib-1.2.5
|
||||||
|
- zlib.h
|
||||||
|
+ win32
|
||||||
|
...
|
||||||
|
+ zlib125dll
|
||||||
|
- readme.txt
|
||||||
|
+ dll32
|
||||||
|
...
|
||||||
|
+ irrlicht-1.7.1
|
||||||
|
+ lib
|
||||||
|
+ include
|
||||||
|
...
|
||||||
|
+ gettext (optional)
|
||||||
|
+bin
|
||||||
|
+include
|
||||||
|
+lib
|
||||||
|
+ minetest
|
||||||
|
+ src
|
||||||
|
+ doc
|
||||||
|
- CMakeLists.txt
|
||||||
|
...
|
||||||
|
-----------------
|
||||||
|
- Start up the CMake GUI
|
||||||
|
- Select "Browse Source..." and select DIR/minetest
|
||||||
|
- Now, if using MSVC:
|
||||||
|
- Select "Browse Build..." and select DIR/minetest-build
|
||||||
|
- Else if using MinGW:
|
||||||
|
- Select "Browse Build..." and select DIR/minetest
|
||||||
|
- Select "Configure"
|
||||||
|
- Select your compiler
|
||||||
|
- It will warn about missing stuff, ignore that at this point. (later don't)
|
||||||
|
- Make sure the configuration is as follows
|
||||||
|
(note that the versions may differ for you):
|
||||||
|
-----------------
|
||||||
|
BUILD_CLIENT [X]
|
||||||
|
BUILD_SERVER [ ]
|
||||||
|
CMAKE_BUILD_TYPE Release
|
||||||
|
CMAKE_INSTALL_PREFIX DIR/minetest-install
|
||||||
|
IRRLICHT_SOURCE_DIR DIR/irrlicht-1.7.1
|
||||||
|
RUN_IN_PLACE [X]
|
||||||
|
WARN_ALL [ ]
|
||||||
|
ZLIB_DLL DIR/zlib125dll/dll32/zlibwapi.dll
|
||||||
|
ZLIB_INCLUDE_DIR DIR/zlib-1.2.5
|
||||||
|
ZLIB_LIBRARIES DIR/zlib125dll/dll32/zlibwapi.lib
|
||||||
|
GETTEXT_BIN_DIR DIR/gettext/bin
|
||||||
|
GETTEXT_INCLUDE_DIR DIR/gettext/include
|
||||||
|
GETTEXT_LIBRARIES DIR/gettext/lib/intl.lib
|
||||||
|
GETTEXT_MSGFMT DIR/gettext/bin/msgfmt
|
||||||
|
-----------------
|
||||||
|
- Hit "Configure"
|
||||||
|
- Hit "Configure" once again 8)
|
||||||
|
- If something is still coloured red, you have a problem.
|
||||||
|
- Hit "Generate"
|
||||||
|
If using MSVC:
|
||||||
|
- Open the generated minetest.sln
|
||||||
|
- The project defaults to the "Debug" configuration. Make very sure to
|
||||||
|
select "Release", unless you want to debug some stuff (it's slower
|
||||||
|
and might not even work at all)
|
||||||
|
- Build the ALL_BUILD project
|
||||||
|
- Build the INSTALL project
|
||||||
|
- You should now have a working game with the executable in
|
||||||
|
DIR/minetest-install/bin/minetest.exe
|
||||||
|
- Additionally you may create a zip package by building the PACKAGE
|
||||||
|
project.
|
||||||
|
If using MinGW:
|
||||||
|
- Using the command line, browse to the build directory and run 'make'
|
||||||
|
(or mingw32-make or whatever it happens to be)
|
||||||
|
- You may need to copy some of the downloaded DLLs into bin/, see what
|
||||||
|
running the produced executable tells you it doesn't have.
|
||||||
|
- You should now have a working game with the executable in
|
||||||
|
DIR/minetest/bin/minetest.exe
|
||||||
|
|
||||||
|
Windows releases of minetest are built using a bat script like this:
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
set sourcedir=%CD%
|
||||||
|
set installpath="C:\tmp\minetest_install"
|
||||||
|
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%
|
||||||
|
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
|
||||||
|
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" INSTALL.vcxproj /p:Configuration=Release
|
||||||
|
if %errorlevel% neq 0 goto fail
|
||||||
|
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" PACKAGE.vcxproj /p:Configuration=Release
|
||||||
|
if %errorlevel% neq 0 goto fail
|
||||||
|
popd
|
||||||
|
echo Finished.
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
:fail
|
||||||
|
popd
|
||||||
|
echo Failed.
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
License of Minetest textures and sounds
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
This applies to textures and sounds contained in the main Minetest
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||||
|
http://creativecommons.org/licenses/by-sa/3.0/
|
||||||
|
|
||||||
|
Authors of media files
|
||||||
|
-----------------------
|
||||||
|
Everything not listed in here:
|
||||||
|
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
BlockMen:
|
||||||
|
textures/base/pack/menuheader.png
|
||||||
|
|
||||||
|
erlehmann:
|
||||||
|
misc/minetest-icon-24x24.png
|
||||||
|
misc/minetest-icon.ico
|
||||||
|
misc/minetest-icon.svg
|
||||||
|
textures/base/pack/logo.png
|
||||||
|
|
||||||
|
License of Minetest source code
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Irrlicht
|
||||||
|
---------------
|
||||||
|
|
||||||
|
This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/
|
||||||
|
|
||||||
|
The Irrlicht Engine License
|
||||||
|
|
||||||
|
Copyright © 2002-2005 Nikolaus Gebhardt
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute
|
||||||
|
it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you
|
||||||
|
must not claim that you wrote the original software. If you use
|
||||||
|
this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must
|
||||||
|
not be misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
|
||||||
|
JThread
|
||||||
|
---------------
|
||||||
|
|
||||||
|
This program uses the JThread library. License for JThread follows:
|
||||||
|
|
||||||
|
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Lua
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Lua is licensed under the terms of the MIT license reproduced below.
|
||||||
|
This means that Lua is free software and can be used for both academic
|
||||||
|
and commercial purposes at absolutely no cost.
|
||||||
|
|
||||||
|
For details and rationale, see http://www.lua.org/license.html .
|
||||||
|
|
||||||
|
Copyright (C) 1994-2008 Lua.org, PUC-Rio.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
Fonts
|
||||||
|
---------------
|
||||||
|
|
||||||
|
DejaVu Sans Mono:
|
||||||
|
|
||||||
|
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||||
|
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||||
|
|
||||||
|
Bitstream Vera Fonts Copyright:
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||||
|
a trademark of Bitstream, Inc.
|
||||||
|
|
||||||
|
Arev Fonts Copyright:
|
||||||
|
|
||||||
|
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||||
|
|
||||||
|
Liberation Fonts Copyright:
|
||||||
|
|
||||||
|
Copyright (c) 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
* make it generate the map (by taking screenshots)
|
||||||
|
* remove all "useless" functionnality
|
||||||
|
-> Make the "client" directly read the database, and remove support for server
|
||||||
|
-> Remove entities (who cares about entities in a static map)
|
||||||
|
-> Remove all UI (except, maybe, a world/file selection dialog)
|
||||||
|
* get all chunks before taking screenshot
|
||||||
|
* fix aspect ratio (current values are quite random, maybe find out the exact ones)
|
||||||
|
|
||||||
|
Reminder:
|
||||||
|
|
||||||
|
[map chunk position]
|
||||||
|
(player position)
|
||||||
|
|
||||||
|
|
||||||
|
[0,1] [1,1]
|
||||||
|
(-20,25,20) (-10,25,30)
|
||||||
|
|
||||||
|
|
||||||
|
[0,0] [1,0]
|
||||||
|
(0,25,0) (10,25,10)
|
|
@ -0,0 +1,188 @@
|
||||||
|
-- Minetest: builtin/auth.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Authentication handler
|
||||||
|
--
|
||||||
|
|
||||||
|
function minetest.string_to_privs(str, delim)
|
||||||
|
assert(type(str) == "string")
|
||||||
|
delim = delim or ','
|
||||||
|
privs = {}
|
||||||
|
for _, priv in pairs(string.split(str, delim)) do
|
||||||
|
privs[priv:trim()] = true
|
||||||
|
end
|
||||||
|
return privs
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.privs_to_string(privs, delim)
|
||||||
|
assert(type(privs) == "table")
|
||||||
|
delim = delim or ','
|
||||||
|
list = {}
|
||||||
|
for priv, bool in pairs(privs) do
|
||||||
|
if bool then
|
||||||
|
table.insert(list, priv)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(list, delim)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(minetest.string_to_privs("a,b").b == true)
|
||||||
|
assert(minetest.privs_to_string({a=true,b=true}) == "a,b")
|
||||||
|
|
||||||
|
minetest.auth_file_path = minetest.get_worldpath().."/auth.txt"
|
||||||
|
minetest.auth_table = {}
|
||||||
|
|
||||||
|
local function read_auth_file()
|
||||||
|
local newtable = {}
|
||||||
|
local file, errmsg = io.open(minetest.auth_file_path, 'rb')
|
||||||
|
if not file then
|
||||||
|
minetest.log("info", minetest.auth_file_path.." could not be opened for reading ("..errmsg.."); assuming new world")
|
||||||
|
return
|
||||||
|
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
|
||||||
|
error("Invalid line in auth.txt: "..dump(line))
|
||||||
|
end
|
||||||
|
local privileges = minetest.string_to_privs(privilegestring)
|
||||||
|
newtable[name] = {password=password, privileges=privileges}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
io.close(file)
|
||||||
|
minetest.auth_table = newtable
|
||||||
|
minetest.notify_authentication_modified()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function save_auth_file()
|
||||||
|
local newtable = {}
|
||||||
|
-- Check table for validness before attempting to save
|
||||||
|
for name, stuff in pairs(minetest.auth_table) do
|
||||||
|
assert(type(name) == "string")
|
||||||
|
assert(name ~= "")
|
||||||
|
assert(type(stuff) == "table")
|
||||||
|
assert(type(stuff.password) == "string")
|
||||||
|
assert(type(stuff.privileges) == "table")
|
||||||
|
end
|
||||||
|
local file, errmsg = io.open(minetest.auth_file_path, 'w+b')
|
||||||
|
if not file then
|
||||||
|
error(minetest.auth_file_path.." could not be opened for writing: "..errmsg)
|
||||||
|
end
|
||||||
|
for name, stuff in pairs(minetest.auth_table) do
|
||||||
|
local privstring = minetest.privs_to_string(stuff.privileges)
|
||||||
|
file:write(name..":"..stuff.password..":"..privstring..'\n')
|
||||||
|
end
|
||||||
|
io.close(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
read_auth_file()
|
||||||
|
|
||||||
|
minetest.builtin_auth_handler = {
|
||||||
|
get_auth = function(name)
|
||||||
|
assert(type(name) == "string")
|
||||||
|
-- Figure out what password to use for a new player (singleplayer
|
||||||
|
-- always has an empty password, otherwise use default, which is
|
||||||
|
-- usually empty too)
|
||||||
|
local new_password_hash = ""
|
||||||
|
-- If not in authentication table, return nil
|
||||||
|
if not minetest.auth_table[name] then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
-- Figure out what privileges the player should have.
|
||||||
|
-- Take a copy of the privilege table
|
||||||
|
local privileges = {}
|
||||||
|
for priv, _ in pairs(minetest.auth_table[name].privileges) do
|
||||||
|
privileges[priv] = true
|
||||||
|
end
|
||||||
|
-- If singleplayer, give all privileges except those marked as give_to_singleplayer = false
|
||||||
|
if minetest.is_singleplayer() then
|
||||||
|
for priv, def in pairs(minetest.registered_privileges) do
|
||||||
|
if def.give_to_singleplayer then
|
||||||
|
privileges[priv] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- For the admin, give everything
|
||||||
|
elseif name == minetest.setting_get("name") then
|
||||||
|
for priv, def in pairs(minetest.registered_privileges) do
|
||||||
|
privileges[priv] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- All done
|
||||||
|
return {
|
||||||
|
password = minetest.auth_table[name].password,
|
||||||
|
privileges = privileges,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
create_auth = function(name, password)
|
||||||
|
assert(type(name) == "string")
|
||||||
|
assert(type(password) == "string")
|
||||||
|
minetest.log('info', "Built-in authentication handler adding player '"..name.."'")
|
||||||
|
minetest.auth_table[name] = {
|
||||||
|
password = password,
|
||||||
|
privileges = minetest.string_to_privs(minetest.setting_get("default_privs")),
|
||||||
|
}
|
||||||
|
save_auth_file()
|
||||||
|
end,
|
||||||
|
set_password = function(name, password)
|
||||||
|
assert(type(name) == "string")
|
||||||
|
assert(type(password) == "string")
|
||||||
|
if not minetest.auth_table[name] then
|
||||||
|
minetest.builtin_auth_handler.create_auth(name, password)
|
||||||
|
else
|
||||||
|
minetest.log('info', "Built-in authentication handler setting password of player '"..name.."'")
|
||||||
|
minetest.auth_table[name].password = password
|
||||||
|
save_auth_file()
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
set_privileges = function(name, privileges)
|
||||||
|
assert(type(name) == "string")
|
||||||
|
assert(type(privileges) == "table")
|
||||||
|
if not minetest.auth_table[name] then
|
||||||
|
minetest.builtin_auth_handler.create_auth(name, minetest.get_password_hash(name, minetest.setting_get("default_password")))
|
||||||
|
end
|
||||||
|
minetest.auth_table[name].privileges = privileges
|
||||||
|
minetest.notify_authentication_modified(name)
|
||||||
|
save_auth_file()
|
||||||
|
end,
|
||||||
|
reload = function()
|
||||||
|
read_auth_file()
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
function minetest.register_authentication_handler(handler)
|
||||||
|
if minetest.registered_auth_handler then
|
||||||
|
error("Add-on authentication handler already registered by "..minetest.registered_auth_handler_modname)
|
||||||
|
end
|
||||||
|
minetest.registered_auth_handler = handler
|
||||||
|
minetest.registered_auth_handler_modname = minetest.get_current_modname()
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.get_auth_handler()
|
||||||
|
if minetest.registered_auth_handler then
|
||||||
|
return minetest.registered_auth_handler
|
||||||
|
end
|
||||||
|
return minetest.builtin_auth_handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.set_player_password(name, password)
|
||||||
|
if minetest.get_auth_handler().set_password then
|
||||||
|
minetest.get_auth_handler().set_password(name, password)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.set_player_privs(name, privs)
|
||||||
|
if minetest.get_auth_handler().set_privileges then
|
||||||
|
minetest.get_auth_handler().set_privileges(name, privs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.auth_reload()
|
||||||
|
if minetest.get_auth_handler().reload then
|
||||||
|
return minetest.get_auth_handler().reload()
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
--
|
||||||
|
-- This file contains built-in stuff in Minetest implemented in Lua.
|
||||||
|
--
|
||||||
|
-- It is always loaded and executed after registration of the C API,
|
||||||
|
-- before loading and running any mods.
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Initialize some very basic things
|
||||||
|
print = minetest.debug
|
||||||
|
math.randomseed(os.time())
|
||||||
|
os.setlocale("C", "numeric")
|
||||||
|
|
||||||
|
-- Load other files
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/serialize.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/misc_helpers.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/item.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/misc_register.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/item_entity.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/deprecated.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/misc.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/privileges.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/auth.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/chatcommands.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/static_spawn.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/detached_inventory.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/falling.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/features.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/voxelarea.lua")
|
|
@ -0,0 +1,687 @@
|
||||||
|
-- Minetest: builtin/chatcommands.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Chat command handler
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.chatcommands = {}
|
||||||
|
function minetest.register_chatcommand(cmd, def)
|
||||||
|
def = def or {}
|
||||||
|
def.params = def.params or ""
|
||||||
|
def.description = def.description or ""
|
||||||
|
def.privs = def.privs or {}
|
||||||
|
minetest.chatcommands[cmd] = def
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_chat_message(function(name, message)
|
||||||
|
local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
|
||||||
|
if not param then
|
||||||
|
param = ""
|
||||||
|
end
|
||||||
|
local cmd_def = minetest.chatcommands[cmd]
|
||||||
|
if cmd_def then
|
||||||
|
local has_privs, missing_privs = minetest.check_player_privs(name, cmd_def.privs)
|
||||||
|
if has_privs then
|
||||||
|
cmd_def.func(name, param)
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, "You don't have permission to run this command (missing privileges: "..table.concat(missing_privs, ", ")..")")
|
||||||
|
end
|
||||||
|
return true -- handled chat message
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Chat commands
|
||||||
|
--
|
||||||
|
minetest.register_chatcommand("me", {
|
||||||
|
params = "<action>",
|
||||||
|
description = "chat action (eg. /me orders a pizza)",
|
||||||
|
privs = {shout=true},
|
||||||
|
func = function(name, param)
|
||||||
|
minetest.chat_send_all("* " .. name .. " " .. param)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("help", {
|
||||||
|
privs = {},
|
||||||
|
params = "(nothing)/all/privs/<cmd>",
|
||||||
|
description = "Get help for commands or list privileges",
|
||||||
|
func = function(name, param)
|
||||||
|
local format_help_line = function(cmd, def)
|
||||||
|
local msg = "/"..cmd
|
||||||
|
if def.params and def.params ~= "" then msg = msg .. " " .. def.params end
|
||||||
|
if def.description and def.description ~= "" then msg = msg .. ": " .. def.description end
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
if param == "" then
|
||||||
|
local msg = ""
|
||||||
|
cmds = {}
|
||||||
|
for cmd, def in pairs(minetest.chatcommands) do
|
||||||
|
if minetest.check_player_privs(name, def.privs) then
|
||||||
|
table.insert(cmds, cmd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, "Available commands: "..table.concat(cmds, " "))
|
||||||
|
minetest.chat_send_player(name, "Use '/help <cmd>' to get more information, or '/help all' to list everything.")
|
||||||
|
elseif param == "all" then
|
||||||
|
minetest.chat_send_player(name, "Available commands:")
|
||||||
|
for cmd, def in pairs(minetest.chatcommands) do
|
||||||
|
if minetest.check_player_privs(name, def.privs) then
|
||||||
|
minetest.chat_send_player(name, format_help_line(cmd, def))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif param == "privs" then
|
||||||
|
minetest.chat_send_player(name, "Available privileges:")
|
||||||
|
for priv, def in pairs(minetest.registered_privileges) do
|
||||||
|
minetest.chat_send_player(name, priv..": "..def.description)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local cmd = param
|
||||||
|
def = minetest.chatcommands[cmd]
|
||||||
|
if not def then
|
||||||
|
minetest.chat_send_player(name, "Command not available: "..cmd)
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, format_help_line(cmd, def))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("privs", {
|
||||||
|
params = "<name>",
|
||||||
|
description = "print out privileges of player",
|
||||||
|
func = function(name, param)
|
||||||
|
if param == "" then
|
||||||
|
param = name
|
||||||
|
else
|
||||||
|
--[[if not minetest.check_player_privs(name, {privs=true}) then
|
||||||
|
minetest.chat_send_player(name, "Privileges of "..param.." are hidden from you.")
|
||||||
|
return
|
||||||
|
end]]
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, "Privileges of "..param..": "..minetest.privs_to_string(minetest.get_player_privs(param), ' '))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("grant", {
|
||||||
|
params = "<name> <privilege>|all",
|
||||||
|
description = "Give privilege to player",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
if not minetest.check_player_privs(name, {privs=true}) and
|
||||||
|
not minetest.check_player_privs(name, {basic_privs=true}) then
|
||||||
|
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
|
||||||
|
if not grantname or not grantprivstr then
|
||||||
|
minetest.chat_send_player(name, "Invalid parameters (see /help grant)")
|
||||||
|
return
|
||||||
|
elseif not minetest.auth_table[grantname] then
|
||||||
|
minetest.chat_send_player(name, "Player "..grantname.." does not exist.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local grantprivs = minetest.string_to_privs(grantprivstr)
|
||||||
|
if grantprivstr == "all" then
|
||||||
|
grantprivs = minetest.registered_privileges
|
||||||
|
end
|
||||||
|
local privs = minetest.get_player_privs(grantname)
|
||||||
|
local privs_known = true
|
||||||
|
for priv, _ in pairs(grantprivs) do
|
||||||
|
if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and not minetest.check_player_privs(name, {privs=true}) then
|
||||||
|
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not minetest.registered_privileges[priv] then
|
||||||
|
minetest.chat_send_player(name, "Unknown privilege: "..priv)
|
||||||
|
privs_known = false
|
||||||
|
end
|
||||||
|
privs[priv] = true
|
||||||
|
end
|
||||||
|
if not privs_known then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
minetest.set_player_privs(grantname, privs)
|
||||||
|
minetest.log(name..' granted ('..minetest.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
|
||||||
|
minetest.chat_send_player(name, "Privileges of "..grantname..": "..minetest.privs_to_string(minetest.get_player_privs(grantname), ' '))
|
||||||
|
if grantname ~= name then
|
||||||
|
minetest.chat_send_player(grantname, name.." granted you privileges: "..minetest.privs_to_string(grantprivs, ' '))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("revoke", {
|
||||||
|
params = "<name> <privilege>|all",
|
||||||
|
description = "Remove privilege from player",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
if not minetest.check_player_privs(name, {privs=true}) and
|
||||||
|
not minetest.check_player_privs(name, {basic_privs=true}) then
|
||||||
|
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
|
||||||
|
if not revokename or not revokeprivstr then
|
||||||
|
minetest.chat_send_player(name, "Invalid parameters (see /help revoke)")
|
||||||
|
return
|
||||||
|
elseif not minetest.auth_table[revokename] then
|
||||||
|
minetest.chat_send_player(name, "Player "..revokename.." does not exist.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local revokeprivs = minetest.string_to_privs(revokeprivstr)
|
||||||
|
local privs = minetest.get_player_privs(revokename)
|
||||||
|
for priv, _ in pairs(revokeprivs) do
|
||||||
|
if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and not minetest.check_player_privs(name, {privs=true}) then
|
||||||
|
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if revokeprivstr == "all" then
|
||||||
|
privs = {}
|
||||||
|
else
|
||||||
|
for priv, _ in pairs(revokeprivs) do
|
||||||
|
privs[priv] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.set_player_privs(revokename, privs)
|
||||||
|
minetest.log(name..' revoked ('..minetest.privs_to_string(revokeprivs, ', ')..') privileges from '..revokename)
|
||||||
|
minetest.chat_send_player(name, "Privileges of "..revokename..": "..minetest.privs_to_string(minetest.get_player_privs(revokename), ' '))
|
||||||
|
if revokename ~= name then
|
||||||
|
minetest.chat_send_player(revokename, name.." revoked privileges from you: "..minetest.privs_to_string(revokeprivs, ' '))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("setpassword", {
|
||||||
|
params = "<name> <password>",
|
||||||
|
description = "set given password",
|
||||||
|
privs = {password=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local toname, raw_password = string.match(param, "^([^ ]+) +(.+)$")
|
||||||
|
if not toname then
|
||||||
|
toname = string.match(param, "^([^ ]+) *$")
|
||||||
|
raw_password = nil
|
||||||
|
end
|
||||||
|
if not toname then
|
||||||
|
minetest.chat_send_player(name, "Name field required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local actstr = "?"
|
||||||
|
if not raw_password then
|
||||||
|
minetest.set_player_password(toname, "")
|
||||||
|
actstr = "cleared"
|
||||||
|
else
|
||||||
|
minetest.set_player_password(toname, minetest.get_password_hash(toname, raw_password))
|
||||||
|
actstr = "set"
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, "Password of player \""..toname.."\" "..actstr)
|
||||||
|
if toname ~= name then
|
||||||
|
minetest.chat_send_player(toname, "Your password was "..actstr.." by "..name)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("clearpassword", {
|
||||||
|
params = "<name>",
|
||||||
|
description = "set empty password",
|
||||||
|
privs = {password=true},
|
||||||
|
func = function(name, param)
|
||||||
|
toname = param
|
||||||
|
if toname == "" then
|
||||||
|
minetest.chat_send_player(name, "Name field required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
minetest.set_player_password(toname, '')
|
||||||
|
minetest.chat_send_player(name, "Password of player \""..toname.."\" cleared")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("auth_reload", {
|
||||||
|
params = "",
|
||||||
|
description = "reload authentication data",
|
||||||
|
privs = {server=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local done = minetest.auth_reload()
|
||||||
|
if done then
|
||||||
|
minetest.chat_send_player(name, "Done.")
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, "Failed.")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("teleport", {
|
||||||
|
params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
|
||||||
|
description = "teleport to given position",
|
||||||
|
privs = {teleport=true},
|
||||||
|
func = function(name, param)
|
||||||
|
-- Returns (pos, true) if found, otherwise (pos, false)
|
||||||
|
local function find_free_position_near(pos)
|
||||||
|
local tries = {
|
||||||
|
{x=1,y=0,z=0},
|
||||||
|
{x=-1,y=0,z=0},
|
||||||
|
{x=0,y=0,z=1},
|
||||||
|
{x=0,y=0,z=-1},
|
||||||
|
}
|
||||||
|
for _, d in ipairs(tries) do
|
||||||
|
local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z}
|
||||||
|
local n = minetest.get_node(p)
|
||||||
|
if not minetest.registered_nodes[n.name].walkable then
|
||||||
|
return p, true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return pos, false
|
||||||
|
end
|
||||||
|
|
||||||
|
local teleportee = nil
|
||||||
|
local p = {}
|
||||||
|
p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||||
|
teleportee = minetest.get_player_by_name(name)
|
||||||
|
if teleportee and p.x and p.y and p.z then
|
||||||
|
minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")")
|
||||||
|
teleportee:setpos(p)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local teleportee = nil
|
||||||
|
local p = nil
|
||||||
|
local target_name = nil
|
||||||
|
target_name = string.match(param, "^([^ ]+)$")
|
||||||
|
teleportee = minetest.get_player_by_name(name)
|
||||||
|
if target_name then
|
||||||
|
local target = minetest.get_player_by_name(target_name)
|
||||||
|
if target then
|
||||||
|
p = target:getpos()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if teleportee and p then
|
||||||
|
p = find_free_position_near(p)
|
||||||
|
minetest.chat_send_player(name, "Teleporting to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
|
||||||
|
teleportee:setpos(p)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.check_player_privs(name, {bring=true}) then
|
||||||
|
local teleportee = nil
|
||||||
|
local p = {}
|
||||||
|
local teleportee_name = nil
|
||||||
|
teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||||
|
if teleportee_name then
|
||||||
|
teleportee = minetest.get_player_by_name(teleportee_name)
|
||||||
|
end
|
||||||
|
if teleportee and p.x and p.y and p.z then
|
||||||
|
minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to ("..p.x..", "..p.y..", "..p.z..")")
|
||||||
|
teleportee:setpos(p)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local teleportee = nil
|
||||||
|
local p = nil
|
||||||
|
local teleportee_name = nil
|
||||||
|
local target_name = nil
|
||||||
|
teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$")
|
||||||
|
if teleportee_name then
|
||||||
|
teleportee = minetest.get_player_by_name(teleportee_name)
|
||||||
|
end
|
||||||
|
if target_name then
|
||||||
|
local target = minetest.get_player_by_name(target_name)
|
||||||
|
if target then
|
||||||
|
p = target:getpos()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if teleportee and p then
|
||||||
|
p = find_free_position_near(p)
|
||||||
|
minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
|
||||||
|
teleportee:setpos(p)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.chat_send_player(name, "Invalid parameters (\""..param.."\") or player not found (see /help teleport)")
|
||||||
|
return
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("set", {
|
||||||
|
params = "[-n] <name> <value> | <name>",
|
||||||
|
description = "set or read server configuration setting",
|
||||||
|
privs = {server=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
|
||||||
|
if arg and arg == "-n" and setname and setvalue then
|
||||||
|
minetest.setting_set(setname, setvalue)
|
||||||
|
minetest.chat_send_player(name, setname.." = "..setvalue)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local setname, setvalue = string.match(param, "([^ ]+) (.+)")
|
||||||
|
if setname and setvalue then
|
||||||
|
if not minetest.setting_get(setname) then
|
||||||
|
minetest.chat_send_player(name, "Failed. Use '/set -n <name> <value>' to create a new setting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
minetest.setting_set(setname, setvalue)
|
||||||
|
minetest.chat_send_player(name, setname.." = "..setvalue)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local setname = string.match(param, "([^ ]+)")
|
||||||
|
if setname then
|
||||||
|
local setvalue = minetest.setting_get(setname)
|
||||||
|
if not setvalue then
|
||||||
|
setvalue = "<not set>"
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, setname.." = "..setvalue)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, "Invalid parameters (see /help set)")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("mods", {
|
||||||
|
params = "",
|
||||||
|
description = "lists mods installed on the server",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
local response = ""
|
||||||
|
local modnames = minetest.get_modnames()
|
||||||
|
for i, mod in ipairs(modnames) do
|
||||||
|
response = response .. mod
|
||||||
|
-- Add space if not at the end
|
||||||
|
if i ~= #modnames then
|
||||||
|
response = response .. " "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, response)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
local function handle_give_command(cmd, giver, receiver, stackstring)
|
||||||
|
minetest.log("action", giver.." invoked "..cmd..', stackstring="'
|
||||||
|
..stackstring..'"')
|
||||||
|
minetest.log(cmd..' invoked, stackstring="'..stackstring..'"')
|
||||||
|
local itemstack = ItemStack(stackstring)
|
||||||
|
if itemstack:is_empty() then
|
||||||
|
minetest.chat_send_player(giver, 'error: cannot give an empty item')
|
||||||
|
return
|
||||||
|
elseif not itemstack:is_known() then
|
||||||
|
minetest.chat_send_player(giver, 'error: cannot give an unknown item')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local receiverref = minetest.get_player_by_name(receiver)
|
||||||
|
if receiverref == nil then
|
||||||
|
minetest.chat_send_player(giver, receiver..' is not a known player')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local leftover = receiverref:get_inventory():add_item("main", itemstack)
|
||||||
|
if leftover:is_empty() then
|
||||||
|
partiality = ""
|
||||||
|
elseif leftover:get_count() == itemstack:get_count() then
|
||||||
|
partiality = "could not be "
|
||||||
|
else
|
||||||
|
partiality = "partially "
|
||||||
|
end
|
||||||
|
-- The actual item stack string may be different from what the "giver"
|
||||||
|
-- entered (e.g. big numbers are always interpreted as 2^16-1).
|
||||||
|
stackstring = itemstack:to_string()
|
||||||
|
if giver == receiver then
|
||||||
|
minetest.chat_send_player(giver, '"'..stackstring
|
||||||
|
..'" '..partiality..'added to inventory.');
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(giver, '"'..stackstring
|
||||||
|
..'" '..partiality..'added to '..receiver..'\'s inventory.');
|
||||||
|
minetest.chat_send_player(receiver, '"'..stackstring
|
||||||
|
..'" '..partiality..'added to inventory.');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_chatcommand("give", {
|
||||||
|
params = "<name> <itemstring>",
|
||||||
|
description = "give item to player",
|
||||||
|
privs = {give=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local toname, itemstring = string.match(param, "^([^ ]+) +(.+)$")
|
||||||
|
if not toname or not itemstring then
|
||||||
|
minetest.chat_send_player(name, "name and itemstring required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
handle_give_command("/give", name, toname, itemstring)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("giveme", {
|
||||||
|
params = "<itemstring>",
|
||||||
|
description = "give item to yourself",
|
||||||
|
privs = {give=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local itemstring = string.match(param, "(.+)$")
|
||||||
|
if not itemstring then
|
||||||
|
minetest.chat_send_player(name, "itemstring required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
handle_give_command("/giveme", name, name, itemstring)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("spawnentity", {
|
||||||
|
params = "<entityname>",
|
||||||
|
description = "spawn entity at your position",
|
||||||
|
privs = {give=true, interact=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local entityname = string.match(param, "(.+)$")
|
||||||
|
if not entityname then
|
||||||
|
minetest.chat_send_player(name, "entityname required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
print('/spawnentity invoked, entityname="'..entityname..'"')
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player == nil then
|
||||||
|
print("Unable to spawn entity, player is nil")
|
||||||
|
return true -- Handled chat message
|
||||||
|
end
|
||||||
|
local p = player:getpos()
|
||||||
|
p.y = p.y + 1
|
||||||
|
minetest.add_entity(p, entityname)
|
||||||
|
minetest.chat_send_player(name, '"'..entityname
|
||||||
|
..'" spawned.');
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("pulverize", {
|
||||||
|
params = "",
|
||||||
|
description = "delete item in hand",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player == nil then
|
||||||
|
print("Unable to pulverize, player is nil")
|
||||||
|
return true -- Handled chat message
|
||||||
|
end
|
||||||
|
if player:get_wielded_item():is_empty() then
|
||||||
|
minetest.chat_send_player(name, 'Unable to pulverize, no item in hand.')
|
||||||
|
else
|
||||||
|
player:set_wielded_item(nil)
|
||||||
|
minetest.chat_send_player(name, 'An item was pulverized.')
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Key = player name
|
||||||
|
minetest.rollback_punch_callbacks = {}
|
||||||
|
|
||||||
|
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||||
|
local name = puncher:get_player_name()
|
||||||
|
if minetest.rollback_punch_callbacks[name] then
|
||||||
|
minetest.rollback_punch_callbacks[name](pos, node, puncher)
|
||||||
|
minetest.rollback_punch_callbacks[name] = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_chatcommand("rollback_check", {
|
||||||
|
params = "[<range>] [<seconds>]",
|
||||||
|
description = "check who has last touched a node or near it, "..
|
||||||
|
"max. <seconds> ago (default range=0, seconds=86400=24h)",
|
||||||
|
privs = {rollback=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local range, seconds = string.match(param, "(%d+) *(%d*)")
|
||||||
|
range = tonumber(range) or 0
|
||||||
|
seconds = tonumber(seconds) or 86400
|
||||||
|
minetest.chat_send_player(name, "Punch a node (limits set: range="..
|
||||||
|
dump(range).." seconds="..dump(seconds).."s)")
|
||||||
|
minetest.rollback_punch_callbacks[name] = function(pos, node, puncher)
|
||||||
|
local name = puncher:get_player_name()
|
||||||
|
minetest.chat_send_player(name, "Checking...")
|
||||||
|
local actor, act_p, act_seconds =
|
||||||
|
minetest.rollback_get_last_node_actor(pos, range, seconds)
|
||||||
|
if actor == "" then
|
||||||
|
minetest.chat_send_player(name, "Nobody has touched the "..
|
||||||
|
"specified location in "..dump(seconds).." seconds")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local nodedesc = "this node"
|
||||||
|
if act_p.x ~= pos.x or act_p.y ~= pos.y or act_p.z ~= pos.z then
|
||||||
|
nodedesc = minetest.pos_to_string(act_p)
|
||||||
|
end
|
||||||
|
local nodename = minetest.get_node(act_p).name
|
||||||
|
minetest.chat_send_player(name, "Last actor on "..nodedesc..
|
||||||
|
" was "..actor..", "..dump(act_seconds)..
|
||||||
|
"s ago (node is now "..nodename..")")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("rollback", {
|
||||||
|
params = "<player name> [<seconds>] | :<actor> [<seconds>]",
|
||||||
|
description = "revert actions of a player; default for <seconds> is 60",
|
||||||
|
privs = {rollback=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
|
||||||
|
if not target_name then
|
||||||
|
local player_name = nil;
|
||||||
|
player_name, seconds = string.match(param, "([^ ]+) *(%d*)")
|
||||||
|
if not player_name then
|
||||||
|
minetest.chat_send_player(name, "Invalid parameters. See /help rollback and /help rollback_check")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
target_name = "player:"..player_name
|
||||||
|
end
|
||||||
|
seconds = tonumber(seconds) or 60
|
||||||
|
minetest.chat_send_player(name, "Reverting actions of "..
|
||||||
|
dump(target_name).." since "..dump(seconds).." seconds.")
|
||||||
|
local success, log = minetest.rollback_revert_actions_by(
|
||||||
|
target_name, seconds)
|
||||||
|
if #log > 10 then
|
||||||
|
minetest.chat_send_player(name, "(log is too long to show)")
|
||||||
|
else
|
||||||
|
for _,line in ipairs(log) do
|
||||||
|
minetest.chat_send_player(name, line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if success then
|
||||||
|
minetest.chat_send_player(name, "Reverting actions succeeded.")
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, "Reverting actions FAILED.")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("status", {
|
||||||
|
params = "",
|
||||||
|
description = "print server status line",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
minetest.chat_send_player(name, minetest.get_server_status())
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("time", {
|
||||||
|
params = "<0...24000>",
|
||||||
|
description = "set time of day",
|
||||||
|
privs = {settime=true},
|
||||||
|
func = function(name, param)
|
||||||
|
if param == "" then
|
||||||
|
minetest.chat_send_player(name, "Missing parameter")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local newtime = tonumber(param)
|
||||||
|
if newtime == nil then
|
||||||
|
minetest.chat_send_player(name, "Invalid time")
|
||||||
|
else
|
||||||
|
minetest.set_timeofday((newtime % 24000) / 24000)
|
||||||
|
minetest.chat_send_player(name, "Time of day changed.")
|
||||||
|
minetest.log("action", name .. " sets time " .. newtime)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("shutdown", {
|
||||||
|
params = "",
|
||||||
|
description = "shutdown server",
|
||||||
|
privs = {server=true},
|
||||||
|
func = function(name, param)
|
||||||
|
minetest.log("action", name .. " shuts down server")
|
||||||
|
minetest.request_shutdown()
|
||||||
|
minetest.chat_send_all("*** Server shutting down (operator request).")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("ban", {
|
||||||
|
params = "<name>",
|
||||||
|
description = "ban IP of player",
|
||||||
|
privs = {ban=true},
|
||||||
|
func = function(name, param)
|
||||||
|
if param == "" then
|
||||||
|
minetest.chat_send_player(name, "Ban list: " .. minetest.get_ban_list())
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not minetest.get_player_by_name(param) then
|
||||||
|
minetest.chat_send_player(name, "No such player")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not minetest.ban_player(param) then
|
||||||
|
minetest.chat_send_player(name, "Failed to ban player")
|
||||||
|
else
|
||||||
|
local desc = minetest.get_ban_description(param)
|
||||||
|
minetest.chat_send_player(name, "Banned " .. desc .. ".")
|
||||||
|
minetest.log("action", name .. " bans " .. desc .. ".")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("unban", {
|
||||||
|
params = "<name/ip>",
|
||||||
|
description = "remove IP ban",
|
||||||
|
privs = {ban=true},
|
||||||
|
func = function(name, param)
|
||||||
|
if not minetest.unban_player_or_ip(param) then
|
||||||
|
minetest.chat_send_player(name, "Failed to unban player/IP")
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, "Unbanned " .. param)
|
||||||
|
minetest.log("action", name .. " unbans " .. param)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("clearobjects", {
|
||||||
|
params = "",
|
||||||
|
description = "clear all objects in world",
|
||||||
|
privs = {server=true},
|
||||||
|
func = function(name, param)
|
||||||
|
minetest.log("action", name .. " clears all objects")
|
||||||
|
minetest.chat_send_all("Clearing all objects. This may take long. You may experience a timeout. (by " .. name .. ")")
|
||||||
|
minetest.clear_objects()
|
||||||
|
minetest.log("action", "object clearing done")
|
||||||
|
minetest.chat_send_all("*** Cleared all objects.")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("msg", {
|
||||||
|
params = "<name> <message>",
|
||||||
|
description = "Send a private message",
|
||||||
|
privs = {shout=true},
|
||||||
|
func = function(name, param)
|
||||||
|
local found, _, sendto, message = param:find("^([^%s]+)%s(.+)$")
|
||||||
|
if found then
|
||||||
|
if minetest.get_player_by_name(sendto) then
|
||||||
|
minetest.log("action", "PM from "..name.." to "..sendto..": "..message)
|
||||||
|
minetest.chat_send_player(sendto, "PM from "..name..": "..message, false)
|
||||||
|
minetest.chat_send_player(name, "Message sent")
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, "The player "..sendto.." is not online")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name, "Invalid usage, see /help msg")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
|
@ -0,0 +1,48 @@
|
||||||
|
-- Minetest: builtin/deprecated.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Default material types
|
||||||
|
--
|
||||||
|
function digprop_err()
|
||||||
|
minetest.log("info", debug.traceback())
|
||||||
|
minetest.log("info", "WARNING: The minetest.digprop_* functions are obsolete and need to be replaced by item groups.")
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.digprop_constanttime = digprop_err
|
||||||
|
minetest.digprop_stonelike = digprop_err
|
||||||
|
minetest.digprop_dirtlike = digprop_err
|
||||||
|
minetest.digprop_gravellike = digprop_err
|
||||||
|
minetest.digprop_woodlike = digprop_err
|
||||||
|
minetest.digprop_leaveslike = digprop_err
|
||||||
|
minetest.digprop_glasslike = digprop_err
|
||||||
|
|
||||||
|
minetest.node_metadata_inventory_move_allow_all = function()
|
||||||
|
minetest.log("info", "WARNING: minetest.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.add_to_creative_inventory = function(itemstring)
|
||||||
|
minetest.log('info', "WARNING: minetest.add_to_creative_inventory: This function is deprecated and does nothing.")
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- EnvRef
|
||||||
|
--
|
||||||
|
minetest.env = {}
|
||||||
|
local envref_deprecation_message_printed = false
|
||||||
|
setmetatable(minetest.env, {
|
||||||
|
__index = function(table, key)
|
||||||
|
if not envref_deprecation_message_printed then
|
||||||
|
minetest.log("info", "WARNING: minetest.env:[...] is deprecated and should be replaced with minetest.[...]")
|
||||||
|
envref_deprecation_message_printed = true
|
||||||
|
end
|
||||||
|
local func = minetest[key]
|
||||||
|
if type(func) == "function" then
|
||||||
|
rawset(table, key, function(self, ...)
|
||||||
|
return func(unpack({...}))
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
rawset(table, key, nil)
|
||||||
|
end
|
||||||
|
return rawget(table, key)
|
||||||
|
end
|
||||||
|
})
|
|
@ -0,0 +1,19 @@
|
||||||
|
-- Minetest: builtin/detached_inventory.lua
|
||||||
|
|
||||||
|
minetest.detached_inventories = {}
|
||||||
|
|
||||||
|
function minetest.create_detached_inventory(name, callbacks)
|
||||||
|
local stuff = {}
|
||||||
|
stuff.name = name
|
||||||
|
if callbacks then
|
||||||
|
stuff.allow_move = callbacks.allow_move
|
||||||
|
stuff.allow_put = callbacks.allow_put
|
||||||
|
stuff.allow_take = callbacks.allow_take
|
||||||
|
stuff.on_move = callbacks.on_move
|
||||||
|
stuff.on_put = callbacks.on_put
|
||||||
|
stuff.on_take = callbacks.on_take
|
||||||
|
end
|
||||||
|
minetest.detached_inventories[name] = stuff
|
||||||
|
return minetest.create_detached_inventory_raw(name)
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
-- Minetest: builtin/item.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Falling stuff
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.register_entity("__builtin:falling_node", {
|
||||||
|
initial_properties = {
|
||||||
|
physical = true,
|
||||||
|
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||||
|
visual = "wielditem",
|
||||||
|
textures = {},
|
||||||
|
visual_size = {x=0.667, y=0.667},
|
||||||
|
},
|
||||||
|
|
||||||
|
nodename = "",
|
||||||
|
|
||||||
|
set_node = function(self, nodename)
|
||||||
|
self.nodename = nodename
|
||||||
|
local stack = ItemStack(nodename)
|
||||||
|
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 minetest.registered_items[itemname] then
|
||||||
|
item_texture = minetest.registered_items[itemname].inventory_image
|
||||||
|
item_type = minetest.registered_items[itemname].type
|
||||||
|
end
|
||||||
|
prop = {
|
||||||
|
is_visible = true,
|
||||||
|
textures = {nodename},
|
||||||
|
}
|
||||||
|
self.object:set_properties(prop)
|
||||||
|
end,
|
||||||
|
|
||||||
|
get_staticdata = function(self)
|
||||||
|
return self.nodename
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
self.nodename = staticdata
|
||||||
|
self.object:set_armor_groups({immortal=1})
|
||||||
|
--self.object:setacceleration({x=0, y=-10, z=0})
|
||||||
|
self:set_node(self.nodename)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
-- Set gravity
|
||||||
|
self.object:setacceleration({x=0, y=-10, z=0})
|
||||||
|
-- Turn to actual sand when collides to ground or just move
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
|
||||||
|
local bcn = minetest.get_node(bcp)
|
||||||
|
-- Note: walkable is in the node definition, not in item groups
|
||||||
|
if minetest.registered_nodes[bcn.name] and
|
||||||
|
minetest.registered_nodes[bcn.name].walkable then
|
||||||
|
if minetest.registered_nodes[bcn.name].buildable_to then
|
||||||
|
minetest.remove_node(bcp)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
|
||||||
|
-- Check what's here
|
||||||
|
local n2 = minetest.get_node(np)
|
||||||
|
-- If it's not air or liquid, remove node and replace it with
|
||||||
|
-- it's drops
|
||||||
|
if n2.name ~= "air" and (not minetest.registered_nodes[n2.name] or
|
||||||
|
minetest.registered_nodes[n2.name].liquidtype == "none") then
|
||||||
|
local drops = minetest.get_node_drops(n2.name, "")
|
||||||
|
minetest.remove_node(np)
|
||||||
|
-- Add dropped items
|
||||||
|
local _, dropped_item
|
||||||
|
for _, dropped_item in ipairs(drops) do
|
||||||
|
minetest.add_item(np, dropped_item)
|
||||||
|
end
|
||||||
|
-- Run script hook
|
||||||
|
local _, callback
|
||||||
|
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
||||||
|
callback(np, n2, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Create node and remove entity
|
||||||
|
minetest.add_node(np, {name=self.nodename})
|
||||||
|
self.object:remove()
|
||||||
|
nodeupdate(np)
|
||||||
|
else
|
||||||
|
-- Do nothing
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
function spawn_falling_node(p, nodename)
|
||||||
|
obj = minetest.add_entity(p, "__builtin:falling_node")
|
||||||
|
obj:get_luaentity():set_node(nodename)
|
||||||
|
end
|
||||||
|
|
||||||
|
function drop_attached_node(p)
|
||||||
|
local nn = minetest.get_node(p).name
|
||||||
|
minetest.remove_node(p)
|
||||||
|
for _,item in ipairs(minetest.get_node_drops(nn, "")) do
|
||||||
|
local pos = {
|
||||||
|
x = p.x + math.random()/2 - 0.25,
|
||||||
|
y = p.y + math.random()/2 - 0.25,
|
||||||
|
z = p.z + math.random()/2 - 0.25,
|
||||||
|
}
|
||||||
|
minetest.add_item(pos, item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function check_attached_node(p, n)
|
||||||
|
local def = minetest.registered_nodes[n.name]
|
||||||
|
local d = {x=0, y=0, z=0}
|
||||||
|
if def.paramtype2 == "wallmounted" then
|
||||||
|
if n.param2 == 0 then
|
||||||
|
d.y = 1
|
||||||
|
elseif n.param2 == 1 then
|
||||||
|
d.y = -1
|
||||||
|
elseif n.param2 == 2 then
|
||||||
|
d.x = 1
|
||||||
|
elseif n.param2 == 3 then
|
||||||
|
d.x = -1
|
||||||
|
elseif n.param2 == 4 then
|
||||||
|
d.z = 1
|
||||||
|
elseif n.param2 == 5 then
|
||||||
|
d.z = -1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
d.y = -1
|
||||||
|
end
|
||||||
|
local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z}
|
||||||
|
local nn = minetest.get_node(p2).name
|
||||||
|
local def2 = minetest.registered_nodes[nn]
|
||||||
|
if def2 and not def2.walkable then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Some common functions
|
||||||
|
--
|
||||||
|
|
||||||
|
function nodeupdate_single(p, delay)
|
||||||
|
n = minetest.get_node(p)
|
||||||
|
if minetest.get_node_group(n.name, "falling_node") ~= 0 then
|
||||||
|
p_bottom = {x=p.x, y=p.y-1, z=p.z}
|
||||||
|
n_bottom = minetest.get_node(p_bottom)
|
||||||
|
-- Note: walkable is in the node definition, not in item groups
|
||||||
|
if minetest.registered_nodes[n_bottom.name] and
|
||||||
|
(not minetest.registered_nodes[n_bottom.name].walkable or
|
||||||
|
minetest.registered_nodes[n_bottom.name].buildable_to) then
|
||||||
|
if delay then
|
||||||
|
minetest.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
|
||||||
|
else
|
||||||
|
minetest.remove_node(p)
|
||||||
|
spawn_falling_node(p, n.name)
|
||||||
|
nodeupdate(p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_node_group(n.name, "attached_node") ~= 0 then
|
||||||
|
if not check_attached_node(p, n) then
|
||||||
|
drop_attached_node(p)
|
||||||
|
nodeupdate(p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function nodeupdate(p)
|
||||||
|
-- Round p to prevent falling entities to get stuck
|
||||||
|
p.x = math.floor(p.x+0.5)
|
||||||
|
p.y = math.floor(p.y+0.5)
|
||||||
|
p.z = math.floor(p.z+0.5)
|
||||||
|
|
||||||
|
for x = -1,1 do
|
||||||
|
for y = -1,1 do
|
||||||
|
for z = -1,1 do
|
||||||
|
nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, not (x==0 and y==0 and z==0))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Global callbacks
|
||||||
|
--
|
||||||
|
|
||||||
|
function on_placenode(p, node)
|
||||||
|
nodeupdate(p)
|
||||||
|
end
|
||||||
|
minetest.register_on_placenode(on_placenode)
|
||||||
|
|
||||||
|
function on_dignode(p, node)
|
||||||
|
nodeupdate(p)
|
||||||
|
end
|
||||||
|
minetest.register_on_dignode(on_dignode)
|
|
@ -0,0 +1,28 @@
|
||||||
|
-- Minetest: builtin/features.lua
|
||||||
|
|
||||||
|
minetest.features = {
|
||||||
|
glasslike_framed = true,
|
||||||
|
nodebox_as_selectionbox = true,
|
||||||
|
chat_send_player_param3 = true,
|
||||||
|
get_all_craft_recipes_works = true,
|
||||||
|
use_texture_alpha = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
function minetest.has_feature(arg)
|
||||||
|
if type(arg) == "table" then
|
||||||
|
missing_features = {}
|
||||||
|
result = true
|
||||||
|
for ft, _ in pairs(arg) do
|
||||||
|
if not minetest.features[ftr] then
|
||||||
|
missing_features[ftr] = true
|
||||||
|
result = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result, missing_features
|
||||||
|
elseif type(arg) == "string" then
|
||||||
|
if not minetest.features[arg] then
|
||||||
|
return false, {[arg]=true}
|
||||||
|
end
|
||||||
|
return true, {}
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,495 @@
|
||||||
|
-- Minetest: builtin/item.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Item definition helpers
|
||||||
|
--
|
||||||
|
|
||||||
|
function minetest.inventorycube(img1, img2, img3)
|
||||||
|
img2 = img2 or img1
|
||||||
|
img3 = img3 or img1
|
||||||
|
return "[inventorycube"
|
||||||
|
.. "{" .. img1:gsub("%^", "&")
|
||||||
|
.. "{" .. img2:gsub("%^", "&")
|
||||||
|
.. "{" .. img3:gsub("%^", "&")
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.get_pointed_thing_position(pointed_thing, above)
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
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
|
||||||
|
elseif pointed_thing.type == "object" then
|
||||||
|
obj = pointed_thing.ref
|
||||||
|
if obj ~= nil then
|
||||||
|
return obj:getpos()
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.dir_to_facedir(dir)
|
||||||
|
if math.abs(dir.x) > math.abs(dir.z) then
|
||||||
|
if dir.x < 0 then
|
||||||
|
return 3
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if dir.z < 0 then
|
||||||
|
return 2
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.dir_to_wallmounted(dir)
|
||||||
|
if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
|
||||||
|
if dir.y < 0 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
elseif math.abs(dir.x) > math.abs(dir.z) then
|
||||||
|
if dir.x < 0 then
|
||||||
|
return 3
|
||||||
|
else
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if dir.z < 0 then
|
||||||
|
return 5
|
||||||
|
else
|
||||||
|
return 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.get_node_drops(nodename, toolname)
|
||||||
|
local drop = ItemStack({name=nodename}):get_definition().drop
|
||||||
|
if drop == nil then
|
||||||
|
-- default drop
|
||||||
|
return {nodename}
|
||||||
|
elseif type(drop) == "string" then
|
||||||
|
-- itemstring drop
|
||||||
|
return {drop}
|
||||||
|
elseif drop.items == nil then
|
||||||
|
-- drop = {} to disable default drop
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Extended drop table
|
||||||
|
local got_items = {}
|
||||||
|
local got_count = 0
|
||||||
|
local _, item, tool
|
||||||
|
for _, item in ipairs(drop.items) do
|
||||||
|
local good_rarity = true
|
||||||
|
local good_tool = true
|
||||||
|
if item.rarity ~= nil then
|
||||||
|
good_rarity = item.rarity < 1 or math.random(item.rarity) == 1
|
||||||
|
end
|
||||||
|
if item.tools ~= nil then
|
||||||
|
good_tool = false
|
||||||
|
for _, tool in ipairs(item.tools) do
|
||||||
|
if tool:sub(1, 1) == '~' then
|
||||||
|
good_tool = toolname:find(tool:sub(2)) ~= nil
|
||||||
|
else
|
||||||
|
good_tool = toolname == tool
|
||||||
|
end
|
||||||
|
if good_tool then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if good_rarity and good_tool then
|
||||||
|
got_count = got_count + 1
|
||||||
|
for _, add_item in ipairs(item.items) do
|
||||||
|
got_items[#got_items+1] = add_item
|
||||||
|
end
|
||||||
|
if drop.max_items ~= nil and got_count == drop.max_items then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return got_items
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||||
|
local item = itemstack:peek_item()
|
||||||
|
local def = itemstack:get_definition()
|
||||||
|
if def.type ~= "node" or pointed_thing.type ~= "node" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local under = pointed_thing.under
|
||||||
|
local oldnode_under = minetest.get_node_or_nil(under)
|
||||||
|
local above = pointed_thing.above
|
||||||
|
local oldnode_above = minetest.get_node_or_nil(above)
|
||||||
|
|
||||||
|
if not oldnode_under or not oldnode_above then
|
||||||
|
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||||
|
.. " node in unloaded position " .. minetest.pos_to_string(above))
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
|
||||||
|
olddef_under = olddef_under or minetest.nodedef_default
|
||||||
|
local olddef_above = ItemStack({name=oldnode_above.name}):get_definition()
|
||||||
|
olddef_above = olddef_above or minetest.nodedef_default
|
||||||
|
|
||||||
|
if not olddef_above.buildable_to and not olddef_under.buildable_to then
|
||||||
|
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||||
|
.. " node in invalid position " .. minetest.pos_to_string(above)
|
||||||
|
.. ", replacing " .. oldnode_above.name)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Place above pointed node
|
||||||
|
local place_to = {x = above.x, y = above.y, z = above.z}
|
||||||
|
|
||||||
|
-- If node under is buildable_to, place into it instead (eg. snow)
|
||||||
|
if olddef_under.buildable_to then
|
||||||
|
minetest.log("info", "node under is buildable to")
|
||||||
|
place_to = {x = under.x, y = under.y, z = under.z}
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.log("action", placer:get_player_name() .. " places node "
|
||||||
|
.. def.name .. " at " .. minetest.pos_to_string(place_to))
|
||||||
|
|
||||||
|
local oldnode = minetest.get_node(place_to)
|
||||||
|
local newnode = {name = def.name, param1 = 0, param2 = 0}
|
||||||
|
|
||||||
|
-- Calculate direction for wall mounted stuff like torches and signs
|
||||||
|
if def.paramtype2 == 'wallmounted' then
|
||||||
|
local dir = {
|
||||||
|
x = under.x - above.x,
|
||||||
|
y = under.y - above.y,
|
||||||
|
z = under.z - above.z
|
||||||
|
}
|
||||||
|
newnode.param2 = minetest.dir_to_wallmounted(dir)
|
||||||
|
-- Calculate the direction for furnaces and chests and stuff
|
||||||
|
elseif def.paramtype2 == 'facedir' then
|
||||||
|
local placer_pos = placer:getpos()
|
||||||
|
if placer_pos then
|
||||||
|
local dir = {
|
||||||
|
x = above.x - placer_pos.x,
|
||||||
|
y = above.y - placer_pos.y,
|
||||||
|
z = above.z - placer_pos.z
|
||||||
|
}
|
||||||
|
newnode.param2 = minetest.dir_to_facedir(dir)
|
||||||
|
minetest.log("action", "facedir: " .. newnode.param2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if the node is attached and if it can be placed there
|
||||||
|
if minetest.get_item_group(def.name, "attached_node") ~= 0 and
|
||||||
|
not check_attached_node(place_to, newnode) then
|
||||||
|
minetest.log("action", "attached node " .. def.name ..
|
||||||
|
" can not be placed at " .. minetest.pos_to_string(place_to))
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add node and update
|
||||||
|
minetest.add_node(place_to, newnode)
|
||||||
|
|
||||||
|
local take_item = true
|
||||||
|
|
||||||
|
-- Run callback
|
||||||
|
if def.after_place_node then
|
||||||
|
-- Copy place_to because callback can modify it
|
||||||
|
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||||
|
if def.after_place_node(place_to_copy, placer, itemstack) then
|
||||||
|
take_item = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Run script hook
|
||||||
|
local _, callback
|
||||||
|
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
||||||
|
-- Copy pos and node because callback can modify them
|
||||||
|
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||||
|
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
|
||||||
|
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
|
||||||
|
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack) then
|
||||||
|
take_item = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if take_item then
|
||||||
|
itemstack:take_item()
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.item_place_object(itemstack, placer, pointed_thing)
|
||||||
|
local pos = minetest.get_pointed_thing_position(pointed_thing, true)
|
||||||
|
if pos ~= nil then
|
||||||
|
local item = itemstack:take_item()
|
||||||
|
minetest.add_item(pos, item)
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.item_place(itemstack, placer, pointed_thing)
|
||||||
|
-- Call on_rightclick if the pointed node defines it
|
||||||
|
if pointed_thing.type == "node" and placer and
|
||||||
|
not placer:get_player_control().sneak then
|
||||||
|
local n = minetest.get_node(pointed_thing.under)
|
||||||
|
local nn = n.name
|
||||||
|
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then
|
||||||
|
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n, placer, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if itemstack:get_definition().type == "node" then
|
||||||
|
return minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.item_drop(itemstack, dropper, pos)
|
||||||
|
if dropper.get_player_name then
|
||||||
|
local v = dropper:get_look_dir()
|
||||||
|
local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z}
|
||||||
|
local obj = minetest.add_item(p, itemstack)
|
||||||
|
if obj then
|
||||||
|
v.x = v.x*2
|
||||||
|
v.y = v.y*2 + 1
|
||||||
|
v.z = v.z*2
|
||||||
|
obj:setvelocity(v)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
minetest.add_item(pos, itemstack)
|
||||||
|
end
|
||||||
|
return ItemStack("")
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.item_eat(hp_change, replace_with_item)
|
||||||
|
return function(itemstack, user, pointed_thing) -- closure
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.node_punch(pos, node, puncher)
|
||||||
|
-- Run script hook
|
||||||
|
local _, callback
|
||||||
|
for _, callback in ipairs(minetest.registered_on_punchnodes) do
|
||||||
|
-- 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}
|
||||||
|
callback(pos_copy, node_copy, puncher)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
-- Add dropped items to object's inventory
|
||||||
|
if digger:get_inventory() then
|
||||||
|
local _, dropped_item
|
||||||
|
for _, dropped_item in ipairs(drops) do
|
||||||
|
local left = digger:get_inventory():add_item("main", dropped_item)
|
||||||
|
if not left:is_empty() then
|
||||||
|
local p = {
|
||||||
|
x = pos.x + math.random()/2-0.25,
|
||||||
|
y = pos.y + math.random()/2-0.25,
|
||||||
|
z = pos.z + math.random()/2-0.25,
|
||||||
|
}
|
||||||
|
minetest.add_item(p, left)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.node_dig(pos, node, digger)
|
||||||
|
local def = ItemStack({name=node.name}):get_definition()
|
||||||
|
-- Check if def ~= 0 because we always want to be able to remove unknown nodes
|
||||||
|
if #def ~= 0 and not def.diggable or (def.can_dig and not def.can_dig(pos,digger)) then
|
||||||
|
minetest.log("info", digger:get_player_name() .. " tried to dig "
|
||||||
|
.. node.name .. " which is not diggable "
|
||||||
|
.. minetest.pos_to_string(pos))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.log('action', digger:get_player_name() .. " digs "
|
||||||
|
.. node.name .. " at " .. minetest.pos_to_string(pos))
|
||||||
|
|
||||||
|
local wielded = digger:get_wielded_item()
|
||||||
|
local drops = minetest.get_node_drops(node.name, wielded:get_name())
|
||||||
|
|
||||||
|
-- Wear out tool
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
local tp = wielded:get_tool_capabilities()
|
||||||
|
local dp = minetest.get_dig_params(def.groups, tp)
|
||||||
|
wielded:add_wear(dp.wear)
|
||||||
|
digger:set_wielded_item(wielded)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Handle drops
|
||||||
|
minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
|
||||||
|
local oldmetadata = nil
|
||||||
|
if def.after_dig_node then
|
||||||
|
oldmetadata = minetest.get_meta(pos):to_table()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove node and update
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
|
||||||
|
-- Run callback
|
||||||
|
if def.after_dig_node then
|
||||||
|
-- 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}
|
||||||
|
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Run script hook
|
||||||
|
local _, callback
|
||||||
|
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
||||||
|
-- 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}
|
||||||
|
callback(pos_copy, node_copy, digger)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is used to allow mods to redefine minetest.item_place and so on
|
||||||
|
-- NOTE: This is not the preferred way. Preferred way is to provide enough
|
||||||
|
-- callbacks to not require redefining global functions. -celeron55
|
||||||
|
local function redef_wrapper(table, name)
|
||||||
|
return function(...)
|
||||||
|
return table[name](...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Item definition defaults
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.nodedef_default = {
|
||||||
|
-- Item properties
|
||||||
|
type="node",
|
||||||
|
-- name intentionally not defined here
|
||||||
|
description = "",
|
||||||
|
groups = {},
|
||||||
|
inventory_image = "",
|
||||||
|
wield_image = "",
|
||||||
|
wield_scale = {x=1,y=1,z=1},
|
||||||
|
stack_max = 99,
|
||||||
|
usable = false,
|
||||||
|
liquids_pointable = false,
|
||||||
|
tool_capabilities = nil,
|
||||||
|
node_placement_prediction = nil,
|
||||||
|
|
||||||
|
-- Interaction callbacks
|
||||||
|
on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place
|
||||||
|
on_drop = redef_wrapper(minetest, 'item_drop'), -- minetest.item_drop
|
||||||
|
on_use = nil,
|
||||||
|
can_dig = nil,
|
||||||
|
|
||||||
|
on_punch = redef_wrapper(minetest, 'node_punch'), -- minetest.node_punch
|
||||||
|
on_rightclick = nil,
|
||||||
|
on_dig = redef_wrapper(minetest, 'node_dig'), -- minetest.node_dig
|
||||||
|
|
||||||
|
on_receive_fields = nil,
|
||||||
|
|
||||||
|
on_metadata_inventory_move = minetest.node_metadata_inventory_move_allow_all,
|
||||||
|
on_metadata_inventory_offer = minetest.node_metadata_inventory_offer_allow_all,
|
||||||
|
on_metadata_inventory_take = minetest.node_metadata_inventory_take_allow_all,
|
||||||
|
|
||||||
|
-- Node properties
|
||||||
|
drawtype = "normal",
|
||||||
|
visual_scale = 1.0,
|
||||||
|
-- Don't define these because otherwise the old tile_images and
|
||||||
|
-- special_materials wouldn't be read
|
||||||
|
--tiles ={""},
|
||||||
|
--special_tiles = {
|
||||||
|
-- {name="", backface_culling=true},
|
||||||
|
-- {name="", backface_culling=true},
|
||||||
|
--},
|
||||||
|
alpha = 255,
|
||||||
|
post_effect_color = {a=0, r=0, g=0, b=0},
|
||||||
|
paramtype = "none",
|
||||||
|
paramtype2 = "none",
|
||||||
|
is_ground_content = false,
|
||||||
|
sunlight_propagates = false,
|
||||||
|
walkable = true,
|
||||||
|
pointable = true,
|
||||||
|
diggable = true,
|
||||||
|
climbable = false,
|
||||||
|
buildable_to = false,
|
||||||
|
liquidtype = "none",
|
||||||
|
liquid_alternative_flowing = "",
|
||||||
|
liquid_alternative_source = "",
|
||||||
|
liquid_viscosity = 0,
|
||||||
|
light_source = 0,
|
||||||
|
damage_per_second = 0,
|
||||||
|
selection_box = {type="regular"},
|
||||||
|
legacy_facedir_simple = false,
|
||||||
|
legacy_wallmounted = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.craftitemdef_default = {
|
||||||
|
type="craft",
|
||||||
|
-- name intentionally not defined here
|
||||||
|
description = "",
|
||||||
|
groups = {},
|
||||||
|
inventory_image = "",
|
||||||
|
wield_image = "",
|
||||||
|
wield_scale = {x=1,y=1,z=1},
|
||||||
|
stack_max = 99,
|
||||||
|
liquids_pointable = false,
|
||||||
|
tool_capabilities = nil,
|
||||||
|
|
||||||
|
-- Interaction callbacks
|
||||||
|
on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place
|
||||||
|
on_drop = redef_wrapper(minetest, 'item_drop'), -- minetest.item_drop
|
||||||
|
on_use = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.tooldef_default = {
|
||||||
|
type="tool",
|
||||||
|
-- name intentionally not defined here
|
||||||
|
description = "",
|
||||||
|
groups = {},
|
||||||
|
inventory_image = "",
|
||||||
|
wield_image = "",
|
||||||
|
wield_scale = {x=1,y=1,z=1},
|
||||||
|
stack_max = 1,
|
||||||
|
liquids_pointable = false,
|
||||||
|
tool_capabilities = nil,
|
||||||
|
|
||||||
|
-- Interaction callbacks
|
||||||
|
on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place
|
||||||
|
on_drop = redef_wrapper(minetest, 'item_drop'), -- minetest.item_drop
|
||||||
|
on_use = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.noneitemdef_default = { -- This is used for the hand and unknown items
|
||||||
|
type="none",
|
||||||
|
-- name intentionally not defined here
|
||||||
|
description = "",
|
||||||
|
groups = {},
|
||||||
|
inventory_image = "",
|
||||||
|
wield_image = "",
|
||||||
|
wield_scale = {x=1,y=1,z=1},
|
||||||
|
stack_max = 99,
|
||||||
|
liquids_pointable = false,
|
||||||
|
tool_capabilities = nil,
|
||||||
|
|
||||||
|
-- Interaction callbacks
|
||||||
|
on_place = redef_wrapper(minetest, 'item_place'),
|
||||||
|
on_drop = nil,
|
||||||
|
on_use = nil,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
-- Minetest: builtin/item_entity.lua
|
||||||
|
|
||||||
|
function minetest.spawn_item(pos, item)
|
||||||
|
-- Take item in any format
|
||||||
|
local stack = ItemStack(item)
|
||||||
|
local obj = minetest.add_entity(pos, "__builtin:item")
|
||||||
|
obj:get_luaentity():set_item(stack:to_string())
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("__builtin:item", {
|
||||||
|
initial_properties = {
|
||||||
|
hp_max = 1,
|
||||||
|
physical = true,
|
||||||
|
collisionbox = {-0.17,-0.17,-0.17, 0.17,0.17,0.17},
|
||||||
|
visual = "sprite",
|
||||||
|
visual_size = {x=0.5, y=0.5},
|
||||||
|
textures = {""},
|
||||||
|
spritediv = {x=1, y=1},
|
||||||
|
initial_sprite_basepos = {x=0, y=0},
|
||||||
|
is_visible = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
itemstring = '',
|
||||||
|
physical_state = true,
|
||||||
|
|
||||||
|
set_item = function(self, itemstring)
|
||||||
|
self.itemstring = itemstring
|
||||||
|
local stack = ItemStack(itemstring)
|
||||||
|
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 minetest.registered_items[itemname] then
|
||||||
|
item_texture = minetest.registered_items[itemname].inventory_image
|
||||||
|
item_type = minetest.registered_items[itemname].type
|
||||||
|
end
|
||||||
|
prop = {
|
||||||
|
is_visible = true,
|
||||||
|
visual = "sprite",
|
||||||
|
textures = {"unknown_item.png"}
|
||||||
|
}
|
||||||
|
if item_texture and item_texture ~= "" then
|
||||||
|
prop.visual = "sprite"
|
||||||
|
prop.textures = {item_texture}
|
||||||
|
prop.visual_size = {x=0.50, y=0.50}
|
||||||
|
else
|
||||||
|
prop.visual = "wielditem"
|
||||||
|
prop.textures = {itemname}
|
||||||
|
prop.visual_size = {x=0.20, y=0.20}
|
||||||
|
prop.automatic_rotate = math.pi * 0.25
|
||||||
|
end
|
||||||
|
self.object:set_properties(prop)
|
||||||
|
end,
|
||||||
|
|
||||||
|
get_staticdata = function(self)
|
||||||
|
--return self.itemstring
|
||||||
|
return minetest.serialize({
|
||||||
|
itemstring = self.itemstring,
|
||||||
|
always_collect = self.always_collect,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
if string.sub(staticdata, 1, string.len("return")) == "return" then
|
||||||
|
local data = minetest.deserialize(staticdata)
|
||||||
|
if data and type(data) == "table" then
|
||||||
|
self.itemstring = data.itemstring
|
||||||
|
self.always_collect = data.always_collect
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.itemstring = staticdata
|
||||||
|
end
|
||||||
|
self.object:set_armor_groups({immortal=1})
|
||||||
|
self.object:setvelocity({x=0, y=2, z=0})
|
||||||
|
self.object:setacceleration({x=0, y=-10, z=0})
|
||||||
|
self:set_item(self.itemstring)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
local p = self.object:getpos()
|
||||||
|
p.y = p.y - 0.3
|
||||||
|
local nn = minetest.get_node(p).name
|
||||||
|
-- If node is not registered or node is walkably solid and resting on nodebox
|
||||||
|
local v = self.object:getvelocity()
|
||||||
|
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and v.y == 0 then
|
||||||
|
if self.physical_state then
|
||||||
|
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
|
||||||
|
})
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not self.physical_state then
|
||||||
|
self.object:setvelocity({x=0,y=0,z=0})
|
||||||
|
self.object:setacceleration({x=0, y=-10, z=0})
|
||||||
|
self.physical_state = true
|
||||||
|
self.object:set_properties({
|
||||||
|
physical = true
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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
|
||||||
|
self.itemstring = left:to_string()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.object:remove()
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
-- Minetest: builtin/misc.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Misc. API functions
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.timers_to_add = {}
|
||||||
|
minetest.timers = {}
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for _, timer in ipairs(minetest.timers_to_add) do
|
||||||
|
table.insert(minetest.timers, timer)
|
||||||
|
end
|
||||||
|
minetest.timers_to_add = {}
|
||||||
|
for index, timer in ipairs(minetest.timers) do
|
||||||
|
timer.time = timer.time - dtime
|
||||||
|
if timer.time <= 0 then
|
||||||
|
timer.func(unpack(timer.args or {}))
|
||||||
|
table.remove(minetest.timers,index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function minetest.after(time, func, ...)
|
||||||
|
table.insert(minetest.timers_to_add, {time=time, func=func, args={...}})
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.check_player_privs(name, privs)
|
||||||
|
local player_privs = minetest.get_player_privs(name)
|
||||||
|
local missing_privileges = {}
|
||||||
|
for priv, val in pairs(privs) do
|
||||||
|
if val then
|
||||||
|
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
|
||||||
|
|
||||||
|
function minetest.get_connected_players()
|
||||||
|
-- This could be optimized a bit, but leave that for later
|
||||||
|
local list = {}
|
||||||
|
for _, obj in pairs(minetest.get_objects_inside_radius({x=0,y=0,z=0}, 1000000)) do
|
||||||
|
if obj:is_player() then
|
||||||
|
table.insert(list, obj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.hash_node_position(pos)
|
||||||
|
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.get_item_group(name, group)
|
||||||
|
if not minetest.registered_items[name] or not
|
||||||
|
minetest.registered_items[name].groups[group] then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return minetest.registered_items[name].groups[group]
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.get_node_group(name, group)
|
||||||
|
return minetest.get_item_group(name, group)
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.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(minetest.string_to_pos("10.0, 5, -2").x == 10)
|
||||||
|
assert(minetest.string_to_pos("( 10.0, 5, -2)").z == -2)
|
||||||
|
assert(minetest.string_to_pos("asd, 5, -2)") == nil)
|
||||||
|
|
||||||
|
function minetest.setting_get_pos(name)
|
||||||
|
local value = minetest.setting_get(name)
|
||||||
|
if not value then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return minetest.string_to_pos(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.formspec_escape(str)
|
||||||
|
str = string.gsub(str, "\\", "\\\\")
|
||||||
|
str = string.gsub(str, "%[", "\\[")
|
||||||
|
str = string.gsub(str, "%]", "\\]")
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
-- Minetest: builtin/misc_helpers.lua
|
||||||
|
|
||||||
|
function basic_dump2(o)
|
||||||
|
if type(o) == "number" then
|
||||||
|
return tostring(o)
|
||||||
|
elseif type(o) == "string" then
|
||||||
|
return string.format("%q", o)
|
||||||
|
elseif type(o) == "boolean" then
|
||||||
|
return tostring(o)
|
||||||
|
elseif type(o) == "function" then
|
||||||
|
return "<function>"
|
||||||
|
elseif type(o) == "userdata" then
|
||||||
|
return "<userdata>"
|
||||||
|
elseif type(o) == "nil" then
|
||||||
|
return "nil"
|
||||||
|
else
|
||||||
|
error("cannot dump a " .. type(o))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dump2(o, name, dumped)
|
||||||
|
name = name or "_"
|
||||||
|
dumped = dumped or {}
|
||||||
|
io.write(name, " = ")
|
||||||
|
if type(o) == "number" or type(o) == "string" or type(o) == "boolean"
|
||||||
|
or type(o) == "function" or type(o) == "nil"
|
||||||
|
or type(o) == "userdata" then
|
||||||
|
io.write(basic_dump2(o), "\n")
|
||||||
|
elseif type(o) == "table" then
|
||||||
|
if dumped[o] then
|
||||||
|
io.write(dumped[o], "\n")
|
||||||
|
else
|
||||||
|
dumped[o] = name
|
||||||
|
io.write("{}\n") -- new table
|
||||||
|
for k,v in pairs(o) do
|
||||||
|
local fieldname = string.format("%s[%s]", name, basic_dump2(k))
|
||||||
|
dump2(v, fieldname, dumped)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("cannot dump a " .. type(o))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dump(o, dumped)
|
||||||
|
dumped = dumped or {}
|
||||||
|
if type(o) == "number" then
|
||||||
|
return tostring(o)
|
||||||
|
elseif type(o) == "string" then
|
||||||
|
return string.format("%q", o)
|
||||||
|
elseif type(o) == "table" then
|
||||||
|
if dumped[o] then
|
||||||
|
return "<circular reference>"
|
||||||
|
end
|
||||||
|
dumped[o] = true
|
||||||
|
local t = {}
|
||||||
|
for k,v in pairs(o) do
|
||||||
|
t[#t+1] = "[" .. dump(k, dumped) .. "] = " .. dump(v, dumped)
|
||||||
|
end
|
||||||
|
return "{" .. table.concat(t, ", ") .. "}"
|
||||||
|
elseif type(o) == "boolean" then
|
||||||
|
return tostring(o)
|
||||||
|
elseif type(o) == "function" then
|
||||||
|
return "<function>"
|
||||||
|
elseif type(o) == "userdata" then
|
||||||
|
return "<userdata>"
|
||||||
|
elseif type(o) == "nil" then
|
||||||
|
return "nil"
|
||||||
|
else
|
||||||
|
error("cannot dump a " .. type(o))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
function string:trim()
|
||||||
|
return (self:gsub("^%s*(.-)%s*$", "%1"))
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
|
||||||
|
|
||||||
|
function minetest.pos_to_string(pos)
|
||||||
|
return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,322 @@
|
||||||
|
-- Minetest: builtin/misc_register.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Make raw registration functions inaccessible to anyone except this file
|
||||||
|
--
|
||||||
|
|
||||||
|
local register_item_raw = minetest.register_item_raw
|
||||||
|
minetest.register_item_raw = nil
|
||||||
|
|
||||||
|
local register_alias_raw = minetest.register_alias_raw
|
||||||
|
minetest.register_item_raw = nil
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Item / entity / ABM registration functions
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.registered_abms = {}
|
||||||
|
minetest.registered_entities = {}
|
||||||
|
minetest.registered_items = {}
|
||||||
|
minetest.registered_nodes = {}
|
||||||
|
minetest.registered_craftitems = {}
|
||||||
|
minetest.registered_tools = {}
|
||||||
|
minetest.registered_aliases = {}
|
||||||
|
|
||||||
|
-- For tables that are indexed by item name:
|
||||||
|
-- If table[X] does not exist, default to table[minetest.registered_aliases[X]]
|
||||||
|
local function set_alias_metatable(table)
|
||||||
|
setmetatable(table, {
|
||||||
|
__index = function(name)
|
||||||
|
return rawget(table, minetest.registered_aliases[name])
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
set_alias_metatable(minetest.registered_items)
|
||||||
|
set_alias_metatable(minetest.registered_nodes)
|
||||||
|
set_alias_metatable(minetest.registered_craftitems)
|
||||||
|
set_alias_metatable(minetest.registered_tools)
|
||||||
|
|
||||||
|
-- These item names may not be used because they would interfere
|
||||||
|
-- with legacy itemstrings
|
||||||
|
local forbidden_item_names = {
|
||||||
|
MaterialItem = true,
|
||||||
|
MaterialItem2 = true,
|
||||||
|
MaterialItem3 = true,
|
||||||
|
NodeItem = true,
|
||||||
|
node = true,
|
||||||
|
CraftItem = true,
|
||||||
|
craft = true,
|
||||||
|
MBOItem = true,
|
||||||
|
ToolItem = true,
|
||||||
|
tool = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function check_modname_prefix(name)
|
||||||
|
if name:sub(1,1) == ":" then
|
||||||
|
-- Escape the modname prefix enforcement mechanism
|
||||||
|
return name:sub(2)
|
||||||
|
else
|
||||||
|
-- Modname prefix enforcement
|
||||||
|
local expected_prefix = minetest.get_current_modname() .. ":"
|
||||||
|
if name:sub(1, #expected_prefix) ~= expected_prefix then
|
||||||
|
error("Name " .. name .. " does not follow naming conventions: " ..
|
||||||
|
"\"modname:\" or \":\" prefix required")
|
||||||
|
end
|
||||||
|
local subname = name:sub(#expected_prefix+1)
|
||||||
|
if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
|
||||||
|
error("Name " .. name .. " does not follow naming conventions: " ..
|
||||||
|
"contains unallowed characters")
|
||||||
|
end
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_abm(spec)
|
||||||
|
-- Add to minetest.registered_abms
|
||||||
|
minetest.registered_abms[#minetest.registered_abms+1] = spec
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_entity(name, prototype)
|
||||||
|
-- Check name
|
||||||
|
if name == nil then
|
||||||
|
error("Unable to register entity: Name is nil")
|
||||||
|
end
|
||||||
|
name = check_modname_prefix(tostring(name))
|
||||||
|
|
||||||
|
prototype.name = name
|
||||||
|
prototype.__index = prototype -- so that it can be used as a metatable
|
||||||
|
|
||||||
|
-- Add to minetest.registered_entities
|
||||||
|
minetest.registered_entities[name] = prototype
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_item(name, itemdef)
|
||||||
|
-- Check name
|
||||||
|
if name == nil then
|
||||||
|
error("Unable to register item: Name is nil")
|
||||||
|
end
|
||||||
|
name = check_modname_prefix(tostring(name))
|
||||||
|
if forbidden_item_names[name] then
|
||||||
|
error("Unable to register item: Name is forbidden: " .. name)
|
||||||
|
end
|
||||||
|
itemdef.name = name
|
||||||
|
|
||||||
|
-- Apply defaults and add to registered_* table
|
||||||
|
if itemdef.type == "node" then
|
||||||
|
-- Use the nodebox as selection box if it's not set manually
|
||||||
|
if itemdef.drawtype == "nodebox" and not itemdef.selection_box then
|
||||||
|
itemdef.selection_box = itemdef.node_box
|
||||||
|
end
|
||||||
|
setmetatable(itemdef, {__index = minetest.nodedef_default})
|
||||||
|
minetest.registered_nodes[itemdef.name] = itemdef
|
||||||
|
elseif itemdef.type == "craft" then
|
||||||
|
setmetatable(itemdef, {__index = minetest.craftitemdef_default})
|
||||||
|
minetest.registered_craftitems[itemdef.name] = itemdef
|
||||||
|
elseif itemdef.type == "tool" then
|
||||||
|
setmetatable(itemdef, {__index = minetest.tooldef_default})
|
||||||
|
minetest.registered_tools[itemdef.name] = itemdef
|
||||||
|
elseif itemdef.type == "none" then
|
||||||
|
setmetatable(itemdef, {__index = minetest.noneitemdef_default})
|
||||||
|
else
|
||||||
|
error("Unable to register item: Type is invalid: " .. dump(itemdef))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Flowing liquid uses param2
|
||||||
|
if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
|
||||||
|
itemdef.paramtype2 = "flowingliquid"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BEGIN Legacy stuff
|
||||||
|
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
|
||||||
|
minetest.register_craft({
|
||||||
|
type="cooking",
|
||||||
|
output=itemdef.cookresult_itemstring,
|
||||||
|
recipe=itemdef.name,
|
||||||
|
cooktime=itemdef.furnace_cooktime
|
||||||
|
})
|
||||||
|
end
|
||||||
|
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
|
||||||
|
minetest.register_craft({
|
||||||
|
type="fuel",
|
||||||
|
recipe=itemdef.name,
|
||||||
|
burntime=itemdef.furnace_burntime
|
||||||
|
})
|
||||||
|
end
|
||||||
|
-- END Legacy stuff
|
||||||
|
|
||||||
|
-- Disable all further modifications
|
||||||
|
getmetatable(itemdef).__newindex = {}
|
||||||
|
|
||||||
|
--minetest.log("Registering item: " .. itemdef.name)
|
||||||
|
minetest.registered_items[itemdef.name] = itemdef
|
||||||
|
minetest.registered_aliases[itemdef.name] = nil
|
||||||
|
register_item_raw(itemdef)
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_node(name, nodedef)
|
||||||
|
nodedef.type = "node"
|
||||||
|
minetest.register_item(name, nodedef)
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_craftitem(name, craftitemdef)
|
||||||
|
craftitemdef.type = "craft"
|
||||||
|
|
||||||
|
-- BEGIN Legacy stuff
|
||||||
|
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
|
||||||
|
craftitemdef.inventory_image = craftitemdef.image
|
||||||
|
end
|
||||||
|
-- END Legacy stuff
|
||||||
|
|
||||||
|
minetest.register_item(name, craftitemdef)
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_tool(name, tooldef)
|
||||||
|
tooldef.type = "tool"
|
||||||
|
tooldef.stack_max = 1
|
||||||
|
|
||||||
|
-- BEGIN Legacy stuff
|
||||||
|
if tooldef.inventory_image == nil and tooldef.image ~= nil then
|
||||||
|
tooldef.inventory_image = tooldef.image
|
||||||
|
end
|
||||||
|
if tooldef.tool_capabilities == nil and
|
||||||
|
(tooldef.full_punch_interval ~= nil or
|
||||||
|
tooldef.basetime ~= nil or
|
||||||
|
tooldef.dt_weight ~= nil or
|
||||||
|
tooldef.dt_crackiness ~= nil or
|
||||||
|
tooldef.dt_crumbliness ~= nil or
|
||||||
|
tooldef.dt_cuttability ~= nil or
|
||||||
|
tooldef.basedurability ~= nil or
|
||||||
|
tooldef.dd_weight ~= nil or
|
||||||
|
tooldef.dd_crackiness ~= nil or
|
||||||
|
tooldef.dd_crumbliness ~= nil or
|
||||||
|
tooldef.dd_cuttability ~= nil) then
|
||||||
|
tooldef.tool_capabilities = {
|
||||||
|
full_punch_interval = tooldef.full_punch_interval,
|
||||||
|
basetime = tooldef.basetime,
|
||||||
|
dt_weight = tooldef.dt_weight,
|
||||||
|
dt_crackiness = tooldef.dt_crackiness,
|
||||||
|
dt_crumbliness = tooldef.dt_crumbliness,
|
||||||
|
dt_cuttability = tooldef.dt_cuttability,
|
||||||
|
basedurability = tooldef.basedurability,
|
||||||
|
dd_weight = tooldef.dd_weight,
|
||||||
|
dd_crackiness = tooldef.dd_crackiness,
|
||||||
|
dd_crumbliness = tooldef.dd_crumbliness,
|
||||||
|
dd_cuttability = tooldef.dd_cuttability,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
-- END Legacy stuff
|
||||||
|
|
||||||
|
minetest.register_item(name, tooldef)
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.register_alias(name, convert_to)
|
||||||
|
if forbidden_item_names[name] then
|
||||||
|
error("Unable to register alias: Name is forbidden: " .. name)
|
||||||
|
end
|
||||||
|
if minetest.registered_items[name] ~= nil then
|
||||||
|
minetest.log("WARNING: Not registering alias, item with same name" ..
|
||||||
|
" is already defined: " .. name .. " -> " .. convert_to)
|
||||||
|
else
|
||||||
|
--minetest.log("Registering alias: " .. name .. " -> " .. convert_to)
|
||||||
|
minetest.registered_aliases[name] = convert_to
|
||||||
|
register_alias_raw(name, convert_to)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Alias the forbidden item names to "" so they can't be
|
||||||
|
-- created via itemstrings (e.g. /give)
|
||||||
|
local name
|
||||||
|
for name in pairs(forbidden_item_names) do
|
||||||
|
minetest.registered_aliases[name] = ""
|
||||||
|
register_alias_raw(name, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Deprecated:
|
||||||
|
-- Aliases for minetest.register_alias (how ironic...)
|
||||||
|
--minetest.alias_node = minetest.register_alias
|
||||||
|
--minetest.alias_tool = minetest.register_alias
|
||||||
|
--minetest.alias_craftitem = minetest.register_alias
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Built-in node definitions. Also defined in C.
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.register_item(":unknown", {
|
||||||
|
type = "none",
|
||||||
|
description = "Unknown Item",
|
||||||
|
inventory_image = "unknown_item.png",
|
||||||
|
on_place = minetest.item_place,
|
||||||
|
on_drop = minetest.item_drop,
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node(":air", {
|
||||||
|
description = "Air (you hacker you!)",
|
||||||
|
inventory_image = "unknown_node.png",
|
||||||
|
wield_image = "unknown_node.png",
|
||||||
|
drawtype = "airlike",
|
||||||
|
paramtype = "light",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
walkable = false,
|
||||||
|
pointable = false,
|
||||||
|
diggable = false,
|
||||||
|
buildable_to = true,
|
||||||
|
air_equivalent = true,
|
||||||
|
drop = "",
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node(":ignore", {
|
||||||
|
description = "Ignore (you hacker you!)",
|
||||||
|
inventory_image = "unknown_node.png",
|
||||||
|
wield_image = "unknown_node.png",
|
||||||
|
drawtype = "airlike",
|
||||||
|
paramtype = "none",
|
||||||
|
sunlight_propagates = false,
|
||||||
|
walkable = false,
|
||||||
|
pointable = false,
|
||||||
|
diggable = false,
|
||||||
|
buildable_to = true, -- A way to remove accidentally placed ignores
|
||||||
|
air_equivalent = true,
|
||||||
|
drop = "",
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
})
|
||||||
|
|
||||||
|
-- The hand (bare definition)
|
||||||
|
minetest.register_item(":", {
|
||||||
|
type = "none",
|
||||||
|
groups = {not_in_creative_inventory=1},
|
||||||
|
})
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Callback registration
|
||||||
|
--
|
||||||
|
|
||||||
|
local function make_registration()
|
||||||
|
local t = {}
|
||||||
|
local registerfunc = function(func) table.insert(t, func) end
|
||||||
|
return t, registerfunc
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_registration_reverse()
|
||||||
|
local t = {}
|
||||||
|
local registerfunc = function(func) table.insert(t, 1, func) end
|
||||||
|
return t, registerfunc
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.registered_on_chat_messages, minetest.register_on_chat_message = make_registration()
|
||||||
|
minetest.registered_globalsteps, minetest.register_globalstep = make_registration()
|
||||||
|
minetest.registered_on_mapgen_inits, minetest.register_on_mapgen_init = make_registration()
|
||||||
|
minetest.registered_on_shutdown, minetest.register_on_shutdown = make_registration()
|
||||||
|
minetest.registered_on_punchnodes, minetest.register_on_punchnode = make_registration()
|
||||||
|
minetest.registered_on_placenodes, minetest.register_on_placenode = make_registration()
|
||||||
|
minetest.registered_on_dignodes, minetest.register_on_dignode = make_registration()
|
||||||
|
minetest.registered_on_generateds, minetest.register_on_generated = make_registration()
|
||||||
|
minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registration()
|
||||||
|
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
|
||||||
|
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
|
||||||
|
minetest.registered_on_joinplayers, minetest.register_on_joinplayer = make_registration()
|
||||||
|
minetest.registered_on_leaveplayers, minetest.register_on_leaveplayer = make_registration()
|
||||||
|
minetest.registered_on_player_receive_fields, minetest.register_on_player_receive_fields = make_registration_reverse()
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
-- Minetest: builtin/privileges.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Privileges
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.registered_privileges = {}
|
||||||
|
|
||||||
|
function minetest.register_privilege(name, param)
|
||||||
|
local function fill_defaults(def)
|
||||||
|
if def.give_to_singleplayer == nil then
|
||||||
|
def.give_to_singleplayer = true
|
||||||
|
end
|
||||||
|
if def.description == nil then
|
||||||
|
def.description = "(no description)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local def = {}
|
||||||
|
if type(param) == "table" then
|
||||||
|
def = param
|
||||||
|
else
|
||||||
|
def = {description = param}
|
||||||
|
end
|
||||||
|
fill_defaults(def)
|
||||||
|
minetest.registered_privileges[name] = def
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_privilege("interact", "Can interact with things and modify the world")
|
||||||
|
minetest.register_privilege("teleport", "Can use /teleport command")
|
||||||
|
minetest.register_privilege("bring", "Can teleport other players")
|
||||||
|
minetest.register_privilege("settime", "Can use /time")
|
||||||
|
minetest.register_privilege("privs", "Can modify privileges")
|
||||||
|
minetest.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
|
||||||
|
minetest.register_privilege("server", "Can do server maintenance stuff")
|
||||||
|
minetest.register_privilege("shout", "Can speak in chat")
|
||||||
|
minetest.register_privilege("ban", "Can ban and unban players")
|
||||||
|
minetest.register_privilege("give", "Can use /give and /giveme")
|
||||||
|
minetest.register_privilege("password", "Can use /setpassword and /clearpassword")
|
||||||
|
minetest.register_privilege("fly", {
|
||||||
|
description = "Can fly using the free_move mode",
|
||||||
|
give_to_singleplayer = false,
|
||||||
|
})
|
||||||
|
minetest.register_privilege("fast", {
|
||||||
|
description = "Can walk fast using the fast_move mode",
|
||||||
|
give_to_singleplayer = false,
|
||||||
|
})
|
||||||
|
minetest.register_privilege("noclip", {
|
||||||
|
description = "Can fly through walls",
|
||||||
|
give_to_singleplayer = false,
|
||||||
|
})
|
||||||
|
minetest.register_privilege("rollback", "Can use the rollback functionality")
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
-- 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>
|
||||||
|
-- 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.
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local no_identity = { number=1, boolean=1, string=1, ['nil']=1 }
|
||||||
|
|
||||||
|
function minetest.serialize(x)
|
||||||
|
|
||||||
|
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.
|
||||||
|
--
|
||||||
|
-- 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)
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nested [x] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local dumped = { } -- multiply occuring values already dumped in localdefs
|
||||||
|
local localdefs = { } -- already dumped local definitions as source code lines
|
||||||
|
|
||||||
|
-- mutually recursive 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 .. "]"
|
||||||
|
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.
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
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=="table" then
|
||||||
|
local acc = { }
|
||||||
|
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))
|
||||||
|
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))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return "{ "..table.concat(acc,", ").." }"
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mark_multiple_occurences (x)
|
||||||
|
local toplevel = dump_or_ref_val (x)
|
||||||
|
dump_nest_patches()
|
||||||
|
|
||||||
|
if next (localdefs) then
|
||||||
|
return "local _={ }\n" ..
|
||||||
|
table.concat (localdefs, "\n") ..
|
||||||
|
"\nreturn " .. toplevel
|
||||||
|
else
|
||||||
|
return "return " .. toplevel
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Deserialization.
|
||||||
|
-- http://stackoverflow.com/questions/5958818/loading-serialized-data-into-a-table
|
||||||
|
--
|
||||||
|
|
||||||
|
local function stringtotable(sdata)
|
||||||
|
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
|
||||||
|
setfenv(f, table)
|
||||||
|
return f()
|
||||||
|
end
|
||||||
|
|
||||||
|
function minetest.deserialize(sdata)
|
||||||
|
local table = {}
|
||||||
|
local okay,results = pcall(stringtotable, sdata)
|
||||||
|
if okay then
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
print('error:'.. 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
|
||||||
|
|
||||||
|
unittest_input = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
|
||||||
|
unittest_output = minetest.deserialize(minetest.serialize(unittest_input))
|
||||||
|
|
||||||
|
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 = minetest.deserialize(minetest.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
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
-- Minetest: builtin/static_spawn.lua
|
||||||
|
|
||||||
|
local function warn_invalid_static_spawnpoint()
|
||||||
|
if minetest.setting_get("static_spawnpoint") and
|
||||||
|
not minetest.setting_get_pos("static_spawnpoint") then
|
||||||
|
minetest.log('error', "The static_spawnpoint setting is invalid: \""..
|
||||||
|
minetest.setting_get("static_spawnpoint").."\"")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
warn_invalid_static_spawnpoint()
|
||||||
|
|
||||||
|
local function put_player_in_spawn(obj)
|
||||||
|
warn_invalid_static_spawnpoint()
|
||||||
|
local static_spawnpoint = minetest.setting_get_pos("static_spawnpoint")
|
||||||
|
if not static_spawnpoint then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
minetest.log('action', "Moving "..obj:get_player_name()..
|
||||||
|
" to static spawnpoint at "..
|
||||||
|
minetest.pos_to_string(static_spawnpoint))
|
||||||
|
obj:setpos(static_spawnpoint)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_newplayer(function(obj)
|
||||||
|
put_player_in_spawn(obj)
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_respawnplayer(function(obj)
|
||||||
|
return put_player_in_spawn(obj)
|
||||||
|
end)
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
VoxelArea = {
|
||||||
|
MinEdge = {x=1, y=1, z=1},
|
||||||
|
MaxEdge = {x=0, y=0, z=0},
|
||||||
|
ystride = 0,
|
||||||
|
zstride = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
function VoxelArea:new(o)
|
||||||
|
o = o or {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
|
||||||
|
local e = o:getExtent()
|
||||||
|
o.ystride = e.x
|
||||||
|
o.zstride = e.x * e.y
|
||||||
|
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
function VoxelArea:getExtent()
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function VoxelArea:getVolume()
|
||||||
|
local e = self:getExtent()
|
||||||
|
return e.x * e.y * e.z
|
||||||
|
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
|
||||||
|
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
|
||||||
|
return math.floor(i)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
function VoxelArea:containsi(i)
|
||||||
|
return (i >= 1) and (i <= self:getVolume())
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
|
@ -0,0 +1 @@
|
||||||
|
trans_alphach_ref
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
uniform sampler2D myTexture;
|
||||||
|
uniform vec4 skyBgColor;
|
||||||
|
uniform float fogDistance;
|
||||||
|
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main (void)
|
||||||
|
{
|
||||||
|
//vec4 col = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||||
|
float a = col.a;
|
||||||
|
col *= gl_Color;
|
||||||
|
col = col * col; // SRGB -> Linear
|
||||||
|
col *= 1.8;
|
||||||
|
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||||
|
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||||
|
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||||
|
col = sqrt(col); // Linear -> SRGB
|
||||||
|
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.r, col.g, col.b, a);
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
uniform mat4 mWorldViewProj;
|
||||||
|
uniform mat4 mInvWorld;
|
||||||
|
uniform mat4 mTransWorld;
|
||||||
|
uniform float dayNightRatio;
|
||||||
|
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_Position = mWorldViewProj * gl_Vertex;
|
||||||
|
|
||||||
|
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||||
|
|
||||||
|
vec4 color;
|
||||||
|
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
float day = gl_Color.r;
|
||||||
|
float night = gl_Color.g;
|
||||||
|
float light_source = gl_Color.b;
|
||||||
|
|
||||||
|
/*color.r = mix(night, day, dayNightRatio);
|
||||||
|
color.g = color.r;
|
||||||
|
color.b = color.r;*/
|
||||||
|
|
||||||
|
float rg = mix(night, day, dayNightRatio);
|
||||||
|
rg += light_source * 1.0; // Make light sources brighter
|
||||||
|
float b = rg;
|
||||||
|
|
||||||
|
// Moonlight is blue
|
||||||
|
b += (day - night) / 13.0;
|
||||||
|
rg -= (day - night) / 13.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;
|
||||||
|
|
||||||
|
// Make sides and bottom darker than the top
|
||||||
|
color = color * color; // SRGB -> Linear
|
||||||
|
if(gl_Normal.y <= 0.5)
|
||||||
|
color *= 0.6;
|
||||||
|
//color *= 0.7;
|
||||||
|
color = sqrt(color); // Linear -> SRGB
|
||||||
|
|
||||||
|
color.a = gl_Color.a;
|
||||||
|
|
||||||
|
gl_FrontColor = gl_BackColor = color;
|
||||||
|
|
||||||
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
trans_alphach
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
uniform sampler2D myTexture;
|
||||||
|
uniform float fogDistance;
|
||||||
|
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main (void)
|
||||||
|
{
|
||||||
|
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||||
|
col *= gl_Color;
|
||||||
|
float a = gl_Color.a;
|
||||||
|
col = col * col; // SRGB -> Linear
|
||||||
|
col *= 1.8;
|
||||||
|
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||||
|
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||||
|
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||||
|
col = sqrt(col); // Linear -> SRGB
|
||||||
|
if(fogDistance != 0.0){
|
||||||
|
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||||
|
a = mix(a, 0.0, d);
|
||||||
|
}
|
||||||
|
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
uniform mat4 mWorldViewProj;
|
||||||
|
uniform mat4 mInvWorld;
|
||||||
|
uniform mat4 mTransWorld;
|
||||||
|
uniform float dayNightRatio;
|
||||||
|
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_Position = mWorldViewProj * gl_Vertex;
|
||||||
|
|
||||||
|
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||||
|
|
||||||
|
vec4 color;
|
||||||
|
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
float day = gl_Color.r;
|
||||||
|
float night = gl_Color.g;
|
||||||
|
float light_source = gl_Color.b;
|
||||||
|
|
||||||
|
/*color.r = mix(night, day, dayNightRatio);
|
||||||
|
color.g = color.r;
|
||||||
|
color.b = color.r;*/
|
||||||
|
|
||||||
|
float rg = mix(night, day, dayNightRatio);
|
||||||
|
rg += light_source * 1.0; // Make light sources brighter
|
||||||
|
float b = rg;
|
||||||
|
|
||||||
|
// Moonlight is blue
|
||||||
|
b += (day - night) / 13.0;
|
||||||
|
rg -= (day - night) / 13.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 = color;
|
||||||
|
|
||||||
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
trans_alphach
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
uniform sampler2D myTexture;
|
||||||
|
uniform float fogDistance;
|
||||||
|
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main (void)
|
||||||
|
{
|
||||||
|
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||||
|
col *= gl_Color;
|
||||||
|
float a = col.a;
|
||||||
|
col = col * col; // SRGB -> Linear
|
||||||
|
col *= 1.8;
|
||||||
|
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||||
|
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||||
|
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||||
|
col = sqrt(col); // Linear -> SRGB
|
||||||
|
|
||||||
|
if(fogDistance != 0.0){
|
||||||
|
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||||
|
a = mix(a, 0.0, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
uniform mat4 mWorldViewProj;
|
||||||
|
uniform mat4 mInvWorld;
|
||||||
|
uniform mat4 mTransWorld;
|
||||||
|
uniform float dayNightRatio;
|
||||||
|
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_Position = mWorldViewProj * gl_Vertex;
|
||||||
|
|
||||||
|
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||||
|
|
||||||
|
vec4 color;
|
||||||
|
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
float day = gl_Color.r;
|
||||||
|
float night = gl_Color.g;
|
||||||
|
float light_source = gl_Color.b;
|
||||||
|
|
||||||
|
/*color.r = mix(night, day, dayNightRatio);
|
||||||
|
color.g = color.r;
|
||||||
|
color.b = color.r;*/
|
||||||
|
|
||||||
|
float rg = mix(night, day, dayNightRatio);
|
||||||
|
rg += light_source * 1.0; // Make light sources brighter
|
||||||
|
float b = rg;
|
||||||
|
|
||||||
|
// Moonlight is blue
|
||||||
|
b += (day - night) / 13.0;
|
||||||
|
rg -= (day - night) / 13.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 = color;
|
||||||
|
|
||||||
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
# - 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.
|
||||||
|
|
||||||
|
if( UNIX )
|
||||||
|
FIND_PATH(CURL_INCLUDE_DIR NAMES curl.h
|
||||||
|
PATHS
|
||||||
|
/usr/local/include/curl
|
||||||
|
/usr/include/curl
|
||||||
|
)
|
||||||
|
|
||||||
|
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.
|
||||||
|
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 )
|
||||||
|
|
||||||
|
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 )
|
||||||
|
|
||||||
|
MESSAGE(STATUS "CURL_INCLUDE_DIR = ${CURL_INCLUDE_DIR}")
|
||||||
|
MESSAGE(STATUS "CURL_LIBRARY = ${CURL_LIBRARY}")
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Package finder for gettext libs and include files
|
||||||
|
|
||||||
|
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
|
||||||
|
NAMES libintl.h
|
||||||
|
PATHS "${CUSTOM_GETTEXT_PATH}/include"
|
||||||
|
DOC "gettext include directory")
|
||||||
|
|
||||||
|
FIND_PROGRAM(GETTEXT_MSGFMT
|
||||||
|
NAMES msgfmt
|
||||||
|
PATHS "${CUSTOM_GETTEXT_PATH}/bin"
|
||||||
|
DOC "path to msgfmt")
|
||||||
|
|
||||||
|
# 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
|
||||||
|
libintl.lib intl.lib libintl3.lib intl3.lib)
|
||||||
|
ELSE()
|
||||||
|
SET(GETTEXT_LIB_NAMES
|
||||||
|
libintl.dll.a intl.dll.a libintl3.dll.a intl3.dll.a)
|
||||||
|
ENDIF()
|
||||||
|
FIND_LIBRARY(GETTEXT_LIBRARY
|
||||||
|
NAMES ${GETTEXT_LIB_NAMES}
|
||||||
|
PATHS "${CUSTOM_GETTEXT_PATH}/lib"
|
||||||
|
DOC "gettext *intl*.lib")
|
||||||
|
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
|
||||||
|
NAMES libiconv2.dll
|
||||||
|
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
|
||||||
|
DOC "gettext *iconv*.lib")
|
||||||
|
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()
|
|
@ -0,0 +1,94 @@
|
||||||
|
#FindIrrlicht.cmake
|
||||||
|
|
||||||
|
set(IRRLICHT_SOURCE_DIR "" CACHE PATH "Path to irrlicht source directory (optional)")
|
||||||
|
|
||||||
|
if( UNIX )
|
||||||
|
# Unix
|
||||||
|
else( UNIX )
|
||||||
|
# Windows
|
||||||
|
endif( UNIX )
|
||||||
|
|
||||||
|
# Find include directory
|
||||||
|
|
||||||
|
if(NOT IRRLICHT_SOURCE_DIR STREQUAL "")
|
||||||
|
set(IRRLICHT_SOURCE_DIR_INCLUDE
|
||||||
|
"${IRRLICHT_SOURCE_DIR}/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a Irrlicht Irrlicht.lib)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
if(MSVC)
|
||||||
|
set(IRRLICHT_SOURCE_DIR_LIBS "${IRRLICHT_SOURCE_DIR}/lib/Win32-visualstudio")
|
||||||
|
set(IRRLICHT_LIBRARY_NAMES Irrlicht.lib)
|
||||||
|
else()
|
||||||
|
set(IRRLICHT_SOURCE_DIR_LIBS "${IRRLICHT_SOURCE_DIR}/lib/Win32-gcc")
|
||||||
|
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a libIrrlicht.dll.a)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(IRRLICHT_SOURCE_DIR_LIBS "${IRRLICHT_SOURCE_DIR}/lib/Linux")
|
||||||
|
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
FIND_PATH(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
|
||||||
|
PATHS
|
||||||
|
${IRRLICHT_SOURCE_DIR_INCLUDE}
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
PATHS
|
||||||
|
/usr/local/include/irrlicht
|
||||||
|
/usr/include/irrlicht
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(IRRLICHT_LIBRARY NAMES 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
|
||||||
|
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)"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
FIND_FILE(IRRLICHT_DLL NAMES Irrlicht.dll
|
||||||
|
PATHS
|
||||||
|
"${IRRLICHT_SOURCE_DIR}/bin/Win32-gcc"
|
||||||
|
DOC "Path of the Irrlicht dll (for installation)"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
MESSAGE(STATUS "IRRLICHT_DLL = ${IRRLICHT_DLL}")
|
||||||
|
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)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Look for json, use our own if not found
|
||||||
|
|
||||||
|
#FIND_PATH(JSON_INCLUDE_DIR json.h)
|
||||||
|
|
||||||
|
#FIND_LIBRARY(JSON_LIBRARY NAMES jsoncpp)
|
||||||
|
|
||||||
|
#IF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
|
||||||
|
# SET( JSON_FOUND TRUE )
|
||||||
|
#ENDIF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
|
||||||
|
|
||||||
|
#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)
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Look for jthread, use our own if not found
|
||||||
|
|
||||||
|
FIND_PATH(JTHREAD_INCLUDE_DIR jthread.h)
|
||||||
|
|
||||||
|
FIND_LIBRARY(JTHREAD_LIBRARY NAMES jthread)
|
||||||
|
|
||||||
|
IF(JTHREAD_LIBRARY AND JTHREAD_INCLUDE_DIR)
|
||||||
|
SET( JTHREAD_FOUND TRUE )
|
||||||
|
ENDIF(JTHREAD_LIBRARY AND JTHREAD_INCLUDE_DIR)
|
||||||
|
|
||||||
|
IF(JTHREAD_FOUND)
|
||||||
|
MESSAGE(STATUS "Found system jthread header file in ${JTHREAD_INCLUDE_DIR}")
|
||||||
|
MESSAGE(STATUS "Found system jthread library ${JTHREAD_LIBRARY}")
|
||||||
|
ELSE(JTHREAD_FOUND)
|
||||||
|
SET(JTHREAD_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/jthread)
|
||||||
|
SET(JTHREAD_LIBRARY jthread)
|
||||||
|
MESSAGE(STATUS "Using project jthread library")
|
||||||
|
ENDIF(JTHREAD_FOUND)
|
|
@ -0,0 +1,130 @@
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
# This file is stolen from part of the CMake build system for OGRE (Object-oriented Graphics Rendering Engine) http://www.ogre3d.org/
|
||||||
|
#
|
||||||
|
# The contents of this file are placed in the public domain. Feel
|
||||||
|
# free to make use of it in any way you like.
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
# - Try to find OpenGLES and EGL
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# OPENGLES2_FOUND - system has OpenGLES
|
||||||
|
# OPENGLES2_INCLUDE_DIR - the GL include directory
|
||||||
|
# OPENGLES2_LIBRARIES - Link these to use OpenGLES
|
||||||
|
#
|
||||||
|
# EGL_FOUND - system has EGL
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
create_search_paths(/Developer/Platforms)
|
||||||
|
findpkg_framework(OpenGLES2)
|
||||||
|
set(OPENGLES2_gl_LIBRARY "-framework OpenGLES")
|
||||||
|
|
||||||
|
ELSE(APPLE)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(EGL_egl_LIBRARY
|
||||||
|
NAMES EGL
|
||||||
|
PATHS /opt/graphics/OpenGL/lib
|
||||||
|
/usr/openwin/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.
|
||||||
|
|
||||||
|
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 ()
|
||||||
|
|
||||||
|
ENDIF(APPLE)
|
||||||
|
ENDIF (WIN32)
|
||||||
|
|
||||||
|
#SET( OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_LIBRARIES})
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
IF(OPENGLES2_FOUND)
|
||||||
|
MESSAGE(STATUS "Found system opengles2 library ${OPENGLES2_LIBRARIES}")
|
||||||
|
ELSE ()
|
||||||
|
SET(OPENGLES2_LIBRARIES "")
|
||||||
|
ENDIF ()
|
|
@ -0,0 +1,18 @@
|
||||||
|
# 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)
|
|
@ -0,0 +1,46 @@
|
||||||
|
# - Find vorbis
|
||||||
|
# Find the native vorbis includes and libraries
|
||||||
|
#
|
||||||
|
# VORBIS_INCLUDE_DIR - where to find vorbis.h, etc.
|
||||||
|
# OGG_INCLUDE_DIR - where to find ogg/ogg.h, etc.
|
||||||
|
# VORBIS_LIBRARIES - List of libraries when using vorbis(file).
|
||||||
|
# VORBIS_FOUND - True if vorbis found.
|
||||||
|
|
||||||
|
if(NOT GP2XWIZ)
|
||||||
|
if(VORBIS_INCLUDE_DIR)
|
||||||
|
# Already in cache, be silent
|
||||||
|
set(VORBIS_FIND_QUIETLY TRUE)
|
||||||
|
endif(VORBIS_INCLUDE_DIR)
|
||||||
|
find_path(OGG_INCLUDE_DIR ogg/ogg.h)
|
||||||
|
find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h)
|
||||||
|
# MSVC built ogg/vorbis may be named ogg_static and vorbis_static
|
||||||
|
find_library(OGG_LIBRARY NAMES ogg ogg_static)
|
||||||
|
find_library(VORBIS_LIBRARY NAMES vorbis vorbis_static)
|
||||||
|
find_library(VORBISFILE_LIBRARY NAMES vorbisfile vorbisfile_static)
|
||||||
|
# Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND
|
||||||
|
# to TRUE if all listed variables are TRUE.
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(VORBIS DEFAULT_MSG
|
||||||
|
OGG_INCLUDE_DIR VORBIS_INCLUDE_DIR
|
||||||
|
OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY)
|
||||||
|
else(NOT GP2XWIZ)
|
||||||
|
find_path(VORBIS_INCLUDE_DIR tremor/ivorbisfile.h)
|
||||||
|
find_library(VORBIS_LIBRARY NAMES vorbis_dec)
|
||||||
|
find_package_handle_standard_args(VORBIS DEFAULT_MSG
|
||||||
|
VORBIS_INCLUDE_DIR VORBIS_LIBRARY)
|
||||||
|
endif(NOT GP2XWIZ)
|
||||||
|
|
||||||
|
if(VORBIS_FOUND)
|
||||||
|
if(NOT GP2XWIZ)
|
||||||
|
set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY}
|
||||||
|
${OGG_LIBRARY})
|
||||||
|
else(NOT GP2XWIZ)
|
||||||
|
set(VORBIS_LIBRARIES ${VORBIS_LIBRARY})
|
||||||
|
endif(NOT GP2XWIZ)
|
||||||
|
else(VORBIS_FOUND)
|
||||||
|
set(VORBIS_LIBRARIES)
|
||||||
|
endif(VORBIS_FOUND)
|
||||||
|
|
||||||
|
mark_as_advanced(OGG_INCLUDE_DIR VORBIS_INCLUDE_DIR)
|
||||||
|
mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY)
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#
|
||||||
|
# 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)
|
||||||
|
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU 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.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
|
@ -0,0 +1,583 @@
|
||||||
|
=============================
|
||||||
|
Minetest World Format 22...25
|
||||||
|
=============================
|
||||||
|
|
||||||
|
This applies to a world format carrying the block serialization version
|
||||||
|
22...25, used at least in
|
||||||
|
- 0.4.dev-20120322 ... 0.4.dev-20120606 (22...23)
|
||||||
|
- 0.4.0 (23)
|
||||||
|
- 24 was never released as stable and existed for ~2 days
|
||||||
|
|
||||||
|
The block serialization version does not fully specify every aspect of this
|
||||||
|
format; if compliance with this format is to be checked, it needs to be
|
||||||
|
done by detecting if the files and data indeed follows it.
|
||||||
|
|
||||||
|
Legacy stuff
|
||||||
|
=============
|
||||||
|
Data can, in theory, be contained in the flat file directory structure
|
||||||
|
described below in Version 17, but it is not officially supported. Also you
|
||||||
|
may stumble upon all kinds of oddities in not-so-recent formats.
|
||||||
|
|
||||||
|
Files
|
||||||
|
======
|
||||||
|
Everything is contained in a directory, the name of which is freeform, but
|
||||||
|
often serves as the name of the world.
|
||||||
|
|
||||||
|
Currently the authentication and ban data is stored on a per-world basis.
|
||||||
|
It can be copied over from an old world to a newly created world.
|
||||||
|
|
||||||
|
World
|
||||||
|
|-- auth.txt ----- Authentication data
|
||||||
|
|-- env_meta.txt - Environment metadata
|
||||||
|
|-- ipban.txt ---- Banned ips/users
|
||||||
|
|-- map_meta.txt - Map metadata
|
||||||
|
|-- map.sqlite --- Map data
|
||||||
|
|-- players ------ Player directory
|
||||||
|
| |-- player1 -- Player file
|
||||||
|
| '-- Foo ------ Player file
|
||||||
|
`-- world.mt ----- World metadata
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Example lines:
|
||||||
|
- Player "celeron55", no password, privileges "interact" and "shout":
|
||||||
|
celeron55::interact,shout
|
||||||
|
- Player "Foo", password "bar", privilege "shout":
|
||||||
|
foo:iEPX+SQWIR3p67lj/0zigSWTKHg:shout
|
||||||
|
- Player "bar", no password, no privileges:
|
||||||
|
bar::
|
||||||
|
|
||||||
|
env_meta.txt
|
||||||
|
-------------
|
||||||
|
Simple global environment variables.
|
||||||
|
Example content (added indentation):
|
||||||
|
game_time = 73471
|
||||||
|
time_of_day = 19118
|
||||||
|
EnvArgsEnd
|
||||||
|
|
||||||
|
ipban.txt
|
||||||
|
----------
|
||||||
|
Banned IP addresses and usernames.
|
||||||
|
Example content (added indentation):
|
||||||
|
123.456.78.9|foo
|
||||||
|
123.456.78.10|bar
|
||||||
|
|
||||||
|
map_meta.txt
|
||||||
|
-------------
|
||||||
|
Simple global map variables.
|
||||||
|
Example content (added indentation):
|
||||||
|
seed = 7980462765762429666
|
||||||
|
[end_of_params]
|
||||||
|
|
||||||
|
map.sqlite
|
||||||
|
-----------
|
||||||
|
Map data.
|
||||||
|
See Map File Format below.
|
||||||
|
|
||||||
|
player1, Foo
|
||||||
|
-------------
|
||||||
|
Player data.
|
||||||
|
Filename can be anything.
|
||||||
|
See Player File Format below.
|
||||||
|
|
||||||
|
world.mt
|
||||||
|
---------
|
||||||
|
World metadata.
|
||||||
|
Example content (added indentation):
|
||||||
|
gameid = mesetint
|
||||||
|
|
||||||
|
Player File Format
|
||||||
|
===================
|
||||||
|
|
||||||
|
- Should be pretty self-explanatory.
|
||||||
|
- Note: position is in nodes * 10
|
||||||
|
|
||||||
|
Example content (added indentation):
|
||||||
|
hp = 11
|
||||||
|
name = celeron55
|
||||||
|
pitch = 39.77
|
||||||
|
position = (-5231.97,15,1961.41)
|
||||||
|
version = 1
|
||||||
|
yaw = 101.37
|
||||||
|
PlayerArgsEnd
|
||||||
|
List main 32
|
||||||
|
Item default:torch 13
|
||||||
|
Item default:pick_steel 1 50112
|
||||||
|
Item experimental:tnt
|
||||||
|
Item default:cobble 99
|
||||||
|
Item default:pick_stone 1 13104
|
||||||
|
Item default:shovel_steel 1 51838
|
||||||
|
Item default:dirt 61
|
||||||
|
Item default:rail 78
|
||||||
|
Item default:coal_lump 3
|
||||||
|
Item default:cobble 99
|
||||||
|
Item default:leaves 22
|
||||||
|
Item default:gravel 52
|
||||||
|
Item default:axe_steel 1 2045
|
||||||
|
Item default:cobble 98
|
||||||
|
Item default:sand 61
|
||||||
|
Item default:water_source 94
|
||||||
|
Item default:glass 2
|
||||||
|
Item default:mossycobble
|
||||||
|
Item default:pick_steel 1 64428
|
||||||
|
Item animalmaterials:bone
|
||||||
|
Item default:sword_steel
|
||||||
|
Item default:sapling
|
||||||
|
Item default:sword_stone 1 10647
|
||||||
|
Item default:dirt 99
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
EndInventoryList
|
||||||
|
List craft 9
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
EndInventoryList
|
||||||
|
List craftpreview 1
|
||||||
|
Empty
|
||||||
|
EndInventoryList
|
||||||
|
List craftresult 1
|
||||||
|
Empty
|
||||||
|
EndInventoryList
|
||||||
|
EndInventory
|
||||||
|
|
||||||
|
Map File Format
|
||||||
|
================
|
||||||
|
|
||||||
|
Minetest maps consist of MapBlocks, chunks of 16x16x16 nodes.
|
||||||
|
|
||||||
|
In addition to the bulk node data, MapBlocks stored on disk also contain
|
||||||
|
other things.
|
||||||
|
|
||||||
|
History
|
||||||
|
--------
|
||||||
|
We need a bit of history in here. Initially Minetest stored maps in a
|
||||||
|
format called the "sectors" format. It was a directory/file structure like
|
||||||
|
this:
|
||||||
|
sectors2/XXX/ZZZ/YYYY
|
||||||
|
For example, the MapBlock at (0,1,-2) was this file:
|
||||||
|
sectors2/000/ffd/0001
|
||||||
|
|
||||||
|
Eventually Minetest outgrow this directory structure, as filesystems were
|
||||||
|
struggling under the amount of files and directories.
|
||||||
|
|
||||||
|
Large servers seriously needed a new format, and thus the base of the
|
||||||
|
current format was invented, suggested by celeron55 and implemented by
|
||||||
|
JacobF.
|
||||||
|
|
||||||
|
SQLite3 was slammed in, and blocks files were directly inserted as blobs
|
||||||
|
in a single table, indexed by integer primary keys, oddly mangled from
|
||||||
|
coordinates.
|
||||||
|
|
||||||
|
Today we know that SQLite3 allows multiple primary keys (which would allow
|
||||||
|
storing coordinates separately), but the format has been kept unchanged for
|
||||||
|
that part. So, this is where it has come.
|
||||||
|
</history>
|
||||||
|
|
||||||
|
So here goes
|
||||||
|
-------------
|
||||||
|
map.sqlite is an sqlite3 database, containg a single table, called
|
||||||
|
"blocks". It looks like this:
|
||||||
|
|
||||||
|
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY,`data` BLOB);
|
||||||
|
|
||||||
|
The key
|
||||||
|
--------
|
||||||
|
"pos" is created from the three coordinates of a MapBlock using this
|
||||||
|
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):
|
||||||
|
x = unsignedToSigned(i % 4096, 2048)
|
||||||
|
i = int((i - x) / 4096)
|
||||||
|
y = unsignedToSigned(i % 4096, 2048)
|
||||||
|
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
|
||||||
|
else:
|
||||||
|
return i - 2*max_positive
|
||||||
|
|
||||||
|
The blob
|
||||||
|
---------
|
||||||
|
The blob is the data that would have otherwise gone into the file.
|
||||||
|
|
||||||
|
See below for description.
|
||||||
|
|
||||||
|
MapBlock serialization format
|
||||||
|
==============================
|
||||||
|
NOTE: Byte order is MSB first (big-endian).
|
||||||
|
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
|
||||||
|
|
||||||
|
u8 flags
|
||||||
|
- Flag bitmasks:
|
||||||
|
- 0x01: is_underground: Should be set to 0 if there will be no light
|
||||||
|
obstructions above the block. If/when sunlight of a block is updated
|
||||||
|
and there is no block above it, this value is checked for determining
|
||||||
|
whether sunlight comes from the top.
|
||||||
|
- 0x02: day_night_differs: Whether the lighting of the block is different
|
||||||
|
on day and night. Only blocks that have this bit set are updated when
|
||||||
|
day transforms to night.
|
||||||
|
- 0x04: lighting_expired: If true, lighting is invalid and should be
|
||||||
|
updated. If you can't calculate lighting in your generator properly,
|
||||||
|
you could try setting this 1 to everything and setting the uppermost
|
||||||
|
block in every sector as is_underground=0. I am quite sure it doesn't
|
||||||
|
work properly, though.
|
||||||
|
- 0x08: generated: True if the block has been generated. If false, block
|
||||||
|
is mostly filled with CONTENT_IGNORE and is likely to contain eg. parts
|
||||||
|
of trees of neighboring blocks.
|
||||||
|
|
||||||
|
u8 content_width
|
||||||
|
- Number of bytes in the content (param0) fields of nodes
|
||||||
|
if map format version <= 23:
|
||||||
|
- Always 1
|
||||||
|
if map format version >= 24:
|
||||||
|
- Always 2
|
||||||
|
|
||||||
|
u8 params_width
|
||||||
|
- Number of bytes used for parameters per node
|
||||||
|
- Always 2
|
||||||
|
|
||||||
|
zlib-compressed node data:
|
||||||
|
if content_width == 1:
|
||||||
|
- content:
|
||||||
|
u8[4096]: param0 fields
|
||||||
|
u8[4096]: param1 fields
|
||||||
|
u8[4096]: param2 fields
|
||||||
|
if content_width == 2:
|
||||||
|
- content:
|
||||||
|
u16[4096]: param0 fields
|
||||||
|
u8[4096]: param1 fields
|
||||||
|
u8[4096]: param2 fields
|
||||||
|
- The location of a node in each of those arrays is (z*16*16 + y*16 + x).
|
||||||
|
|
||||||
|
zlib-compressed node metadata list
|
||||||
|
- content:
|
||||||
|
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)
|
||||||
|
|
||||||
|
- Node timers
|
||||||
|
if map format version == 23:
|
||||||
|
u8 unused version (always 0)
|
||||||
|
if map format version == 24: (NOTE: Not released as stable)
|
||||||
|
u8 nodetimer_version
|
||||||
|
if nodetimer_version == 0:
|
||||||
|
(nothing else)
|
||||||
|
if nodetimer_version == 1:
|
||||||
|
u16 num_of_timers
|
||||||
|
foreach num_of_timers:
|
||||||
|
u16 timer position (z*16*16 + y*16 + x)
|
||||||
|
s32 timeout*1000
|
||||||
|
s32 elapsed*1000
|
||||||
|
|
||||||
|
u8 static object version:
|
||||||
|
- Always 0
|
||||||
|
|
||||||
|
u16 static_object_count
|
||||||
|
|
||||||
|
foreach static_object_count:
|
||||||
|
u8 type (object type-id)
|
||||||
|
s32 pos_x_nodes * 10000
|
||||||
|
s32 pos_y_nodes * 10000
|
||||||
|
s32 pos_z_nodes * 10000
|
||||||
|
u16 data_size
|
||||||
|
u8[data_size] data
|
||||||
|
|
||||||
|
u32 timestamp
|
||||||
|
- Timestamp when last saved, as seconds from starting the game.
|
||||||
|
- 0xffffffff = invalid/unknown timestamp, nothing should be done with the time
|
||||||
|
difference when loaded
|
||||||
|
|
||||||
|
u8 name-id-mapping version
|
||||||
|
- Always 0
|
||||||
|
|
||||||
|
u16 num_name_id_mappings
|
||||||
|
|
||||||
|
foreach num_name_id_mappings
|
||||||
|
u16 id
|
||||||
|
u16 name_len
|
||||||
|
u8[name_len] name
|
||||||
|
|
||||||
|
- Node timers
|
||||||
|
if map format version == 25:
|
||||||
|
u8 length of the data of a single timer (always 2+4+4=10)
|
||||||
|
u16 num_of_timers
|
||||||
|
foreach num_of_timers:
|
||||||
|
u16 timer position (z*16*16 + y*16 + x)
|
||||||
|
s32 timeout*1000
|
||||||
|
s32 elapsed*1000
|
||||||
|
|
||||||
|
EOF.
|
||||||
|
|
||||||
|
Format of nodes
|
||||||
|
----------------
|
||||||
|
A node is composed of the u8 fields param0, param1 and param2.
|
||||||
|
|
||||||
|
if map format version <= 23:
|
||||||
|
The content id of a node is determined as so:
|
||||||
|
- If param0 < 0x80,
|
||||||
|
content_id = param0
|
||||||
|
- Otherwise
|
||||||
|
content_id = (param0<<4) + (param2>>4)
|
||||||
|
if map format version >= 24:
|
||||||
|
The content id of a node is param0.
|
||||||
|
|
||||||
|
The purpose of param1 and param2 depend on the definition of the node.
|
||||||
|
|
||||||
|
The name-id-mapping
|
||||||
|
--------------------
|
||||||
|
The mapping maps node content ids to node names.
|
||||||
|
|
||||||
|
Node metadata format
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
1: Generic metadata
|
||||||
|
serialized inventory
|
||||||
|
u32 len
|
||||||
|
u8[len] text
|
||||||
|
u16 len
|
||||||
|
u8[len] owner
|
||||||
|
u16 len
|
||||||
|
u8[len] infotext
|
||||||
|
u16 len
|
||||||
|
u8[len] inventory drawspec
|
||||||
|
u8 allow_text_input (bool)
|
||||||
|
u8 removal_disabled (bool)
|
||||||
|
u8 enforce_owner (bool)
|
||||||
|
u32 num_vars
|
||||||
|
foreach num_vars
|
||||||
|
u16 len
|
||||||
|
u8[len] name
|
||||||
|
u32 len
|
||||||
|
u8[len] value
|
||||||
|
|
||||||
|
14: Sign metadata
|
||||||
|
u16 text_len
|
||||||
|
u8[text_len] text
|
||||||
|
|
||||||
|
15: Chest metadata
|
||||||
|
serialized inventory
|
||||||
|
|
||||||
|
16: Furnace metadata
|
||||||
|
TBD
|
||||||
|
|
||||||
|
17: Locked Chest metadata
|
||||||
|
u16 len
|
||||||
|
u8[len] owner
|
||||||
|
serialized inventory
|
||||||
|
|
||||||
|
Static objects
|
||||||
|
---------------
|
||||||
|
Static objects are persistent freely moving objects in the world.
|
||||||
|
|
||||||
|
Object types:
|
||||||
|
1: Test object
|
||||||
|
2: Item
|
||||||
|
3: Rat (deprecated)
|
||||||
|
4: Oerkki (deprecated)
|
||||||
|
5: Firefly (deprecated)
|
||||||
|
6: MobV2 (deprecated)
|
||||||
|
7: LuaEntity
|
||||||
|
|
||||||
|
1: Item:
|
||||||
|
u8 version
|
||||||
|
version 0:
|
||||||
|
u16 len
|
||||||
|
u8[len] itemstring
|
||||||
|
|
||||||
|
7: LuaEntity:
|
||||||
|
u8 version
|
||||||
|
version 1:
|
||||||
|
u16 len
|
||||||
|
u8[len] entity name
|
||||||
|
u32 len
|
||||||
|
u8[len] static data
|
||||||
|
s16 hp
|
||||||
|
s32 velocity.x * 10000
|
||||||
|
s32 velocity.y * 10000
|
||||||
|
s32 velocity.z * 10000
|
||||||
|
s32 yaw * 1000
|
||||||
|
|
||||||
|
Itemstring format
|
||||||
|
------------------
|
||||||
|
eg. 'default:dirt 5'
|
||||||
|
eg. 'default:pick_wood 21323'
|
||||||
|
eg. '"default:apple" 2'
|
||||||
|
eg. 'default:apple'
|
||||||
|
- The wear value in tools is 0...65535
|
||||||
|
- There are also a number of older formats that you might stumble upon:
|
||||||
|
eg. 'node "default:dirt" 5'
|
||||||
|
eg. 'NodeItem default:dirt 5'
|
||||||
|
eg. 'ToolItem WPick 21323'
|
||||||
|
|
||||||
|
Inventory serialization format
|
||||||
|
-------------------------------
|
||||||
|
- The inventory serialization format is line-based
|
||||||
|
- The newline character used is "\n"
|
||||||
|
- The end condition of a serialized inventory is always "EndInventory\n"
|
||||||
|
- All the slots in a list must always be serialized.
|
||||||
|
|
||||||
|
Example (format does not include "---"):
|
||||||
|
---
|
||||||
|
List foo 4
|
||||||
|
Item default:sapling
|
||||||
|
Item default:sword_stone 1 10647
|
||||||
|
Item default:dirt 99
|
||||||
|
Empty
|
||||||
|
EndInventoryList
|
||||||
|
List bar 9
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
EndInventoryList
|
||||||
|
EndInventory
|
||||||
|
---
|
||||||
|
|
||||||
|
==============================================
|
||||||
|
Minetest World Format used as of 2011-05 or so
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
Map data serialization format version 17.
|
||||||
|
|
||||||
|
0.3.1 does not use this format, but a more recent one. This exists here for
|
||||||
|
historical reasons.
|
||||||
|
|
||||||
|
Directory structure:
|
||||||
|
sectors/XXXXZZZZ or sectors2/XXX/ZZZ
|
||||||
|
XXXX, ZZZZ, XXX and ZZZ being the hexadecimal X and Z coordinates.
|
||||||
|
Under these, the block files are stored, called YYYY.
|
||||||
|
|
||||||
|
There also exists files map_meta.txt and chunk_meta, that are used by the
|
||||||
|
generator. If they are not found or invalid, the generator will currently
|
||||||
|
behave quite strangely.
|
||||||
|
|
||||||
|
The MapBlock file format (sectors2/XXX/ZZZ/YYYY):
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
NOTE: Byte order is MSB first.
|
||||||
|
|
||||||
|
u8 version
|
||||||
|
- map format version number, this one is version 17
|
||||||
|
|
||||||
|
u8 flags
|
||||||
|
- Flag bitmasks:
|
||||||
|
- 0x01: is_underground: Should be set to 0 if there will be no light
|
||||||
|
obstructions above the block. If/when sunlight of a block is updated and
|
||||||
|
there is no block above it, this value is checked for determining whether
|
||||||
|
sunlight comes from the top.
|
||||||
|
- 0x02: day_night_differs: Whether the lighting of the block is different on
|
||||||
|
day and night. Only blocks that have this bit set are updated when day
|
||||||
|
transforms to night.
|
||||||
|
- 0x04: lighting_expired: If true, lighting is invalid and should be updated.
|
||||||
|
If you can't calculate lighting in your generator properly, you could try
|
||||||
|
setting this 1 to everything and setting the uppermost block in every
|
||||||
|
sector as is_underground=0. I am quite sure it doesn't work properly,
|
||||||
|
though.
|
||||||
|
|
||||||
|
zlib-compressed map data:
|
||||||
|
- content:
|
||||||
|
u8[4096]: content types
|
||||||
|
u8[4096]: param1 values
|
||||||
|
u8[4096]: param2 values
|
||||||
|
|
||||||
|
zlib-compressed node metadata
|
||||||
|
- content:
|
||||||
|
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] misc. stuff contained in the metadata
|
||||||
|
|
||||||
|
u16 mapblockobject_count
|
||||||
|
- always write as 0.
|
||||||
|
- if read != 0, just fail.
|
||||||
|
|
||||||
|
foreach mapblockobject_count:
|
||||||
|
- deprecated, should not be used. Length of this data can only be known by
|
||||||
|
properly parsing it. Just hope not to run into any of this.
|
||||||
|
|
||||||
|
u8 static object version:
|
||||||
|
- currently 0
|
||||||
|
|
||||||
|
u16 static_object_count
|
||||||
|
|
||||||
|
foreach static_object_count:
|
||||||
|
u8 type (object type-id)
|
||||||
|
s32 pos_x * 1000
|
||||||
|
s32 pos_y * 1000
|
||||||
|
s32 pos_z * 1000
|
||||||
|
u16 data_size
|
||||||
|
u8[data_size] data
|
||||||
|
|
||||||
|
u32 timestamp
|
||||||
|
- Timestamp when last saved, as seconds from starting the game.
|
||||||
|
- 0xffffffff = invalid/unknown timestamp, nothing will be done with the time
|
||||||
|
difference when loaded (recommended)
|
||||||
|
|
||||||
|
Node metadata format:
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Sign metadata:
|
||||||
|
u16 string_len
|
||||||
|
u8[string_len] string
|
||||||
|
|
||||||
|
Furnace metadata:
|
||||||
|
TBD
|
||||||
|
|
||||||
|
Chest metadata:
|
||||||
|
TBD
|
||||||
|
|
||||||
|
Locking Chest metadata:
|
||||||
|
u16 string_len
|
||||||
|
u8[string_len] string
|
||||||
|
TBD
|
||||||
|
|
||||||
|
// END
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
.\" Minetest man page
|
||||||
|
.TH minetest 6 "11 March 2012" "" ""
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
minetest \- Multiplayer infinite-world block sandbox
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B minetest
|
||||||
|
[ 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
|
||||||
|
\-\-address <value>
|
||||||
|
Address to connect to
|
||||||
|
.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
|
||||||
|
\-\-go
|
||||||
|
Disable main menu
|
||||||
|
.TP
|
||||||
|
\-\-help
|
||||||
|
Show allowed options
|
||||||
|
.TP
|
||||||
|
\-\-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
|
||||||
|
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
|
||||||
|
|
||||||
|
.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 minetestserver(6)
|
|
@ -0,0 +1,70 @@
|
||||||
|
.\" Minetestserver man page
|
||||||
|
.TH minetestserver 6 "11 March 2012" "" ""
|
||||||
|
|
||||||
|
.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
|
||||||
|
\-\-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
|
||||||
|
|
||||||
|
.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)
|
|
@ -0,0 +1,108 @@
|
||||||
|
Minetest protocol (incomplete, early draft):
|
||||||
|
Updated 2011-06-18
|
||||||
|
|
||||||
|
A custom protocol over UDP.
|
||||||
|
Integers are big endian.
|
||||||
|
Refer to connection.{h,cpp} for further reference.
|
||||||
|
|
||||||
|
Initialization:
|
||||||
|
- A dummy reliable packet with peer_id=PEER_ID_INEXISTENT=0 is sent to the server:
|
||||||
|
- Actually this can be sent without the reliable packet header, too, i guess,
|
||||||
|
but the sequence number in the header allows the sender to re-send the
|
||||||
|
packet without accidentally getting a double initialization.
|
||||||
|
- Packet content:
|
||||||
|
# Basic header
|
||||||
|
u32 protocol_id = PROTOCOL_ID = 0x4f457403
|
||||||
|
u16 sender_peer_id = PEER_ID_INEXISTENT = 0
|
||||||
|
u8 channel = 0
|
||||||
|
# Reliable packet header
|
||||||
|
u8 type = TYPE_RELIABLE = 3
|
||||||
|
u16 seqnum = SEQNUM_INITIAL = 65500
|
||||||
|
# Original packet header
|
||||||
|
u8 type = TYPE_ORIGINAL = 1
|
||||||
|
# And no actual payload.
|
||||||
|
- Server responds with something like this:
|
||||||
|
- Packet content:
|
||||||
|
# Basic header
|
||||||
|
u32 protocol_id = PROTOCOL_ID = 0x4f457403
|
||||||
|
u16 sender_peer_id = PEER_ID_INEXISTENT = 0
|
||||||
|
u8 channel = 0
|
||||||
|
# Reliable packet header
|
||||||
|
u8 type = TYPE_RELIABLE = 3
|
||||||
|
u16 seqnum = SEQNUM_INITIAL = 65500
|
||||||
|
# Control packet header
|
||||||
|
u8 type = TYPE_CONTROL = 0
|
||||||
|
u8 controltype = CONTROLTYPE_SET_PEER_ID = 1
|
||||||
|
u16 peer_id_new = assigned peer id to client (other than 0 or 1)
|
||||||
|
- Then the connection can be disconnected by sending:
|
||||||
|
- Packet content:
|
||||||
|
# Basic header
|
||||||
|
u32 protocol_id = PROTOCOL_ID = 0x4f457403
|
||||||
|
u16 sender_peer_id = whatever was gotten in CONTROLTYPE_SET_PEER_ID
|
||||||
|
u8 channel = 0
|
||||||
|
# Control packet header
|
||||||
|
u8 type = TYPE_CONTROL = 0
|
||||||
|
u8 controltype = CONTROLTYPE_DISCO = 3
|
||||||
|
|
||||||
|
- Here's a quick untested connect-disconnect done in PHP:
|
||||||
|
# host: ip of server (use gethostbyname(hostname) to get from a dns name)
|
||||||
|
# port: port of server
|
||||||
|
function check_if_minetestserver_up($host, $port)
|
||||||
|
{
|
||||||
|
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||||
|
$timeout = array("sec" => 1, "usec" => 0);
|
||||||
|
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
|
||||||
|
$buf = "\x4f\x45\x74\x03\x00\x00\x00\x03\xff\xdc\x01";
|
||||||
|
socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
|
||||||
|
$buf = socket_read($socket, 1000);
|
||||||
|
if($buf != "")
|
||||||
|
{
|
||||||
|
# We got a reply! read the peer id from it.
|
||||||
|
$peer_id = substr($buf, 9, 2);
|
||||||
|
|
||||||
|
# Disconnect
|
||||||
|
$buf = "\x4f\x45\x74\x03".$peer_id."\x00\x00\x03";
|
||||||
|
socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
|
||||||
|
socket_close($socket);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
- Here's a Python script for checking if a minetest server is up, confirmed working
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import sys, time, socket
|
||||||
|
address = ""
|
||||||
|
port = 30000
|
||||||
|
if len(sys.argv) <= 1:
|
||||||
|
print("Usage: %s <address>" % sys.argv[0])
|
||||||
|
exit()
|
||||||
|
if ':' in sys.argv[1]:
|
||||||
|
address = sys.argv[1].split(':')[0]
|
||||||
|
try:
|
||||||
|
port = int(sys.argv[1].split(':')[1])
|
||||||
|
except ValueError:
|
||||||
|
print("Please specify a valid port")
|
||||||
|
exit()
|
||||||
|
else:
|
||||||
|
address = sys.argv[1]
|
||||||
|
|
||||||
|
try:
|
||||||
|
start = time.time()
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.settimeout(2.0)
|
||||||
|
buf = "\x4f\x45\x74\x03\x00\x00\x00\x01"
|
||||||
|
sock.sendto(buf, (address, port))
|
||||||
|
data, addr = sock.recvfrom(1000)
|
||||||
|
if data:
|
||||||
|
peer_id = data[12:14]
|
||||||
|
buf = "\x4f\x45\x74\x03" + peer_id + "\x00\x00\x03"
|
||||||
|
sock.sendto(buf, (address, port))
|
||||||
|
sock.close()
|
||||||
|
end = time.time()
|
||||||
|
print("%s is up (%0.5fms)" % (sys.argv[1],end-start))
|
||||||
|
else:
|
||||||
|
print("%s seems to be down " % sys.argv[1])
|
||||||
|
except:
|
||||||
|
print("%s seems to be down " % sys.argv[1])
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = Minimal development test
|
||||||
|
|
After Width: | Height: | Size: 392 B |
After Width: | Height: | Size: 218 B |
|
@ -0,0 +1,2 @@
|
||||||
|
default
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
-- bucket (Minetest 0.4 mod)
|
||||||
|
-- A bucket, which can pick up water and lava
|
||||||
|
|
||||||
|
minetest.register_alias("bucket", "bucket:bucket_empty")
|
||||||
|
minetest.register_alias("bucket_water", "bucket:bucket_water")
|
||||||
|
minetest.register_alias("bucket_lava", "bucket:bucket_lava")
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'bucket:bucket_empty 1',
|
||||||
|
recipe = {
|
||||||
|
{'default:steel_ingot', '', 'default:steel_ingot'},
|
||||||
|
{'', 'default:steel_ingot', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
bucket = {}
|
||||||
|
bucket.liquids = {}
|
||||||
|
|
||||||
|
-- Register a new liquid
|
||||||
|
-- source = name of the source node
|
||||||
|
-- flowing = name of the flowing node
|
||||||
|
-- itemname = name of the new bucket item (or nil if liquid is not takeable)
|
||||||
|
-- inventory_image = texture of the new bucket item (ignored if itemname == nil)
|
||||||
|
-- This function can be called from any mod (that depends on bucket).
|
||||||
|
function bucket.register_liquid(source, flowing, itemname, inventory_image)
|
||||||
|
bucket.liquids[source] = {
|
||||||
|
source = source,
|
||||||
|
flowing = flowing,
|
||||||
|
itemname = itemname,
|
||||||
|
}
|
||||||
|
bucket.liquids[flowing] = bucket.liquids[source]
|
||||||
|
|
||||||
|
if itemname ~= nil then
|
||||||
|
minetest.register_craftitem(itemname, {
|
||||||
|
inventory_image = inventory_image,
|
||||||
|
stack_max = 1,
|
||||||
|
liquids_pointable = true,
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
-- Must be pointing to node
|
||||||
|
if pointed_thing.type ~= "node" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Check if pointing to a liquid
|
||||||
|
n = minetest.get_node(pointed_thing.under)
|
||||||
|
if bucket.liquids[n.name] == nil then
|
||||||
|
-- Not a liquid
|
||||||
|
minetest.add_node(pointed_thing.above, {name=source})
|
||||||
|
elseif n.name ~= source then
|
||||||
|
-- It's a liquid
|
||||||
|
minetest.add_node(pointed_thing.under, {name=source})
|
||||||
|
end
|
||||||
|
return {name="bucket:bucket_empty"}
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craftitem("bucket:bucket_empty", {
|
||||||
|
inventory_image = "bucket.png",
|
||||||
|
stack_max = 1,
|
||||||
|
liquids_pointable = true,
|
||||||
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
|
-- Must be pointing to node
|
||||||
|
if pointed_thing.type ~= "node" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Check if pointing to a liquid source
|
||||||
|
n = minetest.get_node(pointed_thing.under)
|
||||||
|
liquiddef = bucket.liquids[n.name]
|
||||||
|
if liquiddef ~= nil and liquiddef.source == n.name and liquiddef.itemname ~= nil then
|
||||||
|
minetest.add_node(pointed_thing.under, {name="air"})
|
||||||
|
return {name=liquiddef.itemname}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
bucket.register_liquid(
|
||||||
|
"default:water_source",
|
||||||
|
"default:water_flowing",
|
||||||
|
"bucket:bucket_water",
|
||||||
|
"bucket_water.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
bucket.register_liquid(
|
||||||
|
"default:lava_source",
|
||||||
|
"default:lava_flowing",
|
||||||
|
"bucket:bucket_lava",
|
||||||
|
"bucket_lava.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "bucket:bucket_lava",
|
||||||
|
burntime = 60,
|
||||||
|
})
|
After Width: | Height: | Size: 182 B |
After Width: | Height: | Size: 183 B |
After Width: | Height: | Size: 180 B |
|
@ -0,0 +1,136 @@
|
||||||
|
-- minetest/default/mapgen.lua
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Aliases for map generator outputs
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.register_alias("mapgen_air", "air")
|
||||||
|
minetest.register_alias("mapgen_stone", "default:stone")
|
||||||
|
minetest.register_alias("mapgen_tree", "default:tree")
|
||||||
|
minetest.register_alias("mapgen_leaves", "default:leaves")
|
||||||
|
minetest.register_alias("mapgen_apple", "default:apple")
|
||||||
|
minetest.register_alias("mapgen_water_source", "default:water_source")
|
||||||
|
minetest.register_alias("mapgen_dirt", "default:dirt")
|
||||||
|
minetest.register_alias("mapgen_sand", "default:sand")
|
||||||
|
minetest.register_alias("mapgen_gravel", "default:gravel")
|
||||||
|
minetest.register_alias("mapgen_clay", "default:clay")
|
||||||
|
minetest.register_alias("mapgen_lava_source", "default:lava_source")
|
||||||
|
minetest.register_alias("mapgen_cobble", "default:cobble")
|
||||||
|
minetest.register_alias("mapgen_mossycobble", "default:mossycobble")
|
||||||
|
minetest.register_alias("mapgen_dirt_with_grass", "default:dirt_with_grass")
|
||||||
|
minetest.register_alias("mapgen_junglegrass", "default:junglegrass")
|
||||||
|
minetest.register_alias("mapgen_stone_with_coal", "default:stone_with_coal")
|
||||||
|
minetest.register_alias("mapgen_stone_with_iron", "default:stone_with_iron")
|
||||||
|
minetest.register_alias("mapgen_mese", "default:mese")
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Ore generation
|
||||||
|
--
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:stone_with_coal",
|
||||||
|
wherein = "default:stone",
|
||||||
|
clust_scarcity = 8*8*8,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
height_min = -31000,
|
||||||
|
height_max = 64,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:stone_with_iron",
|
||||||
|
wherein = "default:stone",
|
||||||
|
clust_scarcity = 16*16*16,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
height_min = -5,
|
||||||
|
height_max = 7,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:stone_with_iron",
|
||||||
|
wherein = "default:stone",
|
||||||
|
clust_scarcity = 12*12*12,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
height_min = -16,
|
||||||
|
height_max = -5,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:stone_with_iron",
|
||||||
|
wherein = "default:stone",
|
||||||
|
clust_scarcity = 9*9*9,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
height_min = -31000,
|
||||||
|
height_max = -17,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- for float islands and far scaled
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:stone_with_coal",
|
||||||
|
wherein = "default:stone",
|
||||||
|
clust_scarcity = 8*8*8,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
height_min = 200,
|
||||||
|
height_max = 31000,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "default:stone_with_iron",
|
||||||
|
wherein = "default:stone",
|
||||||
|
clust_scarcity = 9*9*9,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
height_min = 200,
|
||||||
|
height_max = 31000,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_on_generated(function(minp, maxp, seed)
|
||||||
|
-- Generate clay
|
||||||
|
if maxp.y >= 2 and minp.y <= 0 then
|
||||||
|
-- Assume X and Z lengths are equal
|
||||||
|
local divlen = 4
|
||||||
|
local divs = (maxp.x-minp.x)/divlen+1;
|
||||||
|
for divx=0+1,divs-1-1 do
|
||||||
|
for divz=0+1,divs-1-1 do
|
||||||
|
local cx = minp.x + math.floor((divx+0.5)*divlen)
|
||||||
|
local cz = minp.z + math.floor((divz+0.5)*divlen)
|
||||||
|
if minetest.get_node({x=cx,y=1,z=cz}).name == "default:water_source" and
|
||||||
|
minetest.get_node({x=cx,y=0,z=cz}).name == "default:sand" then
|
||||||
|
local is_shallow = true
|
||||||
|
local num_water_around = 0
|
||||||
|
if minetest.get_node({x=cx-divlen*2,y=1,z=cz+0}).name == "default:water_source" then
|
||||||
|
num_water_around = num_water_around + 1 end
|
||||||
|
if minetest.get_node({x=cx+divlen*2,y=1,z=cz+0}).name == "default:water_source" then
|
||||||
|
num_water_around = num_water_around + 1 end
|
||||||
|
if minetest.get_node({x=cx+0,y=1,z=cz-divlen*2}).name == "default:water_source" then
|
||||||
|
num_water_around = num_water_around + 1 end
|
||||||
|
if minetest.get_node({x=cx+0,y=1,z=cz+divlen*2}).name == "default:water_source" then
|
||||||
|
num_water_around = num_water_around + 1 end
|
||||||
|
if num_water_around >= 2 then
|
||||||
|
is_shallow = false
|
||||||
|
end
|
||||||
|
if is_shallow then
|
||||||
|
for x1=-divlen,divlen do
|
||||||
|
for z1=-divlen,divlen do
|
||||||
|
if minetest.get_node({x=cx+x1,y=0,z=cz+z1}).name == "default:sand" then
|
||||||
|
minetest.set_node({x=cx+x1,y=0,z=cz+z1}, {name="default:clay"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
After Width: | Height: | Size: 273 B |
After Width: | Height: | Size: 255 B |
After Width: | Height: | Size: 109 B |
After Width: | Height: | Size: 157 B |
After Width: | Height: | Size: 515 B |
After Width: | Height: | Size: 457 B |
After Width: | Height: | Size: 144 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 114 B |
After Width: | Height: | Size: 145 B |
After Width: | Height: | Size: 98 B |
After Width: | Height: | Size: 93 B |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 173 B |
After Width: | Height: | Size: 140 B |
After Width: | Height: | Size: 83 B |
After Width: | Height: | Size: 138 B |
After Width: | Height: | Size: 374 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 480 B |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 719 B |
After Width: | Height: | Size: 159 B |
After Width: | Height: | Size: 283 B |
After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 210 B |
After Width: | Height: | Size: 782 B |
After Width: | Height: | Size: 771 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 140 B |
After Width: | Height: | Size: 237 B |
After Width: | Height: | Size: 210 B |
After Width: | Height: | Size: 205 B |
After Width: | Height: | Size: 368 B |
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 129 B |