master
RealBadAngel 2013-10-30 12:20:08 +01:00
commit 0cf0311ff4
647 changed files with 315368 additions and 0 deletions

10
.travis.yml Normal file
View File

@ -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

225
CMakeLists.txt Normal file
View File

@ -0,0 +1,225 @@
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})
else()
# Comment the following line during release
set(VERSION_PATCH ${VERSION_PATCH}-dev)
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/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
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)

412
README.txt Normal file
View File

@ -0,0 +1,412 @@
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.net/
- 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.
DroidSansFallback:
Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

188
builtin/auth.lua Normal file
View File

@ -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

36
builtin/builtin.lua Normal file
View File

@ -0,0 +1,36 @@
--
-- 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")
local errorfct = error
error = function(text)
print(debug.traceback(""))
errorfct(text)
end
-- Load other files
local modpath = minetest.get_modpath("__builtin")
dofile(modpath.."/serialize.lua")
dofile(modpath.."/misc_helpers.lua")
dofile(modpath.."/item.lua")
dofile(modpath.."/misc_register.lua")
dofile(modpath.."/item_entity.lua")
dofile(modpath.."/deprecated.lua")
dofile(modpath.."/misc.lua")
dofile(modpath.."/privileges.lua")
dofile(modpath.."/auth.lua")
dofile(modpath.."/chatcommands.lua")
dofile(modpath.."/static_spawn.lua")
dofile(modpath.."/detached_inventory.lua")
dofile(modpath.."/falling.lua")
dofile(modpath.."/features.lua")
dofile(modpath.."/voxelarea.lua")
dofile(modpath.."/vector.lua")

693
builtin/chatcommands.lua Normal file
View File

@ -0,0 +1,693 @@
-- 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.-]+)$")
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
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.-]+)$")
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
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,
})

48
builtin/deprecated.lua Normal file
View File

@ -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(...)
end)
else
rawset(table, key, nil)
end
return rawget(table, key)
end
})

View File

@ -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

211
builtin/falling.lua Normal file
View File

@ -0,0 +1,211 @@
-- Minetest: builtin/item.lua
--
-- Falling stuff
--
minetest.register_entity("__builtin:falling_node", {
initial_properties = {
physical = true,
collide_with_objects = false,
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
visual = "wielditem",
textures = {},
visual_size = {x=0.667, y=0.667},
},
node = {},
set_node = function(self, node)
self.node = node
local stack = ItemStack(node.name)
local itemtable = stack:to_table()
local itemname = nil
if itemtable then
itemname = stack:to_table().name
end
local item_texture = nil
local item_type = ""
if 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 = {node.name},
}
self.object:set_properties(prop)
end,
get_staticdata = function(self)
return self.node.name
end,
on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal=1})
--self.object:setacceleration({x=0, y=-10, z=0})
self:set_node({name=staticdata})
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 or
(minetest.get_node_group(self.node.name, "float") ~= 0 and minetest.registered_nodes[bcn.name].liquidtype ~= "none")
then
if minetest.registered_nodes[bcn.name].leveled and bcn.name == self.node.name then
local addlevel = self.node.level
if addlevel == nil or addlevel <= 0 then addlevel = minetest.registered_nodes[bcn.name].leveled end
if minetest.env:add_node_level(bcp, addlevel) == 0 then
self.object:remove()
return
end
elseif minetest.registered_nodes[bcn.name].buildable_to and (minetest.get_node_group(self.node.name, "float") == 0 or minetest.registered_nodes[bcn.name].liquidtype == "none") 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, self.node)
self.object:remove()
nodeupdate(np)
else
-- Do nothing
end
end
})
function spawn_falling_node(p, node)
obj = minetest.add_entity(p, "__builtin:falling_node")
obj:get_luaentity():set_node(node)
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
(minetest.get_node_group(n.name, "float") == 0 or minetest.registered_nodes[n_bottom.name].liquidtype == "none") and
(n.name ~= n_bottom.name or (minetest.registered_nodes[n_bottom.name].leveled and minetest.env:get_node_level(p_bottom) < minetest.env:get_node_max_level(p_bottom))) 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
n.level = minetest.env:get_node_level(p)
minetest.remove_node(p)
spawn_falling_node(p, n)
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, delay)
-- 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}, delay or 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)

28
builtin/features.lua Normal file
View File

@ -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

287
builtin/filterlist.lua Normal file
View File

