Compare commits

..

23 Commits

Author SHA1 Message Date
Perttu Ahola
7993a403f2 Bump version to 0.4.12 2015-02-18 19:50:37 +02:00
Novatux
b0df67d9c0 Add modname convention checking
Fixes #2037
2015-02-18 17:06:09 +01:00
Loic Blot
45ff8569d7 Fix serverlist include 2015-02-18 16:26:23 +01:00
est31
82bfa2ee7b Server: announce MIN/MAX protocol version supported to serverlist. Client: check serverlist
Client now informs about incompatible servers from the list, this permits to prevent the protocol movements.
Server announces its supported protocol versions to master server
2015-02-18 16:17:03 +01:00
fz72
9ef2e5000f Fix map_seed not changed when creating a new world after login to another 2015-02-18 14:02:30 +02:00
BlockMen
678546308e Increase default font_size 2015-02-18 12:59:16 +01:00
BlockMen
6f688c50ee Fix font_size under windows 2015-02-18 12:59:07 +01:00
Perttu Ahola
bb603ff18e Use fixed size for builtin menus on non-android platforms 2015-02-18 13:57:54 +02:00
Loic Blot
4208fdfd22 Fix unused (and so, broken) enable_rollback_recording. This option must be reloaded at server loop but loaded when server starts, for data consistency (not a hot load variable) 2015-02-18 09:36:42 +01:00
Kahrl
4875213168 Grab GUIChatConsole::m_font, fixes segfault when changing font_size 2015-02-18 00:40:11 +10:00
Loic Blot
f92540e8ad Add german and french translation for minetest.desktop
This fixes #1573
2015-02-14 13:12:08 +01:00
Jakub Vaněk
ec0bf899ed Update czech translation 2015-02-14 13:11:50 +01:00
ngosang
2b635a892c Minor fixes in translations 2015-02-14 13:11:33 +01:00
Loic Blot
7f6fc148bd Fix issue #2279. ok @zeno- 2015-02-14 21:02:19 +10:00
ngosang
878e9f7594 Fix .zip extraction (mod store) 2015-02-14 21:00:13 +10:00
Rui
c7249f5983 Fix store.lua bug: default screenshot 2015-02-14 21:00:06 +10:00
Rui
7f07858209 Fix tab_mods.lua: default screenshot patch
https://forum.minetest.net/viewtopic.php?f=6&t=11201
Fixed this bug.
2015-02-14 21:00:01 +10:00
ShadowNinja
9e9688fc61 Fix Android build of narrow_to_wide 2015-02-14 20:59:45 +10:00
Markus Koschany
93e5ab367a Fix FTBFS on GNU/Hurd platform
Minetest fails to build on GNU/Hurd due to a name clash with OSX/Apple,
both are defining the __MACH__ keyword. This commit fixes the issue.
2015-02-14 20:59:35 +10:00
est31
60fa5807b9 README.txt: Simplify initial build steps by using git to fetch sources
Also simplify wget steps and apt-get install zlib1g-dev libjsoncpp-dev
2015-02-14 20:59:00 +10:00
ngosang
9dbca41385 Fix Exit to OS button focus in Pause Menu 2015-02-14 20:58:39 +10:00
est31
61588a43dd Fix crash on passing false as value in table to table.copy(t)
Fixes #2293.
2015-02-14 15:24:09 +10:00
BlockMen
e62927ed71 Fix gettext on MSVC 2015-02-13 01:23:30 +10:00
674 changed files with 54750 additions and 213165 deletions

95
.gitignore vendored
View File

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

View File

@@ -1,31 +1,19 @@
language: cpp
compiler:
- gcc
- clang
env:
- WINDOWS=32
- WINDOWS=64
- WINDOWS=no
before_install: ./util/travis/before_install.sh
script: ./util/travis/script.sh
sudo: required
notifications:
email: false
matrix:
fast_finish: true
include:
- env: PLATFORM=Win32
compiler: gcc
os: linux
- env: PLATFORM=Win64
compiler: gcc
os: linux
- env: PLATFORM=Unix COMPILER=clang
exclude:
- env: WINDOWS=32
compiler: clang
os: osx
- env: PLATFORM=Unix COMPILER=g++
compiler: gcc
os: linux
- env: PLATFORM=Unix COMPILER=clang
- env: WINDOWS=64
compiler: clang
os: linux
- env: PLATFORM=Unix COMPILER=g++-6
compiler: gcc
os: linux
addons:
apt:
sources: &sources
- ubuntu-toolchain-r-test

View File