@ -0,0 +1,287 @@
--Minetest
--Copyright (C) 2013 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
-- Generic implementation of a filter/sortable list --
--------------------------------------------------------------------------------
filterlist = {}
--------------------------------------------------------------------------------
function filterlist.refresh(this)
this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
filterlist.process(this)
end
--------------------------------------------------------------------------------
function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
assert((raw_fct ~= nil) and (type(raw_fct) == "function"))
assert((compare_fct ~= nil) and (type(compare_fct) == "function"))
local this = {}
this.m_raw_list_fct = raw_fct
this.m_compare_fct = compare_fct
this.m_filter_fct = filter_fct
this.m_uid_match_fct = uid_match_fct
this.m_filtercriteria = nil
this.m_fetch_param = fetch_param
this.m_sortmode = "none"
this.m_sort_list = {}
this.m_processed_list = nil
this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
filterlist.process(this)
return this
end
--------------------------------------------------------------------------------
function filterlist.add_sort_mechanism(this,name,fct)
this.m_sort_list[name] = fct
end
--------------------------------------------------------------------------------
function filterlist.set_filtercriteria(this,criteria)
if criteria == this.m_filtercriteria and
type(criteria) ~= "table" then
return
end
this.m_filtercriteria = criteria
filterlist.process(this)
end
--------------------------------------------------------------------------------
function filterlist.get_filtercriteria(this)
return this.m_filtercriteria
end
--------------------------------------------------------------------------------
--supported sort mode "alphabetic|none"
function filterlist.set_sortmode(this,mode)
if (mode == this.m_sortmode) then
return
end
this.m_sortmode = mode
filterlist.process(this)
end
--------------------------------------------------------------------------------
function filterlist.get_list(this)
return this.m_processed_list
end
--------------------------------------------------------------------------------
function filterlist.get_raw_list(this)
return this.m_raw_list
end
--------------------------------------------------------------------------------
function filterlist.get_raw_element(this,idx)
if type(idx) ~= "number" then
idx = tonumber(idx)
end
if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
return this.m_raw_list[idx]
end
return nil
end
--------------------------------------------------------------------------------
function filterlist.get_raw_index(this,listindex)
assert(this.m_processed_list ~= nil)
if listindex ~= nil and listindex > 0 and
listindex <= #this.m_processed_list then
local entry = this.m_processed_list[listindex]
for i,v in ipairs(this.m_raw_list) do
if this.m_compare_fct(v,entry) then
return i
end
end
end
return 0
end
--------------------------------------------------------------------------------
function filterlist.get_current_index(this,listindex)
assert(this.m_processed_list ~= nil)
if listindex ~= nil and listindex > 0 and
listindex <= #this.m_raw_list then
local entry = this.m_raw_list[listindex]
for i,v in ipairs(this.m_processed_list) do
if this.m_compare_fct(v,entry) then
return i
end
end
end
return 0
end
--------------------------------------------------------------------------------
function filterlist.process(this)
assert(this.m_raw_list ~= nil)
if this.m_sortmode == "none" and
this.m_filtercriteria == nil then
this.m_processed_list = this.m_raw_list
return
end
this.m_processed_list = {}
for k,v in pairs(this.m_raw_list) do
if this.m_filtercriteria == nil or
this.m_filter_fct(v,this.m_filtercriteria) then
table.insert(this.m_processed_list,v)
end
end
if this.m_sortmode == "none" then
return
end
if this.m_sort_list[this.m_sortmode] ~= nil and
type(this.m_sort_list[this.m_sortmode]) == "function" then
this.m_sort_list[this.m_sortmode](this)
end
end
--------------------------------------------------------------------------------
function filterlist.size(this)
if this.m_processed_list == nil then
return 0
end
return #this.m_processed_list
end
--------------------------------------------------------------------------------
function filterlist.uid_exists_raw(this,uid)
for i,v in ipairs(this.m_raw_list) do
if this.m_uid_match_fct(v,uid) then
return true
end
end
return false
end
--------------------------------------------------------------------------------
function filterlist.raw_index_by_uid(this, uid)
local elementcount = 0
local elementidx = 0
for i,v in ipairs(this.m_raw_list) do
if this.m_uid_match_fct(v,uid) then
elementcount = elementcount +1
elementidx = i
end
end
-- If there are more elements than one with same name uid can't decide which
-- one is meant. This shouldn't be possible but just for sure.
if elementcount > 1 then
elementidx=0
end
return elementidx
end
--------------------------------------------------------------------------------
-- COMMON helper functions --
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function compare_worlds(world1,world2)
if world1.path ~= world2.path then
return false
end
if world1.name ~= world2.name then
return false
end
if world1.gameid ~= world2.gameid then
return false
end
return true
end
--------------------------------------------------------------------------------
function sort_worlds_alphabetic(this)
table.sort(this.m_processed_list, function(a, b)
--fixes issue #857 (crash due to sorting nil in worldlist)
if a == nil or b == nil then
if a == nil and b ~= nil then return false end
if b == nil and a ~= nil then return true end
return false
end
if a.name:lower() == b.name:lower() then
return a.name < b.name
end
return a.name:lower() < b.name:lower()
end)
end
--------------------------------------------------------------------------------
function sort_mod_list(this)
table.sort(this.m_processed_list, function(a, b)
-- Show game mods at bottom
if a.typ ~= b.typ then
return b.typ == "game_mod"
end
-- If in same or no modpack, sort by name
if a.modpack == b.modpack then
if a.name:lower() == b.name:lower() then
return a.name < b.name
end
return a.name:lower() < b.name:lower()
-- Else compare name to modpack name
else
-- Always show modpack pseudo-mod on top of modpack mod list
if a.name == b.modpack then
return true
elseif b.name == a.modpack then
return false
end
local name_a = a.modpack or a.name
local name_b = b.modpack or b.name
if name_a:lower() == name_b:lower() then
return name_a < name_b
end
return name_a:lower() < name_b:lower()
end
end)
end

322
builtin/gamemgr.lua Normal file
View File

@ -0,0 +1,322 @@
--Minetest
--Copyright (C) 2013 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
gamemgr = {}
--------------------------------------------------------------------------------
function gamemgr.dialog_new_game()
local retval =
"label[2,2;" .. fgettext("Game Name") .. "]"..
"field[4.5,2.4;6,0.5;te_game_name;;]" ..
"button[5,4.2;2.6,0.5;new_game_confirm;" .. fgettext("Create") .. "]" ..
"button[7.5,4.2;2.8,0.5;new_game_cancel;" .. fgettext("Cancel") .. "]"
return retval
end
--------------------------------------------------------------------------------
function gamemgr.handle_games_buttons(fields)
if fields["gamelist"] ~= nil then
local event = explode_textlist_event(fields["gamelist"])
gamemgr.selected_game = event.index
end
if fields["btn_game_mgr_edit_game"] ~= nil then
return {
is_dialog = true,
show_buttons = false,
current_tab = "dialog_edit_game"
}
end
if fields["btn_game_mgr_new_game"] ~= nil then
return {
is_dialog = true,
show_buttons = false,
current_tab = "dialog_new_game"
}
end
return nil
end
--------------------------------------------------------------------------------
function gamemgr.handle_new_game_buttons(fields)
if fields["new_game_confirm"] and
fields["te_game_name"] ~= nil and
fields["te_game_name"] ~= "" then
local gamepath = engine.get_gamepath()
if gamepath ~= nil and
gamepath ~= "" then
local gamefolder = cleanup_path(fields["te_game_name"])
--TODO check for already existing first
engine.create_dir(gamepath .. DIR_DELIM .. gamefolder)
engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "mods")
engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "menu")
local gameconf =
io.open(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "game.conf","w")
if gameconf then
gameconf:write("name = " .. fields["te_game_name"])
gameconf:close()
end
end
end
return {
is_dialog = false,
show_buttons = true,
current_tab = engine.setting_get("main_menu_tab")
}
end
--------------------------------------------------------------------------------
function gamemgr.handle_edit_game_buttons(fields)
local current_game = gamemgr.get_game(gamemgr.selected_game)
if fields["btn_close_edit_game"] ~= nil or
current_game == nil then
return {
is_dialog = false,
show_buttons = true,
current_tab = engine.setting_get("main_menu_tab")
}
end
if fields["btn_remove_mod_from_game"] ~= nil then
gamemgr.delete_mod(current_game,engine.get_textlist_index("mods_current"))
end
if fields["btn_add_mod_to_game"] ~= nil then
local modindex = engine.get_textlist_index("mods_available")
local mod = modmgr.get_global_mod(modindex)
if mod ~= nil then
local sourcepath = mod.path
if not gamemgr.add_mod(current_game,sourcepath) then
gamedata.errormessage =
fgettext("Gamemgr: Unable to copy mod \"$1\" to game \"$2\"", mod.name, current_game.id)
end
end
end
return nil
end
--------------------------------------------------------------------------------
function gamemgr.add_mod(gamespec,sourcepath)
if gamespec.gamemods_path ~= nil and
gamespec.gamemods_path ~= "" then
local modname = get_last_folder(sourcepath)
return engine.copy_dir(sourcepath,gamespec.gamemods_path .. DIR_DELIM .. modname);
end
return false
end
--------------------------------------------------------------------------------
function gamemgr.delete_mod(gamespec,modindex)
if gamespec.gamemods_path ~= nil and
gamespec.gamemods_path ~= "" then
local game_mods = {}
get_mods(gamespec.gamemods_path,game_mods)
if modindex > 0 and
#game_mods >= modindex then
if game_mods[modindex].path:sub(0,gamespec.gamemods_path:len())
== gamespec.gamemods_path then
engine.delete_dir(game_mods[modindex].path)
end
end
end
end
--------------------------------------------------------------------------------
function gamemgr.find_by_gameid(gameid)
for i=1,#gamemgr.games,1 do
if gamemgr.games[i].id == gameid then
return gamemgr.games[i], i
end
end
return nil, nil
end
--------------------------------------------------------------------------------
function gamemgr.get_game_mods(gamespec, retval)
if gamespec ~= nil and
gamespec.gamemods_path ~= nil and
gamespec.gamemods_path ~= "" then
get_mods(gamespec.gamemods_path, retval)
end
end
--------------------------------------------------------------------------------
function gamemgr.get_game_modlist(gamespec)
local retval = ""
local game_mods = {}
gamemgr.get_game_mods(gamespec, game_mods)
for i=1,#game_mods,1 do
if retval ~= "" then
retval = retval..","
end
retval = retval .. game_mods[i].name
end
return retval
end
--------------------------------------------------------------------------------
function gamemgr.gettab(name)
local retval = ""
if name == "dialog_edit_game" then
retval = retval .. gamemgr.dialog_edit_game()
end
if name == "dialog_new_game" then
retval = retval .. gamemgr.dialog_new_game()
end
if name == "game_mgr" then
retval = retval .. gamemgr.tab()
end
return retval
end
--------------------------------------------------------------------------------
function gamemgr.tab()
if gamemgr.selected_game == nil then
gamemgr.selected_game = 1
end
local retval =
"vertlabel[0,-0.25;" .. fgettext("GAMES") .. "]" ..
"label[1,-0.25;" .. fgettext("Games") .. ":]" ..
"textlist[1,0.25;4.5,4.4;gamelist;" ..
gamemgr.gamelist() ..
";" .. gamemgr.selected_game .. "]"
local current_game = gamemgr.get_game(gamemgr.selected_game)
if current_game ~= nil then
if current_game.menuicon_path ~= nil and
current_game.menuicon_path ~= "" then
retval = retval ..
"image[5.8,-0.25;2,2;" ..
engine.formspec_escape(current_game.menuicon_path) .. "]"
end
retval = retval ..
"field[8,-0.25;6,2;;" .. current_game.name .. ";]"..
"label[6,1.4;" .. fgettext("Mods:") .."]" ..
"button[9.7,1.5;2,0.2;btn_game_mgr_edit_game;" .. fgettext("edit game") .. "]" ..
"textlist[6,2;5.5,3.3;game_mgr_modlist;"
.. gamemgr.get_game_modlist(current_game) ..";0]" ..
"button[1,4.75;3.2,0.5;btn_game_mgr_new_game;" .. fgettext("new game") .. "]"
end
return retval
end
--------------------------------------------------------------------------------
function gamemgr.dialog_edit_game()
local current_game = gamemgr.get_game(gamemgr.selected_game)
if current_game ~= nil then
local retval =
"vertlabel[0,-0.25;" .. fgettext("EDIT GAME") .."]" ..
"label[0,-0.25;" .. current_game.name .. "]" ..
"button[11.55,-0.2;0.75,0.5;btn_close_edit_game;x]"
if current_game.menuicon_path ~= nil and
current_game.menuicon_path ~= "" then
retval = retval ..
"image[5.25,0;2,2;" ..
engine.formspec_escape(current_game.menuicon_path) .. "]"
end
retval = retval ..
"textlist[0.5,0.5;4.5,4.3;mods_current;"
.. gamemgr.get_game_modlist(current_game) ..";0]"
retval = retval ..
"textlist[7,0.5;4.5,4.3;mods_available;"
.. modmgr.render_modlist() .. ";0]"
retval = retval ..
"button[0.55,4.95;4.7,0.5;btn_remove_mod_from_game;" .. fgettext("Remove selected mod") .."]"
retval = retval ..
"button[7.05,4.95;4.7,0.5;btn_add_mod_to_game;" .. fgettext("<<-- Add mod") .."]"
return retval
end
end
--------------------------------------------------------------------------------
function gamemgr.handle_buttons(tab,fields)
local retval = nil
if tab == "dialog_edit_game" then
retval = gamemgr.handle_edit_game_buttons(fields)
end
if tab == "dialog_new_game" then
retval = gamemgr.handle_new_game_buttons(fields)
end
if tab == "game_mgr" then
retval = gamemgr.handle_games_buttons(fields)
end
return retval
end
--------------------------------------------------------------------------------
function gamemgr.get_game(index)
if index > 0 and index <= #gamemgr.games then
return gamemgr.games[index]
end
return nil
end
--------------------------------------------------------------------------------
function gamemgr.update_gamelist()
gamemgr.games = engine.get_games()
end
--------------------------------------------------------------------------------
function gamemgr.gamelist()
local retval = ""
if #gamemgr.games > 0 then
retval = retval .. gamemgr.games[1].id
for i=2,#gamemgr.games,1 do
retval = retval .. "," .. gamemgr.games[i].name
end
end
return retval
end

559
builtin/item.lua Normal file
View File

@ -0,0 +1,559 @@
-- 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, is6d)
--account for y if requested
if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
--from above
if dir.y < 0 then
if math.abs(dir.x) > math.abs(dir.z) then
if dir.x < 0 then
return 19
else
return 13
end
else
if dir.z < 0 then
return 10
else
return 4
end
end
--from below
else
if math.abs(dir.x) > math.abs(dir.z) then
if dir.x < 0 then
return 15
else
return 17
end
else
if dir.z < 0 then
return 6
else
return 8
end
end
end
--otherwise, place horizontally
elseif 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.facedir_to_dir(facedir)
--a table of possible dirs
return ({{x=0, y=0, z=1},
{x=1, y=0, z=0},
{x=0, y=0, z=-1},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0},
{x=0, y=1, z=0}})
--indexed into by a table of correlating facedirs
[({[0]=1, 2, 3, 4,
5, 4, 6, 2,
6, 2, 5, 4,
1, 5, 3, 6,
1, 6, 3, 5,
1, 4, 3, 2})
--indexed into by the facedir in question
[facedir]]
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, param2)
local item = itemstack:peek_item()
local def = itemstack:get_definition()
if def.type ~= "node" or pointed_thing.type ~= "node" then
return itemstack, false
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, false
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, false
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 = param2}
-- Calculate direction for wall mounted stuff like torches and signs
if def.paramtype2 == 'wallmounted' and not param2 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' and not param2 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, false
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, true
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, param2)
-- 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, false
end
end
if itemstack:get_definition().type == "node" then
return minetest.item_place_node(itemstack, placer, pointed_thing, param2)
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())
local wdef = wielded:get_definition()
local tp = wielded:get_tool_capabilities()
local dp = minetest.get_dig_params(def.groups, tp)
if wdef and wdef.after_use then
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
else
-- Wear out tool
if not minetest.setting_getbool("creative_mode") then
wielded:add_wear(dp.wear)
end
end
digger:set_wielded_item(wielded)
-- 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,
drowning = 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,
}