@@ -1,64 +1,69 @@
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()
# 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(PROJECT_NAME_CAPITALIZED "Minetest")
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
set(VERSION_PATCH 15)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Change to false for releases
set(DEVELOPMENT_BUILD FALSE)
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
set(VERSION_PATCH 12)
set(VERSION_PATCH_ORIG ${VERSION_PATCH})
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
if(VERSION_EXTRA)
set(VERSION_STRING ${VERSION_STRING}-${VERSION_EXTRA})
elseif(DEVELOPMENT_BUILD)
set(VERSION_STRING "${VERSION_STRING}-dev")
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} ***")
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
# Configuration options
set(DEFAULT_RUN_IN_PLACE FALSE)
if(WIN32)
set(DEFAULT_RUN_IN_PLACE TRUE)
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()
set(RUN_IN_PLACE ${DEFAULT_RUN_IN_PLACE} CACHE BOOL
"Run directly in source directory structure")
# RUN_IN_PLACE is exported as a #define value, ensure it's 1/0 instead of ON/OFF
if(RUN_IN_PLACE)
set(RUN_IN_PLACE 1)
else()
set(RUN_IN_PLACE 0)
endif()
set(BUILD_CLIENT TRUE CACHE BOOL "Build client")
set(BUILD_SERVER FALSE CACHE BOOL "Build server")
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 TRUE CACHE BOOL "Enable -Wall for Release build")
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 reasonable
# This is done here so that relative search paths are more reasnable
find_package(Irrlicht)
#
# Installation
#
if(WIN32)
set(SHAREDIR ".")
@@ -67,13 +72,11 @@ if(WIN32)
set(EXAMPLE_CONF_DIR ".")
set(LOCALEDIR "locale")
elseif(APPLE)
set(BUNDLE_NAME ${PROJECT_NAME}.app)
set(BUNDLE_PATH "${BUNDLE_NAME}")
set(BINDIR ${BUNDLE_NAME}/Contents/MacOS)
set(SHAREDIR ${BUNDLE_NAME}/Contents/Resources)
set(DOCDIR "${SHAREDIR}/${PROJECT_NAME}")
set(SHAREDIR ".")
set(BINDIR ".")
set(DOCDIR "./doc/${PROJECT_NAME}")
set(EXAMPLE_CONF_DIR ${DOCDIR})
set(LOCALEDIR "${SHAREDIR}/locale")
set(LOCALEDIR "locale")
elseif(UNIX) # Linux, BSD etc
if(RUN_IN_PLACE)
set(SHAREDIR ".")
@@ -103,58 +106,54 @@ 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}")
if(NOT RUN_IN_PLACE)
set(EXAMPLE_CONF_DIR ${DOCDIR})
endif()
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" DESTINATION "${SHAREDIR}" PATTERN ".git*" EXCLUDE)
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)
@@ -167,32 +166,23 @@ install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/fonts" DESTINATION "${SHAREDIR}")
install(FILES "README.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/lua_api.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/menu_lua_api.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/texture_packs.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/world_format.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/mapformat.txt" DESTINATION "${DOCDIR}")
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
if(UNIX AND NOT APPLE)
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
install(FILES "misc/minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
install(FILES "misc/minetest.appdata.xml" DESTINATION "${APPDATADIR}")
install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
install(FILES "misc/minetest-xorg-icon-128.png"
DESTINATION "${ICONDIR}/hicolor/128x128/apps"
RENAME "minetest.png")
install(FILES "misc/minetest-icon.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
endif()
if(APPLE)
install(FILES "misc/minetest-icon.icns" DESTINATION "${SHAREDIR}")
install(FILES "misc/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents")
endif()
#
# Subdirectories
# Be sure to add all relevant definitions above this
#
add_subdirectory(src)
# CPack
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An InfiniMiner/Minecraft inspired game")
@@ -203,17 +193,32 @@ set(CPACK_PACKAGE_VENDOR "celeron55")
set(CPACK_PACKAGE_CONTACT "Perttu Ahola <celeron55@gmail.com>")
if(WIN32)
# For some reason these aren't copied otherwise
# NOTE: For some reason now it seems to work without these
#if(BUILD_CLIENT)
# install(FILES bin/minetest.exe DESTINATION bin)
#endif()
#if(BUILD_SERVER)
# install(FILES bin/minetestserver.exe DESTINATION bin)
#endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-win64")
else()
else(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-win32")
endif()
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
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)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-osx")
set(CPACK_GENERATOR ZIP)
set(CPACK_PACKAGE_ICON ${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.icns)
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
set(CPACK_BUNDLE_ICON ${CPACK_PACKAGE_ICON})
set(CPACK_BUNDLE_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/misc/Info.plist)
set(CPACK_GENERATOR "Bundle")
else()
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux")
set(CPACK_GENERATOR TGZ)
@@ -222,16 +227,14 @@ endif()
include(CPack)
# Add a target to generate API documentation with Doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
endif()
endif(DOXYGEN_FOUND)

View File

@@ -1,107 +0,0 @@
# Contributing
Contributions are welcome! Here's how you can help:
- [Contributing code](#code)
- [Reporting issues](#issues)
- [Requesting features](#feature-requests)
- [Translating](#translations)
- [Donating](#donations)
## Code
If you are planning to start some significant coding, you would benefit from asking first on [our IRC channel](http://www.minetest.net/irc/) before starting.
1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository and [clone](https://help.github.com/articles/cloning-a-repository/) your fork.
2. Start coding!
- Refer to the [Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt), [Developer Wiki](http://dev.minetest.net/Main_Page) and other [documentation](https://github.com/minetest/minetest/tree/master/doc).
- Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and [Lua](http://dev.minetest.net/Lua_code_style_guidelines) code style guidelines.
- Check your code works as expected and document any changes to the Lua API.
3. Commit & [push](https://help.github.com/articles/pushing-to-a-remote/) your changes to a new branch (not `master`, one change per branch)
- Commit messages should:
- Use the present tense
- Have a title which begins with a capital letter
- Be descriptive. (e.g. no `Update init.lua` or `Fix a problem`)
- Have a first line with less than *80 characters* and have a second line that is *empty*
- Do **not** [sign your commits](https://git-scm.com/book/uz/v2/Git-Tools-Signing-Your-Work), as Minetest offers automatically built ppas over launchpad and it [would break](https://bugs.launchpad.net/bzr-git/+bug/1084403) if there were signed commits in master
4. Once you are happy with your changes, submit a pull request.
- Open the [pull-request form](https://github.com/minetest/minetest/pull/new/master)
- Add a short description explaining briefly what you've done (or if it's a work-in-progress - what you need to do)
##### A pull-request is considered merge-able when:
1. It follows the [roadmap](https://forum.minetest.net/viewtopic.php?t=9177) in some way and fits the whole picture of the project.
2. It works.
3. It follows the code style for [C/C++](http://dev.minetest.net/Code_style_guidelines) or [Lua](http://dev.minetest.net/Lua_code_style_guidelines).
4. The code's interfaces are well designed, regardless of other aspects that might need more work in the future.
5. It uses protocols and formats which include the required compatibility.
## Issues
If you experience an issue, we would like to know the details - especially when a stable release is on the way.
1. Do a quick search on GitHub to check if the issue has already been reported.
2. Is it an issue with the Minetest *engine*? If not, report it [elsewhere](http://www.minetest.net/development/#reporting-issues).
3. [Open an issue](https://github.com/minetest/minetest/issues/new) and describe the issue you are having - you could include:
- Error logs (check the bottom of the `debug.txt` file)
- Screenshots
- Ways you have tried to solve the issue, and whether they worked or not
- Your Minetest version and the content (subgames, mods or texture packs) you have installed
- Your platform (e.g. Windows 10 or Ubuntu 15.04 x64)
After reporting you should aim to answer questions or clarifications as this helps pinpoint the cause of the issue (if you don't do this your issue may be closed after 1 month).
## Feature requests
Feature requests are welcome but take a moment to see if your idea follows the [roadmap](https://forum.minetest.net/viewtopic.php?t=9177) in some way and fits the whole picture of the project. You should provide a clear explanation with as much detail as possible.
## Translations
Translations of Minetest are performed using Weblate. You can access the project page with a list of current languages [here](https://hosted.weblate.org/projects/minetest/minetest/).
### Donations
If you'd like to monetarily support Minetest development, you can find donation methods on [our website](http://www.minetest.net/development/#donate).
# Maintaining
*This is a concise version of the [Rules & Guidelines](http://dev.minetest.net/Category:Rules_and_Guidelines) on the developer wiki.*
These notes are for those who have push access Minetest (core developers / maintainers).
- See the [project organisation](http://dev.minetest.net/Organisation) for the people involved.
## Reviewing pull requests
Pull requests should be reviewed and, if appropriate, checked if they achieve their intended purpose. You can show that you are in the process of, or will review the pull request by commenting *"Looks good"* or something similar.
**If the pull-request is not [merge-able](#a-pull-request-is-considered-merge-able-when):**
Submit a comment explaining to the author what they need to change to make the pull-request merge-able.
- If the author comments or makes changes to the pull-request, it can be reviewed again.
- If no response is made from the author within 1 month (when improvements are suggested or a question is asked), it can be closed.
**If the pull-request is [merge-able](#a-pull-request-is-considered-merge-able-when):**
Submit a :+1: (+1) or "Looks good" comment to show you believe the pull-request should be merged. "Looks good" comments often signify that the patch might require (more) testing.
- Two core developers must agree to the merge before it is carried out and both should +1 the pull request.
- Who intends to merge the pull-request should follow the commit rules:
- The title should follow the commit guidelines (title starts with a capital letter, present tense, descriptive).
- Don't modify history older than 10 minutes.
- Use rebase, not merge to get linear history:
- `curl https://github.com/minetest/minetest/pull/1.patch | git am`
## Reviewing issues and feature requests
- If an issue does not get a response from its author within 1 month (when requiring more details), it can be closed.
- When an issue is a duplicate, refer to the first ones and close the later ones.
- Tag issues with the appropriate [labels](https://github.com/minetest/minetest/labels) for devices, platforms etc.
## Releasing a new version
*Refer to [dev.minetest.net/Releasing_Minetest](http://dev.minetest.net/Releasing_Minetest)*

View File

@@ -1,4 +1,4 @@
Minetest
Minetest
========
An InfiniMiner/Minecraft inspired game.
@@ -27,47 +27,39 @@ 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
Default Controls
-----------------
- Move mouse: Look around
- W, A, S, D: Move
- Space: Jump/move up
- Shift: Sneak/move down
- Q: Drop itemstack
- Shift + Q: Drop single item
- Left mouse button: Dig/punch/take item
- Right mouse button: Place/use
- Shift + right mouse button: Build (without using)
- I: Inventory menu
- Mouse wheel: Select item
- 0-9: Select item
- Z: Zoom (needs zoom privilege)
- T: Chat
- /: Commad
- WASD: move
- Space: jump/climb
- Shift: sneak/go down
- Q: drop itemstack (+ SHIFT for single item)
- I: inventory
- Mouse: turn/look
- Mouse left: dig/punch
- Mouse right: place/use
- Mouse wheel: select item
- T: chat
- 1-8: select item
- Esc: Pause menu/abort/exit (pauses only singleplayer game)
- R: Enable/disable full range view
- Esc: pause menu (pauses only singleplayer game)
- R: Enable/Disable full range view
- +: Increase view range
- -: Decrease view range
- K: Enable/disable fly mode (needs fly privilege)
- J: Enable/disable fast mode (needs fast privilege)
- H: Enable/disable noclip mode (needs noclip privilege)
- K: Enable/Disable fly (needs fly privilege)
- J: Enable/Disable fast (needs fast privilege)
- H: Enable/Disable noclip (needs noclip privilege)
- F1: Hide/show HUD
- F2: Hide/show chat
- F3: Disable/enable fog
- F4: Disable/enable camera update (Mapblocks are not updated anymore when disabled, disabled in release builds)
- F5: Cycle through debug info screens
- F6: Cycle through profiler info screens
- F7: Cycle through camera modes
- F8: Toggle cinematic mode
- F9: Cycle through minimap modes
- Shift + F9: Change minimap orientation
- F10: Show/hide console
- F1: Hide/Show HUD
- F2: Hide/Show Chat
- F3: Disable/Enable Fog
- F4: Disable/Enable Camera update (Mapblocks are not updated anymore when disabled)
- F5: Toogle through debug info screens
- F6: Toogle through output data
- F7: Toggle through camera modes
- F10: Show/Hide console
- F12: Take screenshot
- P: Write stack traces into debug.txt
Most controls are settable in the configuration file, see the section below.
- Settable in the configuration file, see the section below.
Paths
------
@@ -86,9 +78,9 @@ $share = /usr/share/minetest
$user = ~/.minetest
OS X:
$bin = Contents/MacOS
$share = Contents/Resources
$user = Contents/User OR ~/Library/Application Support/minetest
$bin = ?
$share = ?
$user = ~/Library/Application Support/minetest
World directory
----------------
@@ -111,25 +103,21 @@ Compiling on GNU/Linux:
-----------------------
Install dependencies. Here's an example for Debian/Ubuntu:
$ sudo apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
For Fedora users:
$ sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl* openal* libvorbis* libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel irrlicht-devel bzip2-libs gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel doxygen spatialindex-devel bzip2-devel
$ 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 zlib1g-dev libjsoncpp-dev
You can install git for easily keeping your copy up to date.
If you dont want git, read below on how to get the source without git.
This is an example for installing git on Debian/Ubuntu:
$ sudo apt-get install git
For Fedora users:
$ sudo dnf install git
$ apt-get install git-core
Download source (this is the URL to the latest of source repository, which might not work at all times) using git:
$ git clone --depth 1 https://github.com/minetest/minetest.git
$ cd minetest
Download minetest_game (otherwise only the "Minimal development test" game is available) using git:
$ git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
$ cd games/
$ git clone --depth 1 https://github.com/minetest/minetest_game.git
$ cd ..
Download source, without using git:
$ wget https://github.com/minetest/minetest/archive/master.tar.gz
@@ -144,21 +132,19 @@ $ mv minetest_game-master minetest_game
$ cd ..
Build a version that runs directly from the source directory:
$ cmake . -DRUN_IN_PLACE=TRUE
$ make -j <number of processors>
$ cmake . -DRUN_IN_PLACE=1
$ make -j2
Run it:
$ ./bin/minetest
$ 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=FALSE
- You can build a bare server by specifying -DBUILD_SERVER=TRUE
- You can disable the client build by specifying -DBUILD_CLIENT=FALSE
- 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
- If you build a bare server, you don't need to have Irrlicht installed. In that case use -DIRRLICHT_SOURCE_DIR=/the/irrlicht/source
CMake options
-------------
@@ -169,21 +155,16 @@ BUILD_SERVER - Build Minetest server
CMAKE_BUILD_TYPE - Type of build (Release vs. Debug)
Release - Release build
Debug - Debug build
SemiDebug - Partially optimized debug build
RelWithDebInfo - Release build with Debug information
MinSizeRel - Release build with -Os passed to compiler to make executable as small as possible
ENABLE_CURL - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
ENABLE_CURSES - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_FREETYPE - Build with FreeType2; Allows using TTF fonts
ENABLE_FREETYPE - Build with Freetype2; Allows using TTF fonts
ENABLE_GETTEXT - Build with Gettext; Allows using translations
ENABLE_GLES - Search for Open GLES headers & libraries and use them
ENABLE_LEVELDB - Build with LevelDB; Enables use of LevelDB map backend
ENABLE_POSTGRESQL - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater required)
ENABLE_REDIS - Build with libhiredis; Enables use of Redis map backend
ENABLE_SPATIAL - Build with LibSpatial; Speeds up AreaStores
ENABLE_LEVELDB - Build with LevelDB; Enables use of LevelDB, which is much faster than SQLite, as map backend
ENABLE_REDIS - Build with libhiredis; Enables use of redis map backend
ENABLE_SOUND - Build with OpenAL, libogg & libvorbis; in-game Sounds
ENABLE_LUAJIT - Build with LuaJIT (much faster than non-JIT Lua)
ENABLE_SYSTEM_GMP - Use GMP from system (much faster than bundled mini-gmp)
DISABLE_LUAJIT - Do not search for LuaJIT headers & library
RUN_IN_PLACE - Create a portable install (worlds, settings etc. in current directory)
USE_GPROF - Enable profiling using GProf
VERSION_EXTRA - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar)
@@ -196,7 +177,7 @@ CURL_DLL - Only if building with cURL on Windows; path to
CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located
CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib
EGL_INCLUDE_DIR - Only if building with GLES; directory that contains egl.h
EGL_LIBRARY - Only if building with GLES; path to libEGL.a/libEGL.so
EGL_egl_LIBRARY - Only if building with GLES; path to libEGL.a/libEGL.so
FREETYPE_INCLUDE_DIR_freetype2 - Only if building with Freetype2; directory that contains an freetype directory with files such as ftimage.h in it
FREETYPE_INCLUDE_DIR_ft2build - Only if building with Freetype2; directory that contains ft2build.h
FREETYPE_LIBRARY - Only if building with Freetype2; path to libfreetype.a/libfreetype.so/freetype.lib
@@ -206,18 +187,14 @@ GETTEXT_ICONV_DLL - Only when building with Gettext on Windows; pa
GETTEXT_INCLUDE_DIR - Only when building with Gettext; directory that contains iconv.h
GETTEXT_LIBRARY - Only when building with Gettext on Windows; path to libintl.dll.a
GETTEXT_MSGFMT - Only when building with Gettext; path to msgfmt/msgfmt.exe
IRRLICHT_DLL - Only on Windows; path to Irrlicht.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h
IRRLICHT_LIBRARY - Path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a/Irrlicht.lib
IRRLICHT_DLL - path to Irrlicht.dll
IRRLICHT_INCLUDE_DIR - directory that contains IrrCompileConfig.h
IRRLICHT_LIBRARY - path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll
POSTGRESQL_INCLUDE_DIR - Only when building with PostgreSQL; directory that contains libpq-fe.h
POSTGRESQL_LIBRARY - Only when building with PostgreSQL; path to libpq.a/libpq.so
REDIS_INCLUDE_DIR - Only when building with Redis; directory that contains hiredis.h
REDIS_LIBRARY - Only when building with Redis; path to libhiredis.a/libhiredis.so
SPATIAL_INCLUDE_DIR - Only when building with LibSpatial; directory that contains spatialindex/SpatialIndex.h
SPATIAL_LIBRARY - Only when building with LibSpatial; path to libspatialindex_c.so/spatialindex-32.lib
REDIS_INCLUDE_DIR - Only when building with redis support; directory that contains hiredis.h
REDIS_LIBRARY - Only when building with redis support; path to libhiredis.a/libhiredis.so
LUA_INCLUDE_DIR - Only if you want to use LuaJIT; directory where luajit.h is located
LUA_LIBRARY - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so
MINGWM10_DLL - Only if compiling with MinGW; path to mingwm10.dll
@@ -228,9 +205,9 @@ OPENAL_DLL - Only if building with sound on Windows; path t
OPENAL_INCLUDE_DIR - Only if building with sound; directory where al.h is located
OPENAL_LIBRARY - Only if building with sound; path to libopenal.a/libopenal.so/OpenAL32.lib
OPENGLES2_INCLUDE_DIR - Only if building with GLES; directory that contains gl2.h
OPENGLES2_LIBRARY - Only if building with GLES; path to libGLESv2.a/libGLESv2.so
SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h
SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib
OPENGLES2_gl_LIBRARY - Only if building with GLES; path to libGLESv2.a/libGLESv2.so
SQLITE3_INCLUDE_DIR - Only if you want to use SQLite from your OS; directory that contains sqlite3.h
SQLITE3_LIBRARY - Only if you want to use the SQLite from your OS; path to libsqlite3.a/libsqlite3.so
VORBISFILE_DLL - Only if building with sound on Windows; path to libvorbisfile-3.dll
VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a
VORBIS_DLL - Only if building with sound on Windows; path to libvorbis-0.dll
@@ -239,8 +216,8 @@ VORBIS_LIBRARY - Only if building with sound; path to libvorbis
XXF86VM_LIBRARY - Only on Linux; path to libXXf86vm.a/libXXf86vm.so
ZLIB_DLL - Only on Windows; path to zlib1.dll
ZLIBWAPI_DLL - Only on Windows; path to zlibwapi.dll
ZLIB_INCLUDE_DIR - Directory that contains zlib.h
ZLIB_LIBRARY - Path to libz.a/libz.so/zlibwapi.lib
ZLIB_INCLUDE_DIR - directory where zlib.h is located
ZLIB_LIBRARY - path to libz.a/libz.so/zlibwapi.lib
Compiling on Windows:
---------------------
@@ -260,8 +237,6 @@ Compiling on Windows:
http://www.winimage.com/zLibDll/index.html
* Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
http://www.winimage.com/zLibDll/index.html
* SQLite3 headers and library
https://www.sqlite.org/download.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.
@@ -273,10 +248,6 @@ Compiling on Windows:
- 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
NOTE: You need to extract sqlite3.h & sqlite3ext.h from sqlite3 source
and sqlite3.dll & sqlite3.def from sqlite3 precompiled binaries
into "sqlite3" directory, and generate sqlite3.lib using command
"LIB /DEF:sqlite3.def /OUT:sqlite3.lib"
- 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):
@@ -284,9 +255,7 @@ Compiling on Windows:
+ DIR
- zlib-1.2.5.tar.gz
- zlib125dll.zip
- irrlicht-1.8.3.zip
- sqlite-amalgamation-3130000.zip (SQLite3 headers)
- sqlite-dll-win32-x86-3130000.zip (SQLite3 library for 32bit system)
- irrlicht-1.7.1.zip
- 110214175330.zip (or whatever, this is the minetest source)
+ zlib-1.2.5
- zlib.h
@@ -296,15 +265,10 @@ Compiling on Windows:
- readme.txt
+ dll32
...
+ irrlicht-1.8.3
+ irrlicht-1.7.1
+ lib
+ include
...
+ sqlite3
sqlite3.h
sqlite3ext.h
sqlite3.lib
sqlite3.dll
+ gettext (optional)
+bin
+include
@@ -331,7 +295,7 @@ Compiling on Windows:
BUILD_SERVER [ ]
CMAKE_BUILD_TYPE Release
CMAKE_INSTALL_PREFIX DIR/minetest-install
IRRLICHT_SOURCE_DIR DIR/irrlicht-1.8.3
IRRLICHT_SOURCE_DIR DIR/irrlicht-1.7.1
RUN_IN_PLACE [X]
WARN_ALL [ ]
ZLIB_DLL DIR/zlib125dll/dll32/zlibwapi.dll
@@ -342,11 +306,6 @@ Compiling on Windows:
GETTEXT_LIBRARIES DIR/gettext/lib/intl.lib
GETTEXT_MSGFMT DIR/gettext/bin/msgfmt
-----------------
- If CMake complains it couldn't find SQLITE3, choose "Advanced" box on the
right top corner, then specify the location of SQLITE3_INCLUDE_DIR and
SQLITE3_LIBRARY manually.
- If you want to build 64-bit minetest, you will need to build 64-bit version
of irrlicht engine manually, as only 32-bit pre-built library is provided.
- Hit "Configure"
- Hit "Configure" once again 8)
- If something is still coloured red, you have a problem.
@@ -380,7 +339,7 @@ set irrlichtpath="C:\tmp\irrlicht-1.7.2"
set builddir=%sourcedir%\bvc10
mkdir %builddir%
pushd %builddir%
cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DRUN_IN_PLACE=TRUE -DCMAKE_INSTALL_PREFIX=%installpath%
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
@@ -411,16 +370,13 @@ Authors of media files
Everything not listed in here:
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
ShadowNinja:
textures/base/pack/smoke_puff.png
Paramat:
textures/base/pack/menu_header.png
BlockMen:
textures/base/pack/menuheader.png
erlehmann:
misc/minetest-icon-24x24.png
misc/minetest-icon.ico
misc/minetest.svg
misc/minetest-icon.svg
textures/base/pack/logo.png
License of Minetest source code

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.minetest.minetest"
android:versionCode="###ANDROID_VERSION###"
android:versionName="###BASE_VERSION###.###ANDROID_VERSION###"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="9"/>
<uses-feature android:glEsVersion="0x00010000" android:required="true"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
###DEBUG_BUILD###
<application android:icon="@drawable/irr_icon" android:label="Minetest" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" ###DEBUG_FLAG###>
<activity android:name=".MtNativeActivity"
android:label="Minetest"
android:launchMode="singleTask"
android:configChanges="orientation|keyboard|keyboardHidden|navigation"
android:screenOrientation="sensorLandscape"
android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="minetest" />
</activity>
<activity android:name=".MinetestTextEntry"
android:theme="@style/Theme.Transparent"
android:excludeFromRecents="true">
</activity>
<activity android:name=".MinetestAssetCopy"
android:theme="@style/Theme.Transparent"
android:excludeFromRecents="true">
</activity>
</application>
</manifest>

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:1.5.0"
}
}
apply plugin: "com.android.application"
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
versionCode 16
versionName "${System.env.VERSION_STR}.${versionCode}"
minSdkVersion 9
targetSdkVersion 9
applicationId "net.minetest.minetest"
manifestPlaceholders = [ package: "net.minetest.minetest", project: project.name ]
}
lintOptions {
disable "OldTargetApi", "GoogleAppIndexingWarning"
}
Properties props = new Properties()
props.load(new FileInputStream(file("local.properties")))
if (props.getProperty("keystore") != null) {
signingConfigs {
release {
storeFile file(props["keystore"])
storePassword props["keystore.password"]
keyAlias props["key"]
keyPassword props["key.password"]
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
}

16
build/android/build.xml Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="Minetest" default="help">
<property file="local.properties" />
<property file="ant.properties" />
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<loadproperties srcFile="project.properties" />
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<import file="custom_rules.xml" optional="true" />
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@@ -1,15 +1,14 @@
--- irrlicht/source/Irrlicht/Android/CIrrDeviceAndroid.cpp.orig 2015-08-29 15:43:09.000000000 +0300
+++ irrlicht/source/Irrlicht/Android/CIrrDeviceAndroid.cpp 2016-05-13 21:36:22.880388505 +0300
@@ -486,7 +486,7 @@
event.KeyInput.Char = 0;
--- irrlicht/source/Irrlicht/Android/CIrrDeviceAndroid.cpp 2014-06-03 20:56:21.289559503 +0200
+++ irrlicht/source/Irrlicht/Android/CIrrDeviceAndroid.cpp.orig 2014-06-03 20:57:39.281556749 +0200
@@ -423,6 +423,7 @@
}
- device->postEventFromUser(event);
+ status = device->postEventFromUser(event);
device->postEventFromUser(event);
+ status = 1;
}
break;
default:
@@ -543,7 +543,7 @@
@@ -479,7 +480,7 @@
KeyMap[1] = KEY_LBUTTON; // AKEYCODE_SOFT_LEFT
KeyMap[2] = KEY_RBUTTON; // AKEYCODE_SOFT_RIGHT
KeyMap[3] = KEY_HOME; // AKEYCODE_HOME

View File

@@ -24,11 +24,6 @@ LOCAL_MODULE := freetype
LOCAL_SRC_FILES := deps/freetype2-android/Android/obj/local/$(TARGET_ARCH_ABI)/libfreetype2-static.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := iconv
LOCAL_SRC_FILES := deps/libiconv/lib/.libs/libiconv.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := openal
LOCAL_SRC_FILES := deps/openal-soft/libs/$(TARGET_LIBDIR)/libopenal.so
@@ -44,11 +39,6 @@ LOCAL_MODULE := vorbis
LOCAL_SRC_FILES := deps/libvorbis-libogg-android/libs/$(TARGET_LIBDIR)/libvorbis.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := gmp
LOCAL_SRC_FILES := deps/gmp/usr/lib/libgmp.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := deps/openssl/libssl.a
@@ -59,6 +49,7 @@ LOCAL_MODULE := crypto
LOCAL_SRC_FILES := deps/openssl/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := minetest
@@ -69,18 +60,18 @@ GPROF_DEF=-DGPROF
endif
LOCAL_CFLAGS := -D_IRR_ANDROID_PLATFORM_ \
-DHAVE_TOUCHSCREENGUI \
-DUSE_CURL=1 \
-DUSE_SOUND=1 \
-DUSE_FREETYPE=1 \
-DUSE_LEVELDB=$(HAVE_LEVELDB) \
$(GPROF_DEF) \
-pipe -fstrict-aliasing
-DHAVE_TOUCHSCREENGUI \
-DUSE_CURL=1 \
-DUSE_SOUND=1 \
-DUSE_FREETYPE=1 \
-DUSE_LEVELDB=$(HAVE_LEVELDB) \
$(GPROF_DEF) \
-pipe -fstrict-aliasing
ifndef NDEBUG
LOCAL_CFLAGS += -g -D_DEBUG -O0 -fno-omit-frame-pointer
else
LOCAL_CFLAGS += -O3
LOCAL_CFLAGS += -fexpensive-optimizations -O3
endif
ifdef GPROF
@@ -95,24 +86,23 @@ ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_CFLAGS += -fno-stack-protector
endif
LOCAL_C_INCLUDES := \
jni/src \
LOCAL_C_INCLUDES := \
jni/src jni/src/sqlite \
jni/src/script \
jni/src/lua/src \
jni/src/jsoncpp \
jni/src/json \
jni/src/cguittfont \
deps/irrlicht/include \
deps/libiconv/include \
deps/freetype2-android/include \
deps/curl/include \
deps/openal-soft/jni/OpenAL/include \
deps/libvorbis-libogg-android/jni/include \
deps/gmp/usr/include \
deps/leveldb/include \
deps/sqlite/
LOCAL_SRC_FILES := \
LOCAL_SRC_FILES := \
jni/src/ban.cpp \
jni/src/base64.cpp \
jni/src/camera.cpp \
jni/src/cavegen.cpp \
jni/src/chat.cpp \
@@ -123,6 +113,7 @@ LOCAL_SRC_FILES := \
jni/src/clientobject.cpp \
jni/src/clouds.cpp \
jni/src/collision.cpp \
jni/src/connection.cpp \
jni/src/content_abm.cpp \
jni/src/content_cao.cpp \
jni/src/content_cso.cpp \
@@ -154,12 +145,9 @@ LOCAL_SRC_FILES := \
jni/src/guiKeyChangeMenu.cpp \
jni/src/guiPasswordChange.cpp \
jni/src/guiTable.cpp \
jni/src/guiscalingfilter.cpp \
jni/src/guiVolumeChange.cpp \
jni/src/httpfetch.cpp \
jni/src/hud.cpp \
jni/src/imagefilters.cpp \
jni/src/intlGUIEditBox.cpp \
jni/src/inventory.cpp \
jni/src/inventorymanager.cpp \
jni/src/itemdef.cpp \
@@ -169,17 +157,13 @@ LOCAL_SRC_FILES := \
jni/src/log.cpp \
jni/src/main.cpp \
jni/src/map.cpp \
jni/src/map_settings_manager.cpp \
jni/src/mapblock.cpp \
jni/src/mapblock_mesh.cpp \
jni/src/mapgen.cpp \
jni/src/mapgen_flat.cpp \
jni/src/mapgen_fractal.cpp \
jni/src/mapgen_singlenode.cpp \
jni/src/mapgen_v5.cpp \
jni/src/mapgen_v6.cpp \
jni/src/mapgen_v7.cpp \
jni/src/mapgen_valleys.cpp \
jni/src/mapnode.cpp \
jni/src/mapsector.cpp \
jni/src/mesh.cpp \
@@ -187,30 +171,26 @@ LOCAL_SRC_FILES := \
jni/src/mg_decoration.cpp \
jni/src/mg_ore.cpp \
jni/src/mg_schematic.cpp \
jni/src/minimap.cpp \
jni/src/mods.cpp \
jni/src/nameidmapping.cpp \
jni/src/nodedef.cpp \
jni/src/nodemetadata.cpp \
jni/src/nodetimer.cpp \
jni/src/noise.cpp \
jni/src/objdef.cpp \
jni/src/object_properties.cpp \
jni/src/particles.cpp \
jni/src/pathfinder.cpp \
jni/src/player.cpp \
jni/src/porting_android.cpp \
jni/src/porting.cpp \
jni/src/profiler.cpp \
jni/src/quicktune.cpp \
jni/src/reflowscan.cpp \
jni/src/remoteplayer.cpp \
jni/src/rollback.cpp \
jni/src/rollback_interface.cpp \
jni/src/serialization.cpp \
jni/src/server.cpp \
jni/src/serverlist.cpp \
jni/src/serverobject.cpp \
jni/src/sha1.cpp \
jni/src/shader.cpp \
jni/src/sky.cpp \
jni/src/socket.cpp \
@@ -218,71 +198,30 @@ LOCAL_SRC_FILES := \
jni/src/sound_openal.cpp \
jni/src/staticobject.cpp \
jni/src/subgame.cpp \
jni/src/test.cpp \
jni/src/tile.cpp \
jni/src/tool.cpp \
jni/src/treegen.cpp \
jni/src/version.cpp \
jni/src/voxel.cpp \
jni/src/voxelalgorithms.cpp \
jni/src/util/areastore.cpp \
jni/src/util/auth.cpp \
jni/src/util/base64.cpp \
jni/src/util/directiontables.cpp \
jni/src/util/enriched_string.cpp \
jni/src/util/numeric.cpp \
jni/src/util/pointedthing.cpp \
jni/src/util/serialize.cpp \
jni/src/util/sha1.cpp \
jni/src/util/string.cpp \
jni/src/util/srp.cpp \
jni/src/util/timetaker.cpp \
jni/src/unittest/test.cpp \
jni/src/unittest/test_collision.cpp \
jni/src/unittest/test_compression.cpp \
jni/src/unittest/test_connection.cpp \
jni/src/unittest/test_filepath.cpp \
jni/src/unittest/test_inventory.cpp \
jni/src/unittest/test_map_settings_manager.cpp \
jni/src/unittest/test_mapnode.cpp \
jni/src/unittest/test_nodedef.cpp \
jni/src/unittest/test_noderesolver.cpp \
jni/src/unittest/test_noise.cpp \
jni/src/unittest/test_objdef.cpp \
jni/src/unittest/test_profiler.cpp \
jni/src/unittest/test_random.cpp \
jni/src/unittest/test_schematic.cpp \
jni/src/unittest/test_serialization.cpp \
jni/src/unittest/test_settings.cpp \
jni/src/unittest/test_socket.cpp \
jni/src/unittest/test_utilities.cpp \
jni/src/unittest/test_voxelalgorithms.cpp \
jni/src/unittest/test_voxelmanipulator.cpp \
jni/src/touchscreengui.cpp \
jni/src/database-leveldb.cpp \
jni/src/settings.cpp \
jni/src/wieldmesh.cpp \
jni/src/client/clientlauncher.cpp \
jni/src/client/tile.cpp \
jni/src/client/joystick_controller.cpp \
jni/src/irrlicht_changes/static_text.cpp
# intentionally kept out (we already build openssl itself): jni/src/util/sha256.c
# Network
LOCAL_SRC_FILES += \
jni/src/network/connection.cpp \
jni/src/network/networkpacket.cpp \
jni/src/network/clientopcodes.cpp \
jni/src/network/clientpackethandler.cpp \
jni/src/network/serveropcodes.cpp \
jni/src/network/serverpackethandler.cpp \
jni/src/wieldmesh.cpp
# lua api
LOCAL_SRC_FILES += \
LOCAL_SRC_FILES += \
jni/src/script/common/c_content.cpp \
jni/src/script/common/c_converter.cpp \
jni/src/script/common/c_internal.cpp \
jni/src/script/common/c_types.cpp \
jni/src/script/cpp_api/s_async.cpp \
jni/src/script/cpp_api/s_base.cpp \
jni/src/script/cpp_api/s_entity.cpp \
jni/src/script/cpp_api/s_env.cpp \
@@ -292,9 +231,8 @@ LOCAL_SRC_FILES += \
jni/src/script/cpp_api/s_node.cpp \
jni/src/script/cpp_api/s_nodemeta.cpp \
jni/src/script/cpp_api/s_player.cpp \
jni/src/script/cpp_api/s_security.cpp \
jni/src/script/cpp_api/s_server.cpp \
jni/src/script/lua_api/l_areastore.cpp \
jni/src/script/cpp_api/s_async.cpp \
jni/src/script/lua_api/l_base.cpp \
jni/src/script/lua_api/l_craft.cpp \
jni/src/script/lua_api/l_env.cpp \
@@ -310,17 +248,17 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_rollback.cpp \
jni/src/script/lua_api/l_server.cpp \
jni/src/script/lua_api/l_settings.cpp \
jni/src/script/lua_api/l_http.cpp \
jni/src/script/lua_api/l_util.cpp \
jni/src/script/lua_api/l_vmanip.cpp \
jni/src/script/scripting_game.cpp \
jni/src/script/scripting_mainmenu.cpp
#freetype2 support
LOCAL_SRC_FILES += jni/src/cguittfont/xCGUITTFont.cpp
LOCAL_SRC_FILES += \
jni/src/cguittfont/xCGUITTFont.cpp
# Lua
LOCAL_SRC_FILES += \
# lua
LOCAL_SRC_FILES += \
jni/src/lua/src/lapi.c \
jni/src/lua/src/lauxlib.c \
jni/src/lua/src/lbaselib.c \
@@ -352,20 +290,20 @@ LOCAL_SRC_FILES += \
jni/src/lua/src/lzio.c \
jni/src/lua/src/print.c
# SQLite3
# sqlite
LOCAL_SRC_FILES += deps/sqlite/sqlite3.c
# Threading
LOCAL_SRC_FILES += \
jni/src/threading/event.cpp \
jni/src/threading/mutex.cpp \
jni/src/threading/semaphore.cpp \
jni/src/threading/thread.cpp
# jthread
LOCAL_SRC_FILES += \
jni/src/jthread/pthread/jevent.cpp \
jni/src/jthread/pthread/jmutex.cpp \
jni/src/jthread/pthread/jsemaphore.cpp \
jni/src/jthread/pthread/jthread.cpp
# JSONCPP
LOCAL_SRC_FILES += jni/src/jsoncpp/json/jsoncpp.cpp
# json
LOCAL_SRC_FILES += jni/src/json/jsoncpp.cpp
LOCAL_SHARED_LIBRARIES := iconv openal ogg vorbis gmp
LOCAL_SHARED_LIBRARIES := openal ogg vorbis
LOCAL_STATIC_LIBRARIES := Irrlicht freetype curl ssl crypto android_native_app_glue $(PROFILER_LIBS)
ifeq ($(HAVE_LEVELDB), 1)
@@ -380,4 +318,3 @@ ifdef GPROF
$(call import-module,android-ndk-profiler)
endif
$(call import-module,android/native_app_glue)

View File

@@ -1,4 +1,4 @@
# NDK_TOOLCHAIN_VERSION := clang3.8
# NDK_TOOLCHAIN_VERSION := clang3.3
APP_PLATFORM := android-9
APP_MODULES := minetest
@@ -6,4 +6,3 @@ APP_STL := gnustl_static
APP_CPPFLAGS += -fexceptions
APP_GNUSTL_FORCE_CPP_FEATURES := rtti

View File

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

View File

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

View File

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

View File

@@ -1,17 +0,0 @@
--- sqlite3.c 2016-11-29 02:29:24.000000000 +0000
+++ sqlite3.c 2016-12-08 22:54:54.206465377 +0000
@@ -30445,7 +30445,14 @@
#if OS_VXWORKS
struct vxworksFileId *pId; /* Unique file ID for vxworks. */
#else
- ino_t ino; /* Inode number */
+ #ifdef ANDROID
+ // Bionic's struct stat has a 64 bit st_ino on both 32 and
+ // 64 bit architectures. ino_t remains 32 bits wide on 32 bit
+ // architectures and can lead to inode truncation.
+ unsigned long long ino; /* Inode number */
+ #else
+ ino_t ino; /* Inode number */
+ #endif
#endif
};

View File

@@ -0,0 +1 @@
target=android-10

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

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

View File

@@ -1,2 +0,0 @@
rootProject.name = "Minetest"

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
</manifest>

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.minetest.minetest"
android:installLocation="auto">
<uses-feature android:glEsVersion="0x00010000" android:required="true"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:icon="@drawable/irr_icon"
android:label="${project}"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:allowBackup="true">
<activity android:name=".MtNativeActivity"
android:label="${project}"
android:launchMode="singleTask"
android:configChanges="orientation|keyboard|keyboardHidden|navigation"
android:screenOrientation="sensorLandscape"
android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="minetest" />
</activity>
<activity android:name=".MinetestTextEntry"
android:theme="@style/Theme.Transparent"
android:excludeFromRecents="true">
</activity>
<activity android:name=".MinetestAssetCopy"
android:theme="@style/Theme.Transparent"
android:excludeFromRecents="true">
</activity>
</application>
</manifest>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="preparing_media">Preparing media...</string>
</resources>

View File

@@ -1,4 +1,4 @@
package net.minetest.minetest;
package org.minetest.minetest;
import java.io.BufferedReader;
import java.io.File;
@@ -254,14 +254,54 @@ public class MinetestAssetCopy extends Activity
boolean shortened = false;
String todisplay = m_tocopy.get(progress[0]);
m_ProgressBar.setProgress(progress[0]);
m_Filename.setText(todisplay);
// make sure our text doesn't exceed our layout width
Rect bounds = new Rect();
Paint textPaint = m_Filename.getPaint();
textPaint.getTextBounds(todisplay, 0, todisplay.length(), bounds);
while (bounds.width() > getResources().getDisplayMetrics().widthPixels * 0.7) {
if (todisplay.length() < 2) {
break;
}
todisplay = todisplay.substring(1);
textPaint.getTextBounds(todisplay, 0, todisplay.length(), bounds);
shortened = true;
}
if (! shortened) {
m_Filename.setText(todisplay);
}
else {
m_Filename.setText(".." + todisplay);
}
}
else
{
boolean shortened = false;
String todisplay = m_Foldername;
String full_text = "scanning " + todisplay + " ...";
m_Filename.setText(full_text);
// make sure our text doesn't exceed our layout width
Rect bounds = new Rect();
Paint textPaint = m_Filename.getPaint();
textPaint.getTextBounds(full_text, 0, full_text.length(), bounds);
while (bounds.width() > getResources().getDisplayMetrics().widthPixels * 0.7) {
if (todisplay.length() < 2) {
break;
}
todisplay = todisplay.substring(1);
full_text = "scanning " + todisplay + " ...";
textPaint.getTextBounds(full_text, 0, full_text.length(), bounds);
shortened = true;
}
if (! shortened) {
m_Filename.setText(full_text);
}
else {
m_Filename.setText("scanning .." + todisplay + " ...");
}
}
}

View File

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

View File

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

View File

@@ -189,7 +189,7 @@ function filterlist.process(self)
for k,v in pairs(self.m_raw_list) do
if self.m_filtercriteria == nil or
self.m_filter_fct(v,self.m_filtercriteria) then
self.m_processed_list[#self.m_processed_list + 1] = v
table.insert(self.m_processed_list,v)
end
end

View File

@@ -1,9 +1,5 @@
-- Minetest: builtin/misc_helpers.lua
--------------------------------------------------------------------------------
-- Localize functions to avoid table lookups (better performance).
local string_sub, string_find = string.sub, string.find
--------------------------------------------------------------------------------
function basic_dump(o)
local tp = type(o)
@@ -93,13 +89,13 @@ function dump2(o, name, dumped)
-- the form _G["table: 0xFFFFFFF"]
keyStr = string.format("_G[%q]", tostring(k))
-- Dump key table
t[#t + 1] = dump2(k, keyStr, dumped)
table.insert(t, dump2(k, keyStr, dumped))
end
else
keyStr = basic_dump(k)
end
local vname = string.format("%s[%s]", name, keyStr)
t[#t + 1] = dump2(v, vname, dumped)
table.insert(t, dump2(v, vname, dumped))
end
return string.format("%s = {}\n%s", name, table.concat(t))
end
@@ -134,7 +130,7 @@ function dump(o, indent, nested, level)
local t = {}
local dumped_indexes = {}
for i, v in ipairs(o) do
t[#t + 1] = dump(v, indent, nested, level + 1)
table.insert(t, dump(v, indent, nested, level + 1))
dumped_indexes[i] = true
end
for k, v in pairs(o) do
@@ -143,7 +139,7 @@ function dump(o, indent, nested, level)
k = "["..dump(k, indent, nested, level + 1).."]"
end
v = dump(v, indent, nested, level + 1)
t[#t + 1] = k.." = "..v
table.insert(t, k.." = "..v)
end
end
nested[o] = nil
@@ -159,6 +155,9 @@ function dump(o, indent, nested, level)
end
--------------------------------------------------------------------------------
-- Localize functions to avoid table lookups (better performance).
local table_insert = table.insert
local str_sub, str_find = string.sub, string.find
function string.split(str, delim, include_empty, max_splits, sep_is_pattern)
delim = delim or ","
max_splits = max_splits or -1
@@ -167,39 +166,26 @@ function string.split(str, delim, include_empty, max_splits, sep_is_pattern)
local plain = not sep_is_pattern
max_splits = max_splits + 1
repeat
local np, npe = string_find(str, delim, pos, plain)
local np, npe = str_find(str, delim, pos, plain)
np, npe = (np or (len+1)), (npe or (len+1))
if (not np) or (max_splits == 1) then
np = len + 1
npe = np
end
local s = string_sub(str, pos, np - 1)
local s = str_sub(str, pos, np - 1)
if include_empty or (s ~= "") then
max_splits = max_splits - 1
items[#items + 1] = s
table_insert(items, s)
end
pos = npe + 1
until (max_splits == 0) or (pos > (len + 1))
return items
end
--------------------------------------------------------------------------------
function table.indexof(list, val)
for i, v in ipairs(list) do
if v == val then
return i
end
end
return -1
end
assert(table.indexof({"foo", "bar"}, "foo") == 1)
assert(table.indexof({"foo", "bar"}, "baz") == -1)
--------------------------------------------------------------------------------
function file_exists(filename)
local f = io.open(filename, "r")
if f == nil then
if f==nil then
return false
else
f:close()
@@ -312,8 +298,8 @@ function core.splittext(text,charlimit)
local current_idx = 1
local start,stop = string_find(text, " ", current_idx)
local nl_start,nl_stop = string_find(text, "\n", current_idx)
local start,stop = string.find(text," ",current_idx)
local nl_start,nl_stop = string.find(text,"\n",current_idx)
local gotnewline = false
if nl_start ~= nil and (start == nil or nl_start < start) then
start = nl_start
@@ -323,7 +309,7 @@ function core.splittext(text,charlimit)
local last_line = ""
while start ~= nil do
if string.len(last_line) + (stop-start) > charlimit then
retval[#retval + 1] = last_line
table.insert(retval,last_line)
last_line = ""
end
@@ -331,17 +317,17 @@ function core.splittext(text,charlimit)
last_line = last_line .. " "
end
last_line = last_line .. string_sub(text, current_idx, stop - 1)
last_line = last_line .. string.sub(text,current_idx,stop -1)
if gotnewline then
retval[#retval + 1] = last_line
table.insert(retval,last_line)
last_line = ""
gotnewline = false
end
current_idx = stop+1
start,stop = string_find(text, " ", current_idx)
nl_start,nl_stop = string_find(text, "\n", current_idx)
start,stop = string.find(text," ",current_idx)
nl_start,nl_stop = string.find(text,"\n",current_idx)
if nl_start ~= nil and (start == nil or nl_start < start) then
start = nl_start
@@ -352,11 +338,11 @@ function core.splittext(text,charlimit)
--add last part of text
if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
retval[#retval + 1] = last_line
retval[#retval + 1] = string_sub(text, current_idx)
table.insert(retval,last_line)
table.insert(retval,string.sub(text,current_idx))
else
last_line = last_line .. " " .. string_sub(text, current_idx)
retval[#retval + 1] = last_line
last_line = last_line .. " " .. string.sub(text,current_idx)
table.insert(retval,last_line)
end
return retval
@@ -382,6 +368,7 @@ if INIT == "game" then
itemstack, pointed_thing)
return
end
local pitch = placer:get_look_pitch()
local fdir = core.dir_to_facedir(placer:get_look_dir())
local wield_name = itemstack:get_name()
@@ -428,14 +415,14 @@ if INIT == "game" then
if iswall then
core.set_node(pos, {name = wield_name,
param2 = dirs1[fdir + 1]})
param2 = dirs1[fdir+1]})
elseif isceiling then
if orient_flags.force_facedir then
core.set_node(pos, {name = wield_name,
param2 = 20})
else
core.set_node(pos, {name = wield_name,
param2 = dirs2[fdir + 1]})
param2 = dirs2[fdir+1]})
end
else -- place right side up
if orient_flags.force_facedir then
@@ -552,36 +539,6 @@ assert(core.string_to_pos("10.0, 5, -2").x == 10)
assert(core.string_to_pos("( 10.0, 5, -2)").z == -2)
assert(core.string_to_pos("asd, 5, -2)") == nil)
--------------------------------------------------------------------------------
function core.string_to_area(value)
local p1, p2 = unpack(value:split(") ("))
if p1 == nil or p2 == nil then
return nil
end
p1 = core.string_to_pos(p1 .. ")")
p2 = core.string_to_pos("(" .. p2)
if p1 == nil or p2 == nil then
return nil
end
return p1, p2
end
local function test_string_to_area()
local p1, p2 = core.string_to_area("(10.0, 5, -2) ( 30.2, 4, -12.53)")
assert(p1.x == 10.0 and p1.y == 5 and p1.z == -2)
assert(p2.x == 30.2 and p2.y == 4 and p2.z == -12.53)
p1, p2 = core.string_to_area("(10.0, 5, -2 30.2, 4, -12.53")
assert(p1 == nil and p2 == nil)
p1, p2 = core.string_to_area("(10.0, 5,) -2 fgdf2, 4, -12.53")
assert(p1 == nil and p2 == nil)
end
test_string_to_area()
--------------------------------------------------------------------------------
function table.copy(t, seen)
local n = {}

View File

@@ -104,7 +104,7 @@ function core.serialize(x)
local i = local_index
local_index = local_index + 1
var = "_["..i.."]"
local_defs[#local_defs + 1] = var.." = "..val
table.insert(local_defs, var.." = "..val)
dumped[x] = var
return var
end
@@ -115,35 +115,27 @@ function core.serialize(x)
function dump_val(x)
local tp = type(x)
if x == nil then return "nil"
elseif tp == "number" then return string.format("%d", x)
elseif tp == "string" then return string.format("%q", x)
elseif tp == "boolean" then return x and "true" or "false"
elseif tp == "function" then
return string.format("loadstring(%q)", string.dump(x))
elseif tp == "number" then
-- Serialize integers with string.format to prevent
-- scientific notation, which doesn't preserve
-- precision and breaks things like node position
-- hashes. Serialize floats normally.
if math.floor(x) == x then
return string.format("%d", x)
else
return tostring(x)
end
elseif tp == "table" then
local vals = {}
local idx_dumped = {}
local np = nest_points[x]
for i, v in ipairs(x) do
if not np or not np[i] then
vals[#vals + 1] = dump_or_ref_val(v)
table.insert(vals, dump_or_ref_val(v))
end
idx_dumped[i] = true
end
for k, v in pairs(x) do
if (not np or not np[k]) and
not idx_dumped[k] then
vals[#vals + 1] = "["..dump_or_ref_val(k).."] = "
..dump_or_ref_val(v)
table.insert(vals,
"["..dump_or_ref_val(k).."] = "
..dump_or_ref_val(v))
end
end
return "{"..table.concat(vals, ", ").."}"
@@ -155,9 +147,9 @@ function core.serialize(x)
local function dump_nest_points()
for parent, vals in pairs(nest_points) do
for k, v in pairs(vals) do
local_defs[#local_defs + 1] = dump_or_ref_val(parent)
table.insert(local_defs, dump_or_ref_val(parent)
.."["..dump_or_ref_val(k).."] = "
..dump_or_ref_val(v)
..dump_or_ref_val(v))
end
end
end

View File

@@ -4,11 +4,8 @@
local WARN_INIT = false
function core.global_exists(name)
if type(name) ~= "string" then
error("core.global_exists: " .. tostring(name) .. " is not a string")
end
return rawget(_G, name) ~= nil
local function warn(message)
print(os.date("%H:%M:%S: WARNING: ")..message)
end
@@ -25,7 +22,7 @@ function meta:__newindex(name, value)
info.currentline, name)
if not warned[warn_key] and info.what ~= "main" and
info.what ~= "C" then
core.log("warning", ("Assignment to undeclared "..
warn(("Assignment to undeclared "..
"global %q inside a function at %s.")
:format(name, desc))
warned[warn_key] = true
@@ -33,8 +30,9 @@ function meta:__newindex(name, value)
declared[name] = true
end
-- Ignore mod namespaces
if WARN_INIT and name ~= core.get_current_modname() then
core.log("warning", ("Global variable %q created at %s.")
if WARN_INIT and (not core.get_current_modname or
name ~= core.get_current_modname()) then
warn(("Global variable %q created at %s.")
:format(name, desc))
end
rawset(self, name, value)
@@ -45,7 +43,7 @@ function meta:__index(name)
local info = debug.getinfo(2, "Sl")
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
if not declared[name] and not warned[warn_key] and info.what ~= "C" then
core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
warn(("Undeclared global variable %q accessed at %s:%s")
:format(name, info.short_src, info.currentline))
warned[warn_key] = true
end

View File

@@ -31,14 +31,6 @@ function vector.normalize(v)
end
end
function vector.floor(v)
return {
x = math.floor(v.x),
y = math.floor(v.y),
z = math.floor(v.z)
}
end
function vector.round(v)
return {
x = math.floor(v.x + 0.5),
@@ -138,3 +130,4 @@ function vector.divide(a, b)
z = a.z / b}
end
end

View File

@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--This program is free software; you can redistribute it and/or modify
--self 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,
--self 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.,
--with self program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -24,11 +24,11 @@ local function buttonbar_formspec(self)
local formspec = string.format("box[%f,%f;%f,%f;%s]",
self.pos.x,self.pos.y ,self.size.x,self.size.y,self.bgcolor)
for i=self.startbutton,#self.buttons,1 do
local btn_name = self.buttons[i].name
local btn_pos = {}
if self.orientation == "horizontal" then
btn_pos.x = self.pos.x + --base pos
(i - self.startbutton) * self.btn_size + --button offset
@@ -36,7 +36,7 @@ local function buttonbar_formspec(self)
else
btn_pos.x = self.pos.x + (self.btn_size * 0.05)
end
if self.orientation == "vertical" then
btn_pos.y = self.pos.y + --base pos
(i - self.startbutton) * self.btn_size + --button offset
@@ -44,18 +44,18 @@ local function buttonbar_formspec(self)
else
btn_pos.y = self.pos.y + (self.btn_size * 0.05)
end
if (self.orientation == "vertical" and
(btn_pos.y + self.btn_size <= self.pos.y + self.size.y)) or
(self.orientation == "horizontal" and
(btn_pos.x + self.btn_size <= self.pos.x + self.size.x)) then
local borders="true"
if self.buttons[i].image ~= nil then
borders="false"
end
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;%s]tooltip[%s;%s]",
btn_pos.x, btn_pos.y, self.btn_size, self.btn_size,
@@ -75,7 +75,7 @@ local function buttonbar_formspec(self)
btn_dec_pos.y = self.pos.y + (self.btn_size * 0.05)
local btn_inc_pos = {}
local btn_size = {}
if self.orientation == "horizontal" then
btn_size.x = 0.5
btn_size.y = self.btn_size
@@ -87,25 +87,25 @@ local function buttonbar_formspec(self)
btn_inc_pos.x = self.pos.x + (self.btn_size * 0.05)
btn_inc_pos.y = self.pos.y + self.size.y - 0.5
end
local text_dec = "<"
local text_inc = ">"
if self.orientation == "vertical" then
text_dec = "^"
text_inc = "v"
end
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_dec_%s;%s;true;true]",
btn_dec_pos.x, btn_dec_pos.y, btn_size.x, btn_size.y,
self.name, text_dec)
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_inc_%s;%s;true;true]",
btn_inc_pos.x, btn_inc_pos.y, btn_size.x, btn_size.y,
self.name, text_inc)
end
return formspec
end
@@ -113,16 +113,16 @@ local function buttonbar_buttonhandler(self, fields)
if fields["btnbar_inc_" .. self.name] ~= nil and
self.startbutton < #self.buttons then
self.startbutton = self.startbutton + 1
return true
end
if fields["btnbar_dec_" .. self.name] ~= nil and self.startbutton > 1 then
self.startbutton = self.startbutton - 1
return true
end
for i=1,#self.buttons,1 do
if fields[self.buttons[i].name] ~= nil then
return self.userbuttonhandler(fields)
@@ -134,40 +134,35 @@ local buttonbar_metatable = {
handle_buttons = buttonbar_buttonhandler,
handle_events = function(self, event) end,
get_formspec = buttonbar_formspec,
hide = function(self) self.hidden = true end,
show = function(self) self.hidden = false end,
delete = function(self) ui.delete(self) end,
add_button = function(self, name, caption, image, tooltip)
if caption == nil then caption = "" end
if image == nil then image = "" end
if tooltip == nil then tooltip = "" end
self.buttons[#self.buttons + 1] = {
name = name,
caption = caption,
image = image,
tooltip = tooltip
}
table.insert(self.buttons,{ name=name, caption=caption, image=image, tooltip=tooltip})
if self.orientation == "horizontal" then
if ( (self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.x ) then
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
else
if ((self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.y ) then
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
end
end,
set_bgparams = function(self, bgcolor)
if (type(bgcolor) == "string") then
self.bgcolor = bgcolor
@@ -194,20 +189,20 @@ function buttonbar_create(name, cbf_buttonhandler, pos, orientation, size)
self.startbutton = 1
self.have_move_buttons = false
self.hidden = false
if self.orientation == "horizontal" then
self.btn_size = self.size.y
else
self.btn_size = self.size.x
end
if (self.btn_initial_offset == nil) then
self.btn_initial_offset = self.btn_size * 0.05
end
self.userbuttonhandler = cbf_buttonhandler
self.buttons = {}
setmetatable(self,buttonbar_metatable)
ui.add(self)

View File

@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--This program is free software; you can redistribute it and/or modify
--self 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,
--self 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.,
--with self program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local function dialog_event_handler(self,event)
@@ -61,7 +61,7 @@ function dialog_create(name,get_formspec,buttonhandler,eventhandler)
self.formspec = get_formspec
self.buttonhandler = buttonhandler
self.user_eventhandler = eventhandler
setmetatable(self,dialog_metatable)
ui.add(self)

View File

@@ -1,18 +1,18 @@
--Minetest
--Copyright (C) 2014 sapier
--
--This program is free software; you can redistribute it and/or modify
--self 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,
--self 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.,
--with self program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -46,7 +46,7 @@ local function add_tab(self,tab)
tabdata = {},
}
self.tablist[#self.tablist + 1] = newtab
table.insert(self.tablist,newtab)
if self.last_tab_index == #self.tablist then
self.current_tab = tab.name
@@ -61,7 +61,7 @@ local function get_formspec(self)
local formspec = ""
if not self.hidden and (self.parent == nil or not self.parent.hidden) then
if self.parent == nil then
local tsize = self.tablist[self.last_tab_index].tabsize or
{width=self.width, height=self.height}
@@ -87,11 +87,11 @@ local function handle_buttons(self,fields)
if self.hidden then
return false
end
if self:handle_tab_buttons(fields) then
return true
end
if self.glb_btn_handler ~= nil and
self.glb_btn_handler(self,fields) then
return true
@@ -112,16 +112,16 @@ end
--------------------------------------------------------------------------------
local function handle_events(self,event)
if self.hidden then
return false
end
if self.glb_evt_handler ~= nil and
self.glb_evt_handler(self,event) then
return true
end
if self.tablist[self.last_tab_index].evt_handler ~= nil then
return
self.tablist[self.last_tab_index].evt_handler(
@@ -131,7 +131,7 @@ local function handle_events(self,event)
self.tablist[self.last_tab_index].tabdata
)
end
return false
end
@@ -160,16 +160,16 @@ local function switch_to_tab(self, index)
self.tablist[self.last_tab_index].on_change("LEAVE",
self.current_tab, self.tablist[index].name)
end
--update tabview data
self.last_tab_index = index
local old_tab = self.current_tab
self.current_tab = self.tablist[index].name
if (self.autosave_tab) then
core.setting_set(self.name .. "_LAST",self.current_tab)
end
-- call for tab to enter
if self.tablist[index].on_change ~= nil then
self.tablist[index].on_change("ENTER",
@@ -197,14 +197,14 @@ local function set_tab_by_name(self, name)
return true
end
end
return false
end
--------------------------------------------------------------------------------
local function hide_tabview(self)
self.hidden=true
--call on_change as we're not gonna show self tab any longer
if self.tablist[self.last_tab_index].on_change ~= nil then
self.tablist[self.last_tab_index].on_change("LEAVE",
@@ -215,7 +215,7 @@ end
--------------------------------------------------------------------------------
local function show_tabview(self)
self.hidden=false
-- call for tab to enter
if self.tablist[self.last_tab_index].on_change ~= nil then
self.tablist[self.last_tab_index].on_change("ENTER",
@@ -265,7 +265,7 @@ function tabview_create(name, size, tabheaderpos)
self.current_tab = nil
self.last_tab_index = 1
self.tablist = {}
self.autosave_tab = false
ui.add(self)

View File

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

View File

@@ -20,7 +20,7 @@ function core.privs_to_string(privs, delim)
local list = {}
for priv, bool in pairs(privs) do
if bool then
list[#list + 1] = priv
table.insert(list, priv)
end
end
return table.concat(list, delim)
@@ -171,7 +171,6 @@ function core.register_authentication_handler(handler)
end
core.registered_auth_handler = handler
core.registered_auth_handler_modname = core.get_current_modname()
handler.mod_origin = core.registered_auth_handler_modname
end
function core.get_auth_handler()
@@ -199,19 +198,3 @@ core.register_on_joinplayer(function(player)
record_login(player:get_player_name())
end)
core.register_on_prejoinplayer(function(name, ip)
local auth = core.auth_table
if auth[name] ~= nil then
return
end
local name_lower = name:lower()
for k in pairs(auth) do
if k:lower() == name_lower then
return string.format("\nCannot create new player called '%s'. "..
"Another account called '%s' is already registered. "..
"Please check the spelling if it's your account "..
"or use a different nickname.", name, k)
end
end
end)

View File

@@ -10,10 +10,22 @@ function core.register_chatcommand(cmd, def)
def.params = def.params or ""
def.description = def.description or ""
def.privs = def.privs or {}
def.mod_origin = core.get_current_modname() or "??"
core.chatcommands[cmd] = def
end
if core.setting_getbool("mod_profiling") then
local tracefct = profiling_print_log
profiling_print_log = nil
core.register_chatcommand("save_mod_profile",
{
params = "",
description = "save mod profiling data to logfile " ..
"(depends on default loglevel)",
func = tracefct,
privs = { server=true }
})
end
core.register_on_chat_message(function(name, message)
local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
if not param then
@@ -25,7 +37,6 @@ core.register_on_chat_message(function(name, message)
end
local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
if has_privs then
core.set_last_run_mod(cmd_def.mod_origin)
local success, message = cmd_def.func(name, param)
if message then
core.chat_send_player(name, message)
@@ -38,33 +49,6 @@ core.register_on_chat_message(function(name, message)
return true -- Handled chat message
end)
if core.setting_getbool("profiler.load") then
-- Run after register_chatcommand and its register_on_chat_message
-- Before any chattcommands that should be profiled
profiler.init_chatcommand()
end
-- Parses a "range" string in the format of "here (number)" or
-- "(x1, y1, z1) (x2, y2, z2)", returning two position vectors
local function parse_range_str(player_name, str)
local p1, p2
local args = str:split(" ")
if args[1] == "here" then
p1, p2 = core.get_player_radius_area(player_name, tonumber(args[2]))
if p1 == nil then
return false, "Unable to get player " .. player_name .. " position"
end
else
p1, p2 = core.string_to_area(str)
if p1 == nil then
return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
end
end
return p1, p2
end
--
-- Chat commands
--
@@ -77,25 +61,13 @@ core.register_chatcommand("me", {
end,
})
core.register_chatcommand("admin", {
description = "Show the name of the server owner",
func = function(name)
local admin = minetest.setting_get("name")
if admin then
return true, "The administrator of this server is "..admin.."."
else
return false, "There's no administrator named in the config file."
end
end,
})
core.register_chatcommand("help", {
privs = {},
params = "[all/privs/<cmd>]",
description = "Get help for commands or list privileges",
func = function(name, param)
local function format_help_line(cmd, def)
local msg = core.colorize("#00ffff", "/"..cmd)
local msg = "/"..cmd
if def.params and def.params ~= "" then
msg = msg .. " " .. def.params
end
@@ -109,7 +81,7 @@ core.register_chatcommand("help", {
local cmds = {}
for cmd, def in pairs(core.chatcommands) do
if core.check_player_privs(name, def.privs) then
cmds[#cmds + 1] = cmd
table.insert(cmds, cmd)
end
end
table.sort(cmds)
@@ -120,7 +92,7 @@ core.register_chatcommand("help", {
local cmds = {}
for cmd, def in pairs(core.chatcommands) do
if core.check_player_privs(name, def.privs) then
cmds[#cmds + 1] = format_help_line(cmd, def)
table.insert(cmds, format_help_line(cmd, def))
end
end
table.sort(cmds)
@@ -128,7 +100,7 @@ core.register_chatcommand("help", {
elseif param == "privs" then
local privs = {}
for priv, def in pairs(core.registered_privileges) do
privs[#privs + 1] = priv .. ": " .. def.description
table.insert(privs, priv .. ": " .. def.description)
end
table.sort(privs)
return true, "Available privileges:\n"..table.concat(privs, "\n")
@@ -147,79 +119,58 @@ core.register_chatcommand("help", {
core.register_chatcommand("privs", {
params = "<name>",
description = "print out privileges of player",
func = function(caller, param)
param = param:trim()
local name = (param ~= "" and param or caller)
return true, "Privileges of " .. name .. ": "
func = function(name, param)
param = (param ~= "" and param or name)
return true, "Privileges of " .. param .. ": "
.. core.privs_to_string(
core.get_player_privs(name), ' ')
core.get_player_privs(param), ' ')
end,
})
local function handle_grant_command(caller, grantname, grantprivstr)
local caller_privs = minetest.get_player_privs(caller)
if not (caller_privs.privs or caller_privs.basic_privs) then
return false, "Your privileges are insufficient."
end
if not core.auth_table[grantname] then
return false, "Player " .. grantname .. " does not exist."
end
local grantprivs = core.string_to_privs(grantprivstr)
if grantprivstr == "all" then
grantprivs = core.registered_privileges
end
local privs = core.get_player_privs(grantname)
local privs_unknown = ""
local basic_privs =
core.string_to_privs(core.setting_get("basic_privs") or "interact,shout")
for priv, _ in pairs(grantprivs) do
if not basic_privs[priv] and not caller_privs.privs then
return false, "Your privileges are insufficient."
end
if not core.registered_privileges[priv] then
privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
end
privs[priv] = true
end
if privs_unknown ~= "" then
return false, privs_unknown
end
core.set_player_privs(grantname, privs)
core.log("action", caller..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
if grantname ~= caller then
core.chat_send_player(grantname, caller
.. " granted you privileges: "
.. core.privs_to_string(grantprivs, ' '))
end
return true, "Privileges of " .. grantname .. ": "
.. core.privs_to_string(
core.get_player_privs(grantname), ' ')
end
core.register_chatcommand("grant", {
params = "<name> <privilege>|all",
description = "Give privilege to player",
func = function(name, param)
if not core.check_player_privs(name, {privs=true}) and
not core.check_player_privs(name, {basic_privs=true}) then
return false, "Your privileges are insufficient."
end
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
if not grantname or not grantprivstr then
return false, "Invalid parameters (see /help grant)"
end
return handle_grant_command(name, grantname, grantprivstr)
elseif not core.auth_table[grantname] then
return false, "Player " .. grantname .. " does not exist."
end
local grantprivs = core.string_to_privs(grantprivstr)
if grantprivstr == "all" then
grantprivs = core.registered_privileges
end
local privs = core.get_player_privs(grantname)
local privs_unknown = ""
for priv, _ in pairs(grantprivs) do
if priv ~= "interact" and priv ~= "shout" and
not core.check_player_privs(name, {privs=true}) then
return false, "Your privileges are insufficient."
end
if not core.registered_privileges[priv] then
privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
end
privs[priv] = true
end
if privs_unknown ~= "" then
return false, privs_unknown
end
core.set_player_privs(grantname, privs)
core.log("action", name..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
if grantname ~= name then
core.chat_send_player(grantname, name
.. " granted you privileges: "
.. core.privs_to_string(grantprivs, ' '))
end
return true, "Privileges of " .. grantname .. ": "
.. core.privs_to_string(
core.get_player_privs(grantname), ' ')
end,
})
core.register_chatcommand("grantme", {
params = "<privilege>|all",
description = "Grant privileges to yourself",
func = function(name, param)
if param == "" then
return false, "Invalid parameters (see /help grantme)"
end
return handle_grant_command(name, name, param)
end,
})
core.register_chatcommand("revoke", {
params = "<name> <privilege>|all",
description = "Remove privilege from player",
@@ -237,10 +188,8 @@ core.register_chatcommand("revoke", {
end
local revoke_privs = core.string_to_privs(revoke_priv_str)
local privs = core.get_player_privs(revoke_name)
local basic_privs =
core.string_to_privs(core.setting_get("basic_privs") or "interact,shout")
for priv, _ in pairs(revoke_privs) do
if not basic_privs[priv] and
if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and
not core.check_player_privs(name, {privs=true}) then
return false, "Your privileges are insufficient."
end
@@ -280,28 +229,21 @@ core.register_chatcommand("setpassword", {
if not toname then
return false, "Name field required"
end
local act_str_past = "?"
local act_str_pres = "?"
local actstr = "?"
if not raw_password then
core.set_player_password(toname, "")
act_str_past = "cleared"
act_str_pres = "clears"
actstr = "cleared"
else
core.set_player_password(toname,
core.get_password_hash(toname,
raw_password))
act_str_past = "set"
act_str_pres = "sets"
actstr = "set"
end
if toname ~= name then
core.chat_send_player(toname, "Your password was "
.. act_str_past .. " by " .. name)
.. actstr .. " by " .. name)
end
core.log("action", name .. " " .. act_str_pres
.. " password of " .. toname .. ".")
return true, "Password of player \"" .. toname .. "\" " .. act_str_past
return true, "Password of player \"" .. toname .. "\" " .. actstr
end,
})
@@ -315,9 +257,6 @@ core.register_chatcommand("clearpassword", {
return false, "Name field required"
end
core.set_player_password(toname, '')
core.log("action", name .. " clears password of " .. toname .. ".")
return true, "Password of player \"" .. toname .. "\" cleared"
end,
})
@@ -364,18 +303,12 @@ core.register_chatcommand("teleport", {
p.x = tonumber(p.x)
p.y = tonumber(p.y)
p.z = tonumber(p.z)
if p.x and p.y and p.z then
local lm = tonumber(minetest.setting_get("map_generation_limit") or 31000)
if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm or p.z < -lm or p.z > lm then
return false, "Cannot teleport out of map bounds!"
end
teleportee = core.get_player_by_name(name)
if teleportee then
teleportee:setpos(p)
return true, "Teleporting to "..core.pos_to_string(p)
end
teleportee = core.get_player_by_name(name)
if teleportee and p.x and p.y and p.z then
teleportee:setpos(p)
return true, "Teleporting to "..core.pos_to_string(p)
end
local teleportee = nil
local p = nil
local target_name = nil
@@ -412,7 +345,7 @@ core.register_chatcommand("teleport", {
return true, "Teleporting " .. teleportee_name
.. " to " .. core.pos_to_string(p)
end
local teleportee = nil
local p = nil
local teleportee_name = nil
@@ -434,7 +367,7 @@ core.register_chatcommand("teleport", {
.. " to " .. target_name
.. " at " .. core.pos_to_string(p)
end
return false, 'Invalid parameters ("' .. param
.. '") or player not found (see /help teleport)'
end,
@@ -470,65 +403,33 @@ core.register_chatcommand("set", {
end,
})
local function emergeblocks_callback(pos, action, num_calls_remaining, ctx)
if ctx.total_blocks == 0 then
ctx.total_blocks = num_calls_remaining + 1
ctx.current_blocks = 0
end
ctx.current_blocks = ctx.current_blocks + 1
if ctx.current_blocks == ctx.total_blocks then
core.chat_send_player(ctx.requestor_name,
string.format("Finished emerging %d blocks in %.2fms.",
ctx.total_blocks, (os.clock() - ctx.start_time) * 1000))
end
end
local function emergeblocks_progress_update(ctx)
if ctx.current_blocks ~= ctx.total_blocks then
core.chat_send_player(ctx.requestor_name,
string.format("emergeblocks update: %d/%d blocks emerged (%.1f%%)",
ctx.current_blocks, ctx.total_blocks,
(ctx.current_blocks / ctx.total_blocks) * 100))
core.after(2, emergeblocks_progress_update, ctx)
end
end
core.register_chatcommand("emergeblocks", {
params = "(here [radius]) | (<pos1> <pos2>)",
description = "starts loading (or generating, if inexistent) map blocks "
.. "contained in area pos1 to pos2",
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
if p1 == false then
return false, p2
end
local context = {
current_blocks = 0,
total_blocks = 0,
start_time = os.clock(),
requestor_name = name
}
core.emerge_area(p1, p2, emergeblocks_callback, context)
core.after(2, emergeblocks_progress_update, context)
return true, "Started emerge of area ranging from " ..
core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1)
end,
})
core.register_chatcommand("deleteblocks", {
params = "(here [radius]) | (<pos1> <pos2>)",
params = "[here] [<pos1> <pos2>]",
description = "delete map blocks contained in area pos1 to pos2",
privs = {server=true},
func = function(name, param)
local p1, p2 = parse_range_str(name, param)
if p1 == false then
return false, p2
local p1 = {}
local p2 = {}
if param == "here" then
local player = core.get_player_by_name(name)
if player == nil then
core.log("error", "player is nil")
return false, "Unable to get current position; player is nil"
end
p1 = player:getpos()
p2 = p1
else
local pos1, pos2 = unpack(param:split(") ("))
if pos1 == nil or pos2 == nil then
return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
end
p1 = core.string_to_pos(pos1 .. ")")
p2 = core.string_to_pos("(" .. pos2)
if p1 == nil or p2 == nil then
return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
end
end
if core.delete_area(p1, p2) then
@@ -612,29 +513,22 @@ core.register_chatcommand("giveme", {
})
core.register_chatcommand("spawnentity", {
params = "<EntityName> [<X>,<Y>,<Z>]",
description = "Spawn entity at given (or your) position",
params = "<EntityName>",
description = "Spawn entity at your position",
privs = {give=true, interact=true},
func = function(name, param)
local entityname, p = string.match(param, "^([^ ]+) *(.*)$")
local entityname = string.match(param, "(.+)$")
if not entityname then
return false, "EntityName required"
end
core.log("action", ("%s invokes /spawnentity, entityname=%q")
:format(name, entityname))
core.log("action", ("/spawnentity invoked, entityname=%q")
:format(entityname))
local player = core.get_player_by_name(name)
if player == nil then
core.log("error", "Unable to spawn entity, player is nil")
return false, "Unable to spawn entity, player is nil"
end
if p == "" then
p = player:getpos()
else
p = core.string_to_pos(p)
if p == nil then
return false, "Invalid parameters ('" .. param .. "')"
end
end
local p = player:getpos()
p.y = p.y + 1
core.add_entity(p, entityname)
return true, ("%q spawned."):format(entityname)
@@ -768,52 +662,23 @@ core.register_chatcommand("status", {
})
core.register_chatcommand("time", {
params = "<0..23>:<0..59> | <0..24000>",
params = "<0...24000>",
description = "set time of day",
privs = {},
privs = {settime=true},
func = function(name, param)
if param == "" then
local current_time = math.floor(core.get_timeofday() * 1440)
local minutes = current_time % 60
local hour = (current_time - minutes) / 60
return true, ("Current time is %d:%02d"):format(hour, minutes)
return false, "Missing time."
end
local player_privs = core.get_player_privs(name)
if not player_privs.settime then
return false, "You don't have permission to run this command " ..
"(missing privilege: settime)."
local newtime = tonumber(param)
if newtime == nil then
return false, "Invalid time."
end
local hour, minute = param:match("^(%d+):(%d+)$")
if not hour then
local new_time = tonumber(param)
if not new_time then
return false, "Invalid time."
end
-- Backward compatibility.
core.set_timeofday((new_time % 24000) / 24000)
core.log("action", name .. " sets time to " .. new_time)
return true, "Time of day changed."
end
hour = tonumber(hour)
minute = tonumber(minute)
if hour < 0 or hour > 23 then
return false, "Invalid hour (must be between 0 and 23 inclusive)."
elseif minute < 0 or minute > 59 then
return false, "Invalid minute (must be between 0 and 59 inclusive)."
end
core.set_timeofday((hour * 60 + minute) / 1440)
core.log("action", ("%s sets time to %d:%02d"):format(name, hour, minute))
core.set_timeofday((newtime % 24000) / 24000)
core.log("action", name .. " sets time " .. newtime)
return true, "Time of day changed."
end,
})
core.register_chatcommand("days", {
description = "Display day count",
func = function(name, param)
return true, "Current day is " .. core.get_day_count()
end
})
core.register_chatcommand("shutdown", {
description = "shutdown server",
privs = {server=true},
@@ -867,35 +732,20 @@ core.register_chatcommand("kick", {
if not core.kick_player(tokick, reason) then
return false, "Failed to kick player " .. tokick
end
local log_reason = ""
if reason then
log_reason = " with reason \"" .. reason .. "\""
end
core.log("action", name .. " kicks " .. tokick .. log_reason)
core.log("action", name .. " kicked " .. tokick)
return true, "Kicked " .. tokick
end,
})
core.register_chatcommand("clearobjects", {
params = "[full|quick]",
description = "clear all objects in world",
privs = {server=true},
func = function(name, param)
local options = {}
if param == "" or param == "full" then
options.mode = "full"
elseif param == "quick" then
options.mode = "quick"
else
return false, "Invalid usage, see /help clearobjects."
end
core.log("action", name .. " clears all objects ("
.. options.mode .. " mode).")
core.log("action", name .. " clears all objects.")
core.chat_send_all("Clearing all objects. This may take long."
.. " You may experience a timeout. (by "
.. name .. ")")
core.clear_objects(options)
core.clear_objects()
core.log("action", "Object clearing done.")
core.chat_send_all("*** Cleared all objects.")
end,
@@ -938,3 +788,4 @@ core.register_chatcommand("last-login", {
return false, "Last login time is unknown"
end,
})

View File

@@ -1,27 +0,0 @@
-- Minetest: builtin/constants.lua
--
-- Constants values for use with the Lua API
--
-- mapnode.h
-- Built-in Content IDs (for use with VoxelManip API)
core.CONTENT_UNKNOWN = 125
core.CONTENT_AIR = 126
core.CONTENT_IGNORE = 127
-- emerge.h
-- Block emerge status constants (for use with core.emerge_area)
core.EMERGE_CANCELLED = 0
core.EMERGE_ERRORED = 1
core.EMERGE_FROM_MEMORY = 2
core.EMERGE_FROM_DISK = 3
core.EMERGE_GENERATED = 4
-- constants.h
-- Size of mapblocks in nodes
core.MAP_BLOCKSIZE = 16
-- light.h
-- Maximum value for node 'light_source' parameter
core.LIGHT_MAX = 14

View File

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

View File

@@ -2,7 +2,7 @@
core.detached_inventories = {}
function core.create_detached_inventory(name, callbacks, player_name)
function core.create_detached_inventory(name, callbacks)
local stuff = {}
stuff.name = name
if callbacks then
@@ -13,8 +13,7 @@ function core.create_detached_inventory(name, callbacks, player_name)
stuff.on_put = callbacks.on_put
stuff.on_take = callbacks.on_take
end
stuff.mod_origin = core.get_current_modname() or "??"
core.detached_inventories[name] = stuff
return core.create_detached_inventory_raw(name, player_name)
return core.create_detached_inventory_raw(name)
end

View File

@@ -1,68 +1,68 @@
-- Minetest: builtin/item.lua
local builtin_shared = ...
--
-- Falling stuff
--
core.register_entity(":__builtin:falling_node", {
initial_properties = {
visual = "wielditem",
visual_size = {x = 0.667, y = 0.667},
textures = {},
physical = true,
is_visible = false,
collide_with_objects = false,
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
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
self.object:set_properties({
local stack = ItemStack(node.name)
local itemtable = stack:to_table()
local itemname = nil
if itemtable then
itemname = stack:to_table().name
end
local item_texture = nil
local item_type = ""
if core.registered_items[itemname] then
item_texture = core.registered_items[itemname].inventory_image
item_type = core.registered_items[itemname].type
end
local prop = {
is_visible = true,
textures = {node.name},
})
}
self.object:set_properties(prop)
end,
get_staticdata = function(self)
return core.serialize(self.node)
return self.node.name
end,
on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal = 1})
local node = core.deserialize(staticdata)
if node then
self:set_node(node)
elseif staticdata ~= "" then
self:set_node({name = staticdata})
end
self.object:set_armor_groups({immortal=1})
self:set_node({name=staticdata})
end,
on_step = function(self, dtime)
-- Set gravity
local acceleration = self.object:getacceleration()
if not vector.equals(acceleration, {x = 0, y = -10, z = 0}) then
self.object:setacceleration({x = 0, y = -10, z = 0})
end
-- Turn to actual node when colliding with ground, or continue to move
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()
-- Position of bottom center point
local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
-- Avoid bugs caused by an unloaded node below
local bcn = core.get_node_or_nil(bcp)
local bcd = bcn and core.registered_nodes[bcn.name]
if bcn and
(not bcd or bcd.walkable or
local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
local bcn = core.get_node(bcp)
local bcd = core.registered_nodes[bcn.name]
-- Note: walkable is in the node definition, not in item groups
if not bcd or
(bcd.walkable or
(core.get_item_group(self.node.name, "float") ~= 0 and
bcd.liquidtype ~= "none")) then
if bcd and bcd.leveled and
bcn.name == self.node.name then
local addlevel = self.node.level
if not addlevel or addlevel <= 0 then
if addlevel == nil or addlevel <= 0 then
addlevel = bcd.leveled
end
if core.add_node_level(bcp, addlevel) == 0 then
@@ -75,53 +75,51 @@ core.register_entity(":__builtin:falling_node", {
core.remove_node(bcp)
return
end
local np = {x = bcp.x, y = bcp.y + 1, z = bcp.z}
local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
-- Check what's here
local n2 = core.get_node(np)
local nd = core.registered_nodes[n2.name]
-- If it's not air or liquid, remove node and replace it with
-- it's drops
if n2.name ~= "air" and (not nd or nd.liquidtype == "none") then
if n2.name ~= "air" and (not core.registered_nodes[n2.name] or
core.registered_nodes[n2.name].liquidtype == "none") then
core.remove_node(np)
if nd.buildable_to == false then
if core.registered_nodes[n2.name].buildable_to == false then
-- Add dropped items
local drops = core.get_node_drops(n2.name, "")
for _, dropped_item in pairs(drops) do
local _, dropped_item
for _, dropped_item in ipairs(drops) do
core.add_item(np, dropped_item)
end
end
-- Run script hook
for _, callback in pairs(core.registered_on_dignodes) do
callback(np, n2)
local _, callback
for _, callback in ipairs(core.registered_on_dignodes) do
callback(np, n2, nil)
end
end
-- Create node and remove entity
if core.registered_nodes[self.node.name] then
core.add_node(np, self.node)
end
core.add_node(np, self.node)
self.object:remove()
core.check_for_falling(np)
nodeupdate(np)
return
end
local vel = self.object:getvelocity()
if vector.equals(vel, {x = 0, y = 0, z = 0}) then
if vector.equals(vel, {x=0,y=0,z=0}) then
local npos = self.object:getpos()
self.object:setpos(vector.round(npos))
end
end
})
local function spawn_falling_node(p, node)
function spawn_falling_node(p, node)
local obj = core.add_entity(p, "__builtin:falling_node")
if obj then
obj:get_luaentity():set_node(node)
end
obj:get_luaentity():set_node(node)
end
local function drop_attached_node(p)
function drop_attached_node(p)
local nn = core.get_node(p).name
core.remove_node(p)
for _, item in pairs(core.get_node_drops(nn, "")) do
for _,item in ipairs(core.get_node_drops(nn, "")) do
local pos = {
x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25,
@@ -131,19 +129,27 @@ local function drop_attached_node(p)
end
end
function builtin_shared.check_attached_node(p, n)
function check_attached_node(p, n)
local def = core.registered_nodes[n.name]
local d = {x = 0, y = 0, z = 0}
local d = {x=0, y=0, z=0}
if def.paramtype2 == "wallmounted" then
-- The fallback vector here is in case 'wallmounted to dir' is nil due
-- to voxelmanip placing a wallmounted node without resetting a
-- pre-existing param2 value that is out-of-range for wallmounted.
-- The fallback vector corresponds to param2 = 0.
d = core.wallmounted_to_dir(n.param2) or {x = 0, y = 1, z = 0}
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 = vector.add(p, d)
local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z}
local nn = core.get_node(p2).name
local def2 = core.registered_nodes[nn]
if def2 and not def2.walkable then
@@ -156,105 +162,50 @@ end
-- Some common functions
--
function core.check_single_for_falling(p)
function nodeupdate_single(p, delay)
local n = core.get_node(p)
if core.get_item_group(n.name, "falling_node") ~= 0 then
local p_bottom = {x = p.x, y = p.y - 1, z = p.z}
-- Only spawn falling node if node below is loaded
local n_bottom = core.get_node_or_nil(p_bottom)
local d_bottom = n_bottom and core.registered_nodes[n_bottom.name]
if d_bottom and
local p_bottom = {x=p.x, y=p.y-1, z=p.z}
local n_bottom = core.get_node(p_bottom)
-- Note: walkable is in the node definition, not in item groups
if core.registered_nodes[n_bottom.name] and
(core.get_item_group(n.name, "float") == 0 or
d_bottom.liquidtype == "none") and
(n.name ~= n_bottom.name or (d_bottom.leveled and
core.get_node_level(p_bottom) <
core.get_node_max_level(p_bottom))) and
(not d_bottom.walkable or d_bottom.buildable_to) then
n.level = core.get_node_level(p)
core.remove_node(p)
spawn_falling_node(p, n)
return true
core.registered_nodes[n_bottom.name].liquidtype == "none") and
(n.name ~= n_bottom.name or (core.registered_nodes[n_bottom.name].leveled and
core.get_node_level(p_bottom) < core.get_node_max_level(p_bottom))) and
(not core.registered_nodes[n_bottom.name].walkable or
core.registered_nodes[n_bottom.name].buildable_to) then
if delay then
core.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
else
n.level = core.get_node_level(p)
core.remove_node(p)
spawn_falling_node(p, n)
nodeupdate(p)
end
end
end
if core.get_item_group(n.name, "attached_node") ~= 0 then
if not builtin_shared.check_attached_node(p, n) then
if not check_attached_node(p, n) then
drop_attached_node(p)
return true
nodeupdate(p)
end
end
return false
end
-- This table is specifically ordered.
-- We don't walk diagonals, only our direct neighbors, and self.
-- Down first as likely case, but always before self. The same with sides.
-- Up must come last, so that things above self will also fall all at once.
local check_for_falling_neighbors = {
{x = -1, y = -1, z = 0},
{x = 1, y = -1, z = 0},
{x = 0, y = -1, z = -1},
{x = 0, y = -1, z = 1},
{x = 0, y = -1, z = 0},
{x = -1, y = 0, z = 0},
{x = 1, y = 0, z = 0},
{x = 0, y = 0, z = 1},
{x = 0, y = 0, z = -1},
{x = 0, y = 0, z = 0},
{x = 0, y = 1, z = 0},
}
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)
function core.check_for_falling(p)
-- Round p to prevent falling entities to get stuck.
p = vector.round(p)
-- We make a stack, and manually maintain size for performance.
-- Stored in the stack, we will maintain tables with pos, and
-- last neighbor visited. This way, when we get back to each
-- node, we know which directions we have already walked, and
-- which direction is the next to walk.
local s = {}
local n = 0
-- The neighbor order we will visit from our table.
local v = 1
while true do
-- Push current pos onto the stack.
n = n + 1
s[n] = {p = p, v = v}
-- Select next node from neighbor list.
p = vector.add(p, check_for_falling_neighbors[v])
-- Now we check out the node. If it is in need of an update,
-- it will let us know in the return value (true = updated).
if not core.check_single_for_falling(p) then
-- If we don't need to "recurse" (walk) to it then pop
-- our previous pos off the stack and continue from there,
-- with the v value we were at when we last were at that
-- node
repeat
local pop = s[n]
p = pop.p
v = pop.v
s[n] = nil
n = n - 1
-- If there's nothing left on the stack, and no
-- more sides to walk to, we're done and can exit
if n == 0 and v == 11 then
return
end
until v < 11
-- The next round walk the next neighbor in list.
v = v + 1
else
-- If we did need to walk the neighbor, then
-- start walking it from the walk order start (1),
-- and not the order we just pushed up the stack.
v = 1
end
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
@@ -262,33 +213,12 @@ end
-- Global callbacks
--
local function on_placenode(p, node)
core.check_for_falling(p)
function on_placenode(p, node)
nodeupdate(p)
end
core.register_on_placenode(on_placenode)
local function on_dignode(p, node)
core.check_for_falling(p)
function on_dignode(p, node)
nodeupdate(p)
end
core.register_on_dignode(on_dignode)
local function on_punchnode(p, node)
core.check_for_falling(p)
end
core.register_on_punchnode(on_punchnode)
--
-- Globally exported functions
--
-- TODO remove this function after the 0.4.15 release
function nodeupdate(p)
core.log("deprecated", "nodeupdate: deprecated, please use core.check_for_falling instead")
core.check_for_falling(p)
end
-- TODO remove this function after the 0.4.15 release
function nodeupdate_single(p)
core.log("deprecated", "nodeupdate_single: deprecated, please use core.check_single_for_falling instead")
core.check_single_for_falling(p)
end

View File

@@ -8,14 +8,13 @@ core.features = {
use_texture_alpha = true,
no_legacy_abms = true,
texture_names_parens = true,
area_store_custom_ids = true,
}
function core.has_feature(arg)
if type(arg) == "table" then
local missing_features = {}
local result = true
for ftr in pairs(arg) do
missing_features = {}
result = true
for ft, _ in pairs(arg) do
if not core.features[ftr] then
missing_features[ftr] = true
result = false

View File

@@ -5,10 +5,9 @@ core.forceload_block = nil
core.forceload_free_block = nil
local blocks_forceloaded
local blocks_temploaded = {}
local total_forceloaded = 0
local BLOCKSIZE = core.MAP_BLOCKSIZE
local BLOCKSIZE = 16
local function get_blockpos(pos)
return {
x = math.floor(pos.x/BLOCKSIZE),
@@ -16,52 +15,32 @@ local function get_blockpos(pos)
z = math.floor(pos.z/BLOCKSIZE)}
end
-- When we create/free a forceload, it's either transient or persistent. We want
-- to add to/remove from the table that corresponds to the type of forceload, but
-- we also need the other table because whether we forceload a block depends on
-- both tables.
-- This function returns the "primary" table we are adding to/removing from, and
-- the other table.
local function get_relevant_tables(transient)
if transient then
return blocks_temploaded, blocks_forceloaded
else
return blocks_forceloaded, blocks_temploaded
end
end
function core.forceload_block(pos, transient)
function core.forceload_block(pos)
local blockpos = get_blockpos(pos)
local hash = core.hash_node_position(blockpos)
local relevant_table, other_table = get_relevant_tables(transient)
if relevant_table[hash] ~= nil then
relevant_table[hash] = relevant_table[hash] + 1
if blocks_forceloaded[hash] ~= nil then
blocks_forceloaded[hash] = blocks_forceloaded[hash] + 1
return true
elseif other_table[hash] ~= nil then
relevant_table[hash] = 1
else
if total_forceloaded >= (tonumber(core.setting_get("max_forceloaded_blocks")) or 16) then
return false
end
total_forceloaded = total_forceloaded+1
relevant_table[hash] = 1
blocks_forceloaded[hash] = 1
forceload_block(blockpos)
return true
end
end
function core.forceload_free_block(pos, transient)
function core.forceload_free_block(pos)
local blockpos = get_blockpos(pos)
local hash = core.hash_node_position(blockpos)
local relevant_table, other_table = get_relevant_tables(transient)
if relevant_table[hash] == nil then return end
if relevant_table[hash] > 1 then
relevant_table[hash] = relevant_table[hash] - 1
elseif other_table[hash] ~= nil then
relevant_table[hash] = nil
if blocks_forceloaded[hash] == nil then return end
if blocks_forceloaded[hash] > 1 then
blocks_forceloaded[hash] = blocks_forceloaded[hash] - 1
else
total_forceloaded = total_forceloaded-1
relevant_table[hash] = nil
blocks_forceloaded[hash] = nil
forceload_free_block(blockpos)
end
end

View File

@@ -1,20 +1,15 @@
local scriptpath = core.get_builtin_path()..DIR_DELIM
local scriptpath = minetest.get_builtin_path()..DIR_DELIM
local commonpath = scriptpath.."common"..DIR_DELIM
local gamepath = scriptpath.."game"..DIR_DELIM
-- Shared between builtin files, but
-- not exposed to outer context
local builtin_shared = {}
dofile(commonpath.."vector.lua")
dofile(gamepath.."constants.lua")
assert(loadfile(gamepath.."item.lua"))(builtin_shared)
dofile(gamepath.."item.lua")
dofile(gamepath.."register.lua")
if core.setting_getbool("profiler.load") then
profiler = dofile(scriptpath.."profiler"..DIR_DELIM.."init.lua")
if core.setting_getbool("mod_profiling") then
dofile(gamepath.."mod_profiling.lua")
end
dofile(gamepath.."item_entity.lua")
@@ -25,10 +20,9 @@ dofile(gamepath.."auth.lua")
dofile(gamepath.."chatcommands.lua")
dofile(gamepath.."static_spawn.lua")
dofile(gamepath.."detached_inventory.lua")
assert(loadfile(gamepath.."falling.lua"))(builtin_shared)
dofile(gamepath.."falling.lua")
dofile(gamepath.."features.lua")
dofile(gamepath.."voxelarea.lua")
dofile(gamepath.."forceloading.lua")
dofile(gamepath.."statbars.lua")
profiler = nil

View File

@@ -1,7 +1,5 @@
-- Minetest: builtin/item.lua
local builtin_shared = ...
local function copy_pointed_thing(pointed_thing)
return {
type = pointed_thing.type,
@@ -29,11 +27,19 @@ function core.get_pointed_thing_position(pointed_thing, above)
if above then
-- The position where a node would be placed
return pointed_thing.above
else
-- The position where a node would be dug
return pointed_thing.under
end
-- The position where a node would be dug
return pointed_thing.under
elseif pointed_thing.type == "object" then
return pointed_thing.ref and pointed_thing.ref:getpos()
obj = pointed_thing.ref
if obj ~= nil then
return obj:getpos()
else
return nil
end
else
return nil
end
end
@@ -90,26 +96,25 @@ function core.dir_to_facedir(dir, is6d)
end
end
-- Table of possible dirs
local facedir_to_dir = {
{x= 0, y=0, z= 1},
{x= 1, y=0, z= 0},
{x= 0, y=0, z=-1},
{x=-1, y=0, z= 0},
{x= 0, y=-1, z= 0},
{x= 0, y=1, z= 0},
}
-- Mapping from facedir value to index in facedir_to_dir.
local facedir_to_dir_map = {
[0]=1, 2, 3, 4,
5, 2, 6, 4,
6, 2, 5, 4,
1, 5, 3, 6,
1, 6, 3, 5,
1, 4, 3, 2,
}
function core.facedir_to_dir(facedir)
return facedir_to_dir[facedir_to_dir_map[facedir]]
--a table of possible dirs
return ({{x=0, y=0, z=1},
{x=1, y=0, z=0},
{x=0, y=0, z=-1},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0},
{x=0, y=1, z=0}})
--indexed into by a table of correlating facedirs
[({[0]=1, 2, 3, 4,
5, 2, 6, 4,
6, 2, 5, 4,
1, 5, 3, 6,
1, 6, 3, 5,
1, 4, 3, 2})
--indexed into by the facedir in question
[facedir]]
end
function core.dir_to_wallmounted(dir)
@@ -134,19 +139,6 @@ function core.dir_to_wallmounted(dir)
end
end
-- table of dirs in wallmounted order
local wallmounted_to_dir = {
[0] = {x = 0, y = 1, z = 0},
{x = 0, y = -1, z = 0},
{x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0},
{x = 0, y = 0, z = 1},
{x = 0, y = 0, z = -1},
}
function core.wallmounted_to_dir(wallmounted)
return wallmounted_to_dir[wallmounted]
end
function core.get_node_drops(nodename, toolname)
local drop = ItemStack({name=nodename}):get_definition().drop
if drop == nil then
@@ -235,8 +227,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
place_to = {x = under.x, y = under.y, z = under.z}
end
if core.is_protected(place_to, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
if core.is_protected(place_to, placer:get_player_name()) then
core.log("action", placer:get_player_name()
.. " tried to place " .. def.name
.. " at protected position "
@@ -247,14 +238,12 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
core.log("action", placer:get_player_name() .. " places node "
.. def.name .. " at " .. core.pos_to_string(place_to))
local oldnode = core.get_node(place_to)
local newnode = {name = def.name, param1 = 0, param2 = param2}
-- Calculate direction for wall mounted stuff like torches and signs
if def.place_param2 ~= nil then
newnode.param2 = def.place_param2
elseif def.paramtype2 == 'wallmounted' and not param2 then
if def.paramtype2 == 'wallmounted' and not param2 then
local dir = {
x = under.x - above.x,
y = under.y - above.y,
@@ -277,7 +266,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
-- Check if the node is attached and if it can be placed there
if core.get_item_group(def.name, "attached_node") ~= 0 and
not builtin_shared.check_attached_node(place_to, newnode) then
not check_attached_node(place_to, newnode) then
core.log("action", "attached node " .. def.name ..
" can not be placed at " .. core.pos_to_string(place_to))
return itemstack, false
@@ -345,12 +334,8 @@ function core.item_place(itemstack, placer, pointed_thing, param2)
return itemstack
end
function core.item_secondary_use(itemstack, placer)
return itemstack
end
function core.item_drop(itemstack, dropper, pos)
if dropper and dropper:is_player() then
if dropper.is_player then
local v = dropper:get_look_dir()
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
local cs = itemstack:get_count()
@@ -364,50 +349,27 @@ function core.item_drop(itemstack, dropper, pos)
v.y = v.y*2 + 2
v.z = v.z*2
obj:setvelocity(v)
obj:get_luaentity().dropped_by = dropper:get_player_name()
return itemstack
end
else
if core.add_item(pos, itemstack) then
return itemstack
end
end
-- If we reach this, adding the object to the
-- environment failed
end
function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
for _, callback in pairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
if result then
return result
end
end
if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change)
if replace_with_item then
if itemstack:is_empty() then
itemstack:add_item(replace_with_item)
else
local inv = user:get_inventory()
if inv:room_for_item("main", {name=replace_with_item}) then
inv:add_item("main", replace_with_item)
else
local pos = user:getpos()
pos.y = math.floor(pos.y + 0.5)
core.add_item(pos, replace_with_item)
end
end
end
core.add_item(pos, itemstack)
end
return itemstack
end
function core.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing) -- closure
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
for _, callback in pairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
if result then
return result
end
end
if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change)
itemstack:add_item(replace_with_item) -- note: replace_with_item is optional
end
return itemstack
end
end
@@ -449,8 +411,7 @@ function core.node_dig(pos, node, digger)
return
end
if core.is_protected(pos, digger:get_player_name()) and
not minetest.check_player_privs(digger, "protection_bypass") then
if core.is_protected(pos, digger:get_player_name()) then
core.log("action", digger:get_player_name()
.. " tried to dig " .. node.name
.. " at protected position "
@@ -464,7 +425,7 @@ function core.node_dig(pos, node, digger)
local wielded = digger:get_wielded_item()
local drops = core.get_node_drops(node.name, wielded:get_name())
local wdef = wielded:get_definition()
local tp = wielded:get_tool_capabilities()
local dp = core.get_dig_params(def.groups, tp)
@@ -474,13 +435,10 @@ function core.node_dig(pos, node, digger)
-- Wear out tool
if not core.setting_getbool("creative_mode") then
wielded:add_wear(dp.wear)
if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5})
end
end
end
digger:set_wielded_item(wielded)
-- Handle drops
core.handle_node_drops(pos, drops, digger)
@@ -491,7 +449,7 @@ function core.node_dig(pos, node, digger)
-- Remove node and update
core.remove_node(pos)
-- Run callback
if def.after_dig_node then
-- Copy pos and node because callback can modify them
@@ -503,15 +461,6 @@ function core.node_dig(pos, node, digger)
-- Run script hook
local _, callback
for _, callback in ipairs(core.registered_on_dignodes) do
local origin = core.callback_origins[callback]
if origin then
core.set_last_run_mod(origin.mod)
--print("Running " .. tostring(callback) ..
-- " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
else
--print("No data associated with callback")
end
-- Copy pos and node because callback can modify them
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
@@ -558,7 +507,7 @@ core.nodedef_default = {
on_dig = redef_wrapper(core, 'node_dig'), -- core.node_dig
on_receive_fields = nil,
on_metadata_inventory_move = core.node_metadata_inventory_move_allow_all,
on_metadata_inventory_offer = core.node_metadata_inventory_offer_allow_all,
on_metadata_inventory_take = core.node_metadata_inventory_take_allow_all,
@@ -584,7 +533,6 @@ core.nodedef_default = {
diggable = true,
climbable = false,
buildable_to = false,
floodable = false,
liquidtype = "none",
liquid_alternative_flowing = "",
liquid_alternative_source = "",
@@ -612,7 +560,6 @@ core.craftitemdef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_use = nil,
}
@@ -630,7 +577,6 @@ core.tooldef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_use = nil,
}
@@ -649,7 +595,6 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'),
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = nil,
on_use = nil,
}

View File

@@ -4,14 +4,11 @@ function core.spawn_item(pos, item)
-- Take item in any format
local stack = ItemStack(item)
local obj = core.add_entity(pos, "__builtin:item")
-- Don't use obj if it couldn't be added to the map.
if obj then
obj:get_luaentity():set_item(stack:to_string())
end
obj:get_luaentity():set_item(stack:to_string())
return obj
end
-- If item_entity_ttl is not set, enity will have default life time
-- If item_entity_ttl is not set, enity will have default life time
-- Setting it to -1 disables the feature
local time_to_live = tonumber(core.setting_get("item_entity_ttl"))
@@ -74,8 +71,7 @@ core.register_entity(":__builtin:item", {
return core.serialize({
itemstring = self.itemstring,
always_collect = self.always_collect,
age = self.age,
dropped_by = self.dropped_by
age = self.age
})
end,
@@ -85,12 +81,11 @@ core.register_entity(":__builtin:item", {
if data and type(data) == "table" then
self.itemstring = data.itemstring
self.always_collect = data.always_collect
if data.age then
if data.age then
self.age = data.age + dtime_s
else
self.age = dtime_s
end
self.dropped_by = data.dropped_by
end
else
self.itemstring = staticdata
@@ -101,56 +96,6 @@ core.register_entity(":__builtin:item", {
self:set_item(self.itemstring)
end,
try_merge_with = function(self, own_stack, object, obj)
local stack = ItemStack(obj.itemstring)
if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then
local overflow = false
local count = stack:get_count() + own_stack:get_count()
local max_count = stack:get_stack_max()
if count > max_count then
overflow = true
count = count - max_count
else
self.itemstring = ''
end
local pos = object:getpos()
pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15
object:moveto(pos, false)
local s, c
local max_count = stack:get_stack_max()
local name = stack:get_name()
if not overflow then
obj.itemstring = name .. " " .. count
s = 0.2 + 0.1 * (count / max_count)
c = s
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.object:remove()
-- merging succeeded
return true
else
s = 0.4
c = 0.3
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
obj.itemstring = name .. " " .. max_count
s = 0.2 + 0.1 * (count / max_count)
c = s
self.object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.itemstring = name .. " " .. count
end
end
-- merging didn't succeed
return false
end,
on_step = function(self, dtime)
self.age = self.age + dtime
if time_to_live > 0 and self.age > time_to_live then
@@ -160,29 +105,58 @@ core.register_entity(":__builtin:item", {
end
local p = self.object:getpos()
p.y = p.y - 0.5
local node = core.get_node_or_nil(p)
local in_unloaded = (node == nil)
if in_unloaded then
-- Don't infinetly fall into unloaded map
self.object:setvelocity({x = 0, y = 0, z = 0})
self.object:setacceleration({x = 0, y = 0, z = 0})
self.physical_state = false
self.object:set_properties({physical = false})
return
end
local nn = node.name
local nn = core.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 core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then
if self.physical_state then
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
-- Merge with close entities of the same item
for _, object in ipairs(core.get_objects_inside_radius(p, 0.8)) do
for _,object in ipairs(core.get_objects_inside_radius(p, 0.8)) do
local obj = object:get_luaentity()
if obj and obj.name == "__builtin:item"
and obj.physical_state == false then
if self:try_merge_with(own_stack, object, obj) then
return
if obj and obj.name == "__builtin:item" and obj.physical_state == false then
local stack = ItemStack(obj.itemstring)
if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then
local overflow = false
local count = stack:get_count() + own_stack:get_count()
local max_count = stack:get_stack_max()
if count>max_count then
overflow = true
count = count - max_count
else
self.itemstring = ''
end
local pos=object:getpos()
pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15
object:moveto(pos, false)
local s, c
local max_count = stack:get_stack_max()
local name = stack:get_name()
if not overflow then
obj.itemstring = name.." "..count
s = 0.2 + 0.1 * (count / max_count)
c = s
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.object:remove()
return
else
s = 0.4
c = 0.3
object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
obj.itemstring = name.." "..max_count
s = 0.2 + 0.1 * (count / max_count)
c = s
self.object:set_properties({
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c}
})
self.itemstring = name.." "..count
end
end
end
end
@@ -202,10 +176,9 @@ core.register_entity(":__builtin:item", {
end,
on_punch = function(self, hitter)
local inv = hitter:get_inventory()
if inv and self.itemstring ~= '' then
local left = inv:add_item("main", self.itemstring)
if left and not left:is_empty() then
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

View File

@@ -4,135 +4,68 @@
-- Misc. API functions
--
local jobs = {}
local time = 0.0
local last = core.get_us_time() / 1000000
core.timers_to_add = {}
core.timers = {}
core.register_globalstep(function(dtime)
local new = core.get_us_time() / 1000000
if new > last then
time = time + (new - last)
else
-- Overflow, we may lose a little bit of time here but
-- only 1 tick max, potentially running timers slightly
-- too early.
time = time + new
for _, timer in ipairs(core.timers_to_add) do
table.insert(core.timers, timer)
end
last = new
if #jobs < 1 then
return
end
-- Iterate backwards so that we miss any new timers added by
-- a timer callback, and so that we don't skip the next timer
-- in the list if we remove one.
for i = #jobs, 1, -1 do
local job = jobs[i]
if time >= job.expire then
core.set_last_run_mod(job.mod_origin)
job.func(unpack(job.arg))
table.remove(jobs, i)
core.timers_to_add = {}
local index = 1
while index <= #core.timers do
local timer = core.timers[index]
timer.time = timer.time - dtime
if timer.time <= 0 then
timer.func(unpack(timer.args or {}))
table.remove(core.timers,index)
else
index = index + 1
end
end
end)
function core.after(after, func, ...)
assert(tonumber(after) and type(func) == "function",
function core.after(time, func, ...)
assert(tonumber(time) and type(func) == "function",
"Invalid core.after invocation")
jobs[#jobs + 1] = {
func = func,
expire = time + after,
arg = {...},
mod_origin = core.get_last_run_mod()
}
table.insert(core.timers_to_add, {time=time, func=func, args={...}})
end
function core.check_player_privs(name, ...)
local arg_type = type(name)
if (arg_type == "userdata" or arg_type == "table") and
name.get_player_name then -- If it quacks like a Player...
name = name:get_player_name()
elseif arg_type ~= "string" then
error("Invalid core.check_player_privs argument type: " .. arg_type, 2)
end
local requested_privs = {...}
function core.check_player_privs(name, privs)
local player_privs = core.get_player_privs(name)
local missing_privileges = {}
if type(requested_privs[1]) == "table" then
-- We were provided with a table like { privA = true, privB = true }.
for priv, value in pairs(requested_privs[1]) do
if value and not player_privs[priv] then
missing_privileges[#missing_privileges + 1] = priv
end
end
else
-- Only a list, we can process it directly.
for key, priv in pairs(requested_privs) do
for priv, val in pairs(privs) do
if val then
if not player_privs[priv] then
missing_privileges[#missing_privileges + 1] = priv
table.insert(missing_privileges, priv)
end
end
end
if #missing_privileges > 0 then
return false, missing_privileges
end
return true, ""
end
local player_list = {}
core.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
player_list[player_name] = player
if not minetest.is_singleplayer() then
core.chat_send_all("*** " .. player_name .. " joined the game.")
end
player_list[player:get_player_name()] = player
end)
core.register_on_leaveplayer(function(player, timed_out)
local player_name = player:get_player_name()
player_list[player_name] = nil
local announcement = "*** " .. player_name .. " left the game."
if timed_out then
announcement = announcement .. " (timed out)"
end
core.chat_send_all(announcement)
core.register_on_leaveplayer(function(player)
player_list[player:get_player_name()] = nil
end)
function core.get_connected_players()
local temp_table = {}
for index, value in pairs(player_list) do
if value:is_player_connected() then
temp_table[#temp_table + 1] = value
table.insert(temp_table, value)
end
end
return temp_table
end
-- Returns two position vectors representing a box of `radius` in each
-- direction centered around the player corresponding to `player_name`
function core.get_player_radius_area(player_name, radius)
local player = core.get_player_by_name(player_name)
if player == nil then
return nil
end
local p1 = player:getpos()
local p2 = p1
if radius then
p1 = vector.subtract(p1, radius)
p2 = vector.add(p2, radius)
end
return p1, p2
end
function core.hash_node_position(pos)
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
end
@@ -179,69 +112,3 @@ function core.record_protection_violation(pos, name)
end
end
local raillike_ids = {}
local raillike_cur_id = 0
function core.raillike_group(name)
local id = raillike_ids[name]
if not id then
raillike_cur_id = raillike_cur_id + 1
raillike_ids[name] = raillike_cur_id
id = raillike_cur_id
end
return id
end
-- HTTP callback interface
function core.http_add_fetch(httpenv)
httpenv.fetch = function(req, callback)
local handle = httpenv.fetch_async(req)
local function update_http_status()
local res = httpenv.fetch_async_get(handle)
if res.completed then
callback(res)
else
core.after(0, update_http_status)
end
end
core.after(0, update_http_status)
end
return httpenv
end
if minetest.setting_getbool("disable_escape_sequences") then
function core.get_color_escape_sequence(color)
return ""
end
function core.get_background_escape_sequence(color)
return ""
end
function core.colorize(color, message)
return message
end
else
local ESCAPE_CHAR = string.char(0x1b)
function core.get_color_escape_sequence(color)
return ESCAPE_CHAR .. "(c@" .. color .. ")"
end
function core.get_background_escape_sequence(color)
return ESCAPE_CHAR .. "(b@" .. color .. ")"
end
function core.colorize(color, message)
return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff")
end
end
function core.close_formspec(player_name, formname)
return minetest.show_formspec(player_name, formname, "")
end

View File

@@ -0,0 +1,356 @@
-- Minetest: builtin/game/mod_profiling.lua
local mod_statistics = {}
mod_statistics.step_total = 0
mod_statistics.data = {}
mod_statistics.stats = {}
mod_statistics.stats["total"] = {
min_us = math.huge,
max_us = 0,
avg_us = 0,
min_per = 100,
max_per = 100,
avg_per = 100
}
local replacement_table = {
"register_globalstep",
"register_on_placenode",
"register_on_dignode",
"register_on_punchnode",
"register_on_generated",
"register_on_newplayer",
"register_on_dieplayer",
"register_on_respawnplayer",
"register_on_prejoinplayer",
"register_on_joinplayer",
"register_on_leaveplayer",
"register_on_cheat",
"register_on_chat_message",
"register_on_player_receive_fields",
"register_on_mapgen_init",
"register_on_craft",
"register_craft_predict",
"register_on_item_eat"
}
--------------------------------------------------------------------------------
function mod_statistics.log_time(type, modname, time_in_us)
if modname == nil then
modname = "builtin"
end
if mod_statistics.data[modname] == nil then
mod_statistics.data[modname] = {}
end
if mod_statistics.data[modname][type] == nil then
mod_statistics.data[modname][type] = 0
end
mod_statistics.data[modname][type] =
mod_statistics.data[modname][type] + time_in_us
mod_statistics.step_total = mod_statistics.step_total + time_in_us
end
--------------------------------------------------------------------------------
function mod_statistics.update_statistics(dtime)
for modname,types in pairs(mod_statistics.data) do
if mod_statistics.stats[modname] == nil then
mod_statistics.stats[modname] = {
min_us = math.huge,
max_us = 0,
avg_us = 0,
min_per = 100,
max_per = 0,
avg_per = 0
}
end
local modtime = 0
for type,time in pairs(types) do
modtime = modtime + time
if mod_statistics.stats[modname].types == nil then
mod_statistics.stats[modname].types = {}
end
if mod_statistics.stats[modname].types[type] == nil then
mod_statistics.stats[modname].types[type] = {
min_us = math.huge,
max_us = 0,
avg_us = 0,
min_per = 100,
max_per = 0,
avg_per = 0
}
end
local toupdate = mod_statistics.stats[modname].types[type]
--update us values
toupdate.min_us = math.min(time, toupdate.min_us)
toupdate.max_us = math.max(time, toupdate.max_us)
--TODO find better algorithm
toupdate.avg_us = toupdate.avg_us * 0.99 + modtime * 0.01
--update percentage values
local cur_per = (time/mod_statistics.step_total) * 100
toupdate.min_per = math.min(toupdate.min_per, cur_per)
toupdate.max_per = math.max(toupdate.max_per, cur_per)
--TODO find better algorithm
toupdate.avg_per = toupdate.avg_per * 0.99 + cur_per * 0.01
mod_statistics.data[modname][type] = 0
end
--per mod statistics
--update us values
mod_statistics.stats[modname].min_us =
math.min(modtime, mod_statistics.stats[modname].min_us)
mod_statistics.stats[modname].max_us =
math.max(modtime, mod_statistics.stats[modname].max_us)
--TODO find better algorithm
mod_statistics.stats[modname].avg_us =
mod_statistics.stats[modname].avg_us * 0.99 + modtime * 0.01
--update percentage values
local cur_per = (modtime/mod_statistics.step_total) * 100
mod_statistics.stats[modname].min_per =
math.min(mod_statistics.stats[modname].min_per, cur_per)
mod_statistics.stats[modname].max_per =
math.max(mod_statistics.stats[modname].max_per, cur_per)
--TODO find better algorithm
mod_statistics.stats[modname].avg_per =
mod_statistics.stats[modname].avg_per * 0.99 + cur_per * 0.01
end
--update "total"
mod_statistics.stats["total"].min_us =
math.min(mod_statistics.step_total, mod_statistics.stats["total"].min_us)
mod_statistics.stats["total"].max_us =
math.max(mod_statistics.step_total, mod_statistics.stats["total"].max_us)
--TODO find better algorithm
mod_statistics.stats["total"].avg_us =
mod_statistics.stats["total"].avg_us * 0.99 +
mod_statistics.step_total * 0.01
mod_statistics.step_total = 0
end
--------------------------------------------------------------------------------
local function build_callback(log_id, fct)
return function( toregister )
local modname = core.get_current_modname()
fct(function(...)
local starttime = core.get_us_time()
-- note maximum 10 return values are supported unless someone finds
-- a way to store a variable lenght return value list
local r0, r1, r2, r3, r4, r5, r6, r7, r8, r9 = toregister(...)
local delta = core.get_us_time() - starttime
mod_statistics.log_time(log_id, modname, delta)
return r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
end
)
end
end
--------------------------------------------------------------------------------
function profiling_print_log(cmd, filter)
print("Filter:" .. dump(filter))
core.log("action", "Values below show times/percentages per server step.")
core.log("action", "Following suffixes are used for entities:")
core.log("action", "\t#oa := on_activate, #os := on_step, #op := on_punch, #or := on_rightclick, #gs := get_staticdata")
core.log("action",
string.format("%16s | %25s | %10s | %10s | %10s | %9s | %9s | %9s",
"modname", "type" , "min µs", "max µs", "avg µs", "min %", "max %", "avg %")
)
core.log("action",
"-----------------+---------------------------+-----------+" ..
"-----------+-----------+-----------+-----------+-----------")
for modname,statistics in pairs(mod_statistics.stats) do
if modname ~= "total" then
if (filter == "") or (modname == filter) then
if modname:len() > 16 then
modname = "..." .. modname:sub(-13)
end
core.log("action",
string.format("%16s | %25s | %9d | %9d | %9d | %9d | %9d | %9d",
modname,
" ",
statistics.min_us,
statistics.max_us,
statistics.avg_us,
statistics.min_per,
statistics.max_per,
statistics.avg_per)
)
if core.setting_getbool("detailed_profiling") then
if statistics.types ~= nil then
for type,typestats in pairs(statistics.types) do
if type:len() > 25 then
type = "..." .. type:sub(-22)
end
core.log("action",
string.format(
"%16s | %25s | %9d | %9d | %9d | %9d | %9d | %9d",
" ",
type,
typestats.min_us,
typestats.max_us,
typestats.avg_us,
typestats.min_per,
typestats.max_per,
typestats.avg_per)
)
end
end
end
end
end
end
core.log("action",
"-----------------+---------------------------+-----------+" ..
"-----------+-----------+-----------+-----------+-----------")
if filter == "" then
core.log("action",
string.format("%16s | %25s | %9d | %9d | %9d | %9d | %9d | %9d",
"total",
" ",
mod_statistics.stats["total"].min_us,
mod_statistics.stats["total"].max_us,
mod_statistics.stats["total"].avg_us,
mod_statistics.stats["total"].min_per,
mod_statistics.stats["total"].max_per,
mod_statistics.stats["total"].avg_per)
)
end
core.log("action", " ")
return true
end
--------------------------------------------------------------------------------
local function initialize_profiling()
core.log("action", "Initialize tracing")
mod_statistics.entity_callbacks = {}
-- first register our own globalstep handler
core.register_globalstep(mod_statistics.update_statistics)
local rp_register_entity = core.register_entity
core.register_entity = function(name, prototype)
local modname = core.get_current_modname()
local new_on_activate = nil
local new_on_step = nil
local new_on_punch = nil
local new_rightclick = nil
local new_get_staticdata = nil
if prototype.on_activate ~= nil then
local cbid = name .. "#oa"
mod_statistics.entity_callbacks[cbid] = prototype.on_activate
new_on_activate = function(self, staticdata, dtime_s)
local starttime = core.get_us_time()
mod_statistics.entity_callbacks[cbid](self, staticdata, dtime_s)
local delta = core.get_us_time() -starttime
mod_statistics.log_time(cbid, modname, delta)
end
end
if prototype.on_step ~= nil then
local cbid = name .. "#os"
mod_statistics.entity_callbacks[cbid] = prototype.on_step
new_on_step = function(self, dtime)
local starttime = core.get_us_time()
mod_statistics.entity_callbacks[cbid](self, dtime)
local delta = core.get_us_time() -starttime
mod_statistics.log_time(cbid, modname, delta)
end
end
if prototype.on_punch ~= nil then
local cbid = name .. "#op"
mod_statistics.entity_callbacks[cbid] = prototype.on_punch
new_on_punch = function(self, hitter)
local starttime = core.get_us_time()
mod_statistics.entity_callbacks[cbid](self, hitter)
local delta = core.get_us_time() -starttime
mod_statistics.log_time(cbid, modname, delta)
end
end
if prototype.rightclick ~= nil then
local cbid = name .. "#rc"
mod_statistics.entity_callbacks[cbid] = prototype.rightclick
new_rightclick = function(self, clicker)
local starttime = core.get_us_time()
mod_statistics.entity_callbacks[cbid](self, clicker)
local delta = core.get_us_time() -starttime
mod_statistics.log_time(cbid, modname, delta)
end
end
if prototype.get_staticdata ~= nil then
local cbid = name .. "#gs"
mod_statistics.entity_callbacks[cbid] = prototype.get_staticdata
new_get_staticdata = function(self)
local starttime = core.get_us_time()
local retval = mod_statistics.entity_callbacks[cbid](self)
local delta = core.get_us_time() -starttime
mod_statistics.log_time(cbid, modname, delta)
return retval
end
end
prototype.on_activate = new_on_activate
prototype.on_step = new_on_step
prototype.on_punch = new_on_punch
prototype.rightclick = new_rightclick
prototype.get_staticdata = new_get_staticdata
rp_register_entity(name,prototype)
end
for i,v in ipairs(replacement_table) do
local to_replace = core[v]
core[v] = build_callback(v, to_replace)
end
local rp_register_abm = core.register_abm
core.register_abm = function(spec)
local modname = core.get_current_modname()
local replacement_spec = {
nodenames = spec.nodenames,
neighbors = spec.neighbors,
interval = spec.interval,
chance = spec.chance,
action = function(pos, node, active_object_count, active_object_count_wider)
local starttime = core.get_us_time()
spec.action(pos, node, active_object_count, active_object_count_wider)
local delta = core.get_us_time() - starttime
mod_statistics.log_time("abm", modname, delta)
end
}
rp_register_abm(replacement_spec)
end
core.log("action", "Mod profiling initialized")
end
initialize_profiling()

View File

@@ -26,46 +26,17 @@ function core.register_privilege(name, param)
end
core.register_privilege("interact", "Can interact with things and modify the world")
core.register_privilege("shout", "Can speak in chat")
core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
core.register_privilege("teleport", "Can use /teleport command")
core.register_privilege("bring", "Can teleport other players")
core.register_privilege("settime", "Can use /time")
core.register_privilege("privs", "Can modify privileges")
core.register_privilege("teleport", {
description = "Can use /teleport command",
give_to_singleplayer = false,
})
core.register_privilege("bring", {
description = "Can teleport other players",
give_to_singleplayer = false,
})
core.register_privilege("settime", {
description = "Can use /time",
give_to_singleplayer = false,
})
core.register_privilege("server", {
description = "Can do server maintenance stuff",
give_to_singleplayer = false,
})
core.register_privilege("protection_bypass", {
description = "Can bypass node protection in the world",
give_to_singleplayer = false,
})
core.register_privilege("ban", {
description = "Can ban and unban players",
give_to_singleplayer = false,
})
core.register_privilege("kick", {
description = "Can kick players",
give_to_singleplayer = false,
})
core.register_privilege("give", {
description = "Can use /give and /giveme",
give_to_singleplayer = false,
})
core.register_privilege("password", {
description = "Can use /setpassword and /clearpassword",
give_to_singleplayer = false,
})
core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
core.register_privilege("server", "Can do server maintenance stuff")
core.register_privilege("shout", "Can speak in chat")
core.register_privilege("ban", "Can ban and unban players")
core.register_privilege("kick", "Can kick players")
core.register_privilege("give", "Can use /give and /giveme")
core.register_privilege("password", "Can use /setpassword and /clearpassword")
core.register_privilege("fly", {
description = "Can fly using the free_move mode",
give_to_singleplayer = false,
@@ -78,15 +49,5 @@ core.register_privilege("noclip", {
description = "Can fly through walls",
give_to_singleplayer = false,
})
core.register_privilege("rollback", {
description = "Can use the rollback functionality",
give_to_singleplayer = false,
})
core.register_privilege("zoom", {
description = "Can zoom the camera",
give_to_singleplayer = false,
})
core.register_privilege("debug", {
description = "Allows enabling various debug options that may affect gameplay",
give_to_singleplayer = false,
})
core.register_privilege("rollback", "Can use the rollback functionality")

View File

@@ -7,18 +7,14 @@
local register_item_raw = core.register_item_raw
core.register_item_raw = nil
local unregister_item_raw = core.unregister_item_raw
core.unregister_item_raw = nil
local register_alias_raw = core.register_alias_raw
core.register_alias_raw = nil
--
-- Item / entity / ABM / LBM registration functions
-- Item / entity / ABM registration functions
--
core.registered_abms = {}
core.registered_lbms = {}
core.registered_entities = {}
core.registered_items = {}
core.registered_nodes = {}
@@ -55,39 +51,27 @@ local forbidden_item_names = {
local function check_modname_prefix(name)
if name:sub(1,1) == ":" then
-- If the name starts with a colon, we can skip the modname prefix
-- mechanism.
-- Escape the modname prefix enforcement mechanism
return name:sub(2)
else
-- Enforce that the name starts with the correct mod name.
-- Modname prefix enforcement
local expected_prefix = core.get_current_modname() .. ":"
if name:sub(1, #expected_prefix) ~= expected_prefix then
error("Name " .. name .. " does not follow naming conventions: " ..
"\"" .. expected_prefix .. "\" or \":\" prefix required")
"\"modname:\" or \":\" prefix required")
end
-- Enforce that the name only contains letters, numbers and underscores.
local subname = name:sub(#expected_prefix+1)
if subname:find("[^%w_]") then
if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
error("Name " .. name .. " does not follow naming conventions: " ..
"contains unallowed characters")
end
return name
end
end
function core.register_abm(spec)
-- Add to core.registered_abms
core.registered_abms[#core.registered_abms + 1] = spec
spec.mod_origin = core.get_current_modname() or "??"
end
function core.register_lbm(spec)
-- Add to core.registered_lbms
check_modname_prefix(spec.name)
core.registered_lbms[#core.registered_lbms + 1] = spec
spec.mod_origin = core.get_current_modname() or "??"
core.registered_abms[#core.registered_abms+1] = spec
end
function core.register_entity(name, prototype)
@@ -102,7 +86,6 @@ function core.register_entity(name, prototype)
-- Add to core.registered_entities
core.registered_entities[name] = prototype
prototype.mod_origin = core.get_current_modname() or "??"
end
function core.register_item(name, itemdef)
@@ -127,11 +110,6 @@ function core.register_item(name, itemdef)
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
}
end
if itemdef.light_source and itemdef.light_source > core.LIGHT_MAX then
itemdef.light_source = core.LIGHT_MAX
core.log("warning", "Node 'light_source' value exceeds maximum," ..
" limiting to maximum: " ..name)
end
setmetatable(itemdef, {__index = core.nodedef_default})
core.registered_nodes[itemdef.name] = itemdef
elseif itemdef.type == "craft" then
@@ -169,8 +147,6 @@ function core.register_item(name, itemdef)
end
-- END Legacy stuff
itemdef.mod_origin = core.get_current_modname() or "??"
-- Disable all further modifications
getmetatable(itemdef).__newindex = {}
@@ -180,27 +156,6 @@ function core.register_item(name, itemdef)
register_item_raw(itemdef)
end
function core.unregister_item(name)
if not core.registered_items[name] then
core.log("warning", "Not unregistering item " ..name..
" because it doesn't exist.")
return
end
-- Erase from registered_* table
local type = core.registered_items[name].type
if type == "node" then
core.registered_nodes[name] = nil
elseif type == "craft" then
core.registered_craftitems[name] = nil
elseif type == "tool" then
core.registered_tools[name] = nil
end
core.registered_items[name] = nil
unregister_item_raw(name)
end
function core.register_node(name, nodedef)
nodedef.type = "node"
core.register_item(name, nodedef)
@@ -262,7 +217,7 @@ function core.register_alias(name, convert_to)
error("Unable to register alias: Name is forbidden: " .. name)
end
if core.registered_items[name] ~= nil then
core.log("warning", "Not registering alias, item with same name" ..
core.log("WARNING: Not registering alias, item with same name" ..
" is already defined: " .. name .. " -> " .. convert_to)
else
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
@@ -271,20 +226,6 @@ function core.register_alias(name, convert_to)
end
end
function core.register_alias_force(name, convert_to)
if forbidden_item_names[name] then
error("Unable to register alias: Name is forbidden: " .. name)
end
if core.registered_items[name] ~= nil then
core.unregister_item(name)
core.log("info", "Removed item " ..name..
" while attempting to force add an alias")
end
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
core.registered_aliases[name] = convert_to
register_alias_raw(name, convert_to)
end
function core.on_craft(itemstack, player, old_craft_list, craft_inv)
for _, func in ipairs(core.registered_on_crafts) do
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
@@ -323,7 +264,6 @@ core.register_item(":unknown", {
description = "Unknown Item",
inventory_image = "unknown_item.png",
on_place = core.item_place,
on_secondary_use = core.item_secondary_use,
on_drop = core.item_drop,
groups = {not_in_creative_inventory=1},
diggable = true,
@@ -340,7 +280,6 @@ core.register_node(":air", {
pointable = false,
diggable = false,
buildable_to = true,
floodable = true,
air_equivalent = true,
drop = "",
groups = {not_in_creative_inventory=1},
@@ -387,8 +326,6 @@ function core.override_item(name, redefinition)
end
core.callback_origins = {}
function core.run_callbacks(callbacks, mode, ...)
assert(type(callbacks) == "table")
local cb_len = #callbacks
@@ -401,14 +338,6 @@ function core.run_callbacks(callbacks, mode, ...)
end
local ret = nil
for i = 1, cb_len do
local origin = core.callback_origins[callbacks[i]]
if origin then
core.set_last_run_mod(origin.mod)
--print("Running " .. tostring(callbacks[i]) ..
-- " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
else
--print("No data associated with callback")
end
local cb_ret = callbacks[i](...)
if mode == 0 and i == 1 then
@@ -441,29 +370,13 @@ end
local function make_registration()
local t = {}
local registerfunc = function(func)
t[#t + 1] = func
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
--local origin = core.callback_origins[func]
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
end
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)
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
--local origin = core.callback_origins[func]
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
end
local registerfunc = function(func) table.insert(t, 1, func) end
return t, registerfunc
end
@@ -485,49 +398,13 @@ local function make_registration_wrap(reg_fn_name, clear_fn_name)
local orig_clear_fn = core[clear_fn_name]
core[clear_fn_name] = function()
for k in pairs(list) do
list[k] = nil
end
list = {}
return orig_clear_fn()
end
return list
end
core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } }
function core.registered_on_player_hpchange(player, hp_change)
local last = false
for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do
local func = core.registered_on_player_hpchanges.modifiers[i]
hp_change, last = func(player, hp_change)
if type(hp_change) ~= "number" then
local debuginfo = debug.getinfo(func)
error("The register_on_hp_changes function has to return a number at " ..
debuginfo.short_src .. " line " .. debuginfo.linedefined)
end
if last then
break
end
end
for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do
func(player, hp_change)
end
return hp_change
end
function core.register_on_player_hpchange(func, modifier)
if modifier then
core.registered_on_player_hpchanges.modifiers[#core.registered_on_player_hpchanges.modifiers + 1] = func
else
core.registered_on_player_hpchanges.loggers[#core.registered_on_player_hpchanges.loggers + 1] = func
end
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
end
core.registered_biomes = make_registration_wrap("register_biome", "clear_registered_biomes")
core.registered_ores = make_registration_wrap("register_ore", "clear_registered_ores")
core.registered_decorations = make_registration_wrap("register_decoration", "clear_registered_decorations")
@@ -552,7 +429,6 @@ core.registered_on_crafts, core.register_on_craft = make_registration()
core.registered_craft_predicts, core.register_craft_predict = make_registration()
core.registered_on_protection_violation, core.register_on_protection_violation = make_registration()
core.registered_on_item_eats, core.register_on_item_eat = make_registration()
core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
--
-- Compatibility for on_mapgen_init()

View File

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

View File

@@ -50,7 +50,7 @@ end
function VoxelArea:position(i)
local p = {}
local MinEdge = self.MinEdge
i = i - 1
p.z = math.floor(i / self.zstride) + MinEdge.z
@@ -84,46 +84,23 @@ end
function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz)
local i = self:index(minx, miny, minz) - 1
local xrange = maxx - minx + 1
local nextaction = i + 1 + xrange
local y = 0
local yrange = maxy - miny + 1
local yreqstride = self.ystride - xrange
local z = 0
local zrange = maxz - minz + 1
local multistride = self.zstride - ((yrange - 1) * self.ystride + xrange)
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()
-- continue i until it needs to jump
i = i + 1
if i ~= nextaction then
if i % zstride == zoff then
i = i + zstridediff
elseif i % ystride == yoff then
i = i + ystridediff
end
if i <= last then
return i
end
-- continue y until maxy is exceeded
y = y + 1
if y ~= yrange then
-- set i to index(minx, miny + y, minz + z) - 1
i = i + yreqstride
nextaction = i + xrange
return i
end
-- continue z until maxz is exceeded
z = z + 1
if z == zrange then
-- cuboid finished, return nil
return
end
-- set i to index(minx, miny, minz + z) - 1
i = i + multistride
y = 0
nextaction = i + xrange
return i
end
end

View File

@@ -6,45 +6,32 @@
--
-- Initialize some very basic things
function core.debug(...) core.log(table.concat({...}, "\t")) end
if core.print then
local core_print = core.print
-- Override native print and use
-- terminal if that's turned on
function print(...)
local n, t = select("#", ...), {...}
for i = 1, n do
t[i] = tostring(t[i])
end
core_print(table.concat(t, "\t"))
end
core.print = nil -- don't pollute our namespace
end
print = core.debug
math.randomseed(os.time())
os.setlocale("C", "numeric")
minetest = core
-- Load other files
local scriptdir = core.get_builtin_path() .. DIR_DELIM
local gamepath = scriptdir .. "game" .. DIR_DELIM
local commonpath = scriptdir .. "common" .. DIR_DELIM
local asyncpath = scriptdir .. "async" .. DIR_DELIM
local scriptdir = core.get_builtin_path()..DIR_DELIM
local gamepath = scriptdir.."game"..DIR_DELIM
local commonpath = scriptdir.."common"..DIR_DELIM
local asyncpath = scriptdir.."async"..DIR_DELIM
dofile(commonpath .. "strict.lua")
dofile(commonpath .. "serialize.lua")
dofile(commonpath .. "misc_helpers.lua")
dofile(commonpath.."strict.lua")
dofile(commonpath.."serialize.lua")
dofile(commonpath.."misc_helpers.lua")
if INIT == "game" then
dofile(gamepath .. "init.lua")
dofile(gamepath.."init.lua")
elseif INIT == "mainmenu" then
local mainmenuscript = core.setting_get("main_menu_script")
if mainmenuscript ~= nil and mainmenuscript ~= "" then
dofile(mainmenuscript)
else
dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua")
dofile(core.get_mainmenu_path()..DIR_DELIM.."init.lua")
end
elseif INIT == "async" then
dofile(asyncpath .. "init.lua")
dofile(asyncpath.."init.lua")
else
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
end

View File

@@ -22,37 +22,28 @@ menudata = {}
--------------------------------------------------------------------------------
-- Local cached values
--------------------------------------------------------------------------------
local min_supp_proto, max_supp_proto
local min_supp_proto = core.get_min_supp_proto()
local max_supp_proto = core.get_max_supp_proto()
function common_update_cached_supp_proto()
min_supp_proto = core.get_min_supp_proto()
max_supp_proto = core.get_max_supp_proto()
end
common_update_cached_supp_proto()
--------------------------------------------------------------------------------
-- Menu helper functions
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function render_client_count(n)
if n > 99 then return '99+'
elseif n >= 0 then return tostring(n)
else return '?' end
end
local function configure_selected_world_params(idx)
local worldconfig = modmgr.get_worldconfig(menudata.worldlist:get_list()[idx].path)
if worldconfig.creative_mode then
core.setting_set("creative_mode", worldconfig.creative_mode)
end
if worldconfig.enable_damage then
core.setting_set("enable_damage", worldconfig.enable_damage)
if n > 99 then
return '99+'
elseif n >= 0 then
return tostring(n)
else
return '?'
end
end
--------------------------------------------------------------------------------
function image_column(tooltip, flagname)
return "image,tooltip=" .. core.formspec_escape(tooltip) .. "," ..
return "image," ..
"tooltip=" .. core.formspec_escape(tooltip) .. "," ..
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_" .. flagname .. ".png")
end
@@ -61,60 +52,76 @@ end
function order_favorite_list(list)
local res = {}
--orders the favorite list after support
for i = 1, #list do
for i=1,#list,1 do
local fav = list[i]
if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
res[#res + 1] = fav
table.insert(res, fav)
end
end
for i = 1, #list do
for i=1,#list,1 do
local fav = list[i]
if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
res[#res + 1] = fav
table.insert(res, fav)
end
end
return res
end
--------------------------------------------------------------------------------
function render_favorite(spec, is_favorite)
function render_favorite(spec,render_details)
local text = ""
if spec.name then
if spec.name ~= nil then
text = text .. core.formspec_escape(spec.name:trim())
elseif spec.address then
text = text .. spec.address:trim()
if spec.port then
text = text .. ":" .. spec.port
-- if spec.description ~= nil and
-- core.formspec_escape(spec.description):trim() ~= "" then
-- text = text .. " (" .. core.formspec_escape(spec.description) .. ")"
-- end
else
if spec.address ~= nil then
text = text .. spec.address:trim()
if spec.port ~= nil then
text = text .. ":" .. spec.port
end
end
end
local details = ""
local grey_out = not is_server_protocol_compat(spec.proto_min, spec.proto_max)
if is_favorite then
details = "1,"
else
details = "0,"
if not render_details then
return text
end
if spec.clients and spec.clients_max then
local details = ""
local grey_out = not is_server_protocol_compat(spec.proto_max, spec.proto_min)
if spec.clients ~= nil and spec.clients_max ~= nil then
local clients_color = ''
local clients_percent = 100 * spec.clients / spec.clients_max
-- Choose a color depending on how many clients are connected
-- (relatively to clients_max)
if grey_out then clients_color = '#aaaaaa'
elseif spec.clients == 0 then clients_color = '' -- 0 players: default/white
elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green
elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow
elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker)
else clients_color = '#ffba97' -- 90-100%: orange
if spec.clients == 0 then
clients_color = '' -- 0 players: default/white
elseif spec.clients == spec.clients_max then
clients_color = '#dd5b5b' -- full server: red (darker)
elseif clients_percent <= 60 then
clients_color = '#a1e587' -- 0-60%: green
elseif clients_percent <= 90 then
clients_color = '#ffdc97' -- 60-90%: yellow
else
clients_color = '#ffba97' -- 90-100%: orange
end
details = details .. clients_color .. ',' ..
render_client_count(spec.clients) .. ',/,' ..
render_client_count(spec.clients_max) .. ','
if grey_out then
clients_color = '#aaaaaa'
end
details = details ..
clients_color .. ',' ..
render_client_count(spec.clients) .. ',' ..
'/,' ..
render_client_count(spec.clients_max) .. ','
elseif grey_out then
details = details .. '#aaaaaa,?,/,?,'
else
@@ -165,152 +172,106 @@ end
--------------------------------------------------------------------------------
function menu_render_worldlist()
local retval = ""
local current_worldlist = menudata.worldlist:get_list()
for i, v in ipairs(current_worldlist) do
if retval ~= "" then retval = retval .. "," end
for i,v in ipairs(current_worldlist) do
if retval ~= "" then
retval = retval ..","
end
retval = retval .. core.formspec_escape(v.name) ..
" \\[" .. core.formspec_escape(v.gameid) .. "\\]"
" \\[" .. core.formspec_escape(v.gameid) .. "\\]"
end
return retval
end
--------------------------------------------------------------------------------
function menu_handle_key_up_down(fields, textlist, settingname)
local oldidx, newidx = core.get_textlist_index(textlist), 1
if fields.key_up or fields.key_down then
if fields.key_up and oldidx and oldidx > 1 then
newidx = oldidx - 1
elseif fields.key_down and oldidx and
oldidx < menudata.worldlist:size() then
newidx = oldidx + 1
function menu_handle_key_up_down(fields,textlist,settingname)
if fields["key_up"] then
local oldidx = core.get_textlist_index(textlist)
if oldidx ~= nil and oldidx > 1 then
local newidx = oldidx -1
core.setting_set(settingname,
menudata.worldlist:get_raw_index(newidx))
end
core.setting_set(settingname, menudata.worldlist:get_raw_index(newidx))
configure_selected_world_params(newidx)
return true
end
if fields["key_down"] then
local oldidx = core.get_textlist_index(textlist)
if oldidx ~= nil and oldidx < menudata.worldlist:size() then
local newidx = oldidx + 1
core.setting_set(settingname,
menudata.worldlist:get_raw_index(newidx))
end
return true
end
return false
end
--------------------------------------------------------------------------------
function asyncOnlineFavourites()
if not menudata.public_known then
menudata.public_known = {{
name = fgettext("Loading..."),
description = fgettext_ne("Try reenabling public serverlist and check your internet connection.")
}}
end
menudata.favorites = menudata.public_known
menudata.favorites_is_public = true
if not menudata.public_downloading then
menudata.public_downloading = true
else
return
end
menudata.favorites = {}
core.handle_async(
function(param)
return core.get_favorites("online")
end,
nil,
function(result)
menudata.public_downloading = nil
local favs = order_favorite_list(result)
if favs[1] then
menudata.public_known = favs
menudata.favorites = menudata.public_known
menudata.favorites_is_public = true
if core.setting_getbool("public_serverlist") then
menudata.favorites = order_favorite_list(result)
core.event_handler("Refresh")
end
core.event_handler("Refresh")
end
)
)
end
--------------------------------------------------------------------------------
function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
local textlines = core.splittext(text, textlen)
local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
"," .. height .. ";" .. tl_name .. ";"
for i = 1, #textlines do
textlines[i] = textlines[i]:gsub("\r", "")
function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
local textlines = core.splittext(text,textlen)
local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
.. width .. "," .. height .. ";"
.. tl_name .. ";"
for i=1, #textlines, 1 do
textlines[i] = textlines[i]:gsub("\r","")
retval = retval .. core.formspec_escape(textlines[i]) .. ","
end
retval = retval .. ";0;"
if transparency then retval = retval .. "true" end
if transparency then
retval = retval .. "true"
end
retval = retval .. "]"
return retval
end
--------------------------------------------------------------------------------
function is_server_protocol_compat(server_proto_min, server_proto_max)
if (not server_proto_min) or (not server_proto_max) then
-- There is no info. Assume the best and act as if we would be compatible.
return true
end
return min_supp_proto <= server_proto_max and max_supp_proto >= server_proto_min
function is_server_protocol_compat(proto_min, proto_max)
return not ((min_supp_proto > (proto_max or 24)) or (max_supp_proto < (proto_min or 13)))
end
--------------------------------------------------------------------------------
function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
if not is_server_protocol_compat(server_proto_min, server_proto_max) then
local server_prot_ver_info, client_prot_ver_info
local s_p_min = server_proto_min
local s_p_max = server_proto_max
if s_p_min ~= s_p_max then
server_prot_ver_info = fgettext_ne("Server supports protocol versions between $1 and $2. ",
s_p_min, s_p_max)
else
server_prot_ver_info = fgettext_ne("Server enforces protocol version $1. ",
s_p_min)
end
if min_supp_proto ~= max_supp_proto then
client_prot_ver_info= fgettext_ne("We support protocol versions between version $1 and $2.",
min_supp_proto, max_supp_proto)
else
client_prot_ver_info = fgettext_ne("We only support protocol version $1.", min_supp_proto)
end
gamedata.errormessage = fgettext_ne("Protocol version mismatch. ")
.. server_prot_ver_info
.. client_prot_ver_info
function is_server_protocol_compat_or_error(proto_min, proto_max)
if not is_server_protocol_compat(proto_min, proto_max) then
gamedata.errormessage = fgettext_ne("Protocol version mismatch, server " ..
((proto_min ~= proto_max) and "supports protocols between $1 and $2" or "enforces protocol version $1") ..
", we " ..
((min_supp_proto ~= max_supp_proto) and "support protocols between version $3 and $4." or "only support protocol version $3"),
proto_min or 13, proto_max or 24, min_supp_proto, max_supp_proto)
return false
end
return true
end
--------------------------------------------------------------------------------
function menu_worldmt(selected, setting, value)
local world = menudata.worldlist:get_list()[selected]
if world then
local filename = world.path .. DIR_DELIM .. "world.mt"
local world_conf = Settings(filename)
if value then
if not world_conf:write() then
core.log("error", "Failed to write world config file")
end
world_conf:set(setting, value)
world_conf:write()
else
return world_conf:get(setting)
end
else
return nil
end
end
function menu_worldmt_legacy(selected)
local modes_names = {"creative_mode", "enable_damage", "server_announce"}
for _, mode_name in pairs(modes_names) do
local mode_val = menu_worldmt(selected, mode_name)
if mode_val then
core.setting_set(mode_name, mode_val)
else
menu_worldmt(selected, mode_name, core.setting_get(mode_name))
end
end
end

View File

@@ -16,9 +16,6 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
local enabled_all = false
local function modname_valid(name)
return not name:find("[^a-z0-9_]")
end
@@ -28,39 +25,34 @@ local function get_formspec(data)
local mod = data.list:get_list()[data.selected_mod]
local retval =
"size[11.5,7.5,true]" ..
"label[0.5,0;" .. fgettext("World:") .. "]" ..
"label[1.75,0;" .. data.worldspec.name .. "]"
"size[11,6.5,true]" ..
"label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
"label[1.75,-0.25;" .. data.worldspec.name .. "]"
if data.hide_gamemods then
retval = retval .. "checkbox[1,6;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
else
retval = retval .. "checkbox[1,6;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
end
if data.hide_modpackcontents then
retval = retval .. "checkbox[6,6;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
else
retval = retval .. "checkbox[6,6;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
end
if mod == nil then
mod = {name=""}
end
local hard_deps, soft_deps = modmgr.get_dependencies(mod.path)
retval = retval ..
"label[0,0.7;" .. fgettext("Mod:") .. "]" ..
"label[0.75,0.7;" .. mod.name .. "]" ..
"label[0,1.25;" .. fgettext("Dependencies:") .. "]" ..
"textlist[0,1.75;5,2.125;world_config_depends;" ..
hard_deps .. ";0]" ..
"label[0,3.875;" .. fgettext("Optional dependencies:") .. "]" ..
"textlist[0,4.375;5,1.8;world_config_optdepends;" ..
soft_deps .. ";0]" ..
"button[3.25,7;2.5,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
"button[5.75,7;2.5,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
"label[0,0.45;" .. fgettext("Mod:") .. "]" ..
"label[0.75,0.45;" .. mod.name .. "]" ..
"label[0,1;" .. fgettext("Depends:") .. "]" ..
"textlist[0,1.5;5,4.25;world_config_depends;" ..
modmgr.get_dependencies(mod.path) .. ";0]" ..
"button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
"button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
if mod.is_modpack then
@@ -76,27 +68,23 @@ local function get_formspec(data)
end
if all_enabled == false then
retval = retval .. "button[5.5,0.125;2.5,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
else
retval = retval .. "button[5.5,0.125;2.5,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
end
else
if mod.enabled then
retval = retval .. "checkbox[5.5,-0.125;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
else
retval = retval .. "checkbox[5.5,-0.125;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
end
end
end
if enabled_all then
retval = retval ..
"button[8.75,0.125;2.5,0.5;btn_disable_all_mods;" .. fgettext("Disable all") .. "]" ..
"textlist[5.5,0.75;5.75,5.4;world_config_modlist;"
else
retval = retval ..
"button[8.75,0.125;2.5,0.5;btn_enable_all_mods;" .. fgettext("Enable all") .. "]" ..
"textlist[5.5,0.75;5.75,5.4;world_config_modlist;"
end
retval = retval ..
"button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
"textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
retval = retval .. modmgr.render_modlist(data.list)
retval = retval .. ";" .. data.selected_mod .."]"
@@ -241,27 +229,15 @@ local function handle_buttons(this, fields)
return true
end
if fields.btn_enable_all_mods then
if fields["btn_all_mods"] then
local list = this.data.list:get_raw_list()
for i = 1, #list do
if list[i].typ ~= "game_mod" and not list[i].is_modpack then
for i=1,#list,1 do
if list[i].typ ~= "game_mod" and
not list[i].is_modpack then
list[i].enabled = true
end
end
enabled_all = true
return true
end
if fields.btn_disable_all_mods then
local list = this.data.list:get_raw_list()
for i = 1, #list do
if list[i].typ ~= "game_mod" and not list[i].is_modpack then
list[i].enabled = false
end
end
enabled_all = false
return true
end

View File

@@ -46,7 +46,7 @@ local function create_world_formspec(dialogdata)
current_seed = core.formspec_escape(current_seed)
local retval =
"size[11.5,6.5,true]" ..
"size[12,6,true]" ..
"label[2,0;" .. fgettext("World name") .. "]"..
"field[4.5,0.4;6,0.5;te_world_name;;]" ..
@@ -60,8 +60,8 @@ local function create_world_formspec(dialogdata)
"textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() ..
";" .. gameidx .. ";true]" ..
"button[3.25,6;2.5,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
"button[5.75,6;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
"button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
"button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
if #gamemgr.games == 0 then
retval = retval .. "box[2,4;8,1;#ff8800]label[2.25,4;" ..

View File

@@ -22,11 +22,10 @@ local function delete_mod_formspec(dialogdata)
dialogdata.mod = modmgr.global_mods:get_list()[dialogdata.selected]
local retval =
"size[11.5,4.5,true]" ..
"label[2,2;" ..
fgettext("Are you sure you want to delete \"$1\"?", dialogdata.mod.name) .. "]"..
"button[3.25,3.5;2.5,0.5;dlg_delete_mod_confirm;" .. fgettext("Delete") .. "]" ..
"button[5.75,3.5;2.5,0.5;dlg_delete_mod_cancel;" .. fgettext("Cancel") .. "]"
"size[12.4,5,true]" ..
"field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", dialogdata.mod.name) .. ";]"..
"button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
"button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
return retval
end

View File

@@ -19,11 +19,11 @@
local function delete_world_formspec(dialogdata)
local retval =
"size[11.5,4.5,true]" ..
"size[12,6,true]" ..
"label[2,2;" ..
fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
"button[3.25,3.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
"button[5.75,3.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]"..
"button[3.5,4.2;2.6,0.5;world_delete_confirm;" .. fgettext("Yes").. "]" ..
"button[6,4.2;2.8,0.5;world_delete_cancel;" .. fgettext("No") .. "]"
return retval
end

View File

@@ -22,12 +22,14 @@ local function rename_modpack_formspec(dialogdata)
dialogdata.mod = modmgr.global_mods:get_list()[dialogdata.selected]
local retval =
"size[11.5,4.5,true]" ..
"field[2.5,2;7,0.5;te_modpack_name;".. fgettext("Rename Modpack:") .. ";" ..
dialogdata.mod.name .. "]" ..
"button[3.25,3.5;2.5,0.5;dlg_rename_modpack_confirm;"..
"size[12.4,5,true]" ..
"label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
"field[4.5,1.4;6,0.5;te_modpack_name;;" ..
dialogdata.mod.name ..
"]" ..
"button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
fgettext("Accept") .. "]" ..
"button[5.75,3.5;2.5,0.5;dlg_rename_modpack_cancel;"..
"button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
fgettext("Cancel") .. "]"
return retval

View File

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

View File

@@ -1,99 +0,0 @@
local settings = ...
local concat = table.concat
local insert = table.insert
local sprintf = string.format
local rep = string.rep
local minetest_example_header = [[
# This file contains a list of all available settings and their default value for minetest.conf
# By default, all the settings are commented and not functional.
# Uncomment settings by removing the preceding #.
# minetest.conf is read by default from:
# ../minetest.conf
# ../../minetest.conf
# Any other path can be chosen by passing the path as a parameter
# to the program, eg. "minetest.exe --config ../minetest.conf.example".
# Further documentation:
# http://wiki.minetest.net/
]]
local function create_minetest_conf_example()
local result = { minetest_example_header }
for _, entry in ipairs(settings) do
if entry.type == "category" then
if entry.level == 0 then
insert(result, "#\n# " .. entry.name .. "\n#\n\n")
else
insert(result, rep("#", entry.level))
insert(result, "# " .. entry.name .. "\n\n")
end
else
if entry.comment ~= "" then
for _, comment_line in ipairs(entry.comment:split("\n", true)) do
insert(result, "# " .. comment_line .. "\n")
end
end
insert(result, "# type: " .. entry.type)
if entry.min then
insert(result, " min: " .. entry.min)
end
if entry.max then
insert(result, " max: " .. entry.max)
end
if entry.values then
insert(result, " values: " .. concat(entry.values, ", "))
end
if entry.possible then
insert(result, " possible values: " .. entry.possible:gsub(",", ", "))
end
insert(result, "\n")
local append
if entry.default ~= "" then
append = " " .. entry.default
end
insert(result, sprintf("# %s =%s\n\n", entry.name, append or ""))
end
end
return concat(result)
end
local translation_file_header = [[
// This file is automatically generated
// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files
// To update it, refer to the bottom of builtin/mainmenu/dlg_settings_advanced.lua
fake_function() {]]
local function create_translation_file()
local result = { translation_file_header }
for _, entry in ipairs(settings) do
if entry.type == "category" then
insert(result, sprintf("\tgettext(%q);", entry.name))
else
if entry.readable_name then
insert(result, sprintf("\tgettext(%q);", entry.readable_name))
end
if entry.comment ~= "" then
local comment_escaped = entry.comment:gsub("\n", "\\n")
comment_escaped = comment_escaped:gsub("\"", "\\\"")
insert(result, "\tgettext(\"" .. comment_escaped .. "\");")
end
end
end
insert(result, "}\n")
return concat(result, "\n")
end
local file = assert(io.open("minetest.conf.example", "w"))
file:write(create_minetest_conf_example())
file:close()
file = assert(io.open("src/settings_translation_file.cpp", "w"))
file:write(create_translation_file())
file:close()

View File

@@ -37,29 +37,22 @@ dofile(menupath .. DIR_DELIM .. "common.lua")
dofile(menupath .. DIR_DELIM .. "gamemgr.lua")
dofile(menupath .. DIR_DELIM .. "modmgr.lua")
dofile(menupath .. DIR_DELIM .. "store.lua")
dofile(menupath .. DIR_DELIM .. "textures.lua")
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua")
dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
if PLATFORM ~= "Android" then
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
end
local tabs = {}
tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
tabs.mods = dofile(menupath .. DIR_DELIM .. "tab_mods.lua")
tabs.credits = dofile(menupath .. DIR_DELIM .. "tab_credits.lua")
if PLATFORM == "Android" then
tabs.simple_main = dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua")
dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
dofile(menupath .. DIR_DELIM .. "tab_server.lua")
dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
dofile(menupath .. DIR_DELIM .. "textures.lua")
else
tabs.singleplayer = dofile(menupath .. DIR_DELIM .. "tab_singleplayer.lua")
tabs.multiplayer = dofile(menupath .. DIR_DELIM .. "tab_multiplayer.lua")
tabs.server = dofile(menupath .. DIR_DELIM .. "tab_server.lua")
tabs.texturepacks = dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua")
dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua")
end
--------------------------------------------------------------------------------
@@ -75,34 +68,8 @@ local function init_globals()
-- Init gamedata
gamedata.worldindex = 0
if PLATFORM == "Android" then
local world_list = core.get_worlds()
local world_index
local found_singleplayerworld = false
for i, world in ipairs(world_list) do
if world.name == "singleplayerworld" then
found_singleplayerworld = true
world_index = i
break
end
end
if not found_singleplayerworld then
core.create_world("singleplayerworld", 1)
world_list = core.get_worlds()
for i, world in ipairs(world_list) do
if world.name == "singleplayerworld" then
world_index = i
break
end
end
end
gamedata.worldindex = world_index
else
if PLATFORM ~= "Android" then
menudata.worldlist = filterlist.create(
core.get_worlds,
compare_worlds,
@@ -121,34 +88,64 @@ local function init_globals()
if not core.setting_get("menu_last_game") then
local default_game = core.setting_get("default_game") or "minetest"
core.setting_set("menu_last_game", default_game)
core.setting_set("menu_last_game", default_game )
end
mm_texture.init()
else
local world_list = core.get_worlds()
local found_singleplayerworld = false
for i,world in pairs(world_list) do
if world.name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
break
end
end
if not found_singleplayerworld then
core.create_world("singleplayerworld", 1)
local world_list = core.get_worlds()
for i,world in pairs(world_list) do
if world.name == "singleplayerworld" then
gamedata.worldindex = i
break
end
end
end
end
-- Create main tabview
local tv_main = tabview_create("maintab", {x = 12, y = 5.2}, {x = 0, y = 0})
if PLATFORM == "Android" then
tv_main:add(tabs.simple_main)
tv_main:add(tabs.settings)
else
local tv_main = tabview_create("maintab",{x=12,y=5.2},{x=0,y=0})
if PLATFORM ~= "Android" then
tv_main:set_autosave_tab(true)
tv_main:add(tabs.singleplayer)
tv_main:add(tabs.multiplayer)
tv_main:add(tabs.server)
tv_main:add(tabs.settings)
tv_main:add(tabs.texturepacks)
end
tv_main:add(tabs.mods)
tv_main:add(tabs.credits)
if PLATFORM ~= "Android" then
tv_main:add(tab_singleplayer)
tv_main:add(tab_multiplayer)
tv_main:add(tab_server)
else
tv_main:add(tab_simple_main)
end
tv_main:add(tab_settings)
if PLATFORM ~= "Android" then
tv_main:add(tab_texturepacks)
end
tv_main:add(tab_mods)
tv_main:add(tab_credits)
tv_main:set_global_event_handler(main_event_handler)
tv_main:set_fixed_size(false)
if PLATFORM ~= "Android" then
tv_main:set_fixed_size(true)
else
tv_main:set_fixed_size(false)
end
if not (PLATFORM == "Android") then
tv_main:set_tab(core.setting_get("maintab_LAST"))
end
ui.set_default("maintab")
@@ -156,9 +153,9 @@ local function init_globals()
-- Create modstore ui
if PLATFORM == "Android" then
modstore.init({x = 12, y = 6}, 3, 2)
modstore.init({x=12, y=6}, 3, 2)
else
modstore.init({x = 12, y = 8}, 4, 3)
modstore.init({x=12, y=8}, 4, 3)
end
ui.update()

View File

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

View File

@@ -17,31 +17,31 @@
--------------------------------------------------------------------------------
function get_mods(path,retval,modpack)
local mods = core.get_dir_list(path, true)
local mods = core.get_dirlist(path, true)
for _, name in ipairs(mods) do
if name:sub(1, 1) ~= "." then
local prefix = path .. DIR_DELIM .. name .. DIR_DELIM
for i=1, #mods, 1 do
if mods[i]:sub(1,1) ~= "." then
local toadd = {}
retval[#retval + 1] = toadd
local modpackfile = nil
local mod_conf = Settings(prefix .. "mod.conf"):to_table()
if mod_conf.name then
name = mod_conf.name
end
toadd.name = name
toadd.path = prefix
if modpack ~= nil and modpack ~= "" then
toadd.name = mods[i]
toadd.path = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
if modpack ~= nil and
modpack ~= "" then
toadd.modpack = modpack
else
local modpackfile = io.open(prefix .. "modpack.txt")
if modpackfile then
modpackfile:close()
toadd.is_modpack = true
get_mods(prefix, retval, name)
end
local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
local error = nil
modpackfile,error = io.open(filename,"r")
end
if modpackfile ~= nil then
modpackfile:close()
toadd.is_modpack = true
table.insert(retval,toadd)
get_mods(path .. DIR_DELIM .. mods[i],retval,mods[i])
else
table.insert(retval,toadd)
end
end
end
@@ -94,7 +94,7 @@ function modmgr.getbasefolder(temppath)
}
end
local subdirs = core.get_dir_list(temppath, true)
local subdirs = core.get_dirlist(temppath,true)
--only single mod or modpack allowed
if #subdirs ~= 1 then
@@ -284,33 +284,27 @@ end
--------------------------------------------------------------------------------
function modmgr.get_dependencies(modfolder)
local toadd_hard = ""
local toadd_soft = ""
local toadd = ""
if modfolder ~= nil then
local filename = modfolder ..
DIR_DELIM .. "depends.txt"
local hard_dependencies = {}
local soft_dependencies = {}
local dependencyfile = io.open(filename,"r")
if dependencyfile then
local dependency = dependencyfile:read("*l")
while dependency do
dependency = dependency:gsub("\r", "")
if string.sub(dependency, -1, -1) == "?" then
table.insert(soft_dependencies, string.sub(dependency, 1, -2))
else
table.insert(hard_dependencies, dependency)
if toadd ~= "" then
toadd = toadd .. ","
end
toadd = toadd .. dependency
dependency = dependencyfile:read()
end
dependencyfile:close()
end
toadd_hard = table.concat(hard_dependencies, ",")
toadd_soft = table.concat(soft_dependencies, ",")
end
return toadd_hard, toadd_soft
return toadd
end
--------------------------------------------------------------------------------
@@ -327,10 +321,8 @@ function modmgr.get_worldconfig(worldpath)
for key,value in pairs(worldfile:to_table()) do
if key == "gameid" then
worldconfig.id = value
elseif key:sub(0, 9) == "load_mod_" then
worldconfig.global_mods[key] = core.is_yes(value)
else
worldconfig[key] = value
worldconfig.global_mods[key] = core.is_yes(value)
end
end
@@ -418,7 +410,7 @@ function modmgr.preparemodlist(data)
for i=1,#global_mods,1 do
global_mods[i].typ = "global_mod"
retval[#retval + 1] = global_mods[i]
table.insert(retval,global_mods[i])
end
--read game mods
@@ -427,7 +419,7 @@ function modmgr.preparemodlist(data)
for i=1,#game_mods,1 do
game_mods[i].typ = "game_mod"
retval[#retval + 1] = game_mods[i]
table.insert(retval,game_mods[i])
end
if data.worldpath == nil then

View File

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

View File

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

View File

@@ -28,7 +28,7 @@ local function get_formspec(tabview, name, tabdata)
local retval =
"label[0.05,-0.25;".. fgettext("Installed Mods:") .. "]" ..
"textlist[0,0.25;5.1,5;modlist;" ..
"textlist[0,0.25;5.1,4.35;modlist;" ..
modmgr.render_modlist(modmgr.global_mods) ..
";" .. tabdata.selected_mod .. "]"
@@ -36,10 +36,7 @@ local function get_formspec(tabview, name, tabdata)
-- "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
-- TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
-- "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
-- TODO Disabled due to service being offline, and not likely to come online again, in this form
-- "button[0,4.85;5.25,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]"
""
"button[0,4.85;5.25,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]"
local selected_mod = nil
@@ -78,7 +75,7 @@ local function get_formspec(tabview, name, tabdata)
descriptionfile:close()
else
descriptionlines = {}
descriptionlines[#descriptionlines + 1] = fgettext("No mod description available")
table.insert(descriptionlines,fgettext("No mod description available"))
end
retval = retval ..
@@ -98,24 +95,12 @@ local function get_formspec(tabview, name, tabdata)
.. fgettext("Uninstall selected modpack") .. "]"
else
--show dependencies
local toadd_hard, toadd_soft = modmgr.get_dependencies(selected_mod.path)
if toadd_hard == "" and toadd_soft == "" then
retval = retval .. "," .. fgettext("No dependencies.")
else
if toadd_hard ~= "" then
retval = retval .. "," .. fgettext("Dependencies:") .. ","
retval = retval .. toadd_hard
end
if toadd_soft ~= "" then
if toadd_hard ~= "" then
retval = retval .. ","
end
retval = retval .. "," .. fgettext("Optional dependencies:") .. ","
retval = retval .. toadd_soft
end
end
retval = retval .. ";0]"
retval = retval .. "," .. fgettext("Depends:") .. ","
local toadd = modmgr.get_dependencies(selected_mod.path)
retval = retval .. toadd .. ";0]"
retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
.. fgettext("Uninstall selected mod") .. "]"
@@ -175,7 +160,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
end
--------------------------------------------------------------------------------
return {
tab_mods = {
name = "mods",
caption = fgettext("Mods"),
cbf_formspec = get_formspec,

View File

@@ -17,71 +17,68 @@
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
-- Update the cached supported proto info,
-- it may have changed after a change by the settings menu.
common_update_cached_supp_proto()
local fav_selected = menudata.favorites[tabdata.fav_selected]
local render_details = core.is_yes(core.setting_getbool("public_serverlist"))
local retval =
"label[7.75,-0.15;" .. fgettext("Address / Port") .. "]" ..
"label[7.75,1.05;" .. fgettext("Name / Password") .. "]" ..
"field[8,0.75;3.3,0.5;te_address;;" ..
core.formspec_escape(core.setting_get("address")) .. "]" ..
"field[11.15,0.75;1.4,0.5;te_port;;" ..
core.formspec_escape(core.setting_get("remote_port")) .. "]" ..
"button[10.1,4.9;2,0.5;btn_mp_connect;" .. fgettext("Connect") .. "]" ..
"field[8,1.95;2.95,0.5;te_name;;" ..
core.formspec_escape(core.setting_get("name")) .. "]" ..
"pwdfield[10.78,1.95;1.77,0.5;te_pwd;]" ..
"box[7.73,2.35;4.3,2.28;#999999]"
"label[7.75,-0.15;" .. fgettext("Address / Port :") .. "]" ..
"label[7.75,1.05;" .. fgettext("Name / Password :") .. "]" ..
"field[8,0.75;3.4,0.5;te_address;;" ..
core.formspec_escape(core.setting_get("address")) .. "]" ..
"field[11.25,0.75;1.3,0.5;te_port;;" ..
core.formspec_escape(core.setting_get("remote_port")) .. "]" ..
"checkbox[0,4.85;cb_public_serverlist;" .. fgettext("Public Serverlist") .. ";" ..
dump(core.setting_getbool("public_serverlist")) .. "]"
if tabdata.fav_selected and fav_selected then
if gamedata.fav then
retval = retval .. "button[7.85,4.9;2.3,0.5;btn_delete_favorite;" ..
fgettext("Del. Favorite") .. "]"
end
if fav_selected.description then
retval = retval .. "textarea[8.1,2.4;4.26,2.6;;" ..
core.formspec_escape((gamedata.serverdescription or ""), true) .. ";]"
end
if not core.setting_getbool("public_serverlist") then
retval = retval ..
"button[8,4.9;2,0.5;btn_delete_favorite;" .. fgettext("Delete") .. "]"
end
retval = retval ..
"button[10,4.9;2,0.5;btn_mp_connect;" .. fgettext("Connect") .. "]" ..
"field[8,1.95;2.95,0.5;te_name;;" ..
core.formspec_escape(core.setting_get("name")) .. "]" ..
"pwdfield[10.78,1.95;1.77,0.5;te_pwd;]" ..
"box[7.73,2.35;4.3,2.28;#999999]" ..
"textarea[8.1,2.4;4.26,2.6;;"
if tabdata.fav_selected ~= nil and
menudata.favorites[tabdata.fav_selected] ~= nil and
menudata.favorites[tabdata.fav_selected].description ~= nil then
retval = retval ..
core.formspec_escape(menudata.favorites[tabdata.fav_selected].description,true)
end
retval = retval ..
";]"
--favourites
retval = retval .. "tablecolumns[" ..
image_column(fgettext("Favorite"), "favorite") .. ";" ..
"color,span=3;" ..
"text,align=right;" .. -- clients
"text,align=center,padding=0.25;" .. -- "/"
"text,align=right,padding=0.25;" .. -- clients_max
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" ..
"table[-0.15,-0.1;7.75,5.5;favourites;"
if render_details then
retval = retval .. "tablecolumns[" ..
"color,span=3;" ..
"text,align=right;" .. -- clients
"text,align=center,padding=0.25;" .. -- "/"
"text,align=right,padding=0.25;" .. -- clients_max
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" -- name
else
retval = retval .. "tablecolumns[text]"
end
retval = retval ..
"table[-0.15,-0.1;7.75,5;favourites;"
if #menudata.favorites > 0 then
local favs = core.get_favorites("local")
if #favs > 0 then
for i = 1, #favs do
for j = 1, #menudata.favorites do
if menudata.favorites[j].address == favs[i].address and
menudata.favorites[j].port == favs[i].port then
table.insert(menudata.favorites, i, table.remove(menudata.favorites, j))
end
end
if favs[i].address ~= menudata.favorites[i].address then
table.insert(menudata.favorites, i, favs[i])
end
end
end
retval = retval .. render_favorite(menudata.favorites[1], (#favs > 0))
for i = 2, #menudata.favorites do
retval = retval .. "," .. render_favorite(menudata.favorites[i], (i <= #favs))
retval = retval .. render_favorite(menudata.favorites[1],render_details)
for i=2,#menudata.favorites,1 do
retval = retval .. "," .. render_favorite(menudata.favorites[i],render_details)
end
end
if tabdata.fav_selected then
if tabdata.fav_selected ~= nil then
retval = retval .. ";" .. tabdata.fav_selected .. "]"
else
retval = retval .. ";0]"
@@ -92,38 +89,36 @@ end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
if fields.te_name then
gamedata.playername = fields.te_name
core.setting_set("name", fields.te_name)
if fields["te_name"] ~= nil then
gamedata.playername = fields["te_name"]
core.setting_set("name", fields["te_name"])
end
if fields.favourites then
local event = core.explode_table_event(fields.favourites)
local fav = menudata.favorites[event.row]
if fields["favourites"] ~= nil then
local event = core.explode_table_event(fields["favourites"])
if event.type == "DCL" then
if event.row <= #menudata.favorites then
if menudata.favorites_is_public and
not is_server_protocol_compat_or_error(
fav.proto_min, fav.proto_max) then
if not is_server_protocol_compat_or_error(menudata.favorites[event.row].proto_min,
menudata.favorites[event.row].proto_max) then
return true
end
gamedata.address = fav.address
gamedata.port = fav.port
gamedata.playername = fields.te_name
gamedata.address = menudata.favorites[event.row].address
gamedata.port = menudata.favorites[event.row].port
gamedata.playername = fields["te_name"]
if fields["te_pwd"] ~= nil then
gamedata.password = fields["te_pwd"]
end
gamedata.selected_world = 0
if fields.te_pwd then
gamedata.password = fields.te_pwd
if menudata.favorites ~= nil then
gamedata.servername = menudata.favorites[event.row].name
gamedata.serverdescription = menudata.favorites[event.row].description
end
gamedata.servername = fav.name
gamedata.serverdescription = fav.description
if gamedata.address and gamedata.port then
core.setting_set("address", gamedata.address)
core.setting_set("remote_port", gamedata.port)
if gamedata.address ~= nil and
gamedata.port ~= nil then
core.setting_set("address",gamedata.address)
core.setting_set("remote_port",gamedata.port)
core.start()
end
end
@@ -132,92 +127,100 @@ local function main_button_handler(tabview, fields, name, tabdata)
if event.type == "CHG" then
if event.row <= #menudata.favorites then
gamedata.fav = false
local favs = core.get_favorites("local")
local address = fav.address
local port = fav.port
gamedata.serverdescription = fav.description
local address = menudata.favorites[event.row].address
local port = menudata.favorites[event.row].port
for i = 1, #favs do
if fav.address == favs[i].address and
fav.port == favs[i].port then
gamedata.fav = true
end
if address ~= nil and
port ~= nil then
core.setting_set("address",address)
core.setting_set("remote_port",port)
end
if address and port then
core.setting_set("address", address)
core.setting_set("remote_port", port)
end
tabdata.fav_selected = event.row
end
return true
end
end
if fields.key_up or fields.key_down then
local fav_idx = core.get_table_index("favourites")
local fav = menudata.favorites[fav_idx]
if fields["key_up"] ~= nil or
fields["key_down"] ~= nil then
if fav_idx then
if fields.key_up and fav_idx > 1 then
fav_idx = fav_idx - 1
elseif fields.key_down and fav_idx < #menudata.favorites then
fav_idx = fav_idx + 1
end
local fav_idx = core.get_table_index("favourites")
if fav_idx ~= nil then
if fields["key_up"] ~= nil and fav_idx > 1 then
fav_idx = fav_idx -1
else if fields["key_down"] and fav_idx < #menudata.favorites then
fav_idx = fav_idx +1
end end
else
fav_idx = 1
end
if not menudata.favorites or not fav then
if menudata.favorites == nil or
menudata.favorites[fav_idx] == nil then
tabdata.fav_selected = 0
return true
end
local address = menudata.favorites[fav_idx].address
local port = menudata.favorites[fav_idx].port
local address = fav.address
local port = fav.port
if address and port then
core.setting_set("address", address)
core.setting_set("remote_port", port)
if address ~= nil and
port ~= nil then
core.setting_set("address",address)
core.setting_set("remote_port",port)
end
tabdata.fav_selected = fav_idx
return true
end
if fields.btn_delete_favorite then
local current_favourite = core.get_table_index("favourites")
if not current_favourite then return end
if fields["cb_public_serverlist"] ~= nil then
core.setting_set("public_serverlist", fields["cb_public_serverlist"])
core.delete_favorite(current_favourite)
asyncOnlineFavourites()
if core.setting_getbool("public_serverlist") then
asyncOnlineFavourites()
else
menudata.favorites = core.get_favorites("local")
end
tabdata.fav_selected = nil
core.setting_set("address", "")
core.setting_set("remote_port", "30000")
return true
end
if (fields.btn_mp_connect or fields.key_enter) and fields.te_address and fields.te_port then
gamedata.playername = fields.te_name
gamedata.password = fields.te_pwd
gamedata.address = fields.te_address
gamedata.port = fields.te_port
gamedata.selected_world = 0
if fields["btn_delete_favorite"] ~= nil then
local current_favourite = core.get_table_index("favourites")
if current_favourite == nil then return end
core.delete_favorite(current_favourite)
menudata.favorites = order_favorite_list(core.get_favorites())
tabdata.fav_selected = nil
core.setting_set("address","")
core.setting_set("remote_port","30000")
return true
end
if fields["btn_mp_connect"] ~= nil or
fields["key_enter"] ~= nil then
gamedata.playername = fields["te_name"]
gamedata.password = fields["te_pwd"]
gamedata.address = fields["te_address"]
gamedata.port = fields["te_port"]
local fav_idx = core.get_table_index("favourites")
local fav = menudata.favorites[fav_idx]
if fav_idx and fav_idx <= #menudata.favorites and
fav.address == fields.te_address and
fav.port == fields.te_port then
if fav_idx ~= nil and fav_idx <= #menudata.favorites and
menudata.favorites[fav_idx].address == fields["te_address"] and
menudata.favorites[fav_idx].port == fields["te_port"] then
gamedata.servername = fav.name
gamedata.serverdescription = fav.description
gamedata.servername = menudata.favorites[fav_idx].name
gamedata.serverdescription = menudata.favorites[fav_idx].description
if menudata.favorites_is_public and
not is_server_protocol_compat_or_error(
fav.proto_min, fav.proto_max) then
if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
menudata.favorites[fav_idx].proto_max)then
return true
end
else
@@ -225,8 +228,10 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.serverdescription = ""
end
core.setting_set("address", fields.te_address)
core.setting_set("remote_port", fields.te_port)
gamedata.selected_world = 0
core.setting_set("address", fields["te_address"])
core.setting_set("remote_port",fields["te_port"])
core.start()
return true
@@ -234,16 +239,22 @@ local function main_button_handler(tabview, fields, name, tabdata)
return false
end
local function on_change(type, old_tab, new_tab)
if type == "LEAVE" then return end
asyncOnlineFavourites()
local function on_change(type,old_tab,new_tab)
if type == "LEAVE" then
return
end
if core.setting_getbool("public_serverlist") then
asyncOnlineFavourites()
else
menudata.favorites = core.get_favorites("local")
end
end
--------------------------------------------------------------------------------
return {
tab_multiplayer = {
name = "multiplayer",
caption = fgettext("Client"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_change
}
}

View File

@@ -67,9 +67,6 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["srv_worlds"] ~= nil then
local event = core.explode_textlist_event(fields["srv_worlds"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt_legacy(selected)
if event.type == "DCL" then
world_doubleclick = true
@@ -87,25 +84,16 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["cb_creative_mode"] then
core.setting_set("creative_mode", fields["cb_creative_mode"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"])
return true
end
if fields["cb_enable_damage"] then
core.setting_set("enable_damage", fields["cb_enable_damage"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"])
return true
end
if fields["cb_server_announce"] then
core.setting_set("server_announce", fields["cb_server_announce"])
local selected = core.get_textlist_index("srv_worlds")
menu_worldmt(selected, "server_announce", fields["cb_server_announce"])
return true
end
@@ -113,12 +101,12 @@ local function main_button_handler(this, fields, name, tabdata)
world_doubleclick or
fields["key_enter"] then
local selected = core.get_textlist_index("srv_worlds")
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
if selected ~= nil and gamedata.selected_world ~= 0 then
if selected ~= nil then
gamedata.playername = fields["te_playername"]
gamedata.password = fields["te_passwd"]
gamedata.port = fields["te_serverport"]
gamedata.address = ""
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
core.setting_set("port",gamedata.port)
if fields["te_serveraddr"] ~= nil then
@@ -127,17 +115,12 @@ local function main_button_handler(this, fields, name, tabdata)
--update last game
local world = menudata.worldlist:get_raw_element(gamedata.selected_world)
if world then
local game, index = gamemgr.find_by_gameid(world.gameid)
core.setting_set("menu_last_game", game.id)
end
local game,index = gamemgr.find_by_gameid(world.gameid)
core.setting_set("menu_last_game",game.id)
core.start()
else
gamedata.errormessage =
fgettext("No world created or selected!")
return true
end
return true
end
if fields["world_create"] ~= nil then
@@ -186,10 +169,10 @@ local function main_button_handler(this, fields, name, tabdata)
end
--------------------------------------------------------------------------------
return {
tab_server = {
name = "server",
caption = fgettext("Server"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = nil
}
}

View File

@@ -17,115 +17,69 @@
--------------------------------------------------------------------------------
local labels = {
leaves = {
fgettext("Opaque Leaves"),
fgettext("Simple Leaves"),
fgettext("Fancy Leaves")
},
node_highlighting = {
fgettext("Node Outlining"),
fgettext("Node Highlighting")
},
filters = {
fgettext("No Filter"),
fgettext("Bilinear Filter"),
fgettext("Trilinear Filter")
},
mipmap = {
fgettext("No Mipmap"),
fgettext("Mipmap"),
fgettext("Mipmap + Aniso. Filter")
},
antialiasing = {
fgettext("None"),
fgettext("2x"),
fgettext("4x"),
fgettext("8x")
}
local dd_filter_labels = {
fgettext("No Filter"),
fgettext("Bilinear Filter"),
fgettext("Trilinear Filter")
}
local dd_options = {
leaves = {
table.concat(labels.leaves, ","),
{"opaque", "simple", "fancy"}
},
node_highlighting = {
table.concat(labels.node_highlighting, ","),
{"box", "halo"}
},
filters = {
table.concat(labels.filters, ","),
{"", "bilinear_filter", "trilinear_filter"}
},
mipmap = {
table.concat(labels.mipmap, ","),
{"", "mip_map", "anisotropic_filter"}
},
antialiasing = {
table.concat(labels.antialiasing, ","),
{"0", "2", "4", "8"}
}
local filters = {
{dd_filter_labels[1]..","..dd_filter_labels[2]..","..dd_filter_labels[3]},
{"", "bilinear_filter", "trilinear_filter"},
}
local getSettingIndex = {
Leaves = function()
local style = core.setting_get("leaves_style")
for idx, name in pairs(dd_options.leaves[2]) do
if style == name then return idx end
end
return 1
end,
NodeHighlighting = function()
local style = core.setting_get("node_highlighting")
for idx, name in pairs(dd_options.node_highlighting[2]) do
if style == name then return idx end
end
return 1
end,
Filter = function()
if core.setting_get(dd_options.filters[2][3]) == "true" then
return 3
elseif core.setting_get(dd_options.filters[2][3]) == "false" and
core.setting_get(dd_options.filters[2][2]) == "true" then
return 2
end
return 1
end,
Mipmap = function()
if core.setting_get(dd_options.mipmap[2][3]) == "true" then
return 3
elseif core.setting_get(dd_options.mipmap[2][3]) == "false" and
core.setting_get(dd_options.mipmap[2][2]) == "true" then
return 2
end
return 1
end,
Antialiasing = function()
local antialiasing_setting = core.setting_get("fsaa")
for i = 1, #dd_options.antialiasing[2] do
if antialiasing_setting == dd_options.antialiasing[2][i] then
return i
end
end
return 1
local dd_mipmap_labels = {
fgettext("No Mipmap"),
fgettext("Mipmap"),
fgettext("Mipmap + Aniso. Filter")
}
local mipmap = {
{dd_mipmap_labels[1]..","..dd_mipmap_labels[2]..","..dd_mipmap_labels[3]},
{"", "mip_map", "anisotropic_filter"},
}
local function getFilterSettingIndex()
if (core.setting_get(filters[2][3]) == "true") then
return 3
end
}
if (core.setting_get(filters[2][3]) == "false" and core.setting_get(filters[2][2]) == "true") then
return 2
end
return 1
end
local function antialiasing_fname_to_name(fname)
for i = 1, #labels.antialiasing do
if fname == labels.antialiasing[i] then
return dd_options.antialiasing[2][i]
local function getMipmapSettingIndex()
if (core.setting_get(mipmap[2][3]) == "true") then
return 3
end
if (core.setting_get(mipmap[2][3]) == "false" and core.setting_get(mipmap[2][2]) == "true") then
return 2
end
return 1
end
local function video_driver_fname_to_name(selected_driver)
local video_drivers = core.get_video_drivers()
for i=1, #video_drivers do
if selected_driver == video_drivers[i].friendly_name then
return video_drivers[i].name:lower()
end
end
return 0
return ""
end
local function dlg_confirm_reset_formspec(data)
return "size[8,3]" ..
"label[1,1;" .. fgettext("Are you sure to reset your singleplayer world?") .. "]" ..
"button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;" .. fgettext("Yes") .. "]" ..
"button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;" .. fgettext("No") .. "]"
local retval =
"size[8,3]" ..
"label[1,1;".. fgettext("Are you sure to reset your singleplayer world?") .. "]"..
"button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;"..
fgettext("Yes") .. "]" ..
"button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;"..
fgettext("No!!!") .. "]"
return retval
end
local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
@@ -134,7 +88,7 @@ local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
local worldlist = core.get_worlds()
local found_singleplayerworld = false
for i = 1, #worldlist do
for i=1,#worldlist,1 do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
@@ -146,10 +100,12 @@ local function dlg_confirm_reset_btnhandler(this, fields, dialogdata)
end
core.create_world("singleplayerworld", 1)
worldlist = core.get_worlds()
found_singleplayerworld = false
for i = 1, #worldlist do
for i=1,#worldlist,1 do
if worldlist[i].name == "singleplayerworld" then
found_singleplayerworld = true
gamedata.worldindex = i
@@ -173,111 +129,150 @@ local function showconfirm_reset(tabview)
new_dlg:show()
end
local function gui_scale_to_scrollbar()
local current_value = tonumber(core.setting_get("gui_scaling"))
if (current_value == nil) or current_value < 0.25 then
return 0
end
if current_value <= 1.25 then
return ((current_value - 0.25)/ 1.0) * 700
end
if current_value <= 6 then
return ((current_value -1.25) * 100) + 700
end
return 1000
end
local function scrollbar_to_gui_scale(value)
value = tonumber(value)
if (value <= 700) then
return ((value / 700) * 1.0) + 0.25
end
if (value <=1000) then
return ((value - 700) / 100) + 1.25
end
return 1
end
local function formspec(tabview, name, tabdata)
local video_drivers = core.get_video_drivers()
local current_video_driver = core.setting_get("video_driver"):lower()
local driver_formspec_string = ""
local driver_current_idx = 0
for i=2, #video_drivers do
driver_formspec_string = driver_formspec_string .. video_drivers[i].friendly_name
if i ~= #video_drivers then
driver_formspec_string = driver_formspec_string .. ","
end
if current_video_driver == video_drivers[i].name:lower() then
driver_current_idx = i - 1
end
end
local tab_string =
"box[0,0;3.5,4.5;#999999]" ..
"checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting") .. ";"
.. dump(core.setting_getbool("smooth_lighting")) .. "]" ..
"checkbox[0.25,0.5;cb_particles;" .. fgettext("Particles") .. ";"
.. dump(core.setting_getbool("enable_particles")) .. "]" ..
"checkbox[0.25,1;cb_3d_clouds;" .. fgettext("3D Clouds") .. ";"
.. dump(core.setting_getbool("enable_3d_clouds")) .. "]" ..
"checkbox[0.25,1.5;cb_opaque_water;" .. fgettext("Opaque Water") .. ";"
.. dump(core.setting_getbool("opaque_water")) .. "]" ..
"checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";"
.. dump(core.setting_getbool("connected_glass")) .. "]" ..
"dropdown[0.25,2.8;3.3;dd_node_highlighting;" .. dd_options.node_highlighting[1] .. ";"
.. getSettingIndex.NodeHighlighting() .. "]" ..
"dropdown[0.25,3.6;3.3;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
.. getSettingIndex.Leaves() .. "]" ..
"box[0,0;3.5,3.9;#999999]" ..
"checkbox[0.25,0;cb_smooth_lighting;".. fgettext("Smooth Lighting")
.. ";".. dump(core.setting_getbool("smooth_lighting")) .. "]"..
"checkbox[0.25,0.5;cb_particles;".. fgettext("Enable Particles") .. ";"
.. dump(core.setting_getbool("enable_particles")) .. "]"..
"checkbox[0.25,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
.. dump(core.setting_getbool("enable_3d_clouds")) .. "]"..
"checkbox[0.25,1.5;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";"
.. dump(core.setting_getbool("new_style_leaves")) .. "]"..
"checkbox[0.25,2.0;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
.. dump(core.setting_getbool("opaque_water")) .. "]"..
"checkbox[0.25,2.5;cb_connected_glass;".. fgettext("Connected Glass") .. ";"
.. dump(core.setting_getbool("connected_glass")) .. "]"..
"checkbox[0.25,3.0;cb_node_highlighting;".. fgettext("Node Highlighting") .. ";"
.. dump(core.setting_getbool("enable_node_highlighting")) .. "]"..
"box[3.75,0;3.75,3.45;#999999]" ..
"label[3.85,0.1;" .. fgettext("Texturing:") .. "]" ..
"dropdown[3.85,0.55;3.85;dd_filters;" .. dd_options.filters[1] .. ";"
.. getSettingIndex.Filter() .. "]" ..
"dropdown[3.85,1.35;3.85;dd_mipmap;" .. dd_options.mipmap[1] .. ";"
.. getSettingIndex.Mipmap() .. "]" ..
"label[3.85,2.15;" .. fgettext("Antialiasing:") .. "]" ..
"dropdown[3.85,2.6;3.85;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
.. getSettingIndex.Antialiasing() .. "]" ..
"box[7.75,0;4,4.4;#999999]" ..
"checkbox[8,0;cb_shaders;" .. fgettext("Shaders") .. ";"
"label[3.85,0.1;".. fgettext("Texturing:") .. "]"..
"dropdown[3.85,0.55;3.85;dd_filters;" .. filters[1][1] .. ";"
.. getFilterSettingIndex() .. "]" ..
"dropdown[3.85,1.35;3.85;dd_mipmap;" .. mipmap[1][1] .. ";"
.. getMipmapSettingIndex() .. "]" ..
"label[3.85,2.15;".. fgettext("Rendering:") .. "]"..
"dropdown[3.85,2.6;3.85;dd_video_driver;"
.. driver_formspec_string .. ";" .. driver_current_idx .. "]" ..
"tooltip[dd_video_driver;" ..
fgettext("Restart minetest for driver change to take effect") .. "]" ..
"box[7.75,0;4,4;#999999]" ..
"checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
.. dump(core.setting_getbool("enable_shaders")) .. "]"
if PLATFORM ~= "Android" then
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
else
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_reset_singleplayer;".. fgettext("Reset singleplayer world") .. "]"
end
tab_string = tab_string ..
"box[0,4.25;3.5,1.1;#999999]" ..
"label[0.25,4.25;" .. fgettext("GUI scale factor") .. "]" ..
"scrollbar[0.25,4.75;3,0.4;sb_gui_scaling;horizontal;" ..
gui_scale_to_scrollbar() .. "]" ..
"tooltip[sb_gui_scaling;" ..
fgettext("Scaling factor applied to menu elements: ") ..
dump(core.setting_get("gui_scaling")) .. "]"
if PLATFORM == "Android" then
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_reset_singleplayer;"
.. fgettext("Reset singleplayer world") .. "]"
else
tab_string = tab_string ..
"button[8,4.75;3.75,0.5;btn_change_keys;"
.. fgettext("Change keys") .. "]"
"box[3.75,3.55;3.75,1.8;#999999]" ..
"checkbox[3.9,3.45;cb_touchscreen_target;".. fgettext("Touch free target") .. ";"
.. dump(core.setting_getbool("touchtarget")) .. "]"
end
tab_string = tab_string ..
"button[0,4.75;3.75,0.5;btn_advanced_settings;"
.. fgettext("Advanced Settings") .. "]"
if core.setting_get("touchscreen_threshold") ~= nil then
tab_string = tab_string ..
"label[4.3,4.1;" .. fgettext("Touchthreshold (px)") .. "]" ..
"dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;" ..
((tonumber(core.setting_get("touchscreen_threshold")) / 10) + 1) .. "]"
"label[4.3,4.1;" .. fgettext("Touchthreshold (px)") .. "]" ..
"dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;" ..
((tonumber(core.setting_get("touchscreen_threshold"))/10)+1) .. "]"
end
if core.setting_getbool("enable_shaders") then
tab_string = tab_string ..
"checkbox[8,0.5;cb_bumpmapping;" .. fgettext("Bump Mapping") .. ";"
.. dump(core.setting_getbool("enable_bumpmapping")) .. "]" ..
"checkbox[8,1;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
.. dump(core.setting_getbool("tone_mapping")) .. "]" ..
"checkbox[8,1.5;cb_generate_normalmaps;" .. fgettext("Normal Mapping") .. ";"
.. dump(core.setting_getbool("generate_normalmaps")) .. "]" ..
"checkbox[8,2;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
.. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]" ..
"checkbox[8,2.5;cb_waving_water;" .. fgettext("Waving Water") .. ";"
.. dump(core.setting_getbool("enable_waving_water")) .. "]" ..
"checkbox[8,3;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
.. dump(core.setting_getbool("enable_waving_leaves")) .. "]" ..
"checkbox[8,3.5;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
.. dump(core.setting_getbool("enable_waving_plants")) .. "]"
"checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
.. dump(core.setting_getbool("enable_bumpmapping")) .. "]"..
"checkbox[8,1.0;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";"
.. dump(core.setting_getbool("generate_normalmaps")) .. "]"..
"checkbox[8,1.5;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
.. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]"..
"checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";"
.. dump(core.setting_getbool("enable_waving_water")) .. "]"..
"checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
.. dump(core.setting_getbool("enable_waving_leaves")) .. "]"..
"checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
.. dump(core.setting_getbool("enable_waving_plants")) .. "]"
else
tab_string = tab_string ..
"tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[8.33,0.7;3.5,4;shaders;" ..
"#888888," .. fgettext("Bump Mapping") .. "," ..
"#888888," .. fgettext("Tone Mapping") .. "," ..
"#888888," .. fgettext("Normal Mapping") .. "," ..
"#888888," .. fgettext("Parallax Occlusion") .. "," ..
"#888888," .. fgettext("Waving Water") .. "," ..
"#888888," .. fgettext("Waving Leaves") .. "," ..
"#888888," .. fgettext("Waving Plants") .. "," ..
";1]"
end
"textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
"textlist[8.33,1.2;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" ..
"textlist[8.33,1.7;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
"textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
"textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
"textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
end
return tab_string
end
--------------------------------------------------------------------------------
local function handle_settings_buttons(this, fields, tabname, tabdata)
if fields["btn_advanced_settings"] ~= nil then
local adv_settings_dlg = create_adv_settings_dlg()
adv_settings_dlg:set_parent(this)
this:hide()
adv_settings_dlg:show()
--mm_texture.update("singleplayer", current_game())
if fields["cb_fancy_trees"] then
core.setting_set("new_style_leaves", fields["cb_fancy_trees"])
return true
end
if fields["cb_smooth_lighting"] then
core.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
return true
end
if fields["cb_particles"] then
core.setting_set("enable_particles", fields["cb_particles"])
return true
end
if fields["cb_3d_clouds"] then
core.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
return true
@@ -286,13 +281,8 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.setting_set("opaque_water", fields["cb_opaque_water"])
return true
end
if fields["cb_connected_glass"] then
core.setting_set("connected_glass", fields["cb_connected_glass"])
return true
end
if fields["cb_shaders"] then
if (core.setting_get("video_driver") == "direct3d8" or
core.setting_get("video_driver") == "direct3d9") then
if (core.setting_get("video_driver") == "direct3d8" or core.setting_get("video_driver") == "direct3d9") then
core.setting_set("enable_shaders", "false")
gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
else
@@ -300,17 +290,23 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
end
return true
end
if fields["cb_bumpmapping"] then
core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
if fields["cb_connected_glass"] then
core.setting_set("connected_glass", fields["cb_connected_glass"])
return true
end
if fields["cb_tonemapping"] then
core.setting_set("tone_mapping", fields["cb_tonemapping"])
if fields["cb_node_highlighting"] then
core.setting_set("enable_node_highlighting", fields["cb_node_highlighting"])
return true
end
if fields["cb_particles"] then
core.setting_set("enable_particles", fields["cb_particles"])
return true
end
if fields["cb_bumpmapping"] then
core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
end
if fields["cb_generate_normalmaps"] then
core.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"])
return true
end
if fields["cb_parallax"] then
core.setting_set("enable_parallax_occlusion", fields["cb_parallax"])
@@ -327,10 +323,20 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.setting_set("enable_waving_plants", fields["cb_waving_plants"])
return true
end
if fields["btn_change_keys"] then
if fields["btn_change_keys"] ~= nil then
core.show_keys_menu()
return true
end
if fields["sb_gui_scaling"] then
local event = core.explode_scrollbar_event(fields["sb_gui_scaling"])
if event.type == "CHG" then
local tosave = string.format("%.2f",scrollbar_to_gui_scale(event.value))
core.setting_set("gui_scaling",tosave)
return true
end
end
if fields["cb_touchscreen_target"] then
core.setting_set("touchtarget", fields["cb_touchscreen_target"])
return true
@@ -343,58 +349,51 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
--Note dropdowns have to be handled LAST!
local ddhandled = false
for i = 1, #labels.leaves do
if fields["dd_leaves_style"] == labels.leaves[i] then
core.setting_set("leaves_style", dd_options.leaves[2][i])
ddhandled = true
end
if fields["dd_touchthreshold"] then
core.setting_set("touchscreen_threshold",fields["dd_touchthreshold"])
ddhandled = true
end
for i = 1, #labels.node_highlighting do
if fields["dd_node_highlighting"] == labels.node_highlighting[i] then
core.setting_set("node_highlighting", dd_options.node_highlighting[2][i])
ddhandled = true
end
if fields["dd_video_driver"] then
core.setting_set("video_driver",
video_driver_fname_to_name(fields["dd_video_driver"]))
ddhandled = true
end
if fields["dd_filters"] == labels.filters[1] then
if fields["dd_filters"] == dd_filter_labels[1] then
core.setting_set("bilinear_filter", "false")
core.setting_set("trilinear_filter", "false")
ddhandled = true
elseif fields["dd_filters"] == labels.filters[2] then
end
if fields["dd_filters"] == dd_filter_labels[2] then
core.setting_set("bilinear_filter", "true")
core.setting_set("trilinear_filter", "false")
ddhandled = true
elseif fields["dd_filters"] == labels.filters[3] then
end
if fields["dd_filters"] == dd_filter_labels[3] then
core.setting_set("bilinear_filter", "false")
core.setting_set("trilinear_filter", "true")
ddhandled = true
end
if fields["dd_mipmap"] == labels.mipmap[1] then
if fields["dd_mipmap"] == dd_mipmap_labels[1] then
core.setting_set("mip_map", "false")
core.setting_set("anisotropic_filter", "false")
ddhandled = true
elseif fields["dd_mipmap"] == labels.mipmap[2] then
end
if fields["dd_mipmap"] == dd_mipmap_labels[2] then
core.setting_set("mip_map", "true")
core.setting_set("anisotropic_filter", "false")
ddhandled = true
elseif fields["dd_mipmap"] == labels.mipmap[3] then
end
if fields["dd_mipmap"] == dd_mipmap_labels[3] then
core.setting_set("mip_map", "true")
core.setting_set("anisotropic_filter", "true")
ddhandled = true
end
if fields["dd_antialiasing"] then
core.setting_set("fsaa",
antialiasing_fname_to_name(fields["dd_antialiasing"]))
ddhandled = true
end
if fields["dd_touchthreshold"] then
core.setting_set("touchscreen_threshold", fields["dd_touchthreshold"])
ddhandled = true
end
return ddhandled
end
return {
tab_settings = {
name = "settings",
caption = fgettext("Settings"),
cbf_formspec = formspec,

View File

@@ -17,184 +17,171 @@
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
-- Update the cached supported proto info,
-- it may have changed after a change by the settings menu.
common_update_cached_supp_proto()
local fav_selected = menudata.favorites[tabdata.fav_selected]
local retval = ""
local retval =
"label[9.5,0;".. fgettext("Name / Password") .. "]" ..
"field[0.25,3.35;5.5,0.5;te_address;;" ..
core.formspec_escape(core.setting_get("address")) .."]" ..
"field[5.75,3.35;2.25,0.5;te_port;;" ..
core.formspec_escape(core.setting_get("remote_port")) .."]" ..
"button[10,2.6;2,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
"field[9.8,1;2.6,0.5;te_name;;" ..
core.formspec_escape(core.setting_get("name")) .."]" ..
"pwdfield[9.8,2;2.6,0.5;te_pwd;]"
local render_details = dump(core.setting_getbool("public_serverlist"))
retval = retval ..
"label[8,0.5;".. fgettext("Name/Password") .. "]" ..
"field[0.25,3.25;5.5,0.5;te_address;;" ..
core.formspec_escape(core.setting_get("address")) .."]" ..
"field[5.75,3.25;2.25,0.5;te_port;;" ..
core.formspec_escape(core.setting_get("remote_port")) .."]" ..
"checkbox[8,-0.25;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
render_details .. "]"
if tabdata.fav_selected and fav_selected then
if gamedata.fav then
retval = retval .. "button[7.7,2.6;2.3,1.5;btn_delete_favorite;" ..
fgettext("Del. Favorite") .. "]"
end
retval = retval ..
"button[8,2.5;4,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
"field[8.75,1.5;3.5,0.5;te_name;;" ..
core.formspec_escape(core.setting_get("name")) .."]" ..
"pwdfield[8.75,2.3;3.5,0.5;te_pwd;]"
if render_details then
retval = retval .. "tablecolumns[" ..
"color,span=3;" ..
"text,align=right;" .. -- clients
"text,align=center,padding=0.25;" .. -- "/"
"text,align=right,padding=0.25;" .. -- clients_max
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" -- name
else
retval = retval .. "tablecolumns[text]"
end
retval = retval .. "tablecolumns[" ..
image_column(fgettext("Favorite"), "favorite") .. ";" ..
"color,span=3;" ..
"text,align=right;" .. -- clients
"text,align=center,padding=0.25;" .. -- "/"
"text,align=right,padding=0.25;" .. -- clients_max
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" .. -- name
"table[-0.05,0;9.2,2.75;favourites;"
retval = retval ..
"table[-0.05,0;7.55,2.75;favourites;"
if #menudata.favorites > 0 then
local favs = core.get_favorites("local")
if #favs > 0 then
for i = 1, #favs do
for j = 1, #menudata.favorites do
if menudata.favorites[j].address == favs[i].address and
menudata.favorites[j].port == favs[i].port then
table.insert(menudata.favorites, i,
table.remove(menudata.favorites, j))
end
end
if favs[i].address ~= menudata.favorites[i].address then
table.insert(menudata.favorites, i, favs[i])
end
end
end
retval = retval .. render_favorite(menudata.favorites[1], (#favs > 0))
for i = 2, #menudata.favorites do
retval = retval .. "," .. render_favorite(menudata.favorites[i], (i <= #favs))
retval = retval .. render_favorite(menudata.favorites[1],render_details)
for i=2,#menudata.favorites,1 do
retval = retval .. "," .. render_favorite(menudata.favorites[i],render_details)
end
end
if tabdata.fav_selected then
if tabdata.fav_selected ~= nil then
retval = retval .. ";" .. tabdata.fav_selected .. "]"
else
retval = retval .. ";0]"
end
-- separator
retval = retval .. "box[-0.28,3.75;12.4,0.1;#FFFFFF]"
retval = retval ..
"box[-0.3,3.75;12.4,0.1;#FFFFFF]"
-- checkboxes
retval = retval ..
"checkbox[8.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" ..
dump(core.setting_getbool("creative_mode")) .. "]"..
"checkbox[8.0,4.4;cb_damage;".. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]"
"checkbox[1.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" ..
dump(core.setting_getbool("creative_mode")) .. "]"..
"checkbox[5.0,3.9;cb_damage;".. fgettext("Enable Damage") .. ";" ..
dump(core.setting_getbool("enable_damage")) .. "]" ..
"checkbox[8,3.9;cb_fly_mode;".. fgettext("Fly mode") .. ";" ..
dump(core.setting_getbool("free_move")) .. "]"
-- buttons
retval = retval ..
"button[0,3.7;8,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" ..
"button[0,4.5;8,1.5;btn_config_sp_world;" .. fgettext("Config mods") .. "]"
"button[2.0,4.5;6,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" ..
"button[8.25,4.5;2.5,1.5;btn_config_sp_world;" .. fgettext("Config mods") .. "]"
return retval
end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
if fields.btn_start_singleplayer then
if fields["btn_start_singleplayer"] then
gamedata.selected_world = gamedata.worldindex
gamedata.singleplayer = true
core.start()
return true
end
if fields.favourites then
local event = core.explode_table_event(fields.favourites)
if fields["favourites"] ~= nil then
local event = core.explode_textlist_event(fields["favourites"])
if event.type == "CHG" then
if event.row <= #menudata.favorites then
gamedata.fav = false
local favs = core.get_favorites("local")
local fav = menudata.favorites[event.row]
local address = fav.address
local port = fav.port
gamedata.serverdescription = fav.description
if event.index <= #menudata.favorites then
local address = menudata.favorites[event.index].address
local port = menudata.favorites[event.index].port
for i = 1, #favs do
if fav.address == favs[i].address and
fav.port == favs[i].port then
gamedata.fav = true
end
if address ~= nil and
port ~= nil then
core.setting_set("address",address)
core.setting_set("remote_port",port)
end
if address and port then
core.setting_set("address", address)
core.setting_set("remote_port", port)
end
tabdata.fav_selected = event.row
tabdata.fav_selected = event.index
end
return true
end
end
if fields.btn_delete_favorite then
local current_favourite = core.get_table_index("favourites")
if not current_favourite then return end
core.delete_favorite(current_favourite)
asyncOnlineFavourites()
tabdata.fav_selected = nil
core.setting_set("address", "")
core.setting_set("remote_port", "30000")
return true
end
if fields.cb_creative then
core.setting_set("creative_mode", fields.cb_creative)
if fields["cb_public_serverlist"] ~= nil then
core.setting_set("public_serverlist", fields["cb_public_serverlist"])
if core.setting_getbool("public_serverlist") then
asyncOnlineFavourites()
else
menudata.favorites = core.get_favorites("local")
end
return true
end
if fields.cb_damage then
core.setting_set("enable_damage", fields.cb_damage)
if fields["cb_creative"] then
core.setting_set("creative_mode", fields["cb_creative"])
return true
end
if fields.btn_mp_connect or fields.key_enter then
gamedata.playername = fields.te_name
gamedata.password = fields.te_pwd
gamedata.address = fields.te_address
gamedata.port = fields.te_port
if fields["cb_damage"] then
core.setting_set("enable_damage", fields["cb_damage"])
return true
end
if fields["cb_fly_mode"] then
core.setting_set("free_move", fields["cb_fly_mode"])
return true
end
if fields["btn_mp_connect"] ~= nil or
fields["key_enter"] ~= nil then
gamedata.playername = fields["te_name"]
gamedata.password = fields["te_pwd"]
gamedata.address = fields["te_address"]
gamedata.port = fields["te_port"]
local fav_idx = core.get_textlist_index("favourites")
if fav_idx and fav_idx <= #menudata.favorites and
menudata.favorites[fav_idx].address == fields.te_address and
menudata.favorites[fav_idx].port == fields.te_port then
local fav = menudata.favorites[fav_idx]
gamedata.servername = fav.name
gamedata.serverdescription = fav.description
if fav_idx ~= nil and fav_idx <= #menudata.favorites and
menudata.favorites[fav_idx].address == fields["te_address"] and
menudata.favorites[fav_idx].port == fields["te_port"] then
if menudata.favorites_is_public and
not is_server_protocol_compat_or_error(
fav.proto_min, fav.proto_max) then
gamedata.servername = menudata.favorites[fav_idx].name
gamedata.serverdescription = menudata.favorites[fav_idx].description
if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
menudata.favorites[fav_idx].proto_max) then
return true
end
else
gamedata.servername = ""
gamedata.serverdescription = ""
gamedata.servername = ""
gamedata.serverdescription = ""
end
gamedata.selected_world = 0
core.setting_set("address", fields.te_address)
core.setting_set("remote_port", fields.te_port)
core.setting_set("address",fields["te_address"])
core.setting_set("remote_port",fields["te_port"])
core.start()
return true
end
if fields.btn_config_sp_world then
if fields["btn_config_sp_world"] ~= nil then
local configdialog = create_configure_world_dlg(1)
if configdialog then
if (configdialog ~= nil) then
configdialog:set_parent(tabview)
tabview:hide()
configdialog:show()
@@ -205,15 +192,21 @@ end
--------------------------------------------------------------------------------
local function on_activate(type,old_tab,new_tab)
if type == "LEAVE" then return end
asyncOnlineFavourites()
if type == "LEAVE" then
return
end
if core.setting_getbool("public_serverlist") then
asyncOnlineFavourites()
else
menudata.favorites = core.get_favorites("local")
end
end
--------------------------------------------------------------------------------
return {
tab_simple_main = {
name = "main",
caption = fgettext("Main"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_activate
}
}

View File

@@ -23,9 +23,9 @@ local function current_game()
end
local function singleplayer_refresh_gamebar()
local old_bar = ui.find_by_name("game_button_bar")
if old_bar ~= nil then
old_bar:delete()
end
@@ -38,17 +38,6 @@ local function singleplayer_refresh_gamebar()
core.set_topleft_text(gamemgr.games[j].name)
core.setting_set("menu_last_game",gamemgr.games[j].id)
menudata.worldlist:set_filtercriteria(gamemgr.games[j].id)
local index = filterlist.get_current_index(menudata.worldlist,
tonumber(core.setting_get("mainmenu_last_selected_world")))
if not index or index < 1 then
local selected = core.get_textlist_index("sp_worlds")
if selected ~= nil and selected < #menudata.worldlist:get_list() then
index = selected
else
index = #menudata.worldlist:get_list()
end
end
menu_worldmt_legacy(index)
return true
end
end
@@ -87,7 +76,7 @@ end
local function get_formspec(tabview, name, tabdata)
local retval = ""
local index = filterlist.get_current_index(menudata.worldlist,
tonumber(core.setting_get("mainmenu_last_selected_world"))
)
@@ -116,17 +105,14 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["sp_worlds"] ~= nil then
local event = core.explode_textlist_event(fields["sp_worlds"])
local selected = core.get_textlist_index("sp_worlds")
menu_worldmt_legacy(selected)
if event.type == "DCL" then
world_doubleclick = true
end
if event.type == "CHG" and selected ~= nil then
if event.type == "CHG" then
core.setting_set("mainmenu_last_selected_world",
menudata.worldlist:get_raw_index(selected))
menudata.worldlist:get_raw_index(core.get_textlist_index("sp_worlds")))
return true
end
end
@@ -137,17 +123,11 @@ local function main_button_handler(this, fields, name, tabdata)
if fields["cb_creative_mode"] then
core.setting_set("creative_mode", fields["cb_creative_mode"])
local selected = core.get_textlist_index("sp_worlds")
menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"])
return true
end
if fields["cb_enable_damage"] then
core.setting_set("enable_damage", fields["cb_enable_damage"])
local selected = core.get_textlist_index("sp_worlds")
menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"])
return true
end
@@ -155,14 +135,12 @@ local function main_button_handler(this, fields, name, tabdata)
world_doubleclick or
fields["key_enter"] then
local selected = core.get_textlist_index("sp_worlds")
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
if selected ~= nil and gamedata.selected_world ~= 0 then
gamedata.singleplayer = true
if selected ~= nil then
gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
gamedata.singleplayer = true
core.start()
else
gamedata.errormessage =
fgettext("No world created or selected!")
end
return true
end
@@ -241,10 +219,10 @@ local function on_change(type, old_tab, new_tab)
end
--------------------------------------------------------------------------------
return {
tab_singleplayer = {
name = "singleplayer",
caption = fgettext("Singleplayer"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_change
}
}

View File

@@ -17,17 +17,12 @@
--------------------------------------------------------------------------------
local function filter_texture_pack_list(list)
local retval = {}
local retval = {"None"}
for _, item in ipairs(list) do
if item ~= "base" then
retval[#retval + 1] = item
table.insert(retval, item)
end
end
table.sort(retval)
table.insert(retval, 1, fgettext("None"))
return retval
end
@@ -36,9 +31,9 @@ local function render_texture_pack_list(list)
local retval = ""
for i, v in ipairs(list) do
if v:sub(1, 1) ~= "." then
if v:sub(1,1) ~= "." then
if retval ~= "" then
retval = retval .. ","
retval = retval ..","
end
retval = retval .. core.formspec_escape(v)
@@ -50,15 +45,15 @@ end
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
local retval = "label[4,-0.25;" .. fgettext("Select texture pack:") .. "]" ..
local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
"textlist[4,0.25;7.5,5.0;TPs;"
local current_texture_path = core.setting_get("texture_path")
local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true))
local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true))
local index = tonumber(core.setting_get("mainmenu_last_selected_TP"))
if not index then index = 1 end
if index == nil then index = 1 end
if current_texture_path == "" then
retval = retval ..
@@ -67,27 +62,18 @@ local function get_formspec(tabview, name, tabdata)
return retval
end
local infofile = current_texture_path .. DIR_DELIM .. "description.txt"
-- This adds backwards compatibility for old texture pack description files named
-- "info.txt", and should be removed once all such texture packs have been updated
if not file_exists(infofile) then
infofile = current_texture_path .. DIR_DELIM .. "info.txt"
if file_exists(infofile) then
core.log("deprecated", "info.txt is deprecated. description.txt should be used instead.")
end
end
local infofile = current_texture_path ..DIR_DELIM.."info.txt"
local infotext = ""
local f = io.open(infofile, "r")
if not f then
if f==nil then
infotext = fgettext("No information available")
else
infotext = f:read("*all")
f:close()
end
local screenfile = current_texture_path .. DIR_DELIM .. "screenshot.png"
local no_screenshot
local screenfile = current_texture_path..DIR_DELIM.."screenshot.png"
local no_screenshot = nil
if not file_exists(screenfile) then
screenfile = nil
no_screenshot = defaulttexturedir .. "no_screenshot.png"
@@ -96,24 +82,24 @@ local function get_formspec(tabview, name, tabdata)
return retval ..
render_texture_pack_list(list) ..
";" .. index .. "]" ..
"image[0.25,0.25;4.05,2.7;" .. core.formspec_escape(screenfile or no_screenshot) .. "]" ..
"textarea[0.6,2.85;3.7,1.5;;" .. core.formspec_escape(infotext or "") .. ";]"
"image[0.25,0.25;4.0,3.7;"..core.formspec_escape(screenfile or no_screenshot).."]"..
"textarea[0.6,3.25;3.7,1.5;;"..core.formspec_escape(infotext or "")..";]"
end
--------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
if fields["TPs"] then
if fields["TPs"] ~= nil then
local event = core.explode_textlist_event(fields["TPs"])
if event.type == "CHG" or event.type == "DCL" then
local index = core.get_textlist_index("TPs")
core.setting_set("mainmenu_last_selected_TP", index)
local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true))
core.setting_set("mainmenu_last_selected_TP",
index)
local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true))
local current_index = core.get_textlist_index("TPs")
if current_index and #list >= current_index then
local new_path = core.get_texturepath() .. DIR_DELIM .. list[current_index]
if list[current_index] == fgettext("None") then
new_path = ""
end
if current_index ~= nil and #list >= current_index then
local new_path = core.get_texturepath()..DIR_DELIM..list[current_index]
if list[current_index] == "None" then new_path = "" end
core.setting_set("texture_path", new_path)
end
end
@@ -123,10 +109,10 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
--------------------------------------------------------------------------------
return {
tab_texturepacks = {
name = "texturepacks",
caption = fgettext("Texturepacks"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = nil
}
}

View File

@@ -129,7 +129,7 @@ function mm_texture.set_generic(identifier)
end
--------------------------------------------------------------------------------
function mm_texture.set_game(identifier, gamedetails)
function mm_texture.set_game(identifier,gamedetails)
if gamedetails == nil then
return false
@@ -137,34 +137,15 @@ function mm_texture.set_game(identifier, gamedetails)
if mm_texture.texturepack ~= nil then
local path = mm_texture.texturepack .. DIR_DELIM ..
gamedetails.id .. "_menu_" .. identifier .. ".png"
if core.set_background(identifier, path) then
gamedetails.id .. "_menu_" .. identifier .. ".png"
if core.set_background(identifier,path) then
return true
end
end
-- Find out how many randomized textures the subgame provides
local n = 0
local filename
local menu_files = core.get_dir_list(gamedetails.path .. DIR_DELIM .. "menu", false)
for i = 1, #menu_files do
filename = identifier .. "." .. i .. ".png"
if table.indexof(menu_files, filename) == -1 then
n = i - 1
break
end
end
-- Select random texture, 0 means standard texture
n = math.random(0, n)
if n == 0 then
filename = identifier .. ".png"
else
filename = identifier .. "." .. n .. ".png"
end
local path = gamedetails.path .. DIR_DELIM .. "menu" ..
DIR_DELIM .. filename
if core.set_background(identifier, path) then
local path = gamedetails.path .. DIR_DELIM .."menu" ..
DIR_DELIM .. identifier .. ".png"
if core.set_background(identifier,path) then
return true
end
@@ -179,7 +160,7 @@ function mm_texture.set_dirt_bg()
end
end
-- Use universal fallback texture in textures/base/pack
local minimalpath = defaulttexturedir .. "menu_bg.png"
--use base pack
local minimalpath = defaulttexturedir .. "dirt_bg.png"
core.set_background("background", minimalpath, true, 128)
end

View File

@@ -1,72 +0,0 @@
--Minetest
--Copyright (C) 2016 T4im
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local profiler_path = core.get_builtin_path()..DIR_DELIM.."profiler"..DIR_DELIM
local profiler = {}
local sampler = assert(loadfile(profiler_path .. "sampling.lua"))(profiler)
local instrumentation = assert(loadfile(profiler_path .. "instrumentation.lua"))(profiler, sampler)
local reporter = dofile(profiler_path .. "reporter.lua")
profiler.instrument = instrumentation.instrument
---
-- Delayed registration of the /profiler chat command
-- Is called later, after `core.register_chatcommand` was set up.
--
function profiler.init_chatcommand()
local instrument_profiler = core.setting_getbool("instrument.profiler") or false
if instrument_profiler then
instrumentation.init_chatcommand()
end
local param_usage = "print [filter] | dump [filter] | save [format [filter]] | reset"
core.register_chatcommand("profiler", {
description = "handle the profiler and profiling data",
params = param_usage,
privs = { server=true },
func = function(name, param)
local command, arg0 = string.match(param, "([^ ]+) ?(.*)")
local args = arg0 and string.split(arg0, " ")
if command == "dump" then
core.log("action", reporter.print(sampler.profile, arg0))
return true, "Statistics written to action log"
elseif command == "print" then
return true, reporter.print(sampler.profile, arg0)
elseif command == "save" then
return reporter.save(sampler.profile, args[1] or "txt", args[2])
elseif command == "reset" then
sampler.reset()
return true, "Statistics were reset"
end
return false, string.format(
"Usage: %s\n" ..
"Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).",
param_usage
)
end
})
if not instrument_profiler then
instrumentation.init_chatcommand()
end
end
sampler.init()
instrumentation.init()
return profiler

View File

@@ -1,232 +0,0 @@
--Minetest
--Copyright (C) 2016 T4im
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local format, pairs, type = string.format, pairs, type
local core, get_current_modname = core, core.get_current_modname
local profiler, sampler = ...
local instrument_builtin = core.setting_getbool("instrument.builtin") or false
local register_functions = {
register_globalstep = 0,
register_playerevent = 0,
register_on_placenode = 0,
register_on_dignode = 0,
register_on_punchnode = 0,
register_on_generated = 0,
register_on_newplayer = 0,
register_on_dieplayer = 0,
register_on_respawnplayer = 0,
register_on_prejoinplayer = 0,
register_on_joinplayer = 0,
register_on_leaveplayer = 0,
register_on_cheat = 0,
register_on_chat_message = 0,
register_on_player_receive_fields = 0,
register_on_craft = 0,
register_craft_predict = 0,
register_on_protection_violation = 0,
register_on_item_eat = 0,
register_on_punchplayer = 0,
register_on_player_hpchange = 0,
}
---
-- Create an unique instrument name.
-- Generate a missing label with a running index number.
--
local counts = {}
local function generate_name(def)
local class, label, func_name = def.class, def.label, def.func_name
if label then
if class or func_name then
return format("%s '%s' %s", class or "", label, func_name or ""):trim()
end
return format("%s", label):trim()
elseif label == false then
return format("%s", class or func_name):trim()
end
local index_id = def.mod .. (class or func_name)
local index = counts[index_id] or 1
counts[index_id] = index + 1
return format("%s[%d] %s", class or func_name, index, class and func_name or ""):trim()
end
---
-- Keep `measure` and the closure in `instrument` lean, as these, and their
-- directly called functions are the overhead that is caused by instrumentation.
--
local time, log = core.get_us_time, sampler.log
local function measure(modname, instrument_name, start, ...)
log(modname, instrument_name, time() - start)
return ...
end
--- Automatically instrument a function to measure and log to the sampler.
-- def = {
-- mod = "",
-- class = "",
-- func_name = "",
-- -- if nil, will create a label based on registration order
-- label = "" | false,
-- }
local function instrument(def)
if not def or not def.func then
return
end
def.mod = def.mod or get_current_modname()
local modname = def.mod
local instrument_name = generate_name(def)
local func = def.func
if not instrument_builtin and modname == "*builtin*" then
return func
end
return function(...)
-- This tail-call allows passing all return values of `func`
-- also called https://en.wikipedia.org/wiki/Continuation_passing_style
-- Compared to table creation and unpacking it won't lose `nil` returns
-- and is expected to be faster
-- `measure` will be executed after time() and func(...)
return measure(modname, instrument_name, time(), func(...))
end
end
local function can_be_called(func)
-- It has to be a function or callable table
return type(func) == "function" or
((type(func) == "table" or type(func) == "userdata") and
getmetatable(func) and getmetatable(func).__call)
end
local function assert_can_be_called(func, func_name, level)
if not can_be_called(func) then
-- Then throw an *helpful* error, by pointing on our caller instead of us.
error(format("Invalid argument to %s. Expected function-like type instead of '%s'.", func_name, type(func)), level + 1)
end
end
---
-- Wraps a registration function `func` in such a way,
-- that it will automatically instrument any callback function passed as first argument.
--
local function instrument_register(func, func_name)
local register_name = func_name:gsub("^register_", "", 1)
return function(callback, ...)
assert_can_be_called(callback, func_name, 2)
register_functions[func_name] = register_functions[func_name] + 1
return func(instrument {
func = callback,
func_name = register_name
}), ...
end
end
local function init_chatcommand()
if core.setting_getbool("instrument.chatcommand") or true then
local orig_register_chatcommand = core.register_chatcommand
core.register_chatcommand = function(cmd, def)
def.func = instrument {
func = def.func,
label = "/" .. cmd,
}
orig_register_chatcommand(cmd, def)
end
end
end
---
-- Start instrumenting selected functions
--
local function init()
local is_set = core.setting_getbool
if is_set("instrument.entity") or true then
-- Explicitly declare entity api-methods.
-- Simple iteration would ignore lookup via __index.
local entity_instrumentation = {
"on_activate",
"on_step",
"on_punch",
"rightclick",
"get_staticdata",
}
-- Wrap register_entity() to instrument them on registration.
local orig_register_entity = core.register_entity
core.register_entity = function(name, prototype)
local modname = get_current_modname()
for _, func_name in pairs(entity_instrumentation) do
prototype[func_name] = instrument {
func = prototype[func_name],
mod = modname,
func_name = func_name,
label = prototype.label,
}
end
orig_register_entity(name,prototype)
end
end
if is_set("instrument.abm") or true then
-- Wrap register_abm() to automatically instrument abms.
local orig_register_abm = core.register_abm
core.register_abm = function(spec)
spec.action = instrument {
func = spec.action,
class = "ABM",
label = spec.label,
}
orig_register_abm(spec)
end
end
if is_set("instrument.lbm") or true then
-- Wrap register_lbm() to automatically instrument lbms.
local orig_register_lbm = core.register_lbm
core.register_lbm = function(spec)
spec.action = instrument {
func = spec.action,
class = "LBM",
label = spec.label or spec.name,
}
orig_register_lbm(spec)
end
end
if is_set("instrument.global_callback") or true then
for func_name, _ in pairs(register_functions) do
core[func_name] = instrument_register(core[func_name], func_name)
end
end
if is_set("instrument.profiler") or false then
-- Measure overhead of instrumentation, but keep it down for functions
-- So keep the `return` for better optimization.
profiler.empty_instrument = instrument {
func = function() return end,
mod = "*profiler*",
class = "Instrumentation overhead",
label = false,
}
end
end
return {
register_functions = register_functions,
instrument = instrument,
init = init,
init_chatcommand = init_chatcommand,
}

View File

@@ -1,277 +0,0 @@
--Minetest
--Copyright (C) 2016 T4im
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local DIR_DELIM, LINE_DELIM = DIR_DELIM, "\n"
local table, unpack, string, pairs, io, os = table, unpack, string, pairs, io, os
local rep, sprintf, tonumber = string.rep, string.format, tonumber
local core, setting_get = core, core.setting_get
local reporter = {}
---
-- Shorten a string. End on an ellipsis if shortened.
--
local function shorten(str, length)
if str and str:len() > length then
return "..." .. str:sub(-(length-3))
end
return str
end
local function filter_matches(filter, text)
return not filter or string.match(text, filter)
end
local function format_number(number, fmt)
number = tonumber(number)
if not number then
return "N/A"
end
return sprintf(fmt or "%d", number)
end
local Formatter = {
new = function(self, object)
object = object or {}
object.out = {} -- output buffer
self.__index = self
return setmetatable(object, self)
end,
__tostring = function (self)
return table.concat(self.out, LINE_DELIM)
end,
print = function(self, text, ...)
if (...) then
text = sprintf(text, ...)
end
if text then
-- Avoid format unicode issues.
text = text:gsub("Ms", "µs")
end
table.insert(self.out, text or LINE_DELIM)
end,
flush = function(self)
table.insert(self.out, LINE_DELIM)
local text = table.concat(self.out, LINE_DELIM)
self.out = {}
return text
end
}
local widths = { 55, 9, 9, 9, 5, 5, 5 }
local txt_row_format = sprintf(" %%-%ds | %%%ds | %%%ds | %%%ds | %%%ds | %%%ds | %%%ds", unpack(widths))
local HR = {}
for i=1, #widths do
HR[i]= rep("-", widths[i])
end
-- ' | ' should break less with github than '-+-', when people are pasting there
HR = sprintf("-%s-", table.concat(HR, " | "))
local TxtFormatter = Formatter:new {
format_row = function(self, modname, instrument_name, statistics)
local label
if instrument_name then
label = shorten(instrument_name, widths[1] - 5)
label = sprintf(" - %s %s", label, rep(".", widths[1] - 5 - label:len()))
else -- Print mod_stats
label = shorten(modname, widths[1] - 2) .. ":"
end
self:print(txt_row_format, label,
format_number(statistics.time_min),
format_number(statistics.time_max),
format_number(statistics:get_time_avg()),
format_number(statistics.part_min, "%.1f"),
format_number(statistics.part_max, "%.1f"),
format_number(statistics:get_part_avg(), "%.1f")
)
end,
format = function(self, filter)
local profile = self.profile
self:print("Values below show absolute/relative times spend per server step by the instrumented function.")
self:print("A total of %d samples were taken", profile.stats_total.samples)
if filter then
self:print("The output is limited to '%s'", filter)
end
self:print()
self:print(
txt_row_format,
"instrumentation", "min Ms", "max Ms", "avg Ms", "min %", "max %", "avg %"
)
self:print(HR)
for modname,mod_stats in pairs(profile.stats) do
if filter_matches(filter, modname) then
self:format_row(modname, nil, mod_stats)
if mod_stats.instruments ~= nil then
for instrument_name, instrument_stats in pairs(mod_stats.instruments) do
self:format_row(nil, instrument_name, instrument_stats)
end
end
end
end
self:print(HR)
if not filter then
self:format_row("total", nil, profile.stats_total)
end
end
}
local CsvFormatter = Formatter:new {
format_row = function(self, modname, instrument_name, statistics)
self:print(
"%q,%q,%d,%d,%d,%d,%d,%f,%f,%f",
modname, instrument_name,
statistics.samples,
statistics.time_min,
statistics.time_max,
statistics:get_time_avg(),
statistics.time_all,
statistics.part_min,
statistics.part_max,
statistics:get_part_avg()
)
end,
format = function(self, filter)
self:print(
"%q,%q,%q,%q,%q,%q,%q,%q,%q,%q",
"modname", "instrumentation",
"samples",
"time min µs",
"time max µs",
"time avg µs",
"time all µs",
"part min %",
"part max %",
"part avg %"
)
for modname, mod_stats in pairs(self.profile.stats) do
if filter_matches(filter, modname) then
self:format_row(modname, "*", mod_stats)
if mod_stats.instruments ~= nil then
for instrument_name, instrument_stats in pairs(mod_stats.instruments) do
self:format_row(modname, instrument_name, instrument_stats)
end
end
end
end
end
}
local function format_statistics(profile, format, filter)
local formatter
if format == "csv" then
formatter = CsvFormatter:new {
profile = profile
}
else
formatter = TxtFormatter:new {
profile = profile
}
end
formatter:format(filter)
return formatter:flush()
end
---
-- Format the profile ready for display and
-- @return string to be printed to the console
--
function reporter.print(profile, filter)
if filter == "" then filter = nil end
return format_statistics(profile, "txt", filter)
end
---
-- Serialize the profile data and
-- @return serialized data to be saved to a file
--
local function serialize_profile(profile, format, filter)
if format == "lua" or format == "json" or format == "json_pretty" then
local stats = filter and {} or profile.stats
if filter then
for modname, mod_stats in pairs(profile.stats) do
if filter_matches(filter, modname) then
stats[modname] = mod_stats
end
end
end
if format == "lua" then
return core.serialize(stats)
elseif format == "json" then
return core.write_json(stats)
elseif format == "json_pretty" then
return core.write_json(stats, true)
end
end
-- Fall back to textual formats.
return format_statistics(profile, format, filter)
end
local worldpath = core.get_worldpath()
local function get_save_path(format, filter)
local report_path = setting_get("profiler.report_path") or ""
if report_path ~= "" then
core.mkdir(sprintf("%s%s%s", worldpath, DIR_DELIM, report_path))
end
return (sprintf(
"%s/%s/profile-%s%s.%s",
worldpath,
report_path,
os.date("%Y%m%dT%H%M%S"),
filter and ("-" .. filter) or "",
format
):gsub("[/\\]+", DIR_DELIM))-- Clean up delims
end
---
-- Save the profile to the world path.
-- @return success, log message
--
function reporter.save(profile, format, filter)
if not format or format == "" then
format = setting_get("profiler.default_report_format") or "txt"
end
if filter == "" then
filter = nil
end
local path = get_save_path(format, filter)
local output, io_err = io.open(path, "w")
if not output then
return false, "Saving of profile failed with: " .. io_err
end
local content, err = serialize_profile(profile, format, filter)
if not content then
output:close()
return false, "Saving of profile failed with: " .. err
end
output:write(content)
output:close()
local logmessage = "Profile saved to " .. path
core.log("action", logmessage)
return true, logmessage
end
return reporter

View File

@@ -1,206 +0,0 @@
--Minetest
--Copyright (C) 2016 T4im
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local setmetatable = setmetatable
local pairs, format = pairs, string.format
local min, max, huge = math.min, math.max, math.huge
local core = core
local profiler = ...
-- Split sampler and profile up, to possibly allow for rotation later.
local sampler = {}
local profile
local stats_total
local logged_time, logged_data
local _stat_mt = {
get_time_avg = function(self)
return self.time_all/self.samples
end,
get_part_avg = function(self)
if not self.part_all then
return 100 -- Extra handling for "total"
end
return self.part_all/self.samples
end,
}
_stat_mt.__index = _stat_mt
function sampler.reset()
-- Accumulated logged time since last sample.
-- This helps determining, the relative time a mod used up.
logged_time = 0
-- The measurements taken through instrumentation since last sample.
logged_data = {}
profile = {
-- Current mod statistics (max/min over the entire mod lifespan)
-- Mod specific instrumentation statistics are nested within.
stats = {},
-- Current stats over all mods.
stats_total = setmetatable({
samples = 0,
time_min = huge,
time_max = 0,
time_all = 0,
part_min = 100,
part_max = 100
}, _stat_mt)
}
stats_total = profile.stats_total
-- Provide access to the most recent profile.
sampler.profile = profile
end
---
-- Log a measurement for the sampler to pick up later.
-- Keep `log` and its often called functions lean.
-- It will directly add to the instrumentation overhead.
--
function sampler.log(modname, instrument_name, time_diff)
if time_diff <= 0 then
if time_diff < 0 then
-- This **might** have happened on a semi-regular basis with huge mods,
-- resulting in negative statistics (perhaps midnight time jumps or ntp corrections?).
core.log("warning", format(
"Time travel of %s::%s by %dµs.",
modname, instrument_name, time_diff
))
end
-- Throwing these away is better, than having them mess with the overall result.
return
end
local mod_data = logged_data[modname]
if mod_data == nil then
mod_data = {}
logged_data[modname] = mod_data
end
mod_data[instrument_name] = (mod_data[instrument_name] or 0) + time_diff
-- Update logged time since last sample.
logged_time = logged_time + time_diff
end
---
-- Return a requested statistic.
-- Initialize if necessary.
--
local function get_statistic(stats_table, name)
local statistic = stats_table[name]
if statistic == nil then
statistic = setmetatable({
samples = 0,
time_min = huge,
time_max = 0,
time_all = 0,
part_min = 100,
part_max = 0,
part_all = 0,
}, _stat_mt)
stats_table[name] = statistic
end
return statistic
end
---
-- Update a statistic table
--
local function update_statistic(stats_table, time)
stats_table.samples = stats_table.samples + 1
-- Update absolute time (µs) spend by the subject
stats_table.time_min = min(stats_table.time_min, time)
stats_table.time_max = max(stats_table.time_max, time)
stats_table.time_all = stats_table.time_all + time
-- Update relative time (%) of this sample spend by the subject
local current_part = (time/logged_time) * 100
stats_table.part_min = min(stats_table.part_min, current_part)
stats_table.part_max = max(stats_table.part_max, current_part)
stats_table.part_all = stats_table.part_all + current_part
end
---
-- Sample all logged measurements each server step.
-- Like any globalstep function, this should not be too heavy,
-- but does not add to the instrumentation overhead.
--
local function sample(dtime)
-- Rare, but happens and is currently of no informational value.
if logged_time == 0 then
return
end
for modname, instruments in pairs(logged_data) do
local mod_stats = get_statistic(profile.stats, modname)
if mod_stats.instruments == nil then
-- Current statistics for each instrumentation component
mod_stats.instruments = {}
end
local mod_time = 0
for instrument_name, time in pairs(instruments) do
if time > 0 then
mod_time = mod_time + time
local instrument_stats = get_statistic(mod_stats.instruments, instrument_name)
-- Update time of this sample spend by the instrumented function.
update_statistic(instrument_stats, time)
-- Reset logged data for the next sample.
instruments[instrument_name] = 0
end
end
-- Update time of this sample spend by this mod.
update_statistic(mod_stats, mod_time)
end
-- Update the total time spend over all mods.
stats_total.time_min = min(stats_total.time_min, logged_time)
stats_total.time_max = max(stats_total.time_max, logged_time)
stats_total.time_all = stats_total.time_all + logged_time
stats_total.samples = stats_total.samples + 1
logged_time = 0
end
---
-- Setup empty profile and register the sampling function
--
function sampler.init()
sampler.reset()
if core.setting_getbool("instrument.profiler") then
core.register_globalstep(function()
if logged_time == 0 then
return
end
return profiler.empty_instrument()
end)
core.register_globalstep(profiler.instrument {
func = sample,
mod = "*profiler*",
class = "Sampler (update stats)",
label = false,
})
else
core.register_globalstep(sample)
end
end
return sampler

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform sampler2D textureFlags;
uniform sampler2D useNormalmap;
uniform vec4 skyBgColor;
uniform float fogDistance;
@@ -8,185 +8,91 @@ uniform vec3 eyePosition;
varying vec3 vPosition;
varying vec3 worldPosition;
varying float area_enable_parallax;
varying vec3 eyeVec;
varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
bool normalTexturePresent = false;
bool normalTexturePresent = false;
const float e = 2.718281828459;
const float BS = 10.0;
const float fogStart = FOG_START;
const float fogShadingParameter = 1 / ( 1 - fogStart);
#ifdef ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters
A = 0.22;
B = 0.30;
C = 0.10;
D = 0.20;
E = 0.01;
F = 0.30;
W = 11.2;
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
*/
vec3 uncharted2Tonemap(vec3 x)
{
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03334;
}
vec4 applyToneMapping(vec4 color)
{
color = vec4(pow(color.rgb, vec3(2.2)), color.a);
const float gamma = 1.6;
const float exposureBias = 5.5;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale;
return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
}
#endif
void get_texture_flags()
{
vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
if (flags.r > 0.5) {
normalTexturePresent = true;
}
}
float intensity(vec3 color)
{
float intensity (vec3 color){
return (color.r + color.g + color.b) / 3.0;
}
float get_rgb_height(vec2 uv)
{
return intensity(texture2D(baseTexture, uv).rgb);
float get_rgb_height (vec2 uv){
return intensity(texture2D(baseTexture,uv).rgb);
}
vec4 get_normal_map(vec2 uv)
{
vec4 get_normal_map(vec2 uv){
vec4 bump = texture2D(normalTexture, uv).rgba;
bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
bump.xyz = normalize(bump.xyz * 2.0 -1.0);
bump.y = -bump.y;
return bump;
}
float find_intersection(vec2 dp, vec2 ds)
{
float depth = 1.0;
float best_depth = 0.0;
float size = 0.0625;
for (int i = 0; i < 15; i++) {
depth -= size;
float h = texture2D(normalTexture, dp + ds * depth).a;
if (depth <= h) {
best_depth = depth;
break;
}
}
depth = best_depth;
for (int i = 0; i < 4; i++) {
size *= 0.5;
float h = texture2D(normalTexture,dp + ds * depth).a;
if (depth <= h) {
best_depth = depth;
depth += size;
} else {
depth -= size;
}
}
return best_depth;
}
float find_intersectionRGB(vec2 dp, vec2 ds)
{
const float depth_step = 1.0 / 24.0;
float depth = 1.0;
for (int i = 0 ; i < 24 ; i++) {
float h = get_rgb_height(dp + ds * depth);
if (h >= depth)
break;
depth -= depth_step;
}
return depth;
}
void main(void)
void main (void)
{
vec3 color;
vec4 bump;
vec2 uv = gl_TexCoord[0].st;
bool use_normalmap = false;
get_texture_flags();
#ifdef USE_NORMALMAPS
if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){
normalTexturePresent = true;
}
#endif
#ifdef ENABLE_PARALLAX_OCCLUSION
vec2 eyeRay = vec2 (tsEyeVec.x, -tsEyeVec.y);
const float scale = PARALLAX_OCCLUSION_SCALE / PARALLAX_OCCLUSION_ITERATIONS;
const float bias = PARALLAX_OCCLUSION_BIAS / PARALLAX_OCCLUSION_ITERATIONS;
#if PARALLAX_OCCLUSION_MODE == 0
// Parallax occlusion with slope information
if (normalTexturePresent && area_enable_parallax > 0.0) {
for (int i = 0; i < PARALLAX_OCCLUSION_ITERATIONS; i++) {
vec4 normal = texture2D(normalTexture, uv.xy);
float h = normal.a * scale - bias;
uv += h * normal.z * eyeRay;
}
#endif
#if PARALLAX_OCCLUSION_MODE == 1
// Relief mapping
if (normalTexturePresent && area_enable_parallax > 0.0) {
vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE;
float dist = find_intersection(uv, ds);
uv += dist * ds;
#endif
} else if (GENERATE_NORMALMAPS == 1 && area_enable_parallax > 0.0) {
vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE;
float dist = find_intersectionRGB(uv, ds);
uv += dist * ds;
if (normalTexturePresent){
vec3 tsEye = normalize(tsEyeVec);
float height = PARALLAX_OCCLUSION_SCALE * texture2D(normalTexture, uv).a - PARALLAX_OCCLUSION_BIAS;
uv = uv + texture2D(normalTexture, uv).z * height * vec2(tsEye.x,-tsEye.y);
}
#endif
#if USE_NORMALMAPS == 1
if (normalTexturePresent) {
#ifdef USE_NORMALMAPS
if (normalTexturePresent){
bump = get_normal_map(uv);
use_normalmap = true;
}
#endif
#ifdef GENERATE_NORMALMAPS
if (use_normalmap == false){
float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP));
float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP));
float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP));
float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y));
float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP));
float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP));
float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP));
float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y));
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0);
use_normalmap = true;
}
#endif
if (GENERATE_NORMALMAPS == 1 && normalTexturePresent == false) {
float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
use_normalmap = true;
}
vec4 base = texture2D(baseTexture, uv).rgba;
vec4 base = texture2D(baseTexture, uv).rgba;
#ifdef ENABLE_BUMPMAPPING
if (use_normalmap) {
if (use_normalmap){
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
float diffuse = dot(-E,bump.xyz);
color = (diffuse + 0.1 * specular) * base.rgb;
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5);
float diffuse = dot(E,bump.xyz);
/* Mathematic optimization
* Original: color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb;
* This optimization save 2 multiplications (orig: 4 multiplications + 3 additions
* end: 2 multiplications + 3 additions)
*/
color = (0.05 + diffuse + 0.2 * specular) * base.rgb;
} else {
color = base.rgb;
}
@@ -194,27 +100,22 @@ void main(void)
color = base.rgb;
#endif
vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0);
#ifdef ENABLE_TONE_MAPPING
col = applyToneMapping(col);
#endif
if (fogDistance != 0.0) {
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
// the fog will only be rendered correctly if the last operation before the
// clamp() is an addition. Else, the clamp() seems to be ignored.
// E.g. the following won't work:
// float clarity = clamp(fogShadingParameter
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
// As additions usually come for free following a multiplication, the new formula
// should be more efficient as well.
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
#if MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE
float alpha = gl_Color.a;
vec4 col = vec4(color.rgb, alpha);
col *= gl_Color;
if(fogDistance != 0.0){
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
alpha = mix(alpha, 0.0, d);
}
col = vec4(col.rgb, base.a);
gl_FragColor = col;
gl_FragColor = vec4(col.rgb, alpha);
#else
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
if(fogDistance != 0.0){
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
col = mix(col, skyBgColor, d);
}
gl_FragColor = vec4(col.rgb, base.a);
#endif
}

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform sampler2D textureFlags;
uniform sampler2D useNormalmap;
uniform vec4 skyBgColor;
uniform float fogDistance;
@@ -14,93 +14,41 @@ varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
bool normalTexturePresent = false;
bool texTileableHorizontal = false;
bool texTileableVertical = false;
bool texSeamless = false;
bool normalTexturePresent = false;
const float e = 2.718281828459;
const float BS = 10.0;
const float fogStart = FOG_START;
const float fogShadingParameter = 1 / ( 1 - fogStart);
#ifdef ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters
A = 0.22;
B = 0.30;
C = 0.10;
D = 0.20;
E = 0.01;
F = 0.30;
W = 11.2;
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
*/
vec3 uncharted2Tonemap(vec3 x)
{
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03334;
}
vec4 applyToneMapping(vec4 color)
{
color = vec4(pow(color.rgb, vec3(2.2)), color.a);
const float gamma = 1.6;
const float exposureBias = 5.5;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale;
return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
}
#endif
void get_texture_flags()
{
vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
if (flags.r > 0.5) {
normalTexturePresent = true;
}
if (flags.g > 0.5) {
texTileableHorizontal = true;
}
if (flags.b > 0.5) {
texTileableVertical = true;
}
if (texTileableHorizontal && texTileableVertical) {
texSeamless = true;
}
}
float intensity(vec3 color)
{
float intensity (vec3 color){
return (color.r + color.g + color.b) / 3.0;
}
float get_rgb_height(vec2 uv)
{
float get_rgb_height (vec2 uv){
return intensity(texture2D(baseTexture,uv).rgb);
}
vec4 get_normal_map(vec2 uv)
{
vec4 get_normal_map(vec2 uv){
vec4 bump = texture2D(normalTexture, uv).rgba;
bump.xyz = normalize(bump.xyz * 2.0 -1.0);
bump.y = -bump.y;
return bump;
}
void main(void)
void main (void)
{
vec3 color;
vec4 bump;
vec2 uv = gl_TexCoord[0].st;
bool use_normalmap = false;
get_texture_flags();
#ifdef USE_NORMALMAPS
if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){
normalTexturePresent = true;
}
#endif
#ifdef ENABLE_PARALLAX_OCCLUSION
if (normalTexturePresent) {
if (normalTexturePresent){
vec3 tsEye = normalize(tsEyeVec);
float height = PARALLAX_OCCLUSION_SCALE * texture2D(normalTexture, uv).a - PARALLAX_OCCLUSION_BIAS;
uv = uv + texture2D(normalTexture, uv).z * height * vec2(tsEye.x,-tsEye.y);
@@ -108,13 +56,14 @@ void main(void)
#endif
#ifdef USE_NORMALMAPS
if (normalTexturePresent) {
if (normalTexturePresent){
bump = get_normal_map(uv);
use_normalmap = true;
}
#endif
if (GENERATE_NORMALMAPS == 1 && use_normalmap == false) {
#ifdef GENERATE_NORMALMAPS
if (use_normalmap == false){
float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP));
float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP));
float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP));
@@ -128,15 +77,16 @@ void main(void)
bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0);
use_normalmap = true;
}
#endif
vec4 base = texture2D(baseTexture, uv).rgba;
#ifdef ENABLE_BUMPMAPPING
if (use_normalmap) {
if (use_normalmap){
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5);
float diffuse = dot(E,bump.xyz);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5);
float diffuse = dot(E,bump.xyz);
/* Mathematic optimization
* Original: color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb;
* This optimization save 2 multiplications (orig: 4 multiplications + 3 additions
@@ -150,27 +100,22 @@ vec4 base = texture2D(baseTexture, uv).rgba;
color = base.rgb;
#endif
vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0);
#ifdef ENABLE_TONE_MAPPING
col = applyToneMapping(col);
#endif
if (fogDistance != 0.0) {
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
// the fog will only be rendered correctly if the last operation before the
// clamp() is an addition. Else, the clamp() seems to be ignored.
// E.g. the following won't work:
// float clarity = clamp(fogShadingParameter
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
// As additions usually come for free following a multiplication, the new formula
// should be more efficient as well.
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
#if MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE
float alpha = gl_Color.a;
vec4 col = vec4(color.rgb, alpha);
col *= gl_Color;
if(fogDistance != 0.0){
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
alpha = mix(alpha, 0.0, d);
}
col = vec4(col.rgb, base.a);
gl_FragColor = col;
gl_FragColor = vec4(col.rgb, alpha);
#else
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
if(fogDistance != 0.0){
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
col = mix(col, skyBgColor, d);
}
gl_FragColor = vec4(col.rgb, base.a);
#endif
}

View File

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

View File

@@ -1,126 +0,0 @@
uniform sampler2D baseTexture;
uniform sampler2D normalTexture;
uniform sampler2D textureFlags;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;
varying vec3 vPosition;
varying vec3 worldPosition;
varying vec3 eyeVec;
varying vec3 lightVec;
bool normalTexturePresent = false;
bool texTileableHorizontal = false;
bool texTileableVertical = false;
bool texSeamless = false;
const float e = 2.718281828459;
const float BS = 10.0;
const float fogStart = FOG_START;
const float fogShadingParameter = 1 / ( 1 - fogStart);
void get_texture_flags()
{
vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
if (flags.r > 0.5) {
normalTexturePresent = true;
}
if (flags.g > 0.5) {
texTileableHorizontal = true;
}
if (flags.b > 0.5) {
texTileableVertical = true;
}
if (texTileableHorizontal && texTileableVertical) {
texSeamless = true;
}
}
float intensity(vec3 color)
{
return (color.r + color.g + color.b) / 3.0;
}
float get_rgb_height(vec2 uv)
{
if (texSeamless) {
return intensity(texture2D(baseTexture, uv).rgb);
} else {
return intensity(texture2D(baseTexture, clamp(uv, 0.0, 0.999)).rgb);
}
}
vec4 get_normal_map(vec2 uv)
{
vec4 bump = texture2D(normalTexture, uv).rgba;
bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
return bump;
}
void main(void)
{
vec3 color;
vec4 bump;
vec2 uv = gl_TexCoord[0].st;
bool use_normalmap = false;
get_texture_flags();
#if USE_NORMALMAPS == 1
if (normalTexturePresent) {
bump = get_normal_map(uv);
use_normalmap = true;
}
#endif
if (GENERATE_NORMALMAPS == 1 && normalTexturePresent == false) {
float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
use_normalmap = true;
}
vec4 base = texture2D(baseTexture, uv).rgba;
#ifdef ENABLE_BUMPMAPPING
if (use_normalmap) {
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
float diffuse = dot(-E,bump.xyz);
color = (diffuse + 0.1 * specular) * base.rgb;
} else {
color = base.rgb;
}
#else
color = base.rgb;
#endif
vec4 col = vec4(color.rgb, base.a);
col *= gl_Color;
if (fogDistance != 0.0) {
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
// the fog will only be rendered correctly if the last operation before the
// clamp() is an addition. Else, the clamp() seems to be ignored.
// E.g. the following won't work:
// float clarity = clamp(fogShadingParameter
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
// As additions usually come for free following a multiplication, the new formula
// should be more efficient as well.
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
}
gl_FragColor = vec4(col.rgb, base.a);
}

View File

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

View File

@@ -1,19 +1,47 @@
mark_as_advanced(CURL_LIBRARY CURL_INCLUDE_DIR)
# - 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.
find_library(CURL_LIBRARY NAMES curl)
find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
if( UNIX )
FIND_PATH(CURL_INCLUDE_DIR NAMES curl.h
PATHS
/usr/local/include/curl
/usr/include/curl
)
set(CURL_REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR)
FIND_LIBRARY(CURL_LIBRARY NAMES curl
PATHS
/usr/local/lib
/usr/lib
)
else( UNIX )
FIND_PATH(CURL_INCLUDE_DIR NAMES curl/curl.h) # Look for the header file.
FIND_LIBRARY(CURL_LIBRARY NAMES curl) # Look for the library.
FIND_FILE(CURL_DLL NAMES libcurl.dll
PATHS
"c:/windows/system32"
DOC "Path of the cURL dll (for installation)")
INCLUDE(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CURL_FOUND to TRUE if
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL DEFAULT_MSG CURL_LIBRARY CURL_INCLUDE_DIR) # all listed variables are TRUE
endif( UNIX )
if(WIN32)
find_file(CURL_DLL NAMES libcurl-4.dll
PATHS
"C:/Windows/System32"
DOC "Path to the cURL DLL (for installation)")
mark_as_advanced(CURL_DLL)
set(CURL_REQUIRED_VARS ${CURL_REQUIRED_VARS} CURL_DLL)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CURL DEFAULT_MSG ${CURL_REQUIRED_VARS})
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}")
MESSAGE(STATUS "CURL_DLL = ${CURL_DLL}")

View File

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

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