122
builtin/item_entity.lua Normal file
View File

@ -0,0 +1,122 @@
-- 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,
collide_with_objects = false,
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,
})

1221
builtin/mainmenu.lua Normal file

File diff suppressed because it is too large Load Diff

108
builtin/misc.lua Normal file
View File

@ -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
local player_list = {}
minetest.register_on_joinplayer(function(player)
player_list[player:get_player_name()] = player
end)
minetest.register_on_leaveplayer(function(player)
player_list[player:get_player_name()] = nil
end)
function minetest.get_connected_players()
local temp_table = {}
for index, value in pairs(player_list) do
table.insert(temp_table, value)
end
return temp_table
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

254
builtin/misc_helpers.lua Normal file
View File

@ -0,0 +1,254 @@
-- 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 file_exists(filename)
local f = io.open(filename, "r")
if f==nil then
return false
else
f:close()
return true
end
end
--------------------------------------------------------------------------------
function string:trim()
return (self:gsub("^%s*(.-)%s*$", "%1"))
end
assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
--------------------------------------------------------------------------------
function math.hypot(x, y)
local t
x = math.abs(x)
y = math.abs(y)
t = math.min(x, y)
x = math.max(x, y)
if x == 0 then return 0 end
t = t / x
return x * math.sqrt(1 + t * t)
end
--------------------------------------------------------------------------------
function explode_textlist_event(text)
local retval = {}
retval.typ = "INV"
local parts = text:split(":")
if #parts == 2 then
retval.typ = parts[1]:trim()
retval.index= tonumber(parts[2]:trim())
if type(retval.index) ~= "number" then
retval.typ = "INV"
end
end
return retval
end
--------------------------------------------------------------------------------
function get_last_folder(text,count)
local parts = text:split(DIR_DELIM)
if count == nil then
return parts[#parts]
end
local retval = ""
for i=1,count,1 do
retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
end
return retval
end
--------------------------------------------------------------------------------
function cleanup_path(temppath)
local parts = temppath:split("-")
temppath = ""
for i=1,#parts,1 do
if temppath ~= "" then
temppath = temppath .. "_"
end
temppath = temppath .. parts[i]
end
parts = temppath:split(".")
temppath = ""
for i=1,#parts,1 do
if temppath ~= "" then
temppath = temppath .. "_"
end
temppath = temppath .. parts[i]
end
parts = temppath:split("'")
temppath = ""
for i=1,#parts,1 do
if temppath ~= "" then
temppath = temppath .. ""
end
temppath = temppath .. parts[i]
end
parts = temppath:split(" ")
temppath = ""
for i=1,#parts,1 do
if temppath ~= "" then
temppath = temppath
end
temppath = temppath .. parts[i]
end
return temppath
end
local tbl = engine or minetest
function tbl.formspec_escape(text)
if text ~= nil then
text = string.gsub(text,"\\","\\\\")
text = string.gsub(text,"%]","\\]")
text = string.gsub(text,"%[","\\[")
text = string.gsub(text,";","\\;")
text = string.gsub(text,",","\\,")
end
return text
end
--------------------------------------------------------------------------------
-- mainmenu only functions
--------------------------------------------------------------------------------
if engine ~= nil then
engine.get_game = function(index)
local games = game.get_games()
if index > 0 and index <= #games then
return games[index]
end
return nil
end
function fgettext(text, ...)
text = engine.gettext(text)
local arg = {n=select('#', ...), ...}
if arg.n >= 1 then
-- Insert positional parameters ($1, $2, ...)
result = ''
pos = 1
while pos <= text:len() do
newpos = text:find('[$]', pos)
if newpos == nil then
result = result .. text:sub(pos)
pos = text:len() + 1
else
paramindex = tonumber(text:sub(newpos+1, newpos+1))
result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
pos = newpos + 2
end
end
text = result
end
return engine.formspec_escape(text)
end
end
--------------------------------------------------------------------------------
-- core only fct
--------------------------------------------------------------------------------
if minetest ~= nil then
--------------------------------------------------------------------------------
function minetest.pos_to_string(pos)
return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
end
end

330
builtin/misc_register.lua Normal file
View File

@ -0,0 +1,330 @@
-- 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
local register_biome_raw = minetest.register_biome
minetest.registered_biomes = {}
function minetest.register_biome(biome)
minetest.registered_biomes[biome.name] = biome
register_biome_raw(biome)
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()
minetest.registered_on_cheats, minetest.register_on_cheat = make_registration()

79
builtin/mm_menubar.lua Normal file
View File

@ -0,0 +1,79 @@
--Minetest
--Copyright (C) 2013 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
menubar = {}
--------------------------------------------------------------------------------
function menubar.handle_buttons(fields)
for i=1,#menubar.buttons,1 do
if fields[menubar.buttons[i].btn_name] ~= nil then
menu.last_game = menubar.buttons[i].index
engine.setting_set("main_menu_last_game_idx",menu.last_game)
menu.update_gametype()
end
end
end
--------------------------------------------------------------------------------
function menubar.refresh()
menubar.formspec = "box[-0.3,5.625;12.4,1.3;000000]" ..
"box[-0.3,5.6;12.4,0.05;FFFFFF]"
menubar.buttons = {}
local button_base = -0.25
local maxbuttons = #gamemgr.games
if maxbuttons > 10 then
maxbuttons = 10
end
for i=1,maxbuttons,1 do
local btn_name = "menubar_btn_" .. gamemgr.games[i].id
local buttonpos = button_base + (i-1) * 1.245
if gamemgr.games[i].menuicon_path ~= nil and
gamemgr.games[i].menuicon_path ~= "" then
menubar.formspec = menubar.formspec ..
"image_button[" .. buttonpos .. ",5.7;1.3,1.3;" ..
engine.formspec_escape(gamemgr.games[i].menuicon_path) .. ";" ..
btn_name .. ";;true;false]"
else
local part1 = gamemgr.games[i].id:sub(1,5)
local part2 = gamemgr.games[i].id:sub(6,10)
local part3 = gamemgr.games[i].id:sub(11)
local text = part1 .. "\n" .. part2
if part3 ~= nil and
part3 ~= "" then
text = text .. "\n" .. part3
end
menubar.formspec = menubar.formspec ..
"image_button[" .. buttonpos .. ",5.7;1.3,1.3;;" ..btn_name ..
";" .. text .. ";true;true]"
end
local toadd = {
btn_name = btn_name,
index = i,
}
table.insert(menubar.buttons,toadd)
end
end

146
builtin/mm_textures.lua Normal file
View File

@ -0,0 +1,146 @@
--Minetest
--Copyright (C) 2013 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
mm_texture = {}
--------------------------------------------------------------------------------
function mm_texture.init()
mm_texture.defaulttexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
mm_texture.basetexturedir = mm_texture.defaulttexturedir
mm_texture.texturepack = engine.setting_get("texture_path")
mm_texture.gameid = nil
end
--------------------------------------------------------------------------------
function mm_texture.update(tab,gamedetails)
if tab ~= "singleplayer" then
mm_texture.reset()
return
end
if gamedetails == nil then
return
end
mm_texture.update_game(gamedetails)
end
--------------------------------------------------------------------------------
function mm_texture.reset()
mm_texture.gameid = nil
local have_bg = false
local have_overlay = mm_texture.set_generic("overlay")
if not have_overlay then
have_bg = mm_texture.set_generic("background")
end
mm_texture.clear("header")
mm_texture.clear("footer")
engine.set_clouds(false)
mm_texture.set_generic("footer")
mm_texture.set_generic("header")
if not have_bg and
engine.setting_getbool("enable_clouds") then
engine.set_clouds(true)
end
end
--------------------------------------------------------------------------------
function mm_texture.update_game(gamedetails)
if mm_texture.gameid == gamedetails.id then
return
end
local have_bg = false
local have_overlay = mm_texture.set_game("overlay",gamedetails)
if not have_overlay then
have_bg = mm_texture.set_game("background",gamedetails)
end
mm_texture.clear("header")
mm_texture.clear("footer")
engine.set_clouds(false)
if not have_bg and
engine.setting_getbool("enable_clouds") then
engine.set_clouds(true)
end
mm_texture.set_game("footer",gamedetails)
mm_texture.set_game("header",gamedetails)
mm_texture.gameid = gamedetails.id
end
--------------------------------------------------------------------------------
function mm_texture.clear(identifier)
engine.set_background(identifier,"")
end
--------------------------------------------------------------------------------
function mm_texture.set_generic(identifier)
--try texture pack first
if mm_texture.texturepack ~= nil then
local path = mm_texture.texturepack .. DIR_DELIM .."menu_" ..
identifier .. ".png"
if engine.set_background(identifier,path) then
return true
end
end
if mm_texture.defaulttexturedir ~= nil then
local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" ..
identifier .. ".png"
if engine.set_background(identifier,path) then
return true
end
end
return false
end
--------------------------------------------------------------------------------
function mm_texture.set_game(identifier,gamedetails)
if gamedetails == nil then
return false
end
if mm_texture.texturepack ~= nil then
local path = mm_texture.texturepack .. DIR_DELIM ..
gamedetails.id .. "_menu_" .. identifier .. ".png"
if engine.set_background(identifier,path) then
return true
end
end
local path = gamedetails.path .. DIR_DELIM .."menu" ..
DIR_DELIM .. identifier .. ".png"
if engine.set_background(identifier,path) then
return true
end
return false
end

1082
builtin/modmgr.lua Normal file

File diff suppressed because it is too large Load Diff

274
builtin/modstore.lua Normal file
View File

@ -0,0 +1,274 @@
--Minetest
--Copyright (C) 2013 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
--modstore implementation
modstore = {}
--------------------------------------------------------------------------------
function modstore.init()
modstore.tabnames = {}
table.insert(modstore.tabnames,"dialog_modstore_unsorted")
table.insert(modstore.tabnames,"dialog_modstore_search")
modstore.modsperpage = 5
modstore.basetexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
modstore.current_list = nil
modstore.details_cache = {}
end
--------------------------------------------------------------------------------
function modstore.nametoindex(name)
for i=1,#modstore.tabnames,1 do
if modstore.tabnames[i] == name then
return i
end
end
return 1
end
--------------------------------------------------------------------------------
function modstore.gettab(tabname)
local retval = ""
local is_modstore_tab = false
if tabname == "dialog_modstore_unsorted" then
retval = modstore.getmodlist(modstore.modlist_unsorted)
is_modstore_tab = true
end
if tabname == "dialog_modstore_search" then
is_modstore_tab = true
end
if is_modstore_tab then
return modstore.tabheader(tabname) .. retval
end
if tabname == "modstore_mod_installed" then
return "size[6,2]label[0.25,0.25;Mod: " .. modstore.lastmodtitle ..
" installed successfully]" ..
"button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;ok]"
end
return ""
end
--------------------------------------------------------------------------------
function modstore.tabheader(tabname)
local retval = "size[12,9.25]"
retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" ..
"Unsorted,Search;" ..
modstore.nametoindex(tabname) .. ";true;false]"
return retval
end
--------------------------------------------------------------------------------
function modstore.handle_buttons(current_tab,fields)
modstore.lastmodtitle = ""
if fields["modstore_tab"] then
local index = tonumber(fields["modstore_tab"])
if index > 0 and
index <= #modstore.tabnames then
return {
current_tab = modstore.tabnames[index],
is_dialog = true,
show_buttons = false
}
end
modstore.modlist_page = 0
end
if fields["btn_modstore_page_up"] then
if modstore.current_list ~= nil and modstore.current_list.page > 0 then
modstore.current_list.page = modstore.current_list.page - 1
end
end
if fields["btn_modstore_page_down"] then
if modstore.current_list ~= nil and
modstore.current_list.page <modstore.current_list.pagecount-1 then
modstore.current_list.page = modstore.current_list.page +1
end
end
if fields["btn_confirm_mod_successfull"] then
return {
current_tab = modstore.tabnames[1],
is_dialog = true,
show_buttons = false
}
end
for i=1, modstore.modsperpage, 1 do
local installbtn = "btn_install_mod_" .. i
if fields[installbtn] then
local modlistentry =
modstore.current_list.page * modstore.modsperpage + i
local moddetails = modstore.get_details(modstore.current_list.data[modlistentry].id)
local fullurl = engine.setting_get("modstore_download_url") ..
moddetails.download_url
local modfilename = os.tempfolder() .. ".zip"
if engine.download_file(fullurl,modfilename) then
modmgr.installmod(modfilename,moddetails.basename)
os.remove(modfilename)
modstore.lastmodtitle = modstore.current_list.data[modlistentry].title
return {
current_tab = "modstore_mod_installed",
is_dialog = true,
show_buttons = false
}
else
gamedata.errormessage = "Unable to download " ..
moddetails.download_url .. " (internet connection?)"
end
end
end
end
--------------------------------------------------------------------------------
function modstore.update_modlist()
modstore.modlist_unsorted = {}
modstore.modlist_unsorted.data = engine.get_modstore_list()
if modstore.modlist_unsorted.data ~= nil then
modstore.modlist_unsorted.pagecount =
math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
else
modstore.modlist_unsorted.data = {}
modstore.modlist_unsorted.pagecount = 1
end
modstore.modlist_unsorted.page = 0
end
--------------------------------------------------------------------------------
function modstore.getmodlist(list)
local retval = ""
retval = retval .. "label[10,-0.4;" .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
retval = retval .. "button[11.6,-0.1;0.5,0.5;btn_modstore_page_up;^]"
retval = retval .. "box[11.6,0.35;0.28,8.6;000000]"
local scrollbarpos = 0.35 + (8.1/(list.pagecount-1)) * list.page
retval = retval .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;32CD32]"
retval = retval .. "button[11.6,9.0;0.5,0.5;btn_modstore_page_down;v]"
if #list.data < (list.page * modstore.modsperpage) then
return retval
end
local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
if (endmod > #list.data) then
endmod = #list.data
end
for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
--getmoddetails
local details = modstore.get_details(list.data[i].id)
if details ~= nil then
local screenshot_ypos = (i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
retval = retval .. "box[0," .. screenshot_ypos .. ";11.4,1.75;FFFFFF]"
--screenshot
if details.screenshot_url ~= nil and
details.screenshot_url ~= "" then
if list.data[i].texturename == nil then
local fullurl = engine.setting_get("modstore_download_url") ..
details.screenshot_url
local filename = os.tempfolder()
if engine.download_file(fullurl,filename) then
list.data[i].texturename = filename
end
end
end
if list.data[i].texturename == nil then
list.data[i].texturename = modstore.basetexturedir .. "no_screenshot.png"
end
retval = retval .. "image[0,".. screenshot_ypos .. ";3,2;" ..
engine.formspec_escape(list.data[i].texturename) .. "]"
--title + author
retval = retval .."label[2.75," .. screenshot_ypos .. ";" ..
engine.formspec_escape(details.title) .. " (" .. details.author .. ")]"
--description
local descriptiony = screenshot_ypos + 0.5
retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
engine.formspec_escape(details.description) .. ";]"
--rating
local ratingy = screenshot_ypos + 0.6
retval = retval .."label[10.1," .. ratingy .. ";" ..
fgettext("Rating") .. ": " .. details.rating .."]"
--install button
local buttony = screenshot_ypos + 1.2
local buttonnumber = (i - (list.page * modstore.modsperpage))
retval = retval .."button[9.6," .. buttony .. ";2,0.5;btn_install_mod_" .. buttonnumber .. ";"
if modmgr.mod_exists(details.basename) then
retval = retval .. fgettext("re-Install") .."]"
else
retval = retval .. fgettext("Install") .."]"
end
end
end
modstore.current_list = list
return retval
end
--------------------------------------------------------------------------------
function modstore.get_details(modid)
if modstore.details_cache[modid] ~= nil then
return modstore.details_cache[modid]
end
local retval = engine.get_modstore_details(tostring(modid))
modstore.details_cache[modid] = retval
return retval
end

52
builtin/privileges.lua Normal file
View File

@ -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")

207
builtin/serialize.lua Normal file
View File

@ -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

33
builtin/static_spawn.lua Normal file
View File

@ -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)

135
builtin/vector.lua Normal file
View File

@ -0,0 +1,135 @@
vector = {}
function vector.new(a, b, c)
assert(a)
if type(a) == "table" then
return {x=a.x, y=a.y, z=a.z}
else
assert(b and c)
return {x=a, y=b, z=c}
end
return {x=0, y=0, z=0}
end
function vector.equals(a, b)
assert(a and b)
return a.x == b.x and
a.y == b.y and
a.z == b.z
end
function vector.length(v)
assert(v)
return math.hypot(v.x, math.hypot(v.y, v.z))
end
function vector.normalize(v)
assert(v)
local len = vector.length(v)
if len == 0 then
return vector.new()
else
return vector.divide(v, len)
end
end
function vector.round(v)
assert(v)
return {
x = math.floor(v.x + 0.5),
y = math.floor(v.y + 0.5),
z = math.floor(v.z + 0.5)
}
end
function vector.distance(a, b)
assert(a and b)
local x = a.x - b.x
local y = a.y - b.y
local z = a.z - b.z
return math.hypot(x, math.hypot(y, z))
end
function vector.direction(pos1, pos2)
assert(pos1 and pos2)
local x_raw = pos2.x - pos1.x
local y_raw = pos2.y - pos1.y
local z_raw = pos2.z - pos1.z
local x_abs = math.abs(x_raw)
local y_abs = math.abs(y_raw)
local z_abs = math.abs(z_raw)
if x_abs >= y_abs and
x_abs >= z_abs then
y_raw = y_raw * (1 / x_abs)
z_raw = z_raw * (1 / x_abs)
x_raw = x_raw / x_abs
end
if y_abs >= x_abs and
y_abs >= z_abs then
x_raw = x_raw * (1 / y_abs)
z_raw = z_raw * (1 / y_abs)
y_raw = y_raw / y_abs
end
if z_abs >= y_abs and
z_abs >= x_abs then
x_raw = x_raw * (1 / z_abs)
y_raw = y_raw * (1 / z_abs)
z_raw = z_raw / z_abs
end
return {x=x_raw, y=y_raw, z=z_raw}
end
function vector.add(a, b)
assert(a and b)
if type(b) == "table" then
return {x = a.x + b.x,
y = a.y + b.y,
z = a.z + b.z}
else
return {x = a.x + b,
y = a.y + b,
z = a.z + b}
end
end
function vector.subtract(a, b)
assert(a and b)
if type(b) == "table" then
return {x = a.x - b.x,
y = a.y - b.y,
z = a.z - b.z}
else
return {x = a.x - b,
y = a.y - b,
z = a.z - b}
end
end
function vector.multiply(a, b)
assert(a and b)
if type(b) == "table" then
return {x = a.x * b.x,
y = a.y * b.y,
z = a.z * b.z}
else
return {x = a.x * b,
y = a.y * b,
z = a.z * b}
end
end
function vector.divide(a, b)
assert(a and b)
if type(b) == "table" then
return {x = a.x / b.x,
y = a.y / b.y,
z = a.z / b.z}
else
return {x = a.x / b,
y = a.y / b,
z = a.z / b}
end
end

103
builtin/voxelarea.lua Normal file
View File

@ -0,0 +1,103 @@
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:position(i)
local p = {}
i = i - 1
p.z = math.floor(i / self.zstride) + self.MinEdge.z
i = i % self.zstride
p.y = math.floor(i / self.ystride) + self.MinEdge.y
i = i % self.ystride
p.x = math.floor(i) + self.MinEdge.x
return p
end
function VoxelArea:contains(x, y, z)
return (x >= self.MinEdge.x) and (x <= self.MaxEdge.x) and
(y >= self.MinEdge.y) and (y <= self.MaxEdge.y) and
(z >= self.MinEdge.z) and (z <= self.MaxEdge.z)
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
function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz)
local i = self:index(minx, miny, minz) - 1
local last = self:index(maxx, maxy, maxz)
local ystride = self.ystride
local zstride = self.zstride
local yoff = (last+1) % ystride
local zoff = (last+1) % zstride
local ystridediff = (i - last) % ystride
local zstridediff = (i - last) % zstride
return function()
i = i + 1
if i % zstride == zoff then
i = i + zstridediff
elseif i % ystride == yoff then
i = i + ystridediff
end
if i <= last then
return i
end
end
end
function VoxelArea:iterp(minp, maxp)
return self:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z)
end

2
client/serverlist/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -0,0 +1 @@
trans_alphach

View File

@ -0,0 +1,46 @@
uniform sampler2D myTexture;
uniform sampler2D normalTexture;
uniform vec4 skyBgColor;
uniform float fogDistance;
varying vec3 vPosition;
varying vec3 viewVec;
void main (void)
{
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
float alpha = col.a;
vec2 uv = gl_TexCoord[0].st;
vec4 base = texture2D(myTexture, uv);
vec4 final_color = vec4(0.2, 0.2, 0.2, 1.0) * base;
vec3 vVec = normalize(viewVec);
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
vec3 R = reflect(-vVec, bump);
vec3 lVec = normalize(vec3(0.0, -0.4, 0.5));
float diffuse = max(dot(lVec, bump), 0.0);
vec3 color = diffuse * texture2D(myTexture, gl_TexCoord[0].st).rgb;
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
color += vec3(0.2*specular*diffuse);
col = vec4(color.r, color.g, color.b, alpha);
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));
alpha = mix(alpha, 0.0, d);
}
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
}

View File

@ -0,0 +1,98 @@
uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform float dayNightRatio;
varying vec3 vPosition;
varying vec3 viewVec;
void main(void)
{
gl_Position = mWorldViewProj * gl_Vertex;
vPosition = (mWorldViewProj * gl_Vertex).xyz;
vec3 tangent;
vec3 binormal;
vec3 c1 = cross( gl_Normal, vec3(0.0, 0.0, 1.0) );
vec3 c2 = cross( gl_Normal, vec3(0.0, 1.0, 0.0) );
if( length(c1)>length(c2) )
{
tangent = c1;
}
else
{
tangent = c2;
}
tangent = normalize(tangent);
//binormal = cross(gl_Normal, tangent);
//binormal = normalize(binormal);
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.5; // 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;
vec3 n1 = normalize(gl_NormalMatrix * gl_Normal);
vec4 tangent1 = vec4(tangent.x, tangent.y, tangent.z, 0);
//vec3 t1 = normalize(gl_NormalMatrix * tangent1);
//vec3 b1 = cross(n1, t1);
vec3 v;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 vVec = -vVertex;
//v.x = dot(vVec, t1);
//v.y = dot(vVec, b1);
//v.z = dot(vVec, n1);
//viewVec = vVec;
viewVec = normalize(vec3(0.0, -0.4, 0.5));
//Vector representing the 0th texture coordinate passed to fragment shader
//gl_TexCoord[0] = vec2(gl_MultiTexCoord0);
// Transform the current vertex
//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

View File

@ -0,0 +1 @@
trans_alphach_ref

View File

@ -0,0 +1,45 @@
uniform sampler2D myTexture;
uniform sampler2D normalTexture;
uniform vec4 skyBgColor;
uniform float fogDistance;
varying vec3 vPosition;
varying vec3 viewVec;
void main (void)
{
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
float alpha = col.a;
vec2 uv = gl_TexCoord[0].st;
vec4 base = texture2D(myTexture, uv);
vec4 final_color = vec4(0.2, 0.2, 0.2, 1.0) * base;
vec3 vVec = normalize(viewVec);
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
vec3 R = reflect(-vVec, bump);
vec3 lVec = normalize(vec3(0.0, -0.4, 0.5));
float diffuse = max(dot(lVec, bump), 0.0);
vec3 color = diffuse * texture2D(myTexture, gl_TexCoord[0].st).rgb;
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
color += vec3(0.2*specular*diffuse);
col = vec4(color.r, color.g, color.b, alpha);
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, alpha);
}

View File

@ -0,0 +1,98 @@
uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform float dayNightRatio;
varying vec3 vPosition;
varying vec3 viewVec;
void main(void)
{
gl_Position = mWorldViewProj * gl_Vertex;
vPosition = (mWorldViewProj * gl_Vertex).xyz;
vec3 tangent;
vec3 binormal;
vec3 c1 = cross( gl_Normal, vec3(0.0, 0.0, 1.0) );
vec3 c2 = cross( gl_Normal, vec3(0.0, 1.0, 0.0) );
if( length(c1)>length(c2) )
{
tangent = c1;
}
else
{
tangent = c2;
}
tangent = normalize(tangent);
//binormal = cross(gl_Normal, tangent);
//binormal = normalize(binormal);
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.5; // 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;
vec3 n1 = normalize(gl_NormalMatrix * gl_Normal);
vec4 tangent1 = vec4(tangent.x, tangent.y, tangent.z, 0);
//vec3 t1 = normalize(gl_NormalMatrix * tangent1);
//vec3 b1 = cross(n1, t1);
vec3 v;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 vVec = -vVertex;
//v.x = dot(vVec, t1);
//v.y = dot(vVec, b1);
//v.z = dot(vVec, n1);
//viewVec = vVec;
viewVec = normalize(vec3(0.0, -0.4, 0.5));
//Vector representing the 0th texture coordinate passed to fragment shader
//gl_TexCoord[0] = vec2(gl_MultiTexCoord0);
// Transform the current vertex
//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

View File

@ -0,0 +1 @@
trans_alphach_ref

View File

@ -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);
}

View File

@ -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;
}

View File

@ -0,0 +1 @@
trans_alphach

View File

@ -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);
}

View File

@ -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;
}

View File

@ -0,0 +1 @@
trans_alphach

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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}")

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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 ()

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,20 @@
# Always run during 'make'
if(VERSION_EXTRA)
set(VERSION_GITHASH "${VERSION_STRING}")
else(VERSION_EXTRA)
execute_process(COMMAND git describe --always --tag --dirty
WORKING_DIRECTORY "${GENERATE_VERSION_SOURCE_DIR}"
OUTPUT_VARIABLE VERSION_GITHASH OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if(VERSION_GITHASH)
message(STATUS "*** Detected git version ${VERSION_GITHASH} ***")
else()
set(VERSION_GITHASH "${VERSION_STRING}")
endif()
endif()
configure_file(
${GENERATE_VERSION_SOURCE_DIR}/cmake_config_githash.h.in
${GENERATE_VERSION_BINARY_DIR}/cmake_config_githash.h)

21
cmake/Modules/misc.cmake Normal file
View File

@ -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)

502
doc/lgpl-2.1.txt Normal file
View File

@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 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.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library 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 library 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 library; 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.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

2297
doc/lua_api.txt Normal file

File diff suppressed because it is too large Load Diff

583
doc/mapformat.txt Normal file
View File

@ -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

190
doc/menu_lua_api.txt Normal file
View File

@ -0,0 +1,190 @@
Minetest Lua Mainmenu API Reference 0.4.6
========================================
Introduction
-------------
The main menu is defined as a formspec by Lua in builtin/mainmenu.lua
Description of formspec language to show your menu is in lua_api.txt
Callbacks
---------
engine.buttonhandler(fields): called when a button is pressed.
^ fields = {name1 = value1, name2 = value2, ...}
engine.event_handler(event)
^ event: "MenuQuit", "KeyEnter", "ExitButton" or "EditBoxEnter"
Gamedata
--------
The "gamedata" table is read when calling engine.start(). It should contain:
{
playername = <name>,
password = <password>,
address = <IP/adress>,
port = <port>,
selected_world = <index>, -- 0 for client mode
singleplayer = <true/false>,
}
Functions
---------
engine.start()
engine.close()
Filesystem:
engine.get_scriptdir()
^ returns directory of script
engine.get_modpath()
^ returns path to global modpath
engine.get_modstore_details(modid)
^ modid numeric id of mod in modstore
^ returns {
id = <numeric id of mod in modstore>,
title = <human readable title>,
basename = <basename for mod>,
description = <description of mod>,
author = <author of mod>,
download_url= <best match download url>,
license = <short description of license>,
rating = <float value of current rating>
}
engine.get_modstore_list()
^ returns {
[1] = {
id = <numeric id of mod in modstore>,
title = <human readable title>,
basename = <basename for mod>
}
}
engine.get_gamepath()
^ returns path to global gamepath
engine.get_dirlist(path,onlydirs)
^ path to get subdirs from
^ onlydirs should result contain only dirs?
^ returns list of folders within path
engine.create_dir(absolute_path)
^ absolute_path to directory to create (needs to be absolute)
^ returns true/false
engine.delete_dir(absolute_path)
^ absolute_path to directory to delete (needs to be absolute)
^ returns true/false
engine.copy_dir(source,destination,keep_soure)
^ source folder
^ destination folder
^ keep_source DEFAULT true --> if set to false source is deleted after copying
^ returns true/false
engine.extract_zip(zipfile,destination) [unzip within path required]
^ zipfile to extract
^ destination folder to extract to
^ returns true/false
engine.download_file(url,target)
^ url to download
^ target to store to
^ returns true/false
engine.get_version()
^ returns current minetest version
engine.sound_play(spec, looped) -> handle
^ spec = SimpleSoundSpec (see lua-api.txt)
^ looped = bool
engine.sound_stop(handle)
GUI:
engine.update_formspec(formspec)
- engine.set_background(type, texturepath)
^ type: "background", "overlay", "header" or "footer"
engine.set_clouds(<true/false>)
engine.set_topleft_text(text)
Games:
engine.get_game(index)
^ returns {
id = <id>,
path = <full path to game>,
gamemods_path = <path>,
name = <name of game>,
menuicon_path = <full path to menuicon>,
DEPRECATED:
addon_mods_paths = {[1] = <path>,},
}
engine.get_games() -> table of all games in upper format
Favorites:
engine.get_favorites(location) -> list of favorites
^ location: "local" or "online"
^ returns {
[1] = {
clients = <number of clients/nil>,
clients_max = <maximum number of clients/nil>,
version = <server version/nil>,
password = <true/nil>,
creative = <true/nil>,
damage = <true/nil>,
pvp = <true/nil>,
description = <server description/nil>,
name = <server name/nil>,
address = <address of server/nil>,
port = <port>
},
}
engine.delete_favorite(id, location) -> success
Logging:
engine.debug(line)
^ Always printed to stderr and logfile (print() is redirected here)
engine.log(line)
engine.log(loglevel, line)
^ loglevel one of "error", "action", "info", "verbose"
Settings:
engine.setting_set(name, value)
engine.setting_get(name) -> string or nil
engine.setting_setbool(name, value)
engine.setting_getbool(name) -> bool or nil
engine.setting_save() -> nil, save all settings to config file
Worlds:
engine.get_worlds() -> list of worlds
^ returns {
[1] = {
path = <full path to world>,
name = <name of world>,
gameid = <gameid of world>,
},
}
engine.create_world(worldname, gameid)
engine.delete_world(index)
UI:
engine.get_textlist_index(textlistname) -> index
engine.show_keys_menu()
engine.file_open_dialog(formname,caption)
^ shows a file open dialog
^ formname is base name of dialog response returned in fields
^ -if dialog was accepted "_accepted"
^^ will be added to fieldname containing the path
^ -if dialog was canceled "_cancelled"
^ will be added to fieldname value is set to formname itself
^ returns nil or selected file/folder
Helpers:
engine.formspec_escape(string) -> string
^ escapes characters [ ] \ , ; that can not be used in formspecs
engine.gettext(string) -> string
^ look up the translation of a string in the gettext message catalog
fgettext(string, ...) -> string
^ call engine.gettext(string), replace "$1"..."$9" with the given
^ extra arguments, call engine.formspec_escape and return the result
engine.parse_json(string[, nullvalue]) -> something
^ see minetest.parse_json (lua_api.txt)
dump(obj, dumped={})
^ Return object serialized as a string
string:split(separator)
^ eg. string:split("a,b", ",") == {"a","b"}
string:trim()
^ eg. string.trim("\n \t\tfoo bar\t ") == "foo bar"
minetest.is_yes(arg)
^ returns whether arg can be interpreted as yes
Class reference
----------------
Settings: see lua_api.txt

101
doc/minetest.6 Normal file
View File

@ -0,0 +1,101 @@
.\" Minetest man page
.TH minetest 6 "10 September 2013" "" ""
.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
\-\-version
Show version information
.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
.TP
\-\-migrate <value>
Migrate from current map backend to another. Possible values are sqlite3
and leveldb. Only works when using --server.
.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)

77
doc/minetestserver.6 Normal file
View File

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

108
doc/protocol.txt Normal file
View File

@ -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])

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
fonts/fontlucida.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
fonts/liberationmono.ttf Normal file

Binary file not shown.

BIN
fonts/liberationsans.ttf Normal file

Binary file not shown.

2
games/minimal/game.conf Normal file
View File

@ -0,0 +1,2 @@
name = Minimal development test

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

BIN
games/minimal/menu/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -0,0 +1,2 @@
default

View File

@ -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,
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
-- minetest/default/mapgen.lua
--
-- Aliases for map generator outputs
--
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")
minetest.register_alias("mapgen_stair_cobble", "stairs:stair_cobble")
--
-- 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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

